mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
mongo server summary
This commit is contained in:
parent
f7bd12881e
commit
ceea1a9047
@ -1,6 +1,7 @@
|
||||
const connections = require('./connections');
|
||||
const socket = require('../utility/socket');
|
||||
const { fork } = require('child_process');
|
||||
const uuidv1 = require('uuid/v1');
|
||||
const _ = require('lodash');
|
||||
const AsyncLock = require('async-lock');
|
||||
const { handleProcessCommunication } = require('../utility/processComm');
|
||||
@ -13,6 +14,7 @@ module.exports = {
|
||||
opened: [],
|
||||
closed: {},
|
||||
lastPinged: {},
|
||||
requests: {},
|
||||
|
||||
handle_databases(conid, { databases }) {
|
||||
const existing = this.opened.find(x => x.conid == conid);
|
||||
@ -33,6 +35,11 @@ module.exports = {
|
||||
socket.emitChanged(`server-status-changed`);
|
||||
},
|
||||
handle_ping() {},
|
||||
handle_response(conid, { msgid, ...response }) {
|
||||
const [resolve, reject] = this.requests[msgid];
|
||||
resolve(response);
|
||||
delete this.requests[msgid];
|
||||
},
|
||||
|
||||
async ensureOpened(conid) {
|
||||
const res = await lock.acquire(conid, async () => {
|
||||
@ -161,4 +168,33 @@ module.exports = {
|
||||
opened.subprocess.send({ msgtype: 'dropDatabase', name });
|
||||
return { status: 'ok' };
|
||||
},
|
||||
|
||||
sendRequest(conn, message) {
|
||||
const msgid = uuidv1();
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
this.requests[msgid] = [resolve, reject];
|
||||
conn.subprocess.send({ msgid, ...message });
|
||||
});
|
||||
return promise;
|
||||
},
|
||||
|
||||
async loadDataCore(msgtype, { conid, ...args }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
const opened = await this.ensureOpened(conid);
|
||||
const res = await this.sendRequest(opened, { msgtype, ...args });
|
||||
if (res.errorMessage) {
|
||||
console.error(res.errorMessage);
|
||||
|
||||
return {
|
||||
errorMessage: res.errorMessage,
|
||||
};
|
||||
}
|
||||
return res.result || null;
|
||||
},
|
||||
|
||||
serverSummary_meta: true,
|
||||
async serverSummary({ conid }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
return this.loadDataCore('serverSummary', { conid });
|
||||
},
|
||||
};
|
||||
|
@ -10,6 +10,7 @@ let storedConnection;
|
||||
let lastDatabases = null;
|
||||
let lastStatus = null;
|
||||
let lastPing = null;
|
||||
let afterConnectCallbacks = [];
|
||||
|
||||
async function handleRefresh() {
|
||||
const driver = requireEngineDriver(storedConnection);
|
||||
@ -74,6 +75,18 @@ async function handleConnect(connection) {
|
||||
// console.error(err);
|
||||
setTimeout(() => process.exit(1), 1000);
|
||||
}
|
||||
|
||||
for (const [resolve] of afterConnectCallbacks) {
|
||||
resolve();
|
||||
}
|
||||
afterConnectCallbacks = [];
|
||||
}
|
||||
|
||||
function waitConnected() {
|
||||
if (systemConnection) return Promise.resolve();
|
||||
return new Promise((resolve, reject) => {
|
||||
afterConnectCallbacks.push([resolve, reject]);
|
||||
});
|
||||
}
|
||||
|
||||
function handlePing() {
|
||||
@ -94,9 +107,25 @@ async function handleDatabaseOp(op, { name }) {
|
||||
await handleRefresh();
|
||||
}
|
||||
|
||||
async function handleDriverDataCore(msgid, callMethod) {
|
||||
await waitConnected();
|
||||
const driver = requireEngineDriver(storedConnection);
|
||||
try {
|
||||
const result = await callMethod(driver);
|
||||
process.send({ msgtype: 'response', msgid, result });
|
||||
} catch (err) {
|
||||
process.send({ msgtype: 'response', msgid, errorMessage: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
async function handleServerSummary({ msgid, options }) {
|
||||
return handleDriverDataCore(msgid, driver => driver.serverSummary(systemConnection));
|
||||
}
|
||||
|
||||
const messageHandlers = {
|
||||
connect: handleConnect,
|
||||
ping: handlePing,
|
||||
serverSummary: handleServerSummary,
|
||||
createDatabase: props => handleDatabaseOp('createDatabase', props),
|
||||
dropDatabase: props => handleDatabaseOp('dropDatabase', props),
|
||||
};
|
||||
|
15
packages/types/engines.d.ts
vendored
15
packages/types/engines.d.ts
vendored
@ -55,6 +55,17 @@ export interface SqlBackupDumper {
|
||||
run();
|
||||
}
|
||||
|
||||
export interface SummaryColumn {
|
||||
fieldName: string;
|
||||
header: string;
|
||||
dataType: 'string' | 'number' | 'bytes';
|
||||
}
|
||||
export interface ServerSummaryDatabase {}
|
||||
export interface ServerSummary {
|
||||
columns: SummaryColumn[];
|
||||
databases: ServerSummaryDatabase[];
|
||||
}
|
||||
|
||||
export interface EngineDriver {
|
||||
engine: string;
|
||||
title: string;
|
||||
@ -65,6 +76,7 @@ export interface EngineDriver {
|
||||
supportedKeyTypes: SupportedDbKeyType[];
|
||||
supportsDatabaseUrl?: boolean;
|
||||
supportsDatabaseDump?: boolean;
|
||||
supportsServerSummary?: boolean;
|
||||
isElectronOnly?: boolean;
|
||||
supportedCreateDatabase?: boolean;
|
||||
showConnectionField?: (field: string, values: any) => boolean;
|
||||
@ -81,7 +93,7 @@ export interface EngineDriver {
|
||||
stream(pool: any, sql: string, options: StreamOptions);
|
||||
readQuery(pool: any, sql: string, structure?: TableInfo): Promise<stream.Readable>;
|
||||
readJsonQuery(pool: any, query: any, structure?: TableInfo): Promise<stream.Readable>;
|
||||
writeTable(pool: any, name: NamedObjectInfo, options: WriteTableOptions): Promise<stream.Writeable>;
|
||||
writeTable(pool: any, name: NamedObjectInfo, options: WriteTableOptions): Promise<stream.Writable>;
|
||||
analyseSingleObject(
|
||||
pool: any,
|
||||
name: NamedObjectInfo,
|
||||
@ -116,6 +128,7 @@ export interface EngineDriver {
|
||||
getNewObjectTemplates(): NewObjectTemplate[];
|
||||
// direct call of pool method, only some methods could be supported, on only some drivers
|
||||
callMethod(pool, method, args);
|
||||
loadSummary(pool): Promise<ServerSummary>;
|
||||
|
||||
analyserClass?: any;
|
||||
dumperClass?: any;
|
||||
|
@ -104,7 +104,7 @@
|
||||
import ImportDatabaseDumpModal from '../modals/ImportDatabaseDumpModal.svelte';
|
||||
import { closeMultipleTabs } from '../widgets/TabsPanel.svelte';
|
||||
import AboutModal from '../modals/AboutModal.svelte';
|
||||
import { tick } from 'svelte';
|
||||
import { tick } from 'svelte';
|
||||
|
||||
export let data;
|
||||
export let passProps;
|
||||
@ -195,6 +195,16 @@ import { tick } from 'svelte';
|
||||
}),
|
||||
});
|
||||
};
|
||||
const handleServerSummary = () => {
|
||||
openNewTab({
|
||||
title: getConnectionLabel(data),
|
||||
icon: 'img server',
|
||||
tabComponent: 'ServerSummaryTab',
|
||||
props: {
|
||||
conid: data._id,
|
||||
},
|
||||
});
|
||||
};
|
||||
const handleNewQuery = () => {
|
||||
const tooltip = `${getConnectionLabel(data)}`;
|
||||
openNewTab({
|
||||
@ -244,6 +254,11 @@ import { tick } from 'svelte';
|
||||
text: 'Create database',
|
||||
onClick: handleCreateDatabase,
|
||||
},
|
||||
$openedConnections.includes(data._id) &&
|
||||
driver?.supportsServerSummary && {
|
||||
text: 'Server summary',
|
||||
onClick: handleServerSummary,
|
||||
},
|
||||
],
|
||||
data.singleDatabase && [
|
||||
{ divider: true },
|
||||
|
@ -1,8 +1,7 @@
|
||||
<script lang="ts">
|
||||
import _ from 'lodash';
|
||||
import FontIcon from '../icons/FontIcon.svelte';
|
||||
|
||||
import Link from './Link.svelte';
|
||||
|
||||
import TableControl from './TableControl.svelte';
|
||||
|
||||
export let title;
|
||||
@ -10,6 +9,7 @@
|
||||
export let columns;
|
||||
export let showIfEmpty = false;
|
||||
export let emptyMessage = null;
|
||||
export let hideDisplayName = false;
|
||||
export let clickable;
|
||||
export let onAddNew;
|
||||
</script>
|
||||
@ -31,14 +31,14 @@
|
||||
<div class="body">
|
||||
<TableControl
|
||||
rows={collection || []}
|
||||
columns={[
|
||||
{
|
||||
columns={_.compact([
|
||||
!hideDisplayName && {
|
||||
fieldName: 'displayName',
|
||||
header: 'Name',
|
||||
slot: -1,
|
||||
},
|
||||
...columns,
|
||||
]}
|
||||
])}
|
||||
{clickable}
|
||||
on:clickrow
|
||||
>
|
||||
|
23
packages/web/src/tabs/ServerSummaryTab.svelte
Normal file
23
packages/web/src/tabs/ServerSummaryTab.svelte
Normal file
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
import Link from '../elements/Link.svelte';
|
||||
import LoadingInfo from '../elements/LoadingInfo.svelte';
|
||||
|
||||
import ObjectListControl from '../elements/ObjectListControl.svelte';
|
||||
import { apiCall } from '../utility/api';
|
||||
|
||||
export let conid;
|
||||
|
||||
let refreshToken = 0;
|
||||
</script>
|
||||
|
||||
{#await apiCall('server-connections/server-summary', { conid, refreshToken })}
|
||||
<LoadingInfo message="Loading server details" wrapper />
|
||||
{:then summary}
|
||||
<ObjectListControl
|
||||
collection={summary.databases}
|
||||
hideDisplayName
|
||||
title="Databases"
|
||||
emptyMessage={'No databases'}
|
||||
columns={summary.columns}
|
||||
/>
|
||||
{/await}
|
@ -26,6 +26,7 @@ import * as QueryDataTab from './QueryDataTab.svelte';
|
||||
import * as ConnectionTab from './ConnectionTab.svelte';
|
||||
import * as MapTab from './MapTab.svelte';
|
||||
import * as PerspectiveTab from './PerspectiveTab.svelte';
|
||||
import * as ServerSummaryTab from './ServerSummaryTab.svelte';
|
||||
|
||||
export default {
|
||||
TableDataTab,
|
||||
@ -56,4 +57,5 @@ export default {
|
||||
ConnectionTab,
|
||||
MapTab,
|
||||
PerspectiveTab,
|
||||
ServerSummaryTab,
|
||||
};
|
||||
|
@ -351,6 +351,25 @@ const driver = {
|
||||
|
||||
return res;
|
||||
},
|
||||
|
||||
async serverSummary(pool) {
|
||||
const res = await pool.__getDatabase().admin().listDatabases();
|
||||
return {
|
||||
columns: [
|
||||
{
|
||||
fieldName: 'name',
|
||||
dataType: 'string',
|
||||
header: 'Name',
|
||||
},
|
||||
{
|
||||
fieldName: 'sizeOnDisk',
|
||||
dataType: 'bytes',
|
||||
header: 'Size',
|
||||
},
|
||||
],
|
||||
databases: res.databases,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = driver;
|
||||
|
@ -32,6 +32,7 @@ const driver = {
|
||||
editorMode: 'javascript',
|
||||
defaultPort: 27017,
|
||||
supportsDatabaseUrl: true,
|
||||
supportsServerSummary: true,
|
||||
databaseUrlPlaceholder: 'e.g. mongodb://username:password@mongodb.mydomain.net/dbname',
|
||||
|
||||
getQuerySplitterOptions: () => mongoSplitterOptions,
|
||||
|
Loading…
Reference in New Issue
Block a user