// Copyright 2022 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 */ /* eslint-disable @devtools/no-lit-render-outside-of-view */ import '../../../ui/kit/kit.js'; import '../../../ui/legacy/legacy.js'; import * as Common from '../../../core/common/common.js'; import * as i18n from '../../../core/i18n/i18n.js'; import * as Platform from '../../../core/platform/platform.js'; import {assertNotNullOrUndefined} from '../../../core/platform/platform.js'; import * as SDK from '../../../core/sdk/sdk.js'; import * as Protocol from '../../../generated/protocol.js'; import * as Buttons from '../../../ui/components/buttons/buttons.js'; // eslint-disable-next-line @devtools/es-modules-import import emptyWidgetStyles from '../../../ui/legacy/emptyWidget.css.js'; import * as UI from '../../../ui/legacy/legacy.js'; import {Directives, html, render} from '../../../ui/lit/lit.js'; import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js'; import * as PreloadingComponents from './components/components.js'; import {ruleSetTagOrLocationShort} from './components/PreloadingString.js'; import * as PreloadingHelper from './helper/helper.js'; import preloadingViewStyles from './preloadingView.css.js'; import preloadingViewDropDownStyles from './preloadingViewDropDown.css.js'; const {createRef, ref} = Directives; const UIStrings = { /** * @description DropDown title for filtering preloading attempts by rule set */ filterFilterByRuleSet: 'Filter by rule set', /** * @description DropDown text for filtering preloading attempts by rule set: No filter */ filterAllPreloads: 'All speculative loads', /** * @description Dropdown subtitle for filtering preloading attempts by rule set * when there are no rule sets in the page. */ noRuleSets: 'no rule sets', /** * @description Text in grid: Rule set is valid */ validityValid: 'Valid', /** * @description Text in grid: Rule set must be a valid JSON object */ validityInvalid: 'Invalid', /** * @description Text in grid: Rule set contains invalid rules and they are ignored */ validitySomeRulesInvalid: 'Some rules invalid', /** * @description Text in grid and details: Preloading attempt is not yet triggered. */ statusNotTriggered: 'Not triggered', /** * @description Text in grid and details: Preloading attempt is eligible but pending. */ statusPending: 'Pending', /** * @description Text in grid and details: Preloading is running. */ statusRunning: 'Running', /** * @description Text in grid and details: Preloading finished and the result is ready for the next navigation. */ statusReady: 'Ready', /** * @description Text in grid and details: Ready, then used. */ statusSuccess: 'Success', /** * @description Text in grid and details: Preloading failed. */ statusFailure: 'Failure', /** * @description Text to pretty print a file */ prettyPrint: 'Pretty print', /** * @description Placeholder text if there are no rules to show. https://developer.chrome.com/docs/devtools/application/debugging-speculation-rules */ noRulesDetected: 'No rules detected', /** * @description Placeholder text if there are no rules to show. https://developer.chrome.com/docs/devtools/application/debugging-speculation-rules */ rulesDescription: 'On this page you will see the speculation rules used to prefetch and prerender page navigations.', /** * @description Placeholder text if there are no speculation attempts for prefetching or prerendering urls. https://developer.chrome.com/docs/devtools/application/debugging-speculation-rules */ noPrefetchAttempts: 'No speculation detected', /** * @description Placeholder text if there are no speculation attempts for prefetching or prerendering urls. https://developer.chrome.com/docs/devtools/application/debugging-speculation-rules */ prefetchDescription: 'On this page you will see details on speculative loads.', /** * @description Text for a learn more link */ learnMore: 'Learn more', } as const; const str_ = i18n.i18n.registerUIStrings('panels/application/preloading/PreloadingView.ts', UIStrings); const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); const SPECULATION_EXPLANATION_URL = 'https://developer.chrome.com/docs/devtools/application/debugging-speculation-rules' as Platform.DevToolsPath.UrlString; // Used for selector, indicating no filter is specified. const AllRuleSetRootId = Symbol('AllRuleSetRootId'); class PreloadingUIUtils { static status(status: SDK.PreloadingModel.PreloadingStatus): string { // See content/public/browser/preloading.h PreloadingAttemptOutcome. switch (status) { case SDK.PreloadingModel.PreloadingStatus.NOT_TRIGGERED: return i18nString(UIStrings.statusNotTriggered); case SDK.PreloadingModel.PreloadingStatus.PENDING: return i18nString(UIStrings.statusPending); case SDK.PreloadingModel.PreloadingStatus.RUNNING: return i18nString(UIStrings.statusRunning); case SDK.PreloadingModel.PreloadingStatus.READY: return i18nString(UIStrings.statusReady); case SDK.PreloadingModel.PreloadingStatus.SUCCESS: return i18nString(UIStrings.statusSuccess); case SDK.PreloadingModel.PreloadingStatus.FAILURE: return i18nString(UIStrings.statusFailure); // NotSupported is used to handle unreachable case. For example, // there is no code path for // PreloadingTriggeringOutcome::kTriggeredButPending in prefetch, // which is mapped to NotSupported. So, we regard it as an // internal error. case SDK.PreloadingModel.PreloadingStatus.NOT_SUPPORTED: return i18n.i18n.lockedString('Internal error'); } } static preloadsStatusSummary(countsByStatus: Map): string { const LIST = [ SDK.PreloadingModel.PreloadingStatus.NOT_TRIGGERED, SDK.PreloadingModel.PreloadingStatus.PENDING, SDK.PreloadingModel.PreloadingStatus.RUNNING, SDK.PreloadingModel.PreloadingStatus.READY, SDK.PreloadingModel.PreloadingStatus.SUCCESS, SDK.PreloadingModel.PreloadingStatus.FAILURE, ]; return LIST.filter(status => (countsByStatus?.get(status) || 0) > 0) .map(status => (countsByStatus?.get(status) || 0) + ' ' + this.status(status)) .join(', ') .toLocaleLowerCase(); } // Summary of error of rule set shown in grid. static validity({errorType}: Protocol.Preload.RuleSet): string { switch (errorType) { case undefined: return i18nString(UIStrings.validityValid); case Protocol.Preload.RuleSetErrorType.SourceIsNotJsonObject: case Protocol.Preload.RuleSetErrorType.InvalidRulesetLevelTag: return i18nString(UIStrings.validityInvalid); case Protocol.Preload.RuleSetErrorType.InvalidRulesSkipped: return i18nString(UIStrings.validitySomeRulesInvalid); } } // Where a rule set came from, shown in grid. static location(ruleSet: Protocol.Preload.RuleSet): string { if (ruleSet.backendNodeId !== undefined) { return i18n.i18n.lockedString('