| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| /* eslint-disable @devtools/no-imperative-dom-api */ |
| |
| import * as i18n from '../../core/i18n/i18n.js'; |
| import type * as Platform from '../../core/platform/platform.js'; |
| import * as Protocol from '../../generated/protocol.js'; |
| import type * as IssuesManager from '../../models/issues_manager/issues_manager.js'; |
| |
| import {AffectedResourcesView} from './AffectedResourcesView.js'; |
| |
| const UIStrings = { |
| /** |
| * @description Label for number of affected resources indication in issue view |
| */ |
| nResources: '{n, plural, =1 {# resource} other {# resources}}', |
| /** |
| * @description Title for the 'Frame' column. |
| */ |
| frameId: 'Frame', |
| /** |
| * @description Label for the violating node link in the issue view. |
| */ |
| violatingNode: 'Violating node', |
| } as const; |
| |
| const str_ = i18n.i18n.registerUIStrings('panels/issues/GenericIssueDetailsView.ts', UIStrings); |
| const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); |
| |
| export class GenericIssueDetailsView extends AffectedResourcesView { |
| protected getResourceNameWithCount(count: number): Platform.UIString.LocalizedString { |
| return i18nString(UIStrings.nResources, {n: count}); |
| } |
| |
| #appendDetails(genericIssues: ReadonlySet<IssuesManager.GenericIssue.GenericIssue>): void { |
| const header = document.createElement('tr'); |
| |
| const sampleIssueDetails = genericIssues.values().next().value?.details(); |
| if (sampleIssueDetails?.frameId) { |
| this.appendColumnTitle(header, i18nString(UIStrings.frameId)); |
| } |
| |
| // Only some `GenericIssueDetails` have information for the 'affected |
| // resources' view. We'll count them and only call `#appendDetail` for |
| // those. `updateAffectedResourceCount` will hide the section if the |
| // count is zero. |
| this.affectedResources.appendChild(header); |
| let count = 0; |
| for (const genericIssue of genericIssues) { |
| const hasAffectedResource = genericIssue.details().frameId || genericIssue.details().violatingNodeId; |
| if (hasAffectedResource) { |
| count++; |
| void this.#appendDetail(genericIssue); |
| } |
| } |
| this.updateAffectedResourceCount(count); |
| } |
| |
| async #appendDetail(genericIssue: IssuesManager.GenericIssue.GenericIssue): Promise<void> { |
| const element = document.createElement('tr'); |
| element.classList.add('affected-resource-directive'); |
| |
| const details = genericIssue.details(); |
| if (details.frameId) { |
| element.appendChild(this.createFrameCell(details.frameId, genericIssue.getCategory())); |
| } |
| if (details.violatingNodeId) { |
| const target = genericIssue.model()?.target() || null; |
| element.appendChild(await this.createElementCell( |
| {backendNodeId: details.violatingNodeId, nodeName: this.violatingNodeIdName(details.errorType), target}, |
| genericIssue.getCategory())); |
| } |
| |
| this.affectedResources.appendChild(element); |
| } |
| |
| private violatingNodeIdName(errorType: Protocol.Audits.GenericIssueErrorType): Platform.UIString.LocalizedString { |
| switch (errorType) { |
| case Protocol.Audits.GenericIssueErrorType.FormLabelForNameError: |
| // Since the error is referencing the <label> tag, this string doesn't |
| // need to be translated. |
| return i18n.i18n.lockedString('Label'); |
| default: |
| return i18nString(UIStrings.violatingNode); |
| } |
| } |
| |
| update(): void { |
| this.clear(); |
| const issues = this.issue.getGenericIssues(); |
| if (issues.size > 0) { |
| this.#appendDetails(issues); |
| } else { |
| this.updateAffectedResourceCount(0); |
| } |
| } |
| } |