This commit is contained in:
Jan Prochazka
2021-03-04 15:20:08 +01:00
parent 7acea0f4ac
commit ef5bfb5a89
23 changed files with 368 additions and 72 deletions

View File

@@ -0,0 +1 @@
<input type="checkbox" {...$$restProps} />

View File

@@ -1,5 +1,15 @@
<script>
import FormStyledButton from '../widgets/FormStyledButton.svelte';
import { getFormContext } from './FormProviderCore.svelte';
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
const { values } = getFormContext();
function handleClick() {
dispatch('click', $values);
}
</script>
<FormStyledButton type="button" on:click {...$$props} />
<FormStyledButton type="button" on:click={handleClick} {...$$props} />

View File

@@ -0,0 +1,14 @@
<script lang="ts">
import { getFormContext } from './FormProviderCore.svelte';
import FromCheckboxFieldRaw from './FromTextFieldRaw.svelte';
export let label;
export let name;
export let templateProps = {};
const { template } = getFormContext();
</script>
<svelte:component this={template} type="checkbox" {label} {...templateProps}>
<FromCheckboxFieldRaw {name} {...$$restProps} />
</svelte:component>

View File

@@ -2,11 +2,12 @@
import { writable } from 'svelte/store';
import FormProviderCore from './FormProviderCore.svelte';
export let initivalValues = {};
export let initialValues = {};
export let template;
const values = writable(initivalValues);
const values = writable(initialValues);
</script>
<FormProviderCore {values}>
<FormProviderCore {values} {template}>
<slot />
</FormProviderCore>

View File

