Skip to content

Projects v3: unify sharing, discussions, and issue ownership - #5624

Open
thomaspblock wants to merge 26 commits into
mainfrom
projects-design-v3-layout-test
Open

Projects v3: unify sharing, discussions, and issue ownership#5624
thomaspblock wants to merge 26 commits into
mainfrom
projects-design-v3-layout-test

Conversation

@thomaspblock

@thomaspblock thomaspblock commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Projects v3 makes repository work shareable, discussion-aware, and easier to scan in one coherent workspace. People can copy canonical links, reopen the exact workspace tab, understand issue and pull-request context at a glance, find related channel conversations, and assign or unassign issues across Desktop and CLI.

  • Unified workspace — top-level sections sit above repository controls in one rounded workspace, with navigation positioned close to the page heading. README and Files retain branch selection; every section has a labeled icon header, and Issues and Pull Requests expose creation from a consistent right-aligned action.
  • Repository management — the repository selector is always available, including single-repository projects. Its integrated add flow lets project owners create a repository manually or select an existing repository without a separate toolbar button.
  • Readable work-item lists — issue and pull-request rows use plain-language context instead of opaque metadata. Files, commits, issues, pull requests, channels, and contributors share consistent row density and right-aligned timestamps, while deterministic fallback-avatar colors keep participants distinct on light backgrounds. Inbox pull-request metadata wraps between complete phrases and truncates long channel names instead of compressing copy into narrow columns.
  • Reliable entity links — projects, repositories, issues, pull requests, and commits have canonical buzz:// links, preview cards, OS deep-link routing, and tab-aware navigation. Reopening the same link re-applies its destination instead of leaving the user on a locally selected tab.
  • Related conversations — repository and work-item views surface channels discussing the current entity, including participants, channel navigation, message context, and an explicit notice when discovery reaches its 500-result cap.
  • Reversible issue ownership — trusted assignment and unassignment events work across Desktop, Tauri, buzz-sdk, and buzz issues. Assignees appear in project views and the assigned inbox, while authorized users can remove assignments directly from the assignee row.

Assignment state is derived chronologically from labeled Nostr notes. Issue authors and repository owners may change any assignee; other users may only assign or unassign themselves. Shared golden fixtures keep entity-link grammar and validation aligned across TypeScript and Rust.

The branch also updates webbrowser to the patched release for RUSTSEC-2026-0257.

Related issue

N/A.

Testing

  • just ci — formatting, lint, typechecking, unit tests, and builds passed
  • Full pre-push suite — organization, branch-skew, Desktop checks, typechecking, and tests passed on the latest push
  • cargo test -p buzz-cli and focused buzz-sdk assignment tests passed
  • Focused Tauri recipient-note and 500-result search-limit tests passed
  • Desktop entity-link and issue-assignment unit tests passed
  • Playwright smoke coverage passed for assignment, repeated entity-link navigation, repository create/select flows, section headers and actions, timestamp alignment, timeline icons, sentence-style issue/PR metadata, header spacing, avatar contrast, and Inbox metadata at stacked and side-rail breakpoints
  • Manual staging pass: link round-trips, Channels tab, assignment flows, and inbox routing

Screenshots

Pull requests explain who opened the request, where it lives, and which branch it comes from; fallback avatars remain visually distinct.

Pull request list with conversational metadata

Issues use the same sentence-style hierarchy while keeping status and recency easy to scan.

Issue list with conversational metadata

The wide Inbox detail keeps author, timestamp, and origin context readable beside its metadata rail.

Pull request Inbox detail with readable metadata

View the complete six-state Projects v3 screenshot set and the compact/wide Inbox comparison.

Projects, repositories, issues, and pull requests had no shareable
reference — the only way to point someone at one was to describe it.
Each now offers "Copy link" in its row menu (plus a copy button in the
project, issue, and pull request detail headers), yielding a `buzz://`
deep link that renders as a preview card in chat and opens the entity
in-app when clicked or opened from the OS.

Completes the entity-link format for this: adds the `buzz://project`
scheme on both sides (TS builders/parser and the buzz-cli mirror, with
`projects create` emitting `link`), resolves repository and project card
titles from their announcement events, and registers the four entity
hosts with the Tauri deep-link handler.

Coordinates whose d-tag falls outside the link charset simply have no
share affordance, rather than producing a link the recipient cannot
parse.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
…rome

The project detail view repeated the project name in both the breadcrumb
and an <h2> directly below it, costing a full row before any content.
Drop that row and move its repository picker and web-page link into the
chrome's action cluster, which always renders — unlike the tab row, which
is hidden while git data is loading or unavailable, exactly when
switching repositories matters most.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
Signed-off-by: Thomas Petersen <thomasp@squareup.com>
Signed-off-by: Thomas Petersen <thomasp@squareup.com>

# Conflicts:
#	desktop/src/shared/lib/useResolvedLinkPreviews.ts
Restructure the project detail view so the repository / source / branch
selection row sits at the top of one panel box, with the tab strip and
the active panel inside it. The readme header rows move up: source
controls into the selection row, the last-changed timestamp into the
tab strip. The files panel drops its duplicated source controls and
keeps only its path breadcrumb. All selection dropdowns (repository,
source, branch) now share one trigger style.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
Copying a project link while on the Pull Request, Issues, Files, Commits,
or Contributors tab now appends &tab=<tab> to the buzz://project|repo
link, and opening such a link lands on that tab instead of the readme
overview. The tab parameter is validated against a fixed allowlist in the
TypeScript parser, the route search schema, and the Tauri deep-link
handler; event links (pr/issue) accept no tab. Chrome repository actions
move to ProjectDetailChromeActions to keep the screen under the size
ratchet.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
Signed-off-by: Thomas Petersen <thomasp@squareup.com>

# Conflicts:
#	desktop/src/features/projects/ui/ProjectDetailScreen.tsx
Project cards and rows drop the textual commit/PR/issue stats and keep
only the segmented activity bar — the exact counts remain in the bar's
hover tooltips. Repository lists keep the text stats next to the bar.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
NIP-50 full-text search finds messages citing an entity's id (or a repo's
coordinate), grouped into a Channels workspace tab and per-entity
'discussed in' cards with participants, channel links, and snippets.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
Assignments are labeled kind:1 comments (t: assignment) whose p tags are
the assignees, mirroring PR review requests — signed via a new Tauri
command, buzz-sdk builder, and 'buzz issues assign' CLI subcommand.
Desktop shows assignee facepiles, an Assignees rail with self-assign, an
'Assigned to me' filter, and entity-specific inbox open buttons. The
recipient-note builders move to their own module to satisfy the file-size
ratchet.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
Copy-link buttons move inline after the issue/PR title, the work-item
list header row is replaced by a plus in the tab strip, the static repo
pill matches the dropdown triggers, and issue comments show author
avatars with feed-sized meta text aligned to the content edge.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
Signed-off-by: Thomas Petersen <thomasp@squareup.com>
…yout-test

Signed-off-by: Thomas Petersen <thomasp@squareup.com>

# Conflicts:
#	desktop/src/app/AppShell.tsx
Tab labels drop from text-base to text-sm and the overview tab no longer
shows the readme's last-changed timestamp.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
thomaspblock added a commit that referenced this pull request Aug 12, 2026
Adds a mock-mode spec that captures the workspace overview, issues tab,
issue detail, and PR detail states for PR screenshots. Mock event ids are
now full 64-hex so share-link copy buttons render in mock mode, and
post-screenshots.sh no longer needs bash 4 (mapfile/declare -A) so it
runs on stock macOS bash 3.2.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
@thomaspblock
thomaspblock marked this pull request as ready for review August 12, 2026 04:37
@thomaspblock
thomaspblock requested a review from a team as a code owner August 12, 2026 04:37
@thomaspblock
thomaspblock enabled auto-merge (squash) August 12, 2026 04:37
Add trusted unassignment operations across Desktop, Tauri, SDK, and CLI,
while making repeated entity links deterministic and discussion discovery
honest about its result cap.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
@thomaspblock thomaspblock changed the title Projects v3: shareable entity links, discussion channels, issue assignments, workspace redesign Projects v3: unify sharing, discussions, and issue ownership Aug 12, 2026
@thomaspblock
thomaspblock disabled auto-merge August 12, 2026 10:59
@thomaspblock
thomaspblock marked this pull request as draft August 12, 2026 10:59
Move to the patched release so cargo-deny no longer blocks every PR on
the newly published browser argument-injection advisory.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
Replace opaque event hashes with author, repository, branch, and label
context so duplicate PR and issue titles remain distinguishable.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
Inset the timeline content by one pixel so outer icon and avatar rings
remain visible inside the clipped connector container.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
Express repository, branch, and label context as readable sentences so
people can understand work-item rows without decoding data fragments.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
thomaspblock added a commit that referenced this pull request Aug 12, 2026
Make repository navigation, section headers, row spacing, and trailing metadata consistent so project tabs are easier to scan and manage.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
Verify non-primary repository routing through rendered PR content now that repository controls intentionally appear only on README and Files.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
thomaspblock added a commit that referenced this pull request Aug 12, 2026
@thomaspblock

