Skip to content

feat(app): add account screen - #210

Merged
tanlethanh merged 3 commits into
mainfrom
agent/account-screen
Aug 19, 2026
Merged

tanlethanh merged 3 commits into
mainfrom
agent/account-screen

Conversation

@tanlethanh

Copy link
Copy Markdown
Member

Summary

Settings → Profile now opens a dedicated Account screen. This is the missing half of account deletion: DELETE /v1/me is already live on Delta, but nothing in the app could reach it, which is what App Store Review 5.1.1(v) actually checks.

The screen shows the signed-in identity with an avatar, notification state in plain language, and the stack and device identifiers. Every identifier row copies its value on tap. It also lists the stack's registered nodes, marking this device.

Push-token registration moved into delta::acquire_and_register_push_token, shared with Settings rather than duplicated per screen — that removed a second copy of the stale-result guard.

Notes

  • Node cache lives in delta.json, so the device list paints on a cold start and only refetches past a 5 minute TTL. It merges on stack_id alone rather than through apply_if_current: it is derived data, so an unrelated token refresh mid-flight must not silently discard it.
  • NodeKind gains the agent and external variants the server already sends. One unknown kind would previously fail deserialization of the whole list, emptying the device list rather than skipping one row.
  • The node refresh fires on navigation, not in AccountView::new — the view is constructed once at startup, where a fetch would race sign-in state and never retry.
  • Sign in with Apple token revocation is deliberately not included. Guideline 5.1.1(v) requires deleting the account, which Delta does; revoking is a "should" whose only effect is removing the app from the user's Apps Using Apple ID list. It needs a separate .p8 created with the Sign in with Apple capability.
  • Bumps vendor/zed for gpui_ios: NUL-terminate clipboard text — nothing in the app had used the clipboard before, and write_to_clipboard passed a non-NUL-terminated Rust String to stringWithUTF8String:, reading past the end of the buffer.

Validation

  • cargo check -p zedra --features ios-platform --target aarch64-apple-ios
  • cargo test -p zedra --features ios-platform — 196 passed
  • cargo fmt --check
  • Not yet exercised on a device.

🤖 Generated with Claude Code

Settings -> Profile now opens a dedicated Account screen, required so a
user can reach account deletion in-app (App Store Review 5.1.1(v)).

The screen shows the signed-in identity with an avatar, notification
state in plain language, and the stack and device identifiers. Every
identifier row copies its value on tap. It also lists the stack's
registered nodes, marking this device, cached in delta.json so the list
paints on a cold start and only refetches past a 5 minute TTL.

The node cache merges on stack id alone rather than through
apply_if_current: it is derived data, so an unrelated token refresh
mid-flight must not discard it. NodeKind gains the agent and external
variants the server already sends, since one unknown kind would fail the
whole list.

Push-token registration moves to delta::acquire_and_register_push_token,
shared with Settings instead of duplicated per screen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 19, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
zedra Ignored Ignored Preview Aug 19, 2026 1:51am

@coderabbitai

coderabbitai Bot commented Aug 19, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@tanlethanh, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 19 minutes

Limit details: You’ve used all 2 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b0875f6-3062-4903-b597-34885ab37b47

📥 Commits

Reviewing files that changed from the base of the PR and between 3498a38 and ed324cb.

⛔ Files ignored due to path filters (1)
  • crates/zedra/assets/icons/copy.svg is excluded by !**/*.svg
📒 Files selected for processing (9)
  • crates/zedra/src/account_view.rs
  • crates/zedra/src/app.rs
  • crates/zedra/src/delta.rs
  • crates/zedra/src/lib.rs
  • crates/zedra/src/settings_view.rs
  • crates/zedra/src/workspace.rs
  • crates/zedra/src/workspace_state.rs
  • docs/MANUAL_TEST.md
  • vendor/zed

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b4805a1a82

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/zedra/src/delta.rs
Comment thread crates/zedra/src/workspace_state.rs
Comment thread crates/zedra/src/account_view.rs
Comment thread crates/zedra/src/settings_view.rs
tanlethanh and others added 2 commits August 19, 2026 08:42
`get_bearer` can refresh and persist rotated credentials mid-request, but
`fetch_nodes` returned only the node list, so `apply_nodes` saved the live
entity back over them with the expired access token.

`fetch_nodes` now returns the state as it stands after the call, and
`apply_nodes` adopts the refreshed credentials when the live state still
matches the one the fetch started from.

Deletion no longer routes through `apply_if_current`, which could reject
the signed-out state after `DELETE /v1/me` had already succeeded and leave
the app signed in to an erased account until relaunch. `apply_deleted`
guards on the stack alone, with a sign-out fallback.

Adds the Account screen, deletion, copy, node-list, and notification steps
to `docs/MANUAL_TEST.md`, replacing the profile-row logout steps the screen
replaced.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every async Delta operation returned a whole `DeltaState` that the entity
assigned wholesale, so two operations in flight overwrote each other's
untouched fields. Four `apply_*` variants had grown to guess which fields
each call site was allowed to stomp, and both bugs found in review were
that guess being wrong.

Operations now hand back a `DeltaPatch` built by diffing what they started
from against what they returned, and `DeltaState::merge` applies group by
group: session, push token, node cache, host bindings. Independent groups
no longer collide, so a token refresh and a node fetch in flight together
both land. Network function signatures are unchanged.

Sign-out clears every stack-scoped group, so a late result from a previous
session cannot repopulate it, and a node list for another stack is dropped.

`merge_fields` holds the rules free of entity plumbing, covered by tests
for the two review findings and the sign-out and stale-stack cases.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@tanlethanh
tanlethanh merged commit c97fda9 into main Aug 19, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant