Compare commits
1 Commits
cmp-28-con
...
cmp-22-db-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04da063abf |
@@ -70,6 +70,7 @@ import {
|
||||
updateDemoKeyTtl,
|
||||
updateDemoStringValue,
|
||||
} from "./lib/demo-workspace";
|
||||
import { buildDatabaseSwitcherLabels } from "./lib/database-switcher";
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
declare const __APP_VERSION__: string;
|
||||
@@ -357,8 +358,6 @@ const initialDemoKeys: KeyRecord[] = [
|
||||
},
|
||||
];
|
||||
|
||||
const databases = ["db0", "db1", "db2", "db5"];
|
||||
|
||||
const fallbackBootstrap: BackendBootstrap = {
|
||||
app_name: "Redis GUI Foundation",
|
||||
surface: "desktop",
|
||||
@@ -396,7 +395,7 @@ function App() {
|
||||
const [connections, setConnections] = useState(initialConnections);
|
||||
const [demoKeys, setDemoKeys] = useState(initialDemoKeys);
|
||||
const [activeConnectionId, setActiveConnectionId] = useState(initialConnections[0].id);
|
||||
const [activeDb, setActiveDb] = useState(databases[0]);
|
||||
const [activeDb, setActiveDb] = useState("db0");
|
||||
const [search, setSearch] = useState("");
|
||||
const [selectedKeyId, setSelectedKeyId] = useState<string | null>(initialDemoKeys[1].id);
|
||||
const [draftValue, setDraftValue] = useState(initialDemoKeys[1].value);
|
||||
@@ -443,6 +442,7 @@ function App() {
|
||||
const activeConnection =
|
||||
connections.find((connection) => connection.id === activeConnectionId) ??
|
||||
connections[0];
|
||||
const databaseOptions = buildDatabaseSwitcherLabels(parseDatabaseLabel(activeDb));
|
||||
|
||||
const filteredDemoKeys = filterWorkspaceKeys(demoKeys, deferredSearch);
|
||||
const filteredKeys = tauriAvailable ? liveKeys : filteredDemoKeys;
|
||||
@@ -1583,7 +1583,7 @@ function App() {
|
||||
<section>
|
||||
<SectionEyebrow icon={<Database className="h-4 w-4" />} label="Database switcher" />
|
||||
<div className="mt-3 grid gap-2">
|
||||
{databases.map((database) => {
|
||||
{databaseOptions.map((database) => {
|
||||
const active = database === activeDb;
|
||||
|
||||
return (
|
||||
|
||||
74
apps/desktop/src/lib/database-switcher.test.ts
Normal file
74
apps/desktop/src/lib/database-switcher.test.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { buildDatabaseSwitcherLabels } from "./database-switcher";
|
||||
|
||||
describe("database switcher helper", () => {
|
||||
it("returns the default operator range from db0 through db15", () => {
|
||||
expect(buildDatabaseSwitcherLabels(0)).toEqual([
|
||||
"db0",
|
||||
"db1",
|
||||
"db2",
|
||||
"db3",
|
||||
"db4",
|
||||
"db5",
|
||||
"db6",
|
||||
"db7",
|
||||
"db8",
|
||||
"db9",
|
||||
"db10",
|
||||
"db11",
|
||||
"db12",
|
||||
"db13",
|
||||
"db14",
|
||||
"db15",
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps an active out-of-range database visible and numerically ordered", () => {
|
||||
expect(buildDatabaseSwitcherLabels(23)).toEqual([
|
||||
"db0",
|
||||
"db1",
|
||||
"db2",
|
||||
"db3",
|
||||
"db4",
|
||||
"db5",
|
||||
"db6",
|
||||
"db7",
|
||||
"db8",
|
||||
"db9",
|
||||
"db10",
|
||||
"db11",
|
||||
"db12",
|
||||
"db13",
|
||||
"db14",
|
||||
"db15",
|
||||
"db23",
|
||||
]);
|
||||
});
|
||||
|
||||
it("normalizes negative or fractional inputs back to safe labels", () => {
|
||||
expect(buildDatabaseSwitcherLabels(-3)).toEqual([
|
||||
"db0",
|
||||
"db1",
|
||||
"db2",
|
||||
"db3",
|
||||
"db4",
|
||||
"db5",
|
||||
"db6",
|
||||
"db7",
|
||||
"db8",
|
||||
"db9",
|
||||
"db10",
|
||||
"db11",
|
||||
"db12",
|
||||
"db13",
|
||||
"db14",
|
||||
"db15",
|
||||
]);
|
||||
expect(buildDatabaseSwitcherLabels(4.8, 2)).toEqual([
|
||||
"db0",
|
||||
"db1",
|
||||
"db2",
|
||||
"db4",
|
||||
]);
|
||||
});
|
||||
});
|
||||
29
apps/desktop/src/lib/database-switcher.ts
Normal file
29
apps/desktop/src/lib/database-switcher.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
export function buildDatabaseSwitcherLabels(
|
||||
activeDatabase: number,
|
||||
maxDefaultDatabase = 15,
|
||||
) {
|
||||
const normalizedDefaultMax = Math.max(0, Math.floor(maxDefaultDatabase));
|
||||
const normalizedActive = Math.max(0, Math.floor(activeDatabase));
|
||||
const labels = new Set<string>();
|
||||
|
||||
for (let database = 0; database <= normalizedDefaultMax; database += 1) {
|
||||
labels.add(formatDatabaseLabel(database));
|
||||
}
|
||||
|
||||
labels.add(formatDatabaseLabel(normalizedActive));
|
||||
|
||||
return [...labels].sort(compareDatabaseLabels);
|
||||
}
|
||||
|
||||
function compareDatabaseLabels(left: string, right: string) {
|
||||
return parseDatabaseLabel(left) - parseDatabaseLabel(right);
|
||||
}
|
||||
|
||||
function parseDatabaseLabel(value: string) {
|
||||
const parsed = Number.parseInt(value.replace(/^db/i, ""), 10);
|
||||
return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
|
||||
}
|
||||
|
||||
function formatDatabaseLabel(database: number) {
|
||||
return `db${database}`;
|
||||
}
|
||||
32
plans/2026-03-31-hac-22-db-switcher-hardening.md
Normal file
32
plans/2026-03-31-hac-22-db-switcher-hardening.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# HAC-22 DB Switcher Hardening
|
||||
|
||||
Date: 2026-03-31 UTC
|
||||
Owner: Senior Frontend Engineer
|
||||
Issue: HAC-22
|
||||
Scope: `desktop-v1` user-visible frontend hardening only
|
||||
|
||||
## Context
|
||||
|
||||
- `apps/desktop` already ships a visible DB switcher, but the current UI only renders four fixed choices: `db0`, `db1`, `db2`, and `db5`.
|
||||
- Current product scope already includes one active standalone Redis connection, explicit DB context, and DB-scoped browse / inspect / command flows.
|
||||
- The hardcoded four-item list is weaker than the current product boundary and makes shell-level verification less representative for operators who need to move across common DB indexes.
|
||||
|
||||
## Decision
|
||||
|
||||
- Do not expand product scope or alter backend contracts.
|
||||
- Keep the existing rail placement and interaction model for the DB switcher.
|
||||
- Widen the visible DB switcher to a predictable default operator range and ensure the currently active DB remains selectable even when it falls outside the default range.
|
||||
|
||||
## Implemented Slice
|
||||
|
||||
1. Added a shared frontend helper that returns DB labels for the switcher.
|
||||
2. Defaulted the visible range to `db0` through `db15`.
|
||||
3. Preserved the currently active DB when it falls outside that range and kept the options numerically ordered.
|
||||
4. Covered the helper with focused Vitest cases.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- The visible DB switcher no longer depends on a four-item hardcoded list.
|
||||
- Operators can select common DB indexes from `db0` through `db15` without editing connection drafts.
|
||||
- An active DB outside the default range still appears in the switcher and stays selectable.
|
||||
- `pnpm --filter @redis-gui/desktop test` and `pnpm run desktop:build` remain green.
|
||||
Reference in New Issue
Block a user