refactor(web): rename removeInstance to disconnectInstance, wire up registry on disconnect

This commit is contained in:
Jannis Braun
2026-04-01 18:00:08 +02:00
parent ce5c164958
commit d7e2f25c31
2 changed files with 20 additions and 10 deletions
@@ -266,7 +266,7 @@ function AddInstanceFlow({ onDone }: { onDone: () => void }) {
// ─── Main component ────────────────────────────────────────────────────────── // ─── Main component ──────────────────────────────────────────────────────────
function InstanceRow({ inst }: { inst: import('../../stores/instanceStore').ConnectedInstance }) { function InstanceRow({ inst }: { inst: import('../../stores/instanceStore').ConnectedInstance }) {
const removeInstance = useInstanceStore((s) => s.removeInstance); const disconnectInstance = useInstanceStore((s) => s.disconnectInstance);
const reconnectInstance = useInstanceStore((s) => s.reconnectInstance); const reconnectInstance = useInstanceStore((s) => s.reconnectInstance);
const reauthenticateInstance = useInstanceStore((s) => s.reauthenticateInstance); const reauthenticateInstance = useInstanceStore((s) => s.reauthenticateInstance);
const hasPendingSync = useInstanceStore((s) => s.pendingSyncOrigins.includes(inst.origin)); const hasPendingSync = useInstanceStore((s) => s.pendingSyncOrigins.includes(inst.origin));
@@ -345,7 +345,7 @@ function InstanceRow({ inst }: { inst: import('../../stores/instanceStore').Conn
) )
)} )}
<button <button
onClick={() => removeInstance(inst.origin)} onClick={() => disconnectInstance(inst.origin)}
className="px-2 py-1 text-xs text-txt-danger hover:bg-accent-rose/10 rounded transition-colors" className="px-2 py-1 text-xs text-txt-danger hover:bg-accent-rose/10 rounded transition-colors"
title="Disconnect" title="Disconnect"
> >
+18 -8
View File
@@ -3,7 +3,7 @@ import type { User, InstanceInfoResponse, ReplicatedInstance, AuthResponse, Fede
import { BackspaceApiClient, createApiClient, api } from '../api/client'; import { BackspaceApiClient, createApiClient, api } from '../api/client';
import { useAuthStore } from './authStore'; import { useAuthStore } from './authStore';
import { setApiForOriginResolver, setUserIdForOriginResolver, setOriginFromHostnameResolver, useSpaceStore } from './spaceStore'; import { setApiForOriginResolver, setUserIdForOriginResolver, setOriginFromHostnameResolver, useSpaceStore } from './spaceStore';
import { connectInstance, disconnectInstance, disconnectAllRemote } from '../hooks/useWebSocket'; import { connectInstance, disconnectInstance as disconnectWs, disconnectAllRemote } from '../hooks/useWebSocket';
import { syncProfileToRemote } from '../utils/profileSync'; import { syncProfileToRemote } from '../utils/profileSync';
// Circular dependency: federationOps imports useInstanceStore, instanceStore imports this. // Circular dependency: federationOps imports useInstanceStore, instanceStore imports this.
// Safe because both modules access each other lazily (at call time, not import time). // Safe because both modules access each other lazily (at call time, not import time).
@@ -163,7 +163,7 @@ interface InstanceState {
probeInstance: (url: string) => Promise<InstanceInfoResponse & { origin: string }>; probeInstance: (url: string) => Promise<InstanceInfoResponse & { origin: string }>;
connectToRemote: (origin: string, password: string, displayName?: string) => Promise<void>; connectToRemote: (origin: string, password: string, displayName?: string) => Promise<void>;
loginToRemote: (origin: string, username: string, password: string) => Promise<void>; loginToRemote: (origin: string, username: string, password: string) => Promise<void>;
removeInstance: (origin: string) => void; disconnectInstance: (origin: string) => void;
setInstanceStatus: (origin: string, status: ConnectedInstance['status'], error?: string) => void; setInstanceStatus: (origin: string, status: ConnectedInstance['status'], error?: string) => void;
reconnectInstance: (origin: string) => Promise<void>; reconnectInstance: (origin: string) => Promise<void>;
reauthenticateInstance: (origin: string, password: string) => Promise<void>; reauthenticateInstance: (origin: string, password: string) => Promise<void>;
@@ -392,22 +392,32 @@ export const useInstanceStore = create<InstanceState>((set, get) => ({
})); }));
}, },
removeInstance: (origin: string) => { disconnectInstance: (origin: string) => {
// Tear down WebSocket connection // Tear down WebSocket connection
disconnectInstance(origin); disconnectWs(origin);
// Update registry entry to disconnected (preserve the entry)
const registry = upsertRegistryEntry(get().registry, origin, {
origin,
status: 'disconnected',
disconnectedAt: Date.now(),
errorMessage: null,
});
const registryUpdatedAt = Date.now();
set((state) => { set((state) => {
const updated = state.instances.filter(i => i.origin !== origin); const updated = state.instances.filter(i => i.origin !== origin);
const userId = useAuthStore.getState().user?.id; const userId = useAuthStore.getState().user?.id;
if (userId) saveCachedTokens(updated, userId); if (userId) saveCachedTokens(updated, userId);
return { instances: updated }; return { instances: updated, registry, registryUpdatedAt };
}); });
// Remove spaces from this instance from the space store // Remove spaces from this instance from the space store
useSpaceStore.getState().removeInstanceSpaces(origin); useSpaceStore.getState().removeInstanceSpaces(origin);
// Sync updated list to remaining instances (fire-and-forget) // Sync updated lists to remaining instances (fire-and-forget)
get().syncInstanceList().catch(() => {}); get().syncInstanceList().catch(() => {});
get().syncRegistry().catch(() => {});
}, },
reconnectInstance: async (origin: string) => { reconnectInstance: async (origin: string) => {
@@ -469,7 +479,7 @@ export const useInstanceStore = create<InstanceState>((set, get) => ({
useSpaceStore.getState().removeInstanceSpaces(origin); useSpaceStore.getState().removeInstanceSpaces(origin);
// Disconnect any lingering WS // Disconnect any lingering WS
disconnectInstance(origin); disconnectWs(origin);
// Re-connect through the standard flow (handles register/login) // Re-connect through the standard flow (handles register/login)
const currentUser = useAuthStore.getState().user; const currentUser = useAuthStore.getState().user;
@@ -498,7 +508,7 @@ export const useInstanceStore = create<InstanceState>((set, get) => ({
if (userId) saveCachedTokens(get().instances, userId); if (userId) saveCachedTokens(get().instances, userId);
// Reconnect WebSocket with new token // Reconnect WebSocket with new token
disconnectInstance(origin); disconnectWs(origin);
connectInstance(origin, newToken); connectInstance(origin, newToken);
}, },