Skip to content

feat(web): issues page and detail panel match pull requests - #8

Merged
Kaloyanes merged 10 commits into
mainfrom
feat/issues-page-unification
Oct 3, 2026
Merged

Kaloyanes merged 10 commits into
mainfrom
feat/issues-page-unification

Conversation

@Kaloyanes

Copy link
Copy Markdown
Owner

The Issues page looked and behaved differently from the Pull Requests page. It had a plain toolbar, one project at a time, spinners, hand-built rows, and comma-separated label and assignee editing. The server already supported involvement, filters and several repositories, but the page used none of it. List rows also fetched every issue's body and reactions, then never used them.

This PR builds Issues on the same pieces as Pull Requests, so the two pages read as one product.

Shared list frame (components/workItem): the PR page's shrinking header, folding search, compact filter menus and refresh control were moved into shared components. The PR page looks and behaves the same as before.

Issues list

  • Controls: search with label:, -label:, author:, assignee:, milestone: and me. Sort, Filters (labels, author, assignee, milestone), involvement (Assigned / Authored / Mentioned), and an All projects or single-project scope.
  • Groups: Working on, then Assigned to you, then Others.
  • Rows: use the PR row layout, with icons for each close reason, assignee avatars, milestone and an "In progress" marker for linked work. Rows are memoized and skip rendering while offscreen.
  • Actions: start work straight from a row (hover button or right-click menu), and bulk close, reopen, add label or assign across selected rows.
  • Keyboard: j/k/Enter on both list pages; x, c and mod+A on Issues.

Issue view

  • Header: folds down on scroll like the PR one.
  • Summary tab:
    • pickers for assignees and labels
    • milestone, linked work, linked pull requests, and the parent issue with sub-issue progress
    • markdown editing with preview, the reaction picker, and a floating comment box with close reasons
  • Timeline tab: the issue's history in one feed.
  • New issue dialog: label and assignee pickers, a preview, and "Create & start work".

Server

  • List rows: carry assignees, milestone, close reason and linked work. The list query no longer fetches bodies, reactions or descriptions.
  • Filters and sort: handled by GitHub search, so pages come back full. me maps to @me.
  • Paging: "All projects" lists no longer drop rows between pages.
  • Edits: label and assignee changes can be sent as add/remove, so they don't overwrite edits someone made in the meantime. Bulk actions and pickers only use these.
  • Issue view data: linked pull requests, parent and sub-issues, and a new paginated issues.timeline. These degrade quietly on older GitHub Enterprise.
  • Older servers: the new list fields are optional, so newer clients still work. On an older server the Timeline tab shows "update this server" instead of an error.

Agents: an MCP issues toolkit, mirroring the pull request one: list_issues, read_issue, comment_on_issue, close_issue, reopen_issue, update_issue, link_issue. Write tools are limited to the calling thread's project.

