debug-server-next
Version:
Dev server for hippy-core.
323 lines (322 loc) • 14.7 kB
JavaScript
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as Common from '../../core/common/common.js';
import * as i18n from '../../core/i18n/i18n.js';
import * as IssuesManager from '../../models/issues_manager/issues_manager.js';
import * as IssueCounter from '../../ui/components/issue_counter/issue_counter.js';
import * as UI from '../../ui/legacy/legacy.js';
import { IssueAggregator } from './IssueAggregator.js';
import { IssueView } from './IssueView.js';
const UIStrings = {
/**
* @description Category title for a group of cross origin embedder policy (COEP) issues
*/
crossOriginEmbedderPolicy: 'Cross Origin Embedder Policy',
/**
* @description Category title for a group of mixed content issues
*/
mixedContent: 'Mixed Content',
/**
* @description Category title for a group of SameSite cookie issues
*/
samesiteCookie: 'SameSite Cookie',
/**
* @description Category title for a group of heavy ads issues
*/
heavyAds: 'Heavy Ads',
/**
* @description Category title for a group of content security policy (CSP) issues
*/
contentSecurityPolicy: 'Content Security Policy',
/**
* @description Category title for a group of trusted web activity issues
*/
trustedWebActivity: 'Trusted Web Activity',
/**
* @description Text for other types of items
*/
other: 'Other',
/**
* @description Category title for the different 'low text contrast' issues. Low text contrast refers
* to the difference between the color of a text and the background color where that text
* appears.
*/
lowTextContrast: 'Low Text Contrast',
/**
* @description Category title for the different 'Cross-Origin Resource Sharing' (CORS) issues. CORS
* refers to one origin (e.g 'a.com') loading resources from another origin (e.g. 'b.com').
*/
cors: 'Cross Origin Resource Sharing',
/**
* @description Title for a checkbox which toggles grouping by category in the issues tab
*/
groupDisplayedIssuesUnder: 'Group displayed issues under associated categories',
/**
* @description Label for a checkbox which toggles grouping by category in the issues tab
*/
groupByCategory: 'Group by category',
/**
* @description Title for a checkbox. Whether the issues tab should include third-party issues or not.
*/
includeCookieIssuesCausedBy: 'Include cookie Issues caused by third-party sites',
/**
* @description Label for a checkbox. Whether the issues tab should include third-party issues or not.
*/
includeThirdpartyCookieIssues: 'Include third-party cookie issues',
/**
* @description Label on the issues tab
*/
onlyThirdpartyCookieIssues: 'Only third-party cookie issues detected so far',
/**
* @description Label in the issues panel
*/
noIssuesDetectedSoFar: 'No issues detected so far',
/**
* @description Category title for the different 'Attribution Reporting API' issues. The
* Attribution Reporting API is a newly proposed web API (see https://github.com/WICG/conversion-measurement-api).
*/
attributionReporting: 'Attribution Reporting `API`',
/**
* @description Category title for the different 'Quirks Mode' issues. Quirks Mode refers
* to the legacy browser modes that displays web content according to outdated
* browser behaviors.
*/
quirksMode: 'Quirks Mode',
};
const str_ = i18n.i18n.registerUIStrings('panels/issues/IssuesPane.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
class IssueCategoryView extends UI.TreeOutline.TreeElement {
category;
issues;
constructor(category) {
super();
this.category = category;
this.issues = [];
this.toggleOnClick = true;
this.listItemElement.classList.add('issue-category');
}
getCategoryName() {
switch (this.category) {
case IssuesManager.Issue.IssueCategory.CrossOriginEmbedderPolicy:
return i18nString(UIStrings.crossOriginEmbedderPolicy);
case IssuesManager.Issue.IssueCategory.MixedContent:
return i18nString(UIStrings.mixedContent);
case IssuesManager.Issue.IssueCategory.SameSiteCookie:
return i18nString(UIStrings.samesiteCookie);
case IssuesManager.Issue.IssueCategory.HeavyAd:
return i18nString(UIStrings.heavyAds);
case IssuesManager.Issue.IssueCategory.ContentSecurityPolicy:
return i18nString(UIStrings.contentSecurityPolicy);
case IssuesManager.Issue.IssueCategory.TrustedWebActivity:
return i18nString(UIStrings.trustedWebActivity);
case IssuesManager.Issue.IssueCategory.LowTextContrast:
return i18nString(UIStrings.lowTextContrast);
case IssuesManager.Issue.IssueCategory.Cors:
return i18nString(UIStrings.cors);
case IssuesManager.Issue.IssueCategory.AttributionReporting:
return i18nString(UIStrings.attributionReporting);
case IssuesManager.Issue.IssueCategory.QuirksMode:
return i18nString(UIStrings.quirksMode);
case IssuesManager.Issue.IssueCategory.Other:
return i18nString(UIStrings.other);
}
}
onattach() {
this.appendHeader();
}
appendHeader() {
const header = document.createElement('div');
header.classList.add('header');
const title = document.createElement('div');
title.classList.add('title');
title.textContent = this.getCategoryName();
header.appendChild(title);
this.listItemElement.appendChild(header);
}
}
export function getGroupIssuesByCategorySetting() {
return Common.Settings.Settings.instance().createSetting('groupIssuesByCategory', false);
}
let issuesPaneInstance;
export class IssuesPane extends UI.Widget.VBox {
categoryViews;
issueViews;
showThirdPartyCheckbox;
issuesTree;
noIssuesMessageDiv;
issuesManager;
aggregator;
issueViewUpdatePromise = Promise.resolve();
constructor() {
super(true);
this.registerRequiredCSS('panels/issues/issuesPane.css');
this.contentElement.classList.add('issues-pane');
this.categoryViews = new Map();
this.issueViews = new Map();
this.showThirdPartyCheckbox = null;
this.createToolbars();
this.issuesTree = new UI.TreeOutline.TreeOutlineInShadow();
this.issuesTree.registerRequiredCSS('panels/issues/issuesTree.css');
this.issuesTree.setShowSelectionOnKeyboardFocus(true);
this.issuesTree.contentElement.classList.add('issues');
this.contentElement.appendChild(this.issuesTree.element);
this.noIssuesMessageDiv = document.createElement('div');
this.noIssuesMessageDiv.classList.add('issues-pane-no-issues');
this.contentElement.appendChild(this.noIssuesMessageDiv);
this.issuesManager = IssuesManager.IssuesManager.IssuesManager.instance();
this.aggregator = new IssueAggregator(this.issuesManager);
this.aggregator.addEventListener("AggregatedIssueUpdated" /* AggregatedIssueUpdated */, this.issueUpdated, this);
this.aggregator.addEventListener("FullUpdateRequired" /* FullUpdateRequired */, this.onFullUpdate, this);
for (const issue of this.aggregator.aggregatedIssues()) {
this.scheduleIssueViewUpdate(issue);
}
this.issuesManager.addEventListener("IssuesCountUpdated" /* IssuesCountUpdated */, this.updateCounts, this);
this.updateCounts();
}
static instance(opts = { forceNew: null }) {
const { forceNew } = opts;
if (!issuesPaneInstance || forceNew) {
issuesPaneInstance = new IssuesPane();
}
return issuesPaneInstance;
}
elementsToRestoreScrollPositionsFor() {
return [this.issuesTree.element];
}
createToolbars() {
const toolbarContainer = this.contentElement.createChild('div', 'issues-toolbar-container');
new UI.Toolbar.Toolbar('issues-toolbar-left', toolbarContainer);
const rightToolbar = new UI.Toolbar.Toolbar('issues-toolbar-right', toolbarContainer);
const groupByCategorySetting = getGroupIssuesByCategorySetting();
const groupByCategoryCheckbox = new UI.Toolbar.ToolbarSettingCheckbox(groupByCategorySetting, i18nString(UIStrings.groupDisplayedIssuesUnder), i18nString(UIStrings.groupByCategory));
// Hide the option to toggle category grouping for now.
groupByCategoryCheckbox.setVisible(false);
rightToolbar.appendToolbarItem(groupByCategoryCheckbox);
groupByCategorySetting.addChangeListener(() => {
this.fullUpdate(true);
});
const thirdPartySetting = IssuesManager.Issue.getShowThirdPartyIssuesSetting();
this.showThirdPartyCheckbox = new UI.Toolbar.ToolbarSettingCheckbox(thirdPartySetting, i18nString(UIStrings.includeCookieIssuesCausedBy), i18nString(UIStrings.includeThirdpartyCookieIssues));
rightToolbar.appendToolbarItem(this.showThirdPartyCheckbox);
this.setDefaultFocusedElement(this.showThirdPartyCheckbox.inputElement);
rightToolbar.appendSeparator();
const issueCounter = new IssueCounter.IssueCounter.IssueCounter();
issueCounter.data = {
tooltipCallback: () => {
const issueEnumeration = IssueCounter.IssueCounter.getIssueCountsEnumeration(IssuesManager.IssuesManager.IssuesManager.instance(), false);
UI.Tooltip.Tooltip.install(issueCounter, issueEnumeration);
},
displayMode: "ShowAlways" /* ShowAlways */,
issuesManager: IssuesManager.IssuesManager.IssuesManager.instance(),
};
issueCounter.id = 'console-issues-counter';
const issuesToolbarItem = new UI.Toolbar.ToolbarItem(issueCounter);
rightToolbar.appendToolbarItem(issuesToolbarItem);
return { toolbarContainer };
}
issueUpdated(event) {
this.scheduleIssueViewUpdate(event.data);
}
scheduleIssueViewUpdate(issue) {
this.issueViewUpdatePromise = this.issueViewUpdatePromise.then(() => this.updateIssueView(issue));
}
/** Don't call directly. Use `scheduleIssueViewUpdate` instead. */
async updateIssueView(issue) {
let issueView = this.issueViews.get(issue.code());
if (!issueView) {
const description = issue.getDescription();
if (!description) {
console.warn('Could not find description for issue code:', issue.code());
return;
}
const markdownDescription = await IssuesManager.MarkdownIssueDescription.createIssueDescriptionFromMarkdown(description);
issueView = new IssueView(this, issue, markdownDescription);
this.issueViews.set(issue.code(), issueView);
const parent = this.getIssueViewParent(issue);
parent.appendChild(issueView, (a, b) => {
if (a instanceof IssueView && b instanceof IssueView) {
return a.getIssueTitle().localeCompare(b.getIssueTitle());
}
console.error('The issues tree should only contain IssueView objects as direct children');
return 0;
});
}
issueView.update();
this.updateCounts();
}
getIssueViewParent(issue) {
if (!getGroupIssuesByCategorySetting().get()) {
return this.issuesTree;
}
const category = issue.getCategory();
const view = this.categoryViews.get(category);
if (view) {
return view;
}
const newView = new IssueCategoryView(category);
this.issuesTree.appendChild(newView, (a, b) => {
if (a instanceof IssueCategoryView && b instanceof IssueCategoryView) {
return a.getCategoryName().localeCompare(b.getCategoryName());
}
return 0;
});
this.categoryViews.set(category, newView);
return newView;
}
clearViews(views, preservedSet) {
for (const [key, view] of Array.from(views.entries())) {
if (preservedSet?.has(key)) {
continue;
}
view.parent && view.parent.removeChild(view);
views.delete(key);
}
}
onFullUpdate() {
this.fullUpdate(false);
}
fullUpdate(force) {
this.clearViews(this.categoryViews, force ? undefined : this.aggregator.aggregatedIssueCategories());
this.clearViews(this.issueViews, force ? undefined : this.aggregator.aggregatedIssueCodes());
if (this.aggregator) {
for (const issue of this.aggregator.aggregatedIssues()) {
this.scheduleIssueViewUpdate(issue);
}
}
this.updateCounts();
}
updateCounts() {
this.showIssuesTreeOrNoIssuesDetectedMessage(this.issuesManager.numberOfIssues());
}
showIssuesTreeOrNoIssuesDetectedMessage(issuesCount) {
if (issuesCount > 0) {
this.issuesTree.element.hidden = false;
this.noIssuesMessageDiv.style.display = 'none';
const firstChild = this.issuesTree.firstChild();
if (firstChild) {
firstChild.select(/* omitFocus= */ true);
this.setDefaultFocusedElement(firstChild.listItemElement);
}
}
else {
this.issuesTree.element.hidden = true;
if (this.showThirdPartyCheckbox) {
this.setDefaultFocusedElement(this.showThirdPartyCheckbox.inputElement);
}
// We alreay know that issesCount is zero here.
const hasOnlyThirdPartyIssues = this.issuesManager.numberOfAllStoredIssues() > 0;
this.noIssuesMessageDiv.textContent = hasOnlyThirdPartyIssues ? i18nString(UIStrings.onlyThirdpartyCookieIssues) :
i18nString(UIStrings.noIssuesDetectedSoFar);
this.noIssuesMessageDiv.style.display = 'flex';
}
}
revealByCode(code) {
const issueView = this.issueViews.get(code);
if (issueView) {
issueView.expand();
issueView.reveal();
issueView.select(false, true);
}
}
}