fix(home): show file sizes in KB/MB/GB, never raw bytes

Per-row file sizes and the Files-card total-size meta both read as
human-readable units now. Smallest unit is KB even for sub-kilobyte
files (so ``538 B`` → ``0.5 KB``, ``4914 B`` → ``4.8 KB``), steps up
to MB at 1 MiB and GB at 1 GiB. Always one decimal place.

New module-level helper ``_format_size(int) -> str`` in ``_home.py``;
both the section meta (``1 file · 4.8 KB total``) and the per-row
``dt-file-size`` cell call it instead of the previous ad-hoc
``f"{n:,} B"`` formatter. Keeps the display consistent regardless of
file size — and keeps the GUI free of raw byte counts that nobody
needs to read.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-19 00:59:56 +00:00
parent 6703e2c15c
commit 4816da1ad6

View File

@@ -36,6 +36,24 @@ class _StashedUpload:
return self._data return self._data
def _format_size(n: int) -> str:
"""Human-readable byte count for file sizes shown in the GUI.
Bytes are never displayed — the smallest unit is KB, even for sub-
kilobyte files (e.g. ``0.5 KB`` for 512 bytes). Steps up to MB
once the count reaches 1 MiB, then to GB at 1 GiB. Always one
decimal place.
"""
KB = 1024
MB = 1024 * 1024
GB = 1024 * 1024 * 1024
if n < MB:
return f"{n / KB:.1f} KB"
if n < GB:
return f"{n / MB:.1f} MB"
return f"{n / GB:.1f} GB"
def _render_stats_overview(findings_by_file: dict) -> None: def _render_stats_overview(findings_by_file: dict) -> None:
"""4-card grid above the per-file findings — summarizes the run. """4-card grid above the per-file findings — summarizes the run.
@@ -224,13 +242,10 @@ def _home_page() -> None:
n_files = len(home_uploads) n_files = len(home_uploads)
if n_files: if n_files:
total_bytes = sum(meta["size"] for meta in home_uploads.values()) total_bytes = sum(meta["size"] for meta in home_uploads.values())
if total_bytes >= 1024:
total_label = f"{total_bytes / 1024:.1f} KB"
else:
total_label = f"{total_bytes:,} B"
files_word = "file" if n_files == 1 else "files" files_word = "file" if n_files == 1 else "files"
meta_html = ( meta_html = (
f'{n_files} {files_word} · {_html.escape(total_label)} total' f'{n_files} {files_word} · '
f'{_html.escape(_format_size(total_bytes))} total'
) )
else: else:
meta_html = "No files imported yet" meta_html = "No files imported yet"
@@ -275,7 +290,7 @@ def _home_page() -> None:
col_size.markdown( col_size.markdown(
f'<div style="text-align:right;">' f'<div style="text-align:right;">'
f'<span class="dt-file-size">' f'<span class="dt-file-size">'
f'{home_uploads[name]["size"]:,} B' f'{_html.escape(_format_size(home_uploads[name]["size"]))}'
'</span></div>', '</span></div>',
unsafe_allow_html=True, unsafe_allow_html=True,
) )