connection tabs - improved UX

This commit is contained in:
Jan Prochazka
2022-06-09 09:16:40 +02:00
parent 6f3076fddb
commit b54026b039
9 changed files with 183 additions and 72 deletions

View File

@@ -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) && {

View File

@@ -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;

View File

@@ -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);
} }

View File

@@ -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}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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} />

View File

@@ -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'}

View File

@@ -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 || {};