mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
connection testing
This commit is contained in:
parent
d66fc06403
commit
1eea117062
@ -17,6 +17,7 @@
|
|||||||
"start:api:portal": "yarn workspace dbgate-api start:portal",
|
"start:api:portal": "yarn workspace dbgate-api start:portal",
|
||||||
"start:api:singledb": "yarn workspace dbgate-api start:singledb",
|
"start:api:singledb": "yarn workspace dbgate-api start:singledb",
|
||||||
"start:api:auth": "yarn workspace dbgate-api start:auth",
|
"start:api:auth": "yarn workspace dbgate-api start:auth",
|
||||||
|
"start:api:dblogin": "yarn workspace dbgate-api start:dblogin",
|
||||||
"start:web": "yarn workspace dbgate-web dev",
|
"start:web": "yarn workspace dbgate-web dev",
|
||||||
"start:sqltree": "yarn workspace dbgate-sqltree start",
|
"start:sqltree": "yarn workspace dbgate-sqltree start",
|
||||||
"start:tools": "yarn workspace dbgate-tools start",
|
"start:tools": "yarn workspace dbgate-tools start",
|
||||||
|
11
packages/api/env/dblogin/.env
vendored
Normal file
11
packages/api/env/dblogin/.env
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
DEVMODE=1
|
||||||
|
|
||||||
|
CONNECTIONS=mysql
|
||||||
|
|
||||||
|
LABEL_mysql=MySql localhost
|
||||||
|
SERVER_mysql=localhost
|
||||||
|
USER_mysql=root
|
||||||
|
PORT_mysql=3306
|
||||||
|
# PASSWORD_mysql=Pwd2020Db
|
||||||
|
ENGINE_mysql=mysql@dbgate-plugin-mysql
|
||||||
|
PASSWORD_MODE_mysql=askPassword
|
@ -60,6 +60,7 @@
|
|||||||
"start:portal": "env-cmd -f env/portal/.env node src/index.js --listen-api",
|
"start:portal": "env-cmd -f env/portal/.env node src/index.js --listen-api",
|
||||||
"start:singledb": "env-cmd -f env/singledb/.env node src/index.js --listen-api",
|
"start:singledb": "env-cmd -f env/singledb/.env node src/index.js --listen-api",
|
||||||
"start:auth": "env-cmd -f env/auth/.env node src/index.js --listen-api",
|
"start:auth": "env-cmd -f env/auth/.env node src/index.js --listen-api",
|
||||||
|
"start:dblogin": "env-cmd -f env/dblogin/.env node src/index.js --listen-api",
|
||||||
"start:filedb": "env-cmd node src/index.js /home/jena/test/chinook/Chinook.db --listen-api",
|
"start:filedb": "env-cmd node src/index.js /home/jena/test/chinook/Chinook.db --listen-api",
|
||||||
"start:singleconn": "env-cmd node src/index.js --server localhost --user root --port 3307 --engine mysql@dbgate-plugin-mysql --password test --listen-api",
|
"start:singleconn": "env-cmd node src/index.js --server localhost --user root --port 3307 --engine mysql@dbgate-plugin-mysql --password test --listen-api",
|
||||||
"ts": "tsc",
|
"ts": "tsc",
|
||||||
|
@ -52,6 +52,7 @@ function getPortalCollections() {
|
|||||||
server: process.env[`SERVER_${id}`],
|
server: process.env[`SERVER_${id}`],
|
||||||
user: process.env[`USER_${id}`],
|
user: process.env[`USER_${id}`],
|
||||||
password: process.env[`PASSWORD_${id}`],
|
password: process.env[`PASSWORD_${id}`],
|
||||||
|
passwordMode: process.env[`PASSWORD_MODE_${id}`],
|
||||||
port: process.env[`PORT_${id}`],
|
port: process.env[`PORT_${id}`],
|
||||||
databaseUrl: process.env[`URL_${id}`],
|
databaseUrl: process.env[`URL_${id}`],
|
||||||
useDatabaseUrl: !!process.env[`URL_${id}`],
|
useDatabaseUrl: !!process.env[`URL_${id}`],
|
||||||
@ -204,7 +205,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
saveVolatile_meta: true,
|
saveVolatile_meta: true,
|
||||||
async saveVolatile({ conid, user, password }) {
|
async saveVolatile({ conid, user, password, test }) {
|
||||||
const old = await this.getCore({ conid });
|
const old = await this.getCore({ conid });
|
||||||
const res = {
|
const res = {
|
||||||
...old,
|
...old,
|
||||||
@ -217,8 +218,20 @@ module.exports = {
|
|||||||
res.user = user;
|
res.user = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
volatileConnections[res._id] = res;
|
if (test) {
|
||||||
return res;
|
const testRes = await this.test(res);
|
||||||
|
if (testRes.msgtype == 'connected') {
|
||||||
|
volatileConnections[res._id] = res;
|
||||||
|
return {
|
||||||
|
...res,
|
||||||
|
msgtype: 'connected',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return testRes;
|
||||||
|
} else {
|
||||||
|
volatileConnections[res._id] = res;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
save_meta: true,
|
save_meta: true,
|
||||||
|
@ -131,9 +131,9 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
ping_meta: true,
|
ping_meta: true,
|
||||||
async ping({ connections }) {
|
async ping({ conidArray }) {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
_.uniq(connections).map(async conid => {
|
_.uniq(conidArray).map(async conid => {
|
||||||
const last = this.lastPinged[conid];
|
const last = this.lastPinged[conid];
|
||||||
if (last && new Date().getTime() - last < 30 * 1000) {
|
if (last && new Date().getTime() - last < 30 * 1000) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
|
@ -11,15 +11,20 @@
|
|||||||
import { onDestroy, onMount } from 'svelte';
|
import { onDestroy, onMount } from 'svelte';
|
||||||
import { writable } from 'svelte/store';
|
import { writable } from 'svelte/store';
|
||||||
import FormStyledButton from '../buttons/FormStyledButton.svelte';
|
import FormStyledButton from '../buttons/FormStyledButton.svelte';
|
||||||
|
import Link from '../elements/Link.svelte';
|
||||||
import FormPasswordField from '../forms/FormPasswordField.svelte';
|
import FormPasswordField from '../forms/FormPasswordField.svelte';
|
||||||
import FormProviderCore from '../forms/FormProviderCore.svelte';
|
import FormProviderCore from '../forms/FormProviderCore.svelte';
|
||||||
import FormSubmit from '../forms/FormSubmit.svelte';
|
import FormSubmit from '../forms/FormSubmit.svelte';
|
||||||
import FormTextField from '../forms/FormTextField.svelte';
|
import FormTextField from '../forms/FormTextField.svelte';
|
||||||
|
import FontIcon from '../icons/FontIcon.svelte';
|
||||||
import { apiCall, setVolatileConnectionRemapping } from '../utility/api';
|
import { apiCall, setVolatileConnectionRemapping } from '../utility/api';
|
||||||
|
import { dispatchCacheChange } from '../utility/cache';
|
||||||
|
import createRef from '../utility/createRef';
|
||||||
|
|
||||||
import { getConnectionInfo } from '../utility/metadataLoaders';
|
import { getConnectionInfo } from '../utility/metadataLoaders';
|
||||||
|
import ErrorMessageModal from './ErrorMessageModal.svelte';
|
||||||
import ModalBase from './ModalBase.svelte';
|
import ModalBase from './ModalBase.svelte';
|
||||||
import { closeCurrentModal } from './modalTools';
|
import { closeCurrentModal, showModal } from './modalTools';
|
||||||
|
|
||||||
export let conid;
|
export let conid;
|
||||||
export let passwordMode;
|
export let passwordMode;
|
||||||
@ -27,6 +32,10 @@
|
|||||||
const values = writable({});
|
const values = writable({});
|
||||||
let connection;
|
let connection;
|
||||||
|
|
||||||
|
let isTesting;
|
||||||
|
let sqlConnectResult;
|
||||||
|
const testIdRef = createRef(0);
|
||||||
|
|
||||||
currentModalConid = conid;
|
currentModalConid = conid;
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
@ -44,14 +53,31 @@
|
|||||||
currentModalConid = null;
|
currentModalConid = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function handleCancelTest() {
|
||||||
|
testIdRef.update(x => x + 1); // invalidate current test
|
||||||
|
isTesting = false;
|
||||||
|
}
|
||||||
|
|
||||||
async function handleSubmit(ev) {
|
async function handleSubmit(ev) {
|
||||||
const con = await apiCall('connections/save-volatile', {
|
isTesting = true;
|
||||||
|
testIdRef.update(x => x + 1);
|
||||||
|
const testid = testIdRef.get();
|
||||||
|
const resp = await apiCall('connections/save-volatile', {
|
||||||
conid,
|
conid,
|
||||||
user: ev.detail.user,
|
user: ev.detail.user,
|
||||||
password: ev.detail.password,
|
password: ev.detail.password,
|
||||||
|
test: true,
|
||||||
});
|
});
|
||||||
setVolatileConnectionRemapping(conid, con._id);
|
if (testIdRef.get() != testid) return;
|
||||||
closeCurrentModal();
|
isTesting = false;
|
||||||
|
if (resp.msgtype == 'connected') {
|
||||||
|
setVolatileConnectionRemapping(conid, resp._id);
|
||||||
|
dispatchCacheChange(`database-list-changed-${conid}`);
|
||||||
|
dispatchCacheChange(`server-status-changed`);
|
||||||
|
closeCurrentModal();
|
||||||
|
} else {
|
||||||
|
sqlConnectResult = resp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -74,9 +100,36 @@
|
|||||||
focused={passwordMode == 'askPassword'}
|
focused={passwordMode == 'askPassword'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{#if isTesting}
|
||||||
|
<div>
|
||||||
|
<FontIcon icon="icon loading" /> Testing connection
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if !isTesting && sqlConnectResult && sqlConnectResult.msgtype == 'error'}
|
||||||
|
<div class="error-result">
|
||||||
|
Connect failed: <FontIcon icon="img error" />
|
||||||
|
{sqlConnectResult.error}
|
||||||
|
<Link
|
||||||
|
onClick={() =>
|
||||||
|
showModal(ErrorMessageModal, {
|
||||||
|
message: sqlConnectResult.detail,
|
||||||
|
showAsCode: true,
|
||||||
|
title: 'Database connection error',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
Show detail
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<svelte:fragment slot="footer">
|
<svelte:fragment slot="footer">
|
||||||
<FormSubmit value="Connect" on:click={handleSubmit} />
|
{#if isTesting}
|
||||||
<FormStyledButton value="Cancel" on:click={closeCurrentModal} />
|
<FormStyledButton value="Stop connecting" on:click={handleCancelTest} />
|
||||||
|
{:else}
|
||||||
|
<FormSubmit value="Connect" on:click={handleSubmit} />
|
||||||
|
{/if}
|
||||||
|
<FormStyledButton value="Close" on:click={closeCurrentModal} />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</ModalBase>
|
</ModalBase>
|
||||||
</FormProviderCore>
|
</FormProviderCore>
|
||||||
|
@ -29,6 +29,10 @@ export function setVolatileConnectionRemapping(existingConnectionId, volatileCon
|
|||||||
volatileConnectionMap[existingConnectionId] = volatileConnectionId;
|
volatileConnectionMap[existingConnectionId] = volatileConnectionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getVolatileRemapping(conid) {
|
||||||
|
return volatileConnectionMap[conid] || conid;
|
||||||
|
}
|
||||||
|
|
||||||
function wantEventSource() {
|
function wantEventSource() {
|
||||||
if (!eventSource) {
|
if (!eventSource) {
|
||||||
eventSource = new EventSource(`${resolveApi()}/stream`);
|
eventSource = new EventSource(`${resolveApi()}/stream`);
|
||||||
@ -61,7 +65,11 @@ function processApiResponse(route, args, resp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function transformApiArgs(args) {
|
function transformApiArgs(args) {
|
||||||
return _.mapValues(args, (v, k) => (k == 'conid' && v && volatileConnectionMap[v] ? volatileConnectionMap[v] : v));
|
return _.mapValues(args, (v, k) => {
|
||||||
|
if (k == 'conid' && v && volatileConnectionMap[v]) return volatileConnectionMap[v];
|
||||||
|
if (k == 'conidArray' && _.isArray(v)) return v.map(x => volatileConnectionMap[x] || x);
|
||||||
|
return v;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function apiCall(route: string, args: {} = undefined) {
|
export async function apiCall(route: string, args: {} = undefined) {
|
||||||
|
@ -105,7 +105,7 @@ export async function unsubscribeCacheChange(reloadTrigger, cacheKey, reloadHand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dispatchCacheChange(reloadTrigger) {
|
export function dispatchCacheChange(reloadTrigger) {
|
||||||
// console.log('CHANGE', reloadTrigger);
|
// console.log('CHANGE', reloadTrigger);
|
||||||
cacheClean(reloadTrigger);
|
cacheClean(reloadTrigger);
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import { getConnectionList } from './metadataLoaders';
|
|||||||
// };
|
// };
|
||||||
|
|
||||||
const doServerPing = value => {
|
const doServerPing = value => {
|
||||||
apiCall('server-connections/ping', { connections: value });
|
apiCall('server-connections/ping', { conidArray: value });
|
||||||
};
|
};
|
||||||
|
|
||||||
const doDatabasePing = value => {
|
const doDatabasePing = value => {
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
import { useConnectionColorFactory } from '../utility/useConnectionColor';
|
import { useConnectionColorFactory } from '../utility/useConnectionColor';
|
||||||
import FontIcon from '../icons/FontIcon.svelte';
|
import FontIcon from '../icons/FontIcon.svelte';
|
||||||
import CloseSearchButton from '../buttons/CloseSearchButton.svelte';
|
import CloseSearchButton from '../buttons/CloseSearchButton.svelte';
|
||||||
import { apiCall } from '../utility/api';
|
import { apiCall, getVolatileRemapping } from '../utility/api';
|
||||||
import LargeButton from '../buttons/LargeButton.svelte';
|
import LargeButton from '../buttons/LargeButton.svelte';
|
||||||
import { plusExpandIcon, chevronExpandIcon } from '../icons/expandIcons';
|
import { plusExpandIcon, chevronExpandIcon } from '../icons/expandIcons';
|
||||||
import { safeJsonParse } from 'dbgate-tools';
|
import { safeJsonParse } from 'dbgate-tools';
|
||||||
@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
$: connectionsWithStatus =
|
$: connectionsWithStatus =
|
||||||
$connections && $serverStatus
|
$connections && $serverStatus
|
||||||
? $connections.map(conn => ({ ...conn, status: $serverStatus[conn._id] }))
|
? $connections.map(conn => ({ ...conn, status: $serverStatus[getVolatileRemapping(conn._id)] }))
|
||||||
: $connections;
|
: $connections;
|
||||||
|
|
||||||
$: connectionsWithStatusFiltered = connectionsWithStatus?.filter(
|
$: connectionsWithStatusFiltered = connectionsWithStatus?.filter(
|
||||||
|
Loading…
Reference in New Issue
Block a user