mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-06-30 12:33:31 +00:00
Add Delete Style Choice to Settings
This commit is contained in:
parent
d64b21357b
commit
711e830c94
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
invalidate_query,
|
||||
node::{
|
||||
config::{NodeConfig, NodeConfigP2P, NodePreferences},
|
||||
config::{DeletePreferences, DeletePromptOptions, NodeConfig, NodeConfigP2P, NodePreferences},
|
||||
get_hardware_model_name, HardwareModel,
|
||||
},
|
||||
old_job::JobProgressEvent,
|
||||
|
@ -94,6 +94,7 @@ pub struct SanitisedNodeConfig {
|
|||
pub features: Vec<BackendFeature>,
|
||||
pub preferences: NodePreferences,
|
||||
pub image_labeler_version: Option<String>,
|
||||
pub delete_prompt: DeletePreferences,
|
||||
}
|
||||
|
||||
impl From<NodeConfig> for SanitisedNodeConfig {
|
||||
|
@ -106,6 +107,7 @@ impl From<NodeConfig> for SanitisedNodeConfig {
|
|||
features: value.features,
|
||||
preferences: value.preferences,
|
||||
image_labeler_version: value.image_labeler_version,
|
||||
delete_prompt: value.delete_prompt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
invalidate_query,
|
||||
node::config::{P2PDiscoveryState, Port},
|
||||
node::config::{DeletePromptOptions, P2PDiscoveryState, Port},
|
||||
};
|
||||
|
||||
use sd_prisma::prisma::{instance, location};
|
||||
|
@ -25,6 +25,7 @@ pub(crate) fn mount() -> AlphaRouter<Ctx> {
|
|||
pub p2p_discovery: Option<P2PDiscoveryState>,
|
||||
pub p2p_remote_access: Option<bool>,
|
||||
pub image_labeler_version: Option<String>,
|
||||
pub delete_prompt: Option<DeletePromptOptions>,
|
||||
}
|
||||
R.mutation(|node, args: ChangeNodeNameArgs| async move {
|
||||
if let Some(name) = &args.name {
|
||||
|
@ -61,6 +62,10 @@ pub(crate) fn mount() -> AlphaRouter<Ctx> {
|
|||
config.p2p.remote_access = remote_access;
|
||||
};
|
||||
|
||||
if let Some(delete_prompt) = args.delete_prompt {
|
||||
config.delete_prompt.set_option(delete_prompt);
|
||||
}
|
||||
|
||||
#[cfg(feature = "ai")]
|
||||
if let Some(version) = args.image_labeler_version {
|
||||
if config
|
||||
|
|
|
@ -124,6 +124,9 @@ pub struct NodeConfig {
|
|||
pub preferences: NodePreferences,
|
||||
// Model version for the image labeler
|
||||
pub image_labeler_version: Option<String>,
|
||||
// Delete preferences
|
||||
#[serde(default)]
|
||||
pub delete_prompt: DeletePreferences,
|
||||
|
||||
version: NodeConfigVersion,
|
||||
}
|
||||
|
@ -152,6 +155,30 @@ mod identity_serde {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Type, Default)]
|
||||
pub enum DeletePromptOptions {
|
||||
#[default]
|
||||
ShowPrompt,
|
||||
SendTrash,
|
||||
DeleteInstantly,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Type, Default)]
|
||||
pub struct DeletePreferences {
|
||||
option: DeletePromptOptions,
|
||||
}
|
||||
|
||||
impl DeletePreferences {
|
||||
pub fn delete_prompt(&self) -> DeletePromptOptions {
|
||||
self.option
|
||||
}
|
||||
|
||||
pub fn set_option(&mut self, mut delete_prompt: DeletePromptOptions) -> &mut Self {
|
||||
self.option = delete_prompt;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Type)]
|
||||
pub struct NodePreferences {
|
||||
pub thumbnailer: ThumbnailerPreferences,
|
||||
|
@ -201,6 +228,7 @@ impl ManagedVersion<NodeConfigVersion> for NodeConfig {
|
|||
sd_api_origin: None,
|
||||
preferences: NodePreferences::default(),
|
||||
image_labeler_version,
|
||||
delete_prompt: DeletePreferences::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,9 @@ export const Component = () => {
|
|||
|
||||
const { t } = useLocale();
|
||||
|
||||
console.log(node.data);
|
||||
// console.log(node.data?.delete_prompt);
|
||||
|
||||
const form = useZodForm({
|
||||
schema: z
|
||||
.object({
|
||||
|
@ -57,7 +60,12 @@ export const Component = () => {
|
|||
})
|
||||
.int()
|
||||
.nonnegative()
|
||||
.lte(100)
|
||||
.lte(100),
|
||||
delete_prompt: z.union([
|
||||
z.literal('ShowPrompt'),
|
||||
z.literal('SendTrash'),
|
||||
z.literal('DeleteInstantly')
|
||||
])
|
||||
})
|
||||
.strict(),
|
||||
reValidateMode: 'onChange',
|
||||
|
@ -70,7 +78,8 @@ export const Component = () => {
|
|||
p2p_remote_access: node.data?.p2p.remote_access || false,
|
||||
image_labeler_version: node.data?.image_labeler_version ?? undefined,
|
||||
background_processing_percentage:
|
||||
node.data?.preferences.thumbnailer.background_processing_percentage || 50
|
||||
node.data?.preferences.thumbnailer.background_processing_percentage || 50,
|
||||
delete_prompt: node.data?.delete_prompt.option || 'ShowPrompt'
|
||||
}
|
||||
});
|
||||
const p2p_port = form.watch('p2p_port');
|
||||
|
@ -87,7 +96,8 @@ export const Component = () => {
|
|||
p2p_ipv6_enabled: value.p2p_ipv6_enabled ?? null,
|
||||
p2p_discovery: value.p2p_discovery ?? null,
|
||||
p2p_remote_access: value.p2p_remote_access ?? null,
|
||||
image_labeler_version: value.image_labeler_version ?? null
|
||||
image_labeler_version: value.image_labeler_version ?? null,
|
||||
delete_prompt: value.delete_prompt ?? "ShowPrompt"
|
||||
});
|
||||
|
||||
if (value.background_processing_percentage != undefined) {
|
||||
|
@ -406,6 +416,30 @@ export const Component = () => {
|
|||
</>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<h1 className="mb-3 text-lg font-bold text-ink">{t('delete_settings')}</h1>
|
||||
|
||||
<Setting
|
||||
mini
|
||||
title={t('delete_show_prompt')}
|
||||
description={
|
||||
<p className="text-sm text-gray-400">
|
||||
{t('delete_show_prompt_description')}
|
||||
</p>
|
||||
}
|
||||
>
|
||||
<Select
|
||||
value={form.watch('delete_prompt') || 'ShowPrompt'}
|
||||
containerClassName="h-[30px]"
|
||||
className="h-full"
|
||||
onChange={(type) => form.setValue('delete_prompt', type)}
|
||||
>
|
||||
<SelectOption value="ShowPrompt">{'Show Prompt'}</SelectOption>
|
||||
<SelectOption value="SendTrash">{'Send to Trash'}</SelectOption>
|
||||
<SelectOption value="DeleteInstantly">{'Delete Instantly'}</SelectOption>
|
||||
</Select>
|
||||
</Setting>
|
||||
</div>
|
||||
</FormProvider>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
import { useItemsAsEphemeralPaths, useItemsAsFilePaths, type ExplorerItem } from '@sd/client';
|
||||
import {
|
||||
useBridgeQuery,
|
||||
useItemsAsEphemeralPaths,
|
||||
useItemsAsFilePaths,
|
||||
useLibraryMutation,
|
||||
type ExplorerItem
|
||||
} from '@sd/client';
|
||||
import { dialogManager } from '@sd/ui';
|
||||
import DeleteDialog from '~/app/$libraryId/Explorer/FilePath/DeleteDialog';
|
||||
import { isNonEmpty } from '~/util';
|
||||
|
@ -8,6 +14,11 @@ import { useShortcut } from './useShortcut';
|
|||
export const useKeyDeleteFile = (selectedItems: Set<ExplorerItem>, locationId?: number | null) => {
|
||||
const filePaths = useItemsAsFilePaths([...selectedItems]);
|
||||
const ephemeralPaths = useItemsAsEphemeralPaths([...selectedItems]);
|
||||
const node = useBridgeQuery(['nodeState']);
|
||||
const deleteFile = useLibraryMutation('files.deleteFiles');
|
||||
const deleteEphemeralFile = useLibraryMutation('ephemeralFiles.deleteFiles');
|
||||
const moveToTrashFile = useLibraryMutation('files.moveToTrash');
|
||||
const moveToTrashEphemeralFile = useLibraryMutation('ephemeralFiles.moveToTrash');
|
||||
|
||||
const deleteHandler = (e: KeyboardEvent) => {
|
||||
e.preventDefault();
|
||||
|
@ -30,15 +41,31 @@ export const useKeyDeleteFile = (selectedItems: Set<ExplorerItem>, locationId?:
|
|||
fileCount += entry.is_dir ? 0 : 1;
|
||||
}
|
||||
|
||||
dialogManager.create((dp) => (
|
||||
<DeleteDialog
|
||||
{...dp}
|
||||
indexedArgs={indexedArgs}
|
||||
ephemeralArgs={ephemeralArgs}
|
||||
dirCount={dirCount}
|
||||
fileCount={fileCount}
|
||||
/>
|
||||
));
|
||||
if (node.data?.delete_prompt.option === 'ShowPrompt') {
|
||||
dialogManager.create((dp) => (
|
||||
<DeleteDialog
|
||||
{...dp}
|
||||
indexedArgs={indexedArgs}
|
||||
ephemeralArgs={ephemeralArgs}
|
||||
dirCount={dirCount}
|
||||
fileCount={fileCount}
|
||||
/>
|
||||
));
|
||||
} else if (node.data?.delete_prompt.option === 'SendTrash') {
|
||||
if (locationId != null && isNonEmpty(filePaths)) {
|
||||
moveToTrashFile.mutate({ location_id: locationId, file_path_ids: filePaths.map((p) => p.id) });
|
||||
} else if (isNonEmpty(ephemeralPaths)) {
|
||||
const { paths } = ephemeralArgs!;
|
||||
moveToTrashEphemeralFile.mutate(paths);
|
||||
}
|
||||
} else {
|
||||
if (locationId != null && isNonEmpty(filePaths)) {
|
||||
deleteFile.mutate({ location_id: locationId, file_path_ids: filePaths.map((p) => p.id) });
|
||||
} else if (isNonEmpty(ephemeralPaths)) {
|
||||
const { paths } = ephemeralArgs!;
|
||||
deleteEphemeralFile.mutate(paths);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useShortcut('delItem', deleteHandler);
|
||||
|
|
|
@ -142,6 +142,9 @@
|
|||
"default": "Default",
|
||||
"default_settings": "Default Settings",
|
||||
"delete": "Delete",
|
||||
"delete_settings": "Delete Functionality",
|
||||
"delete_show_prompt": "Delete Prompt",
|
||||
"delete_show_prompt_description": "Choose if you would like to automatically send files to the trash, delete them forever, or show a prompt before choosing an option.",
|
||||
"delete_dialog_title": "Delete {{prefix}} {{type}}",
|
||||
"delete_forever": "Delete Forever",
|
||||
"delete_info": "This will not delete the actual folder on disk. Preview media will be deleted.",
|
||||
|
|
|
@ -168,7 +168,7 @@ export type CRDTOperationData = { c: { [key in string]: JsonValue } } | { u: { f
|
|||
|
||||
export type CameraData = { device_make: string | null; device_model: string | null; color_space: string | null; color_profile: ColorProfile | null; focal_length: number | null; shutter_speed: number | null; flash: Flash | null; orientation: Orientation; lens_make: string | null; lens_model: string | null; bit_depth: number | null; zoom: number | null; iso: number | null; software: string | null; serial_number: string | null; lens_serial_number: string | null; contrast: number | null; saturation: number | null; sharpness: number | null; composite: Composite | null }
|
||||
|
||||
export type ChangeNodeNameArgs = { name: string | null; p2p_port: Port | null; p2p_ipv4_enabled: boolean | null; p2p_ipv6_enabled: boolean | null; p2p_discovery: P2PDiscoveryState | null; p2p_remote_access: boolean | null; image_labeler_version: string | null }
|
||||
export type ChangeNodeNameArgs = { name: string | null; p2p_port: Port | null; p2p_ipv4_enabled: boolean | null; p2p_ipv6_enabled: boolean | null; p2p_discovery: P2PDiscoveryState | null; p2p_remote_access: boolean | null; image_labeler_version: string | null; delete_prompt: DeletePromptOptions | null }
|
||||
|
||||
export type Chapter = { id: number; start: [number, number]; end: [number, number]; time_base_den: number; time_base_num: number; metadata: Metadata }
|
||||
|
||||
|
@ -224,6 +224,10 @@ export type CursorOrderItem<T> = { order: SortOrder; data: T }
|
|||
|
||||
export type DefaultLocations = { desktop: boolean; documents: boolean; downloads: boolean; pictures: boolean; music: boolean; videos: boolean }
|
||||
|
||||
export type DeletePreferences = { option: DeletePromptOptions }
|
||||
|
||||
export type DeletePromptOptions = "ShowPrompt" | "SendTrash" | "DeleteInstantly"
|
||||
|
||||
/**
|
||||
* The method used for the discovery of this peer.
|
||||
* *Technically* you can have multiple under the hood but this simplifies things for the UX.
|
||||
|
@ -484,7 +488,7 @@ id: string;
|
|||
/**
|
||||
* name is the display name of the current node. This is set by the user and is shown in the UI. // TODO: Length validation so it can fit in DNS record
|
||||
*/
|
||||
name: string; identity: RemoteIdentity; p2p: NodeConfigP2P; features: BackendFeature[]; preferences: NodePreferences; image_labeler_version: string | null }) & { data_path: string; device_model: string | null }
|
||||
name: string; identity: RemoteIdentity; p2p: NodeConfigP2P; features: BackendFeature[]; preferences: NodePreferences; image_labeler_version: string | null; delete_prompt: DeletePreferences }) & { data_path: string; device_model: string | null }
|
||||
|
||||
export type NonIndexedPathItem = { path: string; name: string; extension: string; kind: number; is_dir: boolean; date_created: string; date_modified: string; size_in_bytes_bytes: number[]; hidden: boolean }
|
||||
|
||||
|
|
Loading…
Reference in a new issue