Skip to content

Commit 18db5e2

Browse files
fix: restore main's automatic thread settling after the revert
Round-13 rebase onto main (2 commits). Main reverted the auto-settle opt-in (#8596 undoing #8321), so the branch drops the ported autoSettleMode machinery and returns to sidebarAutoSettleOnMerge with settling-by-default, keeping only the v2 shell-shape delta in threadSettled. The unpin confirmation (#7313) merges into the v2 thread-actions hook, and the mobile list tests re-sync to main's reverted semantics in v2 shapes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 9903422 commit 18db5e2

5 files changed

Lines changed: 66 additions & 36 deletions

File tree

‎apps/mobile/src/features/threads/threadListV2.test.ts‎

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,32 @@ describe("buildThreadListV2Items", () => {
470470
expect(layout.items[0]?.variant).toBe("card");
471471
});
472472

473+
it("settles a thread only when the cached pull request identity matches", () => {
474+
const thread = makeThread({
475+
id: ThreadId.make("linked-merged"),
476+
title: "Linked merged pull request",
477+
linkedPullRequest,
478+
});
479+
const layout = buildThreadListV2Items({
480+
threads: [thread],
481+
environmentId: null,
482+
searchQuery: "",
483+
changeRequestByKey: new Map([
484+
[
485+
`${environmentId}:${thread.id}`,
486+
{
487+
state: "merged" as const,
488+
linkedPullRequestKey: '["project-1","pingdotgg/t3code",42]',
489+
},
490+
],
491+
]),
492+
now: NOW,
493+
});
494+
495+
expect(layout.settledCount).toBe(1);
496+
expect(layout.items[0]?.variant).toBe("slim");
497+
});
498+
473499
it("moves pinned threads to the settled shelf when their pull request merges", () => {
474500
const merged = makeThread({
475501
id: ThreadId.make("pinned-merged"),
@@ -480,10 +506,7 @@ describe("buildThreadListV2Items", () => {
480506
threads: [makeThread({ id: ThreadId.make("active"), title: "Active" }), merged],
481507
environmentId: null,
482508
searchQuery: "",
483-
changeRequestByKey: new Map([
484-
[`${environmentId}:${merged.id}`, { state: "merged", updatedAt: NOW }],
485-
]),
486-
autoSettleMode: "change-request",
509+
changeRequestByKey: new Map([[`${environmentId}:${merged.id}`, { state: "merged" }]]),
487510
now: NOW,
488511
});
489512

@@ -512,7 +535,6 @@ describe("buildThreadListV2Items", () => {
512535
threads: [inactive],
513536
environmentId: null,
514537
searchQuery: "",
515-
autoSettleMode: "inactivity",
516538
now: NOW,
517539
});
518540

@@ -524,7 +546,7 @@ describe("buildThreadListV2Items", () => {
524546
expect(layout.settledCount).toBe(1);
525547
});
526548

527-
it("keeps pinned merged threads pinned when automatic settling is off", () => {
549+
it("keeps pinned merged threads pinned when auto-settle on merge is off", () => {
528550
const merged = makeThread({
529551
id: ThreadId.make("pinned-merged"),
530552
title: "Pinned merged pull request",
@@ -534,10 +556,8 @@ describe("buildThreadListV2Items", () => {
534556
threads: [merged],
535557
environmentId: null,
536558
searchQuery: "",
537-
changeRequestByKey: new Map([
538-
[`${environmentId}:${merged.id}`, { state: "merged", updatedAt: NOW }],
539-
]),
540-
autoSettleMode: "never",
559+
changeRequestByKey: new Map([[`${environmentId}:${merged.id}`, { state: "merged" }]]),
560+
autoSettleOnMerge: false,
541561
now: NOW,
542562
});
543563

@@ -549,16 +569,16 @@ describe("buildThreadListV2Items", () => {
549569
expect(layout.settledCount).toBe(0);
550570
});
551571

552-
it("keeps a merged thread active when automatic settling is off", () => {
572+
it("keeps a merged thread active when auto-settle on merge is off", () => {
553573
const merged = makeThread({ id: ThreadId.make("merged"), title: "Merged" });
554574
const layout = buildThreadListV2Items({
555575
threads: [merged],
556576
environmentId: null,
557577
searchQuery: "",
558578
changeRequestByKey: new Map([
559-
[`${environmentId}:${merged.id}`, { state: "merged" as const, updatedAt: NOW }],
579+
[`${environmentId}:${merged.id}`, { state: "merged" as const }],
560580
]),
561-
autoSettleMode: "never",
581+
autoSettleOnMerge: false,
562582
now: NOW,
563583
});
564584

‎apps/web/src/components/ChatView.tsx‎

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,7 +1264,7 @@ function ChatViewContent(props: ChatViewProps) {
12641264
} = props;
12651265
const draftId = routeKind === "draft" ? props.draftId : null;
12661266
const handleNewThread = useNewThreadHandler();
1267-
const { settleThread, pinThread, unpinThread } = useThreadActions();
1267+
const { settleThread, pinThread, confirmAndUnpinThread } = useThreadActions();
12681268
const routeThreadRef = useMemo(
12691269
() => scopeThreadRef(environmentId, threadId),
12701270
[environmentId, threadId],
@@ -4484,7 +4484,7 @@ function ChatViewContent(props: ChatViewProps) {
44844484
// The server-projected settled state keeps the banner and sidebar in sync.
44854485
const activeThreadShell = useThreadShell(isServerThread ? activeThreadRef : null);
44864486
const autoSettleAfterDays = useClientSettings((settings) => settings.sidebarAutoSettleAfterDays);
4487-
const autoSettleMode = useClientSettings((settings) => settings.sidebarAutoSettleMode);
4487+
const autoSettleOnMerge = useClientSettings((settings) => settings.sidebarAutoSettleOnMerge);
44884488
const changeRequestSnapshotByKey = useAtomValue(threadChangeRequestSnapshotsAtom);
44894489
// The thread's own change request, placed against the project it belongs to.
44904490
const linkedThreadPullRequest = activeThread?.linkedPullRequest ?? null;
@@ -4556,8 +4556,10 @@ function ChatViewContent(props: ChatViewProps) {
45564556
const activeThreadWokeVisible = useMemo(() => {
45574557
if (activeThreadWokeAt === null) return false;
45584558
if (
4559-
autoSettleMode === "change-request" &&
4560-
changeRequestAutoSettles(activeThreadChangeRequest, { thread: activeThreadShell })
4559+
changeRequestAutoSettles(activeThreadChangeRequest, {
4560+
autoSettleOnMerge,
4561+
thread: activeThreadShell,
4562+
})
45614563
) {
45624564
return false;
45634565
}
@@ -4583,21 +4585,21 @@ function ChatViewContent(props: ChatViewProps) {
45834585
activeThreadChangeRequest,
45844586
activeThreadShell,
45854587
activeThreadWokeAt,
4586-
autoSettleMode,
4588+
autoSettleOnMerge,
45874589
]);
45884590
const activeThreadSettled = useMemo(() => {
45894591
if (activeThreadShell === null || !supportsSettlement) return false;
45904592
return effectiveSettled(activeThreadShell, {
45914593
now: `${nowMinute}:00.000Z`,
45924594
autoSettleAfterDays,
4593-
autoSettleMode,
4595+
autoSettleOnMerge,
45944596
changeRequest: activeThreadChangeRequest,
45954597
});
45964598
}, [
45974599
activeThreadPr?.state,
45984600
activeThreadShell,
45994601
autoSettleAfterDays,
4600-
autoSettleMode,
4602+
autoSettleOnMerge,
46014603
changeRequestSnapshotByKey,
46024604
nowMinute,
46034605
supportsSettlement,
@@ -5018,17 +5020,19 @@ function ChatViewContent(props: ChatViewProps) {
50185020
event.stopPropagation();
50195021
if (!isServerThread || !activeThreadRef || !supportsPinning) return;
50205022
const pinned = activeThreadPinned;
5021-
void (pinned ? unpinThread(activeThreadRef) : pinThread(activeThreadRef)).then((result) => {
5022-
if (result._tag !== "Failure" || isAtomCommandInterrupted(result)) return;
5023-
const error = squashAtomCommandFailure(result);
5024-
toastManager.add(
5025-
stackedThreadToast({
5026-
type: "error",
5027-
title: pinned ? "Failed to unpin thread" : "Failed to pin thread",
5028-
description: error instanceof Error ? error.message : "An error occurred.",
5029-
}),
5030-
);
5031-
});
5023+
void (pinned ? confirmAndUnpinThread(activeThreadRef) : pinThread(activeThreadRef)).then(
5024+
(result) => {
5025+
if (result._tag !== "Failure" || isAtomCommandInterrupted(result)) return;
5026+
const error = squashAtomCommandFailure(result);
5027+
toastManager.add(
5028+
stackedThreadToast({
5029+
type: "error",
5030+
title: pinned ? "Failed to unpin thread" : "Failed to pin thread",
5031+
description: error instanceof Error ? error.message : "An error occurred.",
5032+
}),
5033+
);
5034+
},
5035+
);
50325036
return;
50335037
}
50345038

@@ -5154,7 +5158,7 @@ function ChatViewContent(props: ChatViewProps) {
51545158
settleThread,
51555159
supportsPinning,
51565160
supportsSettlement,
5157-
unpinThread,
5161+
confirmAndUnpinThread,
51585162
toggleRightPanel,
51595163
toggleThreadPanel,
51605164
toggleTerminalVisibility,

‎apps/web/src/components/Sidebar.tsx‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,10 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
854854
const isWoke =
855855
wokeAtDate !== null &&
856856
(lastVisitedDate === null || lastVisitedDate < wokeAtDate) &&
857-
!(props.autoSettleMode === "change-request" && changeRequestAutoSettles(pr, { thread }));
857+
!changeRequestAutoSettles(pr, {
858+
autoSettleOnMerge: props.autoSettleOnMerge,
859+
thread,
860+
});
858861
// In-flight rows (working, or waiting on approval/input) fade as a whole:
859862
// there is nothing for the user to do yet, so prominence is reserved for
860863
// rows that need a human — done (unread), read-but-unsettled, failed, and
@@ -2174,7 +2177,7 @@ export default function Sidebar() {
21742177
effectiveSettled(thread, {
21752178
now,
21762179
autoSettleAfterDays,
2177-
autoSettleMode,
2180+
autoSettleOnMerge,
21782181
changeRequest,
21792182
})
21802183
) {
@@ -2211,7 +2214,7 @@ export default function Sidebar() {
22112214
};
22122215
}, [
22132216
autoSettleAfterDays,
2214-
autoSettleMode,
2217+
autoSettleOnMerge,
22152218
changeRequestSnapshotByKey,
22162219
nowMinute,
22172220
scopedProjectKeys,

‎apps/web/src/hooks/useThreadActions.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ export async function requestThreadUnpinConfirmation(input: {
145145
"This will move the thread out of your pinned section.",
146146
].join("\n"),
147147
),
148+
);
149+
}
150+
148151
/**
149152
* Marks a thread unread. Servers with visited tracking own the unread marker
150153
* (thread.mark-unread rewinds the server-side visited watermark, syncing the

‎packages/client-runtime/src/state/threadSettled.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// @effect-diagnostics globalDate:off -- UI snooze presets use local calendar boundaries and Intl labels.
2-
import type { OrchestrationThreadShell, SidebarAutoSettleMode } from "@t3tools/contracts";
2+
import type { OrchestrationThreadShell } from "@t3tools/contracts";
33
import * as DateTime from "effect/DateTime";
44

55
interface SettlementRunLike {

0 commit comments

Comments
 (0)