""" FileRecord: one row per file under review. Both the GUI and the batch/ spreadsheet front end read and write the same fields, so nothing about a file's state is front-end-specific. Every editable field defaults to "no change" (current filename, current folder) when a record is first created — so a file you never touch in review simply stays exactly as it is. Nothing is lost by omission. """ from dataclasses import dataclass, field from pathlib import Path from typing import List @dataclass class FileRecord: path: Path # current absolute path on disk root: Path # vault root this file was scanned under filename: str = "" # current filename, including extension ext: str = "" fs_date: str = "" # best-guess filesystem date — a starting # point only, never treated as authoritative name_matches_convention: bool = False near_miss: bool = False # matched a "close but not quite" date format # --- Editable fields --- date_override: str = "" # what actually goes in the filename topic: str = "" subtopic: str = "" extra: str = "" more: str = "" version: str = "" dest_folder: str = "" # relative to root keep_filename: bool = False # if True, move only — never rebuild the name. # Defaults to True for files that already match # the convention, so opening one to move it # doesn't blank out a name that was already fine. suggested_folders: List[str] = field(default_factory=list) # pending -> not yet reviewed | confirmed -> ready for apply_batch # skip -> deliberately left alone | done -> already applied status: str = "pending" @property def identity(self) -> str: """Stable across rename/move — see core.identity. Use this, not rel_path, as the key for anything that needs to survive a file actually being moved (e.g. resuming progress across sessions).""" from .identity import file_identity return file_identity(self.path) @property def rel_path(self) -> str: return str(self.path.relative_to(self.root)) @property def current_folder(self) -> str: return str(self.path.parent.relative_to(self.root)) @property def new_filename_preview(self) -> str: if self.keep_filename: return self.filename from .sanitiser import build_filename return build_filename( date=self.date_override or self.fs_date, topic=self.topic, subtopic=self.subtopic, extra=self.extra, more=self.more, version=self.version, ext=self.ext, )