Skip to content

feat(store): copy the state and a change's diff - #269

Merged
erkamyaman merged 3 commits into
mainfrom
store/copy-json
Oct 11, 2026
Merged

erkamyaman merged 3 commits into
mainfrom
store/copy-json

Conversation

@erkamyaman

@erkamyaman erkamyaman commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

What and why

The NgRx Store tab had no way to get state out of the panel except selecting text by hand in the State block, and a change's diff could not be copied at all. That made it slow to paste a state or a diff into a bug report or a test.

  • A Copy button next to the State heading copies the state as shown in the panel (already redacted). Accessible name: "Copy state".
  • A Copy button next to State diff in the selected entry's detail copies that entry's diff in the same format. Accessible name: "Copy the state diff of #N". It only shows when the entry changed something.
  • Feedback goes to the page's existing polite role="status" message: "Copied.", or "The clipboard is not available here." when navigator.clipboard is missing or rejects. This matches the try/catch pattern in the Router and Forms copy buttons.
  • The NgRx Store docs page describes both buttons, says the copy is the panel's formatted text and not strict JSON, and documents the clipboard message.

How it was verified

  • pnpm commit:check: 2 commit messages OK
  • pnpm format:check: all files pass
  • pnpm typecheck: exit 0, no error TS or error NG
  • pnpm test:panel: 29 files, 169 tests passed, including 5 copy tests: the state copy equals the panel text; the diff copy for a selected entry; no diff button for an entry with no change; the message when the clipboard is missing; the message when the write is rejected
  • Docs updated (inspectors/ngrx-store.md) and pnpm docs:build passes
  • pnpm extension:build: rebuilt extension/ui committed
  • Browser axe check (on the first commit): pnpm test:axe could not launch its pinned Chromium, so scripts/panel-axe.mjs was run against the installed Chromium 1194 on the same static report: 0 violations on every tab and view in dark and light. The buttons were also checked with live data from the SSR demo (/examples/store, panel at /__devframes/pangular/?view=ngrx) in dark and light at 1280px and 360px. Both copies said "Copied.", the copied state matched the panel text, axe found 0 violations with the change detail open, and there was no horizontal overflow. The second commit only renames the accessible names and was not rerun in the browser.

Notes for reviewers

  • What is copied is the panel's formatted text (the same pretty() output the State block shows), not strict JSON.stringify output. This keeps the copy identical to what is on screen, already redacted, with Date, Map, Set and similar values readable. The labels and docs say "as shown in the panel" instead of "JSON" for that reason.
  • The Copy buttons are 26px tall so they fit next to the small section labels. That is below --control-h but above the 24px minimum target size.
  • There is no shared copy helper yet. This page has its own small helper with the same behaviour as the Router and Forms buttons. Those three could move to one shared helper in a follow-up.
  • The selection signals (selectedChangeSeq, selectedEventSeq, confirmSeq) are untouched, so this should not conflict with fix: reset stale selections and armed actions when the inspected page changes #253.

Summary by CodeRabbit

  • New Features
    • Added copy buttons for the formatted store state and nonempty state diffs, with status messages indicating whether copying succeeded.
  • Documentation
    • Clarified what gets copied and noted that clipboard access may be unavailable in some browser contexts.

Getting store state out of the panel meant selecting text in the State
block by hand, and a change's diff could not be copied at all, which made
it slow to paste a state or a diff into a bug report or a test.

The Store tab now has a Copy button next to the State heading and one next
to the State diff of the selected entry. State copies the same formatted,
already redacted text the panel shows; the diff copies that entry's diff
entries. A polite status message says "Copied." or "The clipboard is not
available here." when the clipboard is missing or refuses the write. Each
button's accessible name says what it copies.

The NgRx Store docs page describes both buttons and the clipboard message.
The copy buttons put the panel's formatted text on the clipboard, the
same text the State block shows, which is not strict JSON (simple keys are
unquoted and values like Date or Map are shown in a readable form).
Accessible names that said "as JSON" promised a format the copy does not
have.

The buttons are now named "Copy state" and "Copy the state diff of #N",
the docs say the copy is the state as shown in the panel, and the tests
assert the new names.
@github-actions github-actions Bot added area: panel The devtools panel app (app/) area: extension The Chrome extension area: docs The documentation site labels Oct 10, 2026
@coderabbitai

coderabbitai Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 89bf439f-67fc-43c1-8625-f529dbe51230

📥 Commits

Reviewing files that changed from the base of the PR and between 893a431 and 63bcdd5.


⛔ Files ignored due to path filters (1)
  • extension/ui/assets/index-ByEDQ2k8.js is excluded by !**/assets/index-[0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-].js

📒 Files selected for processing (4)
  • app/src/pages/store-inspector.ts
  • apps/docs/src/content/inspectors/ngrx-store.md
  • extension/ui/assets/browser-agent-rpc-BXhoSh1z-d1Tsxw97.js
  • extension/ui/index.html

 _________________________________________________
< Copilot is my sidekick. I'm the main character. >
 -------------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
📝 Walkthrough
📝 Walkthrough

Walkthrough

The store inspector adds controls to copy displayed state and nonempty state diffs. It reports clipboard success or unavailability. The extension UI also updates references to a bundled JavaScript asset.

Changes

Store state and diff copying

Layer / File(s) Summary
State and diff clipboard controls
app/src/pages/store-inspector.ts, app/src/__tests__/store-inspector.test.ts, apps/docs/src/content/inspectors/ngrx-store.md
State and nonempty diff headings gain copy buttons. Clipboard writes display “Copied.” on success or “The clipboard is not available here.” on failure. Tests cover copied text, absent diff controls, and clipboard failures. Documentation describes the copied formats and clipboard message.

Extension UI asset references

