Skip to content

Registry View: inline edit, rename, delete with success/error feedback#818

Open
kanhaiyaXITE wants to merge 1 commit into
rokucommunity:masterfrom
kanhaiyaXITE:feat/registry-add-rename-and-errors
Open

Registry View: inline edit, rename, delete with success/error feedback#818
kanhaiyaXITE wants to merge 1 commit into
rokucommunity:masterfrom
kanhaiyaXITE:feat/registry-add-rename-and-errors

Conversation

@kanhaiyaXITE

Copy link
Copy Markdown
Contributor

Summary

Makes the Roku Registry side panel actually editable end-to-end:

  • Double-click a value to edit it in place. Enter / click-away commits; Escape cancels.
  • Double-click a key name (depth ≥ 1) to rename it. Section keys at depth 0 stay non-renamable since they're app namespaces.
  • Trash icon on hover for every row: deletes a leaf key, a nested entry, or a whole section.
  • After each write, the affected cell flashes green on success / red on failure for ~1.6s. Write failures also surface as a VSCode error toast with the underlying message.

The initial registry read is now also wrapped in try/finally so the loader can no longer get stuck spinning if readRegistry rejects — that case now resolves to a toast + empty state.

Motivation

The rewritten Registry View from #784 + the Svelte 5 compat fix from #808 give us a working panel, but it's been read-only in practice:

  • The previous Edit / Copy / Trash icons didn't visibly do much for users who weren't expecting hover-only controls.
  • More importantly, nested edits were silently incorrect. Roku's raw registry API holds two levels of string keys (section → key → string), but applications routinely store JSON-encoded objects as the string at level 2 — so the data users actually see and care about can be N levels deep. formatValues() parses those strings back into a tree for display. The old code wrote the leaf's local key at the top of the section instead of mutating the enclosing JSON blob, so editing e.g. com.xite.Xite.staging.screen_show_counts.get_started from 2 to 0 added a new get_started: 0 sibling next to screen_show_counts instead of updating the nested value. The same bug affected nested delete.

What changed

Webview (webviews/src/views/RokuRegistryView/)

  • RegistryNode.svelte — replaced the per-row Edit/Copy buttons with a dblclick gesture on key + value spans; bound the cells to a context-driven ack store for the success/error flash; trash icon stays as the one always-visible action.
  • RegistryTree.svelte — handler set is now valueChanged, keyRenamed, deleteItem, deleteSection. Adds cloneTopLevel / navigateToParent helpers that share the nested-write plumbing across the three mutating handlers. coerceNestedValue preserves number / boolean / null primitives through the JSON round-trip so re-stringification doesn't change types. All write paths use a single error-toast helper.
  • RokuRegistryView.svelteloadRegistry() wrapper around readRegistry() with try/finally; the spinner can no longer hang.

N-level write support

RegistryNode exposes two extra props through the recursive svelte:self:

  • topLevelKey — the depth-1 registry key whose JSON-encoded string value owns this subtree.
  • pathInTopLevel: string[] — the path inside the parsed object, inclusive of the current leaf. No length cap — works at any depth.

RegistryTree branches on pathInTopLevel.length:

  • 0 → depth-1 edit/rename/delete. Same merge-semantic writeRegistry as before ({ key: null, newKey: value } etc.).
  • ≥ 1 → deep-clone the parsed top-level object, walk the full pathInTopLevel to the leaf's parent, apply the mutation, re-stringify, and write the whole blob back under the original top-level key.

The only hard requirement is the one Roku itself imposes: at the wire, the level-2 value must be a string, so any nested mutation is followed by JSON.stringify of the whole subtree.

Extension host

  • src/viewProviders/ViewProviderCommand.ts — one new enum entry, showErrorMessage.
  • src/viewProviders/BaseWebviewViewProvider.ts — one new else-if in the central message router, alongside setVscodeContext / getVscodeContext / sendMessageToWebviews. Calls vscode.window.showErrorMessage(message.context.message).
  • webviews/src/ExtensionIntermediary.ts — one new showErrorMessage(message) helper that posts the command.

No changes to the RTA / ODC pipeline — every mutation goes through the existing writeRegistry / deleteRegistrySections calls.

Test plan

