feat(desktop): stabilize connection workspace state
Absorb the local workspace drift for connection session handling, database switching, inspector readability helpers, and the bounded add-key preview flow. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
179
apps/desktop/src/lib/connection-session.ts
Normal file
179
apps/desktop/src/lib/connection-session.ts
Normal file
@@ -0,0 +1,179 @@
|
||||
export type SessionConnection = {
|
||||
id: string;
|
||||
name: string;
|
||||
detail: string;
|
||||
status: "healthy" | "idle" | "checking" | "error";
|
||||
target: {
|
||||
database: number;
|
||||
username: string | null;
|
||||
};
|
||||
};
|
||||
|
||||
export type ConnectionTestState = {
|
||||
connectionId: string;
|
||||
};
|
||||
|
||||
export type ConnectionSessionSummary = {
|
||||
badgeLabel: string;
|
||||
badgeVariant: "neutral" | "accent" | "danger";
|
||||
summary: string;
|
||||
hint: string;
|
||||
};
|
||||
|
||||
export type ConnectionTestSuccessResult = {
|
||||
roundTripStatus: string;
|
||||
selectedDatabase: number;
|
||||
authenticatedAs: string | null;
|
||||
};
|
||||
|
||||
export function formatConnectionStatusLabel(connection: SessionConnection) {
|
||||
if (connection.status === "healthy") {
|
||||
return `Ready · ${connection.detail}`;
|
||||
}
|
||||
|
||||
if (connection.status === "checking") {
|
||||
return "Testing · Live contract probe";
|
||||
}
|
||||
|
||||
if (connection.status === "error") {
|
||||
return `Attention · ${connection.detail}`;
|
||||
}
|
||||
|
||||
return `Idle · ${connection.detail}`;
|
||||
}
|
||||
|
||||
export function formatConnectionCardDetailLabel(connection: SessionConnection) {
|
||||
if (connection.status === "checking") {
|
||||
return "live test in progress";
|
||||
}
|
||||
|
||||
if (connection.status === "healthy") {
|
||||
return `ready ${connection.detail}`;
|
||||
}
|
||||
|
||||
if (connection.status === "error") {
|
||||
return `retry ${connection.detail}`;
|
||||
}
|
||||
|
||||
return connection.detail;
|
||||
}
|
||||
|
||||
export function markConnectionTesting<T extends SessionConnection>(
|
||||
connections: T[],
|
||||
connectionId: string,
|
||||
) {
|
||||
return connections.map((connection) =>
|
||||
connection.id === connectionId
|
||||
? {
|
||||
...connection,
|
||||
status: "checking" as const,
|
||||
detail: "Live test in progress",
|
||||
}
|
||||
: connection,
|
||||
);
|
||||
}
|
||||
|
||||
export function applyConnectionTestSuccess<T extends SessionConnection>(
|
||||
connections: T[],
|
||||
connectionId: string,
|
||||
result: ConnectionTestSuccessResult,
|
||||
) {
|
||||
return connections.map((connection) =>
|
||||
connection.id === connectionId
|
||||
? {
|
||||
...connection,
|
||||
status: "healthy" as const,
|
||||
detail: result.roundTripStatus,
|
||||
target: {
|
||||
...connection.target,
|
||||
database: result.selectedDatabase,
|
||||
username: result.authenticatedAs ?? connection.target.username,
|
||||
},
|
||||
}
|
||||
: connection,
|
||||
);
|
||||
}
|
||||
|
||||
export function applyConnectionTestFailure<T extends SessionConnection>(
|
||||
connections: T[],
|
||||
connectionId: string,
|
||||
detail: string,
|
||||
) {
|
||||
return connections.map((connection) =>
|
||||
connection.id === connectionId
|
||||
? {
|
||||
...connection,
|
||||
status: "error" as const,
|
||||
detail,
|
||||
}
|
||||
: connection,
|
||||
);
|
||||
}
|
||||
|
||||
export function buildConnectionSessionSummary(args: {
|
||||
connection: SessionConnection;
|
||||
databaseLabel: string;
|
||||
tauriAvailable: boolean;
|
||||
activeTestRunning: boolean;
|
||||
otherTestingConnectionName: string | null;
|
||||
}): ConnectionSessionSummary {
|
||||
const {
|
||||
connection,
|
||||
databaseLabel,
|
||||
tauriAvailable,
|
||||
activeTestRunning,
|
||||
otherTestingConnectionName,
|
||||
} = args;
|
||||
|
||||
if (!tauriAvailable) {
|
||||
return {
|
||||
badgeLabel: "Demo fallback",
|
||||
badgeVariant: "neutral",
|
||||
summary: `${connection.name} stays scoped to ${databaseLabel} in browser mode without contacting Redis.`,
|
||||
hint: "Use Test demo to verify shell flow only, then switch to the Tauri desktop runtime for a live connection retry.",
|
||||
};
|
||||
}
|
||||
|
||||
if (activeTestRunning) {
|
||||
return {
|
||||
badgeLabel: "Testing",
|
||||
badgeVariant: "accent",
|
||||
summary: `Running a live connection probe for ${connection.name} on ${databaseLabel}.`,
|
||||
hint: "Keep this scope selected if you want the tested database and retry messaging to update in place.",
|
||||
};
|
||||
}
|
||||
|
||||
if (otherTestingConnectionName) {
|
||||
return {
|
||||
badgeLabel: "Ready",
|
||||
badgeVariant: "neutral",
|
||||
summary: `${connection.name} remains selected on ${databaseLabel} while ${otherTestingConnectionName} finishes a separate live test.`,
|
||||
hint: "The current workspace stays stable. Switch back to the testing connection after the probe completes if you need to review its result.",
|
||||
};
|
||||
}
|
||||
|
||||
if (connection.status === "healthy") {
|
||||
return {
|
||||
badgeLabel: "Ready",
|
||||
badgeVariant: "accent",
|
||||
summary: `${connection.name} last passed a live connection check on ${databaseLabel}.`,
|
||||
hint: "Re-run Test live after changing host, DB, credentials, or after recovering from a Redis outage.",
|
||||
};
|
||||
}
|
||||
|
||||
if (connection.status === "error") {
|
||||
return {
|
||||
badgeLabel: "Retry needed",
|
||||
badgeVariant: "danger",
|
||||
summary: `${connection.name} last failed a live connection check on ${databaseLabel}.`,
|
||||
hint: "Review the banner and connection card detail, adjust the profile if needed, then retry Test live from this same scope.",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
badgeLabel: "Ready to test",
|
||||
badgeVariant: "neutral",
|
||||
summary: `${connection.name} is selected on ${databaseLabel} but has not completed a live check in the current session.`,
|
||||
hint: "Run Test live before treating browse, inspect, or command results as current Redis evidence.",
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user