Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
64e9963
feat: discover saved drafts through thread lifecycle filters
brsbl Sep 19, 2026
597c10e
test: align lifecycle projection fixtures and contract allowlist
brsbl Sep 19, 2026
75e3507
test: align CLI assertions with existing search and logging contracts
brsbl Sep 19, 2026
759f542
Add sidebar thread lifecycle filters
brsbl Sep 19, 2026
9cdd061
test: supply required identity in draft CLI fixture
brsbl Sep 19, 2026
f7054df
Keep lifecycle filtering nonmodal and await query updates
brsbl Sep 19, 2026
dec4581
Include lifecycle metadata in realtime list fixture
brsbl Sep 19, 2026
7926ec8
Merge commit '9cdd061f528718aba9eb11fbd432b4586b327d05' into bb/sideb…
brsbl Sep 19, 2026
38819e2
Order lifecycle-filtered lists by global recency
brsbl Sep 19, 2026
d359076
Merge commit '38819e21f3dc923c773be8a64cf97cbbd57aba33' into bb/sideb…
brsbl Sep 19, 2026
12262cd
Remove duplicate unavailable Drafts fixture
brsbl Sep 19, 2026
fc608d8
Merge commit '12262cd53a185097577f93e545290f92aa048898' into bb/sideb…
brsbl Sep 19, 2026
57140ea
Move sidebar lifecycle filters into combined header menus
brsbl Sep 20, 2026
a239bdd
Show and reset modified sidebar view settings
brsbl Sep 20, 2026
155ebcd
Preserve sidebar menu state through tooltip trigger
brsbl Sep 20, 2026
9c078a3
Defer sidebar view menu contents until opened
brsbl Sep 20, 2026
819e2bd
Render active sidebar hierarchy without a duplicate header
brsbl Sep 20, 2026
2d6dc18
Integrate archived threads into the sidebar hierarchy
brsbl Sep 20, 2026
184dbc7
Use the sidebar divider token and update grouping guidance
brsbl Sep 20, 2026
5906b72
Align sidebar settings guides with the combined menu
brsbl Sep 20, 2026
e55cc0f
Match sidebar lifecycle test harness to retained sections
brsbl Sep 20, 2026
bcdbe00
Quiet sidebar view controls and archived restore action
brsbl Sep 20, 2026
bc4be26
Preserve Organize controls and simplify lifecycle actions
brsbl Sep 20, 2026
97842a5
Remove sidebar sort and filter reset actions
brsbl Sep 21, 2026
67ca2d9
Keep selected lifecycle filter rows at normal contrast
brsbl Sep 21, 2026
3205aa3
Index saved queued messages in thread search
brsbl Sep 21, 2026
ff7f214
Treat saved drafts as messages in the ordinary thread list
brsbl Sep 21, 2026
4a04882
Merge branch 'bb/draft-lifecycle-thr_82jtfaq8eq' into bb/sidebar-thre…
brsbl Sep 21, 2026
421870d
Preserve queue corruption diagnostics and migration fixtures
brsbl Sep 21, 2026
a017003
Merge branch 'bb/draft-lifecycle-thr_82jtfaq8eq' into bb/sidebar-thre…
brsbl Sep 21, 2026
1e9c39b
Rewind queue search rows with the migration fixture
brsbl Sep 21, 2026
c9dac9b
Merge branch 'bb/draft-lifecycle-thr_82jtfaq8eq' into bb/sidebar-thre…
brsbl Sep 21, 2026
0d40817
Handle pre-search schemas when rewinding migration fixtures
brsbl Sep 21, 2026
7a954da
Merge commit '0d4081763' into bb/sidebar-thread-lifecycle-filters-thr…
brsbl Sep 21, 2026
0d91874
Merge main and advance saved-message search migration
brsbl Sep 21, 2026
cc64611
Merge updated search foundation into sidebar filters
brsbl Sep 21, 2026
4b4bc3a
Keep sidebar view settings inside the lazy menu
brsbl Sep 21, 2026
55c7625
Remove draft thread lifecycle API and classification
brsbl Sep 21, 2026
3b7a667
Remove draft classification from sidebar filtering
brsbl Sep 21, 2026
6af934a
Remove remaining lifecycle fields from sidebar fixtures
brsbl Sep 21, 2026
741fd21
Use Filter for thread filter labels
brsbl Sep 21, 2026
c717d34
Assert native hover hint only in desktop filter menu
brsbl Sep 21, 2026
165defe
Match the thread filter icon to existing controls
brsbl Sep 21, 2026
fa8c241
Show All when every thread filter is selected
brsbl Sep 21, 2026
575c44a
Detach sidebar filters from deferred draft search and update main
brsbl Sep 21, 2026
46a3b3c
Adapt sidebar filter fixture to current section visibility
brsbl Sep 21, 2026
e47acfc
Defer sidebar menu contents until first open
brsbl Sep 21, 2026
1582c7d
Keep menu type imports with module imports
brsbl Sep 21, 2026
8bfbf64
Load sidebar customization only when requested
brsbl Sep 21, 2026
fca0570
Hide archived sidebar restore icon on mobile
brsbl Sep 21, 2026
b1c8496
Use the unarchive icon for archived sidebar row actions
brsbl Sep 21, 2026
73692f4
Use background focus treatment for sidebar action buttons
brsbl Sep 21, 2026
706650e
Restore conventional sidebar keyboard focus
brsbl Sep 21, 2026
4ad63bb
Test restored sidebar rows remain visible during unarchive
brsbl Sep 21, 2026
3fc3fdb
Keep restored sidebar threads visible throughout unarchive
brsbl Sep 21, 2026
3a4b1fe
Consolidate sidebar filter regression coverage
brsbl Sep 21, 2026
ec7d784
Merge main into sidebar archive filters
brsbl Sep 21, 2026
c2f3cbd
Keep sidebar archive filtering browser-local
brsbl Sep 21, 2026
9255e4c
Remove unused archive action icon override
brsbl Sep 21, 2026
73b10b3
test(app): consolidate sidebar archive regression coverage
brsbl Sep 21, 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
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,7 @@ describe("PluginNavSidebarItems", () => {

expect(onCompactCustomizeModeChange).toHaveBeenCalledWith(true);
expect(
screen.getByTestId("sidebar-navigation-customize-inline"),
await screen.findByTestId("sidebar-navigation-customize-inline"),
).not.toBeNull();
expect(
screen
Expand Down
165 changes: 95 additions & 70 deletions apps/app/src/components/sidebar/ProjectList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ import {
import { isTransientReadError } from "@/hooks/queries/query-helpers";
import { stripProjectThreads } from "@/hooks/queries/project-queries";
import { useSidebarNavigation } from "@/hooks/queries/sidebar-navigation-query";
import {
SidebarThreadLifecycles,
useSidebarThreadLifecycles,
} from "./SidebarThreadLifecycles";
import { useSystemConfig } from "@/hooks/queries/system-queries";
import { useReorderPinnedThread } from "@/hooks/mutations/thread-state-mutations";
import {
Expand Down Expand Up @@ -1437,7 +1441,7 @@ function ProjectListComponent({
() => sidebarNavigation?.projects.map(stripProjectThreads),
[sidebarNavigation],
);
const threads = useMemo(() => {
const unarchivedThreads = useMemo(() => {
if (!sidebarNavigation) {
return [];
}
Expand All @@ -1448,6 +1452,8 @@ function ProjectListComponent({
sidebarThreads.push(...sidebarNavigation.personalProject.threads);
return sidebarThreads;
}, [sidebarNavigation]);
const lifecycles = useSidebarThreadLifecycles(unarchivedThreads);
const { threads } = lifecycles;
const draftThreadIds = usePromptDraftInputThreadIds(threads);
const titleMentionResources = useThreadTitleMentionResources();
const uiPreferencesReady = useUiPreferencesReady();
Expand All @@ -1460,6 +1466,12 @@ function ProjectListComponent({
),
});
const { threadId: selectedThreadId } = useRouteState();
const hierarchyStatus =
projectsState.status === "ready" &&
lifecycles.value.includes("archived") &&
!lifecycles.value.includes("active")
? lifecycles.archivedStatus
: projectsState.status;
const {
isPending: isPinnedReorderPending,
mutate: reorderPinnedThreadMutate,
Expand Down Expand Up @@ -1786,76 +1798,28 @@ function ProjectListComponent({
}}
>
<ProjectListShell>
<ActiveSidebarModeSections
mode={organizationMode}
renderMachine={() => (
<MachineModeSections
threads={threads}
draftThreadIds={draftThreadIds}
effectivePinnedThreadIds={
pinnedSidebarState.effectivePinnedThreadIds
}
status={projectsState.status}
showPinnedSection={hasPinnedSection}
pinnedSection={pinnedSection}
pinnedReorderPending={isPinnedReorderPending}
pinnedRootNodes={pinnedSidebarState.rootNodes}
pinnedThreads={pinnedRootThreads}
onReorderPinnedThread={handleReorderPinnedRoot}
threadsSection={threadsSection}
selectedThreadId={selectedThreadId}
collapsedSectionIds={collapsedSidebarSectionIds}
collapsedThreadIds={collapsedThreadIds}
collapsedEnvironmentIds={collapsedEnvironmentIds}
compareThreads={sidebarThreadComparator}
renderSectionDisplayOptions={renderSectionDisplayOptions}
isSectionDisplayOptionsOpen={isSectionDisplayOptionsOpen}
onProjectSelect={onProjectSelect}
onToggleCollapsed={toggleSidebarSectionCollapsed}
onToggleThreadCollapsed={toggleThreadCollapsed}
onToggleEnvironmentCollapsed={toggleEnvironmentCollapsed}
/>
)}
renderChronological={() => (
<>
<SectionModeSections
threads={threads}
effectivePinnedThreadIds={
pinnedSidebarState.effectivePinnedThreadIds
}
status={projectsState.status}
showPinnedSection={hasPinnedSection}
sections={sections}
pinnedSection={pinnedSection}
pinnedReorderPending={isPinnedReorderPending}
pinnedRootNodes={pinnedSidebarState.rootNodes}
pinnedThreads={pinnedRootThreads}
onReorderPinnedThread={handleReorderPinnedRoot}
threadsSection={threadsSection}
selectedThreadId={selectedThreadId}
collapsedSectionIds={collapsedSidebarSectionIds}
collapsedThreadIds={collapsedThreadIds}
collapsedEnvironmentIds={collapsedEnvironmentIds}
compareThreads={sidebarThreadComparator}
onProjectSelect={onProjectSelect}
onCreateThreadInSection={handleCreateThreadInSection}
onRemoveSection={handleRemoveThreadSection}
onToggleCollapsed={toggleSidebarSectionCollapsed}
onToggleThreadCollapsed={toggleThreadCollapsed}
onToggleEnvironmentCollapsed={toggleEnvironmentCollapsed}
/>
</>
)}
renderProject={() => (
<>
<ProjectModeSections
projects={projects ?? EMPTY_PROJECTS}
<SidebarThreadLifecycles
lifecycles={lifecycles}
treeProps={{
compareThreads: sidebarThreadComparator,
selectedThreadId,
collapsedThreadIds,
collapsedEnvironmentIds,
onProjectSelect,
onToggleThreadCollapsed: toggleThreadCollapsed,
onToggleEnvironmentCollapsed: toggleEnvironmentCollapsed,
}}
>
<ActiveSidebarModeSections
mode={organizationMode}
renderMachine={() => (
<MachineModeSections
threads={threads}
draftThreadIds={draftThreadIds}
effectivePinnedThreadIds={
pinnedSidebarState.effectivePinnedThreadIds
}
status={projectsState.status}
status={hierarchyStatus}
showPinnedSection={hasPinnedSection}
pinnedSection={pinnedSection}
pinnedReorderPending={isPinnedReorderPending}
Expand All @@ -1868,15 +1832,76 @@ function ProjectListComponent({
collapsedThreadIds={collapsedThreadIds}
collapsedEnvironmentIds={collapsedEnvironmentIds}
compareThreads={sidebarThreadComparator}
renderSectionDisplayOptions={renderSectionDisplayOptions}
isSectionDisplayOptionsOpen={isSectionDisplayOptionsOpen}
onProjectSelect={onProjectSelect}
onCreateProjectThread={handleCreateProjectThread}
onToggleCollapsed={toggleSidebarSectionCollapsed}
onToggleThreadCollapsed={toggleThreadCollapsed}
onToggleEnvironmentCollapsed={toggleEnvironmentCollapsed}
/>
</>
)}
/>
)}
renderChronological={() => (
<>
<SectionModeSections
threads={threads}
effectivePinnedThreadIds={
pinnedSidebarState.effectivePinnedThreadIds
}
status={hierarchyStatus}
showPinnedSection={hasPinnedSection}
sections={sections}
pinnedSection={pinnedSection}
pinnedReorderPending={isPinnedReorderPending}
pinnedRootNodes={pinnedSidebarState.rootNodes}
pinnedThreads={pinnedRootThreads}
onReorderPinnedThread={handleReorderPinnedRoot}
threadsSection={threadsSection}
selectedThreadId={selectedThreadId}
collapsedSectionIds={collapsedSidebarSectionIds}
collapsedThreadIds={collapsedThreadIds}
collapsedEnvironmentIds={collapsedEnvironmentIds}
compareThreads={sidebarThreadComparator}
onProjectSelect={onProjectSelect}
onCreateThreadInSection={handleCreateThreadInSection}
onRemoveSection={handleRemoveThreadSection}
onToggleCollapsed={toggleSidebarSectionCollapsed}
onToggleThreadCollapsed={toggleThreadCollapsed}
onToggleEnvironmentCollapsed={toggleEnvironmentCollapsed}
/>
</>
)}
renderProject={() => (
<>
<ProjectModeSections
projects={projects ?? EMPTY_PROJECTS}
threads={threads}
draftThreadIds={draftThreadIds}
effectivePinnedThreadIds={
pinnedSidebarState.effectivePinnedThreadIds
}
status={hierarchyStatus}
showPinnedSection={hasPinnedSection}
pinnedSection={pinnedSection}
pinnedReorderPending={isPinnedReorderPending}
pinnedRootNodes={pinnedSidebarState.rootNodes}
pinnedThreads={pinnedRootThreads}
onReorderPinnedThread={handleReorderPinnedRoot}
threadsSection={threadsSection}
selectedThreadId={selectedThreadId}
collapsedSectionIds={collapsedSidebarSectionIds}
collapsedThreadIds={collapsedThreadIds}
collapsedEnvironmentIds={collapsedEnvironmentIds}
compareThreads={sidebarThreadComparator}
onProjectSelect={onProjectSelect}
onCreateProjectThread={handleCreateProjectThread}
onToggleCollapsed={toggleSidebarSectionCollapsed}
onToggleThreadCollapsed={toggleThreadCollapsed}
onToggleEnvironmentCollapsed={toggleEnvironmentCollapsed}
/>
</>
)}
/>
</SidebarThreadLifecycles>
</ProjectListShell>
{sectionCreateDialog}
{sectionDeleteDialogContent}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ describe("ProjectRow interactions", () => {
it("keeps project header controls touch-accessible when their menu opens and closes", async () => {
renderProjectRow();
const trigger = screen.getByRole("button", {
name: "Test project actions",
name: /^Test project actions(?:;|$)/,
});
const actions = trigger.closest(".bb-sidebar-hover-actions");
expect(actions?.getAttribute("data-sidebar-hover-actions-mobile")).toBe(
Expand Down
Loading
Loading