Skip to content

Commit 0b78dfa

Browse files
lcompleteCopilot
andcommitted
feat(sidepanel): enhance welcome pane with action groups and link cards
- Refactored WelcomePane to include structured action groups for prompts, understanding, questioning, and library suggestions. - Introduced LinkCardsBlock component to display link card groups with expandable sections. - Updated session storage to handle pinned and archived states for sessions. - Added utility functions for title generation retry logic. - Removed unused SourcesBlock component. - Implemented tests for title generation retry state management. Co-authored-by: Copilot <copilot@github.com>
1 parent 1aedbe4 commit 0b78dfa

20 files changed

Lines changed: 1587 additions & 1583 deletions

app/extension/src/__tests__/sidepanelSessions.test.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,78 @@ describe("sidepanel session helpers", () => {
109109
"older-message",
110110
]);
111111
});
112+
113+
it("sorts pinned sessions above unpinned ones regardless of last-message time", () => {
114+
const ordered = sortSessionMetadataByActivity([
115+
createSession("newer-unpinned", {
116+
lastMessageAt: "2026-04-22T08:00:00.000Z",
117+
}),
118+
createSession("older-pinned", {
119+
lastMessageAt: "2026-04-20T08:00:00.000Z",
120+
pinned: true,
121+
pinnedAt: "2026-04-21T08:00:00.000Z",
122+
}),
123+
]);
124+
125+
expect(ordered.map((session) => session.id)).toEqual([
126+
"older-pinned",
127+
"newer-unpinned",
128+
]);
129+
});
130+
131+
it("orders multiple pinned sessions by most recently pinned", () => {
132+
const ordered = sortSessionMetadataByActivity([
133+
createSession("pinned-early", {
134+
pinned: true,
135+
pinnedAt: "2026-04-20T08:00:00.000Z",
136+
}),
137+
createSession("pinned-latest", {
138+
pinned: true,
139+
pinnedAt: "2026-04-22T08:00:00.000Z",
140+
}),
141+
]);
142+
143+
expect(ordered.map((session) => session.id)).toEqual([
144+
"pinned-latest",
145+
"pinned-early",
146+
]);
147+
});
148+
149+
it("exposes pinned and archived metadata when building from session data", () => {
150+
const metadata = buildSessionMetadata(
151+
createSessionData("session-pin", {
152+
pinned: true,
153+
pinnedAt: "2026-04-22T08:00:00.000Z",
154+
archived: true,
155+
archivedAt: "2026-04-22T08:05:00.000Z",
156+
})
157+
);
158+
159+
expect(metadata.pinned).toBe(true);
160+
expect(metadata.pinnedAt).toBe("2026-04-22T08:00:00.000Z");
161+
expect(metadata.archived).toBe(true);
162+
expect(metadata.archivedAt).toBe("2026-04-22T08:05:00.000Z");
163+
});
164+
165+
it("defaults pinned and archived fields to false when not set", () => {
166+
const metadata = buildSessionMetadata(createSessionData("session-default"));
167+
168+
expect(metadata.pinned).toBe(false);
169+
expect(metadata.archived).toBe(false);
170+
expect(metadata.pinnedAt).toBeUndefined();
171+
expect(metadata.archivedAt).toBeUndefined();
172+
});
173+
174+
it("reconciles metadata when pinned or archived flags diverge from the session", () => {
175+
const metadata = createSession("session-flip");
176+
const session = createSessionData("session-flip", {
177+
pinned: true,
178+
pinnedAt: "2026-04-22T08:00:00.000Z",
179+
});
180+
181+
const repaired = reconcileSessionMetadata(metadata, session);
182+
183+
expect(repaired.pinned).toBe(true);
184+
expect(repaired.pinnedAt).toBe("2026-04-22T08:00:00.000Z");
185+
});
112186
});
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import {
2+
getNextTitleGenerationRetryState,
3+
hasTitleGenerationAttemptsRemaining,
4+
resetTitleGenerationRetryState,
5+
} from "../sidepanel/utils/titleGenerationRetry";
6+
7+
describe("sidepanel title generation retry helpers", () => {
8+
it("starts a new request at the first attempt", () => {
9+
const next = getNextTitleGenerationRetryState(
10+
resetTitleGenerationRetryState(),
11+
"session-1:message-1"
12+
);
13+
14+
expect(next).toEqual({
15+
requestKey: "session-1:message-1",
16+
attempts: 1,
17+
});
18+
});
19+
20+
it("increments attempts for the same request", () => {
21+
const first = getNextTitleGenerationRetryState(
22+
resetTitleGenerationRetryState(),
23+
"session-1:message-1"
24+
);
25+
const second = getNextTitleGenerationRetryState(
26+
first,
27+
"session-1:message-1"
28+
);
29+
30+
expect(second).toEqual({
31+
requestKey: "session-1:message-1",
32+
attempts: 2,
33+
});
34+
});
35+
36+
it("resets attempts when the latest message changes", () => {
37+
const current = getNextTitleGenerationRetryState(
38+
resetTitleGenerationRetryState(),
39+
"session-1:message-1"
40+
);
41+
const next = getNextTitleGenerationRetryState(
42+
current,
43+
"session-1:message-2"
44+
);
45+
46+
expect(next).toEqual({
47+
requestKey: "session-1:message-2",
48+
attempts: 1,
49+
});
50+
});
51+
52+
it("stops retrying once the attempt budget is exhausted", () => {
53+
expect(hasTitleGenerationAttemptsRemaining(1, 3)).toBe(true);
54+
expect(hasTitleGenerationAttemptsRemaining(2, 3)).toBe(true);
55+
expect(hasTitleGenerationAttemptsRemaining(3, 3)).toBe(false);
56+
});
57+
});

app/extension/src/components/ai-elements/conversation.tsx

Lines changed: 0 additions & 169 deletions
This file was deleted.

0 commit comments

Comments
 (0)