mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-05-01 17:53:59 +00:00
define description modal
This commit is contained in:
@@ -72,7 +72,7 @@
|
|||||||
<FontIcon icon="img sort-desc" />
|
<FontIcon icon="img sort-desc" />
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
<DropDownButton menu={getMenu} />
|
<DropDownButton menu={getMenu} narrow />
|
||||||
<div class="horizontal-split-handle resizeHandleControl" use:splitterDrag={'clientX'} on:resizeSplitter />
|
<div class="horizontal-split-handle resizeHandleControl" use:splitterDrag={'clientX'} on:resizeSplitter />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,9 @@
|
|||||||
import keycodes from '../utility/keycodes';
|
import keycodes from '../utility/keycodes';
|
||||||
|
|
||||||
import DropDownButton from '../elements/DropDownButton.svelte';
|
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 isReadOnly = false;
|
||||||
export let filterType;
|
export let filterType;
|
||||||
@@ -20,6 +23,9 @@
|
|||||||
export let showResizeSplitter = false;
|
export let showResizeSplitter = false;
|
||||||
export let onFocusGrid;
|
export let onFocusGrid;
|
||||||
export let onGetReference;
|
export let onGetReference;
|
||||||
|
export let foreignKey = null;
|
||||||
|
export let conid = null;
|
||||||
|
export let database = null;
|
||||||
|
|
||||||
let value;
|
let value;
|
||||||
let isError;
|
let isError;
|
||||||
@@ -190,6 +196,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleShowDictionary() {
|
||||||
|
showModal(DictionaryLookupModal, {
|
||||||
|
conid,
|
||||||
|
database,
|
||||||
|
pureName: foreignKey.refTableName,
|
||||||
|
schemaName: foreignKey.refSchemaName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$: value = filter;
|
$: value = filter;
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
@@ -226,9 +241,14 @@
|
|||||||
on:paste={handlePaste}
|
on:paste={handlePaste}
|
||||||
class:isError
|
class:isError
|
||||||
class:isOk
|
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}
|
{#if showResizeSplitter}
|
||||||
<div class="horizontal-split-handle resizeHandleControl" use:splitterDrag={'clientX'} on:resizeSplitter />
|
<div class="horizontal-split-handle resizeHandleControl" use:splitterDrag={'clientX'} on:resizeSplitter />
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -1234,6 +1234,9 @@
|
|||||||
>
|
>
|
||||||
<DataFilterControl
|
<DataFilterControl
|
||||||
onGetReference={value => (domFilterControlsRef.get()[col.uniqueName] = value)}
|
onGetReference={value => (domFilterControlsRef.get()[col.uniqueName] = value)}
|
||||||
|
foreignKey={col.foreignKey}
|
||||||
|
{conid}
|
||||||
|
{database}
|
||||||
filterType={col.filterType || getFilterType(col.dataType)}
|
filterType={col.filterType || getFilterType(col.dataType)}
|
||||||
filter={display.getFilter(col.uniqueName)}
|
filter={display.getFilter(col.uniqueName)}
|
||||||
setFilter={value => display.setFilter(col.uniqueName, value)}
|
setFilter={value => display.setFilter(col.uniqueName, value)}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
export let icon = 'icon chevron-down';
|
export let icon = 'icon chevron-down';
|
||||||
export let menu;
|
export let menu;
|
||||||
|
export let narrow = false;
|
||||||
let domButton;
|
let domButton;
|
||||||
|
|
||||||
function handleClick() {
|
function handleClick() {
|
||||||
@@ -17,6 +18,6 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<InlineButton square on:click={handleClick} bind:this={domButton}>
|
<InlineButton square {narrow} on:click={handleClick} bind:this={domButton}>
|
||||||
<FontIcon {icon} />
|
<FontIcon {icon} />
|
||||||
</InlineButton>
|
</InlineButton>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
export let square = false;
|
export let square = false;
|
||||||
|
export let narrow = false;
|
||||||
|
|
||||||
let domButton;
|
let domButton;
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</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">
|
<div class="inner">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
@@ -34,6 +35,10 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.narrow {
|
||||||
|
padding: 3px 1px;
|
||||||
|
}
|
||||||
|
|
||||||
.outer.disabled {
|
.outer.disabled {
|
||||||
color: var(--theme-font-3);
|
color: var(--theme-font-3);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,8 @@
|
|||||||
'icon check-all': 'mdi mdi-check-all',
|
'icon check-all': 'mdi mdi-check-all',
|
||||||
'icon checkbox-blank': 'mdi mdi-checkbox-blank-outline',
|
'icon checkbox-blank': 'mdi mdi-checkbox-blank-outline',
|
||||||
'icon checkbox-marked': 'mdi mdi-checkbox-marked-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 run': 'mdi mdi-play',
|
||||||
'icon chevron-down': 'mdi mdi-chevron-down',
|
'icon chevron-down': 'mdi mdi-chevron-down',
|
||||||
|
|||||||
103
packages/web/src/modals/DefineDictionaryDescriptionModal.svelte
Normal file
103
packages/web/src/modals/DefineDictionaryDescriptionModal.svelte
Normal 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>
|
||||||
46
packages/web/src/modals/DictionaryLookupModal.svelte
Normal file
46
packages/web/src/modals/DictionaryLookupModal.svelte
Normal 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>
|
||||||
75
packages/web/src/utility/dictionaryDescriptionTools.ts
Normal file
75
packages/web/src/utility/dictionaryDescriptionTools.ts
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,5 +10,6 @@ export function openArchiveFolder() {
|
|||||||
properties: ['openDirectory'],
|
properties: ['openDirectory'],
|
||||||
});
|
});
|
||||||
const linkedFolder = filePaths && filePaths[0];
|
const linkedFolder = filePaths && filePaths[0];
|
||||||
|
if (!linkedFolder) return;
|
||||||
axiosInstance.post('archive/create-link', { linkedFolder });
|
axiosInstance.post('archive/create-link', { linkedFolder });
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user