mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-02 02:34:42 +08:00
feat(sql-file): explain SQL file storage source in panel
This commit is contained in:
@@ -7,6 +7,7 @@ import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
import LightTooltip from "@/components/ui/LightTooltip.vue";
|
||||
import HelpTooltip from "@/components/ui/tooltip/HelpTooltip.vue";
|
||||
import CustomContextMenu, { type ContextMenuItem } from "@/components/ui/CustomContextMenu.vue";
|
||||
import { useQueryStore } from "@/stores/queryStore";
|
||||
import { useConnectionStore } from "@/stores/connectionStore";
|
||||
@@ -542,6 +543,9 @@ function clearContextTarget() {
|
||||
<div class="h-full flex flex-col overflow-hidden">
|
||||
<div class="h-9 flex items-center gap-1 px-2 border-b shrink-0 bg-muted/20">
|
||||
<span class="text-[13px] font-medium">{{ t("sqlFileTree.title") }}</span>
|
||||
<HelpTooltip :label="t('sqlFileTree.storageHelp')" side="bottom" :side-offset="4" trigger-class="h-4 w-4" content-class="max-w-[320px] whitespace-pre-line">
|
||||
{{ t("sqlFileTree.storageHelp") }}
|
||||
</HelpTooltip>
|
||||
<span class="flex-1" />
|
||||
<LightTooltip :text="t('sqlFileTree.filterSettings')" side="bottom" :delay="0" :close-delay="0" nowrap>
|
||||
<Button
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { createApp, nextTick, type App } from "vue";
|
||||
import { createPinia, setActivePinia } from "pinia";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import i18n from "@/i18n";
|
||||
|
||||
vi.mock("@/lib/sqlFile/sqlFileFolders", () => ({
|
||||
getSqlFileFilter: () => "",
|
||||
getSqlFileFolderPaths: () => [],
|
||||
saveSqlFileFilter: vi.fn(),
|
||||
saveSqlFileFolderPaths: vi.fn(),
|
||||
notifySqlFileFoldersChanged: vi.fn(),
|
||||
}));
|
||||
vi.mock("@/lib/backend/tauriRuntime", () => ({ isTauriRuntime: () => false }));
|
||||
|
||||
import SqlFilePanel from "../SqlFilePanel.vue";
|
||||
|
||||
const mounted: Array<{ app: App; host: HTMLElement }> = [];
|
||||
|
||||
function mountPanel() {
|
||||
setActivePinia(createPinia());
|
||||
const host = document.createElement("div");
|
||||
document.body.appendChild(host);
|
||||
const app = createApp(SqlFilePanel);
|
||||
app.use(i18n);
|
||||
app.mount(host);
|
||||
mounted.push({ app, host });
|
||||
return host;
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
for (const { app, host } of mounted.splice(0)) {
|
||||
app.unmount();
|
||||
host.remove();
|
||||
}
|
||||
});
|
||||
|
||||
describe("SQL file panel storage help", () => {
|
||||
it("shows a help button next to the title", async () => {
|
||||
const host = mountPanel();
|
||||
await nextTick();
|
||||
|
||||
const header = host.querySelector(".h-9");
|
||||
expect(header).not.toBeNull();
|
||||
|
||||
const label = i18n.global.t("sqlFileTree.storageHelp");
|
||||
const helpButton = header!.querySelector<HTMLButtonElement>(`button[aria-label="${label}"]`);
|
||||
expect(helpButton).not.toBeNull();
|
||||
expect(helpButton!.querySelector("svg")).not.toBeNull();
|
||||
});
|
||||
|
||||
it("keeps the help button directly after the panel title", async () => {
|
||||
const host = mountPanel();
|
||||
await nextTick();
|
||||
|
||||
const header = host.querySelector(".h-9")!;
|
||||
const title = header.querySelector("span");
|
||||
expect(title?.textContent?.trim()).toBe(i18n.global.t("sqlFileTree.title"));
|
||||
const helpButton = title?.nextElementSibling?.querySelector<HTMLButtonElement>("button[aria-label]");
|
||||
expect(helpButton?.getAttribute("aria-label")).toBe(i18n.global.t("sqlFileTree.storageHelp"));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import az from "../locales/az";
|
||||
import en from "../locales/en";
|
||||
import es from "../locales/es";
|
||||
import it_ from "../locales/it";
|
||||
import ja from "../locales/ja";
|
||||
import ko from "../locales/ko";
|
||||
import ptBR from "../locales/pt-BR";
|
||||
import ru from "../locales/ru";
|
||||
import tr from "../locales/tr";
|
||||
import zhCN from "../locales/zh-CN";
|
||||
import zhTW from "../locales/zh-TW";
|
||||
|
||||
// SQL 文件面板顶部的小问号说明这一侧的内容来源(磁盘上的 .sql 文件),
|
||||
// SQL 库一侧已有自己的说明,所有语言都必须提供译文,避免回落到英文。
|
||||
const KEY = "storageHelp";
|
||||
|
||||
const locales: Array<[string, Record<string, unknown>]> = [
|
||||
["en", en as Record<string, unknown>],
|
||||
["az", az as Record<string, unknown>],
|
||||
["es", es],
|
||||
["it", it_],
|
||||
["ja", ja],
|
||||
["ko", ko],
|
||||
["pt-BR", ptBR],
|
||||
["ru", ru],
|
||||
["tr", tr],
|
||||
["zh-CN", zhCN],
|
||||
["zh-TW", zhTW],
|
||||
];
|
||||
|
||||
function sqlFileTreeHelp(locale: Record<string, unknown>): unknown {
|
||||
const tree = locale.sqlFileTree;
|
||||
if (!tree || typeof tree !== "object") return undefined;
|
||||
return (tree as Record<string, unknown>)[KEY];
|
||||
}
|
||||
|
||||
const englishHelp = sqlFileTreeHelp(en as Record<string, unknown>);
|
||||
|
||||
describe("SQL file panel storage help i18n messages", () => {
|
||||
it("en resolves sqlFileTree.storageHelp to text", () => {
|
||||
expect(englishHelp, "sqlFileTree.storageHelp missing from locales/en.ts").toBeTypeOf("string");
|
||||
});
|
||||
|
||||
it("en explains that the panel lists real .sql files on disk", () => {
|
||||
expect(englishHelp).toContain(".sql");
|
||||
expect(englishHelp).toContain("Open Folder");
|
||||
});
|
||||
|
||||
it.each(locales.slice(1))("%s translates sqlFileTree.storageHelp instead of using the English fallback", (_name, locale) => {
|
||||
const help = sqlFileTreeHelp(locale);
|
||||
expect(help, `${_name} sqlFileTree.storageHelp`).toBeTypeOf("string");
|
||||
expect(help, `${_name} sqlFileTree.storageHelp should not reuse the English text`).not.toBe(englishHelp);
|
||||
});
|
||||
|
||||
it("zh-CN points at the Open Folder flow", () => {
|
||||
const help = sqlFileTreeHelp(zhCN as Record<string, unknown>) as string;
|
||||
expect(help).toContain("打开文件夹");
|
||||
expect(help).toContain(".sql");
|
||||
});
|
||||
});
|
||||
@@ -6670,6 +6670,7 @@ export default withEnglishFallback({
|
||||
},
|
||||
sqlFileTree: {
|
||||
title: "SQL faylları",
|
||||
storageHelp: "Bunlar Qovluq aç ilə açılan diskdəki real .sql fayllarıdır; düzəlişlər birbaşa orijinal fayla yazılır.",
|
||||
openFolder: "Qovluq aç",
|
||||
closePanel: "Bağla",
|
||||
loading: "Yüklənir...",
|
||||
|
||||
@@ -7409,6 +7409,7 @@ export default {
|
||||
},
|
||||
sqlFileTree: {
|
||||
title: "SQL Files",
|
||||
storageHelp: "These are the real .sql files on disk opened via Open Folder; edits are saved straight back to the original file.",
|
||||
openFolder: "Open Folder",
|
||||
closePanel: "Close",
|
||||
loading: "Loading...",
|
||||
|
||||
@@ -9319,6 +9319,7 @@ export default withEnglishFallback({
|
||||
},
|
||||
sqlFileTree: {
|
||||
title: "Archivos SQL",
|
||||
storageHelp: "Son los archivos .sql reales del disco abiertos con Abrir carpeta; las ediciones se guardan directamente en el archivo original.",
|
||||
openFolder: "Abrir carpeta",
|
||||
closePanel: "Cerrar",
|
||||
loading: "Cargando...",
|
||||
|
||||
@@ -9244,6 +9244,7 @@ export default withEnglishFallback({
|
||||
},
|
||||
sqlFileTree: {
|
||||
title: "File SQL",
|
||||
storageHelp: "Sono i file .sql reali sul disco aperti con Apri cartella; le modifiche vengono salvate direttamente nel file originale.",
|
||||
openFolder: "Apri cartella",
|
||||
closePanel: "Chiudi",
|
||||
loading: "Caricamento in corso...",
|
||||
|
||||
@@ -9285,6 +9285,7 @@ export default withEnglishFallback({
|
||||
},
|
||||
sqlFileTree: {
|
||||
title: "SQL ファイル",
|
||||
storageHelp: "「フォルダを開く」で開いたディスク上の実際の.sqlファイルを表示し、編集内容は元のファイルに直接保存されます。",
|
||||
openFolder: "フォルダを開く",
|
||||
closePanel: "閉じる",
|
||||
loading: "読み込み中...",
|
||||
|
||||
@@ -6377,6 +6377,7 @@ export default withEnglishFallback({
|
||||
},
|
||||
sqlFileTree: {
|
||||
title: "SQL 파일",
|
||||
storageHelp: "폴더 열기로 연 디스크의 실제 .sql 파일을 표시하며, 편집 내용은 원본 파일에 바로 저장됩니다.",
|
||||
openFolder: "폴더 열기",
|
||||
closePanel: "닫기",
|
||||
loading: "불러오는 중...",
|
||||
|
||||
@@ -9244,6 +9244,7 @@ export default withEnglishFallback({
|
||||
},
|
||||
sqlFileTree: {
|
||||
title: "Arquivos SQL",
|
||||
storageHelp: "São os arquivos .sql reais no disco abertos com Abrir pasta; as edições são salvas diretamente no arquivo original.",
|
||||
openFolder: "Abrir pasta",
|
||||
closePanel: "Fechar",
|
||||
loading: "Carregando...",
|
||||
|
||||
@@ -7822,6 +7822,7 @@ export default withEnglishFallback({
|
||||
},
|
||||
sqlFileTree: {
|
||||
title: "SQL-файлы",
|
||||
storageHelp: "Это реальные .sql-файлы на диске, открытые через «Открыть папку»; изменения сохраняются прямо в исходный файл.",
|
||||
openFolder: "Открыть папку",
|
||||
closePanel: "Закрыть",
|
||||
loading: "Загрузка...",
|
||||
|
||||
@@ -6552,6 +6552,7 @@ export default withEnglishFallback({
|
||||
},
|
||||
sqlFileTree: {
|
||||
title: "SQL Dosyaları",
|
||||
storageHelp: "Klasör Aç ile açılan diskteki gerçek .sql dosyalarıdır; düzenlemeler doğrudan özgün dosyaya kaydedilir.",
|
||||
openFolder: "Klasör Aç",
|
||||
closePanel: "Kapat",
|
||||
loading: "Yükleniyor...",
|
||||
|
||||
@@ -7376,6 +7376,7 @@ export default withEnglishFallback({
|
||||
},
|
||||
sqlFileTree: {
|
||||
title: "SQL 文件",
|
||||
storageHelp: "此处列出通过「打开文件夹」打开的磁盘上真实 .sql 文件,编辑后直接保存回原文件。",
|
||||
openFolder: "打开文件夹",
|
||||
closePanel: "关闭",
|
||||
loading: "加载中...",
|
||||
|
||||
@@ -9251,6 +9251,7 @@ export default withEnglishFallback({
|
||||
},
|
||||
sqlFileTree: {
|
||||
title: "SQL 檔案",
|
||||
storageHelp: "此處列出透過「開啟資料夾」開啟的磁碟上真實 .sql 檔案,編輯後直接儲存回原檔案。",
|
||||
openFolder: "開啟資料夾",
|
||||
closePanel: "關閉",
|
||||
loading: "載入中...",
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
Reference in New Issue
Block a user