Add Move/Copy/Symlink rename actions, with undo support for all three

- renamr-core::rename: new RenameAction enum (Move/Copy/Symlink, default Move,
  mirroring net.filebot.cli.CmdlineOperations's --action modes). execute_renames() now
  takes an action applied to the whole batch. Copy uses fs::copy (source untouched);
  Symlink uses std::os::unix::fs::symlink / std::os::windows::fs::symlink_file behind a
  cfg(unix)/cfg(windows) split. Same conflict policy (skip, never overwrite) and
  auto-created destination folders apply to all three actions. 8 new tests.
- renamr-core::history: HistoryBatch now records which action produced it
  (#[serde(default)] so old history.json entries - all implicitly Move - still
  deserialize). revert_one() branches on it: Move still moves the file back; Copy/
  Symlink undo by deleting the copy/symlink (using symlink_metadata so a broken link is
  still recognized as present and removable) - the original was never touched by those
  actions, so there's nothing to move back. 3 new tests.
- src-tauri: execute_rename command takes the chosen action and threads it through to
  both execute_renames and record_batch.
- Frontend: a Move/Copy/Symlink segmented selector in the "Confirm Rename" modal
  (remembered across modal opens, defaults to Move), action-aware subtitle/button
  copy, and a status message using the right verb (Renamed/Copied/Symlinked). Only Move
  reconciles a loaded item's id/name/bindings to the new path afterward, since Copy/
  Symlink leave the source file exactly where it was. History panel now shows a Copy/
  Symlink badge on non-Move batches and explains what Undo does for each.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
Renamr Scaffold
2026-08-29 04:31:16 +00:00
co-authored by Claude Sonnet 5
parent aab8e28246
commit fd4e6f66f0
7 changed files with 546 additions and 127 deletions
+38
View File
@@ -459,6 +459,44 @@
color: var(--aurora-cyan);
}
.action-segmented {
display: flex;
gap: 4px;
margin: 2px 0 12px;
padding: 3px;
background: var(--surface);
border: 1px solid var(--surface-deep);
border-radius: 10px;
}
.action-segmented-option {
all: unset;
box-sizing: border-box;
flex: 1 1 0;
text-align: center;
padding: 7px 0;
border-radius: 7px;
font-size: 12.5px;
font-weight: 600;
color: var(--muted-text);
cursor: pointer;
}
.action-segmented-option:hover {
color: var(--text);
}
.action-segmented-option.selected {
background: var(--aurora-green);
color: var(--dock-deep);
}
.action-segmented-option:disabled {
opacity: 0.6;
cursor: default;
pointer-events: none;
}
.modal-field-label {
display: block;
font-size: 11px;