diff --git a/packages/tools/src/SqlDumper.ts b/packages/tools/src/SqlDumper.ts index 54cfd8d23..d4de0c399 100644 --- a/packages/tools/src/SqlDumper.ts +++ b/packages/tools/src/SqlDumper.ts @@ -205,7 +205,18 @@ export class SqlDumper implements AlterProcessor { if (column.isPersisted) this.put(' ^persisted'); return; } - this.put('%k', column.dataType || this.dialect.fallbackDataType); + + const type = column.dataType || this.dialect.fallbackDataType; + const typeWithValues = type.match(/([^(]+)(\(.+[^)]\))/); + + if (typeWithValues?.length) { + typeWithValues.shift(); + this.putRaw(SqlDumper.convertKeywordCase(typeWithValues.shift())); + this.putRaw(typeWithValues); + } else { + this.putRaw(SqlDumper.convertKeywordCase(type)); + } + if (column.autoIncrement) { this.autoIncrement(); } diff --git a/packages/types/dbinfo.d.ts b/packages/types/dbinfo.d.ts index 0856d2027..37b751a6a 100644 --- a/packages/types/dbinfo.d.ts +++ b/packages/types/dbinfo.d.ts @@ -60,6 +60,8 @@ export interface ColumnInfo extends NamedObjectInfo { columnComment?: string; isUnsigned?: boolean; isZerofill?: boolean; + options?: []; + canSelectMultipleOptions?: boolean, } export interface DatabaseObjectInfo extends NamedObjectInfo { diff --git a/packages/web/src/datagrid/DataGridCore.svelte b/packages/web/src/datagrid/DataGridCore.svelte index 8ab9cf656..a12739ae3 100644 --- a/packages/web/src/datagrid/DataGridCore.svelte +++ b/packages/web/src/datagrid/DataGridCore.svelte @@ -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(); diff --git a/packages/web/src/datagrid/DataGridRow.svelte b/packages/web/src/datagrid/DataGridRow.svelte index 7f01b56d7..9c6924a9d 100644 --- a/packages/web/src/datagrid/DataGridRow.svelte +++ b/packages/web/src/datagrid/DataGridRow.svelte @@ -54,15 +54,15 @@ onSetFormView(rowData, null) : null} /> {#each visibleRealColumns as col (col.uniqueName)} {#if inplaceEditorState.cell && rowIndex == inplaceEditorState.cell[0] && col.colIndex == inplaceEditorState.cell[1]} - - grider.setCellValue(rowIndex, col.uniqueName, value)} - /> - + grider.setCellValue(rowIndex, col.uniqueName, value)} + /> {:else} - 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; - { - 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} - { - isChangedRef.set(false); - dispatchInsplaceEditor({ type: 'close' }); - - showModal(EditCellDataModal, { - value: stringifyCellValue(cellValue), - onSave: onSetValue, - }); - }} - /> -{/if} + +
+ {#if options} + + {:else} + + {/if} +
+ diff --git a/packages/web/src/datagrid/InplaceInput.svelte b/packages/web/src/datagrid/InplaceInput.svelte new file mode 100644 index 000000000..aec5d7b61 --- /dev/null +++ b/packages/web/src/datagrid/InplaceInput.svelte @@ -0,0 +1,123 @@ + + + { + 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} + { + isChangedRef.set(false); + dispatchInsplaceEditor({ type: 'close' }); + + showModal(EditCellDataModal, { + value: stringifyCellValue(cellValue), + onSave: onSetValue, + }); + }} + /> +{/if} + + diff --git a/packages/web/src/datagrid/InplaceSelect.svelte b/packages/web/src/datagrid/InplaceSelect.svelte new file mode 100644 index 000000000..7148c2837 --- /dev/null +++ b/packages/web/src/datagrid/InplaceSelect.svelte @@ -0,0 +1,154 @@ + + +
+
isOptionsHidden = !isOptionsHidden} class="value"> + {value} +
+ + {#if canSelectMultipleOptions} +
+ +
+ {/if} + +
+ {#each optionsData ?? [] as option} + + {/each} +
+
+ + diff --git a/packages/web/src/formview/FormView.svelte b/packages/web/src/formview/FormView.svelte index 4397d1671..e24d90216 100644 --- a/packages/web/src/formview/FormView.svelte +++ b/packages/web/src/formview/FormView.svelte @@ -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 @@ - { + grider.setCellValue(0, col.uniqueName, value); + }} + /> + {:else} + handleLookup(col)} - > - {#if rowData && $inplaceEditorState.cell && rowIndex == $inplaceEditorState.cell[0] && chunkIndex * 2 + 1 == $inplaceEditorState.cell[1]} - { - grider.setCellValue(0, col.uniqueName, value); - }} - /> - {/if} - + isCurrentCell={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2 + 1} + onDictionaryLookup={() => handleLookup(col)} + /> + {/if} {/each} diff --git a/plugins/dbgate-plugin-mysql/src/backend/Analyser.js b/plugins/dbgate-plugin-mysql/src/backend/Analyser.js index dd029ddb2..e87bd52b8 100644 --- a/plugins/dbgate-plugin-mysql/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-mysql/src/backend/Analyser.js @@ -31,12 +31,22 @@ function getColumnInfo( driver ) { const { quoteDefaultValues } = driver.__analyserInternals; + let optionsInfo = {}; const columnTypeTokens = _.isString(columnType) ? columnType.split(' ').map(x => x.trim().toLowerCase()) : []; let fullDataType = dataType; if (charMaxLength && isTypeString(dataType)) fullDataType = `${dataType}(${charMaxLength})`; - if (numericPrecision && numericScale && isTypeNumeric(dataType)) + else if (numericPrecision && numericScale && isTypeNumeric(dataType)) fullDataType = `${dataType}(${numericPrecision},${numericScale})`; + else { + const optionsTypeParts = columnType.match(/^(enum|set)\((.+)\)/i); + if (optionsTypeParts?.length) { + fullDataType = columnType; + optionsInfo.options = optionsTypeParts[2].split(',').map(option => option.substring(1, option.length - 1)); + optionsInfo.canSelectMultipleOptions = optionsTypeParts[1] == 'set'; + } + } + return { notNull: !isNullable || isNullable == 'NO' || isNullable == 'no', autoIncrement: !!(extra && extra.toLowerCase().includes('auto_increment')), @@ -46,6 +56,7 @@ function getColumnInfo( defaultValue: quoteDefaultValues ? quoteDefaultValue(defaultValue) : defaultValue, isUnsigned: columnTypeTokens.includes('unsigned'), isZerofill: columnTypeTokens.includes('zerofill'), + ...optionsInfo, }; } diff --git a/plugins/dbgate-plugin-mysql/src/frontend/drivers.js b/plugins/dbgate-plugin-mysql/src/frontend/drivers.js index 20106c99c..d773c39fc 100644 --- a/plugins/dbgate-plugin-mysql/src/frontend/drivers.js +++ b/plugins/dbgate-plugin-mysql/src/frontend/drivers.js @@ -63,8 +63,8 @@ const dialect = { 'mediumblob', 'longtext', 'longblob', - 'enum(val1,val2,val3)', - 'set(val1,val2,val3)', + "enum('val1','val2','val3')", + "set('val1','val2','val3')", 'bit(32)', 'tinyint', 'bool',