mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-18 01:25:37 -05:00
Add background color for null cell in query editor result grid (#22370)
This commit is contained in:
@@ -85,7 +85,7 @@ export function hyperLinkFormatter(row: number | undefined, cell: any | undefine
|
||||
/**
|
||||
* Format all text to replace all new lines with spaces and performs HTML entity encoding
|
||||
*/
|
||||
export function textFormatter(row: number | undefined, cell: any | undefined, value: any, columnDef: any | undefined, dataContext: any | undefined): string {
|
||||
export function textFormatter(row: number | undefined, cell: any | undefined, value: any, columnDef: any | undefined, dataContext: any | undefined, addClasses?: string): string | { text: string, addClasses: string } {
|
||||
let cellClasses = 'grid-cell-value-container';
|
||||
let valueToDisplay = '';
|
||||
let titleValue = '';
|
||||
@@ -122,7 +122,13 @@ export function textFormatter(row: number | undefined, cell: any | undefined, va
|
||||
titleValue = valueToDisplay;
|
||||
}
|
||||
|
||||
return `<span title="${titleValue}" style="${cellStyle}" class="${cellClasses}">${valueToDisplay}</span>`;
|
||||
const formattedValue = `<span title="${titleValue}" style="${cellStyle}" class="${cellClasses}">${valueToDisplay}</span>`;
|
||||
|
||||
if (addClasses) {
|
||||
return { text: formattedValue, addClasses: addClasses };
|
||||
}
|
||||
|
||||
return formattedValue;
|
||||
}
|
||||
|
||||
function getCellDisplayValue(cellValue: string): string {
|
||||
@@ -132,7 +138,7 @@ function getCellDisplayValue(cellValue: string): string {
|
||||
}
|
||||
|
||||
|
||||
export function iconCssFormatter(row: number | undefined, cell: any | undefined, value: any, columnDef: any | undefined, dataContext: any | undefined): string {
|
||||
export function iconCssFormatter(row: number | undefined, cell: any | undefined, value: any, columnDef: any | undefined, dataContext: any | undefined): string | { text: string, addClasses: string } {
|
||||
if (isCssIconCellValue(value)) {
|
||||
return `<div role="image" title="${escape(value.title ?? '')}" aria-label="${escape(value.title ?? '')}" class="grid-cell-value-container icon codicon slick-icon-cell-content ${value.iconCssClass}"></div>`;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@ suite('Grid shared services tests', () => {
|
||||
isNull: false
|
||||
};
|
||||
let formattedHtml = SharedServices.textFormatter(undefined, undefined, cellValue, undefined, undefined);
|
||||
if (typeof formattedHtml !== 'string') {
|
||||
formattedHtml = formattedHtml.text;
|
||||
}
|
||||
|
||||
// Then the result is HTML for a span element containing the cell value's display value as plain text
|
||||
verifyFormattedHtml(formattedHtml, testText);
|
||||
@@ -24,6 +27,9 @@ suite('Grid shared services tests', () => {
|
||||
test('textFormatter should encode HTML when formatting a string', () => {
|
||||
// If I format a string that contains HTML
|
||||
let formattedHtml = SharedServices.textFormatter(undefined, undefined, testText, undefined, undefined);
|
||||
if (typeof formattedHtml !== 'string') {
|
||||
formattedHtml = formattedHtml.text;
|
||||
}
|
||||
|
||||
// Then the result is HTML for a span element containing the given text as plain text
|
||||
verifyFormattedHtml(formattedHtml, testText);
|
||||
|
||||
@@ -91,3 +91,6 @@ export const calloutDialogShadowColor = registerColor('calloutDialog.shadow', {
|
||||
|
||||
// Designer
|
||||
export const DesignerPaneSeparator = registerColor('designer.paneSeparator', { light: '#DDDDDD', dark: '#8A8886', hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('designer.paneSeparator', 'The pane separator color.'));
|
||||
|
||||
// Query Editor
|
||||
export const queryEditorNullBackground = registerColor('queryEditor.nullBackground', { light: '#FFFFE1', dark: '#4B0082', hcDark: '#000000', hcLight: '#FFFFE1' }, nls.localize('queryEditorNullBackground', 'The background color for null values in the query editor results grid.'));
|
||||
|
||||
@@ -17,14 +17,14 @@ import { IGridActionContext, SaveResultAction, CopyResultAction, SelectAllGridAc
|
||||
import { CellSelectionModel } from 'sql/base/browser/ui/table/plugins/cellSelectionModel.plugin';
|
||||
import { RowNumberColumn } from 'sql/base/browser/ui/table/plugins/rowNumberColumn.plugin';
|
||||
import { escape } from 'sql/base/common/strings';
|
||||
import { hyperLinkFormatter, textFormatter } from 'sql/base/browser/ui/table/formatters';
|
||||
import { DBCellValue, hyperLinkFormatter, textFormatter } from 'sql/base/browser/ui/table/formatters';
|
||||
import { AdditionalKeyBindings } from 'sql/base/browser/ui/table/plugins/additionalKeyBindings.plugin';
|
||||
|
||||
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IColorTheme, ICssStyleCollector, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { isUndefinedOrNull } from 'vs/base/common/types';
|
||||
import { Disposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { range } from 'vs/base/common/arrays';
|
||||
@@ -56,6 +56,7 @@ import { CopyAction } from 'vs/editor/contrib/clipboard/browser/clipboard';
|
||||
import { formatDocumentWithSelectedProvider, FormattingMode } from 'vs/editor/contrib/format/browser/format';
|
||||
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { queryEditorNullBackground } from 'sql/platform/theme/common/colorRegistry';
|
||||
|
||||
const ROW_HEIGHT = 29;
|
||||
const HEADER_HEIGHT = 26;
|
||||
@@ -80,6 +81,9 @@ const MIN_GRID_HEIGHT = (MIN_GRID_HEIGHT_ROWS * ROW_HEIGHT) + HEADER_HEIGHT + ES
|
||||
// or '{', and there must be a '}' or ']' to close it.
|
||||
const IsJsonRegex = /^\s*[\{|\[][\S\s]*[\}\]]\s*$/g;
|
||||
|
||||
// The css class for null cell
|
||||
const NULL_CELL_CSS_CLASS = 'cell-null';
|
||||
|
||||
export class GridPanel extends Disposable {
|
||||
private container = document.createElement('div');
|
||||
private scrollableView: ScrollableView;
|
||||
@@ -431,7 +435,7 @@ export abstract class GridTableBase<T> extends Disposable implements IView {
|
||||
? localize('xmlShowplan', "XML Showplan")
|
||||
: escape(c.columnName),
|
||||
field: i.toString(),
|
||||
formatter: c.isXml ? hyperLinkFormatter : (row: number | undefined, cell: any | undefined, value: ICellValue, columnDef: any | undefined, dataContext: any | undefined): string => {
|
||||
formatter: c.isXml ? hyperLinkFormatter : (row: number | undefined, cell: any | undefined, value: ICellValue, columnDef: any | undefined, dataContext: any | undefined): string | { text: string, addClasses: string } => {
|
||||
return queryResultTextFormatter(this.gridConfig.showJsonAsLink, row, cell, value, columnDef, dataContext);
|
||||
},
|
||||
width: this.state.columnSizes && this.state.columnSizes[i] ? this.state.columnSizes[i] : undefined
|
||||
@@ -567,6 +571,13 @@ export abstract class GridTableBase<T> extends Disposable implements IView {
|
||||
refreshColumns: !autoSizeOnRender // The auto size columns plugin refreshes the columns so we don't need to refresh twice if both plugins are on.
|
||||
});
|
||||
this._register(attachTableFilterStyler(this.filterPlugin, this.themeService));
|
||||
this._register(registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => {
|
||||
const nullBackground = theme.getColor(queryEditorNullBackground);
|
||||
if (nullBackground) {
|
||||
collector.addRule(`.${NULL_CELL_CSS_CLASS} { background: ${nullBackground};}`);
|
||||
}
|
||||
}));
|
||||
|
||||
this.table.registerPlugin(this.filterPlugin);
|
||||
if (this.styles) {
|
||||
this.table.style(this.styles);
|
||||
@@ -1004,10 +1015,10 @@ function isJsonCell(value: ICellValue): boolean {
|
||||
return !!(value && !value.isNull && value.displayValue?.match(IsJsonRegex));
|
||||
}
|
||||
|
||||
function queryResultTextFormatter(showJsonAsLink: boolean, row: number | undefined, cell: any | undefined, value: ICellValue, columnDef: any | undefined, dataContext: any | undefined): string {
|
||||
function queryResultTextFormatter(showJsonAsLink: boolean, row: number | undefined, cell: any | undefined, value: ICellValue, columnDef: any | undefined, dataContext: any | undefined): string | { text: string, addClasses: string } {
|
||||
if (showJsonAsLink && isJsonCell(value)) {
|
||||
return hyperLinkFormatter(row, cell, value, columnDef, dataContext);
|
||||
} else {
|
||||
return textFormatter(row, cell, value, columnDef, dataContext);
|
||||
return textFormatter(row, cell, value, columnDef, dataContext, (DBCellValue.isDBCellValue(value) && value.isNull) ? NULL_CELL_CSS_CLASS : undefined);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user