diff --git a/packages/api/src/controllers/serverConnections.js b/packages/api/src/controllers/serverConnections.js index c99d28684..36a751ba9 100644 --- a/packages/api/src/controllers/serverConnections.js +++ b/packages/api/src/controllers/serverConnections.js @@ -197,4 +197,12 @@ module.exports = { testConnectionPermission(conid, req); return this.loadDataCore('serverSummary', { conid }); }, + + summaryCommand_meta: true, + async summaryCommand({ conid, command, row }, req) { + testConnectionPermission(conid, req); + const opened = await this.ensureOpened(conid); + if (opened.connection.isReadOnly) return false; + return this.loadDataCore('summaryCommand', { conid, command, row }); + }, }; diff --git a/packages/api/src/proc/serverConnectionProcess.js b/packages/api/src/proc/serverConnectionProcess.js index 175bb637b..c720b8889 100644 --- a/packages/api/src/proc/serverConnectionProcess.js +++ b/packages/api/src/proc/serverConnectionProcess.js @@ -118,14 +118,19 @@ async function handleDriverDataCore(msgid, callMethod) { } } -async function handleServerSummary({ msgid, options }) { +async function handleServerSummary({ msgid }) { return handleDriverDataCore(msgid, driver => driver.serverSummary(systemConnection)); } +async function handleSummaryCommand({ msgid, command, row }) { + return handleDriverDataCore(msgid, driver => driver.summaryCommand(systemConnection, command, row)); +} + const messageHandlers = { connect: handleConnect, ping: handlePing, serverSummary: handleServerSummary, + summaryCommand: handleSummaryCommand, createDatabase: props => handleDatabaseOp('createDatabase', props), dropDatabase: props => handleDatabaseOp('dropDatabase', props), }; diff --git a/packages/types/engines.d.ts b/packages/types/engines.d.ts index f0e0b8ddb..e2da64c8b 100644 --- a/packages/types/engines.d.ts +++ b/packages/types/engines.d.ts @@ -128,7 +128,8 @@ export interface EngineDriver { getNewObjectTemplates(): NewObjectTemplate[]; // direct call of pool method, only some methods could be supported, on only some drivers callMethod(pool, method, args); - loadSummary(pool): Promise; + serverSummary(pool): Promise; + summaryCommand(pool, command, row): Promise; analyserClass?: any; dumperClass?: any; diff --git a/packages/web/src/tabs/ServerSummaryTab.svelte b/packages/web/src/tabs/ServerSummaryTab.svelte index 90fe7a121..20dfca6d1 100644 --- a/packages/web/src/tabs/ServerSummaryTab.svelte +++ b/packages/web/src/tabs/ServerSummaryTab.svelte @@ -9,6 +9,11 @@ export let conid; let refreshToken = 0; + + async function callAction(command, row) { + await apiCall('server-connections/summary-command', { conid, refreshToken, command, row }); + refreshToken += 1; + } {#await apiCall('server-connections/server-summary', { conid, refreshToken })} @@ -22,10 +27,18 @@ emptyMessage={'No databases'} columns={summary.columns.map(col => ({ ...col, - slot: col.dataType == 'bytes' ? 1 : null, + slot: col.columnType == 'bytes' ? 1 : col.columnType == 'actions' ? 2 : null, }))} > {formatFileSize(row?.[col.fieldName])} + + {#each col.actions as action, index} + {#if index > 0} + | + {/if} + callAction(action.command, row)}>{action.header} + {/each} + {/await} diff --git a/plugins/dbgate-plugin-mongo/src/backend/driver.js b/plugins/dbgate-plugin-mongo/src/backend/driver.js index 24c960708..b69ff7e55 100644 --- a/plugins/dbgate-plugin-mongo/src/backend/driver.js +++ b/plugins/dbgate-plugin-mongo/src/backend/driver.js @@ -352,6 +352,20 @@ const driver = { return res; }, + async summaryCommand(pool, command, row) { + switch (command) { + case 'profileOff': + await pool.db(row.name).command({ profile: 0 }); + return; + case 'profileFiltered': + await pool.db(row.name).command({ profile: 1, slowms: 100 }); + return; + case 'profileAll': + await pool.db(row.name).command({ profile: 2 }); + return; + } + }, + async serverSummary(pool) { const res = await pool.__getDatabase().admin().listDatabases(); const profiling = await Promise.all(res.databases.map((x) => pool.db(x.name).command({ profile: -1 }))); @@ -363,7 +377,7 @@ const driver = { case 1: return `Filtered (>${info.slowms} ms)`; case 2: - 'Profile all'; + return 'Profile all'; default: return '???'; } @@ -373,19 +387,37 @@ const driver = { columns: [ { fieldName: 'name', - dataType: 'string', + columnType: 'string', header: 'Name', }, { fieldName: 'sizeOnDisk', - dataType: 'bytes', + columnType: 'bytes', header: 'Size', }, { fieldName: 'profiling', - dataType: 'string', + columnType: 'string', header: 'Profiling', }, + { + fieldName: 'setProfile', + columnType: 'actions', + actions: [ + { + header: 'Off', + command: 'profileOff', + }, + { + header: 'Filtered', + command: 'profileFiltered', + }, + { + header: 'All', + command: 'profileAll', + }, + ], + }, ], databases: res.databases.map((db, i) => ({ ...db,