diff --git a/popup.html b/popup.html index 353ddc8..0d12463 100644 --- a/popup.html +++ b/popup.html @@ -139,6 +139,9 @@ diff --git a/src/popup/popup.css b/src/popup/popup.css index 98d449d..1730edf 100644 --- a/src/popup/popup.css +++ b/src/popup/popup.css @@ -696,6 +696,16 @@ actor-typeahead { position: relative; display: flex; } +/* What the last debug action did, said in the menu that started it: the two + that fetch have no other place to report, and the popup's status pills are + redrawn from page state rather than written to. */ +.menu-note[hidden] { display: none; } +.menu-note { + margin: 4px 8px 2px; + color: var(--muted); + font-size: 12px; +} + /* Nothing sits below the footer for a menu to drop into, so this one rises. */ .menu.up { top: auto; diff --git a/src/popup/popup.ts b/src/popup/popup.ts index fcbfa8c..6c40604 100644 --- a/src/popup/popup.ts +++ b/src/popup/popup.ts @@ -720,12 +720,30 @@ $('feedback-cancel').addEventListener('click', () => setFeedbackPanel(false)) // --- debug menu (dev channel only) --- // -// Where dev-only tools go. Today it holds one: the welcome page, which Chrome -// otherwise shows exactly once per install (src/background.ts) and which is -// therefore impossible to look at again without reinstalling the extension. +// Where dev-only tools go, all of them reaching something a released build +// deliberately makes unreachable: +// +// - the welcome page, which Chrome otherwise shows exactly once per install +// (src/background.ts) and which is therefore impossible to look at again +// without reinstalling the extension; +// - a re-scan, which the header's Refresh button also does but which lives +// inside the publication section, so it is hidden on exactly the pages a +// re-scan is most wanted for: the ones detection found nothing on; +// - dropping every cached read, which nothing else does at all. Refresh +// bypasses the caches on the path it walks; this empties them, so the +// next read of anything — on any tab, from a cold worker — runs the miss +// path a user with a warm cache would never see. function setDebugMenu(open: boolean) { $('debug-menu').hidden = !open $('debug-open').setAttribute('aria-expanded', String(open)) + // A result belongs to the action that produced it, not to the next opening. + if (open) debugNote('') +} + +/** What the last debug action did. Cleared whenever the menu opens. */ +function debugNote(text: string) { + $('debug-note').textContent = text + $('debug-note').hidden = !text } if (isDevChannel()) $('debug-area').hidden = false @@ -737,6 +755,31 @@ $('debug-open').addEventListener('click', (e) => { $('debug-welcome').addEventListener('click', () => openUrl(welcomeUrl())) +// Both of the below stop the click reaching the document-level close-all +// handler: the menu is where the answer is written, so it has to still be +// open when the answer arrives. +$('debug-rescan').addEventListener('click', async (e) => { + e.stopPropagation() + debugNote('Re-scanning…') + await loadState(true) + debugNote(requestFailed ? 'Re-scan failed; see the console.' : 'Re-scanned.') +}) + +// Only drops. Re-scanning from here would refill on the way out, and watching +// a cold read happen is the reason to empty the caches in the first place — +// so which read runs next is left to whoever asked. +$('debug-drop-cache').addEventListener('click', async (e) => { + e.stopPropagation() + debugNote('Dropping…') + try { + const { dropped } = await send<{ dropped: number }>({ type: 'drop-caches' }) + debugNote(`Dropped ${dropped} ${dropped === 1 ? 'entry' : 'entries'}.`) + } catch (err) { + console.debug('[substandard] drop-caches failed', err) + debugNote(err instanceof Error ? err.message : String(err)) + } +}) + $('feedback-form').addEventListener('submit', async (e) => { e.preventDefault() const note = $('feedback-note')