enum + set for mysql (#693)

* enum + set for mysql

* enum + set for mysql | dropdown

* enum for mysql | removed empty option
This commit is contained in:
Luboš Nguyen
2024-01-23 10:05:49 +01:00
committed by GitHub
parent f2f8b9ef7e
commit cdde770810
10 changed files with 374 additions and 169 deletions

View File

@@ -1162,7 +1162,7 @@
if (event.target.closest('.resizeHandleControl')) return;
if (event.target.closest('.collapseButtonMarker')) return;
if (event.target.closest('.showFormButtonMarker')) return;
if (event.target.closest('input')) return;
if (event.target.closest('.inplaceeditor-container')) return;
shiftDragStartCell = null;
// event.target.closest('table').focus();

View File

@@ -54,15 +54,15 @@
<RowHeaderCell {rowIndex} onShowForm={onSetFormView ? () => onSetFormView(rowData, null) : null} />
{#each visibleRealColumns as col (col.uniqueName)}
{#if inplaceEditorState.cell && rowIndex == inplaceEditorState.cell[0] && col.colIndex == inplaceEditorState.cell[1]}
<td class='editor'>
<InplaceEditor
width={col.width}
{inplaceEditorState}
{dispatchInsplaceEditor}
cellValue={rowData[col.uniqueName]}
onSetValue={value => grider.setCellValue(rowIndex, col.uniqueName, value)}
/>
</td>
<InplaceEditor
width={col.width}
{inplaceEditorState}
{dispatchInsplaceEditor}
cellValue={rowData[col.uniqueName]}
options="{col.options}"
canSelectMultipleOptions="{col.canSelectMultipleOptions}"
onSetValue={value => grider.setCellValue(rowIndex, col.uniqueName, value)}
/>
{:else}
<DataGridCell
{rowIndex}
@@ -100,10 +100,6 @@
background-color: var(--theme-bg-0);
}
td.editor {
position: relative;
}
tr:nth-child(6n + 3) {
background-color: var(--theme-bg-1);
}

View File

@@ -1,134 +1,41 @@
<script lang="ts">
import keycodes from '../utility/keycodes';
import { onMount, tick } from 'svelte';
import createRef from '../utility/createRef';
import _ from 'lodash';
import { arrayToHexString, parseCellValue, stringifyCellValue } from 'dbgate-tools';
import { isCtrlOrCommandKey } from '../utility/common';
import ShowFormButton from '../formview/ShowFormButton.svelte';
import { showModal } from '../modals/modalTools';
import EditCellDataModal from '../modals/EditCellDataModal.svelte';
import InplaceInput from './InplaceInput.svelte';
import InplaceSelect from './InplaceSelect.svelte';
export let inplaceEditorState;
export let dispatchInsplaceEditor;
export let onSetValue;
export let width;
export let cellValue;
export let fillParent = false;
let domEditor;
let showEditorButton = true;
const widthCopy = width;
const isChangedRef = createRef(!!inplaceEditorState.text);
function handleKeyDown(event) {
showEditorButton = false;
switch (event.keyCode) {
case keycodes.escape:
isChangedRef.set(false);
dispatchInsplaceEditor({ type: 'close' });
break;
case keycodes.enter:
if (isChangedRef.get()) {
onSetValue(parseCellValue(domEditor.value));
isChangedRef.set(false);
}
domEditor.blur();
event.preventDefault();
dispatchInsplaceEditor({ type: 'close', mode: 'enter' });
break;
case keycodes.tab:
if (isChangedRef.get()) {
onSetValue(parseCellValue(domEditor.value));
isChangedRef.set(false);
}
domEditor.blur();
event.preventDefault();
dispatchInsplaceEditor({ type: 'close', mode: event.shiftKey ? 'shiftTab' : 'tab' });
break;
case keycodes.s:
if (isCtrlOrCommandKey(event)) {
if (isChangedRef.get()) {
onSetValue(parseCellValue(domEditor.value));
isChangedRef.set(false);
}
event.preventDefault();
dispatchInsplaceEditor({ type: 'close', mode: 'save' });
}
break;
}
}
function handleBlur() {
if (isChangedRef.get()) {
onSetValue(parseCellValue(domEditor.value));
// grider.setCellValue(rowIndex, uniqueName, editor.value);
isChangedRef.set(false);
}
dispatchInsplaceEditor({ type: 'close' });
}
onMount(() => {
domEditor.value = inplaceEditorState.text || stringifyCellValue(cellValue);
domEditor.focus();
if (inplaceEditorState.selectAll) {
domEditor.select();
}
});
$: realWidth = widthCopy ? widthCopy - (showEditorButton ? 16 : 0) : undefined;
export let options;
export let canSelectMultipleOptions;
</script>
<input
type="text"
on:change={() => {
isChangedRef.set(true);
showEditorButton = false;
}}
on:keydown={handleKeyDown}
on:blur={handleBlur}
bind:this={domEditor}
style={widthCopy ? `width:${realWidth}px;min-width:${realWidth}px;max-width:${realWidth}px` : undefined}
class:fillParent
class:showEditorButton
/>
{#if showEditorButton}
<ShowFormButton
icon="icon edit"
on:click={() => {
isChangedRef.set(false);
dispatchInsplaceEditor({ type: 'close' });
showModal(EditCellDataModal, {
value: stringifyCellValue(cellValue),
onSave: onSetValue,
});
}}
/>
{/if}
<td class="editor">
<div class="inplaceeditor-container">
{#if options}
<InplaceSelect
{inplaceEditorState}
{dispatchInsplaceEditor}
{cellValue}
{onSetValue}
{options}
{canSelectMultipleOptions}
/>
{:else}
<InplaceInput
{width}
{inplaceEditorState}
{dispatchInsplaceEditor}
{cellValue}
{onSetValue}
/>
{/if}
</div>
</td>
<style>
input {
border: 0px solid;
outline: none;
margin: 0px;
padding: 0px;
}
input.fillParent {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
}
input.showEditorButton {
margin-right: 16px;
td.editor {
position: relative;
}
</style>

View File

@@ -0,0 +1,123 @@
<script lang="ts">
import keycodes from '../utility/keycodes';
import { onMount, tick } from 'svelte';
import createRef from '../utility/createRef';
import _ from 'lodash';
import { arrayToHexString, parseCellValue, stringifyCellValue } from 'dbgate-tools';
import { isCtrlOrCommandKey } from '../utility/common';
import ShowFormButton from '../formview/ShowFormButton.svelte';
import { showModal } from '../modals/modalTools';
import EditCellDataModal from '../modals/EditCellDataModal.svelte';
export let inplaceEditorState;
export let dispatchInsplaceEditor;
export let onSetValue;
export let width;
export let cellValue;
let domEditor;
let showEditorButton = true;
const widthCopy = width;
const isChangedRef = createRef(!!inplaceEditorState.text);
function handleKeyDown(event) {
showEditorButton = false;
switch (event.keyCode) {
case keycodes.escape:
isChangedRef.set(false);
dispatchInsplaceEditor({ type: 'close' });
break;
case keycodes.enter:
if (isChangedRef.get()) {
onSetValue(parseCellValue(domEditor.value));
isChangedRef.set(false);
}
domEditor.blur();
event.preventDefault();
dispatchInsplaceEditor({ type: 'close', mode: 'enter' });
break;
case keycodes.tab:
if (isChangedRef.get()) {
onSetValue(parseCellValue(domEditor.value));
isChangedRef.set(false);
}
domEditor.blur();
event.preventDefault();
dispatchInsplaceEditor({ type: 'close', mode: event.shiftKey ? 'shiftTab' : 'tab' });
break;
case keycodes.s:
if (isCtrlOrCommandKey(event)) {
if (isChangedRef.get()) {
onSetValue(parseCellValue(domEditor.value));
isChangedRef.set(false);
}
event.preventDefault();
dispatchInsplaceEditor({ type: 'close', mode: 'save' });
}
break;
}
}
function handleBlur() {
if (isChangedRef.get()) {
onSetValue(parseCellValue(domEditor.value));
// grider.setCellValue(rowIndex, uniqueName, editor.value);
isChangedRef.set(false);
}
dispatchInsplaceEditor({ type: 'close' });
}
onMount(() => {
domEditor.value = inplaceEditorState.text || stringifyCellValue(cellValue);
domEditor.focus();
if (inplaceEditorState.selectAll) {
domEditor.select();
}
});
$: realWidth = widthCopy ? widthCopy - (showEditorButton ? 16 : 0) : undefined;
</script>
<input
type="text"
on:change={() => {
isChangedRef.set(true);
showEditorButton = false;
}}
on:keydown={handleKeyDown}
on:blur={handleBlur}
bind:this={domEditor}
style={widthCopy ? `width:${realWidth}px;min-width:${realWidth}px;max-width:${realWidth}px` : undefined}
class:showEditorButton
/>
{#if showEditorButton}
<ShowFormButton
icon="icon edit"
on:click={() => {
isChangedRef.set(false);
dispatchInsplaceEditor({ type: 'close' });
showModal(EditCellDataModal, {
value: stringifyCellValue(cellValue),
onSave: onSetValue,
});
}}
/>
{/if}
<style>
input {
border: 0 solid;
outline: none;
margin: 0;
padding: 0 1px;
}
input.showEditorButton {
margin-right: 16px;
}
</style>

View File

@@ -0,0 +1,154 @@
<script lang="ts">
import { stringifyCellValue } from 'dbgate-tools';
import { onMount } from 'svelte';
import ShowFormButton from '../formview/ShowFormButton.svelte';
import clickOutside from '../utility/clickOutside';
import keycodes from '../utility/keycodes';
export let inplaceEditorState;
export let dispatchInsplaceEditor;
export let onSetValue;
export let cellValue;
export let options;
export let canSelectMultipleOptions;
let value;
let valueInit;
let optionsData;
let isOptionsHidden = false;
onMount(() => {
value = inplaceEditorState.text || stringifyCellValue(cellValue);
valueInit = value;
const optionsSelected = value.split(',');
optionsData = options
.map(function(option) {
return {
value: option,
isSelected: optionsSelected.includes(option)
};
});
});
function handleCheckboxChanged(e, option) {
if (!canSelectMultipleOptions) {
optionsData.forEach(option => option.isSelected = false);
option.isSelected = true;
} else {
option.isSelected = e.target.checked;
}
value = optionsData
.filter(option => option.isSelected)
.map(option => option.value)
.join(',');
if(!canSelectMultipleOptions)
handleConfirm();
}
function handleConfirm() {
if (value !== valueInit) {
onSetValue(value);
dispatchInsplaceEditor({ type: 'close', mode: 'save' });
} else {
dispatchInsplaceEditor({ type: 'close' });
}
}
function handleKeyDown(e) {
if (e.keyCode == keycodes.enter) {
handleConfirm();
}
}
function handleClickOutside() {
isOptionsHidden = true;
handleConfirm();
}
</script>
<div
use:clickOutside
on:clickOutside={handleClickOutside}
on:keydown={handleKeyDown}
class="inplaceselect"
>
<div on:click={() => isOptionsHidden = !isOptionsHidden} class="value">
{value}
</div>
{#if canSelectMultipleOptions}
<div class="confirm">
<ShowFormButton icon="icon ok" on:click={handleConfirm} />
</div>
{/if}
<div class="options" class:hidden={isOptionsHidden}>
{#each optionsData ?? [] as option}
<label>
<input type="checkbox"
on:change={e => handleCheckboxChanged(e, option)}
bind:checked={option.isSelected}
class:hidden={!canSelectMultipleOptions}
>
{option.value}
</label>
{/each}
</div>
</div>
<style>
.options {
position: absolute;
z-index: 10;
top: 100%;
left: 0;
width: 100%;
list-style: none;
margin: 0;
padding: 0;
background-color: var(--theme-bg-alt);
max-height: 150px;
overflow: auto;
box-shadow: 0 1px 10px 1px var(--theme-bg-inv-3);;
}
.value {
position: absolute;
top: 0;
left: 0;
z-index: 20;
min-height: 17px;
background-color: var(--theme-bg-0);
height: 100%;
width: calc(100% - 4px);
padding: 0 2px;
display: flex;
align-items: center;
overflow-x: hidden;
}
.confirm {
position: absolute;
top: 0;
right: 0;
z-index: 30;
}
.hidden {
display: none;
}
label {
padding: 2px 3px;
border-bottom: 1px solid var(--theme-border);
display: block;
min-height: 16px;
}
label:hover {
background-color: var(--theme-bg-hover);
}
</style>

View File

@@ -321,7 +321,7 @@
const handleTableMouseDown = event => {
if (event.target.closest('.buttonLike')) return;
if (event.target.closest('.resizeHandleControl')) return;
if (event.target.closest('input')) return;
if (event.target.closest('.inplaceeditor-container')) return;
if (event.target.closest('.showFormButtonMarker')) return;
event.preventDefault();
@@ -628,38 +628,39 @@
<ColumnLabel {...col} headerText={col.columnName} showDataType {conid} {database} />
</div>
</td>
<DataGridCell
maxWidth={(wrapperWidth * 2) / 3}
minWidth={200}
{rowIndex}
{col}
{rowData}
colIndex={chunkIndex * 2 + 1}
isSelected={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2 + 1}
isModifiedCell={rowStatus.modifiedFields && rowStatus.modifiedFields.has(col.uniqueName)}
allowHintField={!(rowStatus.modifiedFields && rowStatus.modifiedFields.has(col.uniqueName))}
bind:domCell={domCells[`${rowIndex},${chunkIndex * 2 + 1}`]}
onSetFormView={handleSetFormView}
showSlot={!rowData ||
{#if rowData && $inplaceEditorState.cell && rowIndex == $inplaceEditorState.cell[0] && chunkIndex * 2 + 1 == $inplaceEditorState.cell[1]}
<InplaceEditor
width={getCellWidth(rowIndex, chunkIndex * 2 + 1)}
inplaceEditorState={$inplaceEditorState}
{dispatchInsplaceEditor}
cellValue={rowData[col.uniqueName]}
options="{col.options}"
canSelectMultipleOptions="{col.canSelectMultipleOptions}"
onSetValue={value => {
grider.setCellValue(0, col.uniqueName, value);
}}
/>
{:else}
<DataGridCell
maxWidth={(wrapperWidth * 2) / 3}
minWidth={200}
{rowIndex}
{col}
{rowData}
colIndex={chunkIndex * 2 + 1}
isSelected={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2 + 1}
isModifiedCell={rowStatus.modifiedFields && rowStatus.modifiedFields.has(col.uniqueName)}
allowHintField={!(rowStatus.modifiedFields && rowStatus.modifiedFields.has(col.uniqueName))}
bind:domCell={domCells[`${rowIndex},${chunkIndex * 2 + 1}`]}
onSetFormView={handleSetFormView}
showSlot={!rowData ||
($inplaceEditorState.cell &&
rowIndex == $inplaceEditorState.cell[0] &&
chunkIndex * 2 + 1 == $inplaceEditorState.cell[1])}
isCurrentCell={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2 + 1}
onDictionaryLookup={() => handleLookup(col)}
>
{#if rowData && $inplaceEditorState.cell && rowIndex == $inplaceEditorState.cell[0] && chunkIndex * 2 + 1 == $inplaceEditorState.cell[1]}
<InplaceEditor
fillParent
width={getCellWidth(rowIndex, chunkIndex * 2 + 1)}
inplaceEditorState={$inplaceEditorState}
{dispatchInsplaceEditor}
cellValue={rowData[col.uniqueName]}
onSetValue={value => {
grider.setCellValue(0, col.uniqueName, value);
}}
/>
{/if}
</DataGridCell>
isCurrentCell={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2 + 1}
onDictionaryLookup={() => handleLookup(col)}
/>
{/if}
</tr>
{/each}
</table>