Skip to content

Commit 0339e4b

Browse files
danilsomsikovDevtools-frontend LUCI CQ
authored andcommitted
Adopt UI eng vision in the OriginTrialTokenRows
Bug: 407750554 Change-Id: I68a8223ce328ebe90ff6ee117364a375a85dde41 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/7106141 Reviewed-by: Jack Franklin <[email protected]> Auto-Submit: Danil Somsikov <[email protected]> Commit-Queue: Danil Somsikov <[email protected]>
1 parent 93bd5da commit 0339e4b

File tree

3 files changed

+77
-80
lines changed

3 files changed

+77
-80
lines changed

front_end/panels/application/components/OriginTrialTreeView.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ import {
77
renderElementIntoDOM,
88
} from '../../../testing/DOMHelpers.js';
99
import {describeWithLocale} from '../../../testing/LocaleHelpers.js';
10-
import * as RenderCoordinator from '../../../ui/components/render_coordinator/render_coordinator.js';
11-
import type * as UI from '../../../ui/legacy/legacy.js';
10+
import * as UI from '../../../ui/legacy/legacy.js';
1211

1312
import * as ApplicationComponents from './components.js';
1413

@@ -19,7 +18,6 @@ async function renderOriginTrialTreeView(
1918
component.data = data;
2019
renderElementIntoDOM(component);
2120
await component.updateComplete;
22-
await RenderCoordinator.done();
2321
return component;
2422
}
2523