@@ -1,5 +1,6 @@
<script lang="ts" context="module">
import { getContext, setContext } from 'svelte';
const contextKey = 'formProviderContextKey';
export function getFormContext(): any {
@@ -11,9 +12,16 @@
import keycodes from '../utility/keycodes';
export let values;
export let template;
const setFieldValue = (name, value) => {
values.update(x => ({ ...x, [name]: value }));
};
const context = {
values,
template,
setFieldValue,
submitActionRef: { current: null },
};

View File

@@ -0,0 +1,14 @@
<script lang="ts">
import { getFormContext } from './FormProviderCore.svelte';
import FromSelectFieldRaw from './FromSelectFieldRaw.svelte';
export let label;
export let name;
export let templateProps = {};
const { template } = getFormContext();
</script>
<svelte:component this={template} type="select" {label} {...templateProps}>
<FromSelectFieldRaw {name} {...$$restProps} />
</svelte:component>

View File

@@ -6,10 +6,15 @@
const dispatch = createEventDispatcher();
const { submitActionRef } = getFormContext();
const { values } = getFormContext();
function handleClick() {
dispatch('click', $values);
}
submitActionRef.current = () => {
dispatch('click');
handleClick();
};
</script>
<FormStyledButton type="submit" on:click {...$$props} />
<FormStyledButton type="submit" on:click={handleClick} {...$$props} />

View File

@@ -0,0 +1,14 @@
<script lang="ts">
import { getFormContext } from './FormProviderCore.svelte';
import FromTextFieldRaw from './FromTextFieldRaw.svelte';
export let label;
export let name;
export let templateProps = {};
const { template } = getFormContext();
</script>
<svelte:component this={template} type="text" {label} {...templateProps}>
<FromTextFieldRaw {name} {...$$restProps} />
</svelte:component>

View File

@@ -0,0 +1,10 @@
<script lang="ts">
import { getFormContext } from './FormProviderCore.svelte';
import TextField from './TextField.svelte';
export let name;
const { values, setFieldValue } = getFormContext();
</script>
<TextField {...$$restProps} value={$values[name]} on:change={e => setFieldValue(name, e.target['checked'])} />

View File

@@ -0,0 +1,10 @@
<script lang="ts">
import { getFormContext } from './FormProviderCore.svelte';
import SelectField from './SelectField.svelte';
export let name;
const { values, setFieldValue } = getFormContext();
</script>
<SelectField {...$$restProps} value={$values[name]} on:change={e => setFieldValue(name, e.target['value'])} />

View File

@@ -0,0 +1,10 @@
<script lang="ts">
import { getFormContext } from './FormProviderCore.svelte';
import TextField from './TextField.svelte';
export let name;
const { values, setFieldValue } = getFormContext();
</script>
<TextField {...$$restProps} value={$values[name]} on:change={e => setFieldValue(name, e.target['value'])} />

View File

@@ -0,0 +1,14 @@
<script lang="ts">
export let options = [];
export let value;
$: console.log('FIELD', $$props.value);
</script>
<select {...$$restProps} on:change>
{#each options as x (x.value)}
<option value={x.value} selected={value == x.value}>
{x.label}
</option>
{/each}
</select>

View File

@@ -0,0 +1,5 @@
<script lang="ts">
export let value;
</script>
<input type="text" {...$$restProps} bind:value on:change />

View File

@@ -3,18 +3,42 @@
import FormButton from '../forms/FormButton.svelte';
import FormProvider from '../forms/FormProvider.svelte';
import FormSubmit from '../forms/FormSubmit.svelte';
import TabControl from '../widgets/TabControl.svelte';
import ConnectionModalDriverFields from './ConnectionModalDriverFields.svelte';
import FormFieldTemplateLarge from './FormFieldTemplateLarge.svelte';
import ModalBase from './ModalBase.svelte';
export let connection;
</script>
<FormProvider>
<ModalBase {...$$restProps}>
<FormProvider
template={FormFieldTemplateLarge}
initialValues={connection || { server: 'localhost', engine: 'mssql@dbgate-plugin-mssql' }}
>
<ModalBase {...$$restProps} noPadding>
<div slot="header">Add connection</div>
xxx
<TabControl
isInline
tabs={[
{
label: 'Main',
component: ConnectionModalDriverFields,
},
{
label: 'SSH Tunnel',
slot: 1,
},
]}
>
<div slot="1">SSH</div>
</TabControl>
<div slot="footer" class="flex">
<div class="buttons">
<FormButton value="Test" />
<FormSubmit value="Save" on:click={() => console.log('SAVE')} />
<FormSubmit value="Save" on:click={v => console.log('SAVE', v.detail)} />
</div>
</div>
</ModalBase>

View File

@@ -0,0 +1,55 @@
<script lang="ts">
import { getFormContext } from '../forms/FormProviderCore.svelte';
import FormSelectField from '../forms/FormSelectField.svelte';
import FormTextField from '../forms/FormTextField.svelte';
import { extensions } from '../stores';
import { useAuthTypes } from '../utility/metadataLoaders';
const { values } = getFormContext();
$: authType = $values.authType;
$: engine = $values.engine;
$: authTypes = useAuthTypes({ engine });
$: currentAuthType = $authTypes && $authTypes.find(x => x.name == authType);
$: disabledFields = (currentAuthType ? currentAuthType.disabledFields : null) || [];
$: driver = $extensions.drivers.find(x => x.engine == engine);
</script>
<FormSelectField
label="Database engine"
name="engine"
options={[
{ label: '(select driver)', value: '' },
...$extensions.drivers.map(driver => ({
value: driver.engine,
label: driver.title,
})),
]}
/>
<div class="row">
<div class="col-9 mr-1">
<FormTextField
label="Server"
name="server"
disabled={disabledFields.includes('server')}
templateProps={{ noMargin: true }}
/>
</div>
<div class="col-3 mr-1">
<FormTextField
label="Port"
name="port"
disabled={disabledFields.includes('port')}
templateProps={{ noMargin: true }}
placeholder={driver && driver.defaultPort}
/>
</div>
</div>
<style>
.row {
margin: var(--dim-large-form-margin);
display: flex;
}
</style>

View File

@@ -0,0 +1,32 @@
<script lang="ts">
export let type;
export let label;
export let noMargin;
export let disabled = false;
export let labelProps: any = {};
</script>
<div class="largeFormMarker" class:noMargin>
{#if type == 'checkbox'}
<slot />
<span {...labelProps} on:click={labelProps.onClick} class:disabled>{label}</span>
{:else}
<div class="label" {...labelProps} on:click={labelProps.onClick}>
<span {...labelProps} on:click={labelProps.onClick} class:disabled>{label}</span>
</div>
<slot />
{/if}
</div>
<style>
.label {
margin-bottom: 3px;
color: var(--theme-font-3);
}
.largeFormMarker:not(.noMargin) {
margin: var(--dim-large-form-margin);
}
.disabled {
color: var(--theme-font-3);
}
</style>

View File

@@ -4,8 +4,8 @@
import clickOutside from '../utility/clickOutside';
import keycodes from '../utility/keycodes';
export let fullScreen;
export let noPadding;
export let fullScreen = false;
export let noPadding = false;
export let modalId;
function handleCloseModal() {

View File

@@ -119,6 +119,11 @@ const allFilesLoader = () => ({
params: {},
reloadTrigger: `all-files-changed`,
});
const authTypesLoader = ({ engine }) => ({
url: 'plugins/auth-types',
params: { engine },
reloadTrigger: `installed-plugins-changed`,
});
async function getCore(loader, args) {
const { url, params, reloadTrigger, transform } = loader(args);
@@ -377,3 +382,10 @@ export function getFavorites(args) {
export function useFavorites(args) {
return useCore(favoritesLoader, args);
}
export function getAuthTypes(args) {
return getCore(authTypesLoader, args);
}
export function useAuthTypes(args) {
return useCore(authTypesLoader, args);
}

View File

@@ -0,0 +1,93 @@
<script lang="ts">
interface TabDef {
label: string;
slot?: number;
component?: any;
props?: any;
}
export let tabs: TabDef[];
export let value = 0;
export let isInline = false;
</script>
<div class="main">
<div class="tabs">
{#each tabs as tab, index}
<div class="tab-item" class:selected={value == index} on:click={() => (value = index)}>
<span class="ml-2">
{tab.label}
</span>
</div>
{/each}
</div>
<div class="content-container">
{#each tabs as tab, index}
<div class="container" class:isInline class:tabVisible={index == value}>
<svelte:component this={tab.component} {...tab.props} />
{#if tab.slot == 0}<slot name="0" />{/if}
{#if tab.slot == 1}<slot name="1" />{/if}
{#if tab.slot == 2}<slot name="2" />{/if}
{#if tab.slot == 3}<slot name="3" />{/if}
{#if tab.slot == 4}<slot name="4" />{/if}
{#if tab.slot == 5}<slot name="5" />{/if}
{#if tab.slot == 6}<slot name="6" />{/if}
{#if tab.slot == 7}<slot name="7" />{/if}
</div>
{/each}
</div>
</div>
<style>
.main {
display: flex;
flex: 1;
flex-direction: column;
}
.tabs {
display: flex;
height: var(--dim-tabs-height);
right: 0;
background-color: var(--theme-bg-2);
}
.tab-item {
border-right: 1px solid var(--theme-border);
padding-left: 15px;
padding-right: 15px;
display: flex;
align-items: center;
cursor: pointer;
}
/* .tab-item:hover {
color: ${props => props.theme.tabs_font_hover};
} */
.tab-item.selected {
background-color: var(--theme-bg-1);
}
.content-container {
flex: 1;
position: relative;
}
.container:not(.isInline) {
position: absolute;
display: flex;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.container:not(.tabVisible):not(.isInline) {
visibility: hidden;
}
.container.isInline:not(.tabVisible) {
display: none;
}
</style>