blob: ba2f0f1ff05454a5ab1600b30c778cdf12448da3 [file] [log] [blame]
Simon Zünd30152ed2021-01-21 09:18:281// Copyright 2020 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Tim van der Lippebb352e62021-04-01 17:57:285import * as i18n from '../../core/i18n/i18n.js';
Tim van der Lippee00b92f2021-03-31 16:52:176import * as SDK from '../../core/sdk/sdk.js';
Tim van der Lippec59708f2021-03-31 15:07:197import * as LitHtml from '../../third_party/lit-html/lit-html.js';
8import * as Components from '../../ui/components/components.js';
Tim van der Lippeaa61faf2021-04-07 15:32:079import * as UI from '../../ui/legacy/legacy.js';
Simon Zünd30152ed2021-01-21 09:18:2810
11import type {ResourcesPanel} from './ResourcesPanel.js';
12
13import {ApplicationPanelTreeElement} from './ApplicationPanelTreeElement.js';
14
Simon Zünd697fb0b2021-03-01 10:12:4215const UIStrings = {
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:0116 /**
17 *@description Hover text for an info icon in the Trust Token panel
18 */
19 trustTokens: 'Trust Tokens',
20 /**
21 *@description Text for the issuer of an item
22 */
23 issuer: 'Issuer',
24 /**
25 *@description Column header for Trust Token table
26 */
27 storedTokenCount: 'Stored token count',
28 /**
29 *@description Hover text for an info icon in the Trust Token panel
30 */
31 allStoredTrustTokensAvailableIn: 'All stored Trust Tokens available in this browser instance.',
Simon Zündd4ba1532021-02-10 08:35:4932 /**
33 * @description Text shown instead of a table when the table would be empty.
34 */
35 noTrustTokensStored: 'No Trust Tokens are currently stored.',
Simon Zündcf83ad82021-03-12 09:58:0036 /**
37 * @description Each row in the Trust Token table has a delete button. This is the text shown
38 * when hovering over this button. The placeholder is a normal URL, indicating the site which
39 * provided the Trust Tokens that will be deleted when the button is clicked.
40 * @example {https://google.com} PH1
41 */
42 deleteTrustTokens: 'Delete all stored Trust Tokens issued by {PH1}.',
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:0143};
Tim van der Lippec59708f2021-03-31 15:07:1944const str_ = i18n.i18n.registerUIStrings('panels/application/TrustTokensView.ts', UIStrings);
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:0145const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
Simon Zünd0a6a1a72021-02-10 06:42:0646
47/** Fetch the Trust Token data regularly from the backend while the panel is open */
48const REFRESH_INTERVAL_MS = 1000;
49
Simon Zünd30152ed2021-01-21 09:18:2850export class TrustTokensTreeElement extends ApplicationPanelTreeElement {
51 private view?: TrustTokensViewWidgetWrapper;
52
53 constructor(storagePanel: ResourcesPanel) {
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:0154 super(storagePanel, i18nString(UIStrings.trustTokens), false);
Simon Zünd30152ed2021-01-21 09:18:2855 const icon = UI.Icon.Icon.create('mediumicon-database', 'resource-tree-item');
56 this.setLeadingIcons([icon]);
57 }
58
59 get itemURL(): string {
60 return 'trustTokens://';
61 }
62
63 onselect(selectedByUser?: boolean): boolean {
64 super.onselect(selectedByUser);
65 if (!this.view) {
66 this.view = new TrustTokensViewWidgetWrapper();
67 }
68 this.showView(this.view);
69 return false;
70 }
71}
72
Simon Zünd0a6a1a72021-02-10 06:42:0673class TrustTokensViewWidgetWrapper extends UI.ThrottledWidget.ThrottledWidget {
Simon Zünd30152ed2021-01-21 09:18:2874 private readonly trustTokensView = new TrustTokensView();
75
76 constructor() {
Simon Zünd0a6a1a72021-02-10 06:42:0677 super(/* isWebComponent */ false, REFRESH_INTERVAL_MS);
Simon Zünd30152ed2021-01-21 09:18:2878 this.contentElement.appendChild(this.trustTokensView);
Simon Zünd0a6a1a72021-02-10 06:42:0679 this.update();
Simon Zünd30152ed2021-01-21 09:18:2880 }
81
Simon Zünd0a6a1a72021-02-10 06:42:0682 protected async doUpdate(): Promise<void> {
Simon Zünd30152ed2021-01-21 09:18:2883 const mainTarget = SDK.SDKModel.TargetManager.instance().mainTarget();
84 if (!mainTarget) {
85 return;
86 }
Simon Zünd30152ed2021-01-21 09:18:2887 const {tokens} = await mainTarget.storageAgent().invoke_getTrustTokens();
Simon Zündcf83ad82021-03-12 09:58:0088 this.trustTokensView.data = {
89 tokens,
90 deleteClickHandler: (issuer: string): void => {
91 mainTarget.storageAgent().invoke_clearTrustTokens({issuerOrigin: issuer});
92 },
93 };
Simon Zünd0a6a1a72021-02-10 06:42:0694
95 this.update();
Simon Zünd30152ed2021-01-21 09:18:2896 }
97}
98
99export interface TrustTokensViewData {
100 tokens: Protocol.Storage.TrustTokens[];
Simon Zündcf83ad82021-03-12 09:58:00101 deleteClickHandler: (issuerOrigin: string) => void;
Simon Zünd30152ed2021-01-21 09:18:28102}
103
104export class TrustTokensView extends HTMLElement {
105 private readonly shadow = this.attachShadow({mode: 'open'});
106 private tokens: Protocol.Storage.TrustTokens[] = [];
Simon Zündcf83ad82021-03-12 09:58:00107 private deleteClickHandler: (issuerOrigin: string) => void = () => {};
Simon Zünd30152ed2021-01-21 09:18:28108
109 connectedCallback(): void {
110 this.render();
111 }
112
113 set data(data: TrustTokensViewData) {
114 this.tokens = data.tokens;
Simon Zündcf83ad82021-03-12 09:58:00115 this.deleteClickHandler = data.deleteClickHandler;
Simon Zünd30152ed2021-01-21 09:18:28116 this.render();
117 }
118
119 private render(): void {
Simon Zündd4ba1532021-02-10 08:35:49120 LitHtml.render(
121 LitHtml.html`
122 <style>
123 :host {
124 padding: 20px;
125 }
126
127 .heading {
128 font-size: 15px;
129 }
130
131 devtools-data-grid-controller {
132 border: 1px solid var(--color-details-hairline);
133 margin-top: 20px;
134 }
135
136 .info-icon {
137 vertical-align: text-bottom;
138 height: 14px;
139 }
140
141 .no-tt-message {
142 margin-top: 20px;
143 }
144 </style>
145 <div>
146 <span class="heading">Trust Tokens</span>
147 <devtools-icon class="info-icon" title=${i18nString(UIStrings.allStoredTrustTokensAvailableIn)}
148 .data=${
149 {iconName: 'ic_info_black_18dp', color: 'var(--color-link)', width: '14px'} as
150 Components.Icon.IconWithName}>
151 </devtools-icon>
152 ${this.renderGridOrNoDataMessage()}
153 </div>
154 `,
155 this.shadow);
156 }
157
158 private renderGridOrNoDataMessage(): LitHtml.TemplateResult {
159 if (this.tokens.length === 0) {
160 return LitHtml.html`<div class="no-tt-message">${i18nString(UIStrings.noTrustTokensStored)}</div>`;
161 }
162
Simon Zünd427fbd72021-02-03 07:15:31163 const gridData: Components.DataGridController.DataGridControllerData = {
Simon Zünd30152ed2021-01-21 09:18:28164 columns: [
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01165 {
166 id: 'issuer',
167 title: i18nString(UIStrings.issuer),
Simon Zündcf83ad82021-03-12 09:58:00168 widthWeighting: 10,
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01169 hideable: false,
170 visible: true,
171 sortable: true,
172 },
173 {
174 id: 'count',
175 title: i18nString(UIStrings.storedTokenCount),
Simon Zündcf83ad82021-03-12 09:58:00176 widthWeighting: 5,
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01177 hideable: false,
178 visible: true,
179 sortable: true,
180 },
Simon Zündcf83ad82021-03-12 09:58:00181 {
182 id: 'delete-button',
183 title: '',
184 widthWeighting: 1,
185 hideable: false,
186 visible: true,
187 sortable: false,
188 },
Simon Zünd30152ed2021-01-21 09:18:28189 ],
190 rows: this.buildRowsFromTokens(),
Simon Zünd427fbd72021-02-03 07:15:31191 initialSort: {
192 columnId: 'issuer',
193 direction: Components.DataGridUtils.SortDirection.ASC,
194 },
Simon Zünd30152ed2021-01-21 09:18:28195 };
196
Simon Zündd4ba1532021-02-10 08:35:49197 return LitHtml.html`
198 <devtools-data-grid-controller .data=${
199 gridData as Components.DataGridController.DataGridControllerData}></devtools-data-grid-controller>
200 `;
Simon Zünd30152ed2021-01-21 09:18:28201 }
202
203 private buildRowsFromTokens(): Components.DataGridUtils.Row[] {
204 const tokens = this.tokens.filter(token => token.count > 0);
205 return tokens.map(token => ({
206 cells: [
Simon Zündcf83ad82021-03-12 09:58:00207 {
208 columnId: 'delete-button',
209 value: removeTrailingSlash(token.issuerOrigin),
210 renderer: this.deleteButtonRenderer.bind(this),
211 },
Simon Zünd400dcba2021-02-03 09:19:50212 {columnId: 'issuer', value: removeTrailingSlash(token.issuerOrigin)},
Simon Zünd30152ed2021-01-21 09:18:28213 {columnId: 'count', value: token.count},
214 ],
215 }));
216 }
Simon Zündcf83ad82021-03-12 09:58:00217
218 private deleteButtonRenderer(issuer: Components.DataGridUtils.CellValue): LitHtml.TemplateResult {
219 // clang-format off
220 return LitHtml.html`
221 <style>
222 .delete-button {
223 width: 16px;
224 height: 16px;
225 background: transparent;
226 overflow: hidden;
227 border: none;
228 padding: 0;
229 outline: none;
230 cursor: pointer;
231 }
232
233 .delete-button:hover devtools-icon {
234 --icon-color: var(--color-text-primary);
235 }
236
237 .delete-button:focus devtools-icon {
238 --icon-color: var(--color-text-secondary);
239 }
240
241 .button-container {
242 display: block;
243 text-align: center;
244 }
245 </style>
246 <!-- Wrap the button in a container, otherwise we can't center it inside the column. -->
247 <span class="button-container">
248 <button class="delete-button"
249 title=${i18nString(UIStrings.deleteTrustTokens, {PH1: issuer as string})}
250 @click=${(): void => this.deleteClickHandler(issuer as string)}>
251 <devtools-icon .data=${
252 {iconName: 'trash_bin_icon', color: 'var(--color-text-secondary)', width: '9px', height: '14px'} as
253 Components.Icon.IconWithName}>
254 </devtools-icon>
255 </button>
256 </span>`;
257 // clang-format on
258 }
Simon Zünd30152ed2021-01-21 09:18:28259}
260
Simon Zünd400dcba2021-02-03 09:19:50261function removeTrailingSlash(s: string): string {
262 return s.replace(/\/$/, '');
263}
264
Simon Zünd30152ed2021-01-21 09:18:28265customElements.define('devtools-trust-tokens-storage-view', TrustTokensView);
266
267declare global {
268 // eslint-disable-next-line @typescript-eslint/no-unused-vars
269 interface HTMLElementTagNameMap {
270 'devtools-trust-tokens-storage-view': TrustTokensView;
271 }
272}