Skip to content

Commit 8ff352b

Browse files
committed
feat(desktop): expand/collapse all servers and disable on error
Add My Servers header controls to expand or collapse connected rows, and show Disable alongside Retry when a server is stuck in error state. Signed-off-by: crimsonsunset <jsangio1@gmail.com>
1 parent 36a4922 commit 8ff352b

1 file changed

Lines changed: 68 additions & 9 deletions

File tree

apps/desktop/src/features/servers/ServersPage.tsx

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import {
1919
Clock,
2020
FileJson,
2121
FolderOpen,
22+
UnfoldVertical,
23+
FoldVertical,
2224
} from 'lucide-react';
2325
import { ServerActionMenu } from './ServerActionMenu';
2426
import { 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

Comments
 (0)