Layer / File(s) Summary
Updated bundled asset references
extension/ui/index.html, extension/ui/assets/browser-agent-rpc-BXhoSh1z-BV8Vv7MW.js
The extension page and browser-agent RPC bridge now reference index-BPdZd4IT.js instead of index-BEfrZ0QX.js.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~12 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant StoreInspector
  participant ClipboardAPI
  participant StatusArea
  User->>StoreInspector: Select Copy for state or a nonempty diff
  StoreInspector->>ClipboardAPI: Write formatted text
  alt Clipboard write succeeds
    ClipboardAPI-->>StoreInspector: Success
    StoreInspector->>StatusArea: Show Copied.
  else Clipboard is unavailable or write fails
    ClipboardAPI-->>StoreInspector: Failure
    StoreInspector->>StatusArea: Show The clipboard is not available here.
  end
Loading


Merge Risk: ⚪ Minimal · up to 893a4

The copy controls report clipboard failures and use redacted state, while the extension references point to a bundle with the required helper. No concrete merge-blocking risk remains.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 893a4

The copy controls export the inspector’s existing sanitized representation without adding remote access or store-write authority. Privacy still depends on the existing redaction rules, and copied text leaves the panel through the browser clipboard.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The demonstrated new exposure is user-requested transfer of selected store state or a selected entry’s diff to the panel browser’s clipboard. The copy helpers contain no RPC call, dispatch, restore, or server-side persistence operation.

Security Findings and Attack Paths

  • inferred — The deferred exposure candidate relied on missing diff-producer evidence and the formatter’s lack of redaction. Inspection now shows sanitization in signal and classic diff producers, including the reference-diff fallback. No introduced producer-redaction bypass is supported by those paths; the supplied deferred disposition remains distinct from this source-based assessment.

Trust Boundaries and Controls

  • observed — The formatter exports the representation it receives; it neither restores original values nor performs independent privacy filtering. The upstream serializer applies sensitive-key and message redaction rules, so clipboard privacy inherits those rules rather than guaranteeing removal of every sensitive application value.

Resilience and Maintainability Implications

  • inferred — Missing clipboard access and rejected writes terminate in status feedback without changing store state. Repeated or overlapping requests capture their own text and are not sequenced; completion can overwrite shared feedback, but no security-relevant ownership or control change was established. Browser-specific ordering and interruption behavior remain unverified.

Pre-merge checks | Passed 4 | Failed 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 3 files. (2 skipped: 2 … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: adding copy actions for the store state and a change's diff.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.


Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 3 files. (2 skipped: 2 unsupported.)




  • Fix all pre-merge checks with AI
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR




🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: In progress 🔵

View logs ↗
63bcdd5 2026-10-11T02:00:48.925Z View logs ↗
  • Build: Failed ❌

View logs ↗
893a431 2026-10-10T23:06:32.972Z View logs ↗

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔇 Additional comments (6)
extension/ui/index.html (1)

12-12: LGTM!

extension/ui/assets/browser-agent-rpc-BXhoSh1z-BV8Vv7MW.js (1)

1-1: LGTM!

app/src/__tests__/store-inspector.test.ts (1)

199-278: LGTM!

apps/docs/src/content/inspectors/ngrx-store.md (1)

35-35: LGTM!

Also applies to: 48-48, 191-194

app/src/pages/store-inspector.ts (2)

1937-1939: 🔒 Security & Privacy | 🛡️ Detected with Advanced Tier

Verify that the diff producer redacts before and after values. The copyDiff action passes entry.diff directly to pretty, which performs no redaction. The producer must redact both diff values before storing or exposing the entry.


1941-1948: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

⚠️ Unverified finding
Verification ran but could not confirm this finding. It is shown for review, not as a verified issue.

Surface clipboard failures to the caller or do not swallow them silently.

copyText catches every error and sets one message. navigator.clipboard can be undefined, and writeText can reject. Both cases produce the same text. The copyState() and copyDiff() methods return the promise, but it always resolves, so callers cannot observe a failure.

The UI feedback is present, so the user impact is small. Keep the message. Consider logging the error or returning a boolean result. A result lets callers and tests tell success from failure without reading the DOM.

Based on learnings: "async utility functions (e.g., a clipboard-copy helper) should not silently catch and swallow errors internally."

Source: Learnings


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b6056345-119a-40ca-952c-f6686dcdf1fa
📥 Commits

Reviewing files that changed from the base of the PR and between f245551 and 893a431.

⛔ Files ignored due to path filters (1)
  • extension/ui/assets/index-BPdZd4IT.js is excluded by !**/assets/index-[0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-].js
📒 Files selected for processing (5)
  • app/src/__tests__/store-inspector.test.ts
  • app/src/pages/store-inspector.ts
  • apps/docs/src/content/inspectors/ngrx-store.md
  • extension/ui/assets/browser-agent-rpc-BXhoSh1z-BV8Vv7MW.js
  • extension/ui/index.html

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.

# Conflicts:
#	extension/ui/assets/browser-agent-rpc-BXhoSh1z-BV8Vv7MW.js
#	extension/ui/assets/browser-agent-rpc-BXhoSh1z-C_twCiPD.js
#	extension/ui/assets/browser-agent-rpc-BXhoSh1z-Ca92cyCz.js
#	extension/ui/assets/index-B4-Q9-Lj.js
#	extension/ui/assets/index-BEfrZ0QX.js
#	extension/ui/assets/index-BPdZd4IT.js
#	extension/ui/index.html
@erkamyaman
erkamyaman merged commit fea2220 into main Oct 11, 2026
@erkamyaman
erkamyaman deleted the store/copy-json branch October 11, 2026 02:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: docs The documentation site area: extension The Chrome extension area: panel The devtools panel app (app/)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant