From 66063d22c271d73a53a8ddc684ab5062be6db8d6 Mon Sep 17 00:00:00 2001 From: Arnab Chakraborty <11457760+Rocky43007@users.noreply.github.com> Date: Fri, 12 Apr 2024 01:01:37 -0400 Subject: [PATCH] [ENG-1365] Move to Trash (#2318) * Working System Trash Connection * small changes and prettier --------- Co-authored-by: Utku Bakir <74243531+utkubakir@users.noreply.github.com> --- CONTRIBUTING.md | 1 + Cargo.lock | 26 ++++++++ core/Cargo.toml | 1 + core/src/api/ephemeral_files.rs | 30 ++++++++++ core/src/api/files.rs | 48 +++++++++++++++ .../app/$libraryId/Explorer/ExplorerPath.tsx | 12 ++-- .../Explorer/FilePath/DeleteDialog.tsx | 31 +++++++++- interface/locales/by/common.json | 2 +- interface/locales/de/common.json | 2 +- interface/locales/en/common.json | 60 ++++++++++--------- interface/locales/es/common.json | 2 +- interface/locales/fr/common.json | 2 +- interface/locales/it/common.json | 2 +- interface/locales/ja/common.json | 2 +- interface/locales/nl/common.json | 2 +- interface/locales/ru/common.json | 2 +- interface/locales/tr/common.json | 2 +- interface/locales/zh-CN/common.json | 2 +- interface/locales/zh-TW/common.json | 2 +- packages/client/src/core.ts | 2 + packages/ui/src/Dialog.tsx | 52 +++++++++++++++- 21 files changed, 233 insertions(+), 52 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6a3827d74..0acb68468 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -172,6 +172,7 @@ Also ensure that Rosetta is installed, as a few of our dependencies require it. #### `ModuleNotFoundError: No module named 'distutils'` If you run into this issue, or some other error involving `node-gyp`: + ``` File "pnpm@8.15.6/node_modules/pnpm/dist/node_modules/node-gyp/gyp/gyp_main.py", line 42, in import gyp # noqa: E402 diff --git a/Cargo.lock b/Cargo.lock index 37a572a33..aa7f99917 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8276,6 +8276,7 @@ dependencies = [ "tracing-appender", "tracing-subscriber", "tracing-test", + "trash", "uuid", "webp", ] @@ -10531,6 +10532,22 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "trash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a1a7a9a17d3b004898be42be29a4c18d5a4cf008b5cdf72d69b1945dfcb158a" +dependencies = [ + "chrono", + "libc", + "log", + "objc", + "once_cell", + "scopeguard", + "url", + "windows 0.44.0", +] + [[package]] name = "treediff" version = "4.0.2" @@ -11267,6 +11284,15 @@ dependencies = [ "windows_x86_64_msvc 0.39.0", ] +[[package]] +name = "windows" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows" version = "0.48.0" diff --git a/core/Cargo.toml b/core/Cargo.toml index 4aa43b6ad..fce732095 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -132,6 +132,7 @@ static_assertions = "1.1.0" sysinfo = "0.29.10" tar = "0.4.40" tower-service = "0.3.2" +trash = "4.1.0" # Override features of transitive dependencies [dependencies.openssl] diff --git a/core/src/api/ephemeral_files.rs b/core/src/api/ephemeral_files.rs index 17eaa4114..3b500e8e0 100644 --- a/core/src/api/ephemeral_files.rs +++ b/core/src/api/ephemeral_files.rs @@ -27,6 +27,7 @@ use specta::Type; use tokio::{fs, io}; use tokio_stream::{wrappers::ReadDirStream, StreamExt}; use tracing::{error, warn}; +use trash; use super::{ files::{create_directory, FromPattern}, @@ -147,6 +148,35 @@ pub(crate) fn mount() -> AlphaRouter { Ok(()) }) }) + .procedure("moveToTrash", { + R.with2(library()) + .mutation(|(_, library), paths: Vec| async move { + paths + .into_iter() + .map(|path| async move { + match fs::metadata(&path).await { + Ok(_) => { + trash::delete(&path).unwrap(); + + Ok(()) + } + Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(()), + Err(e) => Err(FileIOError::from(( + path, + e, + "Failed to get file metadata for deletion", + ))), + } + }) + .collect::>() + .try_join() + .await?; + + invalidate_query!(library, "search.ephemeralPaths"); + + Ok(()) + }) + }) .procedure("copyFiles", { R.with2(library()) .mutation(|(_, library), args: EphemeralFileSystemOps| async move { diff --git a/core/src/api/files.rs b/core/src/api/files.rs index 1ea794d30..d0e5b7c6f 100644 --- a/core/src/api/files.rs +++ b/core/src/api/files.rs @@ -44,6 +44,7 @@ use serde::{Deserialize, Serialize}; use specta::Type; use tokio::{fs, io, task::spawn_blocking}; use tracing::{error, warn}; +use trash; use super::{Ctx, R}; @@ -515,6 +516,53 @@ pub(crate) fn mount() -> AlphaRouter { } }) }) + .procedure("moveToTrash", { + R.with2(library()) + .mutation(|(node, library), args: OldFileDeleterJobInit| async move { + match args.file_path_ids.len() { + 0 => Ok(()), + 1 => { + let (maybe_location, maybe_file_path) = library + .db + ._batch(( + library + .db + .location() + .find_unique(location::id::equals(args.location_id)) + .select(location::select!({ path })), + library + .db + .file_path() + .find_unique(file_path::id::equals(args.file_path_ids[0])) + .select(file_path_to_isolate::select()), + )) + .await?; + + let location_path = maybe_location + .ok_or(LocationError::IdNotFound(args.location_id))? + .path + .ok_or(LocationError::MissingPath(args.location_id))?; + + let file_path = maybe_file_path.ok_or(LocationError::FilePath( + FilePathError::IdNotFound(args.file_path_ids[0]), + ))?; + + let full_path = Path::new(&location_path).join( + IsolatedFilePathData::try_from(&file_path) + .map_err(LocationError::MissingField)?, + ); + + trash::delete(&full_path).unwrap(); + + Ok(()) + } + _ => Job::new(args) + .spawn(&node, &library) + .await + .map_err(Into::into), + } + }) + }) .procedure("convertImage", { #[derive(Type, Deserialize)] struct ConvertImageArgs { diff --git a/interface/app/$libraryId/Explorer/ExplorerPath.tsx b/interface/app/$libraryId/Explorer/ExplorerPath.tsx index 0c4ce5094..bb8e0913c 100644 --- a/interface/app/$libraryId/Explorer/ExplorerPath.tsx +++ b/interface/app/$libraryId/Explorer/ExplorerPath.tsx @@ -1,4 +1,8 @@ import { AppWindow, ArrowSquareOut, CaretRight, ClipboardText } from '@phosphor-icons/react'; +import clsx from 'clsx'; +import { memo, useMemo, useState } from 'react'; +import { useNavigate } from 'react-router'; +import { createSearchParams } from 'react-router-dom'; import { getExplorerItemData, getIndexedItemFilePath, @@ -6,13 +10,9 @@ import { useLibraryQuery } from '@sd/client'; import { ContextMenu } from '@sd/ui'; -import clsx from 'clsx'; -import { memo, useMemo, useState } from 'react'; -import { useNavigate } from 'react-router'; -import { createSearchParams } from 'react-router-dom'; -import { useTabsContext } from '~/TabsContext'; import { Icon } from '~/components'; import { useIsDark, useLocale, useOperatingSystem } from '~/hooks'; +import { useTabsContext } from '~/TabsContext'; import { usePlatform } from '~/util/Platform'; import { useExplorerContext } from './Context'; @@ -240,7 +240,7 @@ const Path = ({ path, onClick, disabled, locationPath }: PathProps) => { navigator.clipboard.writeText(osPath)} icon={ClipboardText} - label={t("copy_as_path")} + label={t('copy_as_path')} /> ); diff --git a/interface/app/$libraryId/Explorer/FilePath/DeleteDialog.tsx b/interface/app/$libraryId/Explorer/FilePath/DeleteDialog.tsx index ce7435325..dc3425a01 100644 --- a/interface/app/$libraryId/Explorer/FilePath/DeleteDialog.tsx +++ b/interface/app/$libraryId/Explorer/FilePath/DeleteDialog.tsx @@ -47,6 +47,8 @@ export default (props: Props) => { const { t } = useLocale(); const deleteFile = useLibraryMutation('files.deleteFiles'); const deleteEphemeralFile = useLibraryMutation('ephemeralFiles.deleteFiles'); + const moveToTrashFile = useLibraryMutation('files.moveToTrash'); + const moveToTrashEphemeralFile = useLibraryMutation('ephemeralFiles.moveToTrash'); const form = useZodForm(); const { dirCount = 0, fileCount = 0, indexedArgs, ephemeralArgs } = props; @@ -76,23 +78,46 @@ export default (props: Props) => { await deleteEphemeralFile.mutateAsync(paths); } })} + onSubmitSecond={form.handleSubmit(async () => { + if (indexedArgs != undefined) { + console.log( + 'DEBUG: DeleteDialog.tsx: onSubmitSecond (Move to Trash) -> Indexed Files' + ); + const { locationId, rescan, pathIds } = indexedArgs; + await moveToTrashFile.mutateAsync({ + location_id: locationId, + file_path_ids: pathIds + }); + + rescan?.(); + } + + if (ephemeralArgs != undefined) { + console.log( + 'DEBUG: DeleteDialog.tsx: onSubmitSecond (Move to Trash) -> Ephemeral Files' + ); + const { paths } = ephemeralArgs; + await moveToTrashEphemeralFile.mutateAsync(paths); + } + })} icon={} dialog={useDialog(props)} title={t('delete_dialog_title', { prefix, type })} description={description} loading={deleteFile.isLoading} - ctaLabel={t('delete')} + ctaLabel={t('delete_forever')} + ctaSecondLabel={t('move_to_trash')} ctaDanger className="w-[200px]" > - + {/*

Delete all matching {type.endsWith('s') ? type : type + 's'}

-
+
*/} ); }; diff --git a/interface/locales/by/common.json b/interface/locales/by/common.json index 645c0bde1..5acd7f568 100644 --- a/interface/locales/by/common.json +++ b/interface/locales/by/common.json @@ -104,7 +104,7 @@ "delete_rule": "Выдаліць правіла", "delete_tag": "Выдаліць тэг", "delete_tag_description": "Вы ўпэўнены, што хочаце выдаліць гэты тэг? Гэта дзеянне няможна скасаваць, і тэгнутые файлы будуць адлучаны.", - "delete_warning": "Папярэджанне: гэта выдаліць ваш {{type}} назаўжды, у нас пакуль няма сметніцы.", + "delete_warning": "гэта выдаліць ваш {{type}} назаўжды, у нас пакуль няма сметніцы.", "description": "Апісанне", "deselect": "Скасаваць выбар", "details": "Падрабязней", diff --git a/interface/locales/de/common.json b/interface/locales/de/common.json index ccdde3fbb..eb8c7057d 100644 --- a/interface/locales/de/common.json +++ b/interface/locales/de/common.json @@ -104,7 +104,7 @@ "delete_rule": "Regel löschen", "delete_tag": "Tag löschen", "delete_tag_description": "Sind Sie sicher, dass Sie diesen Tag löschen möchten? Dies kann nicht rückgängig gemacht werden, und getaggte Dateien werden nicht mehr verlinkt.", - "delete_warning": "Warnung: Dies wird Ihre {{type}} für immer löschen, wir haben noch keinen Papierkorb...", + "delete_warning": "Dies wird Ihre {{type}} für immer löschen, wir haben noch keinen Papierkorb...", "description": "Beschreibung", "deselect": "Abwählen", "details": "Details", diff --git a/interface/locales/en/common.json b/interface/locales/en/common.json index fdb5d6315..de12b5096 100644 --- a/interface/locales/en/common.json +++ b/interface/locales/en/common.json @@ -64,6 +64,10 @@ "copy_path_to_clipboard": "Copy path to clipboard", "copy_success": "Items copied", "create": "Create", + "create_file_error": "Error creating file", + "create_file_success": "Created new file: {{name}}", + "create_folder_error": "Error creating folder", + "create_folder_success": "Created new folder: {{name}}", "create_library": "Create a Library", "create_library_description": "Libraries are a secure, on-device database. Your files remain where they are, the Library catalogs them and stores all Spacedrive related data.", "create_new_library": "Create new library", @@ -82,11 +86,16 @@ "cut_object": "Cut object", "cut_success": "Items cut", "data_folder": "Data Folder", + "date_accessed": "Date Accessed", + "date_created": "Date Created", + "date_indexed": "Date Indexed", + "date_modified": "Date Modified", "debug_mode": "Debug mode", "debug_mode_description": "Enable extra debugging features within the app.", "default": "Default", "delete": "Delete", "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.", "delete_library": "Delete Library", "delete_library_description": "This is permanent, your files will not be deleted, only the Spacedrive library.", @@ -96,7 +105,7 @@ "delete_rule": "Delete rule", "delete_tag": "Delete Tag", "delete_tag_description": "Are you sure you want to delete this tag? This cannot be undone and tagged files will be unlinked.", - "delete_warning": "Warning: This will delete your {{type}} forever, we don't have a trash can yet...", + "delete_warning": "This will delete your {{type}}. This action cannot be undone as of right now. If you Move to Trash, you can restore it later. If you Delete Forever, it will be gone forever.", "description": "Description", "deselect": "Deselect", "details": "Details", @@ -121,7 +130,10 @@ "edit": "Edit", "edit_library": "Edit Library", "edit_location": "Edit Location", + "empty_file": "Empty file", "enable_networking": "Enable Networking", + "enable_networking_description": "Allow your node to communicate with other Spacedrive nodes around you.", + "enable_networking_description_required": "Required for library sync or Spacedrop!", "encrypt": "Encrypt", "encrypt_library": "Encrypt Library", "encrypt_library_coming_soon": "Library encryption coming soon", @@ -200,6 +212,7 @@ "hide_in_sidebar_description": "Prevent this tag from showing in the sidebar of the app.", "hide_location_from_view": "Hide location and contents from view", "home": "Home", + "icon_size": "Icon size", "image_labeler_ai_model": "Image label recognition AI model", "image_labeler_ai_model_description": "The model used to recognize objects in images. Larger models are more accurate but slower.", "import": "Import", @@ -211,8 +224,6 @@ "install_update": "Install Update", "installed": "Installed", "item_size": "Item size", - "icon_size": "Icon size", - "text_size": "Text size", "item_with_count_one": "{{count}} item", "item_with_count_other": "{{count}} items", "job_has_been_canceled": "Job has been canceled.", @@ -250,6 +261,7 @@ "location_connected_tooltip": "Location is being watched for changes", "location_disconnected_tooltip": "Location is not being watched for changes", "location_display_name_info": "The name of this Location, this is what will be displayed in the sidebar. Will not rename the actual folder on disk.", + "location_empty_notice_message": "No files found here", "location_is_already_linked": "Location is already linked", "location_path_info": "The path to this Location, this is where the files will be stored on disk.", "location_type": "Location Type", @@ -259,9 +271,11 @@ "locations": "Locations", "locations_description": "Manage your storage locations.", "lock": "Lock", + "log_in": "Log in", "log_in_with_browser": "Log in with browser", "log_out": "Log out", "logged_in_as": "Logged in as {{email}}", + "logging_in": "Logging in...", "logout": "Logout", "manage_library": "Manage Library", "managed": "Managed", @@ -279,6 +293,7 @@ "move_back_within_quick_preview": "Move back within quick preview", "move_files": "Move Files", "move_forward_within_quick_preview": "Move forward within quick preview", + "move_to_trash": "Move to Trash", "name": "Name", "navigate_back": "Navigate back", "navigate_backwards": "Navigate backwards", @@ -296,19 +311,14 @@ "networking_port_description": "The port for Spacedrive's Peer-to-peer networking to communicate on. You should leave this disabled unless you have a restrictive firewall. Do not expose to the internet!", "new": "New", "new_folder": "Folder", - "text_file": "Text File", - "empty_file": "Empty file", - "create_folder_error": "Error creating folder", - "create_file_error": "Error creating file", - "create_folder_success": "Created new folder: {{name}}", - "create_file_success": "Created new file: {{name}}", "new_library": "New library", "new_location": "New location", "new_location_web_description": "As you are using the browser version of Spacedrive you will (for now) need to specify an absolute URL of a directory local to the remote node.", "new_tab": "New Tab", "new_tag": "New tag", "new_update_available": "New Update Available!", - "location_empty_notice_message": "No files found here", + "no_favorite_items": "No favorite items", + "no_items_found": "No items found", "no_jobs": "No jobs.", "no_labels": "No labels", "no_nodes_found": "No Spacedrive nodes were found.", @@ -326,6 +336,7 @@ "online": "Online", "open": "Open", "open_file": "Open File", + "open_in_new_tab": "Open in new tab", "open_new_location_once_added": "Open new location once added", "open_new_tab": "Open new tab", "open_object": "Open object", @@ -347,12 +358,14 @@ "pause": "Pause", "peers": "Peers", "people": "People", + "pin": "Pin", "privacy": "Privacy", "privacy_description": "Spacedrive is built for privacy, that's why we're open source and local first. So we'll make it very clear what data is shared with us.", "quick_preview": "Quick Preview", "quick_view": "Quick view", "recent_jobs": "Recent Jobs", "recents": "Recents", + "recents_notice_message": "Recents are created when you open a file.", "regen_labels": "Regen Labels", "regen_thumbnails": "Regen Thumbnails", "regenerate_thumbs": "Regenerate Thumbs", @@ -364,6 +377,7 @@ "rename": "Rename", "rename_object": "Rename object", "replica": "Replica", + "rescan": "Rescan", "rescan_directory": "Rescan Directory", "rescan_location": "Rescan Location", "reset": "Reset", @@ -377,6 +391,7 @@ "save": "Save", "save_changes": "Save Changes", "saved_searches": "Saved Searches", + "search": "Search", "search_extensions": "Search extensions", "search_for_files_and_actions": "Search for files and actions...", "secure_delete": "Secure delete", @@ -399,9 +414,9 @@ "show_slider": "Show slider", "size": "Size", "size_b": "B", + "size_gb": "GB", "size_kb": "kB", "size_mb": "MB", - "size_gb": "GB", "size_tb": "TB", "skip_login": "Skip login", "sort_by": "Sort by", @@ -429,9 +444,12 @@ "sync_with_library_description": "If enabled, your keybinds will be synced with library, otherwise they will apply only to this client.", "tags": "Tags", "tags_description": "Manage your tags.", + "tags_notice_message": "No items assigned to this tag.", "telemetry_description": "Toggle ON to provide developers with detailed usage and telemetry data to enhance the app. Toggle OFF to send only basic data: your activity status, app version, core version, and platform (e.g., mobile, web, or desktop).", "telemetry_title": "Share Additional Telemetry and Usage Data", "temperature": "Temperature", + "text_file": "Text File", + "text_size": "Text size", "thank_you_for_your_feedback": "Thanks for your feedback!", "thumbnailer_cpu_usage": "Thumbnailer CPU usage", "thumbnailer_cpu_usage_description": "Limit how much CPU the thumbnailer can use for background processing.", @@ -462,21 +480,5 @@ "your_account": "Your account", "your_account_description": "Spacedrive account and information.", "your_local_network": "Your Local Network", - "your_privacy": "Your Privacy", - "pin": "Pin", - "rescan": "Rescan", - "open_in_new_tab": "Open in new tab", - "enable_networking_description": "Allow your node to communicate with other Spacedrive nodes around you.", - "enable_networking_description_required": "Required for library sync or Spacedrop!", - "log_in": "Log in", - "logging_in": "Logging in...", - "no_favorite_items": "No favorite items", - "tags_notice_message": "No items assigned to this tag.", - "recents_notice_message": "Recents are created when you open a file.", - "no_items_found": "No items found", - "search": "Search", - "date_created": "Date Created", - "date_modified": "Date Modified", - "date_indexed": "Date Indexed", - "date_accessed": "Date Accessed" -} + "your_privacy": "Your Privacy" +} \ No newline at end of file diff --git a/interface/locales/es/common.json b/interface/locales/es/common.json index aa8aea941..f670e11c7 100644 --- a/interface/locales/es/common.json +++ b/interface/locales/es/common.json @@ -104,7 +104,7 @@ "delete_rule": "Eliminar regla", "delete_tag": "Eliminar Etiqueta", "delete_tag_description": "¿Estás seguro de que quieres eliminar esta etiqueta? Esto no se puede deshacer y los archivos etiquetados serán desvinculados.", - "delete_warning": "Advertencia: Esto eliminará tu {{type}} para siempre, aún no tenemos papelera...", + "delete_warning": "Esto eliminará tu {{type}} para siempre, aún no tenemos papelera...", "description": "Descripción", "deselect": "Deseleccionar", "details": "Detalles", diff --git a/interface/locales/fr/common.json b/interface/locales/fr/common.json index b552efd22..0d9208be1 100644 --- a/interface/locales/fr/common.json +++ b/interface/locales/fr/common.json @@ -104,7 +104,7 @@ "delete_rule": "Supprimer la règle", "delete_tag": "Supprimer l'étiquette", "delete_tag_description": "Êtes-vous sûr de vouloir supprimer cette étiquette ? Cela ne peut pas être annulé et les fichiers étiquetés seront dissociés.", - "delete_warning": "Attention : Ceci supprimera votre {{type}} pour toujours, nous n'avons pas encore de corbeille...", + "delete_warning": "Ceci supprimera votre {{type}} pour toujours, nous n'avons pas encore de corbeille...", "description": "Description", "deselect": "Désélectionner", "details": "Détails", diff --git a/interface/locales/it/common.json b/interface/locales/it/common.json index d0ac69b8e..20b8649c5 100644 --- a/interface/locales/it/common.json +++ b/interface/locales/it/common.json @@ -104,7 +104,7 @@ "delete_rule": "Elimina regola", "delete_tag": "Elimina Tag", "delete_tag_description": "Sei sicuro di voler cancellare questa etichetta? Questa operazione non può essere annullata e i file etichettati verranno scollegati.", - "delete_warning": "Attenzione: stai per eliminare il tuo {{type}} per sempre, non abbiamo ancora un cestino...", + "delete_warning": "stai per eliminare il tuo {{type}} per sempre, non abbiamo ancora un cestino...", "description": "Descrizione", "deselect": "Deseleziona", "details": "Dettagli", diff --git a/interface/locales/ja/common.json b/interface/locales/ja/common.json index 78dc25db6..aafab5276 100644 --- a/interface/locales/ja/common.json +++ b/interface/locales/ja/common.json @@ -104,7 +104,7 @@ "delete_rule": "ルールを削除", "delete_tag": "タグを削除", "delete_tag_description": "本当にこのタグを削除しますか?これを元に戻すことはできず、タグ付けされたファイル間の結びつきは失われます。", - "delete_warning": "【警告】これはあなたの {{type}} を完全に削除します。", + "delete_warning": "これはあなたの {{type}} を完全に削除します。", "description": "説明", "deselect": "クリップボードを空にする", "details": "詳細", diff --git a/interface/locales/nl/common.json b/interface/locales/nl/common.json index 467d34348..e5a79370e 100644 --- a/interface/locales/nl/common.json +++ b/interface/locales/nl/common.json @@ -104,7 +104,7 @@ "delete_rule": "Verwijder regel", "delete_tag": "Verwijder Tag", "delete_tag_description": "Weet je zeker dat je deze tag wilt verwijderen? Dit kan niet ongedaan worden gemaakt en ge-tagde bestanden worden ontkoppeld.", - "delete_warning": "Waarschuwing: hiermee wordt je {{type}} permanent verwijderd, we hebben nog geen prullenbak...", + "delete_warning": "hiermee wordt je {{type}} permanent verwijderd, we hebben nog geen prullenbak...", "description": "Omschrijving", "deselect": "Deselecteer", "details": "Details", diff --git a/interface/locales/ru/common.json b/interface/locales/ru/common.json index 1d0ff8fe2..1400bdec6 100644 --- a/interface/locales/ru/common.json +++ b/interface/locales/ru/common.json @@ -104,7 +104,7 @@ "delete_rule": "Удалить правило", "delete_tag": "Удалить тег", "delete_tag_description": "Вы уверены, что хотите удалить этот тег? Это действие нельзя отменить, и тегнутые файлы будут отсоединены.", - "delete_warning": "Предупреждение: это удалит ваш {{type}} навсегда, у нас пока нет мусорной корзины.", + "delete_warning": "это удалит ваш {{type}} навсегда, у нас пока нет мусорной корзины.", "description": "Описание", "deselect": "Отменить выбор", "details": "Подробности", diff --git a/interface/locales/tr/common.json b/interface/locales/tr/common.json index 13150bcb2..23511c519 100644 --- a/interface/locales/tr/common.json +++ b/interface/locales/tr/common.json @@ -104,7 +104,7 @@ "delete_rule": "Kuralı Sil", "delete_tag": "Etiketi Sil", "delete_tag_description": "Bu etiketi silmek istediğinizden emin misiniz? Bu geri alınamaz ve etiketli dosyalar bağlantısız kalacak.", - "delete_warning": "Uyarı: Bu, {{type}}'ınızı sonsuza dek silecek, henüz çöp kutumuz yok...", + "delete_warning": "Bu, {{type}}'ınızı sonsuza dek silecek, henüz çöp kutumuz yok...", "description": "Açıklama", "deselect": "Seçimi Kaldır", "details": "Detaylar", diff --git a/interface/locales/zh-CN/common.json b/interface/locales/zh-CN/common.json index 1d35cefb0..2fb4aee82 100644 --- a/interface/locales/zh-CN/common.json +++ b/interface/locales/zh-CN/common.json @@ -104,7 +104,7 @@ "delete_rule": "删除规则", "delete_tag": "删除标签", "delete_tag_description": "您确定要删除这个标签吗?这不能被撤销,打过标签的文件将会被取消链接。", - "delete_warning": "警告:这将永久删除您的{{type}},我们目前还没有回收站…", + "delete_warning": "这将永久删除您的{{type}},我们目前还没有回收站…", "description": "描述", "deselect": "取消选择", "details": "详情", diff --git a/interface/locales/zh-TW/common.json b/interface/locales/zh-TW/common.json index 4ddc2fdaa..cdb338abd 100644 --- a/interface/locales/zh-TW/common.json +++ b/interface/locales/zh-TW/common.json @@ -104,7 +104,7 @@ "delete_rule": "刪除規則", "delete_tag": "刪除標籤", "delete_tag_description": "您確定要刪除這個標籤嗎?這不能撤銷,並且帶有標籤的文件將被取消鏈接。", - "delete_warning": "警告:這將永遠刪除您的{{type}},我們還沒有垃圾箱...", + "delete_warning": "這將永遠刪除您的{{type}},我們還沒有垃圾箱...", "description": "描述", "deselect": "取消選擇", "details": "詳情", diff --git a/packages/client/src/core.ts b/packages/client/src/core.ts index 76fc9d166..b96a2809c 100644 --- a/packages/client/src/core.ts +++ b/packages/client/src/core.ts @@ -73,6 +73,7 @@ export type Procedures = { { key: "ephemeralFiles.createFolder", input: LibraryArgs, result: string } | { key: "ephemeralFiles.cutFiles", input: LibraryArgs, result: null } | { key: "ephemeralFiles.deleteFiles", input: LibraryArgs, result: null } | + { key: "ephemeralFiles.moveToTrash", input: LibraryArgs, result: null } | { key: "ephemeralFiles.renameFile", input: LibraryArgs, result: null } | { key: "files.convertImage", input: LibraryArgs, result: null } | { key: "files.copyFiles", input: LibraryArgs, result: null } | @@ -81,6 +82,7 @@ export type Procedures = { { key: "files.cutFiles", input: LibraryArgs, result: null } | { key: "files.deleteFiles", input: LibraryArgs, result: null } | { key: "files.eraseFiles", input: LibraryArgs, result: null } | + { key: "files.moveToTrash", input: LibraryArgs, result: null } | { key: "files.removeAccessTime", input: LibraryArgs, result: null } | { key: "files.renameFile", input: LibraryArgs, result: null } | { key: "files.setFavorite", input: LibraryArgs, result: null } | diff --git a/packages/ui/src/Dialog.tsx b/packages/ui/src/Dialog.tsx index e91e0357f..ca3b42eea 100644 --- a/packages/ui/src/Dialog.tsx +++ b/packages/ui/src/Dialog.tsx @@ -121,7 +121,9 @@ export interface DialogProps loading?: boolean; trigger?: ReactNode; ctaLabel?: string; + ctaSecondLabel?: string; onSubmit?: ReturnType>; + onSubmitSecond?: ReturnType>; children?: ReactNode; ctaDanger?: boolean; closeLabel?: string; @@ -141,6 +143,7 @@ export function Dialog({ form, dialog, onSubmit, + onSubmitSecond, onCancelled = true, invertButtonFocus, ...props @@ -190,7 +193,7 @@ export function Dialog({ ) : !form.formState.isValid; - const submitButton = ( + const submitButton = !props.ctaSecondLabel ? ( + ) : ( +
+ + +
); return ( @@ -226,8 +274,6 @@ export function Dialog({ form={form} onSubmit={async (e) => { e?.preventDefault(); - await onSubmit?.(e); - dialog.onSubmit?.(); setOpen(false); }} className={clsx(