// AUDIO_HAXOR — WALKTHROUGH

Tutorial index Docs hub
Progress
14 / 19

14.Scan history & diffs — F3

A merged sidebar of every scan run across every inventory type, a typed detail pane per run, and a diff view showing what was added or removed between two runs.

History tab with merged scan list on the left and detail pane on the right
assets/history.png · History tab

Layout

frontend/js/history.js. Two panes:

  • Sidebar (.history-sidebar) — scrollable list of all scan records, merged from every inventory type. Header has "Scan History" label and a Clear All button.
  • Detail pane (#historyDetail) — right side, shows the selected run's full payload with a delete button and a compare dropdown.

Sidebar items

Each history row carries the following, built by buildHistorySidebarItemHtml(s) (~line 137):

  • Timestamp — absolute date/time (e.g. "Mar 10 2026 3:45 PM").
  • Scan type tag — colored label: Plugins, Samples, DAW, Presets, PDF, MIDI.
  • Count — "42 plugins", "1,204 samples", etc.
  • Relative time — "2 hours ago".
  • Roots hint — hover to see the full root paths that were scanned.
  • Selected state.selected class on the active row.

The sidebar renders in chunks of HISTORY_SIDEBAR_CHUNK = 100 to stay fast even when you have hundreds of runs.

Sidebar data sources

The sidebar is a merge-sort of six per-type lists:

  • historyScanList — plugins (from history_get_scans).
  • historyAudioScanList — audio (from audio_history_get_scans).
  • historyDawScanList — DAW (from daw_history_get_scans).
  • historyPresetScanList — presets.
  • historyPdfScanList — PDFs.
  • historyMidiScanList — MIDI.

fetchHistoryListsAndRender() (~line 75) fetches all six in parallel, merges into historyMergedList[], sorts by timestamp (newest first), and hands the result to the renderer. Selecting any row calls into a type-specific select*Scan() function that fetches the payload and populates the detail pane.

Detail pane — per-type

Each scan type has its own renderer but they share a common layout:

  • Date header — weekday, month, day, year.
  • Meta line — e.g. for plugin scans: "Scan: 3:45 PM, 412 plugins (VST2: 184, VST3: 192, CLAP: 18, AU: 18)". For audio scans: format counts instead of plugin type breakdown.
  • Scanned roots — code blocks listing the root directories.
  • Delete buttondeleteScanEntry, removes this specific run from the database.
  • Compare dropdown#compareSelect, lists every other scan of the same type with its count; pair with the Compare button (runDiff).
  • Diff results#diffResults container, filled by the diff call.
  • Full item list — scrollable, lazy-loads 200 rows at a time. Columns differ per type:
    • Plugins: type badge · name · manufacturer · size · open-folder.
    • Samples: format badge · name · size · open-folder.
    • DAW: format badge · name · size · date · open-folder.
    • Presets: format badge · name · size · open-folder.
    • PDFs: name · size · open-file.
    • MIDI: name · size · duration · open-file.

Diffs

Select a reference run in the compare dropdown and click Compare. The frontend calls the type-specific diff IPC:

  • history_diff(oldId, newId) — plugins.
  • audio_history_diff(oldId, newId) — samples.
  • daw_history_diff(oldId, newId) — DAW.
  • preset_history_diff, pdf_history_diff, midi_history_diff.

Each returns arrays of added and removed items. The UI renders two colored sections:

  • Added.diff-section.diff-added — count badge + list.
  • Removed.diff-section.diff-removed — count badge + list.

If both arrays are empty, the pane shows a neutral "no differences" message via historyDiffMatchHtml().

Managing the archive

  • Delete one run — the red button in the detail pane.
  • Clear all history of one type — from the detail pane's controls or the per-tab settings.
  • Clear all history (every type) — Settings → Clear all history or the sidebar's Clear All button.
  • Automatic pruning — Settings → Prune old scan snapshots + Scan history to keep. On startup, runs beyond the last N per scanner are deleted.

Count field compatibility

Scan records have two possible count field shapes — legacy snake_case (plugin_count, sample_count, project_count, etc.) and current camelCase (pluginCount, sampleCount, projectCount, etc.). The helper historyScanCountField(s, camelKey, snakeKey) (~line 24) reads either format so upgraded databases keep rendering without migration.

TipDiffs are the fastest way to audit a plugin upgrade. Scan once before installing a bundle, scan again after, and compare the two runs — every new plugin shows in the Added section, every removed one in the Removed section. Same works for samples after an SD-card import.