UNPKG

chrome-devtools-frontend

Version:
185 lines (165 loc) • 7.19 kB
// Copyright 2020 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import '../../../ui/kit/kit.js'; import '../../../ui/legacy/components/data_grid/data_grid.js'; import * as i18n from '../../../core/i18n/i18n.js'; import * as SDK from '../../../core/sdk/sdk.js'; import type * as Protocol from '../../../generated/protocol.js'; import * as Buttons from '../../../ui/components/buttons/buttons.js'; import * as UI from '../../../ui/legacy/legacy.js'; import * as Lit from '../../../ui/lit/lit.js'; import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js'; import trustTokensViewStyles from './trustTokensView.css.js'; const PRIVATE_STATE_TOKENS_EXPLANATION_URL = 'https://developers.google.com/privacy-sandbox/protections/private-state-tokens'; const {html} = Lit; const UIStrings = { /** * @description Text for the issuer of an item */ issuer: 'Issuer', /** * @description Column header for Trust Token table */ storedTokenCount: 'Stored token count', /** * @description Hover text for an info icon in the Private State Token panel */ allStoredTrustTokensAvailableIn: 'All stored private state tokens available in this browser instance.', /** * @description Text shown instead of a table when the table would be empty. https://developers.google.com/privacy-sandbox/protections/private-state-tokens */ noTrustTokens: 'No private state tokens detected', /** * @description Text shown if there are no private state tokens. https://developers.google.com/privacy-sandbox/protections/private-state-tokens */ trustTokensDescription: 'On this page you can view all available private state tokens in the current browsing context.', /** * @description Each row in the Private State Token table has a delete button. This is the text shown * when hovering over this button. The placeholder is a normal URL, indicating the site which * provided the Private State Tokens that will be deleted when the button is clicked. * @example {https://google.com} PH1 */ deleteTrustTokens: 'Delete all stored private state tokens issued by {PH1}.', /** * @description Heading label for a view. Previously known as 'Trust Tokens'. */ trustTokens: 'Private state tokens', /** * @description Text used in a link to learn more about the topic. */ learnMore: 'Learn more', } as const; const str_ = i18n.i18n.registerUIStrings('panels/application/components/TrustTokensView.ts', UIStrings); export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); export interface TrustTokensViewInput { tokens: Protocol.Storage.TrustTokens[]; deleteClickHandler: (issuerOrigin: string) => void; } /** Fetch the Trust Token data regularly from the backend while the panel is open */ const REFRESH_INTERVAL_MS = 1000; function renderGridOrNoDataMessage(input: TrustTokensViewInput): Lit.TemplateResult { if (input.tokens.length === 0) { // clang-format off return html` <div jslog=${VisualLogging.pane('trust-tokens')}> <div class="empty-state" jslog=${VisualLogging.section().context('empty-view')}> <div class="empty-state-header">${i18nString(UIStrings.noTrustTokens)}</div> <div class="empty-state-description"> <span>${i18nString(UIStrings.trustTokensDescription)}</span> <x-link class="x-link devtools-link" href=${PRIVATE_STATE_TOKENS_EXPLANATION_URL} jslog=${VisualLogging.link() .track({ click: true, keydown: 'Enter|Space' }) .context('learn-more')} >${i18nString(UIStrings.learnMore)}</x-link> </div> </div> </div> `; // clang-format on } // clang-format off return html` <div jslog=${VisualLogging.pane('trust-tokens')}> <span class="heading">${i18nString(UIStrings.trustTokens)}</span> <devtools-icon name="info" title=${i18nString(UIStrings.allStoredTrustTokensAvailableIn)}></devtools-icon> <devtools-data-grid striped inline> <table> <tr> <th id="issuer" weight="10" sortable>${i18nString(UIStrings.issuer)}</th> <th id="count" weight="5" sortable>${i18nString(UIStrings.storedTokenCount)}</th> <th id="delete-button" weight="1" sortable></th> </tr> ${input.tokens.filter(token => token.count > 0) .map(token => html` <tr> <td>${removeTrailingSlash(token.issuerOrigin)}</td> <td>${token.count}</td> <td> <devtools-button .iconName=${'bin'} .jslogContext=${'delete-all'} .size=${Buttons.Button.Size.SMALL} .title=${i18nString(UIStrings.deleteTrustTokens, {PH1: removeTrailingSlash(token.issuerOrigin)})} .variant=${Buttons.Button.Variant.ICON} @click=${() =>input.deleteClickHandler(removeTrailingSlash(token.issuerOrigin))}></devtools-button> </td> </tr> `)} </table> </devtools-data-grid> </div> `; // clang-format on } type View = (input: TrustTokensViewInput, output: undefined, target: HTMLElement) => void; const DEFAULT_VIEW: View = (input, output, target) => { // clang-format off Lit.render(html` <style>${trustTokensViewStyles}</style> <style>${UI.inspectorCommonStyles}</style> ${renderGridOrNoDataMessage(input)} `, target); // clang-format on }; export class TrustTokensView extends UI.Widget.VBox { #updateInterval = 0; #tokens: Protocol.Storage.TrustTokens[] = []; #view: View; constructor(element?: HTMLElement, view = DEFAULT_VIEW) { super(element, {useShadowDom: true}); this.#view = view; } override wasShown(): void { super.wasShown(); this.requestUpdate(); this.#updateInterval = setInterval(this.requestUpdate.bind(this), REFRESH_INTERVAL_MS); } override willHide(): void { super.willHide(); clearInterval(this.#updateInterval); this.#updateInterval = 0; } override async performUpdate(): Promise<void> { const mainTarget = SDK.TargetManager.TargetManager.instance().primaryPageTarget(); if (!mainTarget) { return; } const {tokens} = await mainTarget.storageAgent().invoke_getTrustTokens(); tokens.sort((a, b) => a.issuerOrigin.localeCompare(b.issuerOrigin)); this.#tokens = tokens; this.#view( {tokens: this.#tokens, deleteClickHandler: this.#deleteClickHandler.bind(this)}, undefined, this.contentElement); } #deleteClickHandler(issuerOrigin: string): void { const mainTarget = SDK.TargetManager.TargetManager.instance().primaryPageTarget(); void mainTarget?.storageAgent().invoke_clearTrustTokens({issuerOrigin}); } } function removeTrailingSlash(s: string): string { return s.replace(/\/$/, ''); }