Skip to content

Commit 7327003

Browse files
committed
fix: avoid synthetic connecting state for enabled servers
1 parent 57276b7 commit 7327003

2 files changed

Lines changed: 27 additions & 17 deletions

File tree

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

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ function mergeDefinitionsWithStates(
6262
(input: InputDefinition) => input.required && !inputValues[input.id]
6363
);
6464

65-
// Calculate initial connection_status based on enabled state
66-
// Calculate initial connection_status based on enabled state
67-
// Actual runtime status comes from ServerManager events via useServerManager hook
68-
const connection_status = state?.enabled ? 'connecting' : 'disconnected';
65+
// Runtime status is in-memory only and comes from ServerManager.
66+
// Do not infer `connecting` from persisted `enabled`; custom/offline servers can
67+
// otherwise stay stuck in a synthetic Connecting state forever.
68+
const connection_status = 'disconnected';
6969

7070
return {
7171
...def,
@@ -95,11 +95,7 @@ function createOfflineServerViewModel(state: InstalledServerState): ServerViewMo
9595
const inputValues = state.input_values;
9696
const requiredInputs = definition.transport.metadata?.inputs?.filter((i) => i.required) || [];
9797
const missing_required_inputs = requiredInputs.some((input) => !inputValues[input.id]);
98-
const connection_status = state.enabled
99-
? missing_required_inputs
100-
? 'error'
101-
: 'connecting'
102-
: 'disconnected';
98+
const connection_status = 'disconnected';
10399

104100
return {
105101
...definition,
@@ -143,7 +139,7 @@ function createOfflineServerViewModel(state: InstalledServerState): ServerViewMo
143139
enabled: state.enabled,
144140
oauth_connected: state.oauth_connected,
145141
input_values: state.input_values,
146-
connection_status: state.enabled ? 'connecting' : 'disconnected',
142+
connection_status: 'disconnected',
147143
missing_required_inputs: false,
148144
last_error: null,
149145
created_at: state.created_at,
@@ -450,6 +446,7 @@ export function ServersPage() {
450446
* - 'running': Server is connected and running
451447
* - 'error': Server has an error
452448
* - 'connected_auto': Non-OAuth server that's connected (no action buttons needed)
449+
* - 'disconnected': Server is enabled but has no active runtime connection
453450
*/
454451
const getServerAction = (
455452
server: ServerViewModel
@@ -461,7 +458,8 @@ export function ServersPage() {
461458
| 'auth_required'
462459
| 'running'
463460
| 'error'
464-
| 'connected_auto' => {
461+
| 'connected_auto'
462+
| 'disconnected' => {
465463
if (!server.enabled) {
466464
return 'enable';
467465
}
@@ -489,8 +487,7 @@ export function ServersPage() {
489487
case 'error':
490488
return 'error';
491489
case 'disconnected':
492-
// Enabled but disconnected - try to connect
493-
return server.auth?.type === 'oauth' ? 'auth_required' : 'connected_auto';
490+
return server.auth?.type === 'oauth' ? 'auth_required' : 'disconnected';
494491
}
495492
}
496493

@@ -515,8 +512,8 @@ export function ServersPage() {
515512
return 'auth_required';
516513
}
517514

518-
// Non-OAuth server that's enabled but not yet connected
519-
return 'connected_auto';
515+
// Enabled but no runtime connection exists yet. Let the user start/retry it.
516+
return 'disconnected';
520517
};
521518

522519
// Get display status for UI
@@ -544,6 +541,8 @@ export function ServersPage() {
544541
return 'Connected';
545542
case 'connected_auto':
546543
return 'Connected';
544+
case 'disconnected':
545+
return 'Disconnected';
547546
case 'error':
548547
return 'Error';
549548
}
@@ -1228,6 +1227,16 @@ export function ServersPage() {
12281227
</button>
12291228
)}
12301229

1230+
{serverAction === 'disconnected' && gatewayRunning && (
1231+
<button
1232+
onClick={() => handleRetry(server)}
1233+
disabled={retryLoading}
1234+
className="rounded-lg bg-[rgb(var(--success))] px-4 py-2 text-sm font-medium text-white shadow-sm transition-colors hover:bg-[rgb(var(--success))]/80 disabled:opacity-50"
1235+
>
1236+
{retryLoading ? 'Connecting...' : 'Connect'}
1237+
</button>
1238+
)}
1239+
12311240
{serverAction === 'error' && gatewayRunning && (
12321241
<button
12331242
onClick={() => handleRetry(server)}

apps/desktop/src/stores/registryStore.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,8 +363,9 @@ function mergeServers(defs: ServerDefinition[], states: InstalledServerState[]):
363363
input.required && !inputValues[input.id]
364364
);
365365

366-
// Calculate initial connection_status based on enabled state
367-
const connection_status = state?.enabled ? 'connecting' : 'disconnected';
366+
// Runtime connection status is not persisted. Do not infer Connecting from
367+
// the enabled flag; the ServerManager event/status stream owns that state.
368+
const connection_status = 'disconnected';
368369

369370
return {
370371
...def,

0 commit comments

Comments
 (0)