define description modal

This commit is contained in:
Jan Prochazka 2021-11-13 11:08:24 +01:00
parent ec5b887e78
commit 1f821fc654
10 changed files with 261 additions and 5 deletions

View File

@ -72,7 +72,7 @@
<FontIcon icon="img sort-desc" />
</span>
{/if}
<DropDownButton menu={getMenu} />
<DropDownButton menu={getMenu} narrow />
<div class="horizontal-split-handle resizeHandleControl" use:splitterDrag={'clientX'} on:resizeSplitter />
</div>

View File

@ -12,6 +12,9 @@
import keycodes from '../utility/keycodes';
import DropDownButton from '../elements/DropDownButton.svelte';
import InlineButton from '../elements/InlineButton.svelte';
import FontIcon from '../icons/FontIcon.svelte';
import DictionaryLookupModal from '../modals/DictionaryLookupModal.svelte';
export let isReadOnly = false;
export let filterType;
@ -20,6 +23,9 @@
export let showResizeSplitter = false;
export let onFocusGrid;
export let onGetReference;
export let foreignKey = null;
export let conid = null;
export let database = null;
let value;
let isError;
@ -190,6 +196,15 @@
}
}
function handleShowDictionary() {
showModal(DictionaryLookupModal, {
conid,
database,
pureName: foreignKey.refTableName,
schemaName: foreignKey.refSchemaName,
});
}
$: value = filter;
$: {
@ -226,9 +241,14 @@
on:paste={handlePaste}
class:isError
class:isOk
placeholder='Filter'
placeholder="Filter"
/>
<DropDownButton icon="icon filter" menu={createMenu} />
{#if foreignKey && conid && database}
<InlineButton on:click={handleShowDictionary} narrow square>
<FontIcon icon="icon dots-horizontal" />
</InlineButton>
{/if}
<DropDownButton icon="icon filter" menu={createMenu} narrow />
{#if showResizeSplitter}
<div class="horizontal-split-handle resizeHandleControl" use:splitterDrag={'clientX'} on:resizeSplitter />
{/if}

View File

@ -1234,6 +1234,9 @@
>
<DataFilterControl
onGetReference={value => (domFilterControlsRef.get()[col.uniqueName] = value)}
foreignKey={col.foreignKey}
{conid}
{database}
filterType={col.filterType || getFilterType(col.dataType)}
filter={display.getFilter(col.uniqueName)}
setFilter={value => display.setFilter(col.uniqueName, value)}

View File

@ -7,6 +7,7 @@
export let icon = 'icon chevron-down';
export let menu;
export let narrow = false;
let domButton;
function handleClick() {
@ -17,6 +18,6 @@
}
</script>
<InlineButton square on:click={handleClick} bind:this={domButton}>
<InlineButton square {narrow} on:click={handleClick} bind:this={domButton}>
<FontIcon {icon} />
</InlineButton>

View File

@ -1,6 +1,7 @@
<script lang="ts">
export let disabled = false;
export let square = false;
export let narrow = false;
let domButton;
@ -9,7 +10,7 @@
}
</script>
<div class="outer buttonLike" class:disabled class:square on:click bind:this={domButton}>
<div class="outer buttonLike" class:disabled class:square class:narrow on:click bind:this={domButton}>
<div class="inner">
<slot />
</div>
@ -34,6 +35,10 @@
display: flex;
}
.narrow {
padding: 3px 1px;
}
.outer.disabled {
color: var(--theme-font-3);
}

View File

@ -66,6 +66,8 @@
'icon check-all': 'mdi mdi-check-all',
'icon checkbox-blank': 'mdi mdi-checkbox-blank-outline',
'icon checkbox-marked': 'mdi mdi-checkbox-marked-outline',
'icon dots-horizontal': 'mdi mdi-dots-horizontal',
'icon dots-vertical': 'mdi mdi-dots-vertical',
'icon run': 'mdi mdi-play',
'icon chevron-down': 'mdi mdi-chevron-down',

View File

@ -0,0 +1,103 @@
<script lang="ts">
import FormProvider from '../forms/FormProvider.svelte';
import FormSubmit from '../forms/FormSubmit.svelte';
import FormStyledButton from '../elements/FormStyledButton.svelte';
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools';
import { useTableInfo } from '../utility/metadataLoaders';
import TableControl from '../elements/TableControl.svelte';
import TextField from '../forms/TextField.svelte';
import FormTextField from '../forms/FormTextField.svelte';
import { writable } from 'svelte/store';
import FormProviderCore from '../forms/FormProviderCore.svelte';
import {
changeDelimitedColumnList,
getDictionaryDescription,
parseDelimitedColumnList,
saveDictionaryDescription,
} from '../utility/dictionaryDescriptionTools';
import { includes } from 'lodash';
import FormCheckboxField from '../forms/FormCheckboxField.svelte';
export let conid;
export let database;
export let pureName;
export let schemaName;
export let onConfirm;
$: tableInfo = useTableInfo({ conid, database, schemaName, pureName });
$: descriptionInfo = getDictionaryDescription($tableInfo, conid, database);
const values = writable({});
function initValues(descriptionInfo) {
$values = {
columns: descriptionInfo.expression,
delimiter: descriptionInfo.delimiter,
};
}
$: if (descriptionInfo) initValues(descriptionInfo);
</script>
<FormProviderCore {values}>
<ModalBase {...$$restProps}>
<svelte:fragment slot="header">Define description</svelte:fragment>
<div class="wrapper">
<TableControl
rows={$tableInfo?.columns || []}
columns={[
{ fieldName: 'checked', header: '', slot: 1 },
{ fieldName: 'columnName', header: 'Column' },
{ fieldName: 'dataType', header: 'Data type' },
]}
>
<input
let:row
type="checkbox"
slot="1"
checked={parseDelimitedColumnList($values.columns).includes(row.columnName)}
on:change={e => {
$values = {
...$values,
columns: changeDelimitedColumnList($values.columns, row.columnName, e.target.checked),
};
}}
/>
</TableControl>
</div>
<FormTextField name="columns" label="Show columns" />
<FormTextField name="delimiter" label="Delimiter" />
<FormCheckboxField name="useForAllDatabases" label="Use for all databases" />
<svelte:fragment slot="footer">
<FormSubmit
value="OK"
on:click={() => {
closeCurrentModal();
saveDictionaryDescription(
$tableInfo,
conid,
database,
$values.columns,
$values.delimiter,
$values.useForAllDatabases
);
onConfirm();
}}
/>
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} />
</svelte:fragment>
</ModalBase>
</FormProviderCore>
<style>
.wrapper {
margin: var(--dim-large-form-margin);
}
</style>