Copy link
Copy Markdown
Contributor Author

🤖 Updated Projects v3 screenshots with the latest workspace layout and distinct avatar fallback colors.

Single-box workspace

Tabs sit above repository and branch controls; contributor avatars now remain distinct on light backgrounds.

01-workspace-overview

Issues workspace

The Issues section has consistent header, row spacing, and right-aligned dates.

02-issues-tab

Issue detail

Issue ownership and comments use colored author avatars in the focused detail view.

03-issue-detail

Pull request detail

Pull request context and copy-link actions use the same detail hierarchy.

04-pr-detail

Pull request list

Each second line explains who opened the request, in which repository, and from which branch.

05-pr-list-metadata

Issue list

Each second line reads as a sentence, with distinct author avatars for faster scanning.

06-issue-list-metadata

Bring project navigation closer to its page heading and give fallback avatars distinct, readable colors on light backgrounds.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
Wrap pull request metadata between complete phrases and truncate long channel names so the Inbox detail rail cannot compress copy into word-wide columns.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
@thomaspblock

Copy link
Copy Markdown
Contributor Author

🤖 Final Projects v3 Inbox validation.

Compact Inbox detail

The pull request remains actionable when the metadata rail stacks below the conversation.

01-pull-request-detail

Wide Inbox detail

Author, time, and origin metadata wrap as complete phrases; long channel names truncate instead of collapsing into word-wide columns.

02-pull-request-detail-wide

thomaspblock added a commit that referenced this pull request Aug 12, 2026
Retry the pinned GHCR login action once so a brief registry denial does not fail an otherwise valid architecture build.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
…yout-test

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
@thomaspblock
thomaspblock marked this pull request as ready for review August 12, 2026 16:00
@thomaspblock
thomaspblock enabled auto-merge (squash) August 12, 2026 16:00

@klopez4212 klopez4212 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.

Reviewing on behalf of Kenny Lopez. I found three correctness issues that should be addressed before merge; the timestamp-ordering issue is the release blocker.

function assigneesForIssue(issue, issueCommentEvents) {
const allowedActors = allowedActorsForRoot(issue);
const assignees = new Set();
const operations = sortEvents(

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.

[P1] Prevent future-dated self-operations from overriding maintainer actions. This reducer gives every operation precedence solely through the signer-controlled created_at, while line 114 accepts a non-owner operation when its sole p tag is the signer. The relay currently accepts timestamps up to 900 seconds in the future (crates/buzz-relay/src/handlers/ingest.rs:1976-1983). A volunteer can therefore publish a self-assignment at now + 899; if the owner then unassigns them at the real current time, sorting applies the owner's removal first and the volunteer's already-published assignment last, so the maintainer action has no effect. The inverse future self-unassignment defeats a subsequent owner assignment as well. The local monotonic timestamp helper is not a trust boundary because arbitrary signed kind-1 events enter this reducer. Please define conflict semantics in which a user cannot precommit a self-service operation that outranks a later owner/author decision (for example, causal/authoritative ordering not based solely on actor-controlled event time), and cover future-dated self-assign → owner unassign plus the inverse.

void goProject(entityLinkProjectRouteId(link), {
...(tab
? {
entityNavigationId: crypto.randomUUID(),

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.

[P1] Re-trigger repeated PR and issue links too. The request ID is only generated when a repo/project link has a tab. PR and issue links therefore navigate without force, and ProjectDetailScreen resynchronizes its local detail state only when pullRequestId/issueId changes. After the breadcrumb locally clears an open PR or issue (without clearing the route search param), opening the identical link again keeps the same prop and the effect does not run, so the detail stays closed. Generate a request key for every entity-link activation and include it when synchronizing PR/issue selection, with regression coverage for reopening the same PR and issue links—not just the repeated repo-tab case.

? issues.filter(({ issue }) => normalizePubkey(issue.author) === viewer)
: issueScope === "assigned" && viewer
? issues.filter(({ issue }) =>
issue.assignees.some(

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.

[P2] Prefetch profiles for the assignees consumed by this scope and rendered in the issue list. ProjectsIssuesList now passes issue.assignees to IssueAssigneeFacepile, but the projectPubkeys batch assembled above includes only each issue's author, recipients, and commenters. An assignee who appears in none of those sets never has their profile loaded, so the facepile falls back to a truncated pubkey and generated avatar even when that user has profile metadata. Please add ...issue.assignees to the issue keys in projectPubkeys, matching the project-detail profile collection.

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.

3 participants