grid data types WIP

This commit is contained in:
SPRINX0\prochazka
2024-08-23 14:42:18 +02:00
parent 4ea55644c4
commit 23a52dc79e
14 changed files with 275 additions and 50 deletions

View File

@@ -161,4 +161,9 @@ export const driverBase = {
getCollectionExportQueryJson(collection: string, condition: any, sort: any) { getCollectionExportQueryJson(collection: string, condition: any, sort: any) {
return null; return null;
}, },
dataEditorTypesBehaviour: {
parseSqlNull: true,
parseHexAsBuffer: true,
},
}; };

View File

@@ -1,6 +1,8 @@
import _isString from 'lodash/isString'; import _isString from 'lodash/isString';
import _isArray from 'lodash/isArray'; import _isArray from 'lodash/isArray';
import _isNumber from 'lodash/isNumber';
import _isPlainObject from 'lodash/isPlainObject'; import _isPlainObject from 'lodash/isPlainObject';
import { DataEditorTypesBehaviour } from 'dbgate-types';
export function arrayToHexString(byteArray) { export function arrayToHexString(byteArray) {
return byteArray.reduce((output, elem) => output + ('0' + elem.toString(16)).slice(-2), '').toUpperCase(); return byteArray.reduce((output, elem) => output + ('0' + elem.toString(16)).slice(-2), '').toUpperCase();
@@ -15,36 +17,103 @@ export function hexStringToArray(inputString) {
return res; return res;
} }
export function parseCellValue(value) { export function parseCellValue(value, editorTypes?: DataEditorTypesBehaviour) {
if (!_isString(value)) return value; if (!_isString(value)) return value;
if (value == '(NULL)') return null; if (editorTypes?.parseSqlNull) {
if (value == '(NULL)') return null;
const mHex = value.match(/^0x([0-9a-fA-F][0-9a-fA-F])+$/);
if (mHex) {
return {
type: 'Buffer',
data: hexStringToArray(value.substring(2)),
};
} }
const mOid = value.match(/^ObjectId\("([0-9a-f]{24})"\)$/); if (editorTypes?.parseHexAsBuffer) {
if (mOid) { const mHex = value.match(/^0x([0-9a-fA-F][0-9a-fA-F])+$/);
return { $oid: mOid[1] }; if (mHex) {
return {
type: 'Buffer',
data: hexStringToArray(value.substring(2)),
};
}
}
if (editorTypes?.parseObjectIdAsDollar) {
const mOid = value.match(/^ObjectId\("([0-9a-f]{24})"\)$/);
if (mOid) {
return { $oid: mOid[1] };
}
}
if (editorTypes?.parseJsonNull) {
if (value == 'null') return null;
}
if (editorTypes?.parseJsonBoolean) {
if (value == 'true') return true;
if (value == 'false') return false;
}
if (editorTypes?.parseNumber) {
if (/^-?[0-9]+(?:\.[0-9]+)?$/.test(value)) {
return parseFloat(value);
}
}
if (editorTypes?.parseJsonArray || editorTypes?.parseJsonObject) {
const jsonValue = safeJsonParse(value);
if (_isPlainObject(jsonValue) && editorTypes?.parseJsonObject) return jsonValue;
if (_isArray(jsonValue) && editorTypes?.parseJsonArray) return jsonValue;
} }
return value; return value;
} }
export function stringifyCellValue(value) { function parseObjectIdAsDollar(value) {
if (value === null) return '(NULL)'; if (value?.$oid) return value;
if (value === undefined) return '(NoField)'; if (_isString(value)) {
if (value?.type == 'Buffer' && _isArray(value.data)) return '0x' + arrayToHexString(value.data); if (value.match(/^[0-9a-f]{24}$/)) return { $oid: value };
if (value?.$oid) return `ObjectId("${value?.$oid}")`; const mOid = value.match(/^ObjectId\("([0-9a-f]{24})"\)$/);
if (_isPlainObject(value) || _isArray(value)) return JSON.stringify(value); if (mOid) {
return { $oid: mOid[1] };
}
}
return value; return value;
} }
export function stringifyCellValue(value, editorTypes?: DataEditorTypesBehaviour) {
if (editorTypes?.parseSqlNull) {
if (value === null) return '(NULL)';
}
if (value === undefined) return '(NoField)';
if (editorTypes?.parseJsonNull) {
if (value === null) return 'null';
}
if (editorTypes?.parseJsonBoolean) {
if (value === true) return 'true';
if (value === false) return 'false';
}
if (editorTypes?.parseHexAsBuffer) {
if (value?.type == 'Buffer' && _isArray(value.data)) return '0x' + arrayToHexString(value.data);
}
if (editorTypes?.parseObjectIdAsDollar) {
if (value?.$oid) return `ObjectId("${value?.$oid}")`;
}
if (editorTypes?.parseJsonArray) {
if (_isArray(value)) return JSON.stringify(value);
}
if (editorTypes?.parseJsonObject) {
if (_isPlainObject(value)) return JSON.stringify(value);
}
if (editorTypes?.parseNumber) {
if (_isNumber(value)) return value.toString();
}
if (_isString(value)) return value;
// fallback
if (_isNumber(value)) return value.toString();
if (value === null || value === undefined) return '';
return '';
}
export function safeJsonParse(json, defaultValue?, logError = false) { export function safeJsonParse(json, defaultValue?, logError = false) {
if (_isArray(json) || _isPlainObject(json)) { if (_isArray(json) || _isPlainObject(json)) {
return json; return json;
@@ -127,3 +196,40 @@ export function parseSqlDefaultValue(value: string) {
} }
return undefined; return undefined;
} }
export function detectTypeIcon(value) {
if (value === null) return 'icon type-null';
if (value?.$oid) return 'icon type-objectid';
if (_isString(value)) return 'icon type-string';
if (_isNumber(value)) return 'icon type-number';
if (_isPlainObject(value)) return 'icon type-object';
if (_isArray(value)) return 'icon type-array';
if (value === true || value === false) return 'icon type-boolean';
return 'icon type-unknown';
}
export function getConvertValueMenu(value, onSetValue, editorTypes?: DataEditorTypesBehaviour) {
return [
editorTypes?.supportStringType && {
text: 'String',
onClick: () => onSetValue(stringifyCellValue(value, editorTypes)),
},
editorTypes?.supportNumberType && { text: 'Number', onClick: () => onSetValue(parseFloat(value)) },
editorTypes?.supportNullType && { text: 'Null', onClick: () => onSetValue(null) },
editorTypes?.supportBooleanType && {
text: 'Boolean',
onClick: () => onSetValue(value?.toString()?.toLowerCase() == 'true' || value == '1'),
},
editorTypes?.supportObjectIdType && { text: 'ObjectId', onClick: () => onSetValue(parseObjectIdAsDollar(value)) },
editorTypes?.supportJsonType && {
text: 'JSON',
onClick: () => {
const jsonValue = safeJsonParse(value);
if (jsonValue != null) {
console.log('**** ON SET VALUE', jsonValue);
onSetValue(jsonValue);
}
},
},
];
}

View File

@@ -93,6 +93,26 @@ export interface CollectionSortDefinitionItem {
export type CollectionSortDefinition = CollectionSortDefinitionItem[]; export type CollectionSortDefinition = CollectionSortDefinitionItem[];
export interface DataEditorTypesBehaviour {
parseSqlNull?: boolean;
parseJsonNull?: boolean;
parseJsonBoolean?: boolean;
parseNumber?: boolean;
parseJsonArray?: boolean;
parseJsonObject?: boolean;
parseHexAsBuffer?: boolean;
parseObjectIdAsDollar?: boolean;
explicitDataType?: boolean;
supportNumberType?: boolean;
supportStringType?: boolean;
supportBooleanType?: boolean;
supportDateType?: boolean;
supportNullType?: boolean;
supportJsonType?: boolean;
supportObjectIdType?: boolean;
}
export interface FilterBehaviourProvider { export interface FilterBehaviourProvider {
getFilterBehaviour(dataType: string, standardFilterBehaviours: { [id: string]: FilterBehaviour }): FilterBehaviour; getFilterBehaviour(dataType: string, standardFilterBehaviours: { [id: string]: FilterBehaviour }): FilterBehaviour;
} }
@@ -105,6 +125,7 @@ export interface EngineDriver extends FilterBehaviourProvider {
editorMode?: string; editorMode?: string;
readOnlySessions: boolean; readOnlySessions: boolean;
supportedKeyTypes: SupportedDbKeyType[]; supportedKeyTypes: SupportedDbKeyType[];
dataEditorTypesBehaviour: DataEditorTypesBehaviour;
supportsDatabaseUrl?: boolean; supportsDatabaseUrl?: boolean;
supportsDatabaseDump?: boolean; supportsDatabaseDump?: boolean;
supportsServerSummary?: boolean; supportsServerSummary?: boolean;

View File

@@ -1,13 +1,14 @@
<script lang="ts"> <script lang="ts">
import _ from 'lodash'; import _ from 'lodash';
import ShowFormButton from '../formview/ShowFormButton.svelte'; import ShowFormButton from '../formview/ShowFormButton.svelte';
import { isJsonLikeLongString, safeJsonParse } from 'dbgate-tools'; import { detectTypeIcon, getConvertValueMenu, isJsonLikeLongString, safeJsonParse } from 'dbgate-tools';
import { openJsonDocument } from '../tabs/JsonTab.svelte'; import { openJsonDocument } from '../tabs/JsonTab.svelte';
import openNewTab from '../utility/openNewTab'; import openNewTab from '../utility/openNewTab';
import CellValue from './CellValue.svelte'; import CellValue from './CellValue.svelte';
import { showModal } from '../modals/modalTools'; import { showModal } from '../modals/modalTools';
import EditCellDataModal from '../modals/EditCellDataModal.svelte'; import EditCellDataModal from '../modals/EditCellDataModal.svelte';
import { openJsonLinesData } from '../utility/openJsonLinesData'; import { openJsonLinesData } from '../utility/openJsonLinesData';
import ShowFormDropDownButton from '../formview/ShowFormDropDownButton.svelte';
export let rowIndex; export let rowIndex;
export let col; export let col;
@@ -33,6 +34,7 @@
export let isCurrentCell = false; export let isCurrentCell = false;
export let onDictionaryLookup = null; export let onDictionaryLookup = null;
export let onSetValue; export let onSetValue;
export let editorTypes = null;
$: value = col.isStructured ? _.get(rowData || {}, col.uniquePath) : (rowData || {})[col.uniqueName]; $: value = col.isStructured ? _.get(rowData || {}, col.uniquePath) : (rowData || {})[col.uniqueName];
@@ -51,7 +53,9 @@
$: style = computeStyle(maxWidth, col); $: style = computeStyle(maxWidth, col);
$: isJson = _.isPlainObject(value) && !(value?.type == 'Buffer' && _.isArray(value.data)) && !value.$oid; $: isJson = _.isPlainObject(value) && !(value?.type == 'Buffer' && _.isArray(value.data)) && !value.$oid;
$: jsonParsedValue = isJsonLikeLongString(value) ? safeJsonParse(value) : null;
// don't parse JSON for explicit data types
$: jsonParsedValue = !editorTypes?.explicitDataType && isJsonLikeLongString(value) ? safeJsonParse(value) : null;
</script> </script>
<td <td
@@ -76,23 +80,22 @@
> >
{/if} {/if}
{#if col.foreignKey && rowData && rowData[col.uniqueName] && !isCurrentCell} {#if editorTypes?.explicitDataType}
{#if value !== undefined}
<ShowFormDropDownButton
icon={detectTypeIcon(value)}
menu={() => getConvertValueMenu(value, onSetValue, editorTypes)}
/>
{/if}
{:else if col.foreignKey && rowData && rowData[col.uniqueName] && !isCurrentCell}
<ShowFormButton on:click={() => onSetFormView(rowData, col)} /> <ShowFormButton on:click={() => onSetFormView(rowData, col)} />
{/if} {:else if col.foreignKey && isCurrentCell && onDictionaryLookup}
{#if col.foreignKey && isCurrentCell && onDictionaryLookup}
<ShowFormButton icon="icon dots-horizontal" on:click={onDictionaryLookup} /> <ShowFormButton icon="icon dots-horizontal" on:click={onDictionaryLookup} />
{/if} {:else if isJson}
{#if isJson}
<ShowFormButton icon="icon open-in-new" on:click={() => openJsonDocument(value, undefined, true)} /> <ShowFormButton icon="icon open-in-new" on:click={() => openJsonDocument(value, undefined, true)} />
{/if} {:else if jsonParsedValue && _.isPlainObject(jsonParsedValue)}
{#if jsonParsedValue && _.isPlainObject(jsonParsedValue)}
<ShowFormButton icon="icon open-in-new" on:click={() => openJsonDocument(jsonParsedValue, undefined, true)} /> <ShowFormButton icon="icon open-in-new" on:click={() => openJsonDocument(jsonParsedValue, undefined, true)} />
{/if} {:else if _.isArray(jsonParsedValue || value)}
{#if _.isArray(jsonParsedValue || value)}
<ShowFormButton <ShowFormButton
icon="icon open-in-new" icon="icon open-in-new"
on:click={() => { on:click={() => {

View File

@@ -1557,7 +1557,7 @@
} }
let colIndex = startCol; let colIndex = startCol;
for (const cell of rowData) { for (const cell of rowData) {
setCellValue([rowIndex, colIndex], parseCellValue(cell)); setCellValue([rowIndex, colIndex], parseCellValue(cell, display?.driver?.dataEditorTypesBehaviour));
colIndex += 1; colIndex += 1;
} }
rowIndex += 1; rowIndex += 1;

View File

@@ -62,6 +62,7 @@
options="{col.options}" options="{col.options}"
canSelectMultipleOptions="{col.canSelectMultipleOptions}" canSelectMultipleOptions="{col.canSelectMultipleOptions}"
onSetValue={value => grider.setCellValue(rowIndex, col.uniqueName, value)} onSetValue={value => grider.setCellValue(rowIndex, col.uniqueName, value)}
{driver}
/> />
{:else} {:else}
<DataGridCell <DataGridCell
@@ -70,6 +71,7 @@
{col} {col}
{conid} {conid}
{database} {database}
editorTypes={driver?.dataEditorTypesBehaviour}
allowHintField={hintFieldsAllowed?.includes(col.uniqueName)} allowHintField={hintFieldsAllowed?.includes(col.uniqueName)}
isSelected={frameSelection ? false : cellIsSelected(rowIndex, col.colIndex, selectedCells)} isSelected={frameSelection ? false : cellIsSelected(rowIndex, col.colIndex, selectedCells)}
isCurrentCell={col.colIndex == currentCellColumn} isCurrentCell={col.colIndex == currentCellColumn}

View File

@@ -9,6 +9,7 @@
export let cellValue; export let cellValue;
export let options; export let options;
export let canSelectMultipleOptions; export let canSelectMultipleOptions;
export let driver;
</script> </script>
<td class="editor"> <td class="editor">
@@ -21,6 +22,7 @@
{onSetValue} {onSetValue}
{options} {options}
{canSelectMultipleOptions} {canSelectMultipleOptions}
{driver}
/> />
{:else} {:else}
<InplaceInput <InplaceInput
@@ -29,6 +31,7 @@
{dispatchInsplaceEditor} {dispatchInsplaceEditor}
{cellValue} {cellValue}
{onSetValue} {onSetValue}
{driver}
/> />
{/if} {/if}
</div> </div>

View File

@@ -14,6 +14,7 @@
export let onSetValue; export let onSetValue;
export let width; export let width;
export let cellValue; export let cellValue;
export let driver;
let domEditor; let domEditor;
let showEditorButton = true; let showEditorButton = true;
@@ -22,6 +23,8 @@
const isChangedRef = createRef(!!inplaceEditorState.text); const isChangedRef = createRef(!!inplaceEditorState.text);
$: editorTypes = driver?.dataEditorTypesBehaviour;
function handleKeyDown(event) { function handleKeyDown(event) {
showEditorButton = false; showEditorButton = false;
@@ -32,7 +35,7 @@
break; break;
case keycodes.enter: case keycodes.enter:
if (isChangedRef.get()) { if (isChangedRef.get()) {
onSetValue(parseCellValue(domEditor.value)); onSetValue(parseCellValue(domEditor.value, editorTypes));
isChangedRef.set(false); isChangedRef.set(false);
} }
domEditor.blur(); domEditor.blur();
@@ -41,7 +44,7 @@
break; break;
case keycodes.tab: case keycodes.tab:
if (isChangedRef.get()) { if (isChangedRef.get()) {
onSetValue(parseCellValue(domEditor.value)); onSetValue(parseCellValue(domEditor.value, editorTypes));
isChangedRef.set(false); isChangedRef.set(false);
} }
domEditor.blur(); domEditor.blur();
@@ -51,7 +54,7 @@
case keycodes.s: case keycodes.s:
if (isCtrlOrCommandKey(event)) { if (isCtrlOrCommandKey(event)) {
if (isChangedRef.get()) { if (isChangedRef.get()) {
onSetValue(parseCellValue(domEditor.value)); onSetValue(parseCellValue(domEditor.value, editorTypes));
isChangedRef.set(false); isChangedRef.set(false);
} }
event.preventDefault(); event.preventDefault();
@@ -63,7 +66,7 @@
function handleBlur() { function handleBlur() {
if (isChangedRef.get()) { if (isChangedRef.get()) {
onSetValue(parseCellValue(domEditor.value)); onSetValue(parseCellValue(domEditor.value, editorTypes));
// grider.setCellValue(rowIndex, uniqueName, editor.value); // grider.setCellValue(rowIndex, uniqueName, editor.value);
isChangedRef.set(false); isChangedRef.set(false);
} }
@@ -71,7 +74,7 @@
} }
onMount(() => { onMount(() => {
domEditor.value = inplaceEditorState.text || stringifyCellValue(cellValue); domEditor.value = inplaceEditorState.text || stringifyCellValue(cellValue, editorTypes);
domEditor.focus(); domEditor.focus();
if (inplaceEditorState.selectAll) { if (inplaceEditorState.selectAll) {
domEditor.select(); domEditor.select();
@@ -102,7 +105,7 @@
dispatchInsplaceEditor({ type: 'close' }); dispatchInsplaceEditor({ type: 'close' });
showModal(EditCellDataModal, { showModal(EditCellDataModal, {
value: stringifyCellValue(cellValue), value: stringifyCellValue(cellValue, editorTypes),
onSave: onSetValue, onSave: onSetValue,
}); });
}} }}

View File

@@ -11,6 +11,7 @@
export let cellValue; export let cellValue;
export let options; export let options;
export let canSelectMultipleOptions; export let canSelectMultipleOptions;
export let driver;
let value; let value;
let valueInit; let valueInit;
@@ -18,7 +19,7 @@
let isOptionsHidden = false; let isOptionsHidden = false;
onMount(() => { onMount(() => {
value = inplaceEditorState.text || stringifyCellValue(cellValue); value = inplaceEditorState.text || stringifyCellValue(cellValue, driver?.dataEditorTypesBehaviour);
valueInit = value; valueInit = value;
const optionsSelected = value.split(','); const optionsSelected = value.split(',');

View File

@@ -273,7 +273,10 @@
export function copyToClipboard() { export function copyToClipboard() {
const column = getCellColumn(currentCell); const column = getCellColumn(currentCell);
if (!column) return; if (!column) return;
const text = currentCell[1] % 2 == 1 ? extractRowCopiedValue(rowData, column.uniqueName) : column.columnName; const text =
currentCell[1] % 2 == 1
? extractRowCopiedValue(rowData, column.uniqueName, display?.driver?.dataEditorTypesBehaviour)
: column.columnName;
copyTextToClipboard(text); copyTextToClipboard(text);
} }
@@ -631,11 +634,12 @@
{#if rowData && $inplaceEditorState.cell && rowIndex == $inplaceEditorState.cell[0] && chunkIndex * 2 + 1 == $inplaceEditorState.cell[1]} {#if rowData && $inplaceEditorState.cell && rowIndex == $inplaceEditorState.cell[0] && chunkIndex * 2 + 1 == $inplaceEditorState.cell[1]}
<InplaceEditor <InplaceEditor
width={getCellWidth(rowIndex, chunkIndex * 2 + 1)} width={getCellWidth(rowIndex, chunkIndex * 2 + 1)}
driver={display?.driver}
inplaceEditorState={$inplaceEditorState} inplaceEditorState={$inplaceEditorState}
{dispatchInsplaceEditor} {dispatchInsplaceEditor}
cellValue={rowData[col.uniqueName]} cellValue={rowData[col.uniqueName]}
options="{col.options}" options={col.options}
canSelectMultipleOptions="{col.canSelectMultipleOptions}" canSelectMultipleOptions={col.canSelectMultipleOptions}
onSetValue={value => { onSetValue={value => {
grider.setCellValue(0, col.uniqueName, value); grider.setCellValue(0, col.uniqueName, value);
}} }}
@@ -644,6 +648,7 @@
<DataGridCell <DataGridCell
maxWidth={(wrapperWidth * 2) / 3} maxWidth={(wrapperWidth * 2) / 3}
minWidth={200} minWidth={200}
editorTypes={display?.driver?.dataEditorTypesBehaviour}
{rowIndex} {rowIndex}
{col} {col}
{rowData} {rowData}
@@ -654,11 +659,14 @@
bind:domCell={domCells[`${rowIndex},${chunkIndex * 2 + 1}`]} bind:domCell={domCells[`${rowIndex},${chunkIndex * 2 + 1}`]}
onSetFormView={handleSetFormView} onSetFormView={handleSetFormView}
showSlot={!rowData || showSlot={!rowData ||
($inplaceEditorState.cell && ($inplaceEditorState.cell &&
rowIndex == $inplaceEditorState.cell[0] && rowIndex == $inplaceEditorState.cell[0] &&
chunkIndex * 2 + 1 == $inplaceEditorState.cell[1])} chunkIndex * 2 + 1 == $inplaceEditorState.cell[1])}
isCurrentCell={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2 + 1} isCurrentCell={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2 + 1}
onDictionaryLookup={() => handleLookup(col)} onDictionaryLookup={() => handleLookup(col)}
onSetValue={value => {
grider.setCellValue(0, col.uniqueName, value);
}}
/> />
{/if} {/if}
</tr> </tr>

View File

@@ -0,0 +1,44 @@
<script lang="ts">
import FontIcon from '../icons/FontIcon.svelte';
import { currentDropDownMenu } from '../stores';
export let icon = 'icon form';
export let menu;
let domButton;
function handleClick() {
const rect = domButton.getBoundingClientRect();
const left = rect.left;
const top = rect.bottom;
currentDropDownMenu.set({ left, top, items: menu });
}
</script>
<div
on:click|stopPropagation|preventDefault={handleClick}
bind:this={domButton}
on:mousedown|stopPropagation|preventDefault
on:mouseup|stopPropagation|preventDefault
class="showFormButtonMarker"
>
<FontIcon {icon} />
</div>
<style>
div {
position: absolute;
right: 0px;
top: 1px;
color: var(--theme-font-3);
background-color: var(--theme-bg-1);
border: 1px solid var(--theme-bg-1);
}
div:hover {
color: var(--theme-font-hover);
border: var(--theme-border);
top: 1px;
right: 0px;
}
</style>

View File

@@ -186,6 +186,16 @@
'icon num-9-outline': 'mdi mdi-numeric-9-circle-outline', 'icon num-9-outline': 'mdi mdi-numeric-9-circle-outline',
'icon num-9-plus-outline': 'mdi mdi-numeric-9-plus-circle-outline', 'icon num-9-plus-outline': 'mdi mdi-numeric-9-plus-circle-outline',
'icon type-string': 'mdi mdi-code-string',
'icon type-object': 'mdi mdi-code-braces-box',
'icon type-array': 'mdi mdi-code-array',
'icon type-number': 'mdi mdi-pound-box',
'icon type-boolean': 'mdi mdi-code-equal',
'icon type-date': 'mdi mdi-alpha-d-box',
'icon type-objectid': 'mdi mdi-alpha-i-box',
'icon type-null': 'mdi mdi-code-equal',
'icon type-unknown': 'mdi mdi-help-box',
'img ok': 'mdi mdi-check-circle color-icon-green', 'img ok': 'mdi mdi-check-circle color-icon-green',
'img ok-inv': 'mdi mdi-check-circle color-icon-inv-green', 'img ok-inv': 'mdi mdi-check-circle color-icon-inv-green',
'img alert': 'mdi mdi-alert-circle color-icon-blue', 'img alert': 'mdi mdi-alert-circle color-icon-blue',

View File

@@ -1,6 +1,7 @@
import _ from 'lodash'; import _ from 'lodash';
import { arrayToHexString, stringifyCellValue } from 'dbgate-tools'; import { arrayToHexString, stringifyCellValue } from 'dbgate-tools';
import yaml from 'js-yaml'; import yaml from 'js-yaml';
import { DataEditorTypesBehaviour } from 'dbgate-types';
export function copyTextToClipboard(text) { export function copyTextToClipboard(text) {
const oldFocus = document.activeElement; const oldFocus = document.activeElement;
@@ -71,13 +72,13 @@ export async function getClipboardText() {
return await navigator.clipboard.readText(); return await navigator.clipboard.readText();
} }
export function extractRowCopiedValue(row, col) { export function extractRowCopiedValue(row, col, editorTypes?: DataEditorTypesBehaviour) {
let value = row[col]; let value = row[col];
if (value === undefined) value = _.get(row, col); if (value === undefined) value = _.get(row, col);
return stringifyCellValue(value); return stringifyCellValue(value, editorTypes);
} }
const clipboardHeadersFormatter = (delimiter) => (columns) => { const clipboardHeadersFormatter = delimiter => columns => {
return columns.join(delimiter); return columns.join(delimiter);
}; };

View File

@@ -122,6 +122,24 @@ const driver = {
sort: convertToMongoSort(sort) || {}, sort: convertToMongoSort(sort) || {},
}; };
}, },
dataEditorTypesBehaviour: {
parseJsonNull: true,
parseJsonBoolean: true,
parseNumber: true,
parseJsonArray: true,
parseJsonObject: true,
parseObjectIdAsDollar: true,
explicitDataType: true,
supportNumberType: true,
supportStringType: true,
supportBooleanType: true,
supportDateType: true,
supportJsonType: true,
supportObjectIdType: true,
supportNullType: true,
},
}; };
module.exports = driver; module.exports = driver;