mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Fix for Edit Data grid newline on multiline strings (#22269)
* Fix for newline replacement * added proper null regex and null character check * removed cell class * removed unnecessary function * revert back to old check * change onbeforeeditcell * small fix to typo in onBeforeEditCell * made changes based on feedback * added comments clarifying isDBCellValue
This commit is contained in:
@@ -37,6 +37,9 @@ import * as DOM from 'vs/base/browser/dom';
|
|||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
||||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||||
|
import { localize } from 'vs/nls';
|
||||||
|
|
||||||
|
const cellWithNullCharMessage = localize('editData.cellWithNullCharMessage', "This cell contains the Unicode null character which is currently not supported for editing.");
|
||||||
|
|
||||||
export class EditDataGridPanel extends GridParentComponent {
|
export class EditDataGridPanel extends GridParentComponent {
|
||||||
// The time(in milliseconds) we wait before refreshing the grid.
|
// The time(in milliseconds) we wait before refreshing the grid.
|
||||||
@@ -84,7 +87,7 @@ export class EditDataGridPanel extends GridParentComponent {
|
|||||||
public onCellEditEnd: (event: Slick.OnCellChangeEventArgs<any>) => void;
|
public onCellEditEnd: (event: Slick.OnCellChangeEventArgs<any>) => void;
|
||||||
public onIsCellEditValid: (row: number, column: number, newValue: any) => boolean;
|
public onIsCellEditValid: (row: number, column: number, newValue: any) => boolean;
|
||||||
public onIsColumnEditable: (column: number) => boolean;
|
public onIsColumnEditable: (column: number) => boolean;
|
||||||
public overrideCellFn: (rowNumber, columnId, value?, data?) => string;
|
public overrideCellFn: (columnId, value?, data?) => string;
|
||||||
public loadDataFunction: (offset: number, count: number) => Promise<{}[]>;
|
public loadDataFunction: (offset: number, count: number) => Promise<{}[]>;
|
||||||
public onBeforeAppendCell: (row: number, column: number) => string;
|
public onBeforeAppendCell: (row: number, column: number) => string;
|
||||||
public onRefreshComplete: Promise<void>;
|
public onRefreshComplete: Promise<void>;
|
||||||
@@ -192,7 +195,7 @@ export class EditDataGridPanel extends GridParentComponent {
|
|||||||
self.currentEditCellValue = event.item[event.cell];
|
self.currentEditCellValue = event.item[event.cell];
|
||||||
};
|
};
|
||||||
|
|
||||||
this.overrideCellFn = (rowNumber, columnId, value?, data?): string => {
|
this.overrideCellFn = (columnId, value?, data?): string => {
|
||||||
let returnVal = '';
|
let returnVal = '';
|
||||||
// replace the line breaks with space since the edit text control cannot
|
// replace the line breaks with space since the edit text control cannot
|
||||||
// render line breaks and strips them, updating the value.
|
// render line breaks and strips them, updating the value.
|
||||||
@@ -206,9 +209,12 @@ export class EditDataGridPanel extends GridParentComponent {
|
|||||||
returnVal = '\'NULL\'';
|
returnVal = '\'NULL\'';
|
||||||
}
|
}
|
||||||
else if (Services.DBCellValue.isDBCellValue(value)) {
|
else if (Services.DBCellValue.isDBCellValue(value)) {
|
||||||
|
// If a cell is not edited and retrieved direct from the SQL server, it would be in the form of a DBCellValue.
|
||||||
|
// We use the DBCellValue's displayValue as the text value.
|
||||||
returnVal = this.replaceLinebreaks(value.displayValue);
|
returnVal = this.replaceLinebreaks(value.displayValue);
|
||||||
}
|
}
|
||||||
else if (typeof value === 'string') {
|
else if (typeof value === 'string') {
|
||||||
|
// Once a cell has been edited, the cell value will no longer be a DBCellValue until refresh.
|
||||||
returnVal = this.replaceLinebreaks(value);
|
returnVal = this.replaceLinebreaks(value);
|
||||||
}
|
}
|
||||||
return returnVal;
|
return returnVal;
|
||||||
@@ -643,7 +649,8 @@ export class EditDataGridPanel extends GridParentComponent {
|
|||||||
? self.rowIdMappings[self.currentCell.row]
|
? self.rowIdMappings[self.currentCell.row]
|
||||||
: self.currentCell.row;
|
: self.currentCell.row;
|
||||||
|
|
||||||
return self.dataService.updateCell(sessionRowId, self.currentCell.column - 1, this.newlinePattern ? self.currentEditCellValue.replace('\u0000', this.newlinePattern) : self.currentEditCellValue);
|
let restoredValue = this.newlinePattern ? self.currentEditCellValue.replace(/\u0000/g, this.newlinePattern) : self.currentEditCellValue;
|
||||||
|
return self.dataService.updateCell(sessionRowId, self.currentCell.column - 1, restoredValue);
|
||||||
}).then(
|
}).then(
|
||||||
result => {
|
result => {
|
||||||
// last entered input is no longer needed as we have entered a valid input to commit.
|
// last entered input is no longer needed as we have entered a valid input to commit.
|
||||||
@@ -943,15 +950,15 @@ export class EditDataGridPanel extends GridParentComponent {
|
|||||||
this._textEditor.setValue(val);
|
this._textEditor.setValue(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadValue(item, rowNumber): void {
|
loadValue(item): void {
|
||||||
const itemForDisplay = deepClone(item);
|
let itemForEdit = deepClone(item);
|
||||||
if (self.overrideCellFn) {
|
if (self.overrideCellFn) {
|
||||||
let overrideValue = self.overrideCellFn(rowNumber, this._args.column.id, itemForDisplay[this._args.column.id]);
|
let overrideValue = self.overrideCellFn(this._args.column.id, itemForEdit[this._args.column.id]);
|
||||||
if (overrideValue !== undefined) {
|
if (overrideValue !== undefined) {
|
||||||
itemForDisplay[this._args.column.id] = overrideValue;
|
itemForEdit[this._args.column.id] = overrideValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._textEditor.loadValue(itemForDisplay);
|
this._textEditor.loadValue(itemForEdit);
|
||||||
}
|
}
|
||||||
|
|
||||||
serializeValue(): string {
|
serializeValue(): string {
|
||||||
@@ -1110,7 +1117,7 @@ export class EditDataGridPanel extends GridParentComponent {
|
|||||||
this.onCellEditEnd(args);
|
this.onCellEditEnd(args);
|
||||||
});
|
});
|
||||||
this.table.grid.onBeforeEditCell.subscribe((e, args) => {
|
this.table.grid.onBeforeEditCell.subscribe((e, args) => {
|
||||||
this.onBeforeEditCell(args);
|
return this.onBeforeEditCell(args);
|
||||||
});
|
});
|
||||||
// Subscribe to all active cell changes to be able to catch when we tab to the header on the next row
|
// Subscribe to all active cell changes to be able to catch when we tab to the header on the next row
|
||||||
this.table.grid.onActiveCellChanged.subscribe((e, args) => {
|
this.table.grid.onActiveCellChanged.subscribe((e, args) => {
|
||||||
@@ -1126,9 +1133,41 @@ export class EditDataGridPanel extends GridParentComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeEditCell(event: Slick.OnBeforeEditCellEventArgs<any>): void {
|
onBeforeEditCell(event: Slick.OnBeforeEditCellEventArgs<any>): boolean {
|
||||||
|
let result = true;
|
||||||
this.logService.debug('onBeforeEditCell called with grid: ' + event.grid + ' row: ' + event.row
|
this.logService.debug('onBeforeEditCell called with grid: ' + event.grid + ' row: ' + event.row
|
||||||
+ ' cell: ' + event.cell + ' item: ' + event.item + ' column: ' + event.column);
|
+ ' cell: ' + event.cell + ' item: ' + event.item + ' column: ' + event.column);
|
||||||
|
|
||||||
|
let itemToEdit = event.item[event.cell];
|
||||||
|
|
||||||
|
if (Services.DBCellValue.isDBCellValue(itemToEdit)) {
|
||||||
|
// If a cell is not edited and retrieved direct from the SQL server, it would be in the form of a DBCellValue.
|
||||||
|
// We use it's displayValue to check if the cell contains unicode NULL and linebreaks.
|
||||||
|
result = !this.hasNullAndLinebreak(itemToEdit.displayValue)
|
||||||
|
}
|
||||||
|
else if (typeof itemToEdit === 'string' || (itemToEdit && itemToEdit.text)) {
|
||||||
|
// Once a cell has been edited, the cell value will no longer be a DBCellValue until refresh.
|
||||||
|
// In this case, just check directly if it's a string or if it's an item with .text, use the text.
|
||||||
|
if (itemToEdit.text) {
|
||||||
|
result = !this.hasNullAndLinebreak(itemToEdit.text);
|
||||||
|
} else {
|
||||||
|
result = !this.hasNullAndLinebreak(itemToEdit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
this.notificationService.warn(cellWithNullCharMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasNullAndLinebreak(inputString: string): boolean {
|
||||||
|
if (inputString) {
|
||||||
|
let linebreakMatch = inputString.match(/(\r\n|\n|\r)/);
|
||||||
|
return linebreakMatch?.length > 0 && inputString.indexOf('\u0000') !== -1;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleInitializeTable(): void {
|
handleInitializeTable(): void {
|
||||||
@@ -1146,7 +1185,7 @@ export class EditDataGridPanel extends GridParentComponent {
|
|||||||
|
|
||||||
|
|
||||||
/*Formatter for Column*/
|
/*Formatter for Column*/
|
||||||
private getColumnFormatter(row: number | undefined, cell: any | undefined, value: any, columnDef: any | undefined, dataContext: any | undefined): string {
|
private getColumnFormatter(row: number | undefined, cell: number | undefined, value: any, columnDef: any | undefined, dataContext: any | undefined): string {
|
||||||
let valueToDisplay = '';
|
let valueToDisplay = '';
|
||||||
let cellClasses = 'grid-cell-value-container';
|
let cellClasses = 'grid-cell-value-container';
|
||||||
/* tslint:disable:no-null-keyword */
|
/* tslint:disable:no-null-keyword */
|
||||||
@@ -1160,10 +1199,15 @@ export class EditDataGridPanel extends GridParentComponent {
|
|||||||
valueToDisplay = '\'NULL\'';
|
valueToDisplay = '\'NULL\'';
|
||||||
}
|
}
|
||||||
else if (Services.DBCellValue.isDBCellValue(value)) {
|
else if (Services.DBCellValue.isDBCellValue(value)) {
|
||||||
|
// If a cell is not edited and retrieved direct from the SQL server, it would be in the form of a DBCellValue.
|
||||||
|
// We use it's displayValue and remove newlines for display purposes only.
|
||||||
valueToDisplay = (value.displayValue + '');
|
valueToDisplay = (value.displayValue + '');
|
||||||
|
valueToDisplay = valueToDisplay.replace(/(\r\n|\n|\r)/g, '\u0000');
|
||||||
valueToDisplay = escape(valueToDisplay.length > 250 ? valueToDisplay.slice(0, 250) + '...' : valueToDisplay);
|
valueToDisplay = escape(valueToDisplay.length > 250 ? valueToDisplay.slice(0, 250) + '...' : valueToDisplay);
|
||||||
}
|
}
|
||||||
else if (typeof value === 'string' || (value && value.text)) {
|
else if (typeof value === 'string' || (value && value.text)) {
|
||||||
|
// Once a cell has been edited, the cell value will no longer be a DBCellValue until refresh.
|
||||||
|
// In this case, use directly if it's a string or if it's an item with .text, use the text.
|
||||||
if (value.text) {
|
if (value.text) {
|
||||||
valueToDisplay = value.text;
|
valueToDisplay = value.text;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user