mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-28 19:56:00 +00:00
grid data types WIP
This commit is contained in:
@@ -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,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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,11 +17,14 @@ 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 (editorTypes?.parseSqlNull) {
|
||||||
if (value == '(NULL)') return null;
|
if (value == '(NULL)') return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (editorTypes?.parseHexAsBuffer) {
|
||||||
const mHex = value.match(/^0x([0-9a-fA-F][0-9a-fA-F])+$/);
|
const mHex = value.match(/^0x([0-9a-fA-F][0-9a-fA-F])+$/);
|
||||||
if (mHex) {
|
if (mHex) {
|
||||||
return {
|
return {
|
||||||
@@ -27,24 +32,88 @@ export function parseCellValue(value) {
|
|||||||
data: hexStringToArray(value.substring(2)),
|
data: hexStringToArray(value.substring(2)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (editorTypes?.parseObjectIdAsDollar) {
|
||||||
const mOid = value.match(/^ObjectId\("([0-9a-f]{24})"\)$/);
|
const mOid = value.match(/^ObjectId\("([0-9a-f]{24})"\)$/);
|
||||||
if (mOid) {
|
if (mOid) {
|
||||||
return { $oid: mOid[1] };
|
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);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|||||||
21
packages/types/engines.d.ts
vendored
21
packages/types/engines.d.ts
vendored
@@ -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;
|
||||||
|
|||||||
@@ -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={() => {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -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(',');
|
||||||
|
|||||||
@@ -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}
|
||||||
@@ -659,6 +664,9 @@
|
|||||||
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>
|
||||||
|
|||||||
44
packages/web/src/formview/ShowFormDropDownButton.svelte
Normal file
44
packages/web/src/formview/ShowFormDropDownButton.svelte
Normal 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>
|
||||||
@@ -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',
|
||||||
|
|||||||
@@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user