From a6b6b5eb701bf5ed999d8700b4330fa4f7c197d5 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 12 Aug 2025 22:19:16 +0200 Subject: [PATCH 001/659] feat: add typing for listVariables, listProccess, killProccess, update server summary typings --- packages/types/engines.d.ts | 124 +++++++++++++++++++++++++----------- 1 file changed, 86 insertions(+), 38 deletions(-) diff --git a/packages/types/engines.d.ts b/packages/types/engines.d.ts index 4d8fd53b5..a1a864c99 100644 --- a/packages/types/engines.d.ts +++ b/packages/types/engines.d.ts @@ -99,6 +99,25 @@ export interface SupportedDbKeyType { showItemList?: boolean; } +export type DatabaseProcess = { + processId: number; + connectionId: number; + client: string; + operation?: string; + namespace?: string; + command?: any; + runningTime: number; + state?: any; + waitingFor?: boolean; + locks?: any; + progress?: any; +}; + +export type DatabaseVariable = { + variable: string; + value: any; +}; + export interface SqlBackupDumper { run(); } @@ -110,7 +129,8 @@ export interface SummaryColumn { } export interface ServerSummaryDatabase {} export interface ServerSummary { - columns: SummaryColumn[]; + processes: DatabaseProcess[]; + variables: DatabaseVariable[]; databases: ServerSummaryDatabase[]; } @@ -161,12 +181,12 @@ export interface FilterBehaviourProvider { getFilterBehaviour(dataType: string, standardFilterBehaviours: { [id: string]: FilterBehaviour }): FilterBehaviour; } -export interface DatabaseHandle { +export interface DatabaseHandle { client: TClient; database?: string; conid?: string; feedback?: (message: any) => void; - getDatabase?: () => any; + getDatabase?: () => TDataBase; connectionType?: string; treeKeySeparator?: string; } @@ -196,7 +216,7 @@ export interface RestoreDatabaseSettings extends BackupRestoreSettingsBase { inputFile: string; } -export interface EngineDriver extends FilterBehaviourProvider { +export interface EngineDriver extends FilterBehaviourProvider { engine: string; title: string; defaultPort?: number; @@ -242,61 +262,86 @@ export interface EngineDriver extends FilterBehaviourProvider { defaultSocketPath?: string; authTypeLabel?: string; importExportArgs?: any[]; - connect({ server, port, user, password, database, connectionDefinition }): Promise>; - close(dbhan: DatabaseHandle): Promise; - query(dbhan: DatabaseHandle, sql: string, options?: QueryOptions): Promise; - stream(dbhan: DatabaseHandle, sql: string, options: StreamOptions); - readQuery(dbhan: DatabaseHandle, sql: string, structure?: TableInfo): Promise; - readJsonQuery(dbhan: DatabaseHandle, query: any, structure?: TableInfo): Promise; + connect({ + server, + port, + user, + password, + database, + connectionDefinition, + }): Promise>; + close(dbhan: DatabaseHandle): Promise; + query(dbhan: DatabaseHandle, sql: string, options?: QueryOptions): Promise; + stream(dbhan: DatabaseHandle, sql: string, options: StreamOptions); + readQuery(dbhan: DatabaseHandle, sql: string, structure?: TableInfo): Promise; + readJsonQuery(dbhan: DatabaseHandle, query: any, structure?: TableInfo): Promise; // eg. PostgreSQL COPY FROM stdin - writeQueryFromStream(dbhan: DatabaseHandle, sql: string): Promise; - writeTable(dbhan: DatabaseHandle, name: NamedObjectInfo, options: WriteTableOptions): Promise; + writeQueryFromStream(dbhan: DatabaseHandle, sql: string): Promise; + writeTable( + dbhan: DatabaseHandle, + name: NamedObjectInfo, + options: WriteTableOptions + ): Promise; analyseSingleObject( - dbhan: DatabaseHandle, + dbhan: DatabaseHandle, name: NamedObjectInfo, objectTypeField: keyof DatabaseInfo ): Promise; - analyseSingleTable(dbhan: DatabaseHandle, name: NamedObjectInfo): Promise; - getVersion(dbhan: DatabaseHandle): Promise<{ version: string; versionText?: string }>; - listDatabases(dbhan: DatabaseHandle): Promise< + analyseSingleTable(dbhan: DatabaseHandle, name: NamedObjectInfo): Promise; + getVersion(dbhan: DatabaseHandle): Promise<{ version: string; versionText?: string }>; + listDatabases(dbhan: DatabaseHandle): Promise< { name: string; }[] >; - loadKeys(dbhan: DatabaseHandle, root: string, filter?: string): Promise; - scanKeys(dbhan: DatabaseHandle, root: string, pattern: string, cursor: string, count: number): Promise; - exportKeys(dbhan: DatabaseHandle, options: {}): Promise; - loadKeyInfo(dbhan: DatabaseHandle, key): Promise; - loadKeyTableRange(dbhan: DatabaseHandle, key, cursor, count): Promise; + loadKeys(dbhan: DatabaseHandle, root: string, filter?: string): Promise; + scanKeys( + dbhan: DatabaseHandle, + root: string, + pattern: string, + cursor: string, + count: number + ): Promise; + exportKeys(dbhan: DatabaseHandle, options: {}): Promise; + loadKeyInfo(dbhan: DatabaseHandle, key): Promise; + loadKeyTableRange(dbhan: DatabaseHandle, key, cursor, count): Promise; loadFieldValues( - dbhan: DatabaseHandle, + dbhan: DatabaseHandle, name: NamedObjectInfo, field: string, search: string, dataType: string ): Promise; - analyseFull(dbhan: DatabaseHandle, serverVersion): Promise; - analyseIncremental(dbhan: DatabaseHandle, structure: DatabaseInfo, serverVersion): Promise; + analyseFull(dbhan: DatabaseHandle, serverVersion): Promise; + analyseIncremental( + dbhan: DatabaseHandle, + structure: DatabaseInfo, + serverVersion + ): Promise; dialect: SqlDialect; dialectByVersion(version): SqlDialect; createDumper(options = null): SqlDumper; - createBackupDumper(dbhan: DatabaseHandle, options): Promise; + createBackupDumper(dbhan: DatabaseHandle, options): Promise; getAuthTypes(): EngineAuthType[]; - readCollection(dbhan: DatabaseHandle, options: ReadCollectionOptions): Promise; - updateCollection(dbhan: DatabaseHandle, changeSet: any): Promise; + readCollection(dbhan: DatabaseHandle, options: ReadCollectionOptions): Promise; + updateCollection(dbhan: DatabaseHandle, changeSet: any): Promise; getCollectionUpdateScript(changeSet: any, collectionInfo: CollectionInfo): string; - createDatabase(dbhan: DatabaseHandle, name: string): Promise; - dropDatabase(dbhan: DatabaseHandle, name: string): Promise; + createDatabase(dbhan: DatabaseHandle, name: string): Promise; + dropDatabase(dbhan: DatabaseHandle, name: string): Promise; getQuerySplitterOptions(usage: 'stream' | 'script' | 'editor' | 'import'): any; - script(dbhan: DatabaseHandle, sql: string, options?: RunScriptOptions): Promise; - operation(dbhan: DatabaseHandle, operation: CollectionOperationInfo, options?: RunScriptOptions): Promise; + script(dbhan: DatabaseHandle, sql: string, options?: RunScriptOptions): Promise; + operation( + dbhan: DatabaseHandle, + operation: CollectionOperationInfo, + options?: RunScriptOptions + ): Promise; getNewObjectTemplates(): NewObjectTemplate[]; // direct call of dbhan.client method, only some methods could be supported, on only some drivers - callMethod(dbhan: DatabaseHandle, method, args); - serverSummary(dbhan: DatabaseHandle): Promise; - summaryCommand(dbhan: DatabaseHandle, command, row): Promise; - startProfiler(dbhan: DatabaseHandle, options): Promise; - stopProfiler(dbhan: DatabaseHandle, profiler): Promise; + callMethod(dbhan: DatabaseHandle, method, args); + serverSummary(dbhan: DatabaseHandle): Promise; + summaryCommand(dbhan: DatabaseHandle, command, row): Promise; + startProfiler(dbhan: DatabaseHandle, options): Promise; + stopProfiler(dbhan: DatabaseHandle, profiler): Promise; getRedirectAuthUrl(connection, options): Promise<{ url: string; sid: string }>; getAuthTokenFromCode(connection, options): Promise; getAccessTokenFromAuth(connection, req): Promise; @@ -313,7 +358,10 @@ export interface EngineDriver extends FilterBehaviourProvider { adaptTableInfo(table: TableInfo): TableInfo; // simple data type adapter adaptDataType(dataType: string): string; - listSchemas(dbhan: DatabaseHandle): Promise; + listSchemas(dbhan: DatabaseHandle): Promise; + listProcesses(dbhan: DatabaseHandle): Promise; + listVariables(dbhan: DatabaseHandle): Promise; + killProcess(dbhan: DatabaseHandle, pid: number): Promise; backupDatabaseCommand( connection: any, settings: BackupDatabaseSettings, @@ -337,7 +385,7 @@ export interface EngineDriver extends FilterBehaviourProvider { analyserClass?: any; dumperClass?: any; singleConnectionOnly?: boolean; - getLogDbInfo(dbhan: DatabaseHandle): { + getLogDbInfo(dbhan: DatabaseHandle): { database?: string; engine: string; conid?: string; From a293eeb3984ff566e182b5ca08ff9deab132d4c5 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 12 Aug 2025 22:19:28 +0200 Subject: [PATCH 002/659] feat: new mongo server summary --- .../dbgate-plugin-mongo/src/backend/driver.js | 153 +++++++++--------- 1 file changed, 77 insertions(+), 76 deletions(-) diff --git a/plugins/dbgate-plugin-mongo/src/backend/driver.js b/plugins/dbgate-plugin-mongo/src/backend/driver.js index d275f5611..c886d5c18 100644 --- a/plugins/dbgate-plugin-mongo/src/backend/driver.js +++ b/plugins/dbgate-plugin-mongo/src/backend/driver.js @@ -6,7 +6,7 @@ const Analyser = require('./Analyser'); const isPromise = require('is-promise'); const { MongoClient, ObjectId, AbstractCursor, Long } = require('mongodb'); const { EJSON } = require('bson'); -const { serializeJsTypesForJsonStringify, deserializeJsTypesFromJsonParse } = require('dbgate-tools'); +const { serializeJsTypesForJsonStringify, deserializeJsTypesFromJsonParse, getLogger } = require('dbgate-tools'); const createBulkInsertStream = require('./createBulkInsertStream'); const { convertToMongoCondition, @@ -16,6 +16,8 @@ const { let isProApp; +const logger = getLogger('mongoDriver'); + function serializeMongoData(row) { return EJSON.serialize( serializeJsTypesForJsonStringify(row, (value) => { @@ -80,7 +82,7 @@ async function getScriptableDb(dbhan) { // } // } -/** @type {import('dbgate-types').EngineDriver} */ +/** @type {import('dbgate-types').EngineDriver} */ const driver = { ...driverBase, analyserClass: Analyser, @@ -193,7 +195,10 @@ const driver = { let exprValue; try { - const serviceProvider = new NodeDriverServiceProvider(dbhan.client, new EventEmitter(), { productDocsLink: '', productName: 'DbGate' }); + const serviceProvider = new NodeDriverServiceProvider(dbhan.client, new EventEmitter(), { + productDocsLink: '', + productName: 'DbGate', + }); const runtime = new ElectronRuntime(serviceProvider); await runtime.evaluate(`use ${dbhan.database}`); exprValue = await runtime.evaluate(sql); @@ -629,86 +634,82 @@ const driver = { }, async serverSummary(dbhan) { - const res = await dbhan.getDatabase().admin().listDatabases(); - const profiling = await Promise.all(res.databases.map((x) => dbhan.client.db(x.name).command({ profile: -1 }))); + const [processes, variables, databases] = await Promise.all([ + this.listProcesses(dbhan), + this.listVariables(dbhan), + this.listDatabases(dbhan), + ]); - function formatProfiling(info) { - switch (info.was) { - case 0: - return 'No profiling'; - case 1: - return `Filtered (>${info.slowms} ms)`; - case 2: - return 'Profile all'; - default: - return '???'; - } - } - - return { - columns: [ - { - fieldName: 'name', - columnType: 'string', - header: 'Name', - }, - { - fieldName: 'sizeOnDisk', - columnType: 'bytes', - header: 'Size', - }, - { - fieldName: 'profiling', - columnType: 'string', - header: 'Profiling', - }, - { - fieldName: 'setProfile', - columnType: 'actions', - header: 'Profiling actions', - actions: [ - { - header: 'Off', - command: 'profileOff', - }, - { - header: 'Filtered', - command: 'profileFiltered', - }, - { - header: 'All', - command: 'profileAll', - }, - // { - // header: 'View', - // openQuery: "db['system.profile'].find()", - // tabTitle: 'Profile data', - // }, - { - header: 'View', - openTab: { - title: 'system.profile', - icon: 'img collection', - tabComponent: 'CollectionDataTab', - props: { - pureName: 'system.profile', - }, - }, - addDbProps: true, - }, - ], - }, - ], - databases: res.databases.map((db, i) => ({ - ...db, - profiling: formatProfiling(profiling[i]), - })), + const data = { + processes, + variables, + databases, }; + + return data; }, async close(dbhan) { return dbhan.client.close(); }, + + async listProcesses(dbhan) { + const db = dbhan.getDatabase(); + const adminDb = db.admin(); + + const currentOp = await adminDb.command({ + currentOp: { + $all: true, + active: true, + idle: true, + system: true, + killPending: true, + }, + }); + + const processes = currentOp.inprog.map((op) => ({ + processId: op.opid, + connectionId: op.connectionId, + client: op.client, + operation: op.op, + namespace: op.ns, + command: op.command, + runningTime: op.secs_running, + state: op.state, + waitingFor: op.waitingForLock, + locks: op.locks, + progress: op.progress, + })); + + return processes; + }, + + async listVariables(dbhan) { + const db = dbhan.getDatabase(); + const adminDb = db.admin(); + + const variables = await adminDb + .command({ getParameter: '*' }) + .then((params) => + Object.entries(params).map(([key, value]) => ({ variable: key, value: value?.value || value })) + ); + + return variables; + }, + + async killProcess(dbhan, processId) { + const db = dbhan.getDatabase(); + const adminDb = db.admin(); + + const result = await adminDb.command({ + killOp: 1, + op: processId, + }); + + logger.info(`Killed process with ID ${processId}`, result); + + return result; + }, }; driver.initialize = (dbgateEnv) => { From 5dd62ad2aadbf93ff9472b1e10e59e54f85496c4 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 12 Aug 2025 23:45:41 +0200 Subject: [PATCH 003/659] feat: new server summary tab --- packages/web/src/buttons/CtaButton.svelte | 46 +++++++++++ .../web/src/jsontree/JSONArrayNode.svelte | 8 +- .../src/jsontree/JSONIterableArrayNode.svelte | 8 +- .../src/jsontree/JSONIterableMapNode.svelte | 6 +- .../web/src/jsontree/JSONMapEntryNode.svelte | 8 +- packages/web/src/jsontree/JSONNested.svelte | 14 +++- packages/web/src/jsontree/JSONNode.svelte | 2 + .../web/src/jsontree/JSONObjectNode.svelte | 2 + packages/web/src/jsontree/JSONTree.svelte | 3 +- .../web/src/jsontree/JSONValueNode.svelte | 24 ++++-- packages/web/src/stores.ts | 2 + packages/web/src/tabs/ServerSummaryTab.svelte | 53 +++++++------ .../web/src/tabs/TableStructureTab.svelte | 2 +- .../web/src/widgets/SummaryDatabases.svelte | 77 +++++++++++++++++++ .../web/src/widgets/SummaryProcesses.svelte | 77 +++++++++++++++++++ .../web/src/widgets/SummaryVariables.svelte | 29 +++++++ 16 files changed, 321 insertions(+), 40 deletions(-) create mode 100644 packages/web/src/buttons/CtaButton.svelte create mode 100644 packages/web/src/widgets/SummaryDatabases.svelte create mode 100644 packages/web/src/widgets/SummaryProcesses.svelte create mode 100644 packages/web/src/widgets/SummaryVariables.svelte diff --git a/packages/web/src/buttons/CtaButton.svelte b/packages/web/src/buttons/CtaButton.svelte new file mode 100644 index 000000000..2b77f7ca8 --- /dev/null +++ b/packages/web/src/buttons/CtaButton.svelte @@ -0,0 +1,46 @@ + + + + + diff --git a/packages/web/src/jsontree/JSONArrayNode.svelte b/packages/web/src/jsontree/JSONArrayNode.svelte index 1f57ac377..205ff32f8 100644 --- a/packages/web/src/jsontree/JSONArrayNode.svelte +++ b/packages/web/src/jsontree/JSONArrayNode.svelte @@ -3,6 +3,8 @@ export let key, value, isParentExpanded, isParentArray; export let expanded = false; + export let labelOverride = null; + export let hideKey = false; const filteredKey = new Set(['length']); $: keys = Object.getOwnPropertyNames(value); @@ -22,8 +24,10 @@ {keys} {previewKeys} {getValue} - label="Array({value.length})" + label={labelOverride || `Array(${value.length})`} bracketOpen="[" bracketClose="]" elementValue={value} -/> \ No newline at end of file + {labelOverride} + {hideKey} +/> diff --git a/packages/web/src/jsontree/JSONIterableArrayNode.svelte b/packages/web/src/jsontree/JSONIterableArrayNode.svelte index 927455bce..75bc356ea 100644 --- a/packages/web/src/jsontree/JSONIterableArrayNode.svelte +++ b/packages/web/src/jsontree/JSONIterableArrayNode.svelte @@ -2,6 +2,8 @@ import JSONNested from './JSONNested.svelte'; export let key, value, isParentExpanded, isParentArray, nodeType; + export let labelOverride = null; + export let hideKey = false; let keys = []; @@ -29,7 +31,9 @@ {getKey} {getValue} isArray={true} - label="{nodeType}({keys.length})" + label={labelOverride || `${nodeType}(${keys.length})`} bracketOpen={'{'} bracketClose={'}'} -/> \ No newline at end of file + {labelOverride} + {hideKey} +/> diff --git a/packages/web/src/jsontree/JSONIterableMapNode.svelte b/packages/web/src/jsontree/JSONIterableMapNode.svelte index 907ee0326..8c0aad697 100644 --- a/packages/web/src/jsontree/JSONIterableMapNode.svelte +++ b/packages/web/src/jsontree/JSONIterableMapNode.svelte @@ -3,6 +3,8 @@ import MapEntry from './utils/MapEntry' export let key, value, isParentExpanded, isParentArray, nodeType; + export let labelOverride = null; + export let hideKey = false; let keys = []; @@ -28,8 +30,10 @@ {keys} {getKey} {getValue} - label="{nodeType}({keys.length})" + label={labelOverride || `${nodeType}(${keys.length})`} colon="" bracketOpen={'{'} bracketClose={'}'} + {labelOverride} + {hideKey} /> diff --git a/packages/web/src/jsontree/JSONMapEntryNode.svelte b/packages/web/src/jsontree/JSONMapEntryNode.svelte index cccd283fa..1f012e10b 100644 --- a/packages/web/src/jsontree/JSONMapEntryNode.svelte +++ b/packages/web/src/jsontree/JSONMapEntryNode.svelte @@ -3,6 +3,8 @@ export let key, value, isParentExpanded, isParentArray; export let expanded = false; + export let hideKey = false; + export let labelOverride = null; const keys = ['key', 'value']; @@ -17,7 +19,9 @@ key={isParentExpanded ? String(key) : value.key} {keys} {getValue} - label={isParentExpanded ? 'Entry ' : '=> '} + label={labelOverride || (isParentExpanded ? 'Entry ' : '=> ')} bracketOpen={'{'} bracketClose={'}'} -/> \ No newline at end of file + {labelOverride} + {hideKey} +/> diff --git a/packages/web/src/jsontree/JSONNested.svelte b/packages/web/src/jsontree/JSONNested.svelte index 2c0a71bec..0efa828ac 100644 --- a/packages/web/src/jsontree/JSONNested.svelte +++ b/packages/web/src/jsontree/JSONNested.svelte @@ -21,11 +21,14 @@ expandable = true; export let elementValue = null; export let onRootExpandedChanged = null; + export let labelOverride = null; + export let hideKey = false; const context = getContext('json-tree-context-key'); setContext('json-tree-context-key', { ...context, colon }); const elementData = getContext('json-tree-element-data'); const slicedKeyCount = getContext('json-tree-sliced-key-count'); + const keyLabel = labelOverride ?? key; $: slicedKeys = expanded ? keys : previewKeys.slice(0, slicedKeyCount || 5); @@ -56,7 +59,16 @@ {#if expandable && isParentExpanded} {/if} - + {#if !hideKey} + + {/if} {label}{bracketOpen} {#if isParentExpanded} diff --git a/packages/web/src/jsontree/JSONNode.svelte b/packages/web/src/jsontree/JSONNode.svelte index bf526e1ca..a7b179c16 100644 --- a/packages/web/src/jsontree/JSONNode.svelte +++ b/packages/web/src/jsontree/JSONNode.svelte @@ -16,6 +16,7 @@ export let expanded = !!getContext('json-tree-default-expanded'); export let labelOverride = null; export let onRootExpandedChanged = null; + export let hideKey = false; $: nodeType = objType(value); $: componentType = getComponent(nodeType); @@ -85,4 +86,5 @@ {expanded} {labelOverride} {onRootExpandedChanged} + {hideKey} /> diff --git a/packages/web/src/jsontree/JSONObjectNode.svelte b/packages/web/src/jsontree/JSONObjectNode.svelte index 71f0dd536..33320a8ff 100644 --- a/packages/web/src/jsontree/JSONObjectNode.svelte +++ b/packages/web/src/jsontree/JSONObjectNode.svelte @@ -5,6 +5,7 @@ export let expanded = false; export let labelOverride = null; export let onRootExpandedChanged = null; + export let hideKey = false; $: keys = Object.getOwnPropertyNames(value); @@ -26,4 +27,5 @@ bracketClose={'}'} elementValue={value} {onRootExpandedChanged} + {hideKey} /> diff --git a/packages/web/src/jsontree/JSONTree.svelte b/packages/web/src/jsontree/JSONTree.svelte index fddfda32e..311e54c6b 100644 --- a/packages/web/src/jsontree/JSONTree.svelte +++ b/packages/web/src/jsontree/JSONTree.svelte @@ -2,7 +2,6 @@ import JSONNode from './JSONNode.svelte'; import { setContext } from 'svelte'; import contextMenu, { getContextMenu } from '../utility/contextMenu'; - import openNewTab from '../utility/openNewTab'; import _ from 'lodash'; import { copyTextToClipboard } from '../utility/clipboard'; import { openJsonLinesData } from '../utility/openJsonLinesData'; @@ -23,6 +22,7 @@ export let isDeleted = false; export let isInserted = false; export let isModified = false; + export let hideKey = false; const settings = useSettings(); $: wrap = $settings?.['behaviour.jsonPreviewWrap']; @@ -73,6 +73,7 @@ class:wrap > + +
  • + + + {valueGetter ? valueGetter(value) : value} + +
  • + -
  • - - - {valueGetter ? valueGetter(value) : value} - -
  • \ No newline at end of file + diff --git a/packages/web/src/stores.ts b/packages/web/src/stores.ts index badfa1ce7..34188e2cc 100644 --- a/packages/web/src/stores.ts +++ b/packages/web/src/stores.ts @@ -215,6 +215,8 @@ export const connectionAppObjectSearchSettings = writableWithStorage( 'connectionAppObjectSearchSettings2' ); +export const serverSummarySelectedTab = writableWithStorage(0, 'serverSummary.selectedTab'); + let currentThemeValue = null; currentTheme.subscribe(value => { currentThemeValue = value; diff --git a/packages/web/src/tabs/ServerSummaryTab.svelte b/packages/web/src/tabs/ServerSummaryTab.svelte index 0686a5edc..3043ac358 100644 --- a/packages/web/src/tabs/ServerSummaryTab.svelte +++ b/packages/web/src/tabs/ServerSummaryTab.svelte @@ -18,15 +18,17 @@ import ToolStripCommandButton from '../buttons/ToolStripCommandButton.svelte'; import ToolStripContainer from '../buttons/ToolStripContainer.svelte'; import registerCommand from '../commands/registerCommand'; - import Link from '../elements/Link.svelte'; import LoadingInfo from '../elements/LoadingInfo.svelte'; + import TabControl from '../elements/TabControl.svelte'; - import ObjectListControl from '../elements/ObjectListControl.svelte'; import { _t } from '../translations'; import { apiCall } from '../utility/api'; import createActivator, { getActiveComponent } from '../utility/createActivator'; - import formatFileSize from '../utility/formatFileSize'; import openNewTab from '../utility/openNewTab'; + import SummaryVariables from '../widgets/SummaryVariables.svelte'; + import SummaryProcesses from '../widgets/SummaryProcesses.svelte'; + import SummaryDatabases from '../widgets/SummaryDatabases.svelte'; + import { serverSummarySelectedTab } from '../stores'; export let conid; @@ -78,26 +80,31 @@ {:then summary}
    - ({ - ...col, - slot: col.columnType == 'bytes' ? 1 : col.columnType == 'actions' ? 2 : null, - }))} - > - {formatFileSize(row?.[col.fieldName])} - - {#each col.actions as action, index} - {#if index > 0} - | - {/if} - runAction(action, row)}>{action.header} - {/each} - - + serverSummarySelectedTab.set(index)} + tabs={[ + { + label: 'Variables', + component: SummaryVariables, + props: { variables: summary.variables || [] }, + }, + { + label: 'Processes', + component: SummaryProcesses, + props: { processes: summary.processes || [], conid }, + }, + { + label: 'Databases', + component: SummaryDatabases, + props: { databases: summary.databases || [] }, + }, + ]} + />
    {/await} diff --git a/packages/web/src/tabs/TableStructureTab.svelte b/packages/web/src/tabs/TableStructureTab.svelte index 1e8ab9efb..f5dfca571 100644 --- a/packages/web/src/tabs/TableStructureTab.svelte +++ b/packages/web/src/tabs/TableStructureTab.svelte @@ -197,7 +197,7 @@ defaultActionId: 'openTable', }, }); - }}>DataDataX + import TableControl from '../elements/TableControl.svelte'; + import CtaButton from '../buttons/CtaButton.svelte'; + import { _t } from '../translations'; + import formatFileSize from '../utility/formatFileSize'; + + export let databases: any[] = []; + + async function profileOff(database: any) { + // TODO: Implement profile off functionality + console.log('Profile off:', database.name); + } + + async function profileFiltered(database: any) { + // TODO: Implement profile filtered functionality + console.log('Profile filtered:', database.name); + } + + async function profileAll(database: any) { + // TODO: Implement profile all functionality + console.log('Profile all:', database.name); + } + + +
    + + + profileOff(row)}>Profile Off + | + profileFiltered(row)}>Profile Filtered + | + profileAll(row)}>Profile All + + + + {row.name} + + + + {formatFileSize(row.sizeOnDisk)} + + + + {formatFileSize(row.dataSize)} + + + + {formatFileSize(row.indexSize)} + + +
    + + diff --git a/packages/web/src/widgets/SummaryProcesses.svelte b/packages/web/src/widgets/SummaryProcesses.svelte new file mode 100644 index 000000000..c9e765bd3 --- /dev/null +++ b/packages/web/src/widgets/SummaryProcesses.svelte @@ -0,0 +1,77 @@ + + +
    + + + killProcess(row.processId)}> + {_t('common.kill', { defaultMessage: 'Kill' })} + + + + + {row.processId} + + + + {formatRunningTime(row.runningTime)} + + + + {row.waitingFor ? 'Yes' : 'No'} + + +
    + + diff --git a/packages/web/src/widgets/SummaryVariables.svelte b/packages/web/src/widgets/SummaryVariables.svelte new file mode 100644 index 000000000..7a37b6a34 --- /dev/null +++ b/packages/web/src/widgets/SummaryVariables.svelte @@ -0,0 +1,29 @@ + + +
    + + + + + +
    + + From 9d456992cf5af8007473b6d1bcd13bc276a804f4 Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 13 Aug 2025 04:54:15 +0200 Subject: [PATCH 004/659] feat: kill db process --- packages/api/src/controllers/serverConnections.js | 14 ++++++++++++++ packages/api/src/proc/serverConnectionProcess.js | 13 +++++++++++++ packages/web/src/widgets/SummaryProcesses.svelte | 12 +++++++++++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/api/src/controllers/serverConnections.js b/packages/api/src/controllers/serverConnections.js index 86e461feb..cdc4bcb76 100644 --- a/packages/api/src/controllers/serverConnections.js +++ b/packages/api/src/controllers/serverConnections.js @@ -274,6 +274,20 @@ module.exports = { return this.loadDataCore('serverSummary', { conid }); }, + killDatabaseProcess_meta: true, + async killDatabaseProcess(ctx, req) { + const { conid, pid } = ctx; + testConnectionPermission(conid, req); + + const opened = await this.ensureOpened(conid); + if (!opened) { + return null; + } + if (opened.connection.isReadOnly) return false; + + return this.sendRequest(opened, { msgtype: 'killDatabaseProcess', pid }); + }, + summaryCommand_meta: true, async summaryCommand({ conid, command, row }, req) { testConnectionPermission(conid, req); diff --git a/packages/api/src/proc/serverConnectionProcess.js b/packages/api/src/proc/serverConnectionProcess.js index d58aa18ed..99435f274 100644 --- a/packages/api/src/proc/serverConnectionProcess.js +++ b/packages/api/src/proc/serverConnectionProcess.js @@ -146,6 +146,18 @@ async function handleServerSummary({ msgid }) { return handleDriverDataCore(msgid, driver => driver.serverSummary(dbhan)); } +async function handleKillDatabaseProccess({ msgid, pid }) { + await waitConnected(); + const driver = requireEngineDriver(storedConnection); + + try { + const result = await driver.killProcess(dbhan, Number(pid)); + process.send({ msgtype: 'response', msgid, result }); + } catch (err) { + process.send({ msgtype: 'response', msgid, errorMessage: err.message }); + } +} + async function handleSummaryCommand({ msgid, command, row }) { return handleDriverDataCore(msgid, driver => driver.summaryCommand(dbhan, command, row)); } @@ -154,6 +166,7 @@ const messageHandlers = { connect: handleConnect, ping: handlePing, serverSummary: handleServerSummary, + killDatabaseProcess: handleKillDatabaseProccess, summaryCommand: handleSummaryCommand, createDatabase: props => handleDatabaseOp('createDatabase', props), dropDatabase: props => handleDatabaseOp('dropDatabase', props), diff --git a/packages/web/src/widgets/SummaryProcesses.svelte b/packages/web/src/widgets/SummaryProcesses.svelte index c9e765bd3..b1b19bc85 100644 --- a/packages/web/src/widgets/SummaryProcesses.svelte +++ b/packages/web/src/widgets/SummaryProcesses.svelte @@ -3,12 +3,22 @@ import TableControl from '../elements/TableControl.svelte'; import { _t } from '../translations'; import CtaButton from '../buttons/CtaButton.svelte'; + import { apiCall } from '../utility/api'; + import runCommand from '../commands/runCommand'; + export let conid; export let processes: DatabaseProcess[] = []; - async function killProcess(processId: string) { + async function killProcess(processId: number) { // TODO: Implement kill process functionality console.log('Kill process:', processId); + + await apiCall('server-connections/kill-database-process', { + pid: processId, + conid, + }); + + runCommand('serverSummary.refresh'); } function formatRunningTime(seconds: number): string { From 61f1c99791b007865750f86e1f854742b2ad376c Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 14 Aug 2025 16:39:54 +0200 Subject: [PATCH 005/659] feat: send cols from list databases --- packages/types/engines.d.ts | 16 ++++- packages/web/src/tabs/ServerSummaryTab.svelte | 2 +- .../web/src/widgets/SummaryDatabases.svelte | 70 ++----------------- .../dbgate-plugin-mongo/src/backend/driver.js | 9 ++- 4 files changed, 30 insertions(+), 67 deletions(-) diff --git a/packages/types/engines.d.ts b/packages/types/engines.d.ts index a1a864c99..4a848af9c 100644 --- a/packages/types/engines.d.ts +++ b/packages/types/engines.d.ts @@ -127,11 +127,21 @@ export interface SummaryColumn { header: string; dataType: 'string' | 'number' | 'bytes'; } -export interface ServerSummaryDatabase {} +export interface ServerSummaryDatabases { + rows: any[]; + columns: DatabaseColumn[]; +} + +export type DatabaseColumn = { + header: string; + fieldName: string; + type: 'data' | 'fileSize'; +}; + export interface ServerSummary { processes: DatabaseProcess[]; variables: DatabaseVariable[]; - databases: ServerSummaryDatabase[]; + databases: ServerSummaryDatabases; } export type CollectionAggregateFunction = 'count' | 'sum' | 'avg' | 'min' | 'max'; @@ -292,6 +302,8 @@ export interface EngineDriver extends FilterBeha listDatabases(dbhan: DatabaseHandle): Promise< { name: string; + sizeOnDisk?: number; + empty?: boolean; }[] >; loadKeys(dbhan: DatabaseHandle, root: string, filter?: string): Promise; diff --git a/packages/web/src/tabs/ServerSummaryTab.svelte b/packages/web/src/tabs/ServerSummaryTab.svelte index 3043ac358..6d828d7ad 100644 --- a/packages/web/src/tabs/ServerSummaryTab.svelte +++ b/packages/web/src/tabs/ServerSummaryTab.svelte @@ -101,7 +101,7 @@ { label: 'Databases', component: SummaryDatabases, - props: { databases: summary.databases || [] }, + props: { rows: summary.databases?.rows ?? [], columns: summary.databases?.columns ?? [] }, }, ]} /> diff --git a/packages/web/src/widgets/SummaryDatabases.svelte b/packages/web/src/widgets/SummaryDatabases.svelte index cd576fe1e..9fe06bcb8 100644 --- a/packages/web/src/widgets/SummaryDatabases.svelte +++ b/packages/web/src/widgets/SummaryDatabases.svelte @@ -1,77 +1,21 @@
    - - - profileOff(row)}>Profile Off - | - profileFiltered(row)}>Profile Filtered - | - profileAll(row)}>Profile All - - - - {row.name} - - - - {formatFileSize(row.sizeOnDisk)} - - - - {formatFileSize(row.dataSize)} - - - - {formatFileSize(row.indexSize)} - - +
    diff --git a/plugins/dbgate-plugin-mongo/src/backend/driver.js b/plugins/dbgate-plugin-mongo/src/backend/driver.js index c886d5c18..9be451ddf 100644 --- a/plugins/dbgate-plugin-mongo/src/backend/driver.js +++ b/plugins/dbgate-plugin-mongo/src/backend/driver.js @@ -643,7 +643,14 @@ const driver = { const data = { processes, variables, - databases, + databases: { + rows: databases, + columns: [ + { header: 'Name', fieldName: 'name' }, + { header: 'Size on disk', fieldName: 'sizeOnDisk' }, + { header: 'Empty', fieldName: 'empty' }, + ], + }, }; return data; From b1696ed1cd957de050c65996f94f33435725dfe1 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 14 Aug 2025 16:40:20 +0200 Subject: [PATCH 006/659] feat: autorefresh processes, refresh processes w/o displaying loader --- .../api/src/controllers/serverConnections.js | 14 +++++++++++ .../api/src/proc/serverConnectionProcess.js | 13 +++++++++++ .../web/src/widgets/SummaryProcesses.svelte | 23 ++++++++++++++----- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/packages/api/src/controllers/serverConnections.js b/packages/api/src/controllers/serverConnections.js index cdc4bcb76..b486d25e9 100644 --- a/packages/api/src/controllers/serverConnections.js +++ b/packages/api/src/controllers/serverConnections.js @@ -274,6 +274,20 @@ module.exports = { return this.loadDataCore('serverSummary', { conid }); }, + listDatabaseProcesses_meta: true, + async listDatabaseProcesses(ctx, req) { + const { conid } = ctx; + testConnectionPermission(conid, req); + + const opened = await this.ensureOpened(conid); + if (!opened) { + return null; + } + if (opened.connection.isReadOnly) return false; + + return this.sendRequest(opened, { msgtype: 'listDatabaseProcesses' }); + }, + killDatabaseProcess_meta: true, async killDatabaseProcess(ctx, req) { const { conid, pid } = ctx; diff --git a/packages/api/src/proc/serverConnectionProcess.js b/packages/api/src/proc/serverConnectionProcess.js index 99435f274..5540dbbf5 100644 --- a/packages/api/src/proc/serverConnectionProcess.js +++ b/packages/api/src/proc/serverConnectionProcess.js @@ -158,6 +158,18 @@ async function handleKillDatabaseProccess({ msgid, pid }) { } } +async function handleListDatabaseProcesses({ msgid }) { + await waitConnected(); + const driver = requireEngineDriver(storedConnection); + + try { + const result = await driver.listProcesses(dbhan); + process.send({ msgtype: 'response', msgid, result }); + } catch (err) { + process.send({ msgtype: 'response', msgid, errorMessage: err.message }); + } +} + async function handleSummaryCommand({ msgid, command, row }) { return handleDriverDataCore(msgid, driver => driver.summaryCommand(dbhan, command, row)); } @@ -167,6 +179,7 @@ const messageHandlers = { ping: handlePing, serverSummary: handleServerSummary, killDatabaseProcess: handleKillDatabaseProccess, + listDatabaseProcesses: handleListDatabaseProcesses, summaryCommand: handleSummaryCommand, createDatabase: props => handleDatabaseOp('createDatabase', props), dropDatabase: props => handleDatabaseOp('dropDatabase', props), diff --git a/packages/web/src/widgets/SummaryProcesses.svelte b/packages/web/src/widgets/SummaryProcesses.svelte index b1b19bc85..e049bd1bd 100644 --- a/packages/web/src/widgets/SummaryProcesses.svelte +++ b/packages/web/src/widgets/SummaryProcesses.svelte @@ -4,21 +4,26 @@ import { _t } from '../translations'; import CtaButton from '../buttons/CtaButton.svelte'; import { apiCall } from '../utility/api'; - import runCommand from '../commands/runCommand'; + import { onMount } from 'svelte'; export let conid; export let processes: DatabaseProcess[] = []; + export let refreshInterval: number = 1000; + + let internalProcesses = [...processes]; + + async function refreshProcesses() { + const data = await apiCall('server-connections/list-database-processes', { conid }); + internalProcesses = data.result; + } async function killProcess(processId: number) { - // TODO: Implement kill process functionality - console.log('Kill process:', processId); - await apiCall('server-connections/kill-database-process', { pid: processId, conid, }); - runCommand('serverSummary.refresh'); + refreshProcesses(); } function formatRunningTime(seconds: number): string { @@ -27,11 +32,17 @@ if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${seconds % 60}s`; return `${Math.floor(seconds / 3600)}h ${Math.floor((seconds % 3600) / 60)}m`; } + + onMount(() => { + const intervalId = setInterval(() => refreshProcesses(), refreshInterval); + + return () => clearInterval(intervalId); + });
    Date: Thu, 14 Aug 2025 18:46:19 +0200 Subject: [PATCH 007/659] feat: use _t translations in server summary --- packages/web/src/tabs/ServerSummaryTab.svelte | 13 ++++++---- .../web/src/widgets/SummaryProcesses.svelte | 26 ++++++++++++------- .../web/src/widgets/SummaryVariables.svelte | 5 ++-- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/packages/web/src/tabs/ServerSummaryTab.svelte b/packages/web/src/tabs/ServerSummaryTab.svelte index 6d828d7ad..b16058fd1 100644 --- a/packages/web/src/tabs/ServerSummaryTab.svelte +++ b/packages/web/src/tabs/ServerSummaryTab.svelte @@ -77,7 +77,10 @@ {#await apiCall('server-connections/server-summary', { conid, refreshToken })} - + {:then summary}
    serverSummarySelectedTab.set(index)} + onUserChange={index => serverSummarySelectedTab.set(index)} tabs={[ { - label: 'Variables', + label: _t('serverSummaryTab.variables', { defaultMessage: 'Variables' }), component: SummaryVariables, props: { variables: summary.variables || [] }, }, { - label: 'Processes', + label: _t('serverSummaryTab.processes', { defaultMessage: 'Processes' }), component: SummaryProcesses, props: { processes: summary.processes || [], conid }, }, { - label: 'Databases', + label: _t('serverSummaryTab.databases', { defaultMessage: 'Databases' }), component: SummaryDatabases, props: { rows: summary.databases?.rows ?? [], columns: summary.databases?.columns ?? [] }, }, diff --git a/packages/web/src/widgets/SummaryProcesses.svelte b/packages/web/src/widgets/SummaryProcesses.svelte index e049bd1bd..eda44885e 100644 --- a/packages/web/src/widgets/SummaryProcesses.svelte +++ b/packages/web/src/widgets/SummaryProcesses.svelte @@ -44,16 +44,24 @@ import TableControl from '../elements/TableControl.svelte'; import JSONTree from '../jsontree/JSONTree.svelte'; + import { _t } from '../translations'; export let variables: { variable: string; value: any }[] = []; @@ -8,9 +9,9 @@ Date: Thu, 14 Aug 2025 19:18:14 +0200 Subject: [PATCH 008/659] feat: pass tabVisible to tabs --- packages/web/src/elements/TabControl.svelte | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/web/src/elements/TabControl.svelte b/packages/web/src/elements/TabControl.svelte index 4c7ee15aa..cf7b8cd93 100644 --- a/packages/web/src/elements/TabControl.svelte +++ b/packages/web/src/elements/TabControl.svelte @@ -53,7 +53,12 @@
    {#each _.compact(tabs) as tab, index}
    - + {#if tab.slot != null} {#if tab.slot == 0} {:else if tab.slot == 1} From 164a112e0cad055b3e2dacfd45861767949e11cb Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 14 Aug 2025 19:18:33 +0200 Subject: [PATCH 009/659] feat: refresh processes only if processes tab is open --- packages/web/src/widgets/SummaryProcesses.svelte | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/web/src/widgets/SummaryProcesses.svelte b/packages/web/src/widgets/SummaryProcesses.svelte index eda44885e..e73e208a6 100644 --- a/packages/web/src/widgets/SummaryProcesses.svelte +++ b/packages/web/src/widgets/SummaryProcesses.svelte @@ -9,6 +9,7 @@ export let conid; export let processes: DatabaseProcess[] = []; export let refreshInterval: number = 1000; + export let tabVisible: boolean = false; let internalProcesses = [...processes]; @@ -34,7 +35,11 @@ } onMount(() => { - const intervalId = setInterval(() => refreshProcesses(), refreshInterval); + const intervalId = setInterval(() => { + if (!tabVisible) return; + + refreshProcesses(); + }, refreshInterval); return () => clearInterval(intervalId); }); From d8081277eea81a0f1d04ca2e447af68a32460e6a Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 14 Aug 2025 19:18:42 +0200 Subject: [PATCH 010/659] feat: parse col to row formatter --- packages/web/src/elements/TableControl.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web/src/elements/TableControl.svelte b/packages/web/src/elements/TableControl.svelte index 6da2e8914..f760c30b9 100644 --- a/packages/web/src/elements/TableControl.svelte +++ b/packages/web/src/elements/TableControl.svelte @@ -350,7 +350,7 @@ {#if col.component} {:else if col.formatter} - {col.formatter(row)} + {col.formatter(row, col)} {:else if col.slot != null} {#key row[col.slotKey] || 'key'} {#if col.slot == -1} From 02ee3275954bb6421d6fd07ba35ff06b622b5ce8 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 14 Aug 2025 19:21:04 +0200 Subject: [PATCH 011/659] feat: format fileSize cols in summary databases --- packages/web/src/widgets/SummaryDatabases.svelte | 8 ++++++++ plugins/dbgate-plugin-mongo/src/backend/driver.js | 7 ++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/web/src/widgets/SummaryDatabases.svelte b/packages/web/src/widgets/SummaryDatabases.svelte index 9fe06bcb8..91ecf2fa1 100644 --- a/packages/web/src/widgets/SummaryDatabases.svelte +++ b/packages/web/src/widgets/SummaryDatabases.svelte @@ -1,5 +1,6 @@ diff --git a/plugins/dbgate-plugin-mongo/src/backend/driver.js b/plugins/dbgate-plugin-mongo/src/backend/driver.js index 9be451ddf..0057d5bfd 100644 --- a/plugins/dbgate-plugin-mongo/src/backend/driver.js +++ b/plugins/dbgate-plugin-mongo/src/backend/driver.js @@ -640,15 +640,16 @@ const driver = { this.listDatabases(dbhan), ]); + /** @type {import('dbgate-types').ServerSummary} */ const data = { processes, variables, databases: { rows: databases, columns: [ - { header: 'Name', fieldName: 'name' }, - { header: 'Size on disk', fieldName: 'sizeOnDisk' }, - { header: 'Empty', fieldName: 'empty' }, + { header: 'Name', fieldName: 'name', type: 'data' }, + { header: 'Size on disk', fieldName: 'sizeOnDisk', type: 'fileSize' }, + { header: 'Empty', fieldName: 'empty', type: 'data' }, ], }, }; From 939bbc3f2c8d3a58bd8cac3b417e2010aa440c0d Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 14 Aug 2025 20:09:47 +0200 Subject: [PATCH 012/659] chore: update summary typing --- packages/types/engines.d.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/types/engines.d.ts b/packages/types/engines.d.ts index 4a848af9c..b19d1aa88 100644 --- a/packages/types/engines.d.ts +++ b/packages/types/engines.d.ts @@ -122,17 +122,12 @@ export interface SqlBackupDumper { run(); } -export interface SummaryColumn { - fieldName: string; - header: string; - dataType: 'string' | 'number' | 'bytes'; -} export interface ServerSummaryDatabases { rows: any[]; - columns: DatabaseColumn[]; + columns: SummaryDatabaseColumn[]; } -export type DatabaseColumn = { +export type SummaryDatabaseColumn = { header: string; fieldName: string; type: 'data' | 'fileSize'; From 90546ad4a7019f5a358e128be1ec65123d2e09a8 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 14 Aug 2025 21:16:53 +0200 Subject: [PATCH 013/659] feat: toasts when killing db proc --- .../web/src/widgets/SummaryProcesses.svelte | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/web/src/widgets/SummaryProcesses.svelte b/packages/web/src/widgets/SummaryProcesses.svelte index e73e208a6..0a162b4cb 100644 --- a/packages/web/src/widgets/SummaryProcesses.svelte +++ b/packages/web/src/widgets/SummaryProcesses.svelte @@ -5,6 +5,7 @@ import CtaButton from '../buttons/CtaButton.svelte'; import { apiCall } from '../utility/api'; import { onMount } from 'svelte'; + import { showSnackbarError, showSnackbarSuccess } from '../utility/snackbar'; export let conid; export let processes: DatabaseProcess[] = []; @@ -19,17 +20,33 @@ } async function killProcess(processId: number) { - await apiCall('server-connections/kill-database-process', { + const result = await apiCall('server-connections/kill-database-process', { pid: processId, conid, }); + if (result.errorMessage || result.error) { + showSnackbarError( + _t('summaryProcesses.killError', { + defaultMessage: 'Error while killing process {processId}: {errorMessage}', + values: { processId, errorMessage: result.errorMessage || result.error }, + }) + ); + } else { + showSnackbarSuccess( + _t('summaryProcesses.killSuccess', { + defaultMessage: 'Process {processId} killed successfully', + values: { processId }, + }) + ); + } + refreshProcesses(); } function formatRunningTime(seconds: number): string { if (!seconds) return '-'; - if (seconds < 60) return `${seconds}s`; + if (seconds < 60) return `${seconds.toFixed(3)}s`; if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${seconds % 60}s`; return `${Math.floor(seconds / 3600)}h ${Math.floor((seconds % 3600) / 60)}m`; } From 25fe1d03a7c238821d3492ada060bb943975c410 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 14 Aug 2025 21:33:33 +0200 Subject: [PATCH 014/659] feat: server summary for postgres --- .../src/backend/drivers.js | 57 ++++++++++++++++++- .../src/backend/sql/index.js | 6 ++ .../src/backend/sql/listDatabases.js | 11 ++++ .../src/backend/sql/listProcesses.js | 13 +++++ .../src/backend/sql/listVariables.js | 5 ++ .../src/frontend/drivers.js | 3 + 6 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 plugins/dbgate-plugin-postgres/src/backend/sql/listDatabases.js create mode 100644 plugins/dbgate-plugin-postgres/src/backend/sql/listProcesses.js create mode 100644 plugins/dbgate-plugin-postgres/src/backend/sql/listVariables.js diff --git a/plugins/dbgate-plugin-postgres/src/backend/drivers.js b/plugins/dbgate-plugin-postgres/src/backend/drivers.js index 595b56b97..de81e3d19 100644 --- a/plugins/dbgate-plugin-postgres/src/backend/drivers.js +++ b/plugins/dbgate-plugin-postgres/src/backend/drivers.js @@ -6,6 +6,7 @@ const Analyser = require('./Analyser'); const wkx = require('wkx'); const pg = require('pg'); const pgCopyStreams = require('pg-copy-streams'); +const sql = require('./sql'); const { getLogger, createBulkInsertStreamBase, @@ -351,11 +352,65 @@ const drivers = driverBases.map(driverBase => ({ // @ts-ignore return createBulkInsertStreamBase(this, stream, dbhan, name, options); }, + + async serverSummary(dbhan) { + const [processes, variables, databases] = await Promise.all([ + this.listProcesses(dbhan), + this.listVariables(dbhan), + this.listDatabases(dbhan), + ]); + + /** @type {import('dbgate-types').ServerSummary} */ + const data = { + processes, + variables, + databases: { + rows: databases, + columns: [ + { header: 'Name', fieldName: 'name', type: 'data' }, + { header: 'Size on disk', fieldName: 'sizeOnDisk', type: 'fileSize' }, + ], + }, + }; + + return data; + }, + + async killProcess(dbhan, pid) { + const result = await this.query(dbhan, `SELECT pg_terminate_backend(${parseInt(pid)})`); + return result; + }, + async listDatabases(dbhan) { - const { rows } = await this.query(dbhan, 'SELECT datname AS name FROM pg_database WHERE datistemplate = false'); + const { rows } = await this.query(dbhan, sql.listDatabases); return rows; }, + async listVariables(dbhan) { + const result = await this.query(dbhan, sql.listVariables); + return result.rows.map(row => ({ + variable: row.variable, + value: row.value, + })); + }, + + async listProcesses(dbhan) { + const result = await this.query(dbhan, sql.listProcesses); + return result.rows.map(row => ({ + processId: row.processId, + connectionId: row.connectionId, + client: row.client, + operation: row.operation, + namespace: null, + command: row.operation, + runningTime: row.runningTime ? Math.max(Number(row.runningTime), 0) : null, + state: row.state, + waitingFor: row.waitingFor, + locks: null, + progress: null, + })); + }, + getAuthTypes() { const res = [ { diff --git a/plugins/dbgate-plugin-postgres/src/backend/sql/index.js b/plugins/dbgate-plugin-postgres/src/backend/sql/index.js index 8f648c64f..833153196 100644 --- a/plugins/dbgate-plugin-postgres/src/backend/sql/index.js +++ b/plugins/dbgate-plugin-postgres/src/backend/sql/index.js @@ -17,6 +17,9 @@ const geographyColumns = require('./geographyColumns'); const proceduresParameters = require('./proceduresParameters'); const foreignKeys = require('./foreignKeys'); const triggers = require('./triggers'); +const listDatabases = require('./listDatabases'); +const listVariables = require('./listVariables'); +const listProcesses = require('./listProcesses'); const fk_keyColumnUsage = require('./fk_key_column_usage'); @@ -41,4 +44,7 @@ module.exports = { geographyColumns, proceduresParameters, triggers, + listDatabases, + listVariables, + listProcesses, }; diff --git a/plugins/dbgate-plugin-postgres/src/backend/sql/listDatabases.js b/plugins/dbgate-plugin-postgres/src/backend/sql/listDatabases.js new file mode 100644 index 000000000..a033b9297 --- /dev/null +++ b/plugins/dbgate-plugin-postgres/src/backend/sql/listDatabases.js @@ -0,0 +1,11 @@ +module.exports = ` +SELECT + "datname" AS "name", + pg_database_size("datname") AS "sizeOnDisk", + 0 AS "tableCount", + 0 AS "viewCount", + 0 AS "matviewCount" +FROM "pg_database" +WHERE "datistemplate" = false +ORDER BY pg_database_size("datname") DESC +`; diff --git a/plugins/dbgate-plugin-postgres/src/backend/sql/listProcesses.js b/plugins/dbgate-plugin-postgres/src/backend/sql/listProcesses.js new file mode 100644 index 000000000..807dcad38 --- /dev/null +++ b/plugins/dbgate-plugin-postgres/src/backend/sql/listProcesses.js @@ -0,0 +1,13 @@ +module.exports = ` +SELECT + "pid" AS "processId", + "application_name" AS "client", + "client_addr" AS "connectionId", + "state" AS "state", + "query" AS "operation", + EXTRACT(EPOCH FROM (NOW() - "state_change")) AS "runningTime", + "wait_event" IS NOT NULL AS "waitingFor" +FROM "pg_stat_activity" +WHERE "state" IS NOT NULL +ORDER BY "pid" +`; diff --git a/plugins/dbgate-plugin-postgres/src/backend/sql/listVariables.js b/plugins/dbgate-plugin-postgres/src/backend/sql/listVariables.js new file mode 100644 index 000000000..0973f035b --- /dev/null +++ b/plugins/dbgate-plugin-postgres/src/backend/sql/listVariables.js @@ -0,0 +1,5 @@ +module.exports = ` +SELECT "name" AS "variable", "setting" AS "value" +FROM "pg_settings" +ORDER BY "name" +`; diff --git a/plugins/dbgate-plugin-postgres/src/frontend/drivers.js b/plugins/dbgate-plugin-postgres/src/frontend/drivers.js index e44bf8b6f..c67f1577e 100644 --- a/plugins/dbgate-plugin-postgres/src/frontend/drivers.js +++ b/plugins/dbgate-plugin-postgres/src/frontend/drivers.js @@ -361,6 +361,7 @@ EXECUTE FUNCTION function_name();`, /** @type {import('dbgate-types').EngineDriver} */ const postgresDriver = { ...postgresDriverBase, + supportsServerSummary: true, engine: 'postgres@dbgate-plugin-postgres', title: 'PostgreSQL', defaultPort: 5432, @@ -388,6 +389,7 @@ const postgresDriver = { /** @type {import('dbgate-types').EngineDriver} */ const cockroachDriver = { ...postgresDriverBase, + supportsServerSummary: true, engine: 'cockroach@dbgate-plugin-postgres', title: 'CockroachDB', defaultPort: 26257, @@ -403,6 +405,7 @@ const cockroachDriver = { /** @type {import('dbgate-types').EngineDriver} */ const redshiftDriver = { ...postgresDriverBase, + supportsServerSummary: true, dialect: { ...dialect, stringAgg: false, From b5ab1d6b33fb845127fdc4bc72bf5a7745224eeb Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 14 Aug 2025 21:36:34 +0200 Subject: [PATCH 015/659] fix: always convert seconds to fixed 3 when printing running time --- packages/web/src/widgets/SummaryProcesses.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web/src/widgets/SummaryProcesses.svelte b/packages/web/src/widgets/SummaryProcesses.svelte index 0a162b4cb..a6f51c832 100644 --- a/packages/web/src/widgets/SummaryProcesses.svelte +++ b/packages/web/src/widgets/SummaryProcesses.svelte @@ -47,7 +47,7 @@ function formatRunningTime(seconds: number): string { if (!seconds) return '-'; if (seconds < 60) return `${seconds.toFixed(3)}s`; - if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${seconds % 60}s`; + if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${(seconds % 60).toFixed(3)}s`; return `${Math.floor(seconds / 3600)}h ${Math.floor((seconds % 3600) / 60)}m`; } From 8f6783792fce44d70cd4374c27c90ae731c83728 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 14 Aug 2025 21:48:56 +0200 Subject: [PATCH 016/659] feat: add error handler for server summary tab --- packages/web/src/tabs/ServerSummaryTab.svelte | 83 +++++++++++++------ 1 file changed, 56 insertions(+), 27 deletions(-) diff --git a/packages/web/src/tabs/ServerSummaryTab.svelte b/packages/web/src/tabs/ServerSummaryTab.svelte index b16058fd1..e716d5123 100644 --- a/packages/web/src/tabs/ServerSummaryTab.svelte +++ b/packages/web/src/tabs/ServerSummaryTab.svelte @@ -82,33 +82,42 @@ wrapper /> {:then summary} -
    - serverSummarySelectedTab.set(index)} - tabs={[ - { - label: _t('serverSummaryTab.variables', { defaultMessage: 'Variables' }), - component: SummaryVariables, - props: { variables: summary.variables || [] }, - }, - { - label: _t('serverSummaryTab.processes', { defaultMessage: 'Processes' }), - component: SummaryProcesses, - props: { processes: summary.processes || [], conid }, - }, - { - label: _t('serverSummaryTab.databases', { defaultMessage: 'Databases' }), - component: SummaryDatabases, - props: { rows: summary.databases?.rows ?? [], columns: summary.databases?.columns ?? [] }, - }, - ]} - /> -
    + {#if 'errorMessage' in summary} +
    +
    +

    {_t('serverSummaryTab.errorTitle', { defaultMessage: 'Error loading server summary' })}

    +

    {summary.errorMessage}

    +
    +
    + {:else} +
    + serverSummarySelectedTab.set(index)} + tabs={[ + { + label: _t('serverSummaryTab.variables', { defaultMessage: 'Variables' }), + component: SummaryVariables, + props: { variables: summary.variables || [] }, + }, + { + label: _t('serverSummaryTab.processes', { defaultMessage: 'Processes' }), + component: SummaryProcesses, + props: { processes: summary.processes || [], conid }, + }, + { + label: _t('serverSummaryTab.databases', { defaultMessage: 'Databases' }), + component: SummaryDatabases, + props: { rows: summary.databases?.rows ?? [], columns: summary.databases?.columns ?? [] }, + }, + ]} + /> +
    + {/if} {/await} @@ -130,4 +139,24 @@ .action-separator { margin: 0 5px; } + + .error-wrapper { + display: flex; + align-items: center; + justify-content: center; + } + + .error-message { + background: var(--theme-bg-1); + border: 1px solid var(--theme-border); + border-radius: 4px; + padding: 20px; + max-width: 500px; + text-align: center; + } + + .error-message h3 { + color: var(--theme-font-error); + margin-top: 0; + } From 6a5672673488f8568b48d19d97e864c24bc5195a Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 14 Aug 2025 22:48:35 +0200 Subject: [PATCH 017/659] fix: refresh proccesses only if summary tab is opened --- packages/web/src/tabs/ServerSummaryTab.svelte | 11 +++++++++-- packages/web/src/widgets/SummaryProcesses.svelte | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/web/src/tabs/ServerSummaryTab.svelte b/packages/web/src/tabs/ServerSummaryTab.svelte index e716d5123..e923e73d8 100644 --- a/packages/web/src/tabs/ServerSummaryTab.svelte +++ b/packages/web/src/tabs/ServerSummaryTab.svelte @@ -28,9 +28,12 @@ import SummaryVariables from '../widgets/SummaryVariables.svelte'; import SummaryProcesses from '../widgets/SummaryProcesses.svelte'; import SummaryDatabases from '../widgets/SummaryDatabases.svelte'; - import { serverSummarySelectedTab } from '../stores'; + import { activeTabId, serverSummarySelectedTab } from '../stores'; + import { getContext } from 'svelte'; export let conid; + const tabid = getContext('tabid'); + $: isActiveTab = tabid === $activeTabId; let refreshToken = 0; @@ -107,7 +110,11 @@ { label: _t('serverSummaryTab.processes', { defaultMessage: 'Processes' }), component: SummaryProcesses, - props: { processes: summary.processes || [], conid }, + props: { + processes: summary.processes || [], + isSummaryOpened: isActiveTab, + conid, + }, }, { label: _t('serverSummaryTab.databases', { defaultMessage: 'Databases' }), diff --git a/packages/web/src/widgets/SummaryProcesses.svelte b/packages/web/src/widgets/SummaryProcesses.svelte index a6f51c832..175546c58 100644 --- a/packages/web/src/widgets/SummaryProcesses.svelte +++ b/packages/web/src/widgets/SummaryProcesses.svelte @@ -8,6 +8,7 @@ import { showSnackbarError, showSnackbarSuccess } from '../utility/snackbar'; export let conid; + export let isSummaryOpened: boolean = false; export let processes: DatabaseProcess[] = []; export let refreshInterval: number = 1000; export let tabVisible: boolean = false; @@ -53,7 +54,7 @@ onMount(() => { const intervalId = setInterval(() => { - if (!tabVisible) return; + if (!tabVisible || !isSummaryOpened) return; refreshProcesses(); }, refreshInterval); From c49b1a46f8796f58a5e7a6fdc50a8e4572977f4c Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 14 Aug 2025 22:48:42 +0200 Subject: [PATCH 018/659] feat: mysql server summary --- .../src/backend/drivers.js | 55 +++++++++++++++++++ .../src/frontend/drivers.js | 2 + 2 files changed, 57 insertions(+) diff --git a/plugins/dbgate-plugin-mysql/src/backend/drivers.js b/plugins/dbgate-plugin-mysql/src/backend/drivers.js index bd6bb5a02..95f87f8a6 100644 --- a/plugins/dbgate-plugin-mysql/src/backend/drivers.js +++ b/plugins/dbgate-plugin-mysql/src/backend/drivers.js @@ -200,6 +200,61 @@ const drivers = driverBases.map(driverBase => ({ const { rows } = await this.query(dbhan, 'show databases'); return rows.map(x => ({ name: x.Database })); }, + + async listVariables(dbhan) { + const { rows } = await this.query(dbhan, 'SHOW VARIABLES'); + return rows.map(row => ({ + variable: row.Variable_name, + value: row.Value, + })); + }, + + async listProcesses(dbhan) { + const { rows } = await this.query(dbhan, 'SHOW PROCESSLIST'); + return rows.map(row => ({ + processId: row.Id, + connectionId: null, + client: row.Host, + operation: row.Command, + namespace: row.Database, + runningTime: row.Time, + state: row.State, + waitingFor: row.State && row.State.includes('Waiting'), + })); + }, + + async killProcess(dbhan, processId) { + await this.query(dbhan, `KILL ${processId}`); + }, + + async serverSummary(dbhan) { + const [variables, processes, databases] = await Promise.all([ + this.listVariables(dbhan), + this.listProcesses(dbhan), + this.listDatabases(dbhan), + ]); + + return { + variables, + processes: processes.map(p => ({ + processId: p.processId, + connectionId: p.connectionId, + client: p.client, + operation: p.operation, + namespace: p.namespace, + runningTime: p.runningTime, + state: p.state, + waitingFor: p.waitingFor, + })), + databases: { + rows: databases.map(db => ({ + name: db.name, + })), + columns: [{ header: 'Database', fieldName: 'name', type: 'data' }], + }, + }; + }, + async writeTable(dbhan, name, options) { // @ts-ignore return createBulkInsertStreamBase(this, stream, dbhan, name, options); diff --git a/plugins/dbgate-plugin-mysql/src/frontend/drivers.js b/plugins/dbgate-plugin-mysql/src/frontend/drivers.js index 486942207..8e605068c 100644 --- a/plugins/dbgate-plugin-mysql/src/frontend/drivers.js +++ b/plugins/dbgate-plugin-mysql/src/frontend/drivers.js @@ -385,6 +385,7 @@ const mysqlDriverBase = { /** @type {import('dbgate-types').EngineDriver} */ const mysqlDriver = { ...mysqlDriverBase, + supportsServerSummary: true, dialect: mysqlDialect, engine: 'mysql@dbgate-plugin-mysql', title: 'MySQL', @@ -425,6 +426,7 @@ const mariaDbDialect = { /** @type {import('dbgate-types').EngineDriver} */ const mariaDriver = { ...mysqlDriverBase, + supportsServerSummary: true, dialect: mariaDbDialect, engine: 'mariadb@dbgate-plugin-mysql', title: 'MariaDB', From e4bf2b4c9b6903394627d25f535f3b36fa7e05f9 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 14 Aug 2025 22:48:51 +0200 Subject: [PATCH 019/659] feat: mssql server summary --- .../dbgate-plugin-mssql/src/backend/driver.js | 43 ++++++++++++++++++- .../src/backend/sql/index.js | 6 +++ .../src/backend/sql/listDatabases.js | 17 ++++++++ .../src/backend/sql/listProcesses.js | 11 +++++ .../src/backend/sql/listVariables.js | 3 ++ .../src/frontend/driver.js | 1 + 6 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 plugins/dbgate-plugin-mssql/src/backend/sql/listDatabases.js create mode 100644 plugins/dbgate-plugin-mssql/src/backend/sql/listProcesses.js create mode 100644 plugins/dbgate-plugin-mssql/src/backend/sql/listVariables.js diff --git a/plugins/dbgate-plugin-mssql/src/backend/driver.js b/plugins/dbgate-plugin-mssql/src/backend/driver.js index 8d16e35b8..7360b998c 100644 --- a/plugins/dbgate-plugin-mssql/src/backend/driver.js +++ b/plugins/dbgate-plugin-mssql/src/backend/driver.js @@ -9,6 +9,7 @@ const lock = new AsyncLock(); const { tediousConnect, tediousQueryCore, tediousReadQuery, tediousStream } = require('./tediousDriver'); const { nativeConnect, nativeQueryCore, nativeReadQuery, nativeStream } = require('./nativeDriver'); const { getLogger } = global.DBGATE_PACKAGES['dbgate-tools']; +const sql = require('./sql'); const logger = getLogger('mssqlDriver'); @@ -148,9 +149,49 @@ const driver = { return res; }, async listDatabases(dbhan) { - const { rows } = await this.query(dbhan, 'SELECT name FROM sys.databases order by name'); + const { rows } = await this.query(dbhan, sql.listDatabases); return rows; }, + + async listProcesses(dbhan) { + const { rows } = await this.query(dbhan, sql.listProcesses); + return rows; + }, + + async listVariables(dbhan) { + const { rows } = await this.query(dbhan, sql.listVariables); + return rows; + }, + + async killProcess(dbhan, processId) { + await this.query(dbhan, `KILL ${processId}`); + }, + + async serverSummary(dbhan) { + const [variables, processes, databases] = await Promise.all([ + this.listVariables(dbhan), + this.listProcesses(dbhan), + this.listDatabases(dbhan), + ]); + + return { + variables: variables, + processes: processes, + databases: { + rows: databases, + columns: [ + { header: 'Database', fieldName: 'name', type: 'data' }, + { header: 'Status', fieldName: 'status', type: 'data' }, + { header: 'Recovery Model', fieldName: 'recoveryModel', type: 'data' }, + { header: 'Compatibility Level', fieldName: 'compatibilityLevel', type: 'data' }, + { header: 'Read Only', fieldName: 'isReadOnly', type: 'data' }, + { header: 'Data Size', fieldName: 'sizeOnDisk', type: 'fileSize' }, + { header: 'Log Size', fieldName: 'logSizeOnDisk', type: 'fileSize' }, + ], + }, + }; + }, + getRedirectAuthUrl(connection, options) { if (connection.authType != 'msentra') return null; return authProxy.authProxyGetRedirectUrl({ diff --git a/plugins/dbgate-plugin-mssql/src/backend/sql/index.js b/plugins/dbgate-plugin-mssql/src/backend/sql/index.js index 4125b1ebd..f9426419f 100644 --- a/plugins/dbgate-plugin-mssql/src/backend/sql/index.js +++ b/plugins/dbgate-plugin-mssql/src/backend/sql/index.js @@ -13,6 +13,9 @@ const viewColumns = require('./viewColumns'); const indexes = require('./indexes'); const indexcols = require('./indexcols'); const triggers = require('./triggers'); +const listVariables = require('./listVariables'); +const listDatabases = require('./listDatabases'); +const listProcesses = require('./listProcesses'); module.exports = { columns, @@ -30,4 +33,7 @@ module.exports = { indexcols, tableSizes, triggers, + listVariables, + listDatabases, + listProcesses, }; diff --git a/plugins/dbgate-plugin-mssql/src/backend/sql/listDatabases.js b/plugins/dbgate-plugin-mssql/src/backend/sql/listDatabases.js new file mode 100644 index 000000000..751c54b39 --- /dev/null +++ b/plugins/dbgate-plugin-mssql/src/backend/sql/listDatabases.js @@ -0,0 +1,17 @@ +module.exports = ` + SELECT + d.name, + d.database_id, + d.state_desc as status, + d.recovery_model_desc as recoveryModel, + d.collation_name as collation, + d.compatibility_level as compatibilityLevel, + d.is_read_only as isReadOnly, + CAST(SUM(CASE WHEN mf.type = 0 THEN mf.size * 8192.0 ELSE 0 END) AS BIGINT) AS sizeOnDisk, + CAST(SUM(CASE WHEN mf.type = 1 THEN mf.size * 8192.0 ELSE 0 END) AS BIGINT) AS logSizeOnDisk + FROM sys.databases d + LEFT JOIN sys.master_files mf ON d.database_id = mf.database_id + GROUP BY d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.collation_name, + d.compatibility_level, d.is_read_only + ORDER BY d.name +`; diff --git a/plugins/dbgate-plugin-mssql/src/backend/sql/listProcesses.js b/plugins/dbgate-plugin-mssql/src/backend/sql/listProcesses.js new file mode 100644 index 000000000..30ffe5768 --- /dev/null +++ b/plugins/dbgate-plugin-mssql/src/backend/sql/listProcesses.js @@ -0,0 +1,11 @@ +module.exports = ` +SELECT + session_id as processId, + ISNULL(host_name, 'Unknown') + ':' + ISNULL(CAST(host_process_id AS VARCHAR(10)), '?') as client, + ISNULL(DB_NAME(database_id), 'master') as namespace, + ISNULL(DATEDIFF(SECOND, last_request_start_time, GETDATE()), 0) as runningTime, + status as state +FROM sys.dm_exec_sessions +WHERE is_user_process = 1 +ORDER BY session_id +`; diff --git a/plugins/dbgate-plugin-mssql/src/backend/sql/listVariables.js b/plugins/dbgate-plugin-mssql/src/backend/sql/listVariables.js new file mode 100644 index 000000000..a6543c759 --- /dev/null +++ b/plugins/dbgate-plugin-mssql/src/backend/sql/listVariables.js @@ -0,0 +1,3 @@ +module.exports = ` + SELECT name as variable, value FROM sys.configurations ORDER BY name +`; diff --git a/plugins/dbgate-plugin-mssql/src/frontend/driver.js b/plugins/dbgate-plugin-mssql/src/frontend/driver.js index 56c315e14..fd979122e 100644 --- a/plugins/dbgate-plugin-mssql/src/frontend/driver.js +++ b/plugins/dbgate-plugin-mssql/src/frontend/driver.js @@ -116,6 +116,7 @@ const dialect = { /** @type {import('dbgate-types').EngineDriver} */ const driver = { ...driverBase, + supportsServerSummary: true, dumperClass: MsSqlDumper, dialect, readOnlySessions: false, From ab924f6b48df3fb1924f3f92f19fcdff8e213fb3 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 14 Aug 2025 22:55:36 +0200 Subject: [PATCH 020/659] feat: confirm kill process --- packages/web/src/widgets/SummaryProcesses.svelte | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/web/src/widgets/SummaryProcesses.svelte b/packages/web/src/widgets/SummaryProcesses.svelte index 175546c58..995497ebe 100644 --- a/packages/web/src/widgets/SummaryProcesses.svelte +++ b/packages/web/src/widgets/SummaryProcesses.svelte @@ -6,6 +6,8 @@ import { apiCall } from '../utility/api'; import { onMount } from 'svelte'; import { showSnackbarError, showSnackbarSuccess } from '../utility/snackbar'; + import { showModal } from '../modals/modalTools'; + import ConfirmModal from '../modals/ConfirmModal.svelte'; export let conid; export let isSummaryOpened: boolean = false; @@ -45,6 +47,18 @@ refreshProcesses(); } + async function killProcessWithConfirm(processId: number) { + showModal(ConfirmModal, { + message: _t('summaryProcesses.killConfirm', { + defaultMessage: 'Are you sure you want to kill process {processId}?', + values: { processId }, + }), + onConfirm: async () => { + await killProcess(processId); + }, + }); + } + function formatRunningTime(seconds: number): string { if (!seconds) return '-'; if (seconds < 60) return `${seconds.toFixed(3)}s`; @@ -91,7 +105,7 @@ ]} > - killProcess(row.processId)}> + killProcessWithConfirm(row.processId)}> {_t('common.kill', { defaultMessage: 'Kill' })} From 78215552bf3ecfa3fb1b9e8550b3860f0bf3ae5d Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 19 Aug 2025 17:08:07 +0200 Subject: [PATCH 021/659] chore: add logging for server summary --- packages/api/src/controllers/serverConnections.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/api/src/controllers/serverConnections.js b/packages/api/src/controllers/serverConnections.js index b486d25e9..e490aa2e9 100644 --- a/packages/api/src/controllers/serverConnections.js +++ b/packages/api/src/controllers/serverConnections.js @@ -270,6 +270,7 @@ module.exports = { serverSummary_meta: true, async serverSummary({ conid }, req) { + logger.info({ conid }, 'DBGM-00260 Processing server summary'); testConnectionPermission(conid, req); return this.loadDataCore('serverSummary', { conid }); }, @@ -277,6 +278,7 @@ module.exports = { listDatabaseProcesses_meta: true, async listDatabaseProcesses(ctx, req) { const { conid } = ctx; + logger.info({ conid }, 'DBGM-00261 Processing server summary'); testConnectionPermission(conid, req); const opened = await this.ensureOpened(conid); From 114ce1ea3acc907089912b20df137c2ac0b98663 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 19 Aug 2025 17:08:38 +0200 Subject: [PATCH 022/659] feat: make summary table sortable, filtrable, with sticky header --- packages/types/engines.d.ts | 2 + .../web/src/widgets/SummaryDatabases.svelte | 7 ++- .../web/src/widgets/SummaryProcesses.svelte | 49 ++++++++++++++--- .../web/src/widgets/SummaryVariables.svelte | 14 ++++- .../dbgate-plugin-mongo/src/backend/driver.js | 23 ++++++-- .../dbgate-plugin-mssql/src/backend/driver.js | 54 ++++++++++++++++--- .../src/backend/drivers.js | 10 +++- 7 files changed, 140 insertions(+), 19 deletions(-) diff --git a/packages/types/engines.d.ts b/packages/types/engines.d.ts index b19d1aa88..0daf4c172 100644 --- a/packages/types/engines.d.ts +++ b/packages/types/engines.d.ts @@ -131,6 +131,8 @@ export type SummaryDatabaseColumn = { header: string; fieldName: string; type: 'data' | 'fileSize'; + filterable?: boolean; + sortable?: boolean; }; export interface ServerSummary { diff --git a/packages/web/src/widgets/SummaryDatabases.svelte b/packages/web/src/widgets/SummaryDatabases.svelte index 91ecf2fa1..be29fd98f 100644 --- a/packages/web/src/widgets/SummaryDatabases.svelte +++ b/packages/web/src/widgets/SummaryDatabases.svelte @@ -1,11 +1,16 @@
    - +
    diff --git a/packages/web/src/widgets/SummaryProcesses.svelte b/packages/web/src/widgets/SummaryProcesses.svelte index 133134e14..9966f2b4b 100644 --- a/packages/web/src/widgets/SummaryProcesses.svelte +++ b/packages/web/src/widgets/SummaryProcesses.svelte @@ -80,7 +80,7 @@ }); -
    +
    From 176d75768f8ebdd76659934ddb404e9925b408ba Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 19 Aug 2025 18:40:08 +0200 Subject: [PATCH 024/659] feat: vertical split for process operation --- .../web/src/widgets/SummaryProcesses.svelte | 166 ++++++++++-------- 1 file changed, 92 insertions(+), 74 deletions(-) diff --git a/packages/web/src/widgets/SummaryProcesses.svelte b/packages/web/src/widgets/SummaryProcesses.svelte index 9966f2b4b..9ce57e33c 100644 --- a/packages/web/src/widgets/SummaryProcesses.svelte +++ b/packages/web/src/widgets/SummaryProcesses.svelte @@ -1,6 +1,7 @@
    - - - killProcessWithConfirm(row.processId)}> - {_t('common.kill', { defaultMessage: 'Kill' })} - - + + +
    + { + selectedProcess = e.detail; + }} + {filters} + stickyHeader + rows={internalProcesses} + columns={[ + { + sortable: true, + filterable: true, + header: _t('summaryProcesses.processId', { defaultMessage: 'Process ID' }), + fieldName: 'processId', + slot: 1, + }, + { + sortable: true, + filterable: true, + header: _t('summaryProcesses.connectionId', { defaultMessage: 'Connection ID' }), + fieldName: 'connectionId', + }, + { + sortable: true, + filterable: true, + header: _t('summaryProcesses.client', { defaultMessage: 'Client' }), + fieldName: 'client', + }, + { + filterable: true, + header: _t('summaryProcesses.operation', { defaultMessage: 'Operation' }), + fieldName: 'operation', + }, + { + sortable: true, + filterable: true, + header: _t('summaryProcesses.namespace', { defaultMessage: 'Namespace' }), + fieldName: 'namespace', + }, + { + sortable: true, + header: _t('summaryProcesses.runningTime', { defaultMessage: 'Running Time' }), + fieldName: 'runningTime', + slot: 2, + }, + { + sortable: true, + filterable: true, + header: _t('summaryProcesses.state', { defaultMessage: 'State' }), + fieldName: 'state', + }, + { + sortable: true, + header: _t('summaryProcesses.waitingFor', { defaultMessage: 'Waiting For' }), + fieldName: 'waitingFor', + slot: 3, + }, + { + header: _t('summaryProcesses.actions', { defaultMessage: 'Actions' }), + fieldName: 'processId', + slot: 0, + }, + ]} + > + + killProcessWithConfirm(row.processId)}> + {_t('common.kill', { defaultMessage: 'Kill' })} + + - - {row.processId} - + + {row.processId} + - - {formatRunningTime(row.runningTime)} - + + {formatRunningTime(row.runningTime)} + - - {row.waitingFor ? 'Yes' : 'No'} + + {row.waitingFor ? 'Yes' : 'No'} + + +
    -
    + + {#if !!selectedProcess} + + {/if} + +
    From 75c47a11130d70fca5d909e42de8578509e8a968 Mon Sep 17 00:00:00 2001 From: CI workflows Date: Mon, 25 Aug 2025 14:24:46 +0000 Subject: [PATCH 045/659] Update pro ref --- workflow-templates/includes.tpl.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-templates/includes.tpl.yaml b/workflow-templates/includes.tpl.yaml index a1454a780..d635af88f 100644 --- a/workflow-templates/includes.tpl.yaml +++ b/workflow-templates/includes.tpl.yaml @@ -7,7 +7,7 @@ checkout-and-merge-pro: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 2f11747743b1734a3aac7bc175977731d2b31044 + ref: a83aefd73bf4e5b9a4076f2341c7ef61281ff730 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro From d5894b9fb708ee9bd1b39041cbba02aecbaf9744 Mon Sep 17 00:00:00 2001 From: CI workflows Date: Mon, 25 Aug 2025 14:25:01 +0000 Subject: [PATCH 046/659] chore: auto-update github workflows --- .github/workflows/build-app-pro-beta.yaml | 2 +- .github/workflows/build-app-pro.yaml | 2 +- .github/workflows/build-cloud-pro.yaml | 2 +- .github/workflows/build-docker-pro.yaml | 2 +- .github/workflows/build-npm-pro.yaml | 2 +- .github/workflows/e2e-pro.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-app-pro-beta.yaml b/.github/workflows/build-app-pro-beta.yaml index f5f03ae79..9ba54bb80 100644 --- a/.github/workflows/build-app-pro-beta.yaml +++ b/.github/workflows/build-app-pro-beta.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 2f11747743b1734a3aac7bc175977731d2b31044 + ref: a83aefd73bf4e5b9a4076f2341c7ef61281ff730 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-app-pro.yaml b/.github/workflows/build-app-pro.yaml index b1ecaa5ea..cb75120e1 100644 --- a/.github/workflows/build-app-pro.yaml +++ b/.github/workflows/build-app-pro.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 2f11747743b1734a3aac7bc175977731d2b31044 + ref: a83aefd73bf4e5b9a4076f2341c7ef61281ff730 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-cloud-pro.yaml b/.github/workflows/build-cloud-pro.yaml index b5137246f..834d3f72c 100644 --- a/.github/workflows/build-cloud-pro.yaml +++ b/.github/workflows/build-cloud-pro.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 2f11747743b1734a3aac7bc175977731d2b31044 + ref: a83aefd73bf4e5b9a4076f2341c7ef61281ff730 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-docker-pro.yaml b/.github/workflows/build-docker-pro.yaml index e81a5979b..345dee180 100644 --- a/.github/workflows/build-docker-pro.yaml +++ b/.github/workflows/build-docker-pro.yaml @@ -44,7 +44,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 2f11747743b1734a3aac7bc175977731d2b31044 + ref: a83aefd73bf4e5b9a4076f2341c7ef61281ff730 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-npm-pro.yaml b/.github/workflows/build-npm-pro.yaml index 1dc4c8e2b..dc25c3714 100644 --- a/.github/workflows/build-npm-pro.yaml +++ b/.github/workflows/build-npm-pro.yaml @@ -32,7 +32,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 2f11747743b1734a3aac7bc175977731d2b31044 + ref: a83aefd73bf4e5b9a4076f2341c7ef61281ff730 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/e2e-pro.yaml b/.github/workflows/e2e-pro.yaml index 47856db25..eb3670ce8 100644 --- a/.github/workflows/e2e-pro.yaml +++ b/.github/workflows/e2e-pro.yaml @@ -26,7 +26,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 2f11747743b1734a3aac7bc175977731d2b31044 + ref: a83aefd73bf4e5b9a4076f2341c7ef61281ff730 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro From e7963aa324791156c76053371d79fe41b4287c61 Mon Sep 17 00:00:00 2001 From: CI workflows Date: Mon, 25 Aug 2025 14:37:41 +0000 Subject: [PATCH 047/659] Update pro ref --- workflow-templates/includes.tpl.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-templates/includes.tpl.yaml b/workflow-templates/includes.tpl.yaml index d635af88f..59a3cc379 100644 --- a/workflow-templates/includes.tpl.yaml +++ b/workflow-templates/includes.tpl.yaml @@ -7,7 +7,7 @@ checkout-and-merge-pro: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: a83aefd73bf4e5b9a4076f2341c7ef61281ff730 + ref: 3438c79611bf9825cc6406c4fb7adf0c7063902d - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro From 40beb7ceebae07d0d6edf78180ebef9537e9e3c5 Mon Sep 17 00:00:00 2001 From: CI workflows Date: Mon, 25 Aug 2025 14:37:58 +0000 Subject: [PATCH 048/659] chore: auto-update github workflows --- .github/workflows/build-app-pro-beta.yaml | 2 +- .github/workflows/build-app-pro.yaml | 2 +- .github/workflows/build-cloud-pro.yaml | 2 +- .github/workflows/build-docker-pro.yaml | 2 +- .github/workflows/build-npm-pro.yaml | 2 +- .github/workflows/e2e-pro.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-app-pro-beta.yaml b/.github/workflows/build-app-pro-beta.yaml index 9ba54bb80..3cfd711f5 100644 --- a/.github/workflows/build-app-pro-beta.yaml +++ b/.github/workflows/build-app-pro-beta.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: a83aefd73bf4e5b9a4076f2341c7ef61281ff730 + ref: 3438c79611bf9825cc6406c4fb7adf0c7063902d - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-app-pro.yaml b/.github/workflows/build-app-pro.yaml index cb75120e1..7876527f7 100644 --- a/.github/workflows/build-app-pro.yaml +++ b/.github/workflows/build-app-pro.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: a83aefd73bf4e5b9a4076f2341c7ef61281ff730 + ref: 3438c79611bf9825cc6406c4fb7adf0c7063902d - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-cloud-pro.yaml b/.github/workflows/build-cloud-pro.yaml index 834d3f72c..cce642b58 100644 --- a/.github/workflows/build-cloud-pro.yaml +++ b/.github/workflows/build-cloud-pro.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: a83aefd73bf4e5b9a4076f2341c7ef61281ff730 + ref: 3438c79611bf9825cc6406c4fb7adf0c7063902d - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-docker-pro.yaml b/.github/workflows/build-docker-pro.yaml index 345dee180..b187655a7 100644 --- a/.github/workflows/build-docker-pro.yaml +++ b/.github/workflows/build-docker-pro.yaml @@ -44,7 +44,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: a83aefd73bf4e5b9a4076f2341c7ef61281ff730 + ref: 3438c79611bf9825cc6406c4fb7adf0c7063902d - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-npm-pro.yaml b/.github/workflows/build-npm-pro.yaml index dc25c3714..431fd421f 100644 --- a/.github/workflows/build-npm-pro.yaml +++ b/.github/workflows/build-npm-pro.yaml @@ -32,7 +32,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: a83aefd73bf4e5b9a4076f2341c7ef61281ff730 + ref: 3438c79611bf9825cc6406c4fb7adf0c7063902d - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/e2e-pro.yaml b/.github/workflows/e2e-pro.yaml index eb3670ce8..6aaa87054 100644 --- a/.github/workflows/e2e-pro.yaml +++ b/.github/workflows/e2e-pro.yaml @@ -26,7 +26,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: a83aefd73bf4e5b9a4076f2341c7ef61281ff730 + ref: 3438c79611bf9825cc6406c4fb7adf0c7063902d - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro From 08646ea12a7ff32e1cda0a58e0c2d814ee1aee55 Mon Sep 17 00:00:00 2001 From: CI workflows Date: Tue, 26 Aug 2025 07:27:36 +0000 Subject: [PATCH 049/659] Update pro ref --- workflow-templates/includes.tpl.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-templates/includes.tpl.yaml b/workflow-templates/includes.tpl.yaml index 59a3cc379..be83aa4bc 100644 --- a/workflow-templates/includes.tpl.yaml +++ b/workflow-templates/includes.tpl.yaml @@ -7,7 +7,7 @@ checkout-and-merge-pro: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 3438c79611bf9825cc6406c4fb7adf0c7063902d + ref: ae174ba4ffacd5980d6ee6a1ee737faddcf1608a - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro From 0b4895addf887030fc620a44b3ea350ec8d1b8d1 Mon Sep 17 00:00:00 2001 From: CI workflows Date: Tue, 26 Aug 2025 07:27:54 +0000 Subject: [PATCH 050/659] chore: auto-update github workflows --- .github/workflows/build-app-pro-beta.yaml | 2 +- .github/workflows/build-app-pro.yaml | 2 +- .github/workflows/build-cloud-pro.yaml | 2 +- .github/workflows/build-docker-pro.yaml | 2 +- .github/workflows/build-npm-pro.yaml | 2 +- .github/workflows/e2e-pro.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-app-pro-beta.yaml b/.github/workflows/build-app-pro-beta.yaml index 3cfd711f5..245221464 100644 --- a/.github/workflows/build-app-pro-beta.yaml +++ b/.github/workflows/build-app-pro-beta.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 3438c79611bf9825cc6406c4fb7adf0c7063902d + ref: ae174ba4ffacd5980d6ee6a1ee737faddcf1608a - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-app-pro.yaml b/.github/workflows/build-app-pro.yaml index 7876527f7..9ef8d0350 100644 --- a/.github/workflows/build-app-pro.yaml +++ b/.github/workflows/build-app-pro.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 3438c79611bf9825cc6406c4fb7adf0c7063902d + ref: ae174ba4ffacd5980d6ee6a1ee737faddcf1608a - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-cloud-pro.yaml b/.github/workflows/build-cloud-pro.yaml index cce642b58..3ecdb778b 100644 --- a/.github/workflows/build-cloud-pro.yaml +++ b/.github/workflows/build-cloud-pro.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 3438c79611bf9825cc6406c4fb7adf0c7063902d + ref: ae174ba4ffacd5980d6ee6a1ee737faddcf1608a - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-docker-pro.yaml b/.github/workflows/build-docker-pro.yaml index b187655a7..254442e4a 100644 --- a/.github/workflows/build-docker-pro.yaml +++ b/.github/workflows/build-docker-pro.yaml @@ -44,7 +44,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 3438c79611bf9825cc6406c4fb7adf0c7063902d + ref: ae174ba4ffacd5980d6ee6a1ee737faddcf1608a - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-npm-pro.yaml b/.github/workflows/build-npm-pro.yaml index 431fd421f..9deb049c4 100644 --- a/.github/workflows/build-npm-pro.yaml +++ b/.github/workflows/build-npm-pro.yaml @@ -32,7 +32,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 3438c79611bf9825cc6406c4fb7adf0c7063902d + ref: ae174ba4ffacd5980d6ee6a1ee737faddcf1608a - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/e2e-pro.yaml b/.github/workflows/e2e-pro.yaml index 6aaa87054..a12fb5dc2 100644 --- a/.github/workflows/e2e-pro.yaml +++ b/.github/workflows/e2e-pro.yaml @@ -26,7 +26,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 3438c79611bf9825cc6406c4fb7adf0c7063902d + ref: ae174ba4ffacd5980d6ee6a1ee737faddcf1608a - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro From cffb1b87137911db91b94fb8a431493c5964192b Mon Sep 17 00:00:00 2001 From: CI workflows Date: Tue, 26 Aug 2025 07:45:06 +0000 Subject: [PATCH 051/659] Update pro ref --- workflow-templates/includes.tpl.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-templates/includes.tpl.yaml b/workflow-templates/includes.tpl.yaml index be83aa4bc..a418e1d13 100644 --- a/workflow-templates/includes.tpl.yaml +++ b/workflow-templates/includes.tpl.yaml @@ -7,7 +7,7 @@ checkout-and-merge-pro: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: ae174ba4ffacd5980d6ee6a1ee737faddcf1608a + ref: 742d5c1c1734ee3fd2e9748c775228766f368dea - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro From af83b8981226ab9c4fd162ba76a2fe85930c9005 Mon Sep 17 00:00:00 2001 From: CI workflows Date: Tue, 26 Aug 2025 07:45:32 +0000 Subject: [PATCH 052/659] chore: auto-update github workflows --- .github/workflows/build-app-pro-beta.yaml | 2 +- .github/workflows/build-app-pro.yaml | 2 +- .github/workflows/build-cloud-pro.yaml | 2 +- .github/workflows/build-docker-pro.yaml | 2 +- .github/workflows/build-npm-pro.yaml | 2 +- .github/workflows/e2e-pro.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-app-pro-beta.yaml b/.github/workflows/build-app-pro-beta.yaml index 245221464..de3b2c298 100644 --- a/.github/workflows/build-app-pro-beta.yaml +++ b/.github/workflows/build-app-pro-beta.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: ae174ba4ffacd5980d6ee6a1ee737faddcf1608a + ref: 742d5c1c1734ee3fd2e9748c775228766f368dea - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-app-pro.yaml b/.github/workflows/build-app-pro.yaml index 9ef8d0350..ed91fa041 100644 --- a/.github/workflows/build-app-pro.yaml +++ b/.github/workflows/build-app-pro.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: ae174ba4ffacd5980d6ee6a1ee737faddcf1608a + ref: 742d5c1c1734ee3fd2e9748c775228766f368dea - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-cloud-pro.yaml b/.github/workflows/build-cloud-pro.yaml index 3ecdb778b..429d5a057 100644 --- a/.github/workflows/build-cloud-pro.yaml +++ b/.github/workflows/build-cloud-pro.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: ae174ba4ffacd5980d6ee6a1ee737faddcf1608a + ref: 742d5c1c1734ee3fd2e9748c775228766f368dea - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-docker-pro.yaml b/.github/workflows/build-docker-pro.yaml index 254442e4a..1a91833b9 100644 --- a/.github/workflows/build-docker-pro.yaml +++ b/.github/workflows/build-docker-pro.yaml @@ -44,7 +44,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: ae174ba4ffacd5980d6ee6a1ee737faddcf1608a + ref: 742d5c1c1734ee3fd2e9748c775228766f368dea - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-npm-pro.yaml b/.github/workflows/build-npm-pro.yaml index 9deb049c4..01e5dd70a 100644 --- a/.github/workflows/build-npm-pro.yaml +++ b/.github/workflows/build-npm-pro.yaml @@ -32,7 +32,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: ae174ba4ffacd5980d6ee6a1ee737faddcf1608a + ref: 742d5c1c1734ee3fd2e9748c775228766f368dea - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/e2e-pro.yaml b/.github/workflows/e2e-pro.yaml index a12fb5dc2..00c4ad532 100644 --- a/.github/workflows/e2e-pro.yaml +++ b/.github/workflows/e2e-pro.yaml @@ -26,7 +26,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: ae174ba4ffacd5980d6ee6a1ee737faddcf1608a + ref: 742d5c1c1734ee3fd2e9748c775228766f368dea - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro From 98422bd3558e519e0bd17e2c24249f3875b673ab Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Tue, 26 Aug 2025 10:10:55 +0200 Subject: [PATCH 053/659] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 915b1cb47..d77e83306 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ Builds: - linux - application for linux - win - application for Windows +## 6.6.2 - not published +- ADDED: List of processes, ability to kill process (Server summary) #1178 +- ADDED: Database and table permissions (Team Premium edition) + ## 6.6.1 - ADDED: Support for Mongo shell (Premium) - #1114 - FIXED: Support for BLOB in Oracle #1181 From e88092cde70baff2925f8cd3960ba0dcca9b40c7 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Tue, 26 Aug 2025 10:11:16 +0200 Subject: [PATCH 054/659] v6.6.2-premium-beta.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 50eff895f..0b8e8bac9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "6.6.2-beta.4", + "version": "6.6.2-premium-beta.5", "name": "dbgate-all", "workspaces": [ "packages/*", From 003dec269abba36bc1a0eac2d99e4d720d570202 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Tue, 26 Aug 2025 10:30:30 +0200 Subject: [PATCH 055/659] Allow max page size 50000 #1185 --- packages/web/src/datagrid/LoadingDataGridCore.svelte | 2 +- packages/web/src/datagrid/SqlDataGridCore.svelte | 2 +- packages/web/src/settings/SettingsModal.svelte | 2 +- packages/web/src/tabs/AppLogTab.svelte | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/web/src/datagrid/LoadingDataGridCore.svelte b/packages/web/src/datagrid/LoadingDataGridCore.svelte index 366b1e49a..a1b418efb 100644 --- a/packages/web/src/datagrid/LoadingDataGridCore.svelte +++ b/packages/web/src/datagrid/LoadingDataGridCore.svelte @@ -54,7 +54,7 @@ const nextRows = await loadDataPage( $$props, loadedRows.length, - getIntSettingsValue('dataGrid.pageSize', 100, 5, 1000) + getIntSettingsValue('dataGrid.pageSize', 100, 5, 50000) ); if (loadedTimeRef.get() !== loadStart) { // new load was dispatched diff --git a/packages/web/src/datagrid/SqlDataGridCore.svelte b/packages/web/src/datagrid/SqlDataGridCore.svelte index f1134aca5..61f18cd14 100644 --- a/packages/web/src/datagrid/SqlDataGridCore.svelte +++ b/packages/web/src/datagrid/SqlDataGridCore.svelte @@ -144,7 +144,7 @@ } function openQueryOnError() { - openQuery(display.getPageQueryText(0, getIntSettingsValue('dataGrid.pageSize', 100, 5, 1000))); + openQuery(display.getPageQueryText(0, getIntSettingsValue('dataGrid.pageSize', 100, 5, 50000))); } const quickExportHandler = fmt => async () => { diff --git a/packages/web/src/settings/SettingsModal.svelte b/packages/web/src/settings/SettingsModal.svelte index 444310490..1ba6b85c0 100644 --- a/packages/web/src/settings/SettingsModal.svelte +++ b/packages/web/src/settings/SettingsModal.svelte @@ -157,7 +157,7 @@ ORDER BY
    Data grid
    diff --git a/packages/web/src/tabs/AppLogTab.svelte b/packages/web/src/tabs/AppLogTab.svelte index 91cef6db9..f42b7130a 100644 --- a/packages/web/src/tabs/AppLogTab.svelte +++ b/packages/web/src/tabs/AppLogTab.svelte @@ -51,7 +51,7 @@ } async function loadNextRows() { - const pageSize = getIntSettingsValue('dataGrid.pageSize', 100, 5, 1000); + const pageSize = getIntSettingsValue('dataGrid.pageSize', 100, 5, 50000); const rows = await apiCall('jsldata/get-rows', { jslid, offset: loadedRows.length, From d3872ca8a35b3f632b4ab2110405e7c22eaf08c9 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Tue, 26 Aug 2025 10:48:19 +0200 Subject: [PATCH 056/659] Redis "Scan all" button --- packages/web/src/icons/FontIcon.svelte | 1 + packages/web/src/widgets/DbKeysTree.svelte | 26 +++++++++++++++---- .../dbgate-plugin-redis/src/backend/driver.js | 2 +- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/packages/web/src/icons/FontIcon.svelte b/packages/web/src/icons/FontIcon.svelte index 238686d4e..107fe1314 100644 --- a/packages/web/src/icons/FontIcon.svelte +++ b/packages/web/src/icons/FontIcon.svelte @@ -226,6 +226,7 @@ 'icon type-unknown': 'mdi mdi-help-box', 'icon equal': 'mdi mdi-equal', 'icon not-equal': 'mdi mdi-not-equal-variant', + 'icon warn': 'mdi mdi-alert', 'icon at': 'mdi mdi-at', 'icon expand-all': 'mdi mdi-expand-all', diff --git a/packages/web/src/widgets/DbKeysTree.svelte b/packages/web/src/widgets/DbKeysTree.svelte index 8512a9c71..512198a44 100644 --- a/packages/web/src/widgets/DbKeysTree.svelte +++ b/packages/web/src/widgets/DbKeysTree.svelte @@ -33,6 +33,7 @@ import AppObjectListHandler from './AppObjectListHandler.svelte'; import { getOpenDetailOnArrowsSettings } from '../settings/settingsTools'; import openNewTab from '../utility/openNewTab'; + import ConfirmModal from '../modals/ConfirmModal.svelte'; export let conid; export let database; @@ -83,20 +84,30 @@ if (loadNext) loadNextPage(); } - async function loadNextPage() { + async function loadNextPage(skipCount = false) { isLoading = true; const nextScan = await apiCall('database-connections/scan-keys', { conid, database, pattern: filter, cursor: model.cursor, - count: model.loadCount, + count: skipCount ? undefined : model.loadCount, }); model = dbKeys_mergeNextPage(model, nextScan); isLoading = false; } + async function loadAll() { + showModal(ConfirmModal, { + message: + 'This will scan all keys in the database, which could affect server performance. Do you want to continue?', + onConfirm: () => { + loadNextPage(true); + }, + }); + } + function reloadModel() { changeModel(model => dbKeys_clearLoadedData(model), true); } @@ -145,9 +156,14 @@
    {:else} - - Scan more - +
    + loadNextPage()} title="Scan more keys"> + Scan more + + loadAll()} title="Scan all keys"> + Scan all + +
    {/if}
    {/if} diff --git a/plugins/dbgate-plugin-redis/src/backend/driver.js b/plugins/dbgate-plugin-redis/src/backend/driver.js index ea8991c40..3603bf25f 100644 --- a/plugins/dbgate-plugin-redis/src/backend/driver.js +++ b/plugins/dbgate-plugin-redis/src/backend/driver.js @@ -203,7 +203,7 @@ const driver = { async scanKeys(dbhan, pattern, cursor = 0, count) { const match = pattern?.match(/[\?\[\{]/) ? pattern : pattern ? `*${pattern}*` : '*'; - const [nextCursor, keys] = await dbhan.client.scan(cursor, 'MATCH', match, 'COUNT', count); + const [nextCursor, keys] = await dbhan.client.scan(cursor, 'MATCH', match, 'COUNT', count ?? 2 ** 32); const dbsize = await dbhan.client.dbsize(); const keysMapped = keys.map((key) => ({ key, From d1e0c86a712829fa04bdb5a3ce19dfc7d73a4011 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 26 Aug 2025 18:05:08 +0200 Subject: [PATCH 057/659] feat: add ep.class = 1 filter --- .../src/backend/sql/columns.js | 22 ++++++++++--------- .../src/backend/sql/tables.js | 1 + 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/plugins/dbgate-plugin-mssql/src/backend/sql/columns.js b/plugins/dbgate-plugin-mssql/src/backend/sql/columns.js index ad4b67781..6ccebbb3d 100644 --- a/plugins/dbgate-plugin-mssql/src/backend/sql/columns.js +++ b/plugins/dbgate-plugin-mssql/src/backend/sql/columns.js @@ -1,14 +1,13 @@ module.exports = ` select c.name as columnName, t.name as dataType, c.object_id as objectId, c.is_identity as isIdentity, - c.max_length as maxLength, c.precision, c.scale, c.is_nullable as isNullable, - col.CHARACTER_MAXIMUM_LENGTH as charMaxLength, - d.definition as defaultValue, d.name as defaultConstraint, - m.definition as computedExpression, m.is_persisted as isPersisted, c.column_id as columnId, - col.NUMERIC_PRECISION as numericPrecision, - col.NUMERIC_SCALE as numericScale, - -- TODO only if version >= 2008 - c.is_sparse as isSparse, - ep.value as columnComment + c.max_length as maxLength, c.precision, c.scale, c.is_nullable as isNullable, + col.CHARACTER_MAXIMUM_LENGTH as charMaxLength, + d.definition as defaultValue, d.name as defaultConstraint, + m.definition as computedExpression, m.is_persisted as isPersisted, c.column_id as columnId, + col.NUMERIC_PRECISION as numericPrecision, + col.NUMERIC_SCALE as numericScale, + c.is_sparse as isSparse, + ep.value as columnComment from sys.columns c inner join sys.types t on c.system_type_id = t.system_type_id and c.user_type_id = t.user_type_id inner join sys.objects o on c.object_id = o.object_id @@ -16,7 +15,10 @@ INNER JOIN sys.schemas u ON u.schema_id=o.schema_id INNER JOIN INFORMATION_SCHEMA.COLUMNS col ON col.TABLE_NAME = o.name AND col.TABLE_SCHEMA = u.name and col.COLUMN_NAME = c.name left join sys.default_constraints d on c.default_object_id = d.object_id left join sys.computed_columns m on m.object_id = c.object_id and m.column_id = c.column_id -left join sys.extended_properties ep on ep.major_id = c.object_id and ep.minor_id = c.column_id and ep.name = 'MS_Description' +left join sys.extended_properties ep on ep.major_id = c.object_id + and ep.minor_id = c.column_id + and ep.name = 'MS_Description' + and ep.class = 1 -- Add this filter for object/column level properties where o.type = 'U' and o.object_id =OBJECT_ID_CONDITION and u.name =SCHEMA_NAME_CONDITION order by c.column_id `; diff --git a/plugins/dbgate-plugin-mssql/src/backend/sql/tables.js b/plugins/dbgate-plugin-mssql/src/backend/sql/tables.js index 17887761a..f8289eeb9 100644 --- a/plugins/dbgate-plugin-mssql/src/backend/sql/tables.js +++ b/plugins/dbgate-plugin-mssql/src/backend/sql/tables.js @@ -11,4 +11,5 @@ inner join sys.schemas s on o.schema_id = s.schema_id left join sys.extended_properties ep on ep.major_id = o.object_id and ep.minor_id = 0 and ep.name = 'MS_Description' + and ep.class = 1 -- Add this filter for object/column level properties where o.object_id =OBJECT_ID_CONDITION and s.name =SCHEMA_NAME_CONDITION`; From 149abdef9b68f8ca9d96874bd55075361ca76258 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Thu, 28 Aug 2025 15:07:00 +0200 Subject: [PATCH 058/659] v6.6.2-premium-beta.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0b8e8bac9..de24d92bc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "6.6.2-premium-beta.5", + "version": "6.6.2-premium-beta.3", "name": "dbgate-all", "workspaces": [ "packages/*", From 111a7f72f83fd6250ca1c3b75f5c635b68138409 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Thu, 28 Aug 2025 15:07:14 +0200 Subject: [PATCH 059/659] v6.6.2-premium-beta.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index de24d92bc..df3cc97b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "6.6.2-premium-beta.3", + "version": "6.6.2-premium-beta.6", "name": "dbgate-all", "workspaces": [ "packages/*", From d7d5b29b0756061f338c1a1c1c6b569daac18735 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Thu, 28 Aug 2025 17:55:22 +0200 Subject: [PATCH 060/659] change log --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d77e83306..9de49977f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ Builds: ## 6.6.2 - not published - ADDED: List of processes, ability to kill process (Server summary) #1178 - ADDED: Database and table permissions (Team Premium edition) +- ADDED: Redis search box - Scan all #1191 +- FIXED: Optimalized loading SQL server with descriptions #1187 +- CHANGED: Allow a much greater page size #1185 ## 6.6.1 - ADDED: Support for Mongo shell (Premium) - #1114 From c913929ff906479c31e75cf1695855f8309563c2 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Fri, 29 Aug 2025 08:31:14 +0200 Subject: [PATCH 061/659] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9de49977f..a96703162 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ Builds: - linux - application for linux - win - application for Windows -## 6.6.2 - not published +## 6.6.2 - ADDED: List of processes, ability to kill process (Server summary) #1178 - ADDED: Database and table permissions (Team Premium edition) - ADDED: Redis search box - Scan all #1191 From 4a32dfc71b767106bb6a165cf4d2c950ecc7c62f Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Fri, 29 Aug 2025 08:39:19 +0200 Subject: [PATCH 062/659] fixed: DBGate cannot execute any queries and the process is killed #1195 --- packages/api/src/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/api/src/index.js b/packages/api/src/index.js index 17f55ed7a..61816a866 100644 --- a/packages/api/src/index.js +++ b/packages/api/src/index.js @@ -5,6 +5,7 @@ const moment = require('moment'); const path = require('path'); const { logsdir, setLogsFilePath, getLogsFilePath } = require('./utility/directories'); const currentVersion = require('./currentVersion'); +const _ = require('lodash'); const logger = getLogger('apiIndex'); @@ -68,7 +69,7 @@ function configureLogger() { } const additionals = {}; const finalMsg = - msg.msg && msg.msg.match(/^DBGM-\d\d\d\d\d/) + _.isString(msg.msg) && msg.msg.match(/^DBGM-\d\d\d\d\d/) ? { ...msg, msg: msg.msg.substring(10).trimStart(), From ecb3cebc9f77512f833dea3b3f74f0a900490325 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Fri, 29 Aug 2025 08:59:02 +0200 Subject: [PATCH 063/659] v6.6.2-beta.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index df3cc97b4..1990d39c9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "6.6.2-premium-beta.6", + "version": "6.6.2-beta.7", "name": "dbgate-all", "workspaces": [ "packages/*", From b052320f98337f6dd3b941c1f81e495f3bb48cda Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Fri, 29 Aug 2025 09:23:30 +0200 Subject: [PATCH 064/659] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a96703162..8e8635a20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ Builds: - ADDED: Redis search box - Scan all #1191 - FIXED: Optimalized loading SQL server with descriptions #1187 - CHANGED: Allow a much greater page size #1185 +- FIXED: Optimalized loading SQL server with descriptions #1187 +- FIXED: Executing queries for SQLite crash #1195 ## 6.6.1 - ADDED: Support for Mongo shell (Premium) - #1114 From 50ce606e1296dc245f8c9cd1cc40d6babd06925f Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Fri, 29 Aug 2025 09:24:47 +0200 Subject: [PATCH 065/659] v6.6.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1990d39c9..4504f7fbf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "6.6.2-beta.7", + "version": "6.6.2", "name": "dbgate-all", "workspaces": [ "packages/*", From 26cc15b4a2c69213fd4cc008b95fe3b61b5d5231 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Mon, 1 Sep 2025 08:40:20 +0200 Subject: [PATCH 066/659] save zoom level --- app/src/electron.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/electron.js b/app/src/electron.js index 6340a2b74..d78de3702 100644 --- a/app/src/electron.js +++ b/app/src/electron.js @@ -212,6 +212,10 @@ ipcMain.on('app-started', async (event, arg) => { autoUpdater.checkForUpdates(); } } + + if (initialConfig['winZoomLevel'] != null) { + mainWindow.webContents.zoomLevel = initialConfig['winZoomLevel']; + } }); ipcMain.on('window-action', async (event, arg) => { if (!mainWindow) { @@ -394,6 +398,7 @@ function createWindow() { JSON.stringify({ winBounds: mainWindow.getBounds(), winIsMaximized: mainWindow.isMaximized(), + winZoomLevel: mainWindow.webContents.zoomLevel, }), 'utf-8' ); From 14e97cb24f707a8db81bcd256165782ef66152d1 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Mon, 1 Sep 2025 08:57:30 +0200 Subject: [PATCH 067/659] fixed mongoDB rename collection #1198 --- .../dbgate-plugin-mongo/src/backend/driver.js | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/plugins/dbgate-plugin-mongo/src/backend/driver.js b/plugins/dbgate-plugin-mongo/src/backend/driver.js index b48783818..109e294f2 100644 --- a/plugins/dbgate-plugin-mongo/src/backend/driver.js +++ b/plugins/dbgate-plugin-mongo/src/backend/driver.js @@ -167,21 +167,35 @@ const driver = { case 'createCollection': await this.script(dbhan, `db.createCollection('${operation.collection.name}')`); break; + // case 'dropCollection': + // await this.script(dbhan, `db.getCollection('${operation.collection}').drop()`); + // break; + // case 'renameCollection': + // await this.script( + // dbhan, + // `db.getCollection('${operation.collection}').renameCollection('${operation.newName}')` + // ); + // break; + // case 'cloneCollection': + // await this.script( + // dbhan, + // `db.getCollection('${operation.collection}').aggregate([{$out: '${operation.newName}'}]).toArray()` + // ); + // break; + case 'dropCollection': - await this.script(dbhan, `db.getCollection('${operation.collection}').drop()`); + await this.script(dbhan, `db.dropCollection('${operation.collection}')`); break; case 'renameCollection': - await this.script( - dbhan, - `db.getCollection('${operation.collection}').renameCollection('${operation.newName}')` - ); + await this.script(dbhan, `db.renameCollection('${operation.collection}', '${operation.newName}')`); break; case 'cloneCollection': await this.script( dbhan, - `db.getCollection('${operation.collection}').aggregate([{$out: '${operation.newName}'}]).toArray()` + `db.collection('${operation.collection}').aggregate([{$out: '${operation.newName}'}]).toArray()` ); break; + default: throw new Error(`Operation type ${type} not supported`); } From aebb87aa2014291735c2db177088bf02572008dc Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Mon, 1 Sep 2025 09:09:04 +0200 Subject: [PATCH 068/659] Fixed - error listing databases from Azure SQL SERVER #1197 --- plugins/dbgate-plugin-mssql/src/backend/driver.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/dbgate-plugin-mssql/src/backend/driver.js b/plugins/dbgate-plugin-mssql/src/backend/driver.js index 6eeccb4f5..8e7de64a1 100644 --- a/plugins/dbgate-plugin-mssql/src/backend/driver.js +++ b/plugins/dbgate-plugin-mssql/src/backend/driver.js @@ -148,7 +148,13 @@ const driver = { } return res; }, + async listDatabases(dbhan) { + const { rows } = await this.query(dbhan, 'SELECT name FROM sys.databases order by name'); + return rows; + }, + + async listDatabasesFull(dbhan) { const { rows } = await this.query(dbhan, sql.listDatabases); return rows; }, @@ -171,7 +177,7 @@ const driver = { const [variables, processes, databases] = await Promise.all([ this.listVariables(dbhan), this.listProcesses(dbhan), - this.listDatabases(dbhan), + this.listDatabasesFull(dbhan), ]); return { From 8493ea22eb2d595050a9514aa756b9271535cac0 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Mon, 1 Sep 2025 09:51:40 +0200 Subject: [PATCH 069/659] v6.6.3-premium-beta.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4504f7fbf..34fc9ac08 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "6.6.2", + "version": "6.6.3-premium-beta.1", "name": "dbgate-all", "workspaces": [ "packages/*", From d9b88a5d8d8aab40850387de709534ecf16f8e88 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Mon, 1 Sep 2025 15:22:28 +0200 Subject: [PATCH 070/659] v6.6.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 34fc9ac08..52de7042d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "6.6.3-premium-beta.1", + "version": "6.6.3", "name": "dbgate-all", "workspaces": [ "packages/*", From a5a5517555c4f064101d44fbcc064f5e704f3551 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Mon, 1 Sep 2025 15:46:09 +0200 Subject: [PATCH 071/659] changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e8635a20..f55083da3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ Builds: - linux - application for linux - win - application for Windows +## 6.6.3 +- FIXED: Error “db.getCollection(…).renameCollection is not a function” when renaming collection in dbGate #1198 +- FIXED: Can't list databases from Azure SQL SERVER #1197 +- ADDED: Save zoom level in electron apps + ## 6.6.2 - ADDED: List of processes, ability to kill process (Server summary) #1178 - ADDED: Database and table permissions (Team Premium edition) From 096ad97a73f1ffcc82bfc8d7efe00cc2a88adc96 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Wed, 3 Sep 2025 10:37:19 +0200 Subject: [PATCH 072/659] SYNC: Fixed DbGate Web UI Connections do not display 'Databases' #1199 --- packages/api/src/controllers/databaseConnections.js | 2 +- packages/api/src/controllers/serverConnections.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/api/src/controllers/databaseConnections.js b/packages/api/src/controllers/databaseConnections.js index ad6560f2a..383531e02 100644 --- a/packages/api/src/controllers/databaseConnections.js +++ b/packages/api/src/controllers/databaseConnections.js @@ -619,7 +619,7 @@ module.exports = { message: `Loaded database structure for ${database}`, }); - if (!hasPermission(`all-tables`, loadedPermissions)) { + if (process.env.STORAGE_DATABASE && !hasPermission(`all-tables`, loadedPermissions)) { // filter databases by permissions const tablePermissions = await loadTablePermissionsFromRequest(req); const databasePermissions = await loadDatabasePermissionsFromRequest(req); diff --git a/packages/api/src/controllers/serverConnections.js b/packages/api/src/controllers/serverConnections.js index c9f0f3fa1..e182f2184 100644 --- a/packages/api/src/controllers/serverConnections.js +++ b/packages/api/src/controllers/serverConnections.js @@ -46,7 +46,7 @@ module.exports = { existing.status = status; socket.emitChanged(`server-status-changed`); }, - handle_ping() { }, + handle_ping() {}, handle_response(conid, { msgid, ...response }) { const [resolve, reject] = this.requests[msgid]; resolve(response); @@ -166,7 +166,7 @@ module.exports = { message: `Loaded databases for connection`, }); - if (!hasPermission(`all-databases`, loadedPermissions)) { + if (process.env.STORAGE_DATABASE && !hasPermission(`all-databases`, loadedPermissions)) { // filter databases by permissions const databasePermissions = await loadDatabasePermissionsFromRequest(req); const res = []; From e8dc96bcda79909550afb003bdfac816dced30d9 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Wed, 3 Sep 2025 10:40:05 +0200 Subject: [PATCH 073/659] v6.6.4-beta.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 52de7042d..90a957190 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "6.6.3", + "version": "6.6.4-beta.1", "name": "dbgate-all", "workspaces": [ "packages/*", From a239ba22113126833d84844911d40dbcbca6de99 Mon Sep 17 00:00:00 2001 From: CI workflows Date: Wed, 3 Sep 2025 13:30:20 +0000 Subject: [PATCH 074/659] Update pro ref --- workflow-templates/includes.tpl.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-templates/includes.tpl.yaml b/workflow-templates/includes.tpl.yaml index a418e1d13..c4f2bb87a 100644 --- a/workflow-templates/includes.tpl.yaml +++ b/workflow-templates/includes.tpl.yaml @@ -7,7 +7,7 @@ checkout-and-merge-pro: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 742d5c1c1734ee3fd2e9748c775228766f368dea + ref: 0cfa72f6f0d59482e5ee79ffe857f07bb3db5cae - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro From fcb5811f374b3c33fe7436a8f4d66a9c29f3311a Mon Sep 17 00:00:00 2001 From: CI workflows Date: Wed, 3 Sep 2025 13:30:37 +0000 Subject: [PATCH 075/659] chore: auto-update github workflows --- .github/workflows/build-app-pro-beta.yaml | 2 +- .github/workflows/build-app-pro.yaml | 2 +- .github/workflows/build-cloud-pro.yaml | 2 +- .github/workflows/build-docker-pro.yaml | 2 +- .github/workflows/build-npm-pro.yaml | 2 +- .github/workflows/e2e-pro.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-app-pro-beta.yaml b/.github/workflows/build-app-pro-beta.yaml index de3b2c298..b4abae834 100644 --- a/.github/workflows/build-app-pro-beta.yaml +++ b/.github/workflows/build-app-pro-beta.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 742d5c1c1734ee3fd2e9748c775228766f368dea + ref: 0cfa72f6f0d59482e5ee79ffe857f07bb3db5cae - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-app-pro.yaml b/.github/workflows/build-app-pro.yaml index ed91fa041..68d017eaa 100644 --- a/.github/workflows/build-app-pro.yaml +++ b/.github/workflows/build-app-pro.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 742d5c1c1734ee3fd2e9748c775228766f368dea + ref: 0cfa72f6f0d59482e5ee79ffe857f07bb3db5cae - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-cloud-pro.yaml b/.github/workflows/build-cloud-pro.yaml index 429d5a057..e9ed89e2f 100644 --- a/.github/workflows/build-cloud-pro.yaml +++ b/.github/workflows/build-cloud-pro.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 742d5c1c1734ee3fd2e9748c775228766f368dea + ref: 0cfa72f6f0d59482e5ee79ffe857f07bb3db5cae - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-docker-pro.yaml b/.github/workflows/build-docker-pro.yaml index 1a91833b9..7b91e7b4b 100644 --- a/.github/workflows/build-docker-pro.yaml +++ b/.github/workflows/build-docker-pro.yaml @@ -44,7 +44,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 742d5c1c1734ee3fd2e9748c775228766f368dea + ref: 0cfa72f6f0d59482e5ee79ffe857f07bb3db5cae - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-npm-pro.yaml b/.github/workflows/build-npm-pro.yaml index 01e5dd70a..1ebb90a99 100644 --- a/.github/workflows/build-npm-pro.yaml +++ b/.github/workflows/build-npm-pro.yaml @@ -32,7 +32,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 742d5c1c1734ee3fd2e9748c775228766f368dea + ref: 0cfa72f6f0d59482e5ee79ffe857f07bb3db5cae - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/e2e-pro.yaml b/.github/workflows/e2e-pro.yaml index 00c4ad532..a10863b31 100644 --- a/.github/workflows/e2e-pro.yaml +++ b/.github/workflows/e2e-pro.yaml @@ -26,7 +26,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 742d5c1c1734ee3fd2e9748c775228766f368dea + ref: 0cfa72f6f0d59482e5ee79ffe857f07bb3db5cae - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro From cd97647818d3809841b7a390cf6eadf72111e673 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Wed, 3 Sep 2025 16:14:53 +0200 Subject: [PATCH 076/659] SYNC: next permissions --- .../web/src/widgets/WidgetContainer.svelte | 19 ++++++++++--------- .../web/src/widgets/WidgetIconPanel.svelte | 6 +++--- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/web/src/widgets/WidgetContainer.svelte b/packages/web/src/widgets/WidgetContainer.svelte index a08a52d35..bf970a8dc 100644 --- a/packages/web/src/widgets/WidgetContainer.svelte +++ b/packages/web/src/widgets/WidgetContainer.svelte @@ -11,37 +11,38 @@ import AdminPremiumPromoWidget from './AdminPremiumPromoWidget.svelte'; import PublicCloudWidget from './PublicCloudWidget.svelte'; import PrivateCloudWidget from './PrivateCloudWidget.svelte'; + import hasPermission from '../utility/hasPermission';