View File

@ -0,0 +1,46 @@
<script lang="ts">
import FormProvider from '../forms/FormProvider.svelte';
import FormSubmit from '../forms/FormSubmit.svelte';
import FormStyledButton from '../elements/FormStyledButton.svelte';
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal, showModal } from './modalTools';
import DefineDictionaryDescriptionModal from './DefineDictionaryDescriptionModal.svelte';
export let onConfirm;
export let conid;
export let database;
export let pureName;
export let schemaName;
function defineDescription() {
showModal(DefineDictionaryDescriptionModal, {
conid,
database,
schemaName,
pureName,
onConfirm: () => reload(),
});
}
function reload() {}
</script>
<FormProvider>
<ModalBase {...$$restProps}>
<svelte:fragment slot="header">Lookup from {pureName}</svelte:fragment>
{pureName}
<svelte:fragment slot="footer">
<FormSubmit
value="OK"
on:click={() => {
closeCurrentModal();
onConfirm();
}}
/>
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} />
<FormStyledButton type="button" value="Customize" on:click={defineDescription} />
</svelte:fragment>
</ModalBase>
</FormProvider>

View File

@ -0,0 +1,75 @@
import { TableInfo } from 'dbgate-types';
import _ from 'lodash';
import { getLocalStorage, setLocalStorage, removeLocalStorage } from './storageCache';
interface DictionaryDescription {
expression: string;
columns: string[];
delimiter: string;
}
function checkDescription(desc: DictionaryDescription, table: TableInfo) {
return desc.columns.length > 0 && desc.columns.every(x => table.columns.find(y => y.columnName == x));
}
export function getDictionaryDescription(table: TableInfo, conid: string, database: string): DictionaryDescription {
const keySpecific = `dictionary_spec_${table.schemaName}||${table.pureName}||${conid}||${database}`;
const keyCommon = `dictionary_spec_${table.schemaName}||${table.pureName}`;
const cachedSpecific = getLocalStorage(keySpecific);
const cachedCommon = getLocalStorage(keyCommon);
if (cachedSpecific && checkDescription(cachedSpecific, table)) return cachedSpecific;
if (cachedCommon && checkDescription(cachedCommon, table)) return cachedCommon;
const descColumn = table.columns.find(x => x?.dataType?.toLowerCase()?.includes('char'));
if (descColumn) {
return {
columns: [descColumn.columnName],
delimiter: null,
expression: descColumn.columnName,
};
}
return null;
}
export function parseDelimitedColumnList(columns) {
return _.compact((columns || '').split(',').map(x => x.trim()));
}
export function changeDelimitedColumnList(columns, columnName, isChecked) {
const parsed = parseDelimitedColumnList(columns);
const includes = parsed.includes(columnName);
if (includes == isChecked) return columns;
if (isChecked) parsed.push(columnName);
else _.remove(parsed, x => x == columnName);
return parsed.join(',');
}
export function saveDictionaryDescription(
table: TableInfo,
conid: string,
database: string,
expression: string,
delimiter: string,
useForAllDatabases: boolean
) {
const keySpecific = `dictionary_spec_${table.schemaName}||${table.pureName}||${conid}||${database}`;
const keyCommon = `dictionary_spec_${table.schemaName}||${table.pureName}`;
removeLocalStorage(keySpecific);
if (useForAllDatabases) removeLocalStorage(keyCommon);
const description = {
columns: parseDelimitedColumnList(expression),
expression,
delimiter,
};
if (useForAllDatabases) {
setLocalStorage(keyCommon, description);
} else {
setLocalStorage(keySpecific, description);
}
}

View File

@ -10,5 +10,6 @@ export function openArchiveFolder() {
properties: ['openDirectory'],
});
const linkedFolder = filePaths && filePaths[0];
if (!linkedFolder) return;
axiosInstance.post('archive/create-link', { linkedFolder });
}