@@ -257,7 +255,8 @@ describeWithLocale('OriginTrialTreeView', () => {
257255
}
258256
assert.lengthOf(tokenDetailNodes, 2);
259257
const tokenFieldsNode = tokenDetailNodes[0];
260-
const rowsComponent = tokenFieldsNode.nodeElement.querySelector('devtools-resources-origin-trial-token-rows');
258+
const rowsComponent = tokenFieldsNode.nodeElement.querySelector('devtools-widget');
259+
await UI.Widget.Widget.get(rowsComponent!)!.updateComplete;
261260
const {innerHTML} = rowsComponent!.shadowRoot!;
262261
const parsedToken = trialWithSingleToken.tokensWithStatus[0].parsedToken;
263262
assert.exists(parsedToken);
@@ -409,7 +408,8 @@ describeWithLocale('OriginTrialTreeView', () => {
409408
}
410409
assert.lengthOf(tokenDetailNodes, 2);
411410
const tokenFieldsNode = tokenDetailNodes[0];
412-
const rowsComponent = tokenFieldsNode.nodeElement.querySelector('devtools-resources-origin-trial-token-rows');
411+
const rowsComponent = tokenFieldsNode.nodeElement.querySelector('devtools-widget');
412+
await UI.Widget.Widget.get(rowsComponent!)!.updateComplete;
413413
const {innerHTML} = rowsComponent!.shadowRoot!;
414414

415415
assert.include(innerHTML, unknownTrialName);

front_end/panels/application/components/OriginTrialTreeView.ts

Lines changed: 66 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
/* eslint-disable @devtools/no-lit-render-outside-of-view */
6-
75
import '../../../ui/components/icon_button/icon_button.js';
86
import '../../../ui/legacy/legacy.js';
97
import '../../../ui/components/adorners/adorners.js';
@@ -17,7 +15,8 @@ import {Directives, html, type LitTemplate, nothing, render, type TemplateResult
1715
import originTrialTokenRowsStyles from './originTrialTokenRows.css.js';
1816
import originTrialTreeViewStyles from './originTrialTreeView.css.js';
1917

20-
const {ifDefined} = Directives;
18+
const {classMap} = Directives;
19+
const {widgetConfig} = UI.Widget;
2120

2221
const UIStrings = {
2322
/**
@@ -126,14 +125,14 @@ function renderTokenNode(token: Protocol.Page.OriginTrialTokenWithStatus): LitTe
126125

127126
interface TokenField {
128127
name: string;
129-
value: TemplateResult;
128+
value: {text: string, hasError?: boolean};
130129
}
131130

132131
function renderTokenDetails(token: Protocol.Page.OriginTrialTokenWithStatus): TemplateResult {
133132
return html`
134133
<li role="treeitem">
135-
<devtools-resources-origin-trial-token-rows .data=${token}>
136-
</devtools-resources-origin-trial-token-rows>
134+
<devtools-widget .widgetConfig=${widgetConfig(OriginTrialTokenRows, {data: token})}>
135+
</devtools-widget>
137136
</li>`;
138137
}
139138

@@ -167,119 +166,121 @@ export interface OriginTrialTokenRowsData {
167166
node: TreeNode<OriginTrialTreeNodeData>;
168167
}
169168

170-
export class OriginTrialTokenRows extends HTMLElement {
171-
readonly #shadow = this.attachShadow({mode: 'open'});
169+
interface RowsViewInput {
170+
tokenWithStatus: Protocol.Page.OriginTrialTokenWithStatus;
171+
parsedTokenDetails: TokenField[];
172+
}
173+
174+
type RowsView = (input: RowsViewInput, output: undefined, target: HTMLElement) => void;
175+
176+
const ROWS_DEFAULT_VIEW: RowsView = (input, _output, target) => {
177+
const success = input.tokenWithStatus.status === Protocol.Page.OriginTrialTokenStatus.Success;
178+
// clang-format off
179+
render(html`
180+
<style>
181+
${originTrialTokenRowsStyles}
182+
${originTrialTreeViewStyles}
183+
</style>
184+
<div class="content">
185+
<div class="key">${i18nString(UIStrings.status)}</div>
186+
<div class="value">
187+
<devtools-adorner class="badge-${success ? 'success' : 'error'}">
188+
${input.tokenWithStatus.status}
189+
</devtools-adorner>
190+
</div>
191+
${input.parsedTokenDetails.map((field: TokenField) => html`
192+
<div class="key">${field.name}</div>
193+
<div class="value">
194+
<div class=${classMap({'error-text': Boolean(field.value.hasError)})}>
195+
${field.value.text}
196+
</div>
197+
</div>
198+
`)}
199+
</div>`, target);
200+
// clang-format on
201+
};
202+
203+
export class OriginTrialTokenRows extends UI.Widget.Widget {
204+
#view: RowsView;
172205
#tokenWithStatus: Protocol.Page.OriginTrialTokenWithStatus|null = null;
173206
#parsedTokenDetails: TokenField[] = [];
174207
#dateFormatter: Intl.DateTimeFormat = new Intl.DateTimeFormat(
175208
i18n.DevToolsLocale.DevToolsLocale.instance().locale,
176209
{dateStyle: 'long', timeStyle: 'long'},
177210
);
178211

212+
constructor(element?: HTMLElement, view: RowsView = ROWS_DEFAULT_VIEW) {
213+
super(element, {useShadowDom: true});
214+
this.#view = view;
215+
}
216+
179217
set data(data: Protocol.Page.OriginTrialTokenWithStatus) {
180218
this.#tokenWithStatus = data;
181219
this.#setTokenFields();
182220
}
183221

184222
connectedCallback(): void {
185-
this.#render();
186-
}
187-
188-
override cloneNode(): HTMLElement {
189-
const clone = UI.UIUtils.cloneCustomElement(this);
190-
if (this.#tokenWithStatus) {
191-
clone.data = this.#tokenWithStatus;
192-
}
193-
return clone;
223+
this.requestUpdate();
194224
}
195225

196-
#renderTokenField = (fieldValue: string, hasError?: boolean): TemplateResult => html`
197-
<div class=${ifDefined(hasError ? 'error-text' : undefined)}>
198-
${fieldValue}
199-
</div>`;
200-
201226
#setTokenFields(): void {
202227
if (!this.#tokenWithStatus?.parsedToken) {
203228
return;
204229
}
205230
this.#parsedTokenDetails = [
206231
{
207232
name: i18nString(UIStrings.origin),
208-
value: this.#renderTokenField(
209-
this.#tokenWithStatus.parsedToken.origin,
210-
this.#tokenWithStatus.status === Protocol.Page.OriginTrialTokenStatus.WrongOrigin),
233+
value: {
234+
text: this.#tokenWithStatus.parsedToken.origin,
235+
hasError: this.#tokenWithStatus.status === Protocol.Page.OriginTrialTokenStatus.WrongOrigin,
236+
},
211237
},
212238
{
213239
name: i18nString(UIStrings.expiryTime),
214-
value: this.#renderTokenField(
215-
this.#dateFormatter.format(this.#tokenWithStatus.parsedToken.expiryTime * 1000),
216-
this.#tokenWithStatus.status === Protocol.Page.OriginTrialTokenStatus.Expired),
240+
value: {
241+
text: this.#dateFormatter.format(this.#tokenWithStatus.parsedToken.expiryTime * 1000),
242+
hasError: this.#tokenWithStatus.status === Protocol.Page.OriginTrialTokenStatus.Expired
243+
},
217244
},
218245
{
219246
name: i18nString(UIStrings.usageRestriction),
220-
value: this.#renderTokenField(this.#tokenWithStatus.parsedToken.usageRestriction),
247+
value: {text: this.#tokenWithStatus.parsedToken.usageRestriction},
221248
},
222249
{
223250
name: i18nString(UIStrings.isThirdParty),
224-
value: this.#renderTokenField(this.#tokenWithStatus.parsedToken.isThirdParty.toString()),
251+
value: {text: this.#tokenWithStatus.parsedToken.isThirdParty.toString()},
225252
},
226253
{
227254
name: i18nString(UIStrings.matchSubDomains),
228-
value: this.#renderTokenField(this.#tokenWithStatus.parsedToken.matchSubDomains.toString()),
255+
value: {text: this.#tokenWithStatus.parsedToken.matchSubDomains.toString()},
229256
},
230257
];
231258

232259
if (this.#tokenWithStatus.status === Protocol.Page.OriginTrialTokenStatus.UnknownTrial) {
233260
this.#parsedTokenDetails = [
234261
{
235262
name: i18nString(UIStrings.trialName),
236-
value: this.#renderTokenField(this.#tokenWithStatus.parsedToken.trialName),
263+
value: {text: this.#tokenWithStatus.parsedToken.trialName},
237264
},
238265
...this.#parsedTokenDetails,
239266
];
240267
}
268+
this.requestUpdate();
241269
}
242270

243-
#render(): void {
271+
override performUpdate(): void {
244272
if (!this.#tokenWithStatus) {
245273
return;
246274
}
247275

248-
const success = this.#tokenWithStatus.status === Protocol.Page.OriginTrialTokenStatus.Success;
249-
const tokenDetails: TokenField[] = [
250-
{
251-
name: i18nString(UIStrings.status),
252-
value: html`
253-
<devtools-adorner class="badge-${success ? 'success' : 'error'}">
254-
${this.#tokenWithStatus.status}
255-
</devtools-adorner>`,
256-
},
257-
...this.#parsedTokenDetails,
258-
];
259-
260-
const tokenDetailRows = tokenDetails.map((field: TokenField) => {
261-
return html`
262-
<div class="key">${field.name}</div>
263-
<div class="value">${field.value}</div>
264-
`;
265-
});
266-
267-
render(
268-
html`
269-
<style>
270-
${originTrialTokenRowsStyles}
271-
${originTrialTreeViewStyles}
272-
</style>
273-
<div class="content">
274-
${tokenDetailRows}
275-
</div>
276-
`,
277-
this.#shadow, {host: this});
276+
const viewInput: RowsViewInput = {
277+
tokenWithStatus: this.#tokenWithStatus,
278+
parsedTokenDetails: this.#parsedTokenDetails,
279+
};
280+
this.#view(viewInput, undefined, this.contentElement);
278281
}
279282
}
280283

281-
customElements.define('devtools-resources-origin-trial-token-rows', OriginTrialTokenRows);
282-
283284
export interface OriginTrialTreeViewData {
284285
trials: Protocol.Page.OriginTrial[];
285286
}
@@ -330,9 +331,3 @@ export class OriginTrialTreeView extends UI.Widget.Widget {
330331
this.#view(this.#data, undefined, this.contentElement);
331332
}
332333
}
333-
334-
declare global {
335-
interface HTMLElementTagNameMap {
336-
'devtools-resources-origin-trial-token-rows': OriginTrialTokenRows;
337-
}
338-
}

front_end/ui/legacy/Widget.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import * as Platform from '../../core/platform/platform.js';
3535
import * as Geometry from '../../models/geometry/geometry.js';
3636
import * as Lit from '../../ui/lit/lit.js';
3737

38-
import {createShadowRootWithCoreStyles} from './UIUtils.js';
38+
import {cloneCustomElement, createShadowRootWithCoreStyles} from './UIUtils.js';
3939

4040
// Remember the original DOM mutation methods here, since we
4141
// will override them below to sanity check the Widget system.
@@ -227,12 +227,14 @@ export class WidgetElement<WidgetT extends Widget> extends HTMLElement {
227227
}
228228

229229
override cloneNode(deep: boolean): Node {
230-
const clone = super.cloneNode(deep) as WidgetElement<WidgetT>;
230+
const clone = cloneCustomElement(this, deep);
231231
if (!this.#widgetClass) {
232232
throw new Error('No widgetClass defined');
233233
}
234-
clone.#widgetClass = this.#widgetClass;
235-
clone.#widgetParams = this.#widgetParams;
234+
clone.widgetConfig = {
235+
widgetClass: this.#widgetClass,
236+
widgetParams: this.#widgetParams,
237+
};
236238
return clone;
237239
}
238240
}

0 commit comments

Comments
 (0)