diff --git a/frontend/src/components/Sidebar.locate-toolbar.test.tsx b/frontend/src/components/Sidebar.locate-toolbar.test.tsx
index 94b0694..06b19dd 100644
--- a/frontend/src/components/Sidebar.locate-toolbar.test.tsx
+++ b/frontend/src/components/Sidebar.locate-toolbar.test.tsx
@@ -762,6 +762,31 @@ describe('Sidebar locate toolbar', () => {
expect(markup).toContain('删除连接');
});
+ it('omits unsupported database management actions for Oracle-like connection and database menus', () => {
+ const connectionMarkup = renderToStaticMarkup(
+ ,
+ );
+ const databaseMarkup = renderToStaticMarkup(
+ ,
+ );
+
+ expect(connectionMarkup).not.toContain('新建数据库');
+ expect(databaseMarkup).not.toContain('重命名数据库');
+ expect(databaseMarkup).not.toContain('删除数据库 · DROP');
+ expect(databaseMarkup).toContain('刷新对象树');
+ expect(databaseMarkup).toContain('关闭数据库');
+ });
+
it('renders the v2 table group menu with sort state', () => {
const markup = renderToStaticMarkup(
{
const dialect = getMetadataDialect(node.dataRef as SavedConnection);
+ const capabilities = getDataSourceCapabilities((node.dataRef as SavedConnection)?.config);
return (
{
setContextMenu(null);
handleV2DatabaseContextMenuAction(node, action);
@@ -5438,6 +5442,7 @@ const Sidebar: React.FC<{
const renderV2ConnectionContextMenu = (node: any) => {
const conn = node.dataRef as SavedConnection;
+ const capabilities = getDataSourceCapabilities(conn?.config);
const currentTagId = connectionTags.find((tag) => tag.connectionIds.includes(String(conn.id || node.key)))?.id || '';
return (
({
id: tag.id,
name: tag.name,
@@ -6056,8 +6062,9 @@ const Sidebar: React.FC<{
});
// Regular database connection menu
+ const connectionCapabilities = getDataSourceCapabilities((node.dataRef as SavedConnection)?.config);
return [
- {
+ ...(connectionCapabilities.supportsCreateDatabase ? [{
key: 'new-db',
label: '新建数据库',
icon: ,
@@ -6065,7 +6072,7 @@ const Sidebar: React.FC<{
setTargetConnection(node);
setIsCreateDbModalOpen(true);
}
- },
+ }] : []),
{
key: 'refresh',
label: '刷新',
@@ -6235,8 +6242,11 @@ const Sidebar: React.FC<{
}
];
} else if (node.type === 'database') {
- const isStarRocks = getMetadataDialect(node.dataRef as SavedConnection) === 'starrocks';
- const supportsSchemaActions = isPostgresSchemaDialect(getMetadataDialect(node.dataRef as SavedConnection));
+ const databaseConn = node.dataRef as SavedConnection;
+ const dialect = getMetadataDialect(databaseConn);
+ const capabilities = getDataSourceCapabilities(databaseConn?.config);
+ const isStarRocks = dialect === 'starrocks';
+ const supportsSchemaActions = isPostgresSchemaDialect(dialect);
return [
{
key: 'new-table',
@@ -6266,13 +6276,13 @@ const Sidebar: React.FC<{
onClick: () => openCreateStarRocksExternalCatalog(node)
},
] : []),
- {
+ ...(capabilities.supportsRenameDatabase ? [{
key: 'rename-db',
label: '重命名数据库',
icon: ,
onClick: () => handleV2DatabaseContextMenuAction(node, 'rename-db')
- },
- {
+ }] : []),
+ ...(capabilities.supportsDropDatabase ? [{
key: 'danger-zone',
label: '危险操作',
icon: ,
@@ -6285,7 +6295,7 @@ const Sidebar: React.FC<{
onClick: () => handleV2DatabaseContextMenuAction(node, 'drop-db')
}
]
- },
+ }] : []),
{
key: 'refresh',
label: '刷新',
diff --git a/frontend/src/components/V2TableContextMenu.tsx b/frontend/src/components/V2TableContextMenu.tsx
index 8fd19cc..5f8465d 100644
--- a/frontend/src/components/V2TableContextMenu.tsx
+++ b/frontend/src/components/V2TableContextMenu.tsx
@@ -304,12 +304,16 @@ export const V2DatabaseContextMenuView: React.FC<{
dialect?: string;
supportsSchemaActions?: boolean;
supportsStarRocksActions?: boolean;
+ supportsRenameDatabase?: boolean;
+ supportsDropDatabase?: boolean;
onAction?: (action: V2DatabaseContextMenuActionKey) => void;
}> = ({
dbName,
dialect,
supportsSchemaActions = false,
supportsStarRocksActions = false,
+ supportsRenameDatabase = true,
+ supportsDropDatabase = true,
onAction,
}) => {
const renderItems = (items: V2TableContextMenuItemConfig[]) => renderV2ContextMenuItems(
@@ -346,7 +350,7 @@ export const V2DatabaseContextMenuView: React.FC<{
维护
{renderItems([
- { action: 'rename-db', icon: , title: '重命名数据库', kbd: 'F2' },
+ ...(supportsRenameDatabase ? [{ action: 'rename-db', icon: , title: '重命名数据库', kbd: 'F2' }] : []),
{ action: 'refresh', icon: , title: '刷新对象树' },
{ action: 'disconnect-db', icon: , title: '关闭数据库' },
])}
@@ -358,7 +362,7 @@ export const V2DatabaseContextMenuView: React.FC<{
])}
- {renderItems([
+ {supportsDropDatabase && renderItems([
{ action: 'drop-db', icon: , title: '删除数据库 · DROP', tone: 'danger', kbd: '⌫' },
])}
@@ -431,6 +435,7 @@ export const V2ConnectionContextMenuView: React.FC<{
hostSummary?: string;
driverLabel?: string;
isRedis?: boolean;
+ supportsCreateDatabase?: boolean;
tags?: V2ConnectionContextMenuTagItem[];
onAction?: (action: V2ConnectionContextMenuActionKey) => void;
}> = ({
@@ -438,6 +443,7 @@ export const V2ConnectionContextMenuView: React.FC<{
hostSummary,
driverLabel,
isRedis = false,
+ supportsCreateDatabase = true,
tags = [],
onAction,
}) => {
@@ -466,7 +472,7 @@ export const V2ConnectionContextMenuView: React.FC<{
{ action: 'new-command', icon: , title: '新建命令窗口', featured: true },
{ action: 'open-monitor', icon: , title: 'Redis 实例监控' },
]) : renderItems([
- { action: 'new-db', icon: , title: '新建数据库', kbd: '⌘N', featured: true },
+ ...(supportsCreateDatabase ? [{ action: 'new-db' as const, icon: , title: '新建数据库', kbd: '⌘N', featured: true }] : []),
{ action: 'refresh', icon: , title: '刷新连接', kbd: '⌘R' },
{ action: 'new-query', icon: , title: '新建查询' },
{ action: 'open-sql-file', icon: , title: '运行外部 SQL 文件' },
diff --git a/frontend/src/utils/dataSourceCapabilities.test.ts b/frontend/src/utils/dataSourceCapabilities.test.ts
index adea747..0dcee63 100644
--- a/frontend/src/utils/dataSourceCapabilities.test.ts
+++ b/frontend/src/utils/dataSourceCapabilities.test.ts
@@ -76,4 +76,28 @@ describe('dataSourceCapabilities', () => {
supportsApproximateTableCount: true,
});
});
+
+ it('hides database-level DDL actions for Dameng and Oracle-like datasources', () => {
+ expect(getDataSourceCapabilities({ type: 'dameng' })).toMatchObject({
+ type: 'dameng',
+ supportsCreateDatabase: false,
+ supportsRenameDatabase: false,
+ supportsDropDatabase: false,
+ });
+ expect(getDataSourceCapabilities({ type: 'oracle' })).toMatchObject({
+ type: 'oracle',
+ supportsCreateDatabase: false,
+ supportsRenameDatabase: false,
+ supportsDropDatabase: false,
+ });
+ expect(getDataSourceCapabilities({
+ type: 'oceanbase',
+ oceanBaseProtocol: 'oracle',
+ })).toMatchObject({
+ type: 'oracle',
+ supportsCreateDatabase: false,
+ supportsRenameDatabase: false,
+ supportsDropDatabase: false,
+ });
+ });
});
diff --git a/frontend/src/utils/dataSourceCapabilities.ts b/frontend/src/utils/dataSourceCapabilities.ts
index 5de93ba..a82a543 100644
--- a/frontend/src/utils/dataSourceCapabilities.ts
+++ b/frontend/src/utils/dataSourceCapabilities.ts
@@ -99,12 +99,55 @@ export type DataSourceCapabilities = {
supportsQueryEditor: boolean;
supportsSqlQueryExport: boolean;
supportsCopyInsert: boolean;
+ supportsCreateDatabase: boolean;
+ supportsRenameDatabase: boolean;
+ supportsDropDatabase: boolean;
forceReadOnlyQueryResult: boolean;
preferManualTotalCount: boolean;
supportsApproximateTableCount: boolean;
supportsApproximateTotalPages: boolean;
};
+const CREATE_DATABASE_TYPES = new Set([
+ 'mysql',
+ 'mariadb',
+ 'oceanbase',
+ 'diros',
+ 'starrocks',
+ 'postgres',
+ 'kingbase',
+ 'highgo',
+ 'vastbase',
+ 'opengauss',
+ 'sqlserver',
+ 'tdengine',
+ 'clickhouse',
+]);
+
+const RENAME_DATABASE_TYPES = new Set([
+ 'diros',
+ 'postgres',
+ 'kingbase',
+ 'highgo',
+ 'vastbase',
+ 'opengauss',
+]);
+
+const DROP_DATABASE_TYPES = new Set([
+ 'mysql',
+ 'mariadb',
+ 'oceanbase',
+ 'diros',
+ 'starrocks',
+ 'postgres',
+ 'kingbase',
+ 'highgo',
+ 'vastbase',
+ 'opengauss',
+ 'tdengine',
+ 'clickhouse',
+]);
+
export const getDataSourceCapabilities = (config: ConnectionLike): DataSourceCapabilities => {
const type = resolveDataSourceType(config);
return {
@@ -112,6 +155,9 @@ export const getDataSourceCapabilities = (config: ConnectionLike): DataSourceCap
supportsQueryEditor: !QUERY_EDITOR_DISABLED_TYPES.has(type),
supportsSqlQueryExport: SQL_QUERY_EXPORT_TYPES.has(type),
supportsCopyInsert: COPY_INSERT_TYPES.has(type),
+ supportsCreateDatabase: CREATE_DATABASE_TYPES.has(type),
+ supportsRenameDatabase: RENAME_DATABASE_TYPES.has(type),
+ supportsDropDatabase: DROP_DATABASE_TYPES.has(type),
forceReadOnlyQueryResult: FORCE_READ_ONLY_QUERY_TYPES.has(type),
preferManualTotalCount: MANUAL_TOTAL_COUNT_TYPES.has(type),
supportsApproximateTableCount: APPROXIMATE_TABLE_COUNT_TYPES.has(type),