mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-10-28 10:47:17 +00:00
clarify name handling
This commit is contained in:
1 parent
45f877ec78
commit
3f8e2a0c56
14 files changed
+204
-251
No files matched your search
@@ -3,6 +3,7 @@
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Textarea } from '$lib/components/ui/textarea';
|
||||
import { Label } from '$lib/components/ui/label/index.js';
|
||||
import { Checkbox } from '$lib/components/ui/checkbox';
|
||||
import * as Popover from '$lib/components/ui/popover';
|
||||
import { Save } from '@lucide/svelte';
|
||||
import { i18n } from '$lib/i18n/i18n.svelte';
|
||||
@@ -30,9 +31,48 @@
|
||||
node.type === 'file' ? (fileState.structure.desc ?? '') : (path?.desc ?? '')
|
||||
);
|
||||
|
||||
const { workspace } = engine;
|
||||
|
||||
// the name of the file on the disk, without its extension (the desktop app), which is not the
|
||||
// name of the file: it can be renamed with it, which is not undone
|
||||
let fileName = $derived.by(() => {
|
||||
if (node.type !== 'file') return undefined;
|
||||
const path = $workspace?.files[node.fileId]?.path;
|
||||
return path
|
||||
?.split(/[\\/]/)
|
||||
.pop()
|
||||
?.replace(/\.[^.]*$/, '');
|
||||
});
|
||||
// asked only when the name is changed, and proposed then
|
||||
let renamed = $derived(node.type === 'file' && name !== fileState.structure.name);
|
||||
let renameFile = $state(true);
|
||||
|
||||
async function save() {
|
||||
// closes the dialog now: `open` follows `editMetadata`, and the change of the file would
|
||||
// open the dialog again before the effect below has reset it
|
||||
editMetadata.current = false;
|
||||
open = false;
|
||||
// the file on the disk first: nothing is changed if it cannot be renamed (the name of
|
||||
// another file, for instance)
|
||||
if (
|
||||
renamed &&
|
||||
renameFile &&
|
||||
fileName !== undefined &&
|
||||
fileName !== name &&
|
||||
node.type === 'file'
|
||||
) {
|
||||
if (!(await engine.renameFile(node.fileId, name))) {
|
||||
showEngineError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
engine.metadata(name, description);
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
if (!open) {
|
||||
editMetadata.current = false;
|
||||
renameFile = true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -44,22 +84,13 @@
|
||||
<Input bind:value={name} id="name" class="font-semibold h-8" />
|
||||
<Label for="description">{i18n._('menu.metadata.description')}</Label>
|
||||
<Textarea bind:value={description} id="description" />
|
||||
<Button
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
// closes the dialog now: `open` follows `editMetadata`, and the change of the file
|
||||
// would open the dialog again before the effect below has reset it
|
||||
editMetadata.current = false;
|
||||
open = false;
|
||||
// the metadata of the selected elements are changed. In the desktop app, a file on
|
||||
// the disk is renamed with it, which is refused if the name is the one of another
|
||||
engine.metadata(name, description).then((changed) => {
|
||||
if (!changed) {
|
||||
showEngineError();
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
{#if fileName !== undefined && renamed}
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<Checkbox id="rename-file" bind:checked={renameFile} class="scale-90" />
|
||||
<Label for="rename-file">{i18n._('menu.metadata.rename_file')}</Label>
|
||||
</div>
|
||||
{/if}
|
||||
<Button variant="outline" onclick={save}>
|
||||
<Save size="16" />
|
||||
{i18n._('menu.metadata.save')}
|
||||
</Button>
|
||||
|
||||
@@ -228,7 +228,8 @@ export async function createTauriBackend(): Promise<Backend> {
|
||||
openUrl: (url) => invoke('open_url', { url }),
|
||||
newFile: (name, folder, route) => invoke<Outcome>('new_file', { name, folder, route }),
|
||||
createFolder: (parent, name) => invoke<string>('create_folder', { parent, name }),
|
||||
renamePath: (path, name) => invoke<Outcome>('rename_path', { path, name }),
|
||||
renamePath: (path, name) => invoke('rename_path', { path, name }),
|
||||
renameFile: (fileId, name) => invoke<boolean>('rename_file', { fileId, name }),
|
||||
movePaths: (paths, folder) => invoke('move_paths', { paths, folder }),
|
||||
deletePaths: (paths) => invoke<Outcome>('delete_paths', { paths }),
|
||||
revealPath: (path) => invoke('reveal_path', { path }),
|
||||
|
||||
@@ -108,10 +108,15 @@ export interface DesktopFiles {
|
||||
/** Makes a folder in a folder of the open folder (numbered if the name is taken): its path. */
|
||||
createFolder(parent: string, name: string): Promise<string>;
|
||||
/**
|
||||
* Renames a file or a folder of the open folder. An open file is renamed like in its info (it
|
||||
* is selected), which can be undone.
|
||||
* Renames a file or a folder of the open folder, on the disk only (an open file keeps its name).
|
||||
* Not undoable.
|
||||
*/
|
||||
renamePath(path: string, name: string): Promise<Outcome>;
|
||||
renamePath(path: string, name: string): Promise<void>;
|
||||
/**
|
||||
* Renames the file on the disk of an open file, next to where it is; its name in the engine
|
||||
* stays. Not undoable. False for a file that is not on the disk.
|
||||
*/
|
||||
renameFile(fileId: string, name: string): Promise<boolean>;
|
||||
/** Moves files and folders of the open folder into a folder of it. */
|
||||
movePaths(paths: string[], folder: string): Promise<void>;
|
||||
/**
|
||||
|
||||
@@ -626,9 +626,21 @@ class Engine {
|
||||
.value;
|
||||
}
|
||||
|
||||
/** Renames a file or a folder of the open folder. Resolves to whether it was done. */
|
||||
/**
|
||||
* Renames a file or a folder of the open folder, on the disk only: an open file keeps its name.
|
||||
* Resolves to whether it was done.
|
||||
*/
|
||||
async renamePath(path: string, name: string): Promise<boolean> {
|
||||
return this.desktopRun((b) => b.desktop!.renamePath(path, name), true);
|
||||
return (await this.desktopCall((desktop) => desktop.renamePath(path, name), true)).done;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the file on the disk of an open file (the desktop app), which is not undoable: its
|
||||
* name in the engine stays (see `metadata`). Resolves to whether it was done; nothing is done
|
||||
* for a file that is not on the disk.
|
||||
*/
|
||||
async renameFile(fileId: string, name: string): Promise<boolean> {
|
||||
return (await this.desktopCall((desktop) => desktop.renameFile(fileId, name), true)).done;
|
||||
}
|
||||
|
||||
/** Moves files and folders of the open folder into a folder of it. */
|
||||
|
||||
@@ -100,6 +100,7 @@
|
||||
"name": "Name",
|
||||
"description": "Description",
|
||||
"save": "Save",
|
||||
"rename_file": "Rename the file on disk",
|
||||
"name_taken": "A file with this name already exists in the folder.",
|
||||
"rename_failed": "The file could not be renamed."
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user