From f0ed1fcfc9e4f353535a8284ec18fadd592ba9a9 Mon Sep 17 00:00:00 2001 From: E44 <129310925+programmer-44@users.noreply.github.com> Date: Sun, 23 Nov 2025 20:45:52 +0100 Subject: [PATCH] chore(control): add rename file --- .../frontend/src/components/FileView.svelte | 79 +++++++++++++++++-- .../frontend/src/components/TextInput.svelte | 35 +++++++- control/frontend/src/ts/api_handler.ts | 9 +++ 3 files changed, 112 insertions(+), 11 deletions(-) diff --git a/control/frontend/src/components/FileView.svelte b/control/frontend/src/components/FileView.svelte index 6a354df..1bdd9dd 100644 --- a/control/frontend/src/components/FileView.svelte +++ b/control/frontend/src/components/FileView.svelte @@ -34,7 +34,7 @@ import TextInput from './TextInput.svelte'; import { is_valid_name } from '../ts/utils'; import { displays, get_display_by_id, run_on_all_selected_displays } from '../ts/stores/displays'; - import { create_folders, delete_files } from '../ts/api_handler'; + import { create_folders, delete_files, rename_file } from '../ts/api_handler'; import { get } from 'svelte/store'; import HighlightedText from './HighlightedText.svelte'; @@ -61,12 +61,44 @@ display_id, $all_files ); - await create_folders(display.ip, path_data.existing, [...path_data.needed, current_name]); + await create_folders(display.ip, path_data.existing, [ + ...path_data.needed, + current_name.trim() + ]); } await update_current_folder_on_selected_displays(); popup_close_function(); } + async function edit_file_name(new_file_name: string) { + await run_for_selected_files_on_selected_displays(async (ip: string, file_names: string[]) => { + if (file_names.length !== 1) { + console.log('EEEERRRRROOOOOOR', file_names); + return; // Error + } + await rename_file(ip, $current_file_path, file_names[0], new_file_name); + }); + await update_current_folder_on_selected_displays(); + popup_close_function(); + } + + const show_edit_file_popup = () => { + const file = get_file_by_id($selected_file_ids[0], $all_files, $current_file_path); + if (!file) return; + const is_folder = file.type === 'inode/directory'; + const extension = is_folder ? '' : '.' + file.name.split('.').at(-1) || ''; + current_name = file.name.slice(0, file.name.length - extension.length); + current_valid = true; + popup_content = { + open: true, + snippet: edit_file_name_popup, + title: `${is_folder ? 'Ordner' : 'Datei'} umbenennen`, + title_icon: FolderPlus, + snippet_arg: extension, + closable: true + }; + }; + const show_new_folder_popup = () => { current_name = ''; current_valid = false; @@ -140,6 +172,41 @@ {/snippet} +{#snippet edit_file_name_popup(extension: string)} + { + if (input.startsWith('.')) return [false, 'Name darf nicht mit . beginnen']; + const trimmed_input = input.trim() + extension; + if (trimmed_input.length === 0 || trimmed_input.length > 50) + return [false, 'Ungültige Länge']; + if (!is_valid_name(trimmed_input)) return [false, 'Name enthält ungültige Zeichen']; + if ( + get_current_folder_elements($all_files, $current_file_path, $selected_display_ids).some( + (e) => + e.name === trimmed_input && + e.id !== get_file_by_id($selected_file_ids[0], $all_files, $current_file_path)?.id + ) + ) + return [false, 'Name bereits verwendet']; + return [true, 'Gültiger Name']; + }} + enter_mode="submit" + enter_function={() => edit_file_name(current_name.trim() + extension)} + {extension} + /> +
+ +
+{/snippet} + {#snippet delete_request_popup()}
{ await run_for_selected_files_on_selected_displays( async (ip: string, file_names: string[]) => { - delete_files(ip, $current_file_path, file_names); + await delete_files(ip, $current_file_path, file_names); } ); await update_current_folder_on_selected_displays(); - selected_file_ids.update(() => { - return []; - }); popup_close_function(); }}>Löschen @@ -257,6 +321,7 @@
diff --git a/control/frontend/src/components/TextInput.svelte b/control/frontend/src/components/TextInput.svelte index a4f11a4..4d1a082 100644 --- a/control/frontend/src/components/TextInput.svelte +++ b/control/frontend/src/components/TextInput.svelte @@ -13,6 +13,7 @@ placeholder = '', is_valid_function = null, focused_on_start = false, + extension = null, enter_mode = 'none', enter_function = null } = $props<{ @@ -24,6 +25,7 @@ placeholder?: string; is_valid_function?: ((input: string) => [boolean, string]) | null; focused_on_start?: boolean; + extension?: string | null; enter_mode?: 'none' | 'focus_next' | 'submit'; enter_function?: (() => void) | null; }>(); @@ -41,7 +43,7 @@ function get_highlighting_string(): string { if (!is_valid_function) return ''; if (current_valid) { - return 'focus:inset-ring-2 focus:inset-ring-green-400'; + return 'focus-within:inset-ring-2 focus-within:inset-ring-green-400'; } else { return 'inset-ring-2 inset-ring-red-400'; } @@ -80,7 +82,7 @@ }); -
+
{title}: @@ -94,7 +96,7 @@
{/if}
- + /> --> + + + +
{ + input_element.focus(); + }} + class="{bg} focus-within:{focus_bg} flex items-center rounded-xl {get_highlighting_string()} cursor-text" + > + + {#if extension} + + {extension} + + {/if} +
diff --git a/control/frontend/src/ts/api_handler.ts b/control/frontend/src/ts/api_handler.ts index 3386a4f..180c33e 100644 --- a/control/frontend/src/ts/api_handler.ts +++ b/control/frontend/src/ts/api_handler.ts @@ -112,6 +112,15 @@ export async function create_folders(ip: string, path: string, folder_names: str handle_shell_error(ip, json_response, command, true); } +export async function rename_file(ip: string, path: string, old_file_name: string, new_file_name: string): Promise { + const command: string = `cd ".${path}" && mv "${old_file_name}" "${new_file_name}"`; + + const raw_response = await run_shell_command(ip, command); + if (!raw_response.ok || !raw_response.json) return; + const json_response = raw_response.json as ShellCommandResponse; + handle_shell_error(ip, json_response, command, true); +} + export async function delete_files(ip: string, current_path: string, file_names: string[]): Promise { let command: string = `cd ".${current_path}"`; for (const file_name of file_names) {