Add SFV panel: compute/verify CRC32/MD5/SHA1 checksums, .sfv/.md5/.sha1 sidecar files
Fully local feature - no network access, no credentials. New aurora-curator-core::sfv module streams file hashing in 64KB chunks and handles both the traditional .sfv format (CRC32, "name checksum" layout) and the GNU coreutils md5sum/sha1sum sidecar convention (.md5/.sha1, "checksum name" layout), dispatched on a shared ChecksumKind enum. New src-tauri/src/sfv.rs wraps it in three Tauri commands - compute_checksums (per-file error isolation), save_checksum_file (native Save dialog), and verify_checksum_file (resolves each entry against the checksum file's own parent directory, reports OK/Mismatch/Missing per entry). New SfvPanel.tsx/.css wires it all into the sidebar's SFV screen - load files, pick a checksum type, Compute, Save, or Verify against an existing checksum file. 14 new core-crate tests + 1 new src-tauri test, all passing (workspace: 160/160). Verified end-to-end with a 22-check Playwright script against npm run dev.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
.sfv-panel {
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
padding: 18px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.sfv-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
flex-wrap: wrap;
|
||||
background: var(--card);
|
||||
border: 1px solid var(--surface-deep);
|
||||
border-radius: 12px;
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.sfv-loaded-count {
|
||||
font-size: 12px;
|
||||
color: var(--muted-text);
|
||||
}
|
||||
|
||||
.sfv-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.sfv-results {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.sfv-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
background: var(--card);
|
||||
border: 1px solid var(--surface-deep);
|
||||
border-radius: 10px;
|
||||
padding: 9px 12px;
|
||||
}
|
||||
|
||||
.sfv-row-name {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 12.5px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sfv-row-checksum {
|
||||
flex: 0 0 auto;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
font-size: 12px;
|
||||
color: var(--aurora-cyan);
|
||||
}
|
||||
|
||||
.sfv-row-checksum-muted {
|
||||
color: var(--muted-text);
|
||||
}
|
||||
|
||||
.sfv-badge {
|
||||
flex: 0 0 auto;
|
||||
font-size: 10.5px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
border-radius: 999px;
|
||||
padding: 3px 9px;
|
||||
}
|
||||
|
||||
.sfv-badge-ok {
|
||||
background: rgba(52, 211, 153, 0.16);
|
||||
color: #34d399;
|
||||
}
|
||||
|
||||
.sfv-badge-mismatch {
|
||||
background: rgba(248, 113, 113, 0.16);
|
||||
color: #f87171;
|
||||
}
|
||||
|
||||
.sfv-badge-missing {
|
||||
background: rgba(250, 204, 21, 0.16);
|
||||
color: #facc15;
|
||||
}
|
||||
|
||||
.sfv-empty-note {
|
||||
color: var(--muted-text);
|
||||
font-size: 12.5px;
|
||||
padding: 8px 2px;
|
||||
}
|
||||
|
||||
.sfv-status {
|
||||
font-size: 12px;
|
||||
color: var(--aurora-cyan);
|
||||
}
|
||||
Reference in New Issue
Block a user