@@ -11,6 +11,12 @@ import {
1111 TerminalIcon ,
1212 TriangleAlertIcon ,
1313} from "lucide-react" ;
14+ import {
15+ prStatusIndicator ,
16+ resolveThreadPr ,
17+ terminalStatusFromRunningIds ,
18+ ThreadStatusLabel ,
19+ } from "./ThreadStatusIndicators" ;
1420import { ProjectFavicon } from "./ProjectFavicon" ;
1521import { autoAnimate } from "@formkit/auto-animate" ;
1622import React , { useCallback , useEffect , memo , useMemo , useRef , useState } from "react" ;
@@ -38,7 +44,6 @@ import {
3844 type SidebarProjectGroupingMode ,
3945 type ThreadEnvMode ,
4046 ThreadId ,
41- type GitStatusResult ,
4247} from "@t3tools/contracts" ;
4348import {
4449 parseScopedThreadKey ,
@@ -264,113 +269,6 @@ function buildThreadJumpLabelMap(input: {
264269 return mapping . size > 0 ? mapping : EMPTY_THREAD_JUMP_LABELS ;
265270}
266271
267- interface TerminalStatusIndicator {
268- label : "Terminal process running" ;
269- colorClass : string ;
270- pulse : boolean ;
271- }
272-
273- interface PrStatusIndicator {
274- label : "PR open" | "PR closed" | "PR merged" ;
275- colorClass : string ;
276- tooltip : string ;
277- url : string ;
278- }
279-
280- type ThreadPr = GitStatusResult [ "pr" ] ;
281-
282- function ThreadStatusLabel ( {
283- status,
284- compact = false ,
285- } : {
286- status : ThreadStatusPill ;
287- compact ?: boolean ;
288- } ) {
289- if ( compact ) {
290- return (
291- < span
292- title = { status . label }
293- className = { `inline-flex size-3.5 shrink-0 items-center justify-center ${ status . colorClass } ` }
294- >
295- < span
296- className = { `size-[9px] rounded-full ${ status . dotClass } ${
297- status . pulse ? "animate-pulse" : ""
298- } `}
299- />
300- < span className = "sr-only" > { status . label } </ span >
301- </ span >
302- ) ;
303- }
304-
305- return (
306- < span
307- title = { status . label }
308- className = { `inline-flex items-center gap-1 text-[10px] ${ status . colorClass } ` }
309- >
310- < span
311- className = { `h-1.5 w-1.5 rounded-full ${ status . dotClass } ${
312- status . pulse ? "animate-pulse" : ""
313- } `}
314- />
315- < span className = "hidden md:inline" > { status . label } </ span >
316- </ span >
317- ) ;
318- }
319-
320- function terminalStatusFromRunningIds (
321- runningTerminalIds : string [ ] ,
322- ) : TerminalStatusIndicator | null {
323- if ( runningTerminalIds . length === 0 ) {
324- return null ;
325- }
326- return {
327- label : "Terminal process running" ,
328- colorClass : "text-teal-600 dark:text-teal-300/90" ,
329- pulse : true ,
330- } ;
331- }
332-
333- function prStatusIndicator ( pr : ThreadPr ) : PrStatusIndicator | null {
334- if ( ! pr ) return null ;
335-
336- if ( pr . state === "open" ) {
337- return {
338- label : "PR open" ,
339- colorClass : "text-emerald-600 dark:text-emerald-300/90" ,
340- tooltip : `#${ pr . number } PR open: ${ pr . title } ` ,
341- url : pr . url ,
342- } ;
343- }
344- if ( pr . state === "closed" ) {
345- return {
346- label : "PR closed" ,
347- colorClass : "text-zinc-500 dark:text-zinc-400/80" ,
348- tooltip : `#${ pr . number } PR closed: ${ pr . title } ` ,
349- url : pr . url ,
350- } ;
351- }
352- if ( pr . state === "merged" ) {
353- return {
354- label : "PR merged" ,
355- colorClass : "text-violet-600 dark:text-violet-300/90" ,
356- tooltip : `#${ pr . number } PR merged: ${ pr . title } ` ,
357- url : pr . url ,
358- } ;
359- }
360- return null ;
361- }
362-
363- function resolveThreadPr (
364- threadBranch : string | null ,
365- gitStatus : GitStatusResult | null ,
366- ) : ThreadPr | null {
367- if ( threadBranch === null || gitStatus === null || gitStatus . branch !== threadBranch ) {
368- return null ;
369- }
370-
371- return gitStatus . pr ?? null ;
372- }
373-
374272interface SidebarThreadRowProps {
375273 thread : SidebarThreadSummary ;
376274 projectCwd : string | null ;
0 commit comments