feat(desktop): restore archive identity UI in profile panel#961
Draft
tellaho wants to merge 7 commits into
Draft
feat(desktop): restore archive identity UI in profile panel#961tellaho wants to merge 7 commits into
tellaho wants to merge 7 commits into
Conversation
d9f873d to
9074860
Compare
9074860 to
234b8c1
Compare
Adds a Manage section below the quick-actions row with a full-width Archive / Unarchive button, plus the "Archived on this relay" flair under the displayName. Gated by the original three-path composition (self / relay admin or owner / NIP-OA owner of viewee) — the relay re-verifies authority on submit. Button label flips to "Archive agent" on bot profiles. Restores the 5-case e2e gate matrix that #917 dropped alongside the UI. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…hive hook
Introduces useIdentityArchive(pubkey) in features/identity-archive/hooks.ts,
composing the three gate queries (relay membership, OA owner, archived
status) plus currentPubkey, owning both mutations and the toasted
archive/unarchive callbacks. Returns { canArchive, isArchived, isPending,
archive, unarchive }.
Both call sites (ProfileSummaryView and ProfileManageSection) consume the
hook directly, removing the six drilled props from UserProfilePanel and the
now-dead hook calls, handlers, and imports. Gate composition is preserved
verbatim: isSelf || isRelayAdminOrOwner || isOaOwnerOfViewee.
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Relocates the Archive/Unarchive Manage section so it renders after the metadata field group instead of above the memories/channels ingress, placing identity management at the bottom of the profile summary. Co-authored-by: Taylor Ho <taylorkmho@gmail.com> Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
234b8c1 to
17b4a2f
Compare
Collapses the isSelf check to a single line and removes a stray blank line introduced during the rebase conflict resolution. Whitespace only, no logic touched. Co-authored-by: Taylor Ho <taylorkmho@gmail.com> Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
The archive UI work tipped UserProfilePanelSections.tsx past the hard 1000-line cap (1016 > 1000). Per the file-size guard's own rule, split the file rather than adding an override. Extracts the natural section seams into self-documenting sibling files: - ProfileFields.tsx — field type, public/owner builders, group + row, copy helper - ProfileHero.tsx — hero header + collapsible description - ProfileActions.tsx — primary actions, quick action, working badge, ingress row - ProfileManageSection.tsx — NIP-IA archive/unarchive section - profileSummaryTypes.ts — shared profile/status types (avoids circular import) UserProfilePanelSections.tsx now holds only ProfileSummaryView composition and the focused views. Pure refactor: same render output, same gate, same section order, testids and the identity-archive 5-case matrix untouched. Co-authored-by: Taylor Ho <taylorkmho@gmail.com> Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Gate the archive action behind a calm AlertDialog (ArchiveConfirmDialog) that honestly explains what archiving does before it fires. Archiving is relay-scoped (NIP-IA kind:13535 snapshot, not account deletion, not global) and reversible, so the dialog reassures rather than alarms — the confirm button renders secondary, not destructive. - Bot-aware copy throughout: "Archive this agent?" vs "Archive this identity?", "removes this agent" vs "removes this person". - Three effect bullets (won't appear in search/autocomplete/member-add, affects only this space, reversible via unarchive) rendered as a <ul> sibling of AlertDialogDescription — that component is a <p> and can't legally nest a list. - Bot path adds a trailing paragraph pointing to permanent deletion in the Agents tab via an in-app link (Button variant=link) that closes the dialog then navigates with useAppNavigation().goAgents() — no raw anchor, no routing behind an open modal. Navigation is lifted to ProfileManageSection and passed in via onGoToAgents so the dialog stays presentational. Identity path renders no link (there is no delete target for a human identity). - Confirm button styling fix: AlertDialogAction applies buttonVariants() (primary) to its own element; the secondary classes are passed straight to it so tailwind-merge overrides the primary background rather than asChild + a nested Button (which concatenates variants and leaves primary winning on source order). Unarchive stays bare one-click (recovery action, no friction). All three archive testids plus archive-confirm-dialog/archive-confirm-action are intact; identity-archive.spec.ts is testid-driven, stays 5/5 green, and case 1 clicks through the confirm. Zero validateDOMNesting warnings. Co-authored-by: Taylor Ho <taylorkmho@gmail.com> Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
12df2b8 to
d11b8ac
Compare
…le panel Owned agents rendered as humans in the profile panel's archive flow: the Archive button + confirm modal showed the human variant even for an agent the viewer owns (repro: tho's agent Edna). Root cause: two gates disagreed. The archive button's canArchive gate resolves correctly via OA-ownership, but the human-vs-agent framing used a separate signal — isBot = Boolean(relayAgent || managedAgent) — that checks the relay-agents registry + the local managed-agents list. An owned agent deployed elsewhere can miss BOTH lists, so isBot was false and the panel rendered the human framing while the button still showed. Fix: OR in the kind:0-derived agent flag (isAgent on the users-batch summary, which the backend sets from profile_has_valid_oa_owner — a verified NIP-OA auth tag on the target's kind:0). That's the same authoritative signal the archive gate's resolveOaOwner trusts, so isBot can no longer drift from the gate. Client-only change, no relay/registry change. - UserProfilePanel: query useUsersBatchQuery([pubkey]) and OR its isAgent into isBot (keyed by lowercased pubkey, matching the house pattern). - BotIdenticon: forward an optional data-testid to its wrapper. - ProfileHero: tag the profile bot indicator with data-testid=profile-bot-indicator for the regression test. - profile.spec.ts: regression test — an owned agent seeded with the kind:0 agent flag but absent from relay/managed lists now renders agent framing. Applied fresh in-branch on #961 (not cherry-picked) so the bot-detection fix and the archive dialog ship together: Edna now renders the full agent-framed dialog ("Archive this agent?" + Agents-tab link) end-to-end. Co-authored-by: Taylor Ho <taylorkmho@gmail.com> Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Category: new-feature
User Impact: Identity and agent profiles regain a Manage → Archive control, now guarded by a confirmation dialog that plainly explains what archiving does before it happens.
Problem: A prior holistic-pass merge stripped the archive-identity control out of the profile panel and deferred it. Beyond just restoring a button, the archive action needed to explain itself: archiving is relay-scoped and reversible, but without context it reads like account deletion — and the bot case (where permanent deletion lives elsewhere) was conflated with the human-identity case.
Solution: Restore the archive UI as a dedicated Manage section beneath the profile metadata, collapse the old six-prop drilling into a single
useIdentityArchivehook, and gate the destructive-sounding action behind a calm, bot-aware confirmation dialog. The dialog reassures rather than alarms (secondary confirm button, not destructive red), splits its copy by identity type, and — for agents only — links to where permanent deletion actually lives (the Agents tab). The growing panel file was split along its natural seams to stay under the 1000-line cap.File changes
desktop/src/features/identity-archive/hooks.ts
Introduces
useIdentityArchive(pubkey), composing the three gate queries (relay membership, NIP-OA owner, archived status) plus current pubkey, owning both mutations and the toasted archive/unarchive callbacks. Returns{ canArchive, isArchived, isPending, archive, unarchive }. Gate preserved verbatim:isSelf || isRelayAdminOrOwner || isOaOwnerOfViewee.desktop/src/features/profile/ui/ArchiveConfirmDialog.tsx
New confirmation dialog gating the archive action. Bot-aware copy throughout ("Archive this agent?" vs "Archive this identity?"). Three effect bullets in a
<ul>rendered as a sibling ofAlertDialogDescription(which is a<p>and can't legally nest a list). Bot path adds a trailing paragraph linking to permanent deletion in the Agents tab; identity path renders no link (no delete target for a human). Confirm button styled secondary, not destructive.desktop/src/features/profile/ui/ProfileManageSection.tsx
The Manage section hosting Archive/Unarchive. Lifts navigation here (
useAppNavigation().goAgents()) and passesonGoToAgentsinto the dialog so the dialog stays presentational — the link closes the dialog first, then navigates (no routing behind an open modal). Unarchive stays a bare one-click recovery action.desktop/src/features/profile/ui/ProfileFields.tsx
Extracted from the oversized panel file: field type, public/owner builders, the group + row layout, and the copy helper.
desktop/src/features/profile/ui/ProfileHero.tsx
Extracted hero header and collapsible description.
desktop/src/features/profile/ui/ProfileActions.tsx
Extracted primary actions, quick-action row, working badge, and ingress row.
desktop/src/features/profile/ui/profileSummaryTypes.ts
Shared profile/status types, broken out to avoid a circular import between the new sub-components.
desktop/src/features/profile/ui/UserProfilePanelSections.tsx
Reduced to
ProfileSummaryViewcomposition and focused views after the split. The Manage section now renders below the metadata field group. Pure refactor of render output — same gate, same section order, testids intact.desktop/tests/e2e/identity-archive.spec.ts
Restores the 5-case e2e gate matrix dropped by the earlier UI removal, now testid-driven. Case 1 clicks through the confirmation dialog.
Reproduction steps
/agents.Screenshots
Coordination: buzz://message?channel=67a2c861-cd9a-4365-9cf1-d78bc9b24abc&thread=557d7005f943f81972a498452d95fa51cce54f94aa39fed31cf518cd1a6a51bd