mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-05-01 17:53:59 +00:00
connection tabs - improved UX
This commit is contained in:
@@ -31,7 +31,45 @@
|
|||||||
expandedConnections.update(x => _.uniq([...x, connection._id]));
|
expandedConnections.update(x => _.uniq([...x, connection._id]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closeMultipleTabs(x => x.tabComponent == 'ConnectionTab' && x.props?.conid == connection._id, true);
|
// closeMultipleTabs(x => x.tabComponent == 'ConnectionTab' && x.props?.conid == connection._id, true);
|
||||||
|
}
|
||||||
|
export function disconnectServerConnection(conid, showConfirmation = true) {
|
||||||
|
const closeCondition = x => x.props?.conid == conid && x.tabComponent != 'ConnectionTab' && x.closedTime == null;
|
||||||
|
|
||||||
|
if (showConfirmation) {
|
||||||
|
const count = getOpenedTabs().filter(closeCondition).length;
|
||||||
|
if (count > 0) {
|
||||||
|
showModal(ConfirmModal, {
|
||||||
|
message: `Closing connection will close ${count} opened tabs, continue?`,
|
||||||
|
onConfirm: () => disconnectServerConnection(conid, false),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const electron = getElectron();
|
||||||
|
const currentDb = getCurrentDatabase();
|
||||||
|
openedConnections.update(list => list.filter(x => x != conid));
|
||||||
|
if (electron) {
|
||||||
|
apiCall('server-connections/disconnect', { conid });
|
||||||
|
}
|
||||||
|
if (currentDb?.connection?._id == conid) {
|
||||||
|
if (electron) {
|
||||||
|
apiCall('database-connections/disconnect', { conid, database: currentDb.name });
|
||||||
|
}
|
||||||
|
currentDatabase.set(null);
|
||||||
|
}
|
||||||
|
closeMultipleTabs(closeCondition);
|
||||||
|
// if (data.unsaved) {
|
||||||
|
// openNewTab({
|
||||||
|
// title: 'New Connection',
|
||||||
|
// icon: 'img connection',
|
||||||
|
// tabComponent: 'ConnectionTab',
|
||||||
|
// props: {
|
||||||
|
// conid: data._id,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -43,7 +81,9 @@
|
|||||||
expandedConnections,
|
expandedConnections,
|
||||||
extensions,
|
extensions,
|
||||||
getCurrentConfig,
|
getCurrentConfig,
|
||||||
|
getCurrentDatabase,
|
||||||
getOpenedConnections,
|
getOpenedConnections,
|
||||||
|
getOpenedTabs,
|
||||||
openedConnections,
|
openedConnections,
|
||||||
openedSingleDatabaseConnections,
|
openedSingleDatabaseConnections,
|
||||||
} from '../stores';
|
} from '../stores';
|
||||||
@@ -118,27 +158,7 @@
|
|||||||
apiCall('server-connections/refresh', { conid: data._id });
|
apiCall('server-connections/refresh', { conid: data._id });
|
||||||
};
|
};
|
||||||
const handleDisconnect = () => {
|
const handleDisconnect = () => {
|
||||||
openedConnections.update(list => list.filter(x => x != data._id));
|
disconnectServerConnection(data._id);
|
||||||
if (electron) {
|
|
||||||
apiCall('server-connections/disconnect', { conid: data._id });
|
|
||||||
}
|
|
||||||
if (_.get($currentDatabase, 'connection._id') == data._id) {
|
|
||||||
if (electron) {
|
|
||||||
apiCall('database-connections/disconnect', { conid: data._id, database: $currentDatabase.name });
|
|
||||||
}
|
|
||||||
currentDatabase.set(null);
|
|
||||||
}
|
|
||||||
closeMultipleTabs(x => x.props.conid == data._id);
|
|
||||||
if (data.unsaved) {
|
|
||||||
openNewTab({
|
|
||||||
title: 'New Connection',
|
|
||||||
icon: 'img connection',
|
|
||||||
tabComponent: 'ConnectionTab',
|
|
||||||
props: {
|
|
||||||
conid: data._id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
showModal(ConfirmModal, {
|
showModal(ConfirmModal, {
|
||||||
@@ -180,8 +200,8 @@
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
config.runAsPortal == false && [
|
config.runAsPortal == false && [
|
||||||
!$openedConnections.includes(data._id) && {
|
{
|
||||||
text: 'Edit',
|
text: $openedConnections.includes(data._id) ? 'View details' : 'Edit',
|
||||||
onClick: handleOpenConnectionTab,
|
onClick: handleOpenConnectionTab,
|
||||||
},
|
},
|
||||||
!$openedConnections.includes(data._id) && {
|
!$openedConnections.includes(data._id) && {
|
||||||
|
|||||||
@@ -1,6 +1,35 @@
|
|||||||
<script lang="ts" context="module">
|
<script lang="ts" context="module">
|
||||||
export const extractKey = props => props.name;
|
export const extractKey = props => props.name;
|
||||||
|
|
||||||
|
export function disconnectDatabaseConnection(conid, database, showConfirmation = true) {
|
||||||
|
const closeCondition = x =>
|
||||||
|
x.props?.conid == conid &&
|
||||||
|
x.props?.database == database &&
|
||||||
|
x.tabComponent != 'ConnectionTab' &&
|
||||||
|
x.closedTime == null;
|
||||||
|
|
||||||
|
if (showConfirmation) {
|
||||||
|
const count = getOpenedTabs().filter(closeCondition).length;
|
||||||
|
if (count > 0) {
|
||||||
|
showModal(ConfirmModal, {
|
||||||
|
message: `Closing connection will close ${count} opened tabs, continue?`,
|
||||||
|
onConfirm: () => disconnectDatabaseConnection(conid, database, false),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const electron = getElectron();
|
||||||
|
if (electron) {
|
||||||
|
apiCall('database-connections/disconnect', { conid, database });
|
||||||
|
}
|
||||||
|
if (getCurrentDatabase()?.connection?._id == conid && getCurrentDatabase()?.name == database) {
|
||||||
|
currentDatabase.set(null);
|
||||||
|
}
|
||||||
|
openedSingleDatabaseConnections.update(list => list.filter(x => x != conid));
|
||||||
|
closeMultipleTabs(closeCondition);
|
||||||
|
}
|
||||||
|
|
||||||
export function getDatabaseMenuItems(
|
export function getDatabaseMenuItems(
|
||||||
connection,
|
connection,
|
||||||
name,
|
name,
|
||||||
@@ -135,14 +164,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDisconnect = () => {
|
const handleDisconnect = () => {
|
||||||
const electron = getElectron();
|
disconnectDatabaseConnection(connection._id, name);
|
||||||
if (electron) {
|
|
||||||
apiCall('database-connections/disconnect', { conid: connection._id, database: name });
|
|
||||||
}
|
|
||||||
if (getCurrentDatabase()?.connection?._id == connection._id && getCurrentDatabase()?.name == name) {
|
|
||||||
currentDatabase.set(null);
|
|
||||||
}
|
|
||||||
openedSingleDatabaseConnections.update(list => list.filter(x => x != connection._id));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleExportModel = async () => {
|
const handleExportModel = async () => {
|
||||||
@@ -279,6 +301,7 @@
|
|||||||
extensions,
|
extensions,
|
||||||
getCurrentDatabase,
|
getCurrentDatabase,
|
||||||
getExtensions,
|
getExtensions,
|
||||||
|
getOpenedTabs,
|
||||||
openedConnections,
|
openedConnections,
|
||||||
openedSingleDatabaseConnections,
|
openedSingleDatabaseConnections,
|
||||||
pinnedDatabases,
|
pinnedDatabases,
|
||||||
@@ -300,6 +323,8 @@
|
|||||||
import { exportSqlDump } from '../utility/exportFileTools';
|
import { exportSqlDump } from '../utility/exportFileTools';
|
||||||
import ImportDatabaseDumpModal from '../modals/ImportDatabaseDumpModal.svelte';
|
import ImportDatabaseDumpModal from '../modals/ImportDatabaseDumpModal.svelte';
|
||||||
import ExportDatabaseDumpModal from '../modals/ExportDatabaseDumpModal.svelte';
|
import ExportDatabaseDumpModal from '../modals/ExportDatabaseDumpModal.svelte';
|
||||||
|
import ConfirmModal from '../modals/ConfirmModal.svelte';
|
||||||
|
import { closeMultipleTabs } from '../widgets/TabsPanel.svelte';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
export let passProps;
|
export let passProps;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
|
||||||
export let value;
|
export let value;
|
||||||
|
export let disabled = false;
|
||||||
|
|
||||||
function colorValue(color, colorIndex, themeDef) {
|
function colorValue(color, colorIndex, themeDef) {
|
||||||
const palettes = themeDef?.themeType == 'dark' ? presetDarkPalettes : presetPalettes;
|
const palettes = themeDef?.themeType == 'dark' ? presetDarkPalettes : presetPalettes;
|
||||||
@@ -19,6 +20,7 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div
|
<div
|
||||||
class="item"
|
class="item"
|
||||||
|
class:disabled
|
||||||
class:selected={!value}
|
class:selected={!value}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
dispatch('change', null);
|
dispatch('change', null);
|
||||||
@@ -30,8 +32,10 @@
|
|||||||
<div
|
<div
|
||||||
style={`background:${colorValue(color, 3, $currentThemeDefinition)}`}
|
style={`background:${colorValue(color, 3, $currentThemeDefinition)}`}
|
||||||
class="item"
|
class="item"
|
||||||
|
class:disabled
|
||||||
class:selected={color == value}
|
class:selected={color == value}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
|
if (disabled) return;
|
||||||
dispatch('change', color);
|
dispatch('change', color);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -58,7 +62,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item:hover {
|
.item:hover:not(.disabled) {
|
||||||
border: 1px solid var(--theme-font-2);
|
border: 1px solid var(--theme-font-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
export let label;
|
export let label;
|
||||||
export let name;
|
export let name;
|
||||||
|
export let disabled = false;
|
||||||
|
|
||||||
const { template } = getFormContext();
|
const { template } = getFormContext();
|
||||||
const { values, setFieldValue } = getFormContext();
|
const { values, setFieldValue } = getFormContext();
|
||||||
@@ -21,6 +22,7 @@
|
|||||||
<svelte:component this={template} type="text" {label} {...templateProps}>
|
<svelte:component this={template} type="text" {label} {...templateProps}>
|
||||||
<ColorSelector
|
<ColorSelector
|
||||||
value={$values && $values[name]}
|
value={$values && $values[name]}
|
||||||
|
{disabled}
|
||||||
on:change={e => {
|
on:change={e => {
|
||||||
setFieldValue(name, e.detail);
|
setFieldValue(name, e.detail);
|
||||||
}}
|
}}
|
||||||
@@ -29,6 +31,7 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<FormSelectField
|
<FormSelectField
|
||||||
isNative
|
isNative
|
||||||
|
{disabled}
|
||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
{label}
|
{label}
|
||||||
{name}
|
{name}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
import FormSelectField from '../forms/FormSelectField.svelte';
|
import FormSelectField from '../forms/FormSelectField.svelte';
|
||||||
|
|
||||||
import FormTextField from '../forms/FormTextField.svelte';
|
import FormTextField from '../forms/FormTextField.svelte';
|
||||||
import { extensions, getCurrentConfig } from '../stores';
|
import { extensions, getCurrentConfig, openedConnections, openedSingleDatabaseConnections } from '../stores';
|
||||||
import getElectron from '../utility/getElectron';
|
import getElectron from '../utility/getElectron';
|
||||||
import { useAuthTypes } from '../utility/metadataLoaders';
|
import { useAuthTypes } from '../utility/metadataLoaders';
|
||||||
import FormColorField from '../forms/FormColorField.svelte';
|
import FormColorField from '../forms/FormColorField.svelte';
|
||||||
@@ -30,12 +30,14 @@
|
|||||||
|
|
||||||
$: showUser = driver?.showConnectionField('user', $values);
|
$: showUser = driver?.showConnectionField('user', $values);
|
||||||
$: showPassword = driver?.showConnectionField('password', $values);
|
$: showPassword = driver?.showConnectionField('password', $values);
|
||||||
|
$: isConnected = $openedConnections.includes($values._id) || $openedSingleDatabaseConnections.includes($values._id);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FormSelectField
|
<FormSelectField
|
||||||
label="Database engine"
|
label="Database engine"
|
||||||
name="engine"
|
name="engine"
|
||||||
isNative
|
isNative
|
||||||
|
disabled={isConnected}
|
||||||
options={[
|
options={[
|
||||||
{ label: '(select driver)', value: '' },
|
{ label: '(select driver)', value: '' },
|
||||||
...$extensions.drivers
|
...$extensions.drivers
|
||||||
@@ -48,12 +50,13 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{#if driver?.showConnectionField('databaseFile', $values)}
|
{#if driver?.showConnectionField('databaseFile', $values)}
|
||||||
<FormElectronFileSelector label="Database file" name="databaseFile" disabled={!electron} />
|
<FormElectronFileSelector label="Database file" name="databaseFile" disabled={isConnected || !electron} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if driver?.showConnectionField('useDatabaseUrl', $values)}
|
{#if driver?.showConnectionField('useDatabaseUrl', $values)}
|
||||||
<div class="radio">
|
<div class="radio">
|
||||||
<FormRadioGroupField
|
<FormRadioGroupField
|
||||||
|
disabled={isConnected}
|
||||||
name="useDatabaseUrl"
|
name="useDatabaseUrl"
|
||||||
options={[
|
options={[
|
||||||
{ label: 'Fill database connection details', value: '', default: true },
|
{ label: 'Fill database connection details', value: '', default: true },
|
||||||
@@ -64,7 +67,12 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if driver?.showConnectionField('databaseUrl', $values)}
|
{#if driver?.showConnectionField('databaseUrl', $values)}
|
||||||
<FormTextField label="Database URL" name="databaseUrl" placeholder={driver?.databaseUrlPlaceholder} />
|
<FormTextField
|
||||||
|
label="Database URL"
|
||||||
|
name="databaseUrl"
|
||||||
|
placeholder={driver?.databaseUrlPlaceholder}
|
||||||
|
disabled={isConnected}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if $authTypes && driver?.showConnectionField('authType', $values)}
|
{#if $authTypes && driver?.showConnectionField('authType', $values)}
|
||||||
@@ -72,6 +80,7 @@
|
|||||||
label="Authentication"
|
label="Authentication"
|
||||||
name="authType"
|
name="authType"
|
||||||
isNative
|
isNative
|
||||||
|
disabled={isConnected}
|
||||||
defaultValue={driver?.defaultAuthTypeName}
|
defaultValue={driver?.defaultAuthTypeName}
|
||||||
options={$authTypes.map(auth => ({
|
options={$authTypes.map(auth => ({
|
||||||
value: auth.name,
|
value: auth.name,
|
||||||
@@ -86,7 +95,7 @@
|
|||||||
<FormTextField
|
<FormTextField
|
||||||
label="Server"
|
label="Server"
|
||||||
name="server"
|
name="server"
|
||||||
disabled={disabledFields.includes('server')}
|
disabled={isConnected || disabledFields.includes('server')}
|
||||||
templateProps={{ noMargin: true }}
|
templateProps={{ noMargin: true }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -95,7 +104,7 @@
|
|||||||
<FormTextField
|
<FormTextField
|
||||||
label="Port"
|
label="Port"
|
||||||
name="port"
|
name="port"
|
||||||
disabled={disabledFields.includes('port')}
|
disabled={isConnected || disabledFields.includes('port')}
|
||||||
templateProps={{ noMargin: true }}
|
templateProps={{ noMargin: true }}
|
||||||
placeholder={driver && driver.defaultPort}
|
placeholder={driver && driver.defaultPort}
|
||||||
/>
|
/>
|
||||||
@@ -117,7 +126,7 @@
|
|||||||
<FormTextField
|
<FormTextField
|
||||||
label="User"
|
label="User"
|
||||||
name="user"
|
name="user"
|
||||||
disabled={disabledFields.includes('user')}
|
disabled={isConnected || disabledFields.includes('user')}
|
||||||
templateProps={{ noMargin: true }}
|
templateProps={{ noMargin: true }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -127,7 +136,7 @@
|
|||||||
<FormPasswordField
|
<FormPasswordField
|
||||||
label="Password"
|
label="Password"
|
||||||
name="password"
|
name="password"
|
||||||
disabled={disabledFields.includes('password')}
|
disabled={isConnected || disabledFields.includes('password')}
|
||||||
templateProps={{ noMargin: true }}
|
templateProps={{ noMargin: true }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -135,10 +144,10 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if showUser && !showPassword}
|
{#if showUser && !showPassword}
|
||||||
<FormTextField label="User" name="user" disabled={disabledFields.includes('user')} />
|
<FormTextField label="User" name="user" disabled={isConnected || disabledFields.includes('user')} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if !showUser && showPassword}
|
{#if !showUser && showPassword}
|
||||||
<FormPasswordField label="Password" name="password" disabled={disabledFields.includes('password')} />
|
<FormPasswordField label="Password" name="password" disabled={isConnected || disabledFields.includes('password')} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if !disabledFields.includes('password') && showPassword}
|
{#if !disabledFields.includes('password') && showPassword}
|
||||||
@@ -147,6 +156,7 @@
|
|||||||
isNative
|
isNative
|
||||||
name="passwordMode"
|
name="passwordMode"
|
||||||
defaultValue="saveEncrypted"
|
defaultValue="saveEncrypted"
|
||||||
|
disabled={isConnected}
|
||||||
options={[
|
options={[
|
||||||
{ value: 'saveEncrypted', label: 'Save and encrypt' },
|
{ value: 'saveEncrypted', label: 'Save and encrypt' },
|
||||||
{ value: 'saveRaw', label: 'Save raw (UNSAFE!!)' },
|
{ value: 'saveRaw', label: 'Save raw (UNSAFE!!)' },
|
||||||
@@ -155,21 +165,26 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if driver?.showConnectionField('isReadOnly', $values)}
|
{#if driver?.showConnectionField('isReadOnly', $values)}
|
||||||
<FormCheckboxField label="Is read only" name="isReadOnly" />
|
<FormCheckboxField label="Is read only" name="isReadOnly" disabled={isConnected} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if driver?.showConnectionField('defaultDatabase', $values)}
|
{#if driver?.showConnectionField('defaultDatabase', $values)}
|
||||||
<FormTextField label="Default database" name="defaultDatabase" />
|
<FormTextField label="Default database" name="defaultDatabase" disabled={isConnected} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if defaultDatabase && driver?.showConnectionField('singleDatabase', $values)}
|
{#if defaultDatabase && driver?.showConnectionField('singleDatabase', $values)}
|
||||||
<FormCheckboxField label={`Use only database ${defaultDatabase}`} name="singleDatabase" />
|
<FormCheckboxField label={`Use only database ${defaultDatabase}`} name="singleDatabase" disabled={isConnected} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if driver}
|
{#if driver}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6 mr-1">
|
<div class="col-6 mr-1">
|
||||||
<FormTextField label="Display name" name="displayName" templateProps={{ noMargin: true }} />
|
<FormTextField
|
||||||
|
label="Display name"
|
||||||
|
name="displayName"
|
||||||
|
templateProps={{ noMargin: true }}
|
||||||
|
disabled={isConnected}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 mr-1">
|
<div class="col-6 mr-1">
|
||||||
<FormColorField
|
<FormColorField
|
||||||
@@ -178,6 +193,7 @@
|
|||||||
name="connectionColor"
|
name="connectionColor"
|
||||||
emptyLabel="(not selected)"
|
emptyLabel="(not selected)"
|
||||||
templateProps={{ noMargin: true }}
|
templateProps={{ noMargin: true }}
|
||||||
|
disabled={isConnected}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
import getElectron from '../utility/getElectron';
|
import getElectron from '../utility/getElectron';
|
||||||
import { usePlatformInfo } from '../utility/metadataLoaders';
|
import { usePlatformInfo } from '../utility/metadataLoaders';
|
||||||
import FontIcon from '../icons/FontIcon.svelte';
|
import FontIcon from '../icons/FontIcon.svelte';
|
||||||
import { extensions } from '../stores';
|
import { extensions, openedConnections, openedSingleDatabaseConnections } from '../stores';
|
||||||
|
|
||||||
const { values, setFieldValue } = getFormContext();
|
const { values, setFieldValue } = getFormContext();
|
||||||
const electron = getElectron();
|
const electron = getElectron();
|
||||||
@@ -24,31 +24,38 @@
|
|||||||
// if (!$values.sshPort) setFieldValue('sshPort', '22');
|
// if (!$values.sshPort) setFieldValue('sshPort', '22');
|
||||||
if (!$values.sshKeyfile && $platformInfo) setFieldValue('sshKeyfile', $platformInfo.defaultKeyfile);
|
if (!$values.sshKeyfile && $platformInfo) setFieldValue('sshKeyfile', $platformInfo.defaultKeyfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: isConnected = $openedConnections.includes($values._id) || $openedSingleDatabaseConnections.includes($values._id);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FormCheckboxField label="Use SSH tunnel" name="useSshTunnel" />
|
<FormCheckboxField label="Use SSH tunnel" name="useSshTunnel" disabled={isConnected} />
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-9 mr-1">
|
<div class="col-9 mr-1">
|
||||||
<FormTextField label="Host" name="sshHost" disabled={!useSshTunnel} templateProps={{ noMargin: true }} />
|
<FormTextField
|
||||||
|
label="Host"
|
||||||
|
name="sshHost"
|
||||||
|
disabled={isConnected || !useSshTunnel}
|
||||||
|
templateProps={{ noMargin: true }}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<FormTextField
|
<FormTextField
|
||||||
label="Port"
|
label="Port"
|
||||||
name="sshPort"
|
name="sshPort"
|
||||||
disabled={!useSshTunnel}
|
disabled={isConnected || !useSshTunnel}
|
||||||
templateProps={{ noMargin: true }}
|
templateProps={{ noMargin: true }}
|
||||||
placeholder="22"
|
placeholder="22"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<FormTextField label="Bastion host (Jump host)" name="sshBastionHost" disabled={!useSshTunnel} />
|
<FormTextField label="Bastion host (Jump host)" name="sshBastionHost" disabled={isConnected || !useSshTunnel} />
|
||||||
|
|
||||||
<FormSelectField
|
<FormSelectField
|
||||||
label="SSH Authentication"
|
label="SSH Authentication"
|
||||||
name="sshMode"
|
name="sshMode"
|
||||||
isNative
|
isNative
|
||||||
disabled={!useSshTunnel}
|
disabled={isConnected || !useSshTunnel}
|
||||||
options={[
|
options={[
|
||||||
{ value: 'userPassword', label: 'Username & password' },
|
{ value: 'userPassword', label: 'Username & password' },
|
||||||
{ value: 'agent', label: 'SSH agent' },
|
{ value: 'agent', label: 'SSH agent' },
|
||||||
@@ -57,19 +64,24 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{#if $values.sshMode != 'userPassword'}
|
{#if $values.sshMode != 'userPassword'}
|
||||||
<FormTextField label="Login" name="sshLogin" disabled={!useSshTunnel} />
|
<FormTextField label="Login" name="sshLogin" disabled={isConnected || !useSshTunnel} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if $values.sshMode == 'userPassword'}
|
{#if $values.sshMode == 'userPassword'}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6 mr-1">
|
<div class="col-6 mr-1">
|
||||||
<FormTextField label="Login" name="sshLogin" disabled={!useSshTunnel} templateProps={{ noMargin: true }} />
|
<FormTextField
|
||||||
|
label="Login"
|
||||||
|
name="sshLogin"
|
||||||
|
disabled={isConnected || !useSshTunnel}
|
||||||
|
templateProps={{ noMargin: true }}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<FormPasswordField
|
<FormPasswordField
|
||||||
label="Password"
|
label="Password"
|
||||||
name="sshPassword"
|
name="sshPassword"
|
||||||
disabled={!useSshTunnel}
|
disabled={isConnected || !useSshTunnel}
|
||||||
templateProps={{ noMargin: true }}
|
templateProps={{ noMargin: true }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -82,7 +94,7 @@
|
|||||||
<FormElectronFileSelector
|
<FormElectronFileSelector
|
||||||
label="Private key file"
|
label="Private key file"
|
||||||
name="sshKeyfile"
|
name="sshKeyfile"
|
||||||
disabled={!useSshTunnel}
|
disabled={isConnected || !useSshTunnel}
|
||||||
templateProps={{ noMargin: true }}
|
templateProps={{ noMargin: true }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -90,7 +102,7 @@
|
|||||||
<FormPasswordField
|
<FormPasswordField
|
||||||
label="Key file passphrase"
|
label="Key file passphrase"
|
||||||
name="sshKeyfilePassword"
|
name="sshKeyfilePassword"
|
||||||
disabled={!useSshTunnel}
|
disabled={isConnected || !useSshTunnel}
|
||||||
templateProps={{ noMargin: true }}
|
templateProps={{ noMargin: true }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,20 +6,30 @@
|
|||||||
import FormCheckboxField from '../forms/FormCheckboxField.svelte';
|
import FormCheckboxField from '../forms/FormCheckboxField.svelte';
|
||||||
import getElectron from '../utility/getElectron';
|
import getElectron from '../utility/getElectron';
|
||||||
import FormPasswordField from '../forms/FormPasswordField.svelte';
|
import FormPasswordField from '../forms/FormPasswordField.svelte';
|
||||||
|
import { openedConnections, openedSingleDatabaseConnections } from '../stores';
|
||||||
|
|
||||||
const { values, setFieldValue } = getFormContext();
|
const { values, setFieldValue } = getFormContext();
|
||||||
const electron = getElectron();
|
const electron = getElectron();
|
||||||
|
|
||||||
$: useSsl = $values.useSsl;
|
$: useSsl = $values.useSsl;
|
||||||
|
$: isConnected = $openedConnections.includes($values._id) || $openedSingleDatabaseConnections.includes($values._id);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FormCheckboxField label="Use SSL" name="useSsl" />
|
<FormCheckboxField label="Use SSL" name="useSsl" disabled={isConnected} />
|
||||||
<FormElectronFileSelector label="CA Cert (optional)" name="sslCaFile" disabled={!useSsl || !electron} />
|
<FormElectronFileSelector label="CA Cert (optional)" name="sslCaFile" disabled={isConnected || !useSsl || !electron} />
|
||||||
<FormElectronFileSelector label="Certificate (optional)" name="sslCertFile" disabled={!useSsl || !electron} />
|
<FormElectronFileSelector
|
||||||
|
label="Certificate (optional)"
|
||||||
|
name="sslCertFile"
|
||||||
|
disabled={isConnected || !useSsl || !electron}
|
||||||
|
/>
|
||||||
<FormPasswordField
|
<FormPasswordField
|
||||||
label="Certificate key file password (optional)"
|
label="Certificate key file password (optional)"
|
||||||
name="sslCertFilePassword"
|
name="sslCertFilePassword"
|
||||||
disabled={!useSsl || !electron}
|
disabled={isConnected || !useSsl || !electron}
|
||||||
/>
|
/>
|
||||||
<FormElectronFileSelector label="Key file (optional)" name="sslKeyFile" disabled={!useSsl || !electron} />
|
<FormElectronFileSelector
|
||||||
<FormCheckboxField label="Reject unauthorized" name="sslRejectUnauthorized" disabled={!useSsl} />
|
label="Key file (optional)"
|
||||||
|
name="sslKeyFile"
|
||||||
|
disabled={isConnected || !useSsl || !electron}
|
||||||
|
/>
|
||||||
|
<FormCheckboxField label="Reject unauthorized" name="sslRejectUnauthorized" disabled={isConnected || !useSsl} />
|
||||||
|
|||||||
@@ -17,15 +17,22 @@
|
|||||||
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
|
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
|
||||||
import { writable } from 'svelte/store';
|
import { writable } from 'svelte/store';
|
||||||
import FormProviderCore from '../forms/FormProviderCore.svelte';
|
import FormProviderCore from '../forms/FormProviderCore.svelte';
|
||||||
import { extensions, getCurrentConfig, openedTabs } from '../stores';
|
import {
|
||||||
|
extensions,
|
||||||
|
getCurrentConfig,
|
||||||
|
openedConnections,
|
||||||
|
openedSingleDatabaseConnections,
|
||||||
|
openedTabs,
|
||||||
|
} from '../stores';
|
||||||
import _, { Dictionary } from 'lodash';
|
import _, { Dictionary } from 'lodash';
|
||||||
import { apiCall } from '../utility/api';
|
import { apiCall } from '../utility/api';
|
||||||
import { showSnackbarSuccess } from '../utility/snackbar';
|
import { showSnackbarSuccess } from '../utility/snackbar';
|
||||||
import { changeTab } from '../utility/common';
|
import { changeTab } from '../utility/common';
|
||||||
import getConnectionLabel from '../utility/getConnectionLabel';
|
import getConnectionLabel from '../utility/getConnectionLabel';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { openConnection } from '../appobj/ConnectionAppObject.svelte';
|
import { disconnectServerConnection, openConnection } from '../appobj/ConnectionAppObject.svelte';
|
||||||
import { closeMultipleTabs } from '../widgets/TabsPanel.svelte';
|
import { closeMultipleTabs } from '../widgets/TabsPanel.svelte';
|
||||||
|
import { disconnectDatabaseConnection } from '../appobj/DatabaseAppObject.svelte';
|
||||||
|
|
||||||
export let connection;
|
export let connection;
|
||||||
export let tabid;
|
export let tabid;
|
||||||
@@ -136,7 +143,15 @@
|
|||||||
}
|
}
|
||||||
const saved = await apiCall('connections/save', connection);
|
const saved = await apiCall('connections/save', connection);
|
||||||
openConnection(saved);
|
openConnection(saved);
|
||||||
closeMultipleTabs(x => x.tabid == tabid, true);
|
// closeMultipleTabs(x => x.tabid == tabid, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleDisconnect() {
|
||||||
|
if ($values.singleDatabase) {
|
||||||
|
disconnectDatabaseConnection($values._id, $values.defaultDatabase);
|
||||||
|
} else {
|
||||||
|
disconnectServerConnection($values._id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
@@ -144,6 +159,8 @@
|
|||||||
$values = await apiCall('connections/get', { conid });
|
$values = await apiCall('connections/get', { conid });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$: isConnected = $openedConnections.includes($values._id) || $openedSingleDatabaseConnections.includes($values._id);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FormProviderCore template={FormFieldTemplateLarge} {values}>
|
<FormProviderCore template={FormFieldTemplateLarge} {values}>
|
||||||
@@ -171,13 +188,17 @@
|
|||||||
{#if driver}
|
{#if driver}
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<FormButton value="Connect" on:click={handleConnect} />
|
{#if isConnected}
|
||||||
{#if isTesting}
|
<FormButton value="Disconnect" on:click={handleDisconnect} />
|
||||||
<FormButton value="Cancel test" on:click={handleCancelTest} />
|
|
||||||
{:else}
|
{:else}
|
||||||
<FormButton value="Test" on:click={handleTest} />
|
<FormButton value="Connect" on:click={handleConnect} />
|
||||||
|
{#if isTesting}
|
||||||
|
<FormButton value="Cancel test" on:click={handleCancelTest} />
|
||||||
|
{:else}
|
||||||
|
<FormButton value="Test" on:click={handleTest} />
|
||||||
|
{/if}
|
||||||
|
<FormButton value="Save" on:click={handleSave} />
|
||||||
{/if}
|
{/if}
|
||||||
<FormButton value="Save" on:click={handleSave} />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="test-result">
|
<div class="test-result">
|
||||||
{#if !isTesting && sqlConnectResult && sqlConnectResult.msgtype == 'connected'}
|
{#if !isTesting && sqlConnectResult && sqlConnectResult.msgtype == 'connected'}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ openedTabs.subscribe(value => {
|
|||||||
|
|
||||||
const lastTab = lastCurrentTab;
|
const lastTab = lastCurrentTab;
|
||||||
lastCurrentTab = newCurrentTab;
|
lastCurrentTab = newCurrentTab;
|
||||||
if (lastTab?.tabComponent == 'ConnectionTab') return;
|
// if (lastTab?.tabComponent == 'ConnectionTab') return;
|
||||||
|
|
||||||
if (newCurrentTab) {
|
if (newCurrentTab) {
|
||||||
const { conid, database } = newCurrentTab.props || {};
|
const { conid, database } = newCurrentTab.props || {};
|
||||||
|
|||||||
Reference in New Issue
Block a user