chrome-devtools-frontend
Version:
Chrome DevTools UI
119 lines (106 loc) • 4.66 kB
text/typescript
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as i18n from '../../core/i18n/i18n.js';
import type * as Platform from '../../core/platform/platform.js';
import type * as SDK from '../../core/sdk/sdk.js';
import type * as Protocol from '../../generated/protocol.js';
import * as Bindings from '../../models/bindings/bindings.js';
import type * as IssuesManager from '../../models/issues_manager/issues_manager.js';
import * as Components from '../../ui/legacy/components/utils/utils.js';
import * as UI from '../../ui/legacy/legacy.js';
import {Directives, html, type LitTemplate, nothing, render} from '../../ui/lit/lit.js';
import {AffectedResourcesView} from './AffectedResourcesView.js';
const UIStrings = {
/**
* @description Label for number of affected resources indication in issue view
*/
nViolations: '{n, plural, =1 {# violation} other {# violations}}',
/**
* @description Title for the API column in the Selective Permissions Intervention affected resources list
*/
api: 'API',
/**
* @description Title for the Script column in the Selective Permissions Intervention affected resources list
*/
script: 'Script',
/**
* @description Title for the Ad Ancestry column in the Selective Permissions Intervention affected resources list
*/
adAncestry: 'Ad Ancestry',
/**
* @description Text for unknown value
*/
unknown: 'unknown',
/**
* @description Text for loading state
*/
loading: 'loading…',
} as const;
const str_ = i18n.i18n.registerUIStrings('panels/issues/AffectedSelectivePermissionsInterventionView.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
const {widget} = UI.Widget;
export class AffectedSelectivePermissionsInterventionView extends AffectedResourcesView {
readonly #linkifier = new Components.Linkifier.Linkifier();
protected getResourceNameWithCount(count: number): string {
return i18nString(UIStrings.nViolations, {n: count});
}
#render(): void {
const issues = Array.from(this.issue.getSelectivePermissionsInterventionIssues());
// eslint-disable-next-line @devtools/no-lit-render-outside-of-view
render(
html`
<tr>
<td class="affected-resource-header">${i18nString(UIStrings.api)}</td>
<td class="affected-resource-header">${i18nString(UIStrings.script)}</td>
<td class="affected-resource-header">${i18nString(UIStrings.adAncestry)}</td>
</tr>
${issues.map(issue => this.#renderDetail(issue))}
`,
this.affectedResources, {host: this});
this.updateAffectedResourceCount(issues.length);
}
#renderDetail(issue: IssuesManager.SelectivePermissionsInterventionIssue.SelectivePermissionsInterventionIssue):
LitTemplate {
const details = issue.details();
const issuesModel = issue.model();
const stackTracePromise = (details.stackTrace && issuesModel) ?
this.#resolveStackTrace(details.stackTrace, issuesModel) :
Promise.resolve(html`<span>${i18nString(UIStrings.unknown)}</span>`);
const target = issuesModel ? issuesModel.target() : null;
return html`
<tr class="affected-resource-directive">
<td>${details.apiName}</td>
<td>${Directives.until(stackTracePromise, html`<span>${i18nString(UIStrings.loading)}</span>`)}</td>
<td class="affected-resource-cell">
<div class="ad-ancestry-list">
${(details.adAncestry?.ancestryChain || []).map(script => {
const link =
this.#linkifier.linkifyScriptLocation(target, script.scriptId, '' as Platform.DevToolsPath.UrlString, 0);
return html`<div>${link}</div>`;
})}
${
details.adAncestry?.rootScriptFilterlistRule ?
html`<div>Rule: ${details.adAncestry.rootScriptFilterlistRule}</div>` :
nothing}
</div>
</td>
</tr>
`;
}
async #resolveStackTrace(stackTrace: Protocol.Runtime.StackTrace, issuesModel: SDK.IssuesModel.IssuesModel):
Promise<LitTemplate> {
const debuggerWorkspaceBinding = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance();
const stackTraceTranslated =
await debuggerWorkspaceBinding.createStackTraceFromProtocolRuntime(stackTrace, issuesModel.target());
return html`${widget(Components.JSPresentationUtils.StackTracePreviewContent, {
stackTrace: stackTraceTranslated,
options: {expandable: true},
})}`;
}
update(): void {
this.requestResolver.clear();
this.#linkifier.reset();
this.#render();
}
}