Skip to content

Commit f80096d

Browse files
masnobleDevtools-frontend LUCI CQ
authored andcommitted
Allow legacy data grid instantiation from lit-html template
Similar to the split widget changes: https://crrev.com/c/5898679 Bug: 301364727 Change-Id: I9fadad2d9288f1fd90c25b0f9f6db1b9663ae990 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/5960859 Reviewed-by: Philip Pfaffe <[email protected]> Reviewed-by: Jack Franklin <[email protected]> Commit-Queue: Joshua Thomas <[email protected]>
1 parent ddb048e commit f80096d

File tree

4 files changed

+155
-6
lines changed

4 files changed

+155
-6
lines changed

front_end/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ group("unittests") {
238238
"ui/legacy:copy_stylesheets_for_server",
239239
"ui/legacy:unittests",
240240
"ui/legacy/components/color_picker:unittests",
241+
"ui/legacy/components/data_grid:unittests",
241242
"ui/legacy/components/inline_editor:unittests",
242243
"ui/legacy/components/object_ui:unittests",
243244
"ui/legacy/components/perf_ui:unittests",

front_end/ui/legacy/components/data_grid/BUILD.gn

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,14 @@ devtools_entrypoint("bundle") {
5353

5454
visibility += devtools_ui_legacy_visibility
5555
}
56+
57+
ts_library("unittests") {
58+
testonly = true
59+
60+
sources = [ "DataGrid.test.ts" ]
61+
62+
deps = [
63+
":bundle",
64+
"../../../../testing",
65+
]
66+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2024 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import {renderElementIntoDOM} from '../../../../testing/DOMHelpers.js';
6+
import {describeWithEnvironment} from '../../../../testing/EnvironmentHelpers.js';
7+
import * as LitHtml from '../../../../ui/lit-html/lit-html.js';
8+
import * as UI from '../../legacy.js';
9+
10+
import * as DataGrid from './data_grid.js';
11+
12+
const {render, html} = LitHtml;
13+
const widgetRef = UI.Widget.widgetRef;
14+
15+
describeWithEnvironment('DataGrid', () => {
16+
it('can be instantiated from template', async () => {
17+
const container = document.createElement('div');
18+
renderElementIntoDOM(container);
19+
20+
let widget!: DataGrid.DataGrid.DataGridWidget<unknown>;
21+
22+
const dataGridOptions: DataGrid.DataGrid.DataGridWidgetOptions<unknown> = {
23+
implParams: {
24+
displayName: 'testGrid',
25+
columns: [{
26+
id: 'test',
27+
sortable: false,
28+
}],
29+
},
30+
nodes: [new DataGrid.DataGrid.DataGridNode({test: 'testNode'})],
31+
markAsRoot: true,
32+
};
33+
34+
// clang-format off
35+
render(
36+
html`
37+
<devtools-data-grid-widget
38+
.options=${dataGridOptions}
39+
${widgetRef(DataGrid.DataGrid.DataGridWidget, e => { widget = e; })}
40+
></devtools-data-grid-widget>
41+
`,
42+
container, {host: this});
43+
// clang-format on
44+
45+
await new Promise(resolve => setTimeout(resolve, 0));
46+
47+
assert.exists(widget);
48+
// There is a single test row
49+
assert.strictEqual(widget.dataGrid.rootNode().children.length, 1);
50+
});
51+
});

front_end/ui/legacy/components/data_grid/DataGrid.ts

Lines changed: 92 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ export class DataGridImpl<T> extends Common.ObjectWrapper.ObjectWrapper<EventTyp
228228
this.editing = false;
229229
this.selectedNode = null;
230230
this.expandNodesWhenArrowing = false;
231-
this.setRootNode((new DataGridNode() as DataGridNode<T>));
231+
this.setRootNode(new DataGridNode<T>());
232232

233233
this.setHasSelection(false);
234234

@@ -1549,9 +1549,9 @@ export class DataGridImpl<T> extends Common.ObjectWrapper.ObjectWrapper<EventTyp
15491549
return 0;
15501550
}
15511551

1552-
asWidget(): DataGridWidget<T> {
1552+
asWidget(element?: HTMLElement): DataGridWidget<T> {
15531553
if (!this.dataGridWidget) {
1554-
this.dataGridWidget = new DataGridWidget(this);
1554+
this.dataGridWidget = new DataGridWidget(this, element);
15551555
}
15561556
return this.dataGridWidget;
15571557
}
@@ -2441,9 +2441,9 @@ export class CreationDataGridNode<T> extends DataGridNode<T> {
24412441
}
24422442

24432443
export class DataGridWidget<T> extends UI.Widget.VBox {
2444-
private readonly dataGrid: DataGridImpl<T>;
2445-
constructor(dataGrid: DataGridImpl<T>) {
2446-
super();
2444+
readonly dataGrid: DataGridImpl<T>;
2445+
constructor(dataGrid: DataGridImpl<T>, element?: HTMLElement) {
2446+
super(undefined, undefined, element);
24472447
this.dataGrid = dataGrid;
24482448
this.element.appendChild(dataGrid.element);
24492449
this.setDefaultFocusedElement(dataGrid.element);
@@ -2466,6 +2466,92 @@ export class DataGridWidget<T> extends UI.Widget.VBox {
24662466
return [this.dataGrid.scrollContainer];
24672467
}
24682468
}
2469+
2470+
export interface DataGridWidgetOptions<T> {
2471+
implParams: Parameters;
2472+
dataGridImpl?: DataGridImpl<T>;
2473+
markAsRoot?: boolean;
2474+
nodes: DataGridNode<T>[];
2475+
}
2476+
2477+
export class DataGridWidgetElement<T> extends UI.Widget.WidgetElement<DataGridWidget<T>> {
2478+
#options: DataGridWidgetOptions<T>;
2479+
2480+
constructor() {
2481+
super();
2482+
// default values for options
2483+
this.#options = {
2484+
implParams: {
2485+
displayName: 'dataGrid',
2486+
columns: [],
2487+
},
2488+
nodes: [],
2489+
};
2490+
}
2491+
2492+
set options(options: DataGridWidgetOptions<T>) {
2493+
this.#options = options;
2494+
}
2495+
2496+
override createWidget(): DataGridWidget<T> {
2497+
const {
2498+
implParams,
2499+
markAsRoot,
2500+
nodes,
2501+
} = this.#options;
2502+
2503+
if (!this.#options.dataGridImpl) {
2504+
this.#options.dataGridImpl = new DataGridImpl<T>(implParams);
2505+
}
2506+
2507+
this.#options.dataGridImpl.rootNode().removeChildren();
2508+
for (const node of nodes) {
2509+
this.#options.dataGridImpl.rootNode().appendChild(node);
2510+
}
2511+
2512+
// Translate existing DataGridImpl ("ObjectWrapper") events to DOM CustomEvents so clients can
2513+
// use lit templates to bind listeners.
2514+
this.#options.dataGridImpl.addEventListener(Events.SELECTED_NODE, this.#selectedNode.bind(this));
2515+
this.#options.dataGridImpl.addEventListener(Events.DESELECTED_NODE, this.#deselectedNode.bind(this));
2516+
this.#options.dataGridImpl.addEventListener(Events.OPENED_NODE, this.#openedNode.bind(this));
2517+
this.#options.dataGridImpl.addEventListener(Events.SORTING_CHANGED, this.#sortingChanged.bind(this));
2518+
this.#options.dataGridImpl.addEventListener(Events.PADDING_CHANGED, this.#paddingChanged.bind(this));
2519+
const widget = this.#options.dataGridImpl.asWidget(this);
2520+
2521+
if (markAsRoot) {
2522+
widget.markAsRoot();
2523+
}
2524+
return widget;
2525+
}
2526+
2527+
#selectedNode(event: Common.EventTarget.EventTargetEvent<DataGridNode<T>>): void {
2528+
const domEvent = new CustomEvent('selectedNode', {detail: event.data});
2529+
this.dispatchEvent(domEvent);
2530+
}
2531+
2532+
#deselectedNode(): void {
2533+
const domEvent = new CustomEvent('deselectedNode');
2534+
this.dispatchEvent(domEvent);
2535+
}
2536+
2537+
#openedNode(event: Common.EventTarget.EventTargetEvent<DataGridNode<T>>): void {
2538+
const domEvent = new CustomEvent('openedNode', {detail: event.data});
2539+
this.dispatchEvent(domEvent);
2540+
}
2541+
2542+
#sortingChanged(): void {
2543+
const domEvent = new CustomEvent('sortingChanged');
2544+
this.dispatchEvent(domEvent);
2545+
}
2546+
2547+
#paddingChanged(): void {
2548+
const domEvent = new CustomEvent('paddingChanged');
2549+
this.dispatchEvent(domEvent);
2550+
}
2551+
}
2552+
2553+
customElements.define('devtools-data-grid-widget', DataGridWidgetElement);
2554+
24692555
export interface Parameters {
24702556
displayName: string;
24712557
columns: ColumnDescriptor[];

0 commit comments

Comments
 (0)