🐛 fix(sidebar): 恢复批量库表危险操作

- 恢复批量表和批量库按钮到原批量操作弹窗\n- 补回批量删除表和删除库的危险确认与执行逻辑\n- 删除表仅处理 table 对象,避免视图误走 DropTable\n- 补齐多语言文案与入口/删除回归测试
This commit is contained in:
Syngnat
2026-06-29 17:09:01 +08:00
parent aed87665f4
commit dac9e1f571
13 changed files with 371 additions and 13 deletions

View File

@@ -804,6 +804,12 @@ describe('Sidebar locate toolbar', () => {
expect(markup).toContain('data-sidebar-create-group-action="true"');
expect(markup).toContain('data-sidebar-batch-table-action="true"');
expect(markup).toContain('data-sidebar-batch-database-action="true"');
expect(source).toContain('openBatchTableExport: () => openBatchOperationModal(),');
expect(source).toContain('openBatchDatabaseExport: () => openBatchDatabaseModal(),');
expect(source).toContain('onClick={() => openBatchOperationModal()}');
expect(source).toContain('onClick={() => openBatchDatabaseModal()}');
expect(source).not.toContain('openBatchTableExport: () => openBatchTableExportWorkbench()');
expect(source).not.toContain('openBatchDatabaseExport: () => openBatchDatabaseExportWorkbench()');
expect(markup).toContain('data-sidebar-open-external-sql-file-action="true"');
expect(markup).toContain('data-sidebar-locate-current-tab-action="true"');
expect(markup).toContain('data-gonavi-new-query-action="true"');

View File

@@ -773,12 +773,14 @@ const Sidebar: React.FC<{
handleDatabaseChange,
handleBatchExport,
handleBatchClear,
handleBatchDeleteTables,
handleCheckAll,
handleInvertSelection,
openBatchDatabaseModal,
openBatchDatabaseExportWorkbench,
handleDbConnectionChange,
handleBatchDbExport,
handleBatchDbDelete,
handleCheckAllDb,
handleInvertSelectionDb,
} = useSidebarBatchExport({
@@ -2618,8 +2620,8 @@ const Sidebar: React.FC<{
},
handlers: {
openCreateTagModal: () => { setRenameViewTarget(null); createTagForm.resetFields(); setIsCreateTagModalOpen(true); },
openBatchTableExport: () => openBatchTableExportWorkbench(),
openBatchDatabaseExport: () => openBatchDatabaseExportWorkbench(),
openBatchTableExport: () => openBatchOperationModal(),
openBatchDatabaseExport: () => openBatchDatabaseModal(),
openExternalSqlFile: handleOpenSQLFileFromToolbar,
locateActiveTab: handleLocateActiveTabInSidebar,
toggleAI: onToggleAI ?? (() => {}),
@@ -2857,7 +2859,7 @@ const Sidebar: React.FC<{
icon={<TableOutlined />}
aria-label={t('sidebar.action.batch_tables')}
data-sidebar-batch-table-action="true"
onClick={() => openBatchTableExportWorkbench()}
onClick={() => openBatchOperationModal()}
style={{ color: legacyToolbarButtonColor }}
/>
</Tooltip>
@@ -2870,7 +2872,7 @@ const Sidebar: React.FC<{
icon={<DatabaseOutlined />}
aria-label={t('sidebar.action.batch_databases')}
data-sidebar-batch-database-action="true"
onClick={() => openBatchDatabaseExportWorkbench()}
onClick={() => openBatchDatabaseModal()}
style={{ color: legacyToolbarButtonColor }}
/>
</Tooltip>
@@ -3097,6 +3099,7 @@ const Sidebar: React.FC<{
handleConnectionChange={handleConnectionChange}
handleDatabaseChange={handleDatabaseChange}
handleBatchClear={handleBatchClear}
handleBatchDeleteTables={handleBatchDeleteTables}
handleBatchExport={handleBatchExport}
handleCheckAll={handleCheckAll}
handleInvertSelection={handleInvertSelection}
@@ -3108,6 +3111,7 @@ const Sidebar: React.FC<{
setCheckedDbKeys={setCheckedDbKeys}
handleDbConnectionChange={handleDbConnectionChange}
handleBatchDbExport={handleBatchDbExport}
handleBatchDbDelete={handleBatchDbDelete}
handleCheckAllDb={handleCheckAllDb}
handleInvertSelectionDb={handleInvertSelectionDb}
/>

View File

@@ -11,6 +11,8 @@ const requiredKeys = [
'sidebar.action.batch_tables',
'sidebar.action.batch_databases',
'sidebar.action.clear_tables',
'sidebar.action.delete_tables',
'sidebar.action.delete_database_count',
'sidebar.action.export_schema',
'sidebar.action.export_data_only',
'sidebar.action.backup_schema_data',
@@ -63,6 +65,7 @@ describe('Sidebar batch actions i18n', () => {
[
'清空表',
'删除表',
'导出结构',
'仅数据(INSERT)',
'备份(结构+数据)',
@@ -118,6 +121,8 @@ describe('Sidebar batch actions i18n', () => {
[
'sidebar.action.clear_tables',
'sidebar.action.delete_tables',
'sidebar.action.delete_database_count',
'sidebar.action.export_schema',
'sidebar.action.export_data_only',
'sidebar.action.backup_schema_data',
@@ -148,6 +153,10 @@ describe('Sidebar batch actions i18n', () => {
expect(batchModalSource, key).toContain(`t('${key}'`);
});
expect(batchModalSource).toContain('handleBatchDeleteTables');
expect(batchModalSource).toContain('handleBatchDbDelete');
expect(batchModalSource).toContain("item.objectType === 'table'");
[
'sidebar.tab.batch_export_objects',
'sidebar.tab.batch_export_objects_database',
@@ -170,6 +179,8 @@ describe('Sidebar batch actions i18n', () => {
requiredKeys.forEach((key) => {
expect(catalog[key], `${locale}:${key}`).toBeTruthy();
});
expect(placeholders(catalog['sidebar.action.delete_database_count'])).toEqual(['count']);
expect(placeholders(catalog['sidebar.action.delete_tables'])).toEqual([]);
expect(placeholders(catalog['sidebar.tab.batch_export_objects'])).toEqual([]);
expect(placeholders(catalog['sidebar.tab.batch_export_objects_database'])).toEqual(['database']);
expect(placeholders(catalog['sidebar.tab.batch_export_databases'])).toEqual([]);

View File

@@ -12,10 +12,24 @@ const requiredKeys = [
'sidebar.message.clearing_selected_tables',
'sidebar.message.clear_success',
'sidebar.message.clear_failed',
'sidebar.message.select_table_required',
'sidebar.modal.confirm_delete_selected_tables.title',
'sidebar.modal.confirm_delete_selected_tables.content',
'sidebar.message.deleting_selected_tables',
'sidebar.message.delete_tables_success',
'sidebar.message.delete_tables_failed',
] as const;
const extractHandleBatchClearBlock = (): string => {
const start = source.indexOf('const handleBatchClear = async');
const end = source.indexOf('const handleBatchDeleteTables = async', start);
expect(start).toBeGreaterThanOrEqual(0);
expect(end).toBeGreaterThan(start);
return source.slice(start, end);
};
const extractHandleBatchDeleteTablesBlock = (): string => {
const start = source.indexOf('const handleBatchDeleteTables = async');
const end = source.indexOf('const handleCheckAll = (checked: boolean)', start);
expect(start).toBeGreaterThanOrEqual(0);
expect(end).toBeGreaterThan(start);
@@ -55,6 +69,28 @@ describe('Sidebar batch clear feedback i18n', () => {
expect(block).toContain("res.message !== '已取消'");
});
it('localizes handleBatchDeleteTables validation, confirmation, loading, success, and failure wrappers', () => {
const block = extractHandleBatchDeleteTablesBlock();
expect(block).toContain('DropTable');
expect(block).toContain("item.objectType === 'table'");
expect(block).toContain("t('sidebar.message.select_table_required')");
expect(block).toContain("t('sidebar.modal.confirm_delete_selected_tables.title')");
expect(block).toContain("t('sidebar.modal.confirm_delete_selected_tables.content'");
expect(block).toContain("t('sidebar.action.delete')");
expect(block).toContain('okButtonProps: { danger: true }');
expect(block).toContain("t('sidebar.action.cancel')");
expect(block).toContain("t('sidebar.message.deleting_selected_tables'");
expect(block).toContain("t('sidebar.message.delete_tables_success'");
expect(block).toContain("t('sidebar.message.delete_tables_failed'");
expect(block).toContain('connection: conn.name');
expect(block).toContain('database: dbName');
expect(block).toContain('count: tableNames.length');
expect(block).toContain('count: successKeys.length');
expect(block).toContain('table: failed.table');
expect(block).toContain('error: failed.error');
});
it('keeps batch clear feedback keys available with stable placeholders', () => {
locales.forEach((locale) => {
const catalog = JSON.parse(readFileSync(new URL(`../../../shared/i18n/${locale}.json`, import.meta.url), 'utf8')) as Record<string, string>;
@@ -69,6 +105,12 @@ describe('Sidebar batch clear feedback i18n', () => {
expect(placeholders(catalog['sidebar.message.clearing_selected_tables'])).toEqual(['count']);
expect(placeholders(catalog['sidebar.message.clear_success'])).toEqual([]);
expect(placeholders(catalog['sidebar.message.clear_failed'])).toEqual(['error']);
expect(placeholders(catalog['sidebar.message.select_table_required'])).toEqual([]);
expect(placeholders(catalog['sidebar.modal.confirm_delete_selected_tables.title'])).toEqual([]);
expect(placeholders(catalog['sidebar.modal.confirm_delete_selected_tables.content'])).toEqual(['connection', 'count', 'database']);
expect(placeholders(catalog['sidebar.message.deleting_selected_tables'])).toEqual(['count']);
expect(placeholders(catalog['sidebar.message.delete_tables_success'])).toEqual(['count']);
expect(placeholders(catalog['sidebar.message.delete_tables_failed'])).toEqual(['error', 'table']);
});
});
});

View File

@@ -10,6 +10,11 @@ const requiredKeys = [
'sidebar.message.exporting_database_backup',
'sidebar.message.database_export_success',
'sidebar.message.database_export_failed',
'sidebar.modal.confirm_delete_selected_databases.title',
'sidebar.modal.confirm_delete_selected_databases.content',
'sidebar.message.deleting_selected_databases',
'sidebar.message.delete_databases_success',
'sidebar.message.delete_databases_failed',
] as const;
const extractBatchDatabaseExportBlock = (): string => {
@@ -20,6 +25,14 @@ const extractBatchDatabaseExportBlock = (): string => {
return source.slice(start, end);
};
const extractHandleBatchDbDeleteBlock = (): string => {
const start = source.indexOf('const handleBatchDbDelete = async');
const end = source.indexOf('const handleCheckAllDb = (checked: boolean)', start);
expect(start).toBeGreaterThanOrEqual(0);
expect(end).toBeGreaterThan(start);
return source.slice(start, end);
};
const placeholders = (value: string): string[] => [...value.matchAll(/\{\{(\w+)\}\}/g)]
.map((match) => match[1])
.sort();
@@ -47,6 +60,26 @@ describe('Sidebar batch database export feedback i18n', () => {
expect(block).toContain("res.message !== '已取消'");
});
it('localizes handleBatchDbDelete confirmation, loading, success, and failure wrappers', () => {
const block = extractHandleBatchDbDeleteBlock();
expect(block).toContain('DropDatabase');
expect(block).toContain("t('sidebar.message.select_database_required')");
expect(block).toContain("t('sidebar.modal.confirm_delete_selected_databases.title')");
expect(block).toContain("t('sidebar.modal.confirm_delete_selected_databases.content'");
expect(block).toContain("t('sidebar.action.delete')");
expect(block).toContain('okButtonProps: { danger: true }');
expect(block).toContain("t('sidebar.action.cancel')");
expect(block).toContain("t('sidebar.message.deleting_selected_databases'");
expect(block).toContain("t('sidebar.message.delete_databases_success'");
expect(block).toContain("t('sidebar.message.delete_databases_failed'");
expect(block).toContain('connection: batchConnContext.name');
expect(block).toContain('count: selectedDbs.length');
expect(block).toContain('count: successKeys.length');
expect(block).toContain('database: failed.database');
expect(block).toContain('error: failed.error');
});
it('keeps batch database export feedback keys available with stable placeholders', () => {
locales.forEach((locale) => {
const catalog = JSON.parse(readFileSync(new URL(`../../../shared/i18n/${locale}.json`, import.meta.url), 'utf8')) as Record<string, string>;
@@ -59,6 +92,11 @@ describe('Sidebar batch database export feedback i18n', () => {
expect(placeholders(catalog['sidebar.message.exporting_database_backup'])).toEqual(['database']);
expect(placeholders(catalog['sidebar.message.database_export_success'])).toEqual(['database']);
expect(placeholders(catalog['sidebar.message.database_export_failed'])).toEqual(['database', 'error']);
expect(placeholders(catalog['sidebar.modal.confirm_delete_selected_databases.title'])).toEqual([]);
expect(placeholders(catalog['sidebar.modal.confirm_delete_selected_databases.content'])).toEqual(['connection', 'count']);
expect(placeholders(catalog['sidebar.message.deleting_selected_databases'])).toEqual(['count']);
expect(placeholders(catalog['sidebar.message.delete_databases_success'])).toEqual(['count']);
expect(placeholders(catalog['sidebar.message.delete_databases_failed'])).toEqual(['database', 'error']);
});
});
});

View File

@@ -13,16 +13,11 @@ import Modal from '../common/ResizableDraggableModal';
import type { SavedConnection } from '../../types';
import { t } from '../../i18n';
import type {
BatchObjectItem,
BatchObjectFilterType,
BatchSelectionScope,
} from './useSidebarBatchExport';
type BatchObjectItem = {
key: string;
dbName?: string;
title: React.ReactNode;
};
type SidebarBatchExportModalsProps = {
connections: SavedConnection[];
modalPanelStyle: React.CSSProperties;
@@ -55,6 +50,7 @@ type SidebarBatchExportModalsProps = {
handleConnectionChange: (connectionId: string) => void;
handleDatabaseChange: (databaseName: string) => void;
handleBatchClear: () => void;
handleBatchDeleteTables: () => void;
handleBatchExport: (mode: 'schema' | 'dataOnly' | 'backup') => void;
handleCheckAll: (checked: boolean) => void;
handleInvertSelection: () => void;
@@ -66,6 +62,7 @@ type SidebarBatchExportModalsProps = {
setCheckedDbKeys: (keys: string[]) => void;
handleDbConnectionChange: (connectionId: string) => void;
handleBatchDbExport: (includeData: boolean) => void;
handleBatchDbDelete: () => void;
handleCheckAllDb: (checked: boolean) => void;
handleInvertSelectionDb: () => void;
};
@@ -102,6 +99,7 @@ export const SidebarBatchExportModals: React.FC<SidebarBatchExportModalsProps> =
handleConnectionChange,
handleDatabaseChange,
handleBatchClear,
handleBatchDeleteTables,
handleBatchExport,
handleCheckAll,
handleInvertSelection,
@@ -113,9 +111,13 @@ export const SidebarBatchExportModals: React.FC<SidebarBatchExportModalsProps> =
setCheckedDbKeys,
handleDbConnectionChange,
handleBatchDbExport,
handleBatchDbDelete,
handleCheckAllDb,
handleInvertSelectionDb,
}) => (
}) => {
const selectedTableCount = batchTables.filter(item => checkedTableKeys.includes(item.key) && item.objectType === 'table').length;
return (
<>
<Modal
title={tableModalTitle}
@@ -130,6 +132,15 @@ export const SidebarBatchExportModals: React.FC<SidebarBatchExportModalsProps> =
{t('sidebar.action.cancel')}
</Button>
<Space size={8} wrap style={{ marginLeft: 'auto' }}>
<Button
key="delete-tables"
danger
icon={<DeleteOutlined />}
onClick={() => handleBatchDeleteTables()}
disabled={selectedTableCount === 0}
>
{t('sidebar.action.delete_tables')}
</Button>
<Button
key="clear"
danger
@@ -340,6 +351,15 @@ export const SidebarBatchExportModals: React.FC<SidebarBatchExportModalsProps> =
<Button key="cancel" onClick={() => setIsBatchDbModalOpen(false)}>
{t('sidebar.action.cancel')}
</Button>,
<Button
key="delete-databases"
danger
icon={<DeleteOutlined />}
onClick={() => handleBatchDbDelete()}
disabled={checkedDbKeys.length === 0}
>
{t('sidebar.action.delete_database_count', { count: checkedDbKeys.length })}
</Button>,
<Button
key="export-schema"
icon={<ExportOutlined />}
@@ -430,4 +450,5 @@ export const SidebarBatchExportModals: React.FC<SidebarBatchExportModalsProps> =
)}
</Modal>
</>
);
);
};

View File

@@ -1,7 +1,7 @@
import { useEffect, useMemo, useState, type MutableRefObject } from 'react';
import { Modal, message } from 'antd';
import { DBGetDatabases, DBGetTables } from '../../../wailsjs/go/app/App';
import { DBGetDatabases, DBGetTables, DropDatabase, DropTable } from '../../../wailsjs/go/app/App';
import type { SavedConnection } from '../../types';
import { t } from '../../i18n';
import { buildRpcConnectionConfig } from '../../utils/connectionRpcConfig';
@@ -25,6 +25,7 @@ export type BatchSelectionScope = 'filtered' | 'all';
export interface BatchObjectItem {
title: string;
key: string;
dbName?: string;
objectName: string;
objectType: BatchObjectType;
dataRef: any;
@@ -510,6 +511,86 @@ export const useSidebarBatchExport = ({
}
};
const handleBatchDeleteTables = async () => {
const selectedTables = batchTables.filter(item => checkedTableKeys.includes(item.key) && item.objectType === 'table');
if (selectedTables.length === 0) {
message.warning(t('sidebar.message.select_table_required'));
return;
}
const { conn, dbName } = batchDbContext || {};
if (!conn || !dbName) {
message.warning(t('sidebar.message.select_connection_or_database_first'));
return;
}
const tableNames = selectedTables.map(t => t.objectName);
const ok = await new Promise<boolean>((resolve) => {
Modal.confirm({
title: t('sidebar.modal.confirm_delete_selected_tables.title'),
content: t('sidebar.modal.confirm_delete_selected_tables.content', {
connection: conn.name,
database: dbName,
count: tableNames.length,
}),
okText: t('sidebar.action.delete'),
okButtonProps: { danger: true },
cancelText: t('sidebar.action.cancel'),
onOk: () => resolve(true),
onCancel: () => resolve(false),
});
});
if (!ok) return;
setIsBatchModalOpen(false);
const hide = message.loading(t('sidebar.message.deleting_selected_tables', { count: tableNames.length }), 0);
const startTime = Date.now();
const successKeys: string[] = [];
let failed: { table: string; error: string } | null = null;
try {
for (const item of selectedTables) {
const res = await DropTable(normalizeConnConfig(conn.config) as any, dbName, item.objectName);
if (!res.success) {
failed = { table: item.objectName, error: res.message || t('common.unknown') };
break;
}
successKeys.push(item.key);
}
} catch (e: any) {
failed = { table: tableNames[successKeys.length] || tableNames[0], error: e?.message || String(e) };
} finally {
hide();
}
if (successKeys.length > 0) {
const successKeySet = new Set(successKeys);
setBatchTables(prev => prev.filter(item => !successKeySet.has(item.key)));
setCheckedTableKeys(prev => prev.filter(key => !successKeySet.has(key)));
}
const duration = Date.now() - startTime;
const logSql = `/* Drop Tables (${tableNames.length} tables) */\n${tableNames.map(name => `DROP TABLE ${name}`).join(';\n')};`;
addSqlLog({
id: Date.now().toString(),
timestamp: Date.now(),
sql: logSql,
status: failed ? 'error' : 'success',
duration,
message: failed ? failed.error : t('sidebar.message.delete_tables_success', { count: successKeys.length }),
dbName,
affectedRows: successKeys.length,
});
if (failed) {
message.error(t('sidebar.message.delete_tables_failed', {
table: failed.table,
error: failed.error,
}));
return;
}
message.success(t('sidebar.message.delete_tables_success', { count: successKeys.length }));
};
const handleCheckAll = (checked: boolean) => {
if (batchSelectionScope === 'all') {
setCheckedTableKeys(checked ? allBatchObjectKeys : []);
@@ -678,6 +759,81 @@ export const useSidebarBatchExport = ({
}
};
const handleBatchDbDelete = async () => {
const selectedDbs = batchDatabases.filter(db => checkedDbKeys.includes(db.key));
if (selectedDbs.length === 0) {
message.warning(t('sidebar.message.select_database_required'));
return;
}
if (!batchConnContext?.config) {
message.warning(t('sidebar.message.select_connection_or_database_first'));
return;
}
const ok = await new Promise<boolean>((resolve) => {
Modal.confirm({
title: t('sidebar.modal.confirm_delete_selected_databases.title'),
content: t('sidebar.modal.confirm_delete_selected_databases.content', {
connection: batchConnContext.name,
count: selectedDbs.length,
}),
okText: t('sidebar.action.delete'),
okButtonProps: { danger: true },
cancelText: t('sidebar.action.cancel'),
onOk: () => resolve(true),
onCancel: () => resolve(false),
});
});
if (!ok) return;
setIsBatchDbModalOpen(false);
const hide = message.loading(t('sidebar.message.deleting_selected_databases', { count: selectedDbs.length }), 0);
const startTime = Date.now();
const successKeys: string[] = [];
let failed: { database: string; error: string } | null = null;
try {
for (const dbItem of selectedDbs) {
const res = await DropDatabase(normalizeConnConfig(batchConnContext.config) as any, dbItem.dbName);
if (!res.success) {
failed = { database: dbItem.dbName, error: res.message || t('common.unknown') };
break;
}
successKeys.push(dbItem.key);
}
} catch (e: any) {
failed = { database: selectedDbs[successKeys.length]?.dbName || selectedDbs[0]?.dbName || '', error: e?.message || String(e) };
} finally {
hide();
}
if (successKeys.length > 0) {
const successKeySet = new Set(successKeys);
setBatchDatabases(prev => prev.filter(item => !successKeySet.has(item.key)));
setCheckedDbKeys(prev => prev.filter(key => !successKeySet.has(key)));
}
const duration = Date.now() - startTime;
const dbNames = selectedDbs.map(db => db.dbName);
addSqlLog({
id: Date.now().toString(),
timestamp: Date.now(),
sql: `/* Drop Databases (${dbNames.length} databases) */\n${dbNames.map(name => `DROP DATABASE ${name}`).join(';\n')};`,
status: failed ? 'error' : 'success',
duration,
message: failed ? failed.error : t('sidebar.message.delete_databases_success', { count: successKeys.length }),
affectedRows: successKeys.length,
});
if (failed) {
message.error(t('sidebar.message.delete_databases_failed', {
database: failed.database,
error: failed.error,
}));
return;
}
message.success(t('sidebar.message.delete_databases_success', { count: successKeys.length }));
};
const handleCheckAllDb = (checked: boolean) => {
if (checked) {
setCheckedDbKeys(batchDatabases.map(db => db.key));
@@ -724,12 +880,14 @@ export const useSidebarBatchExport = ({
handleDatabaseChange,
handleBatchExport,
handleBatchClear,
handleBatchDeleteTables,
handleCheckAll,
handleInvertSelection,
openBatchDatabaseModal,
openBatchDatabaseExportWorkbench,
handleDbConnectionChange,
handleBatchDbExport,
handleBatchDbDelete,
handleCheckAllDb,
handleInvertSelectionDb,
};

View File

@@ -6594,6 +6594,8 @@
"sidebar.action.close": "Schließen",
"sidebar.action.continue": "Fortfahren",
"sidebar.action.delete": "Löschen",
"sidebar.action.delete_database_count": "Datenbanken löschen ({{count}})",
"sidebar.action.delete_tables": "Tabellen löschen",
"sidebar.action.export_data_only": "Nur Daten (INSERT)",
"sidebar.action.export_database_schema_count": "Datenbankstrukturen exportieren ({{count}})",
"sidebar.action.export_schema": "Struktur exportieren",
@@ -6828,9 +6830,15 @@
"sidebar.message.database_renamed": "Datenbank umbenannt.",
"sidebar.message.delete_connection_backend_unavailable": "Verbindungen können in diesem Build nicht gelöscht werden.",
"sidebar.message.delete_connection_failed": "Verbindung konnte nicht gelöscht werden.",
"sidebar.message.delete_databases_failed": "Datenbank {{database}} konnte nicht gelöscht werden: {{error}}",
"sidebar.message.delete_databases_success": "{{count}} Datenbanken gelöscht.",
"sidebar.message.delete_failed": "Löschen fehlgeschlagen: {{error}}",
"sidebar.message.delete_sql_directory_failed": "SQL-Verzeichnis konnte nicht gelöscht werden: {{error}}",
"sidebar.message.delete_sql_file_failed": "SQL-Datei konnte nicht gelöscht werden: {{error}}",
"sidebar.message.delete_tables_failed": "Tabelle {{table}} konnte nicht gelöscht werden: {{error}}",
"sidebar.message.delete_tables_success": "{{count}} Tabellen gelöscht.",
"sidebar.message.deleting_selected_databases": "{{count}} ausgewählte Datenbanken werden gelöscht...",
"sidebar.message.deleting_selected_tables": "{{count}} ausgewählte Tabellen werden gelöscht...",
"sidebar.message.disconnected": "Getrennt.",
"sidebar.message.duplicate_backend_unavailable": "Das Duplizieren von Verbindungen ist in diesem Build nicht verfügbar.",
"sidebar.message.duplicate_empty_result": "Die duplizierte Verbindung wurde nicht zurückgegeben.",
@@ -6914,6 +6922,7 @@
"sidebar.message.select_database_required": "Wählen Sie mindestens eine Datenbank aus.",
"sidebar.message.select_host_before_large_sql_file": "Wählen Sie einen Host aus, bevor Sie eine große SQL-Datei ausführen.",
"sidebar.message.select_object_required": "Wählen Sie mindestens ein Objekt aus.",
"sidebar.message.select_table_required": "Wählen Sie mindestens eine Tabelle aus.",
"sidebar.message.select_sql_directory_failed": "SQL-Verzeichnis konnte nicht ausgewählt werden: {{error}}",
"sidebar.message.sidebar_filter_reset": "Seitenleistenfilter zurückgesetzt.",
"sidebar.message.sidebar_filter_sync_disabled": "Synchronisierung des linken Filters deaktiviert.",
@@ -6954,6 +6963,10 @@
"sidebar.modal.batch_tables.title": "Stapeloperationen für Objekte",
"sidebar.modal.confirm_clear_selected_tables.content": "Daten der ausgewählten Objekte unter {{connection}} / {{database}} leeren? Dies kann nicht rückgängig gemacht werden.",
"sidebar.modal.confirm_clear_selected_tables.title": "Ausgewählte Tabellen leeren",
"sidebar.modal.confirm_delete_selected_databases.content": "{{count}} ausgewählte Datenbanken unter {{connection}} löschen? Dies kann nicht rückgängig gemacht werden.",
"sidebar.modal.confirm_delete_selected_databases.title": "Ausgewählte Datenbanken löschen",
"sidebar.modal.confirm_delete_selected_tables.content": "{{count}} ausgewählte Tabellen unter {{connection}} / {{database}} löschen? Dies kann nicht rückgängig gemacht werden.",
"sidebar.modal.confirm_delete_selected_tables.title": "Ausgewählte Tabellen löschen",
"sidebar.modal.confirm_delete_connection.content": "{{name}} löschen?",
"sidebar.modal.confirm_delete_database.content": "{{name}} löschen? Dies kann nicht rückgängig gemacht werden.",
"sidebar.modal.confirm_delete_database.title": "Datenbank löschen",

View File

@@ -6594,6 +6594,8 @@
"sidebar.action.close": "Close",
"sidebar.action.continue": "Continue",
"sidebar.action.delete": "Delete",
"sidebar.action.delete_database_count": "Delete databases ({{count}})",
"sidebar.action.delete_tables": "Delete tables",
"sidebar.action.export_data_only": "Data only (INSERT)",
"sidebar.action.export_database_schema_count": "Export database schemas ({{count}})",
"sidebar.action.export_schema": "Export schema",
@@ -6828,9 +6830,15 @@
"sidebar.message.database_renamed": "Database renamed.",
"sidebar.message.delete_connection_backend_unavailable": "Delete connection is not available in this build.",
"sidebar.message.delete_connection_failed": "Failed to delete connection.",
"sidebar.message.delete_databases_failed": "Failed to delete database {{database}}: {{error}}",
"sidebar.message.delete_databases_success": "Deleted {{count}} databases.",
"sidebar.message.delete_failed": "Delete failed: {{error}}",
"sidebar.message.delete_sql_directory_failed": "Failed to delete SQL directory: {{error}}",
"sidebar.message.delete_sql_file_failed": "Failed to delete SQL file: {{error}}",
"sidebar.message.delete_tables_failed": "Failed to delete table {{table}}: {{error}}",
"sidebar.message.delete_tables_success": "Deleted {{count}} tables.",
"sidebar.message.deleting_selected_databases": "Deleting {{count}} selected databases...",
"sidebar.message.deleting_selected_tables": "Deleting {{count}} selected tables...",
"sidebar.message.disconnected": "Disconnected.",
"sidebar.message.duplicate_backend_unavailable": "Duplicate connection is not available in this build.",
"sidebar.message.duplicate_empty_result": "The duplicated connection was not returned.",
@@ -6914,6 +6922,7 @@
"sidebar.message.select_database_required": "Select at least one database.",
"sidebar.message.select_host_before_large_sql_file": "Select a Host before running a large SQL file.",
"sidebar.message.select_object_required": "Select at least one object.",
"sidebar.message.select_table_required": "Select at least one table.",
"sidebar.message.select_sql_directory_failed": "Failed to select SQL directory: {{error}}",
"sidebar.message.sidebar_filter_reset": "Sidebar filter reset.",
"sidebar.message.sidebar_filter_sync_disabled": "Left-side filter sync disabled.",
@@ -6954,6 +6963,10 @@
"sidebar.modal.batch_tables.title": "Batch object operations",
"sidebar.modal.confirm_clear_selected_tables.content": "Clear data in selected objects under {{connection}} / {{database}}? This cannot be undone.",
"sidebar.modal.confirm_clear_selected_tables.title": "Confirm clear selected tables",
"sidebar.modal.confirm_delete_selected_databases.content": "Delete {{count}} selected databases under {{connection}}? This cannot be undone.",
"sidebar.modal.confirm_delete_selected_databases.title": "Confirm delete selected databases",
"sidebar.modal.confirm_delete_selected_tables.content": "Delete {{count}} selected tables under {{connection}} / {{database}}? This cannot be undone.",
"sidebar.modal.confirm_delete_selected_tables.title": "Confirm delete selected tables",
"sidebar.modal.confirm_delete_connection.content": "Delete {{name}}?",
"sidebar.modal.confirm_delete_database.content": "Delete {{name}}? This cannot be undone.",
"sidebar.modal.confirm_delete_database.title": "Delete database",

View File

@@ -6594,6 +6594,8 @@
"sidebar.action.close": "閉じる",
"sidebar.action.continue": "続行",
"sidebar.action.delete": "削除",
"sidebar.action.delete_database_count": "データベースを削除({{count}}",
"sidebar.action.delete_tables": "テーブルを削除",
"sidebar.action.export_data_only": "データのみINSERT",
"sidebar.action.export_database_schema_count": "データベース構造をエクスポート({{count}}",
"sidebar.action.export_schema": "構造をエクスポート",
@@ -6828,9 +6830,15 @@
"sidebar.message.database_renamed": "データベース名を変更しました。",
"sidebar.message.delete_connection_backend_unavailable": "このビルドでは接続の削除を利用できません。",
"sidebar.message.delete_connection_failed": "接続の削除に失敗しました。",
"sidebar.message.delete_databases_failed": "データベース {{database}} の削除に失敗しました: {{error}}",
"sidebar.message.delete_databases_success": "{{count}} 件のデータベースを削除しました。",
"sidebar.message.delete_failed": "削除に失敗しました: {{error}}",
"sidebar.message.delete_sql_directory_failed": "SQL ディレクトリの削除に失敗しました:{{error}}",
"sidebar.message.delete_sql_file_failed": "SQL ファイルの削除に失敗しました:{{error}}",
"sidebar.message.delete_tables_failed": "テーブル {{table}} の削除に失敗しました: {{error}}",
"sidebar.message.delete_tables_success": "{{count}} 件のテーブルを削除しました。",
"sidebar.message.deleting_selected_databases": "選択した {{count}} 件のデータベースを削除しています...",
"sidebar.message.deleting_selected_tables": "選択した {{count}} 件のテーブルを削除しています...",
"sidebar.message.disconnected": "切断しました。",
"sidebar.message.duplicate_backend_unavailable": "このビルドでは接続の複製を利用できません。",
"sidebar.message.duplicate_empty_result": "複製された接続が返されませんでした。",
@@ -6914,6 +6922,7 @@
"sidebar.message.select_database_required": "データベースを 1 件以上選択してください。",
"sidebar.message.select_host_before_large_sql_file": "大きな SQL ファイルを実行する前に Host を選択してください。",
"sidebar.message.select_object_required": "オブジェクトを 1 件以上選択してください。",
"sidebar.message.select_table_required": "テーブルを 1 件以上選択してください。",
"sidebar.message.select_sql_directory_failed": "SQL ディレクトリの選択に失敗しました: {{error}}",
"sidebar.message.sidebar_filter_reset": "サイドバーフィルターをリセットしました。",
"sidebar.message.sidebar_filter_sync_disabled": "左側フィルターの同期を無効にしました。",
@@ -6954,6 +6963,10 @@
"sidebar.modal.batch_tables.title": "オブジェクト一括操作",
"sidebar.modal.confirm_clear_selected_tables.content": "{{connection}} / {{database}} の選択したオブジェクトのデータをクリアしますか?この操作は元に戻せません。",
"sidebar.modal.confirm_clear_selected_tables.title": "選択したテーブルのクリアを確認",
"sidebar.modal.confirm_delete_selected_databases.content": "{{connection}} 配下の選択した {{count}} 件のデータベースを削除しますか?この操作は元に戻せません。",
"sidebar.modal.confirm_delete_selected_databases.title": "選択したデータベースの削除を確認",
"sidebar.modal.confirm_delete_selected_tables.content": "{{connection}} / {{database}} 配下の選択した {{count}} 件のテーブルを削除しますか?この操作は元に戻せません。",
"sidebar.modal.confirm_delete_selected_tables.title": "選択したテーブルの削除を確認",
"sidebar.modal.confirm_delete_connection.content": "接続 {{name}} を削除しますか?",
"sidebar.modal.confirm_delete_database.content": "{{name}} を削除しますか?この操作は元に戻せません。",
"sidebar.modal.confirm_delete_database.title": "データベースを削除",

View File

@@ -6594,6 +6594,8 @@
"sidebar.action.close": "Закрыть",
"sidebar.action.continue": "Продолжить",
"sidebar.action.delete": "Удалить",
"sidebar.action.delete_database_count": "Удалить базы данных ({{count}})",
"sidebar.action.delete_tables": "Удалить таблицы",
"sidebar.action.export_data_only": "Только данные (INSERT)",
"sidebar.action.export_database_schema_count": "Экспортировать структуры баз данных ({{count}})",
"sidebar.action.export_schema": "Экспортировать структуру",
@@ -6828,9 +6830,15 @@
"sidebar.message.database_renamed": "База данных переименована.",
"sidebar.message.delete_connection_backend_unavailable": "Удаление подключений недоступно в этой сборке.",
"sidebar.message.delete_connection_failed": "Не удалось удалить подключение.",
"sidebar.message.delete_databases_failed": "Не удалось удалить базу данных {{database}}: {{error}}",
"sidebar.message.delete_databases_success": "Удалено баз данных: {{count}}.",
"sidebar.message.delete_failed": "Не удалось удалить: {{error}}",
"sidebar.message.delete_sql_directory_failed": "Не удалось удалить SQL-каталог: {{error}}",
"sidebar.message.delete_sql_file_failed": "Не удалось удалить SQL-файл: {{error}}",
"sidebar.message.delete_tables_failed": "Не удалось удалить таблицу {{table}}: {{error}}",
"sidebar.message.delete_tables_success": "Удалено таблиц: {{count}}.",
"sidebar.message.deleting_selected_databases": "Удаляются выбранные базы данных: {{count}}...",
"sidebar.message.deleting_selected_tables": "Удаляются выбранные таблицы: {{count}}...",
"sidebar.message.disconnected": "Отключено.",
"sidebar.message.duplicate_backend_unavailable": "Дублирование подключений недоступно в этой сборке.",
"sidebar.message.duplicate_empty_result": "Дублированное подключение не было возвращено.",
@@ -6914,6 +6922,7 @@
"sidebar.message.select_database_required": "Выберите хотя бы одну базу данных.",
"sidebar.message.select_host_before_large_sql_file": "Выберите Host перед запуском большого SQL-файла.",
"sidebar.message.select_object_required": "Выберите хотя бы один объект.",
"sidebar.message.select_table_required": "Выберите хотя бы одну таблицу.",
"sidebar.message.select_sql_directory_failed": "Не удалось выбрать SQL-каталог: {{error}}",
"sidebar.message.sidebar_filter_reset": "Фильтр боковой панели сброшен.",
"sidebar.message.sidebar_filter_sync_disabled": "Синхронизация левого фильтра отключена.",
@@ -6954,6 +6963,10 @@
"sidebar.modal.batch_tables.title": "Пакетные операции с объектами",
"sidebar.modal.confirm_clear_selected_tables.content": "Очистить данные выбранных объектов в {{connection}} / {{database}}? Это действие нельзя отменить.",
"sidebar.modal.confirm_clear_selected_tables.title": "Подтвердите очистку выбранных таблиц",
"sidebar.modal.confirm_delete_selected_databases.content": "Удалить выбранные базы данных ({{count}}) в {{connection}}? Это действие нельзя отменить.",
"sidebar.modal.confirm_delete_selected_databases.title": "Подтвердите удаление выбранных баз данных",
"sidebar.modal.confirm_delete_selected_tables.content": "Удалить выбранные таблицы ({{count}}) в {{connection}} / {{database}}? Это действие нельзя отменить.",
"sidebar.modal.confirm_delete_selected_tables.title": "Подтвердите удаление выбранных таблиц",
"sidebar.modal.confirm_delete_connection.content": "Удалить {{name}}?",
"sidebar.modal.confirm_delete_database.content": "Удалить {{name}}? Это действие нельзя отменить.",
"sidebar.modal.confirm_delete_database.title": "Удалить базу данных",

View File

@@ -6594,6 +6594,8 @@
"sidebar.action.close": "关闭",
"sidebar.action.continue": "继续",
"sidebar.action.delete": "删除",
"sidebar.action.delete_database_count": "删除库({{count}}",
"sidebar.action.delete_tables": "删除表",
"sidebar.action.export_data_only": "仅数据INSERT",
"sidebar.action.export_database_schema_count": "导出库结构({{count}}",
"sidebar.action.export_schema": "导出结构",
@@ -6828,9 +6830,15 @@
"sidebar.message.database_renamed": "数据库已重命名。",
"sidebar.message.delete_connection_backend_unavailable": "删除连接后端不可用。",
"sidebar.message.delete_connection_failed": "删除连接失败。",
"sidebar.message.delete_databases_failed": "删除库 {{database}} 失败:{{error}}",
"sidebar.message.delete_databases_success": "已删除 {{count}} 个库。",
"sidebar.message.delete_failed": "删除失败:{{error}}",
"sidebar.message.delete_sql_directory_failed": "删除 SQL 目录失败:{{error}}",
"sidebar.message.delete_sql_file_failed": "删除 SQL 文件失败:{{error}}",
"sidebar.message.delete_tables_failed": "删除表 {{table}} 失败:{{error}}",
"sidebar.message.delete_tables_success": "已删除 {{count}} 张表。",
"sidebar.message.deleting_selected_databases": "正在删除 {{count}} 个已选库...",
"sidebar.message.deleting_selected_tables": "正在删除 {{count}} 张已选表...",
"sidebar.message.disconnected": "已断开。",
"sidebar.message.duplicate_backend_unavailable": "当前版本不支持复制连接。",
"sidebar.message.duplicate_empty_result": "未返回复制后的连接。",
@@ -6914,6 +6922,7 @@
"sidebar.message.select_database_required": "请至少选择一个数据库。",
"sidebar.message.select_host_before_large_sql_file": "请先选择一个 Host 后再执行大 SQL 文件。",
"sidebar.message.select_object_required": "请至少选择一个对象。",
"sidebar.message.select_table_required": "请至少选择一张表。",
"sidebar.message.select_sql_directory_failed": "选择 SQL 目录失败:{{error}}",
"sidebar.message.sidebar_filter_reset": "已重置侧栏筛选。",
"sidebar.message.sidebar_filter_sync_disabled": "已关闭左侧筛选同步。",
@@ -6954,6 +6963,10 @@
"sidebar.modal.batch_tables.title": "批量操作表",
"sidebar.modal.confirm_clear_selected_tables.content": "清空 {{connection}} / {{database}} 下已选对象的数据?此操作不可撤销。",
"sidebar.modal.confirm_clear_selected_tables.title": "确认清空已选表",
"sidebar.modal.confirm_delete_selected_databases.content": "删除 {{connection}} 下 {{count}} 个已选库?此操作不可撤销。",
"sidebar.modal.confirm_delete_selected_databases.title": "确认删除已选库",
"sidebar.modal.confirm_delete_selected_tables.content": "删除 {{connection}} / {{database}} 下 {{count}} 张已选表?此操作不可撤销。",
"sidebar.modal.confirm_delete_selected_tables.title": "确认删除已选表",
"sidebar.modal.confirm_delete_connection.content": "删除连接 {{name}}",
"sidebar.modal.confirm_delete_database.content": "删除 {{name}}?此操作不可撤销。",
"sidebar.modal.confirm_delete_database.title": "删除数据库",

View File

@@ -6594,6 +6594,8 @@
"sidebar.action.close": "關閉",
"sidebar.action.continue": "繼續",
"sidebar.action.delete": "刪除",
"sidebar.action.delete_database_count": "刪除資料庫({{count}}",
"sidebar.action.delete_tables": "刪除資料表",
"sidebar.action.export_data_only": "僅資料INSERT",
"sidebar.action.export_database_schema_count": "匯出資料庫結構({{count}}",
"sidebar.action.export_schema": "匯出結構",
@@ -6828,9 +6830,15 @@
"sidebar.message.database_renamed": "資料庫已重新命名。",
"sidebar.message.delete_connection_backend_unavailable": "刪除連線後端不可用。",
"sidebar.message.delete_connection_failed": "刪除連線失敗。",
"sidebar.message.delete_databases_failed": "刪除資料庫 {{database}} 失敗:{{error}}",
"sidebar.message.delete_databases_success": "已刪除 {{count}} 個資料庫。",
"sidebar.message.delete_failed": "刪除失敗:{{error}}",
"sidebar.message.delete_sql_directory_failed": "刪除 SQL 目錄失敗:{{error}}",
"sidebar.message.delete_sql_file_failed": "刪除 SQL 檔案失敗:{{error}}",
"sidebar.message.delete_tables_failed": "刪除資料表 {{table}} 失敗:{{error}}",
"sidebar.message.delete_tables_success": "已刪除 {{count}} 張資料表。",
"sidebar.message.deleting_selected_databases": "正在刪除 {{count}} 個已選資料庫...",
"sidebar.message.deleting_selected_tables": "正在刪除 {{count}} 張已選資料表...",
"sidebar.message.disconnected": "已中斷。",
"sidebar.message.duplicate_backend_unavailable": "目前版本不支援複製連線。",
"sidebar.message.duplicate_empty_result": "未傳回複製後的連線。",
@@ -6914,6 +6922,7 @@
"sidebar.message.select_database_required": "請至少選擇一個資料庫。",
"sidebar.message.select_host_before_large_sql_file": "請先選擇 Host再執行大型 SQL 檔案。",
"sidebar.message.select_object_required": "請至少選擇一個物件。",
"sidebar.message.select_table_required": "請至少選擇一張資料表。",
"sidebar.message.select_sql_directory_failed": "選擇 SQL 目錄失敗:{{error}}",
"sidebar.message.sidebar_filter_reset": "已重設側欄篩選。",
"sidebar.message.sidebar_filter_sync_disabled": "已關閉左側篩選同步。",
@@ -6954,6 +6963,10 @@
"sidebar.modal.batch_tables.title": "批次操作資料表",
"sidebar.modal.confirm_clear_selected_tables.content": "清除 {{connection}} / {{database}} 下已選物件的資料?此操作無法復原。",
"sidebar.modal.confirm_clear_selected_tables.title": "確認清除已選資料表",
"sidebar.modal.confirm_delete_selected_databases.content": "刪除 {{connection}} 下 {{count}} 個已選資料庫?此操作無法復原。",
"sidebar.modal.confirm_delete_selected_databases.title": "確認刪除已選資料庫",
"sidebar.modal.confirm_delete_selected_tables.content": "刪除 {{connection}} / {{database}} 下 {{count}} 張已選資料表?此操作無法復原。",
"sidebar.modal.confirm_delete_selected_tables.title": "確認刪除已選資料表",
"sidebar.modal.confirm_delete_connection.content": "刪除連線 {{name}}",
"sidebar.modal.confirm_delete_database.content": "刪除 {{name}}?此操作無法復原。",
"sidebar.modal.confirm_delete_database.title": "刪除資料庫",