feat(dev-tools): persist last query + unify theming across dev-tool portlets (#36692) - #36781
feat(dev-tools): persist last query + unify theming across dev-tool portlets (#36692)#36781AP2300 wants to merge 1 commit into
Conversation
… portlets
- Add shared `withPersistedQuery` SignalStore feature + pure helpers in
`libs/data-access/dot-localstorage/` — hydrate on init, debounced write
(300ms), and `clearPersistedQuery()` method backed by
`dotcms.devtools.{portletKey}.lastQuery`.
- Wire the feature into `dot-query-tool`, `dot-es-search`, and
`dot-velocity-playground` stores; add a "Clear query" button to each
editor's panel header (`pi-eraser` icon, disabled-when-empty).
- Remove the hardcoded dark Monaco theme from `dot-velocity-playground`;
keep the VTL syntax tokenizer. Editor now inherits the shared light
theme (`vs`) used by the other two dev tools.
- Drop the implicit "code = history[0] on init" in velocity — persisted
query key is the single source of truth per AC.
- Add i18n keys `queryTool.action.clearQuery`, `esSearch.action.clearQuery`,
`velocityPlayground.action.clearQuery`.
- Unit tests for utils, the feature (with fake-timer debounce), and each
store's hydrate + clear integration.
Fixes #36692
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
c7124c7 to
547a1b6
Compare
| * fallback in non-browser environments, when the key is missing, or when the | ||
| * payload can't be parsed. | ||
| */ | ||
| export const readJson = <T>(key: string, fallback: T): T => { |
There was a problem hiding this comment.
These three helpers (readJson / writeJson / removeKey) already exist in libs/portlets/dot-velocity-playground/src/lib/dot-velocity-playground.utils.ts (lines 28-57) with identical implementations — same SSR guard, same try/catch, same JSON parse/stringify.
Since one AC of this PR is "Shared persistence helper in libs/data-access/ (not duplicated)", it would be worth finishing the consolidation: keep the copies here as the single source, drop them from the velocity utils, and have the velocity store import readJson / writeJson / removeKey from @dotcms/data-access for its HISTORY / SPLITTER / WRAP keys. Otherwise the same three functions live in two places inside the very portlet the AC targets.
| * localStorage entry. The debounced-write effect will observe the | ||
| * empty value but the removeKey call has already cleared storage. | ||
| */ | ||
| clearPersistedQuery(): void { |
There was a problem hiding this comment.
Small race worth double-checking: the state change here (patchField(store, '')) re-fires the tracked effect below, which schedules a setTimeout(() => writeJson(storageKey, ''), 300). 300 ms later, writeJson writes "" (JSON-encoded empty string) back to storage — the entry removeKey just deleted gets re-created.
User-visible impact is small (on reload, stored.length > 0 is false → initial state kept), but it contradicts the docstring's "removeKey call has already cleared storage" and the unit test's getItem(persistedKey) === null assertion. The test passes only because it doesn't advanceTimersByTime(300) after clearPersistedQuery().
Two-line fix inside the effect works — skip the write when value === '' (and removeKey there too for safety) — plus a regression test that advances timers past the debounce window.
| return; | ||
| } | ||
|
|
||
| const timer = setTimeout(() => writeJson(storageKey, value), debounceMs); |
There was a problem hiding this comment.
try to avoid use setTimeout here
Summary
Closes #36692. Two consistency gaps across the migrated dev-tool portlets (
dot-query-tool,dot-es-search,dot-velocity-playground), addressed together.withPersistedQuery()SignalStore feature inlibs/data-access/dot-localstorage/(backed by purereadJson/writeJson/removeKeyhelpers, SSR-safe, error-swallowing). Storage key convention:dotcms.devtools.{portletKey}.lastQuery. Hydrates on init, debounces writes at 300 ms, exposes aclearPersistedQuery()action. Wired into all three stores.pi pi-eraser, tooltip via| dm, disabled-when-empty, no confirmation — conscious action per issue discussion). Sits inline next to Help so it doesn't fight PrimeNG'spTemplate="icons"slot on portlets that also have a Wrap-code checkbox.dot-velocity-playground— kept the VTL syntax tokenizer, dropped the hardcodeddot-velocity-darktheme. Editor now inheritsDOT_MONACO_BASE_OPTIONS'theme: 'vs', the same light theme used by the other two dev tools.codefromhistory[0]" was a duplicate persistence path for the query. Removed; the new persisted-query key is now the single source of truth. History remains for the multi-entry selector.queryTool.action.clearQuery,esSearch.action.clearQuery,velocityPlayground.action.clearQuerytoLanguage.properties.Acceptance criteria coverage
dot-velocity-playground(theme definition +defineTheme/setThemecalls +theme:bindings)libs/data-access/(not duplicated)dotcms.devtools.{portlet}.lastQueryTest plan
{not-json) and confirm the portlet loads with an empty editor rather than erroring🤖 Generated with Claude Code