Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
ff8cbc9
fix(web): keep pull request review annotations in the app font
Bil0000 Aug 10, 2026
8754813
feat(web): collapse pull request chrome on scroll in the right panel
Bil0000 Aug 10, 2026
58bc0ba
feat(web): hand pull request tasks to the open thread beside the panel
Bil0000 Aug 10, 2026
e9cbc08
feat(web): show labels and resolved conversations on the pull request…
Bil0000 Aug 10, 2026
4095917
fix(web): report host line counts for files with withheld hunks
Bil0000 Aug 10, 2026
b27a2dd
fix(web): hide the tab strip scrollbar in narrow pull request panels
Bil0000 Aug 10, 2026
d06636c
fix(web): compare withheld-hunk counts when reusing a diff slice
Bil0000 Aug 10, 2026
c4e4edc
feat(web): collapse resolved conversations on the pull request summary
Bil0000 Aug 10, 2026
2e832b7
Merge branch 'main' into fix/pr-right-panel-quick-fixes
Bil0000 Aug 10, 2026
9b66581
fix(web): keep the reader at the top when the pull request chrome reo…
Bil0000 Aug 10, 2026
4132aae
fix(web): match the resolved marker to the other review states
Bil0000 Aug 10, 2026
f47c443
fix(web): ease the pull request chrome back open at the top
Bil0000 Aug 10, 2026
8a4a972
Merge branch 'main' into fix/pr-right-panel-quick-fixes
Bil0000 Aug 10, 2026
a7c4e2f
fix(web): tidy pull request comment meta lines
Bil0000 Aug 10, 2026
3abab8f
feat(web): collapse dismissed approvals with their reason
Bil0000 Aug 10, 2026
8e231dd
fix(web): carry the dismissal reason onto bodiless dismissed reviews
Bil0000 Aug 10, 2026
a6ccf72
fix(web): read dismissed-review bodies past their HTML marker comments
Bil0000 Aug 10, 2026
e87d5b9
fix(web): follow dismissal events past the first page
Bil0000 Aug 10, 2026
aa1a05a
Merge branch 'main' into fix/pr-right-panel-quick-fixes
Bil0000 Aug 11, 2026
f59c9a2
feat(web): add review decision and list filters to the pull request c…
Bil0000 Aug 11, 2026
95a9ed9
feat(web): narrow GitHub listings by draft, review, checks and size
Bil0000 Aug 11, 2026
97dc528
feat(web): filter the pull request list and show each row's review st…
Bil0000 Aug 11, 2026
1c4c08f
feat(web): order pull request diffs by dependency instead of path
Bil0000 Aug 11, 2026
ab14ec1
feat(web): take search qualifiers and wider review filters in the lis…
Bil0000 Aug 11, 2026
681dfc1
feat(web): parse GitHub-style search qualifiers and rework the filter…
Bil0000 Aug 11, 2026
1d446a5
feat(web): merge pull request listings across connected environments
Bil0000 Aug 11, 2026
aae512b
feat(web): list every connected environment's pull requests on the page
Bil0000 Aug 11, 2026
91f6c9c
fix(web): take a filtered empty search as the answer it is
Bil0000 Aug 11, 2026
59799af
fix(web): filter provider rows service-side and hand Azure the reposi…
Bil0000 Aug 11, 2026
3a4f155
fix(web): keep viewers, truncation and project scope per environment
Bil0000 Aug 11, 2026
7a95a28
feat(web): add a server filter and per-environment paging to the pull…
Bil0000 Aug 11, 2026
9c531cc
fix(web): route pull request links, sidebar and panel tabs across ser…
Bil0000 Aug 11, 2026
36b3238
Merge branch 'main' into fix/pr-right-panel-quick-fixes
Bil0000 Aug 11, 2026
6135637
feat(web): report base-branch freshness and take an update-branch action
Bil0000 Aug 11, 2026
cbbb842
feat(web): offer Update branch with merge or rebase in the detail panel
Bil0000 Aug 11, 2026
0636e8c
test(web): pin authored rows from the partition reads to their group
Bil0000 Aug 11, 2026
3b755c0
fix(web): repair the base comparison read and its write-time permissions
Bil0000 Aug 11, 2026
2976bed
fix(web): match the thread's own pull request by project and trust on…
Bil0000 Aug 11, 2026
b02af69
feat(web): label OR groups, a checks rollup and project narrowing in …
Bil0000 Aug 11, 2026
24c3fae
fix(web): name the refusal in every environment error
Bil0000 Aug 11, 2026
728a614
feat(web): report the checks rollup and honour label groups and proje…
Bil0000 Aug 11, 2026
beeaa15
feat(web): wear the checks verdict on rows and the detail title, with…
Bil0000 Aug 11, 2026
76281bd
feat(web): assign shared projects to one connection and read label se…
Bil0000 Aug 11, 2026
74c41aa
feat(web): resolve which connections hold a shared project's repository
Bil0000 Aug 11, 2026
2462e9e
feat(web): pick which connection the detail panel acts on
Bil0000 Aug 11, 2026
60fb7be
fix(web): show one row per check rather than one per run of it
Bil0000 Aug 11, 2026
0c4ec32
feat(web): hand a merge to the host to carry out once it is ready
Bil0000 Aug 11, 2026
0e2fef8
feat(web): copy a change request's link from the number that carries it
Bil0000 Aug 11, 2026
39ab91f
feat(web): mark a stale branch on the branch, and keep a heading in s…
Bil0000 Aug 11, 2026
976e4a6
feat(web): report base-branch freshness and rebase the branch on GitLab
Bil0000 Aug 11, 2026
3e00a6d
feat(web): carry a remark's reactions, and the request that adds or t…
Bil0000 Aug 11, 2026
3f79f6b
feat(web): read reactions from GitHub and GitLab, and write one back
Bil0000 Aug 11, 2026
febba73
feat(web): wear reactions under every remark, and add one from the page
Bil0000 Aug 11, 2026
a5ab857
Merge remote-tracking branch 'origin/main' into fix/pr-right-panel-qu…
Bil0000 Aug 11, 2026
8441785
fix(pull-requests): key a narrowed listing by its projects and tell r…
Bil0000 Aug 11, 2026
6f2394a
Merge remote-tracking branch 'fork/fix/pr-right-panel-quick-fixes' in…
Bil0000 Aug 11, 2026
e00b8ec
fix(pull-requests): keep two Bitbucket pipelines apart, and redraw a …
Bil0000 Aug 11, 2026
e63e7ad
fix(web): read a quoted label whole, and cut a typed query to what th…
Bil0000 Aug 11, 2026
335f4ec
fix(pull-requests): read author:me as whoever is signed in to the host
Bil0000 Aug 11, 2026
a88e62e
Merge branch 'main' into fix/pr-right-panel-quick-fixes
Bil0000 Aug 11, 2026
5806a4e
fix(pull-requests): eight defects across listing, actions, reactions …
Bil0000 Aug 11, 2026
85b780c
Merge remote-tracking branch 'fork/fix/pr-right-panel-quick-fixes' in…
Bil0000 Aug 11, 2026
58f67e7
Merge remote-tracking branch 'origin/main' into fix/pr-right-panel-qu…
Bil0000 Aug 11, 2026
f7f568e
fix(web): open a saved link whose server has since gone
Bil0000 Aug 11, 2026
8860d8d
test(pull-requests): pin the four decisions that had none
Bil0000 Aug 12, 2026
12657a0
fix(pull-requests): name the server a project was picked on, judge ch…
Bil0000 Aug 12, 2026
e013908
fix(web): keep the page's panel under one key, and read every server …
Bil0000 Aug 12, 2026
edb470b
Merge branch 'main' into fix/pr-right-panel-quick-fixes
Bil0000 Aug 12, 2026
5264161
feat(contracts): say what a host lets be rewritten, and who the reade…
Bil0000 Aug 12, 2026
2ebc783
feat(pull-requests): carry a rewrite from the page to the provider th…
Bil0000 Aug 12, 2026
32282e0
test(pull-requests): pin what a rewrite may and may not do
Bil0000 Aug 12, 2026
af7a230
feat(pull-requests): rewrite a GitHub pull request's words, and one's…
Bil0000 Aug 12, 2026
15288f6
feat(pull-requests): rewrite a GitLab merge request's words, and one'…
Bil0000 Aug 12, 2026
eaa5dfa
feat(pull-requests): rewrite a Bitbucket pull request's words, and on…
Bil0000 Aug 12, 2026
0009f70
feat(pull-requests): rewrite an Azure DevOps pull request's title and…
Bil0000 Aug 12, 2026
c6ee4ae
feat(web): rewrite a change request's words, and one's own remarks, i…
Bil0000 Aug 12, 2026
98a5f84
docs: say that a pull request's words can be rewritten in place
Bil0000 Aug 12, 2026
0747e6b
test(pull-requests): drop two diagnostics directives that suppress no…
Bil0000 Aug 12, 2026
17eaa20
Merge branch 'fix/pr-right-panel-quick-fixes' of https://github.com/B…
Bil0000 Aug 12, 2026
4b1b032
Merge branch 'main' into fix/pr-right-panel-quick-fixes
Bil0000 Aug 12, 2026
c84bbff
Merge branch 'main' into fix/pr-right-panel-quick-fixes
Bil0000 Aug 12, 2026
f9c80fe
fix(contracts): let a page read a server that has never heard of reac…
Bil0000 Aug 12, 2026
63689ee
fix(pull-requests): stop a Bitbucket rewrite from putting old reviewe…
Bil0000 Aug 12, 2026
ce1030a
fix(web): keep an open editor from carrying one remark's words onto a…
Bil0000 Aug 12, 2026
9959a49
Merge branch 'fix/pr-right-panel-quick-fixes' of https://github.com/B…
Bil0000 Aug 12, 2026
19a3f6d
fix: improve pull request handoffs and rate-limit errors
juliusmarminge Aug 12, 2026
e4400e5
fix(web): answer a refused branch update for the way it was asked
Bil0000 Aug 12, 2026
dddefae
Merge branch 'main' into fix/pr-right-panel-quick-fixes
Bil0000 Aug 12, 2026
35d5d2f
ci: force rerun
Bil0000 Aug 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/web/src/components/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6055,6 +6055,8 @@ function ChatViewContent(props: ChatViewProps) {
? "thread"
: "page"
}
chromeVariant="collapse"
composerDraftTarget={composerDraftTarget}
onStateChange={handlePullRequestTabStatusChange}
/>
) : activeRightPanelSurface?.kind === "agents" ? (
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
Comment thread
Bil0000 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ export function PullRequestCodeTab({

const renderAnnotation = useCallback(
(annotation: ReviewAnnotation) => (
<div className="py-1">
<div className="py-1 font-sans text-foreground">
{annotation.metadata.threads.map(renderThreadCard)}
{annotation.metadata.pending.map((comment) => (
<PendingReviewCommentCard
Expand Down
75 changes: 55 additions & 20 deletions apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { scopeProjectRef } from "@t3tools/client-runtime/environment";
import { scopedThreadKey, scopeProjectRef } from "@t3tools/client-runtime/environment";
import { squashAtomCommandFailure } from "@t3tools/client-runtime/state/runtime";
import type {
EnvironmentId,
PullRequestAction,
PullRequestMergeMethod,
PullRequestRef,
PullRequestState,
ScopedThreadRef,
} from "@t3tools/contracts";
import {
ArrowDownUpIcon,
Expand Down Expand Up @@ -159,7 +160,10 @@ const PullRequestCodeTab = lazy(loadCodeTab);
* is closed by the time the next one opens. It is how a prompt the reader has since edited is told
* apart from the one they were handed: only the sentence still exactly as written may be replaced.
*/
const lastHandoffPromptByDraft = new Map<DraftId, string>();
const lastHandoffPromptByDraft = new Map<string, string>();

const composerTargetKey = (target: ScopedThreadRef | DraftId): string =>
typeof target === "string" ? target : scopedThreadKey(target);

export function PullRequestDetailPanel({
environmentId,
Expand All @@ -170,6 +174,7 @@ export function PullRequestDetailPanel({
onStateChange,
context = "page",
chromeVariant = "full",
composerDraftTarget,
}: {
environmentId: EnvironmentId;
reference: PullRequestRef;
Expand Down Expand Up @@ -206,6 +211,11 @@ export function PullRequestDetailPanel({
* top — the chrome spends its height on what is being read.
*/
chromeVariant?: "full" | "collapse";
/**
* The open thread's composer. Beside the thread whose own pull request this is, hand-offs
* land here instead of opening a new thread — the branch is already under the reader's feet.
*/
composerDraftTarget?: ScopedThreadRef | DraftId;
}) {
const pullRequestKey = `${reference.projectId}:${reference.repository}#${reference.number}`;
const [tab, setTab] = useState<DetailTab>("summary");
Expand Down Expand Up @@ -393,6 +403,27 @@ export function PullRequestDetailPanel({
reviewComments?: ReadonlyArray<ReviewCommentContext>;
};

// Beside the thread whose own pull request this is, a task belongs in that thread's composer:
// the branch is already checked out under it, so opening a second thread would only scatter
// the work.
const attachTarget = context === "thread" ? (composerDraftTarget ?? null) : null;
Comment thread
Bil0000 marked this conversation as resolved.

const writeTaskToComposer = (target: ScopedThreadRef | DraftId, task: ThreadTask) => {
const store = useComposerDraftStore.getState();
const draft = store.getComposerDraft(target);
const key = composerTargetKey(target);
const prompt = handoffPrompt(
{ prompt: draft?.prompt ?? "", lastHandoffPrompt: lastHandoffPromptByDraft.get(key) },
task.prompt,
);
lastHandoffPromptByDraft.set(key, task.prompt);
store.setPrompt(target, prompt);
store.setReviewComments(
target,
handoffReviewComments(draft?.reviewComments ?? [], task.reviewComments ?? []),
);
};

/**
* Opens a thread on this project and leaves the task in its composer for the reader to send.
*
Expand All @@ -412,35 +443,30 @@ export function PullRequestDetailPanel({
() => null,
));
if (session === null) return null;
const store = useComposerDraftStore.getState();
if (task === null) return session;
// The latest press is the ask: it takes over what an earlier hand-off left, prompt and chips
// both, rather than stacking a second one under the first. What the reader typed themselves
// survives — the composer they are handed is not always a fresh one, and a prompt they have
// since edited is theirs rather than the hand-off's.
const draft = store.getComposerDraft(session.draftId);
const existingComments = draft?.reviewComments ?? [];
const prompt = handoffPrompt(
{
prompt: draft?.prompt ?? "",
lastHandoffPrompt: lastHandoffPromptByDraft.get(session.draftId),
},
task.prompt,
);
// Remember the hand-off's own contribution, not the merged prompt: only that sentence is
// this session's to take back next time, and the reader's text around it is not.
lastHandoffPromptByDraft.set(session.draftId, task.prompt);
store.setPrompt(session.draftId, prompt);
store.setReviewComments(
session.draftId,
handoffReviewComments(existingComments, task.reviewComments ?? []),
);
writeTaskToComposer(session.draftId, task);
return session;
};

/** A question about the change, which needs a thread and nothing else. */
const startAsk = async (kind: string, task: ThreadTask) => {
if (!detail || handoff !== null) return;
if (attachTarget !== null) {
writeTaskToComposer(attachTarget, task);
toastManager.add({
type: "success",
title: "Added to the composer",
description:
task.prompt.length > 0
? "The question is in the composer — read it over, then send."
: "The pull request is in the composer — type your question, then send.",
});
return;
}
setHandoff(kind);
const projectRef = scopeProjectRef(environmentId, detail.projectId);
const opened = await openThreadWithTask(projectRef, task);
Expand Down Expand Up @@ -477,6 +503,15 @@ export function PullRequestDetailPanel({
mode: "worktree" | "local" = "worktree",
) => {
if (!detail || handoff !== null) return;
if (attachTarget !== null && task !== null) {
writeTaskToComposer(attachTarget, task);
toastManager.add({
type: "success",
title: "Added to the composer",
description: "The task is in the composer — read it over, then send.",
});
return;
}
setHandoff(kind);
// The menu closes on the press and takes its "Preparing..." label with it, so this is the
// only thing answering for the checkout. It carries no timeout of its own: a loading toast
Expand Down
Loading