chrome-devtools-frontend
Version:
Chrome DevTools UI
191 lines (175 loc) • 7.43 kB
text/typescript
// 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.
import '../../../ui/legacy/components/data_grid/data_grid.js';
import * as i18n from '../../../core/i18n/i18n.js';
import type * as Protocol from '../../../generated/protocol.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 sharedStorageAccessGridStyles from './sharedStorageAccessGrid.css.js';
const SHARED_STORAGE_EXPLANATION_URL =
'https://developers.google.com/privacy-sandbox/private-advertising/shared-storage';
const {render, html} = Lit;
const UIStrings = {
/**
* @description Text in Shared Storage Events View of the Application panel
*/
sharedStorage: 'Shared storage',
/**
* @description Hover text for an info icon in the Shared Storage Events panel
*/
allSharedStorageEvents: 'All shared storage events for this page.',
/**
* @description Text in Shared Storage Events View of the Application panel
* Date and time of an Shared Storage event in a locale-
* dependent format.
*/
eventTime: 'Event Time',
/**
* @description Text in Shared Storage Events View of the Application panel
* Scope of shared storage event such as 'window', 'sharedStorageWorklet',
* 'protectedAudienceWorklet', or 'header'.
*/
eventScope: 'Access Scope',
/**
* @description Text in Shared Storage Events View of the Application panel
* Method of shared storage event such as 'addModule', 'run', 'set', 'delete',
* or 'get'.
*/
eventMethod: 'Access Method',
/**
* @description Text in Shared Storage Events View of the Application panel
* Owner origin of the shared storage for this access event.
*/
ownerOrigin: 'Owner Origin',
/**
* @description Text in Shared Storage Events View of the Application panel
* Owner site of the shared storage for this access event.
*/
ownerSite: 'Owner Site',
/**
* @description Text in Shared Storage Events View of the Application panel
* Event parameters whose presence/absence depend on the access type.
*/
eventParams: 'Optional Event Params',
/**
* @description Text shown when no shared storage event is shown.
* Shared storage allows to store and access data that can be shared across different sites.
* A shared storage event is for example an access from a site to that storage.
*/
noEvents: 'No shared storage events detected',
/**
* @description Text shown when no shared storage event is shown. It explains the shared storage event page.
* Shared storage allows to store and access data that can be shared across different sites.
* A shared storage event is for example an access from a site to that storage.
*/
sharedStorageDescription:
'On this page you can view, add, edit and delete shared storage key-value pairs and view shared storage events.',
/**
* @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/SharedStorageAccessGrid.ts', UIStrings);
export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
export interface ViewInput {
events: Protocol.Storage.SharedStorageAccessedEvent[];
onSelect: (event: Protocol.Storage.SharedStorageAccessedEvent) => void;
}
export type View = (input: ViewInput, output: object, target: HTMLElement) => void;
export const DEFAULT_VIEW: View = (input, _output, target) => {
// clang-format off
render(html`
<style>${sharedStorageAccessGridStyles}</style>
${input.events.length === 0
? html`
<div class="empty-state" jslog=${VisualLogging.section().context('empty-view')}>
<div class="empty-state-header">${i18nString(UIStrings.noEvents)}</div>
<div class="empty-state-description">
<span>${i18nString(UIStrings.sharedStorageDescription)}</span>
<x-link
class="x-link devtools-link"
href=${SHARED_STORAGE_EXPLANATION_URL}
jslog=${VisualLogging.link().track({click: true, keydown: 'Enter|Space'}).context('learn-more')}
>${i18nString(UIStrings.learnMore)}</x-link>
</div>
</div>`
: html`
<div jslog=${VisualLogging.section('events-table')}>
<span class="heading">${i18nString(UIStrings.sharedStorage)}</span>
<devtools-icon class="info-icon medium" name="info"
title=${i18nString(UIStrings.allSharedStorageEvents)}>
</devtools-icon>
<devtools-data-grid striped inline>
<table>
<thead>
<tr>
<th id="event-time" weight="10" sortable>
${i18nString(UIStrings.eventTime)}
</th>
<th id="event-scope" weight="10" sortable>
${i18nString(UIStrings.eventScope)}
</th>
<th id="event-method" weight="10" sortable>
${i18nString(UIStrings.eventMethod)}
</th>
<th id="event-owner-origin" weight="10" sortable>
${i18nString(UIStrings.ownerOrigin)}
</th>
<th id="event-owner-site" weight="10" sortable>
${i18nString(UIStrings.ownerSite)}
</th>
<th id="event-params" weight="10" sortable>
${i18nString(UIStrings.eventParams)}
</th>
</tr>
</thead>
<tbody>
${input.events.map(event => html`
<tr @select=${() =>input.onSelect(event)}>
<td data-value=${event.accessTime}>
${new Date(1e3 * event.accessTime).toLocaleString()}
</td>
<td>${event.scope}</td>
<td>${event.method}</td>
<td>${event.ownerOrigin}</td>
<td>${event.ownerSite}</td>
<td>${JSON.stringify(event.params)}</td>
</tr>
`)}
</tbody>
</table>
</devtools-data-grid>
</div>`}`, target);
// clang-format on
};
export class SharedStorageAccessGrid extends UI.Widget.Widget {
readonly #view: View;
#events: Protocol.Storage.SharedStorageAccessedEvent[] = [];
#onSelect: (event: Protocol.Storage.SharedStorageAccessedEvent) => void = () => {};
constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
super(element, {useShadowDom: true});
this.#view = view;
this.performUpdate();
}
set events(events: Protocol.Storage.SharedStorageAccessedEvent[]) {
this.#events = events;
this.performUpdate();
}
set onSelect(onSelect: (event: Protocol.Storage.SharedStorageAccessedEvent) => unknown) {
this.#onSelect = onSelect;
this.performUpdate();
}
get onSelect(): (event: Protocol.Storage.SharedStorageAccessedEvent) => unknown {
return this.#onSelect;
}
override performUpdate(): void {
this.#view(
{
events: this.#events,
onSelect: this.#onSelect.bind(this),
},
{}, this.contentElement);
}
}