@@ -19,6 +19,8 @@ import {
1919 Clock ,
2020 FileJson ,
2121 FolderOpen ,
22+ UnfoldVertical ,
23+ FoldVertical ,
2224} from 'lucide-react' ;
2325import { ServerActionMenu } from './ServerActionMenu' ;
2426import { CloneAccountModal } from './CloneAccountModal' ;
@@ -525,6 +527,31 @@ export function ServersPage() {
525527 return 'connected_auto' ;
526528 } ;
527529
530+ /** Connected servers that show the expand/collapse chevron in the list. */
531+ const isServerExpandable = ( server : ServerViewModel ) : boolean => {
532+ const action = getServerAction ( server ) ;
533+ return action === 'running' || action === 'connected_auto' ;
534+ } ;
535+
536+ /** Expands every connected server row and loads features for any not yet fetched. */
537+ const expandAllServers = ( ) => {
538+ const expandableIds = installedServers . filter ( isServerExpandable ) . map ( ( s ) => s . id ) ;
539+ setExpandedServers ( new Set ( expandableIds ) ) ;
540+ for ( const serverId of expandableIds ) {
541+ if ( ! serverFeatures [ serverId ] ) {
542+ loadFeaturesForServer ( serverId ) ;
543+ }
544+ }
545+ } ;
546+
547+ /** Collapses every expanded server row. */
548+ const collapseAllServers = ( ) => {
549+ setExpandedServers ( new Set ( ) ) ;
550+ } ;
551+
552+ const expandableServerCount = installedServers . filter ( isServerExpandable ) . length ;
553+ const hasExpandedServers = expandedServers . size > 0 ;
554+
528555 // Get display status for UI
529556 const getDisplayStatus = ( server : ServerViewModel ) : string => {
530557 const action = getServerAction ( server ) ;
@@ -1029,13 +1056,42 @@ export function ServersPage() {
10291056 </ p >
10301057 </ div >
10311058 { viewSpace && (
1032- < button
1033- onClick = { ( ) => setEditConfigSpace ( { id : viewSpace . id , name : viewSpace . name } ) }
1034- className = "flex items-center gap-2 px-4 py-2.5 text-sm font-medium rounded-lg bg-[rgb(var(--surface-elevated))] border border-[rgb(var(--border))] hover:bg-[rgb(var(--surface-hover))] hover:border-[rgb(var(--border-subtle))] shadow-sm hover:shadow transition-all"
1035- >
1036- < FileJson className = "h-4 w-4 text-[rgb(var(--primary))]" />
1037- Add Custom Server
1038- </ button >
1059+ < div className = "flex items-center gap-2" >
1060+ { installedServers . length > 0 && (
1061+ < >
1062+ < button
1063+ type = "button"
1064+ onClick = { expandAllServers }
1065+ disabled = { expandableServerCount === 0 }
1066+ className = "flex items-center gap-2 px-3 py-2.5 text-sm font-medium rounded-lg bg-[rgb(var(--surface-elevated))] border border-[rgb(var(--border))] hover:bg-[rgb(var(--surface-hover))] hover:border-[rgb(var(--border-subtle))] shadow-sm hover:shadow transition-all disabled:opacity-40 disabled:pointer-events-none"
1067+ title = "Expand all connected servers"
1068+ data-testid = "expand-all-servers"
1069+ >
1070+ < UnfoldVertical className = "h-4 w-4 text-[rgb(var(--muted))]" />
1071+ Expand all
1072+ </ button >
1073+ < button
1074+ type = "button"
1075+ onClick = { collapseAllServers }
1076+ disabled = { ! hasExpandedServers }
1077+ className = "flex items-center gap-2 px-3 py-2.5 text-sm font-medium rounded-lg bg-[rgb(var(--surface-elevated))] border border-[rgb(var(--border))] hover:bg-[rgb(var(--surface-hover))] hover:border-[rgb(var(--border-subtle))] shadow-sm hover:shadow transition-all disabled:opacity-40 disabled:pointer-events-none"
1078+ title = "Collapse all servers"
1079+ data-testid = "collapse-all-servers"
1080+ >
1081+ < FoldVertical className = "h-4 w-4 text-[rgb(var(--muted))]" />
1082+ Collapse all
1083+ </ button >
1084+ </ >
1085+ ) }
1086+ < button
1087+ type = "button"
1088+ onClick = { ( ) => setEditConfigSpace ( { id : viewSpace . id , name : viewSpace . name } ) }
1089+ className = "flex items-center gap-2 px-4 py-2.5 text-sm font-medium rounded-lg bg-[rgb(var(--surface-elevated))] border border-[rgb(var(--border))] hover:bg-[rgb(var(--surface-hover))] hover:border-[rgb(var(--border-subtle))] shadow-sm hover:shadow transition-all"
1090+ >
1091+ < FileJson className = "h-4 w-4 text-[rgb(var(--primary))]" />
1092+ Add Custom Server
1093+ </ button >
1094+ </ div >
10391095 ) }
10401096 </ div >
10411097
@@ -1321,8 +1377,11 @@ export function ServersPage() {
13211377 </ button >
13221378 ) }
13231379
1324- { /* Disable button - shown when enabled and connected/running */ }
1325- { server . enabled && ( serverAction === 'running' || serverAction === 'connected_auto' ) && (
1380+ { /* Disable button - enabled servers that are connected, idle, or stuck in error */ }
1381+ { server . enabled &&
1382+ ( serverAction === 'running' ||
1383+ serverAction === 'connected_auto' ||
1384+ serverAction === 'error' ) && (
13261385 < button
13271386 onClick = { ( ) => handleDisableClick ( server ) }
13281387 disabled = { disableLoading }
0 commit comments