Also: linked issue chips in the sidebar show closed issues (closing state is recorded when a linked worktree's PRs merge).

Docs: an Issues section in docs/user/source-control.md, and the list shortcuts in docs/user/keybindings.md.

Surfaces

  • Clients: web and desktop share this code. Mobile has no Issues or PR list, so nothing changes there.
  • Entry points: the sidebar and the command palette "Open Issues" both land on the new page. The issue view beside a thread uses the same component and now opens linked PRs and sub-issues in that thread's panel.

Verification

  • Typecheck: clean for apps/web, apps/server, packages/contracts and packages/client-runtime.
  • Tests: vp test run on issue, workItem, pullRequest, MCP issues and client-runtime state passes: 83 files, 1,282 tests.
  • Format and lint: formatting is clean, and lint reports no errors from this branch (Sidebar.tsx errors were already there).
  • Not yet checked in a running app. Screenshots of before and after are still to come.

Built with Claude Opus 5.5 (orchestration, UI, review and fixes) and Codex GPT-6.1-Sol (server data layer, MCP toolkit) in T3 Code via the Claude Code harness.

Record the last observed issue state on projection_issue_links, refresh it when a
linked worktree's pull requests merge, and tint closed issue chips in the sidebar.
…request page

Moves the condensing column, compact filter menus, folded search and refresh control
into components/workItem so the issues page can share them, and moves the new-issue
dialog into its own module. No visible change to the pull request page.
Adds an issues toolkit mirroring the pull request one: list_issues, read_issue,
comment_on_issue, close_issue, reopen_issue, update_issue and link_issue.
List rows carry assignees, milestone, close reason and linked work; the list query
drops bodies and reactions; filters and sort are sent to GitHub search so pages are
full. Issue detail gains linked pull requests, parent and sub-issues, and a new
paginated issues.timeline read.
The issues list now uses the shared work-item column: condensing header, search with
label:/author:/assignee:/milestone: qualifiers, Sort, Filters, involvement and an
All projects scope, ghost rows, and groups for Working on / Assigned to you / Others.
Rows share the pull request row layout with close-reason glyphs, assignees, milestone
and an In progress marker. Rows can start work directly, be selected for bulk
close/reopen/label/assign, and both lists support j/k/Enter keyboard navigation.
Summary and Timeline tabs, a condensing header like the pull request panel, pickers
for assignees and labels, linked pull requests, parent and sub-issue progress,
markdown editing with preview, the reaction picker and a floating comment composer.
The new-issue dialog gains label/assignee pickers, a preview and Create & start work.
- Label and assignee edits can be sent as add/remove, applied with GitHub's
  additive endpoints so concurrent edits are not overwritten.
- author:me / assignee:me map to GitHub's @me.
- Multi-repository lists return every fetched row; search cursors keep later pages
  on the search path.
- List rows ignore detached links and pick the latest link deterministically.
- New list row fields are optional so newer clients work with older servers.
- Detail queries run concurrently, fall back on older GitHub Enterprise, and
  timeline assignees include bots.
- MCP issue writes are limited to the calling thread's project.
- Service-level tests for list, detail fallbacks, timeline and additive edits.
Bulk add-label/assign and the summary pickers send additive changes, and bulk
actions are disabled while the list shows saved or carried rows. Search handles
me/@me and moves typed is:/state:/sort: onto the page controls. Parent and sub-issue
links open in the panel, older servers show a timeline-unavailable state, and
retired local storage is cleaned up. Adds an Issues section to the user docs.
Copilot AI balanced review requested due to automatic review settings October 3, 2026 18:05

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-03T18:12:22.269225Z 07c3c7f PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Oct 3, 2026
@Kaloyanes
Kaloyanes merged commit cc64738 into main Oct 3, 2026
7 of 22 checks passed

@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: 07c3c7f9a6

ℹ️ 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".

return {
providers,
entries: entries.slice(0, limit),
entries,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Bound merged issue pages to the requested limit

When listing multiple repositories, each repository fetches up to limit rows and this returns all of them, so the web request with limit: 99 can send and render as many as 9,900 rows, while an MCP caller using limit: 1 can unexpectedly receive one row per repository. This creates a large WebSocket/list-rendering regression in the new all-projects view; pagination needs to preserve unreturned per-repository rows or otherwise avoid advancing their cursors while keeping each merged response globally bounded.

AGENTS.md reference: AGENTS.md:L15-L17

Useful? React with 👍 / 👎.

.toSorted(([left], [right]) => left.localeCompare(right))
.map(([environmentId, selections]) => ({
environmentId,
repositories: [...selections.values()].slice(0, MAX_REPOSITORIES_PER_REQUEST),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Batch repositories instead of dropping entries after 100

For an environment containing more than 100 distinct GitHub repositories, the All projects scope silently discards every repository after the first 100. Because those selections never enter scopeQueries, neither initial loading nor Load more can retrieve their issues; partition the selections into multiple request-sized targets instead of slicing them away.

Useful? React with 👍 / 👎.

@Kaloyanes
Kaloyanes deleted the feat/issues-page-unification branch October 28, 2026 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants