blob: 0325c8922b54c197a5085fd4a8c88ed42b87f32a [file] [log] [blame]
Rayan Kanso68904202019-02-21 14:16:251// Copyright 2019 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
Jan Scheffler1026b9d2021-02-26 17:12:005/* eslint-disable rulesdir/no_underscored_properties */
6
Tim van der Lippe0efccf02020-02-12 15:15:397import * as Bindings from '../bindings/bindings.js';
Tim van der Lippec02a97c2020-02-14 14:39:278import * as Common from '../common/common.js'; // eslint-disable-line no-unused-vars
Tim van der Lippe0efccf02020-02-12 15:15:399import * as DataGrid from '../data_grid/data_grid.js';
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:0110import * as i18n from '../i18n/i18n.js';
Simon Zünd2c704cd2020-06-04 09:08:3511import * as Platform from '../platform/platform.js';
Tim van der Lippe0efccf02020-02-12 15:15:3912import * as SDK from '../sdk/sdk.js';
13import * as UI from '../ui/ui.js';
14
Paul Lewisddf58342020-01-15 14:18:0715import {BackgroundServiceModel, Events} from './BackgroundServiceModel.js'; // eslint-disable-line no-unused-vars
16
Simon Zünd697fb0b2021-03-01 10:12:4217const UIStrings = {
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:0118 /**
19 *@description Text in Background Service View of the Application panel
20 */
21 backgroundFetch: 'Background Fetch',
22 /**
23 *@description Text in Background Service View of the Application panel
24 */
25 backgroundSync: 'Background Sync',
26 /**
27 *@description Text in Background Service View of the Application panel
28 */
29 pushMessaging: 'Push Messaging',
30 /**
31 *@description Text in Background Service View of the Application panel
32 */
33 notifications: 'Notifications',
34 /**
35 *@description Text in Background Service View of the Application panel
36 */
37 paymentHandler: 'Payment Handler',
38 /**
39 *@description Text in the Periodic Background Service View of the Application panel
40 */
41 periodicBackgroundSync: 'Periodic Background Sync',
42 /**
43 *@description Text to clear content
44 */
45 clear: 'Clear',
46 /**
47 *@description Tooltip text that appears when hovering over the largeicon download button in the Background Service View of the Application panel
48 */
49 saveEvents: 'Save events',
50 /**
51 *@description Text in Background Service View of the Application panel
52 */
53 showEventsFromOtherDomains: 'Show events from other domains',
54 /**
55 *@description Title of an action under the Background Services category that can be invoked through the Command Menu
56 */
57 stopRecordingEvents: 'Stop recording events',
58 /**
59 *@description Title of an action under the Background Services category that can be invoked through the Command Menu
60 */
61 startRecordingEvents: 'Start recording events',
62 /**
63 *@description Text for timestamps of items
64 */
65 timestamp: 'Timestamp',
66 /**
67 *@description Text that refers to some events
68 */
69 event: 'Event',
70 /**
71 *@description Text for the origin of something
72 */
73 origin: 'Origin',
74 /**
Sigurd Schneiderbee57a82021-02-23 12:58:2475 *@description Text in Background Service View of the Application panel. The Scope is a URL associated with the Service Worker, which limits which pages/sites the Service Worker operates on.
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:0176 */
Sigurd Schneiderbee57a82021-02-23 12:58:2477 swScope: 'Service Worker Scope',
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:0178 /**
79 *@description Text in Background Service View of the Application panel
80 */
81 instanceId: 'Instance ID',
82 /**
83 *@description Text in Application Panel Sidebar of the Application panel
84 */
85 backgroundServices: 'Background Services',
86 /**
87 *@description Text that is usually a hyperlink to more documentation
88 */
89 learnMore: 'Learn more',
90 /**
91 *@description Text in Background Service View of the Application panel
92 */
93 selectAnEntryToViewMetadata: 'Select an entry to view metadata',
94 /**
95 *@description Text in Background Service View of the Application panel
96 *@example {Background Fetch} PH1
97 */
98 recordingSActivity: 'Recording {PH1} activity...',
99 /**
100 *@description Inform users that DevTools are recording/waiting for events in the Periodic Background Sync tool of the Application panel
101 *@example {Background Fetch} PH1
102 */
103 devtoolsWillRecordAllSActivity: 'DevTools will record all {PH1} activity for up to 3 days, even when closed.',
104 /**
105 *@description Text in Background Service View of the Application panel
106 *@example {record} PH1
107 *@example {Ctrl + R} PH2
108 */
109 clickTheRecordButtonSOrHitSTo: 'Click the record button {PH1} or hit {PH2} to start recording.',
110 /**
111 *@description Text to show an item is empty
112 */
113 empty: 'empty',
114 /**
115 *@description Text in Background Service View of the Application panel
116 */
117 noMetadataForThisEvent: 'No metadata for this event',
118};
Jan Scheffler1026b9d2021-02-26 17:12:00119const str_ = i18n.i18n.registerUIStrings('resources/BackgroundServiceView.ts', UIStrings);
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01120const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
Tim van der Lippe0efccf02020-02-12 15:15:39121export class BackgroundServiceView extends UI.Widget.VBox {
Jan Scheffler1026b9d2021-02-26 17:12:00122 _serviceName: Protocol.BackgroundService.ServiceName;
123 _model: BackgroundServiceModel;
124 _serviceWorkerManager: SDK.ServiceWorkerManager.ServiceWorkerManager|null;
125 _securityOriginManager: SDK.SecurityOriginManager.SecurityOriginManager;
126 _recordAction: UI.ActionRegistration.Action;
127 _recordButton!: UI.Toolbar.ToolbarToggle;
128 _originCheckbox!: UI.Toolbar.ToolbarCheckbox;
129 _saveButton!: UI.Toolbar.ToolbarButton;
130 _toolbar: UI.Toolbar.Toolbar;
131 _splitWidget: UI.SplitWidget.SplitWidget;
132 _dataGrid: DataGrid.DataGrid.DataGridImpl<EventData>;
133 _previewPanel: UI.Widget.VBox;
134 _selectedEventNode: EventDataNode|null;
135 _preview: UI.Widget.Widget|null;
136
137 static getUIString(serviceName: string): string {
Rayan Kansoc0bfdd82019-04-24 12:32:22138 switch (serviceName) {
139 case Protocol.BackgroundService.ServiceName.BackgroundFetch:
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01140 return i18nString(UIStrings.backgroundFetch);
Rayan Kansoc0bfdd82019-04-24 12:32:22141 case Protocol.BackgroundService.ServiceName.BackgroundSync:
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01142 return i18nString(UIStrings.backgroundSync);
Fergus Dall0be4f4c2019-05-21 00:01:29143 case Protocol.BackgroundService.ServiceName.PushMessaging:
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01144 return i18nString(UIStrings.pushMessaging);
Fergus Dall0be4f4c2019-05-21 00:01:29145 case Protocol.BackgroundService.ServiceName.Notifications:
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01146 return i18nString(UIStrings.notifications);
Rayan Kanso8d7918a2019-07-03 21:03:38147 case Protocol.BackgroundService.ServiceName.PaymentHandler:
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01148 return i18nString(UIStrings.paymentHandler);
Rayan Kanso54809672019-07-24 18:40:28149 case Protocol.BackgroundService.ServiceName.PeriodicBackgroundSync:
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01150 return i18nString(UIStrings.periodicBackgroundSync);
Rayan Kansoc0bfdd82019-04-24 12:32:22151 default:
152 return '';
153 }
154 }
155
Jan Scheffler1026b9d2021-02-26 17:12:00156 constructor(serviceName: Protocol.BackgroundService.ServiceName, model: BackgroundServiceModel) {
Rayan Kanso68904202019-02-21 14:16:25157 super(true);
Jack Franklin71519f82020-11-03 12:08:59158 this.registerRequiredCSS('resources/backgroundServiceView.css', {enableLegacyPatching: true});
Jack Franklin7cdd3422020-12-07 11:32:12159 this.registerRequiredCSS('ui/emptyWidget.css', {enableLegacyPatching: false});
Rayan Kanso68904202019-02-21 14:16:25160
Rayan Kanso68904202019-02-21 14:16:25161 this._serviceName = serviceName;
162
Rayan Kanso8fe8ee22019-03-04 14:58:46163 this._model = model;
Paul Lewisddf58342020-01-15 14:18:07164 this._model.addEventListener(Events.RecordingStateChanged, this._onRecordingStateChanged, this);
165 this._model.addEventListener(Events.BackgroundServiceEventReceived, this._onEventReceived, this);
Rayan Kanso8fe8ee22019-03-04 14:58:46166 this._model.enable(this._serviceName);
167
Tim van der Lippe0efccf02020-02-12 15:15:39168 this._serviceWorkerManager = this._model.target().model(SDK.ServiceWorkerManager.ServiceWorkerManager);
Rayan Kansoaca06e72019-03-27 11:57:06169
Jan Scheffler1026b9d2021-02-26 17:12:00170 this._securityOriginManager = this._model.target().model(SDK.SecurityOriginManager.SecurityOriginManager) as
171 SDK.SecurityOriginManager.SecurityOriginManager;
Alex Rudenko60a3e942020-11-02 12:27:57172 if (!this._securityOriginManager) {
173 throw new Error('SecurityOriginManager instance is missing');
174 }
Rayan Kansoaca06e72019-03-27 11:57:06175 this._securityOriginManager.addEventListener(
176 SDK.SecurityOriginManager.Events.MainSecurityOriginChanged, () => this._onOriginChanged());
Paul Lewis24cb7402020-01-24 13:46:35177 this._recordAction =
Jan Scheffler1026b9d2021-02-26 17:12:00178 (UI.ActionRegistry.ActionRegistry.instance().action('background-service.toggle-recording') as
179 UI.ActionRegistration.Action);
Rayan Kanso8fe8ee22019-03-04 14:58:46180
Tim van der Lippe0efccf02020-02-12 15:15:39181 this._toolbar = new UI.Toolbar.Toolbar('background-service-toolbar', this.contentElement);
Rayan Kanso68904202019-02-21 14:16:25182 this._setupToolbar();
Rayan Kanso3252d5e2019-03-27 11:37:24183
Rayan Kansob451b4f2019-04-04 23:12:11184 /**
185 * This will contain the DataGrid for displaying events, and a panel at the bottom for showing
186 * extra metadata related to the selected event.
Rayan Kansob451b4f2019-04-04 23:12:11187 */
Tim van der Lippe0efccf02020-02-12 15:15:39188 this._splitWidget = new UI.SplitWidget.SplitWidget(/* isVertical= */ false, /* secondIsSidebar= */ true);
Rayan Kansob451b4f2019-04-04 23:12:11189 this._splitWidget.show(this.contentElement);
190
Rayan Kanso3252d5e2019-03-27 11:37:24191 this._dataGrid = this._createDataGrid();
Rayan Kansob451b4f2019-04-04 23:12:11192
Tim van der Lippe0efccf02020-02-12 15:15:39193 this._previewPanel = new UI.Widget.VBox();
Rayan Kansob451b4f2019-04-04 23:12:11194
Rayan Kansoc0bfdd82019-04-24 12:32:22195 this._selectedEventNode = null;
196
Rayan Kansob451b4f2019-04-04 23:12:11197 this._preview = null;
198
199 this._splitWidget.setMainWidget(this._dataGrid.asWidget());
200 this._splitWidget.setSidebarWidget(this._previewPanel);
201
202 this._showPreview(null);
Rayan Kanso68904202019-02-21 14:16:25203 }
204
205 /**
206 * Creates the toolbar UI element.
207 */
Jan Scheffler1026b9d2021-02-26 17:12:00208 async _setupToolbar(): Promise<void> {
209 this._recordButton = (UI.Toolbar.Toolbar.createActionButton(this._recordAction) as UI.Toolbar.ToolbarToggle);
Rayan Kanso8fe8ee22019-03-04 14:58:46210 this._toolbar.appendToolbarItem(this._recordButton);
Rayan Kanso68904202019-02-21 14:16:25211
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01212 const clearButton = new UI.Toolbar.ToolbarButton(i18nString(UIStrings.clear), 'largeicon-clear');
Tim van der Lippe0efccf02020-02-12 15:15:39213 clearButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, () => this._clearEvents());
Rayan Kanso68904202019-02-21 14:16:25214 this._toolbar.appendToolbarItem(clearButton);
215
216 this._toolbar.appendSeparator();
217
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01218 this._saveButton = new UI.Toolbar.ToolbarButton(i18nString(UIStrings.saveEvents), 'largeicon-download');
Jan Scheffler1026b9d2021-02-26 17:12:00219 this._saveButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, _event => {
Tim van der Lippe37a35ff2020-03-03 13:49:02220 this._saveToFile();
221 });
Rayan Kansob852ba82019-04-08 13:48:07222 this._saveButton.setEnabled(false);
223 this._toolbar.appendToolbarItem(this._saveButton);
Rayan Kansoc0bfdd82019-04-24 12:32:22224
225 this._toolbar.appendSeparator();
226
Tim van der Lippe0efccf02020-02-12 15:15:39227 this._originCheckbox = new UI.Toolbar.ToolbarCheckbox(
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01228 i18nString(UIStrings.showEventsFromOtherDomains), i18nString(UIStrings.showEventsFromOtherDomains),
229 () => this._refreshView());
Rayan Kansoc0bfdd82019-04-24 12:32:22230 this._toolbar.appendToolbarItem(this._originCheckbox);
Rayan Kanso68904202019-02-21 14:16:25231 }
Rayan Kanso8fe8ee22019-03-04 14:58:46232
233 /**
Rayan Kansob451b4f2019-04-04 23:12:11234 * Displays all available events in the grid.
235 */
Jan Scheffler1026b9d2021-02-26 17:12:00236 _refreshView(): void {
Rayan Kansob451b4f2019-04-04 23:12:11237 this._clearView();
238 const events = this._model.getEvents(this._serviceName).filter(event => this._acceptEvent(event));
Tim van der Lippe1d6e57a2019-09-30 11:55:34239 for (const event of events) {
Rayan Kansob451b4f2019-04-04 23:12:11240 this._addEvent(event);
Tim van der Lippe1d6e57a2019-09-30 11:55:34241 }
Rayan Kansob451b4f2019-04-04 23:12:11242 }
243
244 /**
245 * Clears the grid and panel.
246 */
Jan Scheffler1026b9d2021-02-26 17:12:00247 _clearView(): void {
Rayan Kansoc0bfdd82019-04-24 12:32:22248 this._selectedEventNode = null;
Rayan Kansob451b4f2019-04-04 23:12:11249 this._dataGrid.rootNode().removeChildren();
Rayan Kansob852ba82019-04-08 13:48:07250 this._saveButton.setEnabled(false);
Rayan Kansoc0bfdd82019-04-24 12:32:22251 this._showPreview(null);
Rayan Kansob451b4f2019-04-04 23:12:11252 }
253
254 /**
Rayan Kanso8fe8ee22019-03-04 14:58:46255 * Called when the `Toggle Record` button is clicked.
256 */
Jan Scheffler1026b9d2021-02-26 17:12:00257 _toggleRecording(): void {
Rayan Kanso8fe8ee22019-03-04 14:58:46258 this._model.setRecording(!this._recordButton.toggled(), this._serviceName);
259 }
260
261 /**
Rayan Kanso3252d5e2019-03-27 11:37:24262 * Called when the `Clear` button is clicked.
263 */
Jan Scheffler1026b9d2021-02-26 17:12:00264 _clearEvents(): void {
Rayan Kanso3252d5e2019-03-27 11:37:24265 this._model.clearEvents(this._serviceName);
266 this._clearView();
267 }
268
Jan Scheffler1026b9d2021-02-26 17:12:00269 _onRecordingStateChanged(event: Common.EventTarget.EventTargetEvent): void {
270 const state = (event.data as RecordingState);
Tim van der Lippe1d6e57a2019-09-30 11:55:34271 if (state.serviceName !== this._serviceName) {
Rayan Kanso8fe8ee22019-03-04 14:58:46272 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34273 }
Rayan Kansoc0bfdd82019-04-24 12:32:22274
Tim van der Lippe1d6e57a2019-09-30 11:55:34275 if (state.isRecording === this._recordButton.toggled()) {
Rayan Kansoc0bfdd82019-04-24 12:32:22276 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34277 }
Rayan Kansoc0bfdd82019-04-24 12:32:22278
Rayan Kanso0b30aba2019-05-17 13:39:59279 this._recordButton.setToggled(state.isRecording);
Christy Chen13a12ff2020-08-20 07:43:26280 this._updateRecordButtonTooltip();
Rayan Kansoc0bfdd82019-04-24 12:32:22281 this._showPreview(this._selectedEventNode);
Rayan Kanso8fe8ee22019-03-04 14:58:46282 }
Rayan Kansof40e3152019-03-11 13:49:43283
Jan Scheffler1026b9d2021-02-26 17:12:00284 _updateRecordButtonTooltip(): void {
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01285 const buttonTooltip = this._recordButton.toggled() ? i18nString(UIStrings.stopRecordingEvents) :
286 i18nString(UIStrings.startRecordingEvents);
Christy Chen13a12ff2020-08-20 07:43:26287 this._recordButton.setTitle(buttonTooltip, 'background-service.toggle-recording');
288 }
289
Jan Scheffler1026b9d2021-02-26 17:12:00290 _onEventReceived(event: Common.EventTarget.EventTargetEvent): void {
291 const serviceEvent = (event.data as Protocol.BackgroundService.BackgroundServiceEvent);
Tim van der Lippe1d6e57a2019-09-30 11:55:34292 if (!this._acceptEvent(serviceEvent)) {
Rayan Kansof40e3152019-03-11 13:49:43293 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34294 }
Rayan Kanso3252d5e2019-03-27 11:37:24295 this._addEvent(serviceEvent);
296 }
297
Jan Scheffler1026b9d2021-02-26 17:12:00298 _onOriginChanged(): void {
Rayan Kansoaca06e72019-03-27 11:57:06299 // No need to refresh the view if we are already showing all events.
Tim van der Lippe1d6e57a2019-09-30 11:55:34300 if (this._originCheckbox.checked()) {
Rayan Kansoaca06e72019-03-27 11:57:06301 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34302 }
Rayan Kansoaca06e72019-03-27 11:57:06303 this._refreshView();
304 }
305
Jan Scheffler1026b9d2021-02-26 17:12:00306 _addEvent(serviceEvent: Protocol.BackgroundService.BackgroundServiceEvent): void {
Rayan Kansoaca06e72019-03-27 11:57:06307 const data = this._createEventData(serviceEvent);
Tim van der Lippe097cdec2020-01-06 14:44:17308 const dataNode = new EventDataNode(data, serviceEvent.eventMetadata);
Rayan Kanso3252d5e2019-03-27 11:37:24309 this._dataGrid.rootNode().appendChild(dataNode);
Rayan Kansob852ba82019-04-08 13:48:07310
Rayan Kansoc0bfdd82019-04-24 12:32:22311 if (this._dataGrid.rootNode().children.length === 1) {
312 this._saveButton.setEnabled(true);
313 this._showPreview(this._selectedEventNode);
314 }
Rayan Kanso3252d5e2019-03-27 11:37:24315 }
316
Jan Scheffler1026b9d2021-02-26 17:12:00317 _createDataGrid(): DataGrid.DataGrid.DataGridImpl<EventData> {
318 const columns = ([
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01319 {id: 'id', title: '#', weight: 1},
320 {id: 'timestamp', title: i18nString(UIStrings.timestamp), weight: 8},
321 {id: 'eventName', title: i18nString(UIStrings.event), weight: 10},
322 {id: 'origin', title: i18nString(UIStrings.origin), weight: 10},
Sigurd Schneiderbee57a82021-02-23 12:58:24323 {id: 'swScope', title: i18nString(UIStrings.swScope), weight: 5},
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01324 {id: 'instanceId', title: i18nString(UIStrings.instanceId), weight: 10},
Jan Scheffler1026b9d2021-02-26 17:12:00325 ] as DataGrid.DataGrid.ColumnDescriptor[]);
Alex Rudenko60a3e942020-11-02 12:27:57326 const dataGrid = new DataGrid.DataGrid.DataGridImpl({
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01327 displayName: i18nString(UIStrings.backgroundServices),
Alex Rudenko60a3e942020-11-02 12:27:57328 columns,
329 editCallback: undefined,
330 refreshCallback: undefined,
Jan Scheffler1026b9d2021-02-26 17:12:00331 deleteCallback: undefined,
Alex Rudenko60a3e942020-11-02 12:27:57332 });
Rayan Kanso3252d5e2019-03-27 11:37:24333 dataGrid.setStriped(true);
Rayan Kansob451b4f2019-04-04 23:12:11334
335 dataGrid.addEventListener(
Jan Scheffler1026b9d2021-02-26 17:12:00336 DataGrid.DataGrid.Events.SelectedNode, event => this._showPreview((event.data as EventDataNode)));
Rayan Kansob451b4f2019-04-04 23:12:11337
Rayan Kanso3252d5e2019-03-27 11:37:24338 return dataGrid;
339 }
340
341 /**
Rayan Kansoaca06e72019-03-27 11:57:06342 * Creates the data object to pass to the DataGrid Node.
Rayan Kansoaca06e72019-03-27 11:57:06343 */
Jan Scheffler1026b9d2021-02-26 17:12:00344 _createEventData(serviceEvent: Protocol.BackgroundService.BackgroundServiceEvent): EventData {
Rayan Kansocc02ea32019-05-02 21:26:52345 let swScope = '';
Rayan Kansoaca06e72019-03-27 11:57:06346
Rayan Kansocc02ea32019-05-02 21:26:52347 // Try to get the scope of the Service Worker registration to be more user-friendly.
Alex Rudenko60a3e942020-11-02 12:27:57348 const registration = this._serviceWorkerManager ?
349 this._serviceWorkerManager.registrations().get(serviceEvent.serviceWorkerRegistrationId) :
350 undefined;
Tim van der Lippe1d6e57a2019-09-30 11:55:34351 if (registration) {
Rayan Kansocc02ea32019-05-02 21:26:52352 swScope = registration.scopeURL.substr(registration.securityOrigin.length);
Tim van der Lippe1d6e57a2019-09-30 11:55:34353 }
Rayan Kansoaca06e72019-03-27 11:57:06354
355 return {
Rayan Kansoc79a8bb2019-05-29 21:08:38356 id: this._dataGrid.rootNode().children.length + 1,
Tim van der Lippe0efccf02020-02-12 15:15:39357 timestamp: UI.UIUtils.formatTimestamp(serviceEvent.timestamp * 1000, /* full= */ true),
Rayan Kansoaca06e72019-03-27 11:57:06358 origin: serviceEvent.origin,
Rayan Kansocc02ea32019-05-02 21:26:52359 swScope,
Rayan Kansoaca06e72019-03-27 11:57:06360 eventName: serviceEvent.eventName,
361 instanceId: serviceEvent.instanceId,
362 };
363 }
364
365 /**
Rayan Kanso3252d5e2019-03-27 11:37:24366 * Filtration function to know whether event should be shown or not.
Rayan Kanso3252d5e2019-03-27 11:37:24367 */
Jan Scheffler1026b9d2021-02-26 17:12:00368 _acceptEvent(event: Protocol.BackgroundService.BackgroundServiceEvent): boolean {
Tim van der Lippe1d6e57a2019-09-30 11:55:34369 if (event.service !== this._serviceName) {
Rayan Kansoaca06e72019-03-27 11:57:06370 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34371 }
Rayan Kansoaca06e72019-03-27 11:57:06372
Tim van der Lippe1d6e57a2019-09-30 11:55:34373 if (this._originCheckbox.checked()) {
Rayan Kansoaca06e72019-03-27 11:57:06374 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:34375 }
Rayan Kansoaca06e72019-03-27 11:57:06376
377 // Trim the trailing '/'.
378 const origin = event.origin.substr(0, event.origin.length - 1);
379
380 return this._securityOriginManager.securityOrigins().includes(origin);
Rayan Kanso3252d5e2019-03-27 11:37:24381 }
Rayan Kansob451b4f2019-04-04 23:12:11382
Jan Scheffler1026b9d2021-02-26 17:12:00383 _createLearnMoreLink(): Element {
Rayan Kanso42c0f9e2019-09-02 12:21:09384 let url =
385 'https://developers.google.com/web/tools/chrome-devtools/javascript/background-services?utm_source=devtools';
386
387 switch (this._serviceName) {
388 case Protocol.BackgroundService.ServiceName.BackgroundFetch:
389 url += '#fetch';
390 break;
391 case Protocol.BackgroundService.ServiceName.BackgroundSync:
392 url += '#sync';
393 break;
394 case Protocol.BackgroundService.ServiceName.PushMessaging:
395 url += '#push';
396 break;
397 case Protocol.BackgroundService.ServiceName.Notifications:
398 url += '#notifications';
399 break;
400 default:
401 break;
402 }
403
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01404 return UI.XLink.XLink.create(url, i18nString(UIStrings.learnMore));
Rayan Kanso42c0f9e2019-09-02 12:21:09405 }
406
Jan Scheffler1026b9d2021-02-26 17:12:00407 _showPreview(dataNode: EventDataNode|null): void {
Tim van der Lippe1d6e57a2019-09-30 11:55:34408 if (this._selectedEventNode && this._selectedEventNode === dataNode) {
Rayan Kansoc0bfdd82019-04-24 12:32:22409 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34410 }
Rayan Kansoc0bfdd82019-04-24 12:32:22411
412 this._selectedEventNode = dataNode;
413
Tim van der Lippe1d6e57a2019-09-30 11:55:34414 if (this._preview) {
Rayan Kansob451b4f2019-04-04 23:12:11415 this._preview.detach();
Tim van der Lippe1d6e57a2019-09-30 11:55:34416 }
Rayan Kansob451b4f2019-04-04 23:12:11417
Rayan Kansoc0bfdd82019-04-24 12:32:22418 if (this._selectedEventNode) {
419 this._preview = this._selectedEventNode.createPreview();
Rayan Kanso4476ca52019-07-22 11:51:24420 this._preview.show(this._previewPanel.contentElement);
421 return;
422 }
423
Tim van der Lippe0efccf02020-02-12 15:15:39424 this._preview = new UI.Widget.VBox();
Rayan Kanso4476ca52019-07-22 11:51:24425 this._preview.contentElement.classList.add('background-service-preview', 'fill');
426 const centered = this._preview.contentElement.createChild('div');
427
428 if (this._dataGrid.rootNode().children.length) {
Rayan Kansoc0bfdd82019-04-24 12:32:22429 // Inform users that grid entries are clickable.
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01430 centered.createChild('p').textContent = i18nString(UIStrings.selectAnEntryToViewMetadata);
Rayan Kansoc0bfdd82019-04-24 12:32:22431 } else if (this._recordButton.toggled()) {
432 // Inform users that we are recording/waiting for events.
Tim van der Lippe097cdec2020-01-06 14:44:17433 const featureName = BackgroundServiceView.getUIString(this._serviceName);
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01434 centered.createChild('p').textContent = i18nString(UIStrings.recordingSActivity, {PH1: featureName});
435 centered.createChild('p').textContent = i18nString(UIStrings.devtoolsWillRecordAllSActivity, {PH1: featureName});
Rayan Kansoc0bfdd82019-04-24 12:32:22436 } else {
Tim van der Lippe0efccf02020-02-12 15:15:39437 const landingRecordButton = UI.Toolbar.Toolbar.createActionButton(this._recordAction);
Rayan Kansoc0bfdd82019-04-24 12:32:22438
Tim van der Lippef49e2322020-05-01 15:03:09439 const recordKey = document.createElement('b');
440 recordKey.classList.add('background-service-shortcut');
Tim van der Lippe9c9fb122020-09-08 15:06:17441 recordKey.textContent = UI.ShortcutRegistry.ShortcutRegistry.instance()
442 .shortcutsForAction('background-service.toggle-recording')[0]
443 .title();
Rayan Kanso6156d222019-04-29 23:40:55444
Tim van der Lippe0efccf02020-02-12 15:15:39445 const inlineButton = UI.UIUtils.createInlineButton(landingRecordButton);
Rayan Kansof402ef32019-08-12 13:05:18446 inlineButton.classList.add('background-service-record-inline-button');
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01447 centered.createChild('p').appendChild(i18n.i18n.getFormatLocalizedString(
448 str_, UIStrings.clickTheRecordButtonSOrHitSTo, {PH1: inlineButton, PH2: recordKey}));
Rayan Kanso42c0f9e2019-09-02 12:21:09449
450 centered.appendChild(this._createLearnMoreLink());
Rayan Kansoc0bfdd82019-04-24 12:32:22451 }
Rayan Kansob451b4f2019-04-04 23:12:11452
453 this._preview.show(this._previewPanel.contentElement);
454 }
Rayan Kansob852ba82019-04-08 13:48:07455
456 /**
457 * Saves all currently displayed events in a file (JSON format).
458 */
Jan Scheffler1026b9d2021-02-26 17:12:00459 async _saveToFile(): Promise<void> {
Simon Zünd2c704cd2020-06-04 09:08:35460 const fileName = `${this._serviceName}-${Platform.DateUtilities.toISO8601Compact(new Date())}.json`;
Tim van der Lippe0efccf02020-02-12 15:15:39461 const stream = new Bindings.FileUtils.FileOutputStream();
Rayan Kansob852ba82019-04-08 13:48:07462
463 const accepted = await stream.open(fileName);
Tim van der Lippe1d6e57a2019-09-30 11:55:34464 if (!accepted) {
Rayan Kansob852ba82019-04-08 13:48:07465 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34466 }
Rayan Kansob852ba82019-04-08 13:48:07467
468 const events = this._model.getEvents(this._serviceName).filter(event => this._acceptEvent(event));
469 await stream.write(JSON.stringify(events, undefined, 2));
470 stream.close();
471 }
Tim van der Lippe097cdec2020-01-06 14:44:17472}
Rayan Kanso3252d5e2019-03-27 11:37:24473
Jan Scheffler1026b9d2021-02-26 17:12:00474export class EventDataNode extends DataGrid.DataGrid.DataGridNode<EventData> {
475 _eventMetadata: Protocol.BackgroundService.EventMetadata[];
476
477 constructor(data: EventData, eventMetadata: Protocol.BackgroundService.EventMetadata[]) {
Rayan Kansoaca06e72019-03-27 11:57:06478 super(data);
Rayan Kanso3252d5e2019-03-27 11:37:24479
Jack Franklin056c4002021-01-13 13:53:20480 this._eventMetadata = eventMetadata.sort((m1, m2) => Platform.StringUtilities.compare(m1.key, m2.key));
Rayan Kanso3252d5e2019-03-27 11:37:24481 }
482
Jan Scheffler1026b9d2021-02-26 17:12:00483 createPreview(): UI.Widget.VBox {
Tim van der Lippe0efccf02020-02-12 15:15:39484 const preview = new UI.Widget.VBox();
Rayan Kansoc0bfdd82019-04-24 12:32:22485 preview.element.classList.add('background-service-metadata');
486
487 for (const entry of this._eventMetadata) {
Tim van der Lippef49e2322020-05-01 15:03:09488 const div = document.createElement('div');
489 div.classList.add('background-service-metadata-entry');
Rayan Kansoc0bfdd82019-04-24 12:32:22490 div.createChild('div', 'background-service-metadata-name').textContent = entry.key + ': ';
Rayan Kanso4476ca52019-07-22 11:51:24491 if (entry.value) {
492 div.createChild('div', 'background-service-metadata-value source-code').textContent = entry.value;
493 } else {
494 div.createChild('div', 'background-service-metadata-value background-service-empty-value').textContent =
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01495 i18nString(UIStrings.empty);
Rayan Kanso4476ca52019-07-22 11:51:24496 }
Rayan Kansoc0bfdd82019-04-24 12:32:22497 preview.element.appendChild(div);
498 }
499
500 if (!preview.element.children.length) {
Tim van der Lippef49e2322020-05-01 15:03:09501 const div = document.createElement('div');
502 div.classList.add('background-service-metadata-entry');
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01503 div.createChild('div', 'background-service-metadata-name').textContent =
504 i18nString(UIStrings.noMetadataForThisEvent);
Rayan Kansoc0bfdd82019-04-24 12:32:22505 preview.element.appendChild(div);
506 }
507
508 return preview;
Rayan Kansof40e3152019-03-11 13:49:43509 }
Tim van der Lippe097cdec2020-01-06 14:44:17510}
Rayan Kanso6156d222019-04-29 23:40:55511
Jan Scheffler1026b9d2021-02-26 17:12:00512let actionDelegateInstance: ActionDelegate;
Andres Olivares79578512021-02-02 00:27:49513
Jan Scheffler1026b9d2021-02-26 17:12:00514export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
515 static instance(opts: {
516 forceNew: boolean|null,
517 } = {forceNew: null}): ActionDelegate {
Andres Olivares79578512021-02-02 00:27:49518 const {forceNew} = opts;
519 if (!actionDelegateInstance || forceNew) {
520 actionDelegateInstance = new ActionDelegate();
521 }
522
523 return actionDelegateInstance;
524 }
525
Jan Scheffler1026b9d2021-02-26 17:12:00526 handleAction(context: UI.Context.Context, actionId: string): boolean {
Tim van der Lippe097cdec2020-01-06 14:44:17527 const view = context.flavor(BackgroundServiceView);
Rayan Kanso6156d222019-04-29 23:40:55528 switch (actionId) {
Alex Rudenko60a3e942020-11-02 12:27:57529 case 'background-service.toggle-recording': {
530 if (!view) {
531 throw new Error('BackgroundServiceView instance is missing');
532 }
Rayan Kanso6156d222019-04-29 23:40:55533 view._toggleRecording();
534 return true;
Alex Rudenko60a3e942020-11-02 12:27:57535 }
Rayan Kanso6156d222019-04-29 23:40:55536 }
537 return false;
538 }
Tim van der Lippe097cdec2020-01-06 14:44:17539}
Jan Scheffler1026b9d2021-02-26 17:12:00540export interface RecordingState {
541 isRecording: boolean;
542 serviceName: Protocol.BackgroundService.ServiceName;
543}
544export interface EventData {
545 id: number;
546 timestamp: string;
547 origin: string;
548 swScope: string;
549 eventName: string;
550 instanceId: string;
551}