@@ -9,13 +9,17 @@ import {
99 type DesktopBridge ,
1010 type DesktopUpdateChannel ,
1111 type DesktopUpdateState ,
12+ type EnvironmentApi ,
1213 type LocalApi ,
14+ type OrchestrationShellSnapshot ,
15+ ProjectId ,
1316 ProviderDriverKind ,
1417 ProviderInstanceId ,
1518 type ServerConfig ,
1619 type ServerProcessResourceHistoryResult ,
1720 type ServerProvider ,
1821 type SourceControlDiscoveryResult ,
22+ ThreadId ,
1923} from "@t3tools/contracts" ;
2024import * as DateTime from "effect/DateTime" ;
2125import * as Option from "effect/Option" ;
@@ -30,14 +34,24 @@ import {
3034 createRoute ,
3135 createRouter ,
3236} from "@tanstack/react-router" ;
37+ import { QueryClient , QueryClientProvider } from "@tanstack/react-query" ;
3338
3439import { __resetLocalApiForTests } from "../../localApi" ;
40+ import {
41+ __resetEnvironmentApiOverridesForTests ,
42+ __setEnvironmentApiOverrideForTests ,
43+ } from "../../environmentApi" ;
3544import { AppAtomRegistryProvider , resetAppAtomRegistryForTests } from "../../rpc/atomRegistry" ;
3645import { resetServerStateForTests , setServerConfigSnapshot } from "../../rpc/serverState" ;
46+ import { useStore } from "../../store" ;
3747import { useUiStateStore } from "../../uiStateStore" ;
3848import { ConnectionsSettings } from "./ConnectionsSettings" ;
3949import { DiagnosticsSettingsPanel } from "./DiagnosticsSettings" ;
40- import { GeneralSettingsPanel , ProviderSettingsPanel } from "./SettingsPanels" ;
50+ import {
51+ ArchivedThreadsPanel ,
52+ GeneralSettingsPanel ,
53+ ProviderSettingsPanel ,
54+ } from "./SettingsPanels" ;
4155import { SourceControlSettingsPanel } from "./SourceControlSettings" ;
4256
4357function renderWithTestRouter ( children : ReactNode ) {
@@ -283,6 +297,71 @@ function createEmptyProcessResourceHistoryResult(): ServerProcessResourceHistory
283297 } ;
284298}
285299
300+ const archivedPanelEnvironmentId = EnvironmentId . make ( "environment-archive-test" ) ;
301+ const archivedPanelProjectId = ProjectId . make ( "project-docs" ) ;
302+ const archivedPanelModelSelection = {
303+ instanceId : ProviderInstanceId . make ( "codex" ) ,
304+ model : "gpt-5" ,
305+ } ;
306+
307+ function createArchivedPanelSnapshot (
308+ threads : OrchestrationShellSnapshot [ "threads" ] ,
309+ ) : OrchestrationShellSnapshot {
310+ return {
311+ snapshotSequence : 1 ,
312+ projects : [
313+ {
314+ id : archivedPanelProjectId ,
315+ title : "Docs Portal" ,
316+ workspaceRoot : "/work/clients/docs" ,
317+ defaultModelSelection : archivedPanelModelSelection ,
318+ scripts : [ ] ,
319+ createdAt : "2036-04-07T00:00:00.000Z" ,
320+ updatedAt : "2036-04-07T00:00:00.000Z" ,
321+ } ,
322+ ] ,
323+ threads,
324+ updatedAt : "2036-04-07T00:03:00.000Z" ,
325+ } ;
326+ }
327+
328+ function createArchivedPanelThread ( input : {
329+ readonly id : string ;
330+ readonly title : string ;
331+ readonly branch : string | null ;
332+ readonly worktreePath : string | null ;
333+ readonly createdAt : string ;
334+ readonly archivedAt : string ;
335+ } ) : OrchestrationShellSnapshot [ "threads" ] [ number ] {
336+ return {
337+ id : ThreadId . make ( input . id ) ,
338+ projectId : archivedPanelProjectId ,
339+ title : input . title ,
340+ modelSelection : archivedPanelModelSelection ,
341+ runtimeMode : "full-access" ,
342+ interactionMode : "default" ,
343+ branch : input . branch ,
344+ worktreePath : input . worktreePath ,
345+ latestTurn : null ,
346+ createdAt : input . createdAt ,
347+ updatedAt : input . archivedAt ,
348+ archivedAt : input . archivedAt ,
349+ session : null ,
350+ latestUserMessageAt : null ,
351+ hasPendingApprovals : false ,
352+ hasPendingUserInput : false ,
353+ hasActionableProposedPlan : false ,
354+ } ;
355+ }
356+
357+ function createArchivedPanelEnvironmentApi ( snapshot : OrchestrationShellSnapshot ) : EnvironmentApi {
358+ return {
359+ orchestration : {
360+ getArchivedShellSnapshot : vi . fn ( ) . mockResolvedValue ( snapshot ) ,
361+ } ,
362+ } as unknown as EnvironmentApi ;
363+ }
364+
286365function makePairingLink ( input : {
287366 readonly id : string ;
288367 readonly credential : string ;
@@ -1219,6 +1298,106 @@ describe("GeneralSettingsPanel observability", () => {
12191298 } ) ;
12201299} ) ;
12211300
1301+ describe ( "ArchivedThreadsPanel" , ( ) => {
1302+ let mounted :
1303+ | ( Awaited < ReturnType < typeof render > > & {
1304+ cleanup ?: ( ) => Promise < void > ;
1305+ unmount ?: ( ) => Promise < void > ;
1306+ } )
1307+ | null = null ;
1308+
1309+ beforeEach ( ( ) => {
1310+ resetAppAtomRegistryForTests ( ) ;
1311+ __resetEnvironmentApiOverridesForTests ( ) ;
1312+ document . body . innerHTML = "" ;
1313+ useStore . setState ( {
1314+ activeEnvironmentId : null ,
1315+ environmentStateById : { } ,
1316+ } ) ;
1317+ } ) ;
1318+
1319+ afterEach ( async ( ) => {
1320+ if ( mounted ) {
1321+ const teardown = mounted . cleanup ?? mounted . unmount ;
1322+ await teardown ?. call ( mounted ) . catch ( ( ) => { } ) ;
1323+ }
1324+ mounted = null ;
1325+ document . body . innerHTML = "" ;
1326+ __resetEnvironmentApiOverridesForTests ( ) ;
1327+ resetAppAtomRegistryForTests ( ) ;
1328+ useStore . setState ( {
1329+ activeEnvironmentId : null ,
1330+ environmentStateById : { } ,
1331+ } ) ;
1332+ } ) ;
1333+
1334+ it ( "searches archived threads and collapses archived projects" , async ( ) => {
1335+ useStore
1336+ . getState ( )
1337+ . syncServerShellSnapshot ( createArchivedPanelSnapshot ( [ ] ) , archivedPanelEnvironmentId ) ;
1338+
1339+ __setEnvironmentApiOverrideForTests (
1340+ archivedPanelEnvironmentId ,
1341+ createArchivedPanelEnvironmentApi (
1342+ createArchivedPanelSnapshot ( [
1343+ createArchivedPanelThread ( {
1344+ id : "thread-docs-bug" ,
1345+ title : "Fix publishing bug" ,
1346+ branch : "docs-fix" ,
1347+ worktreePath : "/work/clients/docs/.worktrees/docs-fix" ,
1348+ createdAt : "2036-04-07T00:01:00.000Z" ,
1349+ archivedAt : "2036-04-07T00:04:00.000Z" ,
1350+ } ) ,
1351+ createArchivedPanelThread ( {
1352+ id : "thread-docs-homepage" ,
1353+ title : "Rewrite homepage copy" ,
1354+ branch : null ,
1355+ worktreePath : null ,
1356+ createdAt : "2036-04-07T00:02:00.000Z" ,
1357+ archivedAt : "2036-04-07T00:03:00.000Z" ,
1358+ } ) ,
1359+ ] ) ,
1360+ ) ,
1361+ ) ;
1362+
1363+ const queryClient = new QueryClient ( {
1364+ defaultOptions : {
1365+ queries : { retry : false } ,
1366+ mutations : { retry : false } ,
1367+ } ,
1368+ } ) ;
1369+
1370+ mounted = await renderWithTestRouter (
1371+ < QueryClientProvider client = { queryClient } >
1372+ < AppAtomRegistryProvider >
1373+ < ArchivedThreadsPanel />
1374+ </ AppAtomRegistryProvider >
1375+ </ QueryClientProvider > ,
1376+ ) ;
1377+
1378+ await expect . element ( page . getByText ( "Fix publishing bug" ) ) . toBeInTheDocument ( ) ;
1379+ await expect . element ( page . getByText ( "Rewrite homepage copy" ) ) . toBeInTheDocument ( ) ;
1380+
1381+ await page . getByLabelText ( "Search archived threads" ) . fill ( "homepage" ) ;
1382+
1383+ await expect . element ( page . getByText ( "Rewrite homepage copy" ) ) . toBeInTheDocument ( ) ;
1384+ await expect . element ( page . getByText ( "Fix publishing bug" ) ) . not . toBeInTheDocument ( ) ;
1385+
1386+ await page . getByLabelText ( "Search archived threads" ) . fill ( "" ) ;
1387+ await expect . element ( page . getByText ( "Fix publishing bug" ) ) . toBeInTheDocument ( ) ;
1388+
1389+ await page . getByRole ( "button" , { name : "Collapse Docs Portal" , exact : true } ) . click ( ) ;
1390+
1391+ await expect . element ( page . getByText ( "Fix publishing bug" ) ) . not . toBeInTheDocument ( ) ;
1392+ await expect . element ( page . getByText ( "Rewrite homepage copy" ) ) . not . toBeInTheDocument ( ) ;
1393+
1394+ await page . getByRole ( "button" , { name : "Expand Docs Portal" , exact : true } ) . click ( ) ;
1395+
1396+ await expect . element ( page . getByText ( "Fix publishing bug" ) ) . toBeInTheDocument ( ) ;
1397+ await expect . element ( page . getByText ( "Rewrite homepage copy" ) ) . toBeInTheDocument ( ) ;
1398+ } ) ;
1399+ } ) ;
1400+
12221401describe ( "SourceControlSettingsPanel discovery states" , ( ) => {
12231402 let mounted :
12241403 | ( Awaited < ReturnType < typeof render > > & {
0 commit comments