Manual verification via the Extension Development Host against a real Roku device with the on-device component active:

  • Double-click a depth-1 value (e.g. access_token) → edit, Enter → device updates, cell flashes green.
  • Double-click a depth-1 key → rename → device shows the new key with the same value, key cell flashes green.
  • Double-click a depth-2 nested value (e.g. screen_show_counts.get_started, 2 → 0) → updates the nested entry only; no new top-level sibling appears.
  • Rename a depth-2 nested key → swaps the key inside the parsed object, leaves siblings intact.
  • Deeper-than-2 paths (a.b.c.d.…) work the same way — pathInTopLevel carries the full chain.
  • Trash a leaf, a nested entry, and a whole section.
  • Disconnect the Roku → trigger any write → VSCode error toast appears, cell flashes red.
  • Disconnect the Roku → reopen the panel → "Failed to read registry: …" toast + empty state (no infinite spinner).
  • Cancel paths: start an edit, press Escape → original value restored, no write fires.
  • Number / boolean / null values inside nested objects round-trip through edit + re-stringify with their original primitive type.

Out of scope

  • Adding new keys or new sections from the panel — not requested, keeping the surface minimal.
  • Touching the existing Export / Import / Clear registry commands in RokuRegistryViewProvider.ts.
  • Type coercion for depth-1 edits: depth-1 leaves continue to write as strings, matching prior behavior on the device. Only depth-2+ edits inside JSON-stringified values use the primitive-preserving coercion.

Repro of the nested-write bug on master

If you want to confirm the bug exists today (before this PR):

  1. Run a channel that writes a JSON-encoded object into its registry (anything storing counters or maps).
  2. Open the Roku Registry panel.
  3. Expand the parsed section value; you'll see nested keys like screen_show_counts.get_started: 2.
  4. Hover the nested row → click Edit → change 2 to 0 → confirm.
  5. Refresh — observe a new get_started: 0 at the top level of the section, with the original nested value untouched.

This PR fixes that path.

Builds on PR rokucommunity#808's Svelte 5 fix to make the Roku Registry side-panel
actually editable end-to-end.

UI:
- Double-click a value cell to edit; Enter or click-away commits;
  Escape cancels.
- Double-click a key name (depth >= 1) to rename. Section keys at
  depth 0 stay non-renamable since they're app namespaces.
- Trash icon visible on hover for every row: deletes a leaf key, a
  nested entry, or a whole section.

Correct nested writes:
- The registry is a 2-level store (section -> key -> string) but
  formatValues() recursively JSON.parses string values into a tree
  that often goes 3+ levels deep. Writing a leaf's local key at the
  top of the section creates a sibling instead of mutating the
  enclosing JSON blob, which is what the rewritten Registry View was
  doing before this change (you can repro on master by editing e.g.
  com.xite.Xite.staging.screen_show_counts.get_started).
- RegistryNode now threads `topLevelKey` + `pathInTopLevel` through
  the recursive svelte:self. RegistryTree branches on
  pathInTopLevel.length: depth-1 edits/renames/deletes use the
  existing merge-semantic writeRegistry; deeper edits deep-clone the
  parsed top-level object, apply the mutation, and write back the
  re-stringified blob under the original top-level key.
- coerceNestedValue preserves number/boolean/null primitives through
  the round-trip so re-stringification doesn't silently change types.

Feedback:
- A new ViewProviderCommand.showErrorMessage, routed in
  BaseWebviewViewProvider alongside setVscodeContext/getVscodeContext,
  lets the webview ask the host to show a vscode error toast. Used
  for all write failures and for the initial registry read.
- The two readRegistry callers in RokuRegistryView.svelte are wrapped
  in try/finally so the loader always clears -- previously a
  rejected read would leave the panel spinning forever.
- A Svelte context store from RegistryTree -> RegistryNode pushes an
  ack signal after each write; the matching cell briefly flashes
  green on success or red on failure (~1.6s CSS animation). On
  delete success the row disappears so no flash is fired.

No extension-host ODC pipeline changes. All edits go through the
existing writeRegistry / deleteRegistrySections merge semantics.
@triwav triwav added the create-vsix PRs with this tag will trigger a vsix build on vscode-brightscript-language for every push label Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

create-vsix PRs with this tag will trigger a vsix build on vscode-brightscript-language for every push

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants