Repository navigation
Description
Drop Database in the playground's Storage Usage dialog is undone by the next store update, because it never clears the in-memory store. The button calls useAppStore.persist.clearStorage(), which deletes the IndexedDB key but leaves every saved instrument (and the stored API token) in the running store. The persist middleware writes the whole state back on every set, so the next keystroke, rebuild or Monaco marker update rewrites everything that was just "dropped". Meanwhile the selector keeps listing the saved instruments, and the dialog shows fresh usage figures after a fixed 2-second wait as if the drop had worked. Whether the data is really gone depends on whether the user happens to reload before touching anything. The button is also a one-click, irreversible action inside a dialog the user opened only to read storage figures, with no confirmation step, unlike Delete Instrument and Restore Defaults.
Where
apps/playground/src/components/Header/ActionsDropdown/StorageUsageDialog.tsx:62-73:
<Button
variant="danger"
onClick={() => {
useAppStore.persist.clearStorage();
setMessage(t({ en: 'Deleting...', fr: 'Suppression...' }));
void new Promise((resolve) => setTimeout(resolve, 2000)).then(() => {
setUpdateKey(updateKey + 1);
});
}}
>
{t({ en: 'Drop Database (Irreversible)', fr: 'Supprimer la base de données (Irréversible)' })}
</Button>Reproduce
- Click Create New Instrument and save an instrument named
Mine. - Open the actions menu, choose Storage Usage, and click Drop Database (Irreversible).
- Close the dialog, type one character in the editor, and reload.
Actual: Mine is still listed under Saved, both before and after the reload.
Expected: after the user confirms, Mine disappears from the selector at once and stays gone after a reload.
A node test of the store with a mocked idb-keyval confirms the mechanism: after clearStorage() the app key is gone, and the next set writes it back with every instrument.
Tests
Put the reset in a store action (for example dropDatabase) and test it in apps/playground/src/store/__tests__/index.test.ts: it('should clear saved instruments from memory when the database is dropped, so the next update cannot write them back').
E2E in testing/src/specs/playground.spec.ts: save an instrument, drop the database through the confirmation, type in the editor, reload, and assert that the instrument is not listed.
Suggested fix
Ask for confirmation first. Then reset the in-memory state (resetInstruments, resetSettings, and clear auth) before calling clearStorage(), or call clearStorage() and reload the page so nothing in memory can repopulate storage.
Activity
joshunrau commentedon Oct 26, 2026
Still reproduces on
main(d86740e). Nothing onmainhas touchedStorageUsageDialog.tsxorapps/playground/src/store/since this was filed, and no open PR fixes it.After the fix, Drop Database is Restore Defaults plus logout
Restore Defaults already resets memory (
apps/playground/src/components/Header/ActionsDropdown/RestoreDefaultsDialog.tsx:39-44), and persist then writes the defaults overapp. Once Drop Database resets memory too, the only thing it adds is forgetting the API token. That still justifies the button:apps/playground/src/store/slices/auth.slice.tshas onlyloginandrevalidateToken, so nothing else removes a stored token before it expires. Keep it, and have the confirmation list what goes: saved instruments, settings (including the API URL) and the login.Corrections to the suggested fix
set, so there is one write and no half-reset state. AdddropDatabasenext toresetInstrumentsininstrument.slice.ts, with its type instore/types.ts:instruments = defaultInstruments, fix: resolve 26 low-difficulty issues, one commit each #1825'sloadDefaultInstrument(state), defaultsettings,auth = null.defaultSettingsis module-private (apps/playground/src/store/slices/settings.slice.ts:7-9), so export it.clearStorage()call. The reset's own write leaves noSavedinstrument and no_accessTokeninapp, and the nextsetrewrites the key anyway.clearStorageis typed() => voidand does not return theremoveItempromise (zustand/esm/middleware.mjs:450-453). There is nothing to await beforelocation.reload(), and anysetthat lands before unload writes the key back.RestoreDefaultsDialogflow: confirm, run the action,addNotification({ type: 'success' }), close.updateKeyand theDeleting...message then go. New strings uset({ en, fr }).partialize(apps/playground/src/store/index.ts:77-82), the reset still writes the whole example catalog, so the Usage figure barely drops. Do not assert on it.Tests
apps/playground/src/store/slices/__tests__/instrument.slice.test.ts, not instore/__tests__/index.test.ts. That file mocksidb-keyvalwith plainvi.fn()s, so the test can parse the JSON invi.mocked(set).mock.lastCall. Afterlogin(token),dropDatabase()and one more update, memory and the writtenappboth have noSavedinstrument and no token.loginrunsjwtDecode, so the token needs a base64url JSON payload.Minewith Create New Instrument, as the reproduction does, not withgeneratePlaygroundURLas fix: resolve 26 low-difficulty issues, one commit each #1825's playground specs do. A share fragment stays in the address bar, so the reload imports the instrument again (Reloading a playground share link after editing its instrument adds a new copy on every load and switches away from the edits #1745) and the assertion fails even with the fix. The post-drop update can bePlaygroundPage.selectInstrument(...)(testing/src/pages/playground/index.page.ts:30-33), so no Monaco typing is needed. Add a case where cancelling the confirmation keepsMine.CloneButton.tsx:40-42,ActionsDropdown.tsx:31-33) have no accessible name until Playground icon-only buttons have no accessible names, and editor tabs cannot be closed from the keyboard #1763.testing/AGENTS.mdasks fordata-testidselectors, so add one to each, asPreviewFrame.tsx:65does, rather than wait for Playground icon-only buttons have no accessible names, and editor tabs cannot be closed from the keyboard #1763.Order
This touches the slices,
types.tsandStorageUsageDialog.tsx, notstore/index.ts, and with noclearStorage()call it does not depend on how #1756 changes persistence. It needs only #1825, and can land before or after #1737 and #1756. #1825, #1817 and #1660 all edittesting/src/specs/playground.spec.ts.Triage note written with Claude Code. Code references point at
main@d86740e.