feat(tabs): polish tab groups color bars and object icons

This commit is contained in:
zipg authored and GitHub committed 2026-09-11 21:10:49 +08:00
1 parent 074216ed0f
commit 48d6c94aad
6 files changed
+299 -14

No files matched your search

+35 -1
View File
@@ -29,6 +29,7 @@ const translations: Record<string, string> = {
"tabs.tooltipDatabase": "Database:",
"tabs.tooltipTable": "Table:",
"tabs.tooltipTableComment": "Table Comment:",
"tree.events": "Events",
"connectionGroup.ungroupedLabel": "Ungrouped",
"editor.noDatabase": "No database",
};
@@ -176,6 +177,11 @@ describe("tab group presentation", () => {
expect(tabDisplayTitle(queryTab({ mode: "objects", title: "public objects", objectBrowser: { schema: "public" } }), translate)).toBe("public@db");
});
it("uses the selected MySQL event name for event editor tabs", () => {
expect(tabDisplayTitle(queryTab({ mode: "objects", objectBrowser: { objectType: "tables", initialObjectFilter: "events", eventName: "cleanup_sessions" } }), translate)).toBe("cleanup_sessions@db");
expect(tabDisplayTitle(queryTab({ mode: "objects", objectBrowser: { objectType: "tables", initialObjectFilter: "events" } }), translate)).toBe("Events@db");
});
it("uses the live database and branch context for Dolt version control tabs", () => {
const store = useConnectionStore();
store.connections = [{ id: "conn-1", name: "Production Dolt", db_type: "mysql", driver_profile: "dolt", database: "app" } as ConnectionConfig];
@@ -429,9 +435,37 @@ describe("statement execution markers", () => {
describe("shared tab presentation helpers", () => {
it("classifies tab icon colors without MQ special-casing", () => {
expect(tabIconClass(queryTab({ mode: "data" }))).toContain("text-emerald-600");
expect(tabIconClass(queryTab({ mode: "data" }))).toContain("text-green-500");
const connectionStore = useConnectionStore();
connectionStore.connections = [{ id: "dynamodb-1", name: "DynamoDB", db_type: "dynamodb", driver_profile: "dynamodb", color: "" } as ConnectionConfig];
expect(tabIconClass(queryTab({ connectionId: "dynamodb-1", mode: "data" }))).toContain("text-amber-500");
expect(tabIconClass(queryTab({ mode: "mq" }))).toBe("");
expect(tabIconClass(queryTab({ externalSqlFileMissing: true }))).toContain("text-amber-600");
expect(tabIconClass(queryTab({ mode: "users" }))).toBe("text-primary");
expect(tabIconClass(queryTab({ mode: "objects", objectBrowser: { objectType: "tables", initialObjectFilter: "events", eventName: "cleanup_sessions" } }))).toBe("text-orange-400");
});
it("uses logical Redis database labels instead of the connection title", () => {
const connectionStore = useConnectionStore();
connectionStore.connections = [{ id: "redis-1", name: "Redis", db_type: "redis", driver_profile: "redis", color: "" } as ConnectionConfig];
expect(tabDisplayTitle(queryTab({ connectionId: "redis-1", database: "0", mode: "redis", sql: "" }), translate)).toBe("db0");
expect(tabDisplayTitle(queryTab({ connectionId: "redis-1", database: "1", mode: "redis", sql: "" }), translate)).toBe("db1");
});
it("keeps source tab colors aligned with the sidebar object palette", () => {
const colors = [
["PROCEDURE", "text-blue-500"],
["FUNCTION", "text-amber-500"],
["SEQUENCE", "text-emerald-500"],
["SYNONYM", "text-sky-500"],
["PACKAGE", "text-cyan-500"],
["PACKAGE_BODY", "text-cyan-400"],
["TYPE", "text-violet-500"],
["TYPE_BODY", "text-violet-400"],
] as const;
for (const [objectType, color] of colors) {
expect(tabIconClass(queryTab({ objectSource: { name: "object", objectType } }))).toContain(color);
}
});
it("builds active/inactive color styles for classic and non-classic layouts", () => {
+26 -1
View File
@@ -72,11 +72,18 @@ function queryTitle(tab: QueryTab): string | undefined {
return undefined;
}
export function isEventObjectBrowserTab(tab: QueryTab): boolean {
return tab.mode === "objects" && (tab.objectBrowser?.initialObjectFilter === "events" || tab.objectBrowser?.eventName !== undefined || tab.objectBrowser?.eventCreateRequestId !== undefined);
}
export function tabDisplayTitle(tab: QueryTab, t: Translate): string {
const database = databaseDisplayNameForTab(tab.connectionId, tab.database, t);
const settingsStore = useSettingsStore();
const compact = settingsStore.editorSettings.compactTabTitle;
if (isPreviewTab(tab)) return tab.title;
if (useConnectionStore().getConfig(tab.connectionId)?.db_type === "redis") {
return tab.database ? database : connectionDisplayName(tab.connectionId);
}
if (tab.mode === "data" && tab.tableMeta?.tableName) {
if (compact) return tab.tableMeta.tableName;
const suffix = tab.tableMeta.schema && tab.tableMeta.schema !== tab.database ? `@${database}.${tab.tableMeta.schema}` : `@${database}`;
@@ -153,6 +160,11 @@ export function tabDisplayTitle(tab: QueryTab, t: Translate): string {
return `${t("tabs.databases")}@${connectionDisplayName(tab.connectionId)}`;
}
if (tab.mode === "objects") {
if (isEventObjectBrowserTab(tab)) {
const eventTitle = tab.objectBrowser?.eventName || t("tree.events");
if (compact) return eventTitle;
return `${eventTitle}@${database}`;
}
const schema = tab.objectBrowser?.schema;
const objectScope = tab.catalog ? `${tab.catalog}.${database}` : database;
if (compact) return schema || objectScope;
@@ -474,6 +486,7 @@ export function tabModeLabel(tab: QueryTab, t: Translate): string {
if (tab.mode === "consul-overview") return t("consul.ui.overview");
if (tab.mode === "nacos") return "Nacos";
if (tab.mode === "databases") return t("tabs.databases");
if (isEventObjectBrowserTab(tab)) return t("tree.events");
if (tab.mode === "objects") return t("tabs.objects");
if (tab.mode === "users") return t("tabs.users");
if (tab.mode === "dolt-version-control") return t("doltVersionControl.title");
@@ -496,6 +509,7 @@ export function tabDatabaseIconType(tab: QueryTab): string {
}
export function tabIconClass(tab: QueryTab): string {
const connection = useConnectionStore().getConfig(tab.connectionId);
if (tab.externalSqlFileMissing) return "text-amber-600 dark:text-amber-400";
if (tab.mode === "mq") return "";
if (tab.objectSource?.objectType === "VIEW") return "text-purple-500";
@@ -505,11 +519,22 @@ export function tabIconClass(tab: QueryTab): string {
if (tab.objectSource?.objectType === "TRIGGER") return "text-orange-300";
if (tab.objectSource?.objectType === "EVENT" || tab.objectSource?.objectType === "JOB") return "text-orange-400";
if (tab.objectSource?.objectType === "SEQUENCE") return "text-emerald-500";
if (tab.objectSource?.objectType === "SYNONYM") return "text-sky-500";
if (tab.objectSource?.objectType === "PACKAGE") return "text-cyan-500";
if (tab.objectSource?.objectType === "PACKAGE_BODY") return "text-cyan-400";
if (tab.objectSource?.objectType === "TYPE") return "text-violet-500";
if (tab.objectSource?.objectType === "TYPE_BODY") return "text-violet-400";
if (isEventObjectBrowserTab(tab)) return "text-orange-400";
if (tab.mode === "users") return "text-primary";
if (tab.mode === "redis") return "text-red-400";
if (tab.mode === "data" && tab.tableMeta?.tableType?.toUpperCase() === "VIEW") return "text-purple-500";
if (tab.mode === "data" && tab.tableMeta?.tableType?.toUpperCase() === "MATERIALIZED_VIEW") return "text-indigo-500";
if (tab.mode === "databases" || tab.mode === "objects") return "text-amber-500 dark:text-amber-400";
if (tab.mode === "data" || tab.mode === "mongo" || tab.mode === "vector" || tab.mode === "hbase" || tab.mode === "structure") return "text-emerald-600 dark:text-emerald-400";
if (tab.mode === "data" && connection?.db_type === "dynamodb") return "text-amber-500";
if (tab.mode === "data" || tab.mode === "hbase") return "text-green-500";
if (tab.mode === "mongo") return "text-green-400";
if (tab.mode === "vector") return "text-cyan-400";
if (tab.mode === "structure") return "text-blue-500";
return "text-blue-600 dark:text-blue-400";
}