fix(tabs): reuse data tabs only for the same table
This commit is contained in:
parent
6e4363be36
commit
51560c49ae
|
|
@ -99,6 +99,7 @@ describe("useNavigationTargets with the real query store", () => {
|
|||
vi.unstubAllGlobals();
|
||||
installLocalStorage();
|
||||
mocks.connectionStore.activeConnectionId = "";
|
||||
mocks.connectionStore.getConfig.mockImplementation((connectionId: string) => ({ id: connectionId, db_type: "postgres" }));
|
||||
mocks.settingsStore.editorSettings.reuseDataTab = true;
|
||||
mocks.ensureConnected?.mockResolvedValue?.(undefined);
|
||||
mocks.connectionStore.ensureConnected.mockResolvedValue(undefined);
|
||||
|
|
@ -172,6 +173,63 @@ describe("useNavigationTargets with the real query store", () => {
|
|||
expect(new Set(queryStore.tabs.map((tab) => tab.id))).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("keeps different sidebar tables independent when data-tab reuse is enabled", async () => {
|
||||
const { queryStore } = await setupNavigation();
|
||||
const { useSidebarDataOpenRuntime } = await import("@/composables/useSidebarDataOpenRuntime");
|
||||
const runtime = useSidebarDataOpenRuntime();
|
||||
const users = { id: "users", label: "users", type: "table" as const, connectionId: "connection-1", database: "app", schema: "public", tableType: "TABLE" };
|
||||
|
||||
await runtime.openData(users);
|
||||
await runtime.openData({ ...users, id: "orders", label: "orders" });
|
||||
|
||||
expect(queryStore.tabs).toHaveLength(2);
|
||||
expect(queryStore.tabs.map((tab) => tab.tableMeta?.tableName)).toEqual(["users", "orders"]);
|
||||
});
|
||||
|
||||
it("reuses a sidebar table when the same table is opened from the object browser", async () => {
|
||||
mocks.connectionStore.getConfig.mockImplementation((connectionId: string) => ({ id: connectionId, db_type: "mysql" }));
|
||||
const { navigation, queryStore } = await setupNavigation();
|
||||
const { useSidebarDataOpenRuntime } = await import("@/composables/useSidebarDataOpenRuntime");
|
||||
const runtime = useSidebarDataOpenRuntime();
|
||||
const users = { id: "users", label: "users", type: "table" as const, connectionId: "connection-1", database: "app", tableType: "TABLE" };
|
||||
|
||||
await runtime.openData(users);
|
||||
const sidebarTabId = queryStore.activeTabId;
|
||||
await navigation.openObjectBrowserTableTarget({ connectionId: "connection-1", database: "app", schema: "app", tableName: "users", tableType: "TABLE" });
|
||||
|
||||
expect(queryStore.tabs).toHaveLength(1);
|
||||
expect(queryStore.activeTabId).toBe(sidebarTabId);
|
||||
});
|
||||
|
||||
it("reuses a restored legacy MySQL tab when the same table is opened from the sidebar", async () => {
|
||||
mocks.connectionStore.getConfig.mockImplementation((connectionId: string) => ({ id: connectionId, db_type: "mysql" }));
|
||||
mocks.loadOpenTabsState.mockResolvedValue({
|
||||
tabs: [
|
||||
{
|
||||
id: "restored-users",
|
||||
title: "app.users",
|
||||
connectionId: "connection-1",
|
||||
database: "app",
|
||||
schema: "app",
|
||||
mode: "data",
|
||||
sql: "SELECT * FROM users",
|
||||
tableMeta: { schema: "app", tableName: "users", tableType: "TABLE", columns: [], primaryKeys: [] },
|
||||
},
|
||||
],
|
||||
activeTabId: "restored-users",
|
||||
});
|
||||
const { queryStore } = await setupNavigation();
|
||||
await queryStore.initOpenTabs({ validConnectionIds: ["connection-1"] });
|
||||
const { useSidebarDataOpenRuntime } = await import("@/composables/useSidebarDataOpenRuntime");
|
||||
const runtime = useSidebarDataOpenRuntime();
|
||||
|
||||
await runtime.openData({ id: "users", label: "users", type: "table", connectionId: "connection-1", database: "app", tableType: "TABLE" });
|
||||
|
||||
expect(queryStore.tabs).toHaveLength(1);
|
||||
expect(queryStore.activeTabId).toBe("restored-users");
|
||||
expect(queryStore.tabs[0]?.schema).toBeUndefined();
|
||||
});
|
||||
|
||||
it("creates a new target tab even when the same table was restored", async () => {
|
||||
mocks.loadOpenTabsState.mockResolvedValue({
|
||||
tabs: [
|
||||
|
|
|
|||
|
|
@ -169,6 +169,17 @@ describe("useSidebarDataOpenRuntime", () => {
|
|||
expect(mocks.tabs).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("keeps different sidebar tables independent when reuse is enabled", async () => {
|
||||
mocks.reuseDataTab = true;
|
||||
const ordersNode = { ...tableNode, id: "table-orders", label: "orders" };
|
||||
|
||||
await useSidebarDataOpenRuntime().openData(tableNode);
|
||||
await useSidebarDataOpenRuntime().openData(ordersNode);
|
||||
|
||||
expect(mocks.tabs).toHaveLength(2);
|
||||
expect(mocks.tabs.map((tab) => tab.title)).toEqual(["users", "orders"]);
|
||||
});
|
||||
|
||||
it("creates a new HBase tab for the same table when reuse is disabled", async () => {
|
||||
mocks.databaseType = "hbase";
|
||||
|
||||
|
|
@ -178,6 +189,16 @@ describe("useSidebarDataOpenRuntime", () => {
|
|||
expect(mocks.tabs).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("keeps different HBase tables independent when reuse is enabled", async () => {
|
||||
mocks.databaseType = "hbase";
|
||||
mocks.reuseDataTab = true;
|
||||
|
||||
await useSidebarDataOpenRuntime().openData(tableNode);
|
||||
await useSidebarDataOpenRuntime().openData({ ...tableNode, id: "table-orders", label: "orders" });
|
||||
|
||||
expect(mocks.tabs).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("starts cold-cache OceanBase metadata before the table query", async () => {
|
||||
await useSidebarDataOpenRuntime().openData(tableNode);
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export function useSidebarDataOpenRuntime() {
|
|||
async function openData(node: TreeNode, request?: SidebarDataOpenRequest, openMode: DataTabOpenMode = "default", options: { reuseScope?: DataTabReuseScope } = {}) {
|
||||
if (!(node.type === "table" || node.type === "view" || node.type === "materialized_view") || !hasNodeDatabaseContext(node)) return;
|
||||
const config = connectionStore.getConfig(node.connectionId);
|
||||
const reuseScope = options.reuseScope ?? (settingsStore.editorSettings.reuseDataTab ? "database" : "none");
|
||||
const reuseScope = options.reuseScope ?? (settingsStore.editorSettings.reuseDataTab ? "same-table" : "none");
|
||||
if (config?.db_type === "hbase") {
|
||||
await connectionStore.ensureConnected(node.connectionId);
|
||||
const tabId = queryStore.createTab(node.connectionId, node.database, node.label, "hbase", undefined, node.label, undefined, { forceNew: openMode === "new-tab" || reuseScope === "none" });
|
||||
|
|
|
|||
|
|
@ -4965,7 +4965,7 @@ export default {
|
|||
disconnectTabHandlingModeKeepTabsKeepResults: "Do not close related tabs",
|
||||
disconnectTabHandlingModeKeepTabsKeepResultsDescription: "Keep related tabs, SQL text, and current results without extra cleanup.",
|
||||
reuseDataTab: "Reuse data tab",
|
||||
reuseDataTabDescription: "Reuse data tabs when opening tables from the sidebar; when reopening the same table from the object browser, switch to its existing tab.",
|
||||
reuseDataTabDescription: "Switch to the existing data tab when reopening the same table; different tables always use separate tabs.",
|
||||
sidebarHiddenTablePrefixes: "Hidden table name prefixes",
|
||||
sidebarHiddenTablePrefixesDescription: "One prefix per line. Only sidebar table, view, and collection labels are shortened; tooltips and actions still use the full name.",
|
||||
sidebarHiddenTablePrefixesPlaceholder: "Example:\nODS_\nT8Y2_LONG_",
|
||||
|
|
|
|||
|
|
@ -4740,7 +4740,7 @@ export default withEnglishFallback({
|
|||
disconnectTabHandlingModeKeepTabsKeepResults: "No cerrar pestañas relacionadas",
|
||||
disconnectTabHandlingModeKeepTabsKeepResultsDescription: "Conserva las pestañas relacionadas, el texto SQL y los resultados actuales sin limpieza adicional.",
|
||||
reuseDataTab: "Reutilizar pestaña de datos",
|
||||
reuseDataTabDescription: "Reutiliza las pestañas de datos al abrir tablas desde la barra lateral; al volver a abrir la misma tabla desde el explorador de objetos, cambia a su pestaña existente.",
|
||||
reuseDataTabDescription: "Al volver a abrir la misma tabla, cambia a su pestaña de datos existente; las tablas diferentes siempre usan pestañas separadas.",
|
||||
sidebarHiddenTablePrefixes: "Prefijos ocultos de tablas",
|
||||
sidebarHiddenTablePrefixesDescription: "Un prefijo por linea. Solo acorta etiquetas de tablas, vistas y colecciones en la barra lateral; las acciones y ayudas usan el nombre completo.",
|
||||
sidebarHiddenTablePrefixesPlaceholder: "Ejemplo:\nODS_\nT8Y2_LONG_",
|
||||
|
|
|
|||
|
|
@ -4740,7 +4740,7 @@ export default withEnglishFallback({
|
|||
disconnectTabHandlingModeKeepTabsKeepResults: "Non chiudere le schede correlate",
|
||||
disconnectTabHandlingModeKeepTabsKeepResultsDescription: "Mantieni le schede correlate, il testo SQL e i risultati correnti senza ulteriore pulizia.",
|
||||
reuseDataTab: "Riusa scheda dati",
|
||||
reuseDataTabDescription: "Riutilizza le schede dati quando apri tabelle dalla barra laterale; quando riapri la stessa tabella dal browser degli oggetti, passa alla scheda esistente.",
|
||||
reuseDataTabDescription: "Quando riapri la stessa tabella, passa alla scheda dati esistente; tabelle diverse usano sempre schede separate.",
|
||||
sidebarHiddenTablePrefixes: "Prefissi dei nomi delle tabelle nascosti",
|
||||
sidebarHiddenTablePrefixesDescription: "Un prefisso per riga. Solo le etichette di tabelle, viste e collezioni della barra laterale vengono abbreviate; i suggerimenti e le azioni utilizzano ancora il nome completo.",
|
||||
sidebarHiddenTablePrefixesPlaceholder: "Esempio:\nODS_\nT8Y2_LONG_",
|
||||
|
|
|
|||
|
|
@ -4769,7 +4769,7 @@ export default withEnglishFallback({
|
|||
disconnectTabHandlingModeKeepTabsKeepResults: "関連タブを閉じない",
|
||||
disconnectTabHandlingModeKeepTabsKeepResultsDescription: "関連タブ、SQLテキスト、現在の結果を追加のクリーンアップなしで保持します。",
|
||||
reuseDataTab: "データタブを再利用",
|
||||
reuseDataTabDescription: "サイドバーからテーブルを開く際はデータタブを再利用し、オブジェクトブラウザーから同じテーブルを再度開く際は既存のタブに切り替えます。",
|
||||
reuseDataTabDescription: "同じテーブルを再度開くと既存のデータタブに切り替え、異なるテーブルは常に別のタブで開きます。",
|
||||
sidebarHiddenTablePrefixes: "非表示テーブル名プレフィックス",
|
||||
sidebarHiddenTablePrefixesDescription: "1行に1つのプレフィックス。サイドバーのテーブル、ビュー、コレクションラベルのみ短縮されます。ツールチップと操作は完全な名前を使用します。",
|
||||
sidebarHiddenTablePrefixesPlaceholder: "Example:\nODS_\nT8Y2_LONG_",
|
||||
|
|
|
|||
|
|
@ -4568,7 +4568,7 @@ export default withEnglishFallback({
|
|||
disconnectTabHandlingModeKeepTabsKeepResults: "관련 탭 닫지 않기",
|
||||
disconnectTabHandlingModeKeepTabsKeepResultsDescription: "관련 탭, SQL 텍스트, 현재 결과를 추가 정리 없이 유지합니다.",
|
||||
reuseDataTab: "데이터 탭 재사용",
|
||||
reuseDataTabDescription: "사이드바에서 테이블을 열 때 데이터 탭을 재사용하고, 개체 브라우저에서 같은 테이블을 다시 열면 기존 탭으로 전환합니다.",
|
||||
reuseDataTabDescription: "같은 테이블을 다시 열면 기존 데이터 탭으로 전환하고, 다른 테이블은 항상 별도 탭에서 엽니다.",
|
||||
sidebarHiddenTablePrefixes: "숨겨진 테이블 이름 접두사",
|
||||
sidebarHiddenTablePrefixesDescription: "한 줄에 하나의 접두사. 사이드바의 테이블, 뷰, 컬렉션 라벨만 줄이며 툴팁과 작업은 전체 이름을 계속 사용합니다.",
|
||||
sidebarHiddenTablePrefixesPlaceholder: "예:\nODS_\nT8Y2_LONG_",
|
||||
|
|
|
|||
|
|
@ -4742,7 +4742,7 @@ export default withEnglishFallback({
|
|||
disconnectTabHandlingModeKeepTabsKeepResults: "Não fechar abas relacionadas",
|
||||
disconnectTabHandlingModeKeepTabsKeepResultsDescription: "Manter abas relacionadas, texto SQL e resultados atuais sem limpeza adicional.",
|
||||
reuseDataTab: "Reutilizar aba de dados",
|
||||
reuseDataTabDescription: "Reutiliza abas de dados ao abrir tabelas pela barra lateral; ao reabrir a mesma tabela pelo navegador de objetos, alterna para a aba existente.",
|
||||
reuseDataTabDescription: "Ao reabrir a mesma tabela, alterna para a aba de dados existente; tabelas diferentes sempre usam abas separadas.",
|
||||
sidebarHiddenTablePrefixes: "Prefixos de nome de tabela ocultos",
|
||||
sidebarHiddenTablePrefixesDescription: "Um prefixo por linha. Apenas os rótulos de tabela, view e coleção da barra lateral são encurtados; tooltips e ações ainda usam o nome completo.",
|
||||
sidebarHiddenTablePrefixesPlaceholder: "Exemplo:\nODS_\nT8Y2_LONG_",
|
||||
|
|
|
|||
|
|
@ -4965,7 +4965,7 @@ export default withEnglishFallback({
|
|||
disconnectTabHandlingModeKeepTabsKeepResults: "不关闭相关页签",
|
||||
disconnectTabHandlingModeKeepTabsKeepResultsDescription: "保留相关页签、SQL 文本和当前结果,不做额外处理。",
|
||||
reuseDataTab: "复用数据标签页",
|
||||
reuseDataTabDescription: "从侧边栏打开表时复用数据标签页;从浏览对象重复打开同一张表时切换到已有标签页。",
|
||||
reuseDataTabDescription: "重复打开同一张表时切换到已有数据标签页,不同表始终使用独立标签页。",
|
||||
sidebarHiddenTablePrefixes: "隐藏表名前缀",
|
||||
sidebarHiddenTablePrefixesDescription: "每行一个前缀,仅影响侧边栏表、视图和集合的显示名称,悬浮提示和实际操作仍使用完整名称。",
|
||||
sidebarHiddenTablePrefixesPlaceholder: "例如:\nODS_\nT8Y2_LONG_",
|
||||
|
|
|
|||
|
|
@ -4203,7 +4203,7 @@ export default withEnglishFallback({
|
|||
disconnectTabHandlingModeKeepTabsKeepResults: "不關閉相關分頁",
|
||||
disconnectTabHandlingModeKeepTabsKeepResultsDescription: "保留相關分頁、SQL 文字與目前結果,不另外做清理。",
|
||||
reuseDataTab: "重複使用資料分頁",
|
||||
reuseDataTabDescription: "從側邊欄開啟資料表時重複使用資料分頁;從瀏覽物件重複開啟同一資料表時切換到現有分頁。",
|
||||
reuseDataTabDescription: "重複開啟同一資料表時切換到現有資料分頁,不同資料表一律使用獨立分頁。",
|
||||
sidebarHiddenTablePrefixes: "隱藏資料表名稱字首",
|
||||
sidebarHiddenTablePrefixesDescription: "每行一個字首。只縮短側邊欄中的資料表、檢視和集合標籤;工具提示和實際操作仍使用完整名稱。",
|
||||
sidebarHiddenTablePrefixesPlaceholder: "範例:\nODS_\nT8Y2_LONG_",
|
||||
|
|
|
|||
|
|
@ -221,6 +221,10 @@ describe("query execution schema", () => {
|
|||
});
|
||||
|
||||
describe("object tree node schema", () => {
|
||||
it("ignores database-shaped schema metadata for MySQL tables", () => {
|
||||
expect(connectionObjectTreeNodeSchema({ db_type: "mysql" }, "app", "app")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("uses the SQLite database alias to qualify attached tables", () => {
|
||||
expect(connectionObjectTreeNodeSchema({ db_type: "sqlite" }, "analytics")).toBe("analytics");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -52,11 +52,11 @@ describe("dataTabOpenPolicy", () => {
|
|||
const existing = dataTab("users", "users");
|
||||
existing.tableMeta = { schema: "public", tableName: "users", columns: [], primaryKeys: [] };
|
||||
|
||||
expect(findExistingDataTabCandidate([existing], usersTarget, { openMode: "new-tab", reuseScope: "database" })).toBeUndefined();
|
||||
expect(findExistingDataTabCandidate([existing], usersTarget, { openMode: "new-tab", reuseScope: "same-table" })).toBeUndefined();
|
||||
expect(findExistingDataTabCandidate([existing], usersTarget, { openMode: "new-tab", reuseScope: "none" })).toBeUndefined();
|
||||
});
|
||||
|
||||
it("applies none, same-table, and database reuse scopes independently", () => {
|
||||
it("only reuses the same table when reuse is enabled", () => {
|
||||
const sameTable = dataTab("users", "users");
|
||||
sameTable.tableMeta = { schema: "public", tableName: "users", columns: [], primaryKeys: [] };
|
||||
const otherTable = dataTab("orders", "orders");
|
||||
|
|
@ -64,7 +64,13 @@ describe("dataTabOpenPolicy", () => {
|
|||
expect(findExistingDataTabCandidate([sameTable], usersTarget, { openMode: "default", reuseScope: "none" })).toBeUndefined();
|
||||
expect(findExistingDataTabCandidate([sameTable], usersTarget, { openMode: "default", reuseScope: "same-table" })).toEqual({ tab: sameTable, match: "same-table" });
|
||||
expect(findExistingDataTabCandidate([otherTable], usersTarget, { openMode: "default", reuseScope: "same-table" })).toBeUndefined();
|
||||
expect(findExistingDataTabCandidate([otherTable], usersTarget, { openMode: "default", reuseScope: "database" })).toEqual({ tab: otherTable, match: "database" });
|
||||
});
|
||||
|
||||
it("does not reuse a same-name table from another schema", () => {
|
||||
const archiveUsers = dataTab("archive-users", "users", "archive");
|
||||
archiveUsers.tableMeta = { schema: "archive", tableName: "users", columns: [], primaryKeys: [] };
|
||||
|
||||
expect(findExistingDataTabCandidate([archiveUsers], usersTarget, { openMode: "default", reuseScope: "same-table" })).toBeUndefined();
|
||||
});
|
||||
|
||||
it("allows metadata to update a tab that still points to the requested table", () => {
|
||||
|
|
|
|||
|
|
@ -175,11 +175,11 @@ export function metadataSchemaForConnection(connection: JdbcDialectConnection |
|
|||
export function connectionObjectTreeNodeSchema(connection: JdbcDialectConnection | undefined, database: string, schema?: string): string | undefined {
|
||||
if (connection?.db_type === "jdbc" && inferJdbcDialect(connection) === "databend") return schema || database;
|
||||
if (connectionUsesDatabaseObjectTreeMode(connection)) return undefined;
|
||||
if (schema) return schema;
|
||||
const type = effectiveDatabaseTypeForConnection(connection);
|
||||
if (type === "informix") return undefined;
|
||||
if (type === "sqlite") return database;
|
||||
return isSchemaAware(type) ? database : undefined;
|
||||
if (type === "informix") return schema || undefined;
|
||||
if (type === "sqlite") return schema || database;
|
||||
if (!type) return schema;
|
||||
return isSchemaAware(type) ? schema || database : undefined;
|
||||
}
|
||||
|
||||
/** Maps a database type to the corresponding CodeMirror SQL dialect name used by QueryEditor and DdlViewDialog. */
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { matchesModifierOnlyShortcut, type ShortcutLikeEvent } from "@/lib/edito
|
|||
import type { QueryTab, TreeNodeType } from "@/types/database";
|
||||
|
||||
export type DataTabOpenMode = "default" | "new-tab";
|
||||
export type DataTabReuseScope = "none" | "same-table" | "database";
|
||||
export type DataTabReuseScope = "none" | "same-table";
|
||||
|
||||
type DataTabLike = Pick<QueryTab, "id" | "mode" | "connectionId" | "database" | "schema" | "title" | "tableMeta" | "tableMetaUpdatedAt">;
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ export interface DataTabTarget {
|
|||
|
||||
export type ExistingDataTabCandidate<T extends DataTabLike> = {
|
||||
tab: T;
|
||||
match: "same-table" | "database";
|
||||
match: "same-table";
|
||||
};
|
||||
|
||||
const dataNodeTypes = new Set<TreeNodeType>(["table", "view", "materialized_view"]);
|
||||
|
|
@ -53,8 +53,5 @@ export function findExistingDataTabCandidate<T extends DataTabLike>(tabs: T[], t
|
|||
|
||||
const sameTable = tabs.find((tab) => isSameTable(tab, target));
|
||||
if (sameTable) return { tab: sameTable, match: "same-table" };
|
||||
if (options.reuseScope === "same-table") return undefined;
|
||||
|
||||
const sameDatabase = tabs.find((tab) => isSameDatabase(tab, target));
|
||||
return sameDatabase ? { tab: sameDatabase, match: "database" } : undefined;
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ import { dataTabExecutionDatabase } from "@/lib/table/dataTabExecutionDatabase";
|
|||
import { tableOpenPageLimit } from "@/lib/table/tableOpenPageLimit";
|
||||
import { getCachedTableMetadata, loadTableIndexes, loadTableMetadata, type TableMetadataRequest } from "@/lib/metadata/tableMetadataCache";
|
||||
import { buildTableSelectSql, quoteTableDataIdentifier } from "@/lib/table/tableSelectSql";
|
||||
import { connectionQueryExecutionSchema, connectionUsesDatabaseObjectTreeMode, effectiveDatabaseTypeForConnection, metadataSchemaForConnection } from "@/lib/database/jdbcDialect";
|
||||
import { connectionObjectTreeNodeSchema, connectionQueryExecutionSchema, connectionUsesDatabaseObjectTreeMode, effectiveDatabaseTypeForConnection, metadataSchemaForConnection } from "@/lib/database/jdbcDialect";
|
||||
import { frontendQueryTimeoutSecsForSql, queryTimeoutSecsForConnection } from "@/lib/sql/queryTimeout";
|
||||
import { queryResultNameFromPreamble, queryResultSourceLabel } from "@/lib/sql/queryResultSource";
|
||||
import { beginDataGridNativeSelectionBlock, finishDataGridNativeSelectionBlock } from "@/lib/dataGrid/dataGridNativeSelection";
|
||||
|
|
@ -1200,6 +1200,12 @@ export const useQueryStore = defineStore("query", () => {
|
|||
}
|
||||
|
||||
function applyRestoredOpenTabs(restored: { tabs: QueryTab[]; activeTabId: string | null }) {
|
||||
const connectionStore = useConnectionStore();
|
||||
for (const tab of restored.tabs) {
|
||||
if (tab.mode !== "data") continue;
|
||||
const connection = connectionStore.getConfig(tab.connectionId);
|
||||
if (connection) tab.schema = connectionObjectTreeNodeSchema(connection, tab.database, tab.schema);
|
||||
}
|
||||
tabs.value = restored.tabs;
|
||||
activeTabId.value = restored.activeTabId;
|
||||
activeTabHistory.value = restored.activeTabId ? [restored.activeTabId] : [];
|
||||
|
|
|
|||
Loading…
Reference in New Issue