mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-10-11 14:14:36 +08:00
Refactor console.table messages to their own class
This CL makes the type property on SDK.ConsoleModel.ConsoleMessage read- only and refactors the ConsoleViewMessage to remove the console.table related logic to the derived class ConsoleTableMessageView. Bug: chromium:1140516 Change-Id: I18cb3fa938da40ddf024df7ca01025fec6396585 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2498231 Reviewed-by: Wolfgang Beyer <wolfi@chromium.org> Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
This commit is contained in:
committed by
Commit Bot
parent
30c4a71de5
commit
8bfb421bc2
@@ -42,7 +42,7 @@ import {ConsoleFilter, FilterType} from './ConsoleFilter.js';
|
||||
import {ConsolePinPane} from './ConsolePinPane.js';
|
||||
import {ConsolePrompt, Events as ConsolePromptEvents} from './ConsolePrompt.js';
|
||||
import {ConsoleSidebar, Events} from './ConsoleSidebar.js';
|
||||
import {ConsoleCommand, ConsoleCommandResult, ConsoleGroupViewMessage, ConsoleViewMessage, getMessageForElement, MaxLengthForLinks} from './ConsoleViewMessage.js'; // eslint-disable-line no-unused-vars
|
||||
import {ConsoleCommand, ConsoleCommandResult, ConsoleGroupViewMessage, ConsoleTableMessageView, ConsoleViewMessage, getMessageForElement, MaxLengthForLinks} from './ConsoleViewMessage.js'; // eslint-disable-line no-unused-vars
|
||||
import {ConsoleViewport, ConsoleViewportElement, ConsoleViewportProvider} from './ConsoleViewport.js'; // eslint-disable-line no-unused-vars
|
||||
|
||||
/** @type {!ConsoleView} */
|
||||
@@ -849,6 +849,8 @@ export class ConsoleView extends UI.Widget.VBox {
|
||||
case SDK.ConsoleModel.MessageType.StartGroup:
|
||||
return new ConsoleGroupViewMessage(
|
||||
message, this._linkifier, nestingLevel, this._updateMessageList.bind(this), this._onMessageResizedBound);
|
||||
case SDK.ConsoleModel.MessageType.Table:
|
||||
return new ConsoleTableMessageView(message, this._linkifier, nestingLevel, this._onMessageResizedBound);
|
||||
default:
|
||||
return new ConsoleViewMessage(message, this._linkifier, nestingLevel, this._onMessageResizedBound);
|
||||
}
|
||||
|
||||
@@ -50,6 +50,31 @@ export const getMessageForElement = element => {
|
||||
return elementToMessage.get(element);
|
||||
};
|
||||
|
||||
// This value reflects the 18px min-height of .console-message, plus the
|
||||
// 1px border of .console-message-wrapper. Keep in sync with consoleView.css.
|
||||
const defaultConsoleRowHeight = 19;
|
||||
|
||||
/**
|
||||
* @param {?SDK.RuntimeModel.RuntimeModel} runtimeModel
|
||||
*/
|
||||
const parameterToRemoteObject = runtimeModel =>
|
||||
/**
|
||||
* @param {!SDK.RemoteObject.RemoteObject|!Protocol.Runtime.RemoteObject|string|undefined} parameter
|
||||
* @return {!SDK.RemoteObject.RemoteObject}
|
||||
*/
|
||||
parameter => {
|
||||
if (parameter instanceof SDK.RemoteObject.RemoteObject) {
|
||||
return parameter;
|
||||
}
|
||||
if (!runtimeModel) {
|
||||
return SDK.RemoteObject.RemoteObject.fromLocalObject(parameter);
|
||||
}
|
||||
if (typeof parameter === 'object') {
|
||||
return runtimeModel.createRemoteObject(parameter);
|
||||
}
|
||||
return runtimeModel.createRemoteObjectFromPrimitiveValue(parameter);
|
||||
};
|
||||
|
||||
/**
|
||||
* @implements {ConsoleViewportElement}
|
||||
*/
|
||||
@@ -72,8 +97,6 @@ export class ConsoleViewMessage {
|
||||
/** @type {?HTMLElement} */
|
||||
this._element = null;
|
||||
|
||||
/** @type {?DataGrid.SortableDataGrid.SortableDataGrid<?>} */
|
||||
this._dataGrid = null;
|
||||
this._previewFormatter = new ObjectUI.RemoteObjectPreviewFormatter.RemoteObjectPreviewFormatter();
|
||||
this._searchRegex = null;
|
||||
/** @type {?UI.Icon.Icon} */
|
||||
@@ -117,19 +140,10 @@ export class ConsoleViewMessage {
|
||||
* @override
|
||||
*/
|
||||
wasShown() {
|
||||
if (this._dataGrid) {
|
||||
this._dataGrid.updateWidths();
|
||||
}
|
||||
this._isVisible = true;
|
||||
}
|
||||
|
||||
onResize() {
|
||||
if (!this._isVisible) {
|
||||
return;
|
||||
}
|
||||
if (this._dataGrid) {
|
||||
this._dataGrid.onResize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,6 +154,10 @@ export class ConsoleViewMessage {
|
||||
this._cachedHeight = this.element().offsetHeight;
|
||||
}
|
||||
|
||||
isVisible() {
|
||||
return this._isVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {number}
|
||||
*/
|
||||
@@ -147,15 +165,10 @@ export class ConsoleViewMessage {
|
||||
if (this._cachedHeight) {
|
||||
return this._cachedHeight;
|
||||
}
|
||||
// This value reflects the 18px min-height of .console-message, plus the
|
||||
// 1px border of .console-message-wrapper. Keep in sync with consoleView.css.
|
||||
const defaultConsoleRowHeight = 19;
|
||||
if (this._message.type === SDK.ConsoleModel.MessageType.Table) {
|
||||
const table = this._message.parameters && this._message.parameters[0];
|
||||
if (table && typeof table !== 'string' && table.preview) {
|
||||
return defaultConsoleRowHeight * table.preview.properties.length;
|
||||
}
|
||||
}
|
||||
return this.approximateFastHeight();
|
||||
}
|
||||
|
||||
approximateFastHeight() {
|
||||
return defaultConsoleRowHeight;
|
||||
}
|
||||
|
||||
@@ -166,97 +179,6 @@ export class ConsoleViewMessage {
|
||||
return this._message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!HTMLElement}
|
||||
*/
|
||||
_buildTableMessage() {
|
||||
const formattedMessage = /** @type {!HTMLElement} */ (document.createElement('span'));
|
||||
formattedMessage.classList.add('source-code');
|
||||
this._anchorElement = this._buildMessageAnchor();
|
||||
if (this._anchorElement) {
|
||||
formattedMessage.appendChild(this._anchorElement);
|
||||
}
|
||||
|
||||
const table = this._message.parameters && this._message.parameters.length ? this._message.parameters[0] : null;
|
||||
if (!table) {
|
||||
return this._buildMessage();
|
||||
}
|
||||
const actualTable = this._parameterToRemoteObject(table);
|
||||
if (!actualTable || !actualTable.preview) {
|
||||
return this._buildMessage();
|
||||
}
|
||||
|
||||
const rawValueColumnSymbol = Symbol('rawValueColumn');
|
||||
/** @type {!Array<string|symbol>} */
|
||||
const columnNames = [];
|
||||
const preview = actualTable.preview;
|
||||
const rows = [];
|
||||
for (let i = 0; i < preview.properties.length; ++i) {
|
||||
const rowProperty = preview.properties[i];
|
||||
/** @type {!Array<!Protocol.Runtime.PropertyPreview|!{name:(string|symbol), type: !Protocol.Runtime.PropertyPreviewType, value: (string|undefined)}>} */
|
||||
let rowSubProperties;
|
||||
if (rowProperty.valuePreview) {
|
||||
rowSubProperties = rowProperty.valuePreview.properties;
|
||||
} else if (rowProperty.value) {
|
||||
rowSubProperties = [{name: rawValueColumnSymbol, type: rowProperty.type, value: rowProperty.value}];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @type {!Map<string|symbol, !HTMLElement>} */
|
||||
const rowValue = new Map();
|
||||
const maxColumnsToRender = 20;
|
||||
for (let j = 0; j < rowSubProperties.length; ++j) {
|
||||
const cellProperty = rowSubProperties[j];
|
||||
let columnRendered = columnNames.indexOf(cellProperty.name) !== -1;
|
||||
if (!columnRendered) {
|
||||
if (columnNames.length === maxColumnsToRender) {
|
||||
continue;
|
||||
}
|
||||
columnRendered = true;
|
||||
columnNames.push(cellProperty.name);
|
||||
}
|
||||
|
||||
if (columnRendered) {
|
||||
const cellElement =
|
||||
this._renderPropertyPreviewOrAccessor(actualTable, cellProperty, [rowProperty, cellProperty]);
|
||||
cellElement.classList.add('console-message-nowrap-below');
|
||||
rowValue.set(cellProperty.name, cellElement);
|
||||
}
|
||||
}
|
||||
rows.push({rowName: rowProperty.name, rowValue});
|
||||
}
|
||||
|
||||
const flatValues = [];
|
||||
for (const {rowName, rowValue} of rows) {
|
||||
flatValues.push(rowName);
|
||||
for (let j = 0; j < columnNames.length; ++j) {
|
||||
flatValues.push(rowValue.get(columnNames[j]));
|
||||
}
|
||||
}
|
||||
columnNames.unshift(Common.UIString.UIString('(index)'));
|
||||
const columnDisplayNames =
|
||||
columnNames.map(name => name === rawValueColumnSymbol ? Common.UIString.UIString('Value') : name.toString());
|
||||
|
||||
if (flatValues.length) {
|
||||
this._dataGrid = DataGrid.SortableDataGrid.SortableDataGrid.create(columnDisplayNames, flatValues, ls`Console`);
|
||||
if (this._dataGrid) {
|
||||
this._dataGrid.setStriped(true);
|
||||
this._dataGrid.setFocusable(false);
|
||||
|
||||
const formattedResult = document.createElement('span');
|
||||
formattedResult.classList.add('console-message-text');
|
||||
const tableElement = formattedResult.createChild('div', 'console-message-formatted-table');
|
||||
const dataGridContainer = tableElement.createChild('span');
|
||||
tableElement.appendChild(this._formatParameter(actualTable, true, false));
|
||||
dataGridContainer.appendChild(this._dataGrid.element);
|
||||
formattedMessage.appendChild(formattedResult);
|
||||
this._dataGrid.renderInline();
|
||||
}
|
||||
}
|
||||
return formattedMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!HTMLElement}
|
||||
*/
|
||||
@@ -515,24 +437,6 @@ export class ConsoleViewMessage {
|
||||
runtimeModel.target(), scriptId, url, lineNumber, {columnNumber, className: undefined, tabStop: undefined});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!SDK.RemoteObject.RemoteObject|!Protocol.Runtime.RemoteObject|string|undefined} parameter
|
||||
* @return {!SDK.RemoteObject.RemoteObject}
|
||||
*/
|
||||
_parameterToRemoteObject(parameter) {
|
||||
if (parameter instanceof SDK.RemoteObject.RemoteObject) {
|
||||
return parameter;
|
||||
}
|
||||
const runtimeModel = this._message.runtimeModel();
|
||||
if (!runtimeModel) {
|
||||
return SDK.RemoteObject.RemoteObject.fromLocalObject(parameter);
|
||||
}
|
||||
if (typeof parameter === 'object') {
|
||||
return runtimeModel.createRemoteObject(parameter);
|
||||
}
|
||||
return runtimeModel.createRemoteObjectFromPrimitiveValue(parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array.<!Protocol.Runtime.RemoteObject | !SDK.RemoteObject.RemoteObject | string | undefined>} rawParameters
|
||||
* @return {!HTMLElement}
|
||||
@@ -550,7 +454,7 @@ export class ConsoleViewMessage {
|
||||
// Formatting code below assumes that parameters are all wrappers whereas frontend console
|
||||
// API allows passing arbitrary values as messages (strings, numbers, etc.). Wrap them here.
|
||||
// FIXME: Only pass runtime wrappers here.
|
||||
let parameters = rawParameters.map(this._parameterToRemoteObject.bind(this));
|
||||
let parameters = rawParameters.map(parameterToRemoteObject(this._message.runtimeModel()));
|
||||
|
||||
// There can be string log and string eval result. We distinguish between them based on message type.
|
||||
const shouldFormatMessage =
|
||||
@@ -1343,8 +1247,6 @@ export class ConsoleViewMessage {
|
||||
this._message.type === SDK.ConsoleModel.MessageType.Trace);
|
||||
if (runtimeModel && shouldIncludeTrace) {
|
||||
formattedMessage = this._buildMessageWithStackTrace(runtimeModel);
|
||||
} else if (this._message.type === SDK.ConsoleModel.MessageType.Table) {
|
||||
formattedMessage = this._buildTableMessage();
|
||||
} else {
|
||||
formattedMessage = this._buildMessage();
|
||||
}
|
||||
@@ -2016,6 +1918,168 @@ export class ConsoleCommandResult extends ConsoleViewMessage {
|
||||
}
|
||||
}
|
||||
|
||||
export class ConsoleTableMessageView extends ConsoleViewMessage {
|
||||
/**
|
||||
* @param {!SDK.ConsoleModel.ConsoleMessage} consoleMessage
|
||||
* @param {!Components.Linkifier.Linkifier} linkifier
|
||||
* @param {number} nestingLevel
|
||||
* @param {function(!Common.EventTarget.EventTargetEvent): void} onResize
|
||||
*/
|
||||
constructor(consoleMessage, linkifier, nestingLevel, onResize) {
|
||||
super(consoleMessage, linkifier, nestingLevel, onResize);
|
||||
console.assert(consoleMessage.type === SDK.ConsoleModel.MessageType.Table);
|
||||
/** @type {?DataGrid.SortableDataGrid.SortableDataGrid<?>} */
|
||||
this._dataGrid = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
wasShown() {
|
||||
if (this._dataGrid) {
|
||||
this._dataGrid.updateWidths();
|
||||
}
|
||||
super.wasShown();
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
onResize() {
|
||||
if (!this.isVisible()) {
|
||||
return;
|
||||
}
|
||||
if (this._dataGrid) {
|
||||
this._dataGrid.onResize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @return {!HTMLElement}
|
||||
*/
|
||||
contentElement() {
|
||||
const contentElement = this.getContentElement();
|
||||
if (contentElement) {
|
||||
return contentElement;
|
||||
}
|
||||
|
||||
const newContentElement = /** @type {!HTMLElement} */ (document.createElement('div'));
|
||||
newContentElement.classList.add('console-message');
|
||||
if (this._messageLevelIcon) {
|
||||
newContentElement.appendChild(this._messageLevelIcon);
|
||||
}
|
||||
this.setContentElement(newContentElement);
|
||||
|
||||
newContentElement.appendChild(this._buildTableMessage());
|
||||
this.updateTimestamp();
|
||||
return newContentElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!HTMLElement}
|
||||
*/
|
||||
_buildTableMessage() {
|
||||
const formattedMessage = /** @type {!HTMLElement} */ (document.createElement('span'));
|
||||
formattedMessage.classList.add('source-code');
|
||||
this._anchorElement = this._buildMessageAnchor();
|
||||
if (this._anchorElement) {
|
||||
formattedMessage.appendChild(this._anchorElement);
|
||||
}
|
||||
|
||||
const table = this._message.parameters && this._message.parameters.length ? this._message.parameters[0] : null;
|
||||
if (!table) {
|
||||
return this._buildMessage();
|
||||
}
|
||||
const actualTable = parameterToRemoteObject(this._message.runtimeModel())(table);
|
||||
if (!actualTable || !actualTable.preview) {
|
||||
return this._buildMessage();
|
||||
}
|
||||
|
||||
const rawValueColumnSymbol = Symbol('rawValueColumn');
|
||||
/** @type {!Array<string|symbol>} */
|
||||
const columnNames = [];
|
||||
const preview = actualTable.preview;
|
||||
const rows = [];
|
||||
for (let i = 0; i < preview.properties.length; ++i) {
|
||||
const rowProperty = preview.properties[i];
|
||||
/** @type {!Array<!Protocol.Runtime.PropertyPreview|!{name:(string|symbol), type: !Protocol.Runtime.PropertyPreviewType, value: (string|undefined)}>} */
|
||||
let rowSubProperties;
|
||||
if (rowProperty.valuePreview) {
|
||||
rowSubProperties = rowProperty.valuePreview.properties;
|
||||
} else if (rowProperty.value) {
|
||||
rowSubProperties = [{name: rawValueColumnSymbol, type: rowProperty.type, value: rowProperty.value}];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @type {!Map<string|symbol, !HTMLElement>} */
|
||||
const rowValue = new Map();
|
||||
const maxColumnsToRender = 20;
|
||||
for (let j = 0; j < rowSubProperties.length; ++j) {
|
||||
const cellProperty = rowSubProperties[j];
|
||||
let columnRendered = columnNames.indexOf(cellProperty.name) !== -1;
|
||||
if (!columnRendered) {
|
||||
if (columnNames.length === maxColumnsToRender) {
|
||||
continue;
|
||||
}
|
||||
columnRendered = true;
|
||||
columnNames.push(cellProperty.name);
|
||||
}
|
||||
|
||||
if (columnRendered) {
|
||||
const cellElement =
|
||||
this._renderPropertyPreviewOrAccessor(actualTable, cellProperty, [rowProperty, cellProperty]);
|
||||
cellElement.classList.add('console-message-nowrap-below');
|
||||
rowValue.set(cellProperty.name, cellElement);
|
||||
}
|
||||
}
|
||||
rows.push({rowName: rowProperty.name, rowValue});
|
||||
}
|
||||
|
||||
const flatValues = [];
|
||||
for (const {rowName, rowValue} of rows) {
|
||||
flatValues.push(rowName);
|
||||
for (let j = 0; j < columnNames.length; ++j) {
|
||||
flatValues.push(rowValue.get(columnNames[j]));
|
||||
}
|
||||
}
|
||||
columnNames.unshift(Common.UIString.UIString('(index)'));
|
||||
const columnDisplayNames =
|
||||
columnNames.map(name => name === rawValueColumnSymbol ? Common.UIString.UIString('Value') : name.toString());
|
||||
|
||||
if (flatValues.length) {
|
||||
this._dataGrid = DataGrid.SortableDataGrid.SortableDataGrid.create(columnDisplayNames, flatValues, ls`Console`);
|
||||
if (this._dataGrid) {
|
||||
this._dataGrid.setStriped(true);
|
||||
this._dataGrid.setFocusable(false);
|
||||
|
||||
const formattedResult = document.createElement('span');
|
||||
formattedResult.classList.add('console-message-text');
|
||||
const tableElement = formattedResult.createChild('div', 'console-message-formatted-table');
|
||||
const dataGridContainer = tableElement.createChild('span');
|
||||
tableElement.appendChild(this._formatParameter(actualTable, true, false));
|
||||
dataGridContainer.appendChild(this._dataGrid.element);
|
||||
formattedMessage.appendChild(formattedResult);
|
||||
this._dataGrid.renderInline();
|
||||
}
|
||||
}
|
||||
return formattedMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @return {number}
|
||||
*/
|
||||
approximateFastHeight() {
|
||||
const table = this._message.parameters && this._message.parameters[0];
|
||||
if (table && typeof table !== 'string' && table.preview) {
|
||||
return defaultConsoleRowHeight * table.preview.properties.length;
|
||||
}
|
||||
return defaultConsoleRowHeight;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum length before strings are considered too long for syntax highlighting.
|
||||
* @const
|
||||
|
||||
@@ -508,7 +508,7 @@ export class ConsoleMessage {
|
||||
this.source = source;
|
||||
this.level = /** @type {?MessageLevel} */ (level);
|
||||
this.messageText = messageText;
|
||||
this.type = type || MessageType.Log;
|
||||
this._type = type || MessageType.Log;
|
||||
/** @type {string|undefined} */
|
||||
this.url = url || undefined;
|
||||
/** @type {number} */
|
||||
@@ -549,6 +549,10 @@ export class ConsoleMessage {
|
||||
this._exceptionId = undefined;
|
||||
}
|
||||
|
||||
get type() {
|
||||
return this._type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!RuntimeModel} runtimeModel
|
||||
* @param {!Protocol.Runtime.ExceptionDetails} exceptionDetails
|
||||
|
||||
Reference in New Issue
Block a user