diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellRenderer/CellRenderer.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellRenderer/CellRenderer.tsx index 5c06a79145..b6c85fe958 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellRenderer/CellRenderer.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellRenderer/CellRenderer.tsx @@ -17,6 +17,7 @@ import { ResultSetFormatAction } from '@cloudbeaver/plugin-data-viewer'; import { EditingContext } from '../../Editing/EditingContext'; import { DataGridContext } from '../DataGridContext'; import { DataGridSelectionContext } from '../DataGridSelection/DataGridSelectionContext'; +import { isBooleanFormatterAvailable } from '../Formatters/CellFormatters/isBooleanFormatterAvailable'; import { TableDataContext } from '../TableDataContext'; import { CellContext, ICellContext } from './CellContext'; @@ -79,7 +80,9 @@ export const CellRenderer: React.FC> = observer(function }, [column, rowIdx, selectionContext, dataGridContext]); const handleDoubleClick = useCallback(() => { - if (!column.editable || resultColumn?.dataKind?.toLowerCase() === 'boolean') { + if (!column.editable || ( + resultColumn && isBooleanFormatterAvailable(editor?.getCell(rowIdx, Number(column.key)), resultColumn) + )) { return; } const format = dataGridContext?.model.source.getAction(dataGridContext.resultIndex, ResultSetFormatAction); @@ -96,7 +99,7 @@ export const CellRenderer: React.FC> = observer(function } editingContext?.edit({ idx: column.idx, rowIdx }); - }, [column, rowIdx, props.row]); + }, [column, rowIdx, props.row, editor, resultColumn]); const row = editor?.get(rowIdx) || props.row; diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuCellEditingService.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuCellEditingService.ts index 1f5106af15..8fb0d652fd 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuCellEditingService.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuCellEditingService.ts @@ -9,6 +9,7 @@ import { injectable } from '@cloudbeaver/core-di'; import { ResultSetDataAction, ResultSetFormatAction } from '@cloudbeaver/plugin-data-viewer'; +import { isBooleanFormatterAvailable } from '../Formatters/CellFormatters/isBooleanFormatterAvailable'; import { DataGridContextMenuService } from './DataGridContextMenuService'; @injectable() @@ -50,13 +51,15 @@ export class DataGridContextMenuCellEditingService { }, isHidden(context) { const data = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataAction); + const editor = context.data.model.source.getEditor(context.data.resultIndex); + const cellValue = editor.getCell(context.data.row, context.data.column); const column = data.getColumn(context.data.column); if (!column) { return true; } - return column.dataKind?.toLowerCase() === 'boolean'; + return isBooleanFormatterAvailable(cellValue, column); }, order: 0, title: 'data_grid_table_editing_open_inline_editor', diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatterFactory.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatterFactory.tsx index 2b59c69688..631062b0c6 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatterFactory.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatterFactory.tsx @@ -6,28 +6,38 @@ * you may not use this file except in compliance with the License. */ -import { useContext } from 'react'; +import { useContext, useRef } from 'react'; import type { FormatterProps } from 'react-data-grid'; import { ResultSetFormatAction } from '@cloudbeaver/plugin-data-viewer'; +import { EditingContext } from '../../Editing/EditingContext'; import { DataGridContext } from '../DataGridContext'; import { TableDataContext } from '../TableDataContext'; import { BooleanFormatter } from './CellFormatters/BooleanFormatter'; +import { isBooleanFormatterAvailable } from './CellFormatters/isBooleanFormatterAvailable'; import { TextFormatter } from './CellFormatters/TextFormatter'; export const CellFormatterFactory: React.FC = function CellFormatterFactory(props) { + const formatterRef = useRef | null>(null); const context = useContext(DataGridContext); const tableDataContext = useContext(TableDataContext); const formatter = context?.model.source.getAction(context.resultIndex, ResultSetFormatAction); + const editingContext = useContext(EditingContext); + const isEditing = editingContext?.isEditing({ idx: props.column.idx, rowIdx: props.rowIdx }); + const resultColumn = tableDataContext?.getColumnInfo(props.column.key); const rawValue = formatter?.get(props.row[props.column.key]) ?? props.row[props.column.key]; - let Formatter: React.FC = TextFormatter; + if (!isEditing || formatterRef === null) { + formatterRef.current = TextFormatter; - if (resultColumn?.dataKind?.toLowerCase() === 'boolean' && (typeof rawValue === 'boolean' || formatter?.isNull(rawValue))) { - Formatter = BooleanFormatter; + if (resultColumn && isBooleanFormatterAvailable(rawValue, resultColumn)) { + formatterRef.current = BooleanFormatter; + } } + const Formatter = formatterRef.current!; + return ; }; diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatters/BooleanFormatter.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatters/BooleanFormatter.tsx index 25df1d6c76..773eaa31e8 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatters/BooleanFormatter.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatters/BooleanFormatter.tsx @@ -42,8 +42,9 @@ export const BooleanFormatter: React.FC = observer(function Bool const formatter = context?.model.source.getAction(context.resultIndex, ResultSetFormatAction); const resultColumn = tableDataContext?.getColumnInfo(column.key); const rawValue = formatter?.get(row[column.key]) ?? row[column.key]; - const stringifiedValue = formatter?.toDisplayString(rawValue) ?? String(rawValue); - const value = rawValue === null ? stringifiedValue : `[${rawValue ? 'v' : ' '}]`; + const value = typeof rawValue === 'string' ? rawValue.toLowerCase() === 'true' : rawValue; + const stringifiedValue = formatter?.toDisplayString(value) ?? String(value); + const valueRepresentation = value === null ? stringifiedValue : `[${value ? 'v' : ' '}]`; const classes = getClasses(rawValue); const getNextValue = useCallback((prev: boolean | null) => { @@ -60,10 +61,10 @@ export const BooleanFormatter: React.FC = observer(function Bool as='span' title={stringifiedValue} onClick={() => context?.model.source.getEditor(context.resultIndex) - .setCell(rowIdx, Number(column.key), getNextValue(rawValue))} - {...use({ boolean: rawValue !== null })} + .setCell(rowIdx, Number(column.key), getNextValue(value))} + {...use({ boolean: value !== null })} > - {value} + {valueRepresentation} ); }); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatters/isBooleanFormatterAvailable.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatters/isBooleanFormatterAvailable.ts new file mode 100644 index 0000000000..b912cde48c --- /dev/null +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatters/isBooleanFormatterAvailable.ts @@ -0,0 +1,19 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2021 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ + +import type { SqlResultColumn } from '@cloudbeaver/core-sdk'; +import type { IResultSetValue } from '@cloudbeaver/plugin-data-viewer'; + +export function isBooleanFormatterAvailable(cellValue: IResultSetValue, column: SqlResultColumn): boolean { + return column?.dataKind?.toLowerCase() === 'boolean' + && ( + typeof cellValue === 'boolean' + || cellValue === null + || (typeof cellValue === 'string' && ['false', 'true'].includes(cellValue.toLowerCase())) + ); +} diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataEditor.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataEditor.ts index 8676dc4470..afdf7d3048 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataEditor.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataEditor.ts @@ -299,6 +299,10 @@ export class DatabaseDataEditor implements return String(valueA) === String(valueB); } + if (typeof valueA === 'boolean' || typeof valueB === 'boolean') { + return String(valueA).toLowerCase() === String(valueB).toLowerCase(); + } + if (isResultSetContentValue(valueA) && isResultSetContentValue(valueB)) { if ('text' in valueA && 'text' in valueB) { return valueA.text === valueB.text; diff --git a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentation.tsx b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentation.tsx index 0696cc4646..d0cb39c99d 100644 --- a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentation.tsx +++ b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentation.tsx @@ -17,7 +17,6 @@ import { CodeEditorLoader } from '@cloudbeaver/plugin-codemirror'; import type { IResultSetElementKey } from '../../DatabaseDataModel/Actions/ResultSet/IResultSetElementKey'; import { isResultSetContentValue } from '../../DatabaseDataModel/Actions/ResultSet/isResultSetContentValue'; -import { ResultSetDataAction } from '../../DatabaseDataModel/Actions/ResultSet/ResultSetDataAction'; import { ResultSetFormatAction } from '../../DatabaseDataModel/Actions/ResultSet/ResultSetFormatAction'; import { ResultSetSelectAction } from '../../DatabaseDataModel/Actions/ResultSet/ResultSetSelectAction'; import type { IDatabaseResultSet } from '../../DatabaseDataModel/IDatabaseResultSet'; @@ -93,7 +92,6 @@ export const TextValuePresentation: TabContainerPanelComponent