feat(editor): group editor tabs by database
This commit is contained in:
14 files changed
+127
-22
No files matched your search
@@ -5467,6 +5467,7 @@ onUnmounted(() => {
|
|||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="none">{{ t("settings.tabGroupNone") }}</SelectItem>
|
<SelectItem value="none">{{ t("settings.tabGroupNone") }}</SelectItem>
|
||||||
<SelectItem value="database-type">{{ t("settings.tabGroupDatabaseType") }}</SelectItem>
|
<SelectItem value="database-type">{{ t("settings.tabGroupDatabaseType") }}</SelectItem>
|
||||||
|
<SelectItem value="database">{{ t("settings.tabGroupDatabase") }}</SelectItem>
|
||||||
<SelectItem value="connection">{{ t("settings.tabGroupConnection") }}</SelectItem>
|
<SelectItem value="connection">{{ t("settings.tabGroupConnection") }}</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
|||||||
@@ -221,6 +221,7 @@ watch(
|
|||||||
const tabGroupItems = computed(() => [
|
const tabGroupItems = computed(() => [
|
||||||
{ value: "none", label: t("settings.tabGroupNone") },
|
{ value: "none", label: t("settings.tabGroupNone") },
|
||||||
{ value: "database-type", label: t("settings.tabGroupDatabaseType") },
|
{ value: "database-type", label: t("settings.tabGroupDatabaseType") },
|
||||||
|
{ value: "database", label: t("settings.tabGroupDatabase") },
|
||||||
{ value: "connection", label: t("settings.tabGroupConnection") },
|
{ value: "connection", label: t("settings.tabGroupConnection") },
|
||||||
]);
|
]);
|
||||||
const tabSortItems = computed(() => [
|
const tabSortItems = computed(() => [
|
||||||
@@ -246,7 +247,7 @@ async function persistTabPreferences(partial: TabPreferencePatch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateTabGroupMode(value: string) {
|
function updateTabGroupMode(value: string) {
|
||||||
if (value === "none" || value === "database-type" || value === "connection") void persistTabPreferences({ tabGroupMode: value });
|
if (value === "none" || value === "database-type" || value === "database" || value === "connection") void persistTabPreferences({ tabGroupMode: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTabSortMode(value: string) {
|
function updateTabSortMode(value: string) {
|
||||||
@@ -257,16 +258,59 @@ function updateTabPlacement(value: string) {
|
|||||||
if (value === "top" || value === "bottom" || value === "left" || value === "right") void persistTabPreferences({ tabPlacement: value });
|
if (value === "top" || value === "bottom" || value === "left" || value === "right") void persistTabPreferences({ tabPlacement: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function databaseTabGroupKey(tab: QueryTab) {
|
||||||
|
const database = tab.database || "";
|
||||||
|
// A connection-level tab has no database scope, so its catalog cannot split the group.
|
||||||
|
return JSON.stringify([tab.connectionId, database ? tab.catalog || "" : "", database]);
|
||||||
|
}
|
||||||
|
|
||||||
function tabGroupKey(tab: QueryTab) {
|
function tabGroupKey(tab: QueryTab) {
|
||||||
const connection = connectionStore.getConfig(tab.connectionId);
|
const connection = connectionStore.getConfig(tab.connectionId);
|
||||||
if (settingsStore.editorSettings.tabGroupMode === "connection") return tab.connectionId;
|
if (settingsStore.editorSettings.tabGroupMode === "connection") return tab.connectionId;
|
||||||
|
if (settingsStore.editorSettings.tabGroupMode === "database") return databaseTabGroupKey(tab);
|
||||||
return connection?.driver_profile || connection?.db_type || tab.connectionId || "unknown";
|
return connection?.driver_profile || connection?.db_type || tab.connectionId || "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function compareTabGroupKeys(left: string, right: string) {
|
||||||
|
if (left === right) return 0;
|
||||||
|
const localized = left.localeCompare(right, undefined, { sensitivity: "base", numeric: true });
|
||||||
|
// Collation may consider case-distinct identities equal; the raw tie-break keeps clusters contiguous.
|
||||||
|
return localized || (left < right ? -1 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
function tabTitleText(tab: QueryTab) {
|
function tabTitleText(tab: QueryTab) {
|
||||||
return tabDisplayTitle(tab, t);
|
return tabDisplayTitle(tab, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function tabConnectionLabel(tab: QueryTab) {
|
||||||
|
return connectionStore.getConfig(tab.connectionId)?.name || tab.connectionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tabConnectionTargetLabel(tab: QueryTab) {
|
||||||
|
const connection = connectionStore.getConfig(tab.connectionId);
|
||||||
|
const host = connection?.host.trim();
|
||||||
|
return connection && host ? `${host}:${connection.port}` : tab.connectionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
function databaseTabGroupBaseLabel(tab: QueryTab) {
|
||||||
|
if (!tab.database) return tabConnectionLabel(tab);
|
||||||
|
return [tab.database, ...(tab.catalog ? [tab.catalog] : [])].join(" · ");
|
||||||
|
}
|
||||||
|
|
||||||
|
const databaseTabGroupIdentityDisplaysByLabel = computed(() => {
|
||||||
|
const identitiesByLabel = new Map<string, Map<string, { connectionLabel: string; connectionTargetLabel: string }>>();
|
||||||
|
for (const tab of props.tabs) {
|
||||||
|
const label = databaseTabGroupBaseLabel(tab);
|
||||||
|
const identities = identitiesByLabel.get(label) ?? new Map<string, { connectionLabel: string; connectionTargetLabel: string }>();
|
||||||
|
identities.set(databaseTabGroupKey(tab), {
|
||||||
|
connectionLabel: tabConnectionLabel(tab),
|
||||||
|
connectionTargetLabel: tabConnectionTargetLabel(tab),
|
||||||
|
});
|
||||||
|
identitiesByLabel.set(label, identities);
|
||||||
|
}
|
||||||
|
return identitiesByLabel;
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts a section of this pane's tabs for display. With a group mode active,
|
* Sorts a section of this pane's tabs for display. With a group mode active,
|
||||||
* tabs cluster by group key first; within a cluster (and entirely under
|
* tabs cluster by group key first; within a cluster (and entirely under
|
||||||
@@ -279,7 +323,7 @@ function sortDisplayedTabs(tabs: QueryTab[]) {
|
|||||||
.map((tab, index) => ({ tab, index }))
|
.map((tab, index) => ({ tab, index }))
|
||||||
.sort((left, right) => {
|
.sort((left, right) => {
|
||||||
if (groupMode !== "none") {
|
if (groupMode !== "none") {
|
||||||
const group = tabGroupKey(left.tab).localeCompare(tabGroupKey(right.tab), undefined, { sensitivity: "base", numeric: true });
|
const group = compareTabGroupKeys(tabGroupKey(left.tab), tabGroupKey(right.tab));
|
||||||
if (group) return group;
|
if (group) return group;
|
||||||
}
|
}
|
||||||
if (sortMode === "manual") return left.index - right.index;
|
if (sortMode === "manual") return left.index - right.index;
|
||||||
@@ -310,6 +354,17 @@ const editingTabGroupFallbackColor = ref(tabGroupPalette[0]!);
|
|||||||
function tabGroupDefaultLabel(tab: QueryTab) {
|
function tabGroupDefaultLabel(tab: QueryTab) {
|
||||||
const connection = connectionStore.getConfig(tab.connectionId);
|
const connection = connectionStore.getConfig(tab.connectionId);
|
||||||
if (settingsStore.editorSettings.tabGroupMode === "connection") return connection?.name || tab.connectionId;
|
if (settingsStore.editorSettings.tabGroupMode === "connection") return connection?.name || tab.connectionId;
|
||||||
|
if (settingsStore.editorSettings.tabGroupMode === "database") {
|
||||||
|
const baseLabel = databaseTabGroupBaseLabel(tab);
|
||||||
|
const identityDisplays = databaseTabGroupIdentityDisplaysByLabel.value.get(baseLabel);
|
||||||
|
if ((identityDisplays?.size ?? 0) <= 1) return baseLabel;
|
||||||
|
const connectionLabel = tabConnectionLabel(tab);
|
||||||
|
const sameNameDisplays = [...identityDisplays!.values()].filter((display) => display.connectionLabel === connectionLabel);
|
||||||
|
if (sameNameDisplays.length <= 1) return `${baseLabel} · ${connectionLabel}`;
|
||||||
|
const connectionTargetLabel = tabConnectionTargetLabel(tab);
|
||||||
|
if (sameNameDisplays.filter((display) => display.connectionTargetLabel === connectionTargetLabel).length <= 1) return `${baseLabel} · ${connectionLabel} · ${connectionTargetLabel}`;
|
||||||
|
return `${baseLabel} · ${connectionLabel} · ${connectionTargetLabel} · ${tab.connectionId}`;
|
||||||
|
}
|
||||||
return connection?.driver_label || connection?.driver_profile || connection?.db_type || tab.connectionId;
|
return connection?.driver_label || connection?.driver_profile || connection?.db_type || tab.connectionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,7 +382,7 @@ function tabGroupLabel(tab: QueryTab) {
|
|||||||
|
|
||||||
// Pinned and regular tabs form separate clusters even under the same key.
|
// Pinned and regular tabs form separate clusters even under the same key.
|
||||||
function tabGroupId(tab: QueryTab) {
|
function tabGroupId(tab: QueryTab) {
|
||||||
return `${tab.pinned ? "fixed" : "regular"}:${tabGroupKey(tab)}`;
|
return `${tab.pinned ? "fixed" : "regular"}:${settingsStore.editorSettings.tabGroupMode}:${tabGroupKey(tab)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isTabGroupCollapsed(tab: QueryTab) {
|
function isTabGroupCollapsed(tab: QueryTab) {
|
||||||
@@ -376,7 +431,6 @@ function groupColorStyle(color: string): CSSProperties {
|
|||||||
return {
|
return {
|
||||||
"--tab-group-color": color,
|
"--tab-group-color": color,
|
||||||
"--tab-group-soft": hexToRgba(color, 0.12),
|
"--tab-group-soft": hexToRgba(color, 0.12),
|
||||||
"--tab-group-rail": hexToRgba(color, 0.3),
|
|
||||||
} as CSSProperties;
|
} as CSSProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+28
-2
@@ -29,7 +29,7 @@ const sharedStyles = readFileSync(resolve(specDir, "../appTabBar.css"), "utf8");
|
|||||||
describe("EditorGroupTabBar semantic tab groups", () => {
|
describe("EditorGroupTabBar semantic tab groups", () => {
|
||||||
it("keeps separate collapsed state for pinned and regular clusters under the same key", () => {
|
it("keeps separate collapsed state for pinned and regular clusters under the same key", () => {
|
||||||
expect(source).toContain("const collapsedTabGroups = ref<Set<string>>(new Set());");
|
expect(source).toContain("const collapsedTabGroups = ref<Set<string>>(new Set());");
|
||||||
expect(source).toContain('return `${tab.pinned ? "fixed" : "regular"}:${tabGroupKey(tab)}`;');
|
expect(source).toContain('return `${tab.pinned ? "fixed" : "regular"}:${settingsStore.editorSettings.tabGroupMode}:${tabGroupKey(tab)}`;');
|
||||||
expect(source).toContain("function toggleTabGroup(tab: QueryTab)");
|
expect(source).toContain("function toggleTabGroup(tab: QueryTab)");
|
||||||
expect(source).toContain(':aria-expanded="!isTabGroupCollapsed(entry.tab)"');
|
expect(source).toContain(':aria-expanded="!isTabGroupCollapsed(entry.tab)"');
|
||||||
});
|
});
|
||||||
@@ -180,7 +180,7 @@ describe("EditorGroupTabBar vertical placement", () => {
|
|||||||
expect(sharedStyles).toContain('.vertical-tab-layout .app-tab-pill[data-active-tab="true"]');
|
expect(sharedStyles).toContain('.vertical-tab-layout .app-tab-pill[data-active-tab="true"]');
|
||||||
expect(sharedStyles).toContain("inset 0 0 0 1px color-mix");
|
expect(sharedStyles).toContain("inset 0 0 0 1px color-mix");
|
||||||
expect(sharedStyles).toContain(".vertical-tab-layout .tab-group-header:not(.tab-group-header--collapsed)::after");
|
expect(sharedStyles).toContain(".vertical-tab-layout .tab-group-header:not(.tab-group-header--collapsed)::after");
|
||||||
expect(sharedStyles).toContain("margin-inline: 2.5rem 0.5rem;");
|
expect(sharedStyles).toContain("margin-inline: var(--tab-group-tab-inset) 0.5rem;");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -315,6 +315,32 @@ describe("EditorGroupTabBar group behavior", () => {
|
|||||||
host.remove();
|
host.remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("groups by database identity, disambiguating same-name databases across connections", async () => {
|
||||||
|
const store = useQueryStore();
|
||||||
|
const settings = useSettingsStore();
|
||||||
|
settings.editorSettings.tabGroupMode = "database";
|
||||||
|
const pgApp = store.createTab("pg-1", "app", "PG app", "query");
|
||||||
|
store.createTab("mysql-1", "app", "MY app", "query");
|
||||||
|
const pgConn = store.createTab("pg-1", "", "PG conn", "query");
|
||||||
|
const mainGroup = store.groups[0];
|
||||||
|
const { app, host } = mountBar(mainGroup.id, store.tabs.slice(), pgApp, pinia);
|
||||||
|
await settle();
|
||||||
|
|
||||||
|
const headers = Array.from(host.querySelectorAll<HTMLButtonElement>(".tab-group-header"));
|
||||||
|
// Sorted by group key: the same-name "app" databases stay separate clusters
|
||||||
|
// disambiguated by connection label, and the database-less tab clusters by connection.
|
||||||
|
expect(headers.map((header) => header.title)).toEqual(["app · mysql-1", "pg-1", "app · pg-1"]);
|
||||||
|
expect(host.querySelectorAll("[data-tab-id]").length).toBe(3);
|
||||||
|
|
||||||
|
// Collapsing one "app" cluster leaves the other same-name cluster expanded.
|
||||||
|
headers[0]!.click();
|
||||||
|
await settle();
|
||||||
|
expect(Array.from(host.querySelectorAll("[data-tab-id]")).map((pill) => pill.getAttribute("data-tab-id"))).toEqual([pgConn, pgApp]);
|
||||||
|
|
||||||
|
app.unmount();
|
||||||
|
host.remove();
|
||||||
|
});
|
||||||
|
|
||||||
it("exposes the drag-back hit-test anchor and highlights itself as the detached drop target", async () => {
|
it("exposes the drag-back hit-test anchor and highlights itself as the detached drop target", async () => {
|
||||||
const store = useQueryStore();
|
const store = useQueryStore();
|
||||||
const tabId = store.createTab("pg-1", "app", "PG 1", "query");
|
const tabId = store.createTab("pg-1", "app", "PG 1", "query");
|
||||||
|
|||||||
@@ -351,6 +351,12 @@
|
|||||||
|
|
||||||
.vertical-tab-layout {
|
.vertical-tab-layout {
|
||||||
flex: 0 0 15rem;
|
flex: 0 0 15rem;
|
||||||
|
--tab-group-header-inset: 0.5rem;
|
||||||
|
--tab-group-root-rail-x: 1.16rem;
|
||||||
|
--tab-group-tab-inset: 2.5rem;
|
||||||
|
--tab-group-branch-width: 0.65rem;
|
||||||
|
--tab-group-row-half: 1rem;
|
||||||
|
--tab-group-header-gap: 0.08rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vertical-tab-layout .app-tab-strip {
|
.vertical-tab-layout .app-tab-strip {
|
||||||
@@ -440,7 +446,7 @@
|
|||||||
width: calc(100% - 1rem) !important;
|
width: calc(100% - 1rem) !important;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
margin: 0.35rem 0.5rem 0.08rem;
|
margin: 0.35rem var(--tab-group-header-inset) var(--tab-group-header-gap);
|
||||||
padding: 0;
|
padding: 0;
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
@@ -448,6 +454,11 @@
|
|||||||
line-height: 1rem;
|
line-height: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vertical-tab-layout .tab-group-header,
|
||||||
|
.vertical-tab-layout .tab-group-tab {
|
||||||
|
--tab-group-vertical-rail: color-mix(in srgb, var(--tab-group-color) 30%, var(--background));
|
||||||
|
}
|
||||||
|
|
||||||
.vertical-tab-layout .tab-group-header-content {
|
.vertical-tab-layout .tab-group-header-content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -474,12 +485,12 @@
|
|||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
top: 1rem;
|
top: 50%;
|
||||||
bottom: -1.08rem;
|
bottom: calc(0rem - var(--tab-group-header-gap) - var(--tab-group-row-half));
|
||||||
left: 0.66rem;
|
left: calc(var(--tab-group-root-rail-x) - var(--tab-group-header-inset));
|
||||||
width: 0.7rem;
|
width: calc(var(--tab-group-tab-inset) - var(--tab-group-root-rail-x));
|
||||||
border-bottom: 1px solid var(--tab-group-rail);
|
border-bottom: 1px solid var(--tab-group-vertical-rail);
|
||||||
border-left: 1px solid var(--tab-group-rail);
|
border-left: 1px solid var(--tab-group-vertical-rail);
|
||||||
border-bottom-left-radius: 0.1875rem;
|
border-bottom-left-radius: 0.1875rem;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
@@ -492,7 +503,7 @@
|
|||||||
.vertical-tab-layout .tab-group-tab {
|
.vertical-tab-layout .tab-group-tab {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: calc(100% - 3rem);
|
width: calc(100% - 3rem);
|
||||||
margin-inline: 2.5rem 0.5rem;
|
margin-inline: var(--tab-group-tab-inset) 0.5rem;
|
||||||
padding-inline-start: 0.65rem !important;
|
padding-inline-start: 0.65rem !important;
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
}
|
}
|
||||||
@@ -500,12 +511,12 @@
|
|||||||
.vertical-tab-layout .tab-group-tab::before {
|
.vertical-tab-layout .tab-group-tab::before {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -0.25rem;
|
top: 0;
|
||||||
bottom: -0.25rem;
|
bottom: 0;
|
||||||
left: -0.65rem;
|
left: calc(0rem - var(--tab-group-branch-width));
|
||||||
width: 1px;
|
width: 1px;
|
||||||
border-radius: 9999px;
|
border-radius: 9999px;
|
||||||
background: var(--tab-group-rail);
|
background: var(--tab-group-vertical-rail);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,10 +533,14 @@
|
|||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(50% - 0.5px);
|
top: calc(50% - 0.5px);
|
||||||
left: -0.65rem;
|
left: calc(0rem - var(--tab-group-branch-width));
|
||||||
width: 0.65rem;
|
width: var(--tab-group-branch-width);
|
||||||
height: 1px;
|
height: 1px;
|
||||||
border-radius: 0 9999px 9999px 0;
|
border-radius: 0 9999px 9999px 0;
|
||||||
background: var(--tab-group-rail);
|
background: var(--tab-group-vertical-rail);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vertical-tab-layout .tab-group-tab--first::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
@@ -6523,6 +6523,7 @@ export default {
|
|||||||
tabGroup: "Group by",
|
tabGroup: "Group by",
|
||||||
tabGroupNone: "No grouping",
|
tabGroupNone: "No grouping",
|
||||||
tabGroupDatabaseType: "Group by database type",
|
tabGroupDatabaseType: "Group by database type",
|
||||||
|
tabGroupDatabase: "Group by database",
|
||||||
tabGroupConnection: "Group by connection",
|
tabGroupConnection: "Group by connection",
|
||||||
tabSort: "Sort by",
|
tabSort: "Sort by",
|
||||||
tabSortManual: "Manual order",
|
tabSortManual: "Manual order",
|
||||||
|
|||||||
@@ -6190,6 +6190,7 @@ export default withEnglishFallback({
|
|||||||
tabGroup: "Agrupar por",
|
tabGroup: "Agrupar por",
|
||||||
tabGroupNone: "Sin agrupación",
|
tabGroupNone: "Sin agrupación",
|
||||||
tabGroupDatabaseType: "Agrupar por tipo de base de datos",
|
tabGroupDatabaseType: "Agrupar por tipo de base de datos",
|
||||||
|
tabGroupDatabase: "Agrupar por base de datos",
|
||||||
tabGroupConnection: "Agrupar por conexión",
|
tabGroupConnection: "Agrupar por conexión",
|
||||||
tabSort: "Ordenar por",
|
tabSort: "Ordenar por",
|
||||||
tabSortManual: "Orden manual",
|
tabSortManual: "Orden manual",
|
||||||
|
|||||||
@@ -6190,6 +6190,7 @@ export default withEnglishFallback({
|
|||||||
tabGroup: "Raggruppa per",
|
tabGroup: "Raggruppa per",
|
||||||
tabGroupNone: "Nessun raggruppamento",
|
tabGroupNone: "Nessun raggruppamento",
|
||||||
tabGroupDatabaseType: "Raggruppa per tipo di database",
|
tabGroupDatabaseType: "Raggruppa per tipo di database",
|
||||||
|
tabGroupDatabase: "Raggruppa per database",
|
||||||
tabGroupConnection: "Raggruppa per connessione",
|
tabGroupConnection: "Raggruppa per connessione",
|
||||||
tabSort: "Ordina per",
|
tabSort: "Ordina per",
|
||||||
tabSortManual: "Ordine manuale",
|
tabSortManual: "Ordine manuale",
|
||||||
|
|||||||
@@ -6228,6 +6228,7 @@ export default withEnglishFallback({
|
|||||||
tabGroup: "グループ化",
|
tabGroup: "グループ化",
|
||||||
tabGroupNone: "グループ化しない",
|
tabGroupNone: "グループ化しない",
|
||||||
tabGroupDatabaseType: "データベース種別でグループ化",
|
tabGroupDatabaseType: "データベース種別でグループ化",
|
||||||
|
tabGroupDatabase: "データベースごとにグループ化",
|
||||||
tabGroupConnection: "接続ごとにグループ化",
|
tabGroupConnection: "接続ごとにグループ化",
|
||||||
tabSort: "並べ替え",
|
tabSort: "並べ替え",
|
||||||
tabSortManual: "手動順",
|
tabSortManual: "手動順",
|
||||||
|
|||||||
@@ -5925,6 +5925,7 @@ export default withEnglishFallback({
|
|||||||
tabGroup: "그룹 기준",
|
tabGroup: "그룹 기준",
|
||||||
tabGroupNone: "그룹화 안 함",
|
tabGroupNone: "그룹화 안 함",
|
||||||
tabGroupDatabaseType: "데이터베이스 유형별 그룹화",
|
tabGroupDatabaseType: "데이터베이스 유형별 그룹화",
|
||||||
|
tabGroupDatabase: "데이터베이스별 그룹화",
|
||||||
tabGroupConnection: "연결별 그룹화",
|
tabGroupConnection: "연결별 그룹화",
|
||||||
tabSort: "정렬 기준",
|
tabSort: "정렬 기준",
|
||||||
tabSortManual: "수동 순서",
|
tabSortManual: "수동 순서",
|
||||||
|
|||||||
@@ -6192,6 +6192,7 @@ export default withEnglishFallback({
|
|||||||
tabGroup: "Agrupar por",
|
tabGroup: "Agrupar por",
|
||||||
tabGroupNone: "Sem agrupamento",
|
tabGroupNone: "Sem agrupamento",
|
||||||
tabGroupDatabaseType: "Agrupar por tipo de banco de dados",
|
tabGroupDatabaseType: "Agrupar por tipo de banco de dados",
|
||||||
|
tabGroupDatabase: "Agrupar por banco de dados",
|
||||||
tabGroupConnection: "Agrupar por conexão",
|
tabGroupConnection: "Agrupar por conexão",
|
||||||
tabSort: "Ordenar por",
|
tabSort: "Ordenar por",
|
||||||
tabSortManual: "Ordem manual",
|
tabSortManual: "Ordem manual",
|
||||||
|
|||||||
@@ -6513,6 +6513,7 @@ export default withEnglishFallback({
|
|||||||
tabGroup: "Gruplama ölçütü",
|
tabGroup: "Gruplama ölçütü",
|
||||||
tabGroupNone: "Gruplama yok",
|
tabGroupNone: "Gruplama yok",
|
||||||
tabGroupDatabaseType: "Veritabanı türüne göre grupla",
|
tabGroupDatabaseType: "Veritabanı türüne göre grupla",
|
||||||
|
tabGroupDatabase: "Veritabanına göre grupla",
|
||||||
tabGroupConnection: "Bağlantıya göre grupla",
|
tabGroupConnection: "Bağlantıya göre grupla",
|
||||||
tabSort: "Sıralama ölçütü",
|
tabSort: "Sıralama ölçütü",
|
||||||
tabSortManual: "Elle sıralama",
|
tabSortManual: "Elle sıralama",
|
||||||
|
|||||||
@@ -6506,6 +6506,7 @@ export default withEnglishFallback({
|
|||||||
tabGroup: "分组方式",
|
tabGroup: "分组方式",
|
||||||
tabGroupNone: "不分组",
|
tabGroupNone: "不分组",
|
||||||
tabGroupDatabaseType: "按数据库类型分组",
|
tabGroupDatabaseType: "按数据库类型分组",
|
||||||
|
tabGroupDatabase: "按数据库分组",
|
||||||
tabGroupConnection: "按连接分组",
|
tabGroupConnection: "按连接分组",
|
||||||
tabSort: "排序方式",
|
tabSort: "排序方式",
|
||||||
tabSortManual: "手动排序",
|
tabSortManual: "手动排序",
|
||||||
|
|||||||
@@ -5509,6 +5509,7 @@ export default withEnglishFallback({
|
|||||||
tabGroup: "分組方式",
|
tabGroup: "分組方式",
|
||||||
tabGroupNone: "不分組",
|
tabGroupNone: "不分組",
|
||||||
tabGroupDatabaseType: "依資料庫類型分組",
|
tabGroupDatabaseType: "依資料庫類型分組",
|
||||||
|
tabGroupDatabase: "依資料庫分組",
|
||||||
tabGroupConnection: "依連線分組",
|
tabGroupConnection: "依連線分組",
|
||||||
tabSort: "排序方式",
|
tabSort: "排序方式",
|
||||||
tabSortManual: "手動排序",
|
tabSortManual: "手動排序",
|
||||||
|
|||||||
@@ -574,7 +574,7 @@ const TAB_LAYOUT_MODES = ["scroll", "wrap"] as const;
|
|||||||
export type TabLayoutMode = (typeof TAB_LAYOUT_MODES)[number];
|
export type TabLayoutMode = (typeof TAB_LAYOUT_MODES)[number];
|
||||||
const TAB_PLACEMENTS = ["top", "bottom", "left", "right"] as const;
|
const TAB_PLACEMENTS = ["top", "bottom", "left", "right"] as const;
|
||||||
export type TabPlacement = (typeof TAB_PLACEMENTS)[number];
|
export type TabPlacement = (typeof TAB_PLACEMENTS)[number];
|
||||||
const TAB_GROUP_MODES = ["none", "database-type", "connection"] as const;
|
const TAB_GROUP_MODES = ["none", "database-type", "database", "connection"] as const;
|
||||||
export type TabGroupMode = (typeof TAB_GROUP_MODES)[number];
|
export type TabGroupMode = (typeof TAB_GROUP_MODES)[number];
|
||||||
export interface TabGroupCustomization {
|
export interface TabGroupCustomization {
|
||||||
name?: string;
|
name?: string;
|
||||||
|
|||||||
Reference in new issue
Block a user