This commit is contained in:
Jan Prochazka
2022-05-19 13:12:11 +02:00
parent 1d013f96fb
commit 00c9ac61c4
7 changed files with 7 additions and 177 deletions

View File

@@ -1,163 +0,0 @@
<script lang="ts">
import registerCommand from '../commands/registerCommand';
import FormButton from '../forms/FormButton.svelte';
import FormProvider from '../forms/FormProvider.svelte';
import FormSubmit from '../forms/FormSubmit.svelte';
import FontIcon from '../icons/FontIcon.svelte';
import TabControl from '../elements/TabControl.svelte';
import ConnectionModalDriverFields from './ConnectionModalDriverFields.svelte';
import ConnectionModalSshTunnelFields from './ConnectionModalSshTunnelFields.svelte';
import ConnectionModalSslFields from './ConnectionModalSslFields.svelte';
import FormFieldTemplateLarge from '../forms/FormFieldTemplateLarge.svelte';
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal, closeModal, showModal } from './modalTools';
import createRef from '../utility/createRef';
import Link from '../elements/Link.svelte';
import ErrorMessageModal from './ErrorMessageModal.svelte';
import { writable } from 'svelte/store';
import FormProviderCore from '../forms/FormProviderCore.svelte';
import { extensions, getCurrentConfig } from '../stores';
import _ from 'lodash';
import { getDatabaseFileLabel } from '../utility/getConnectionLabel';
import { apiCall } from '../utility/api';
export let connection;
let isTesting;
let sqlConnectResult;
const values = writable(
connection || {
server: getCurrentConfig().isDocker ? 'dockerhost' : 'localhost',
engine: '',
}
);
$: engine = $values.engine;
$: driver = $extensions.drivers.find(x => x.engine == engine);
const testIdRef = createRef(0);
async function handleTest(e) {
isTesting = true;
testIdRef.update(x => x + 1);
const testid = testIdRef.get();
const resp = await apiCall('connections/test', e.detail);
if (testIdRef.get() != testid) return;
isTesting = false;
sqlConnectResult = resp;
}
function handleCancelTest() {
testIdRef.update(x => x + 1); // invalidate current test
isTesting = false;
}
async function handleSubmit(e) {
const allProps = [
'databaseFile',
'useDatabaseUrl',
'databaseUrl',
'authType',
'server',
'port',
'user',
'password',
'defaultDatabase',
'singleDatabase',
];
const visibleProps = allProps.filter(x => driver?.showConnectionField(x, $values));
const omitProps = _.difference(allProps, visibleProps);
if (!$values.defaultDatabase) omitProps.push('singleDatabase');
let connection = _.omit(e.detail, omitProps);
if (driver?.beforeConnectionSave) connection = driver?.beforeConnectionSave(connection);
apiCall('connections/save', connection);
closeCurrentModal();
}
</script>
<FormProviderCore template={FormFieldTemplateLarge} {values}>
<ModalBase {...$$restProps} noPadding>
<div slot="header">Add connection</div>
<TabControl
isInline
tabs={[
{
label: 'Main',
component: ConnectionModalDriverFields,
},
(!driver?.showConnectionTab || driver?.showConnectionTab('sshTunnel', $values)) && {
label: 'SSH Tunnel',
component: ConnectionModalSshTunnelFields,
},
(!driver?.showConnectionTab || driver?.showConnectionTab('ssl', $values)) && {
label: 'SSL',
component: ConnectionModalSslFields,
},
]}
/>
<div slot="footer" class="flex">
<div class="buttons">
{#if isTesting}
<FormButton value="Cancel test" on:click={handleCancelTest} />
{:else}
<FormButton value="Test" on:click={handleTest} />
{/if}
<FormSubmit value="Save" on:click={handleSubmit} />
</div>
<div class="test-result">
{#if !isTesting && sqlConnectResult && sqlConnectResult.msgtype == 'connected'}
<div>
Connected: <FontIcon icon="img ok" />
{sqlConnectResult.version}
</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}
{#if isTesting}
<div>
<FontIcon icon="icon loading" /> Testing connection
</div>
{/if}
</div>
</div>
</ModalBase>
</FormProviderCore>
<style>
.buttons {
flex-shrink: 0;
}
.test-result {
margin-left: 10px;
align-self: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.error-result {
white-space: normal;
}
</style>

View File

@@ -1,198 +0,0 @@
<script lang="ts">
import FormCheckboxField from '../forms/FormCheckboxField.svelte';
import FormElectronFileSelector from '../forms/FormElectronFileSelector.svelte';
import FormPasswordField from '../forms/FormPasswordField.svelte';
import _ from 'lodash';
import { getFormContext } from '../forms/FormProviderCore.svelte';
import FormRadioGroupField from '../forms/FormRadioGroupField.svelte';
import FormSelectField from '../forms/FormSelectField.svelte';
import FormTextField from '../forms/FormTextField.svelte';
import { extensions, getCurrentConfig } from '../stores';
import getElectron from '../utility/getElectron';
import { useAuthTypes } from '../utility/metadataLoaders';
import FormColorField from '../forms/FormColorField.svelte';
import FontIcon from '../icons/FontIcon.svelte';
const { values } = getFormContext();
const electron = getElectron();
$: authType = $values.authType;
$: engine = $values.engine;
$: useDatabaseUrl = $values.useDatabaseUrl;
$: authTypes = useAuthTypes({ engine });
$: currentAuthType = $authTypes && $authTypes.find(x => x.name == authType);
$: disabledFields = (currentAuthType ? currentAuthType.disabledFields : null) || [];
$: driver = $extensions.drivers.find(x => x.engine == engine);
$: defaultDatabase = $values.defaultDatabase;
$: showUser = driver?.showConnectionField('user', $values);
$: showPassword = driver?.showConnectionField('password', $values);
</script>
<FormSelectField
label="Database engine"
name="engine"
isNative
options={[
{ label: '(select driver)', value: '' },
...$extensions.drivers
.filter(driver => !driver.isElectronOnly || electron)
.map(driver => ({
value: driver.engine,
label: driver.title,
})),
]}
/>
{#if driver?.showConnectionField('databaseFile', $values)}
<FormElectronFileSelector label="Database file" name="databaseFile" disabled={!electron} />
{/if}
{#if driver?.showConnectionField('useDatabaseUrl', $values)}
<div class="radio">
<FormRadioGroupField
name="useDatabaseUrl"
options={[
{ label: 'Fill database connection details', value: '', default: true },
{ label: 'Use database URL', value: '1' },
]}
/>
</div>
{/if}
{#if driver?.showConnectionField('databaseUrl', $values)}
<FormTextField label="Database URL" name="databaseUrl" placeholder={driver?.databaseUrlPlaceholder} />
{/if}
{#if $authTypes && driver?.showConnectionField('authType', $values)}
<FormSelectField
label="Authentication"
name="authType"
isNative
defaultValue={driver?.defaultAuthTypeName}
options={$authTypes.map(auth => ({
value: auth.name,
label: auth.title,
}))}
/>
{/if}
{#if driver?.showConnectionField('server', $values)}
<div class="row">
<div class="col-9 mr-1">
<FormTextField
label="Server"
name="server"
disabled={disabledFields.includes('server')}
templateProps={{ noMargin: true }}
/>
</div>
{#if driver?.showConnectionField('port', $values)}
<div class="col-3 mr-1">
<FormTextField
label="Port"
name="port"
disabled={disabledFields.includes('port')}
templateProps={{ noMargin: true }}
placeholder={driver && driver.defaultPort}
/>
</div>
{/if}
</div>
{#if getCurrentConfig().isDocker}
<div class="row">
<FontIcon icon="img warn" padRight />
Under docker, localhost and 127.0.0.1 will not work, use dockerhost instead
</div>
{/if}
{/if}
{#if showUser && showPassword}
<div class="row">
{#if showUser}
<div class="col-6 mr-1">
<FormTextField
label="User"
name="user"
disabled={disabledFields.includes('user')}
templateProps={{ noMargin: true }}
/>
</div>
{/if}
{#if showPassword}
<div class="col-6 mr-1">
<FormPasswordField
label="Password"
name="password"
disabled={disabledFields.includes('password')}
templateProps={{ noMargin: true }}
/>
</div>
{/if}
</div>
{/if}
{#if showUser && !showPassword}
<FormTextField label="User" name="user" disabled={disabledFields.includes('user')} />
{/if}
{#if !showUser && showPassword}
<FormPasswordField label="Password" name="password" disabled={disabledFields.includes('password')} />
{/if}
{#if !disabledFields.includes('password') && showPassword}
<FormSelectField
label="Password mode"
isNative
name="passwordMode"
defaultValue="saveEncrypted"
options={[
{ value: 'saveEncrypted', label: 'Save and encrypt' },
{ value: 'saveRaw', label: 'Save raw (UNSAFE!!)' },
]}
/>
{/if}
{#if driver?.showConnectionField('isReadOnly', $values)}
<FormCheckboxField label="Is read only" name="isReadOnly" />
{/if}
{#if driver?.showConnectionField('defaultDatabase', $values)}
<FormTextField label="Default database" name="defaultDatabase" />
{/if}
{#if defaultDatabase && driver?.showConnectionField('singleDatabase', $values)}
<FormCheckboxField label={`Use only database ${defaultDatabase}`} name="singleDatabase" />
{/if}
{#if driver}
<div class="row">
<div class="col-6 mr-1">
<FormTextField label="Display name" name="displayName" templateProps={{ noMargin: true }} />
</div>
<div class="col-6 mr-1">
<FormColorField
useSelector
label="Color"
name="connectionColor"
emptyLabel="(not selected)"
templateProps={{ noMargin: true }}
/>
</div>
</div>
{/if}
<style>
.row {
margin: var(--dim-large-form-margin);
display: flex;
}
.radio {
margin-left: var(--dim-large-form-margin);
display: flex;
}
.radio :global(label) {
margin-right: 10px;
}
</style>

View File

@@ -1,109 +0,0 @@
<script lang="ts">
import FormElectronFileSelector from '../forms/FormElectronFileSelector.svelte';
import FormPasswordField from '../forms/FormPasswordField.svelte';
import { getFormContext } from '../forms/FormProviderCore.svelte';
import FormSelectField from '../forms/FormSelectField.svelte';
import FormTextField from '../forms/FormTextField.svelte';
import FormCheckboxField from '../forms/FormCheckboxField.svelte';
import getElectron from '../utility/getElectron';
import { usePlatformInfo } from '../utility/metadataLoaders';
import FontIcon from '../icons/FontIcon.svelte';
import { extensions } from '../stores';
const { values, setFieldValue } = getFormContext();
const electron = getElectron();
$: useSshTunnel = $values.useSshTunnel;
$: platformInfo = usePlatformInfo();
$: {
if (!$values.sshMode) setFieldValue('sshMode', 'userPassword');
if (!$values.sshPort) setFieldValue('sshPort', '22');
if (!$values.sshKeyfile && $platformInfo) setFieldValue('sshKeyfile', $platformInfo.defaultKeyfile);
}
</script>
<FormCheckboxField label="Use SSH tunnel" name="useSshTunnel" />
<div class="row">
<div class="col-9 mr-1">
<FormTextField label="Host" name="sshHost" disabled={!useSshTunnel} templateProps={{ noMargin: true }} />
</div>
<div class="col-3">
<FormTextField label="Port" name="sshPort" disabled={!useSshTunnel} templateProps={{ noMargin: true }} />
</div>
</div>
<FormTextField label="Bastion host (Jump host)" name="sshBastionHost" disabled={!useSshTunnel} />
<FormSelectField
label="SSH Authentication"
name="sshMode"
isNative
disabled={!useSshTunnel}
options={[
{ value: 'userPassword', label: 'Username & password' },
{ value: 'agent', label: 'SSH agent' },
electron && { value: 'keyFile', label: 'Key file' },
]}
/>
{#if $values.sshMode != 'userPassword'}
<FormTextField label="Login" name="sshLogin" disabled={!useSshTunnel} />
{/if}
{#if $values.sshMode == 'userPassword'}
<div class="row">
<div class="col-6 mr-1">
<FormTextField label="Login" name="sshLogin" disabled={!useSshTunnel} templateProps={{ noMargin: true }} />
</div>
<div class="col-6">
<FormPasswordField
label="Password"
name="sshPassword"
disabled={!useSshTunnel}
templateProps={{ noMargin: true }}
/>
</div>
</div>
{/if}
{#if $values.sshMode == 'keyFile'}
<div class="row">
<div class="col-6 mr-1">
<FormElectronFileSelector
label="Private key file"
name="sshKeyfile"
disabled={!useSshTunnel}
templateProps={{ noMargin: true }}
/>
</div>
<div class="col-6">
<FormPasswordField
label="Key file passphrase"
name="sshKeyfilePassword"
disabled={!useSshTunnel}
templateProps={{ noMargin: true }}
/>
</div>
</div>
{/if}
{#if useSshTunnel && $values.sshMode == 'agent'}
<div class="ml-3 mb-3">
{#if $platformInfo && $platformInfo.sshAuthSock}
<FontIcon icon="img ok" /> SSH Agent found
{:else}
<FontIcon icon="img error" /> SSH Agent not found
{/if}
</div>
{/if}
<style>
.row {
margin: var(--dim-large-form-margin);
display: flex;
}
</style>

View File

@@ -1,25 +0,0 @@
<script lang="ts">
import FormElectronFileSelector from '../forms/FormElectronFileSelector.svelte';
import { getFormContext } from '../forms/FormProviderCore.svelte';
import FormCheckboxField from '../forms/FormCheckboxField.svelte';
import getElectron from '../utility/getElectron';
import FormPasswordField from '../forms/FormPasswordField.svelte';
const { values, setFieldValue } = getFormContext();
const electron = getElectron();
$: useSsl = $values.useSsl;
</script>
<FormCheckboxField label="Use SSL" name="useSsl" />
<FormElectronFileSelector label="CA Cert (optional)" name="sslCaFile" disabled={!useSsl || !electron} />
<FormElectronFileSelector label="Certificate (optional)" name="sslCertFile" disabled={!useSsl || !electron} />
<FormPasswordField
label="Certificate key file password (optional)"
name="sslCertFilePassword"
disabled={!useSsl || !electron}
/>
<FormElectronFileSelector label="Key file (optional)" name="sslKeyFile" disabled={!useSsl || !electron} />
<FormCheckboxField label="Reject unauthorized" name="sslRejectUnauthorized" disabled={!useSsl} />