mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-08 20:41:38 +08:00
🐛 fix(sidebar): 恢复批量库表危险操作
- 恢复批量表和批量库按钮到原批量操作弹窗\n- 补回批量删除表和删除库的危险确认与执行逻辑\n- 删除表仅处理 table 对象,避免视图误走 DropTable\n- 补齐多语言文案与入口/删除回归测试
This commit is contained in:
@@ -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"');
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
|
||||
@@ -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([]);
|
||||
|
||||
@@ -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']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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": "データベースを削除",
|
||||
|
||||
@@ -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": "Удалить базу данных",
|
||||
|
||||
@@ -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": "删除数据库",
|
||||
|
||||
@@ -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": "刪除資料庫",
|
||||
|
||||
Reference in New Issue
Block a user