mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
fix: CB-907 numeric cell editing
This commit is contained in:
@@ -87,22 +87,9 @@ export const CellEditor = observer<Pick<EditorProps<any, any>, 'rowIdx' | 'row'
|
||||
}
|
||||
});
|
||||
|
||||
const value = formatter?.get(row[column.key]);
|
||||
const numericCell = typeof tableDataContext?.getCellValue(rowIdx, column.key) === 'number';
|
||||
const value = formatter?.getText(row[column.key]) ?? '';
|
||||
|
||||
const handleSave = () => {
|
||||
if (numericCell) {
|
||||
const editor = dataGridContext.model.source.getEditor(dataGridContext.resultIndex);
|
||||
let value = editor.getCell(rowIdx, Number(column.key));
|
||||
|
||||
if (typeof value === 'string') {
|
||||
value = value.replace(',', '.');
|
||||
}
|
||||
|
||||
editor.setCell(rowIdx, Number(column.key), Number(value));
|
||||
}
|
||||
onClose(false);
|
||||
};
|
||||
const handleSave = () => onClose(false);
|
||||
const handleReject = () => {
|
||||
dataGridContext.model.source.getEditor(dataGridContext.resultIndex)
|
||||
.revertCell(rowIdx, Number(column.key));
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ export const CellRenderer: React.FC<CellRendererProps<any>> = observer(function
|
||||
classes.push('rdg-cell-custom-editing');
|
||||
}
|
||||
|
||||
if (editor?.isCellEdited(rowIdx, Number(column.key))) {
|
||||
if (!tableDataContext?.isIndexColumn(column.key) && editor?.isCellEdited(rowIdx, Number(column.key))) {
|
||||
classes.push('rdg-cell-custom-edited');
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -90,7 +90,7 @@ export class DataGridContextMenuFilterService {
|
||||
},
|
||||
titleGetter() {
|
||||
const val = typeof value === 'function' ? value() : value;
|
||||
const stringifyValue = format.toString(val);
|
||||
const stringifyValue = format.toDisplayString(val);
|
||||
const wrappedValue = wrapOperationArgument(operation.id, stringifyValue);
|
||||
const clippeddValue = replaceMiddle(wrappedValue, ' ... ', 8, 30);
|
||||
return `${columnLabel} ${operation.expression} ${clippeddValue}`;
|
||||
@@ -244,7 +244,7 @@ export class DataGridContextMenuFilterService {
|
||||
icon: '/icons/filter_custom.png',
|
||||
onClick: async () => {
|
||||
const isNull = format.isNull(cellValue);
|
||||
const stringifyCellValue = format.toString(cellValue);
|
||||
const stringifyCellValue = format.toDisplayString(cellValue);
|
||||
const customValue = await this.commonDialogService.open(
|
||||
FilterCustomValueDialog,
|
||||
{
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ export const CellFormatter: React.FC<FormatterProps> = observer(function CellFor
|
||||
const rawValue = formatter?.get(row[column.key]) ?? row[column.key];
|
||||
const classes = getClasses(rawValue);
|
||||
const [menuVisible, setMenuVisible] = useState(false);
|
||||
const value = formatter?.toString(rawValue) ?? String(rawValue);
|
||||
const value = formatter?.toDisplayString(rawValue) ?? String(rawValue);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
editingContext?.closeEditor({ idx: column.idx, rowIdx });
|
||||
|
||||
+1
-5
@@ -9,9 +9,5 @@
|
||||
import type { FormatterProps } from 'react-data-grid';
|
||||
|
||||
export const IndexFormatter: React.FC<FormatterProps> = function IndexFormatter({ rowIdx }) {
|
||||
return (
|
||||
<index-formatter as='div'>
|
||||
{rowIdx + 1}
|
||||
</index-formatter>
|
||||
);
|
||||
return <div>{rowIdx + 1}</div>;
|
||||
};
|
||||
|
||||
+1
-3
@@ -12,7 +12,5 @@ import { Row } from 'react-data-grid';
|
||||
import { CellRenderer } from '../CellRenderer/CellRenderer';
|
||||
|
||||
export const RowRenderer: React.FC<RowRendererProps<any>> = function RowRenderer(props) {
|
||||
return (
|
||||
<Row cellRenderer={CellRenderer} {...props} />
|
||||
);
|
||||
return <Row cellRenderer={CellRenderer} {...props} />;
|
||||
};
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ function copyGridSelectedDataToClipboard(
|
||||
|
||||
if (colIndexes.includes(columnIdx)) {
|
||||
const cell = editor.getCell(rowIdx, columnIdx);
|
||||
const cellValue = format.get(cell);
|
||||
const cellValue = format.getText(cell);
|
||||
rowCellsValues.push(cellValue ?? '');
|
||||
} else {
|
||||
rowCellsValues.push('');
|
||||
|
||||
+1
-1
@@ -15,5 +15,5 @@ export interface IDatabaseDataFormatAction<TKey, TResult extends IDatabaseDataRe
|
||||
get: (value: any) => any;
|
||||
getText: (value: any) => string | null;
|
||||
isNull: (value: any) => boolean;
|
||||
toString: (value: any) => string;
|
||||
toDisplayString: (value: any) => string;
|
||||
}
|
||||
|
||||
+13
-5
@@ -16,6 +16,8 @@ import type { IResultSetElementKey } from './IResultSetElementKey';
|
||||
import { isResultSetContentValue } from './isResultSetContentValue';
|
||||
import { ResultSetDataAction } from './ResultSetDataAction';
|
||||
|
||||
export type IResultSetValue = string | number | Record<string, string | number | Record<string, any> | null> | null;
|
||||
|
||||
@databaseDataAction()
|
||||
export class ResultSetFormatAction extends DatabaseDataAction<any, IDatabaseResultSet>
|
||||
implements IDatabaseDataFormatAction<IResultSetElementKey, IDatabaseResultSet> {
|
||||
@@ -45,11 +47,11 @@ export class ResultSetFormatAction extends DatabaseDataAction<any, IDatabaseResu
|
||||
return columnReadonly || cellReadonly;
|
||||
}
|
||||
|
||||
isNull(value: any): boolean {
|
||||
isNull(value: IResultSetValue): boolean {
|
||||
return this.get(value) === null;
|
||||
}
|
||||
|
||||
get(value: any): any {
|
||||
get(value: IResultSetValue): IResultSetValue {
|
||||
if (value !== null && typeof value === 'object') {
|
||||
if ('text' in value) {
|
||||
return value.text;
|
||||
@@ -62,16 +64,22 @@ export class ResultSetFormatAction extends DatabaseDataAction<any, IDatabaseResu
|
||||
return value;
|
||||
}
|
||||
|
||||
getText(value: any): string {
|
||||
getText(value: IResultSetValue): string | null {
|
||||
value = this.get(value);
|
||||
|
||||
if (value !== null && typeof value === 'object') {
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
|
||||
if (typeof value === 'number') {
|
||||
return String(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
toString(value: any): string {
|
||||
value = this.getText(this.get(value));
|
||||
toDisplayString(value: IResultSetValue): string {
|
||||
value = this.getText(value);
|
||||
|
||||
if (typeof value === 'string' && value.length > 1000) {
|
||||
return value.split('').map(v => (v.charCodeAt(0) < 32 ? ' ' : v)).join('');
|
||||
|
||||
@@ -292,8 +292,11 @@ export class DatabaseDataEditor<TResult extends IDatabaseDataResult> implements
|
||||
}
|
||||
|
||||
private compareCellValue(valueA: any, valueB: any) {
|
||||
valueA = valueA ?? '';
|
||||
valueB = valueB ?? '';
|
||||
|
||||
if (typeof valueA === 'number' || typeof valueB === 'number') {
|
||||
return Number(valueA) === Number(valueB);
|
||||
return String(valueA) === String(valueB);
|
||||
}
|
||||
|
||||
if (isResultSetContentValue(valueA) && isResultSetContentValue(valueB)) {
|
||||
|
||||
+5
-6
@@ -89,14 +89,14 @@ export const TextValuePresentation: TabContainerPanelComponent<IDataValuePanelPr
|
||||
currentContentType: observable,
|
||||
lastContentType: observable,
|
||||
}, ['setContentType', 'setDefaultContentType']);
|
||||
|
||||
const result = model.getResult(resultIndex);
|
||||
const selection = model.source.getAction(resultIndex, ResultSetSelectAction);
|
||||
|
||||
const selectedCells = selection.getSelectedElements();
|
||||
const focusCell = selection.getFocusedElement();
|
||||
|
||||
let value: any;
|
||||
let stringValue: string | undefined;
|
||||
let stringValue = '';
|
||||
let contentType = 'text/plain';
|
||||
let firstSelectedCell: Required<IResultSetElementKey> | undefined;
|
||||
let readonly = true;
|
||||
@@ -106,11 +106,11 @@ export const TextValuePresentation: TabContainerPanelComponent<IDataValuePanelPr
|
||||
|
||||
firstSelectedCell = selectedCells[0] || focusCell;
|
||||
|
||||
value = model.source
|
||||
const value = model.source
|
||||
.getEditor(resultIndex)
|
||||
.getCell(firstSelectedCell.row, firstSelectedCell.column);
|
||||
|
||||
stringValue = format.getText(format.get(value));
|
||||
stringValue = format.getText(value) ?? '';
|
||||
readonly = format.isReadOnly(firstSelectedCell);
|
||||
|
||||
if (isResultSetContentValue(value)) {
|
||||
@@ -159,7 +159,7 @@ export const TextValuePresentation: TabContainerPanelComponent<IDataValuePanelPr
|
||||
{useCodeEditor ? (
|
||||
<CodeEditorLoader
|
||||
readonly={readonly}
|
||||
value={stringValue || ''}
|
||||
value={stringValue}
|
||||
options={{
|
||||
mode: state.currentContentType,
|
||||
theme: 'material',
|
||||
@@ -175,7 +175,6 @@ export const TextValuePresentation: TabContainerPanelComponent<IDataValuePanelPr
|
||||
name="value"
|
||||
rows={3}
|
||||
value={stringValue}
|
||||
disabled={stringValue === undefined}
|
||||
readOnly={readonly}
|
||||
embedded
|
||||
onChange={handleChange}
|
||||
|
||||
Reference in New Issue
Block a user