blob: 88fca3324c92281201e062fe2929dbfb500ed09a [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 Lippe76961572021-04-06 10:48:077import * as Common from '../../core/common/common.js'; // eslint-disable-line no-unused-vars
Tim van der Lippebb352e62021-04-01 17:57:288import * as i18n from '../../core/i18n/i18n.js';
Tim van der Lippeaa1ed7a2021-03-31 14:38:279import * as Platform from '../../core/platform/platform.js';
Tim van der Lippee00b92f2021-03-31 16:52:1710import * as SDK from '../../core/sdk/sdk.js';
Tim van der Lippec59708f2021-03-31 15:07:1911import * as DataGrid from '../../data_grid/data_grid.js';
Tim van der Lippe959b6f02021-04-07 09:07:5912import * as Bindings from '../../models/bindings/bindings.js';
Tim van der Lippeaa61faf2021-04-07 15:32:0713import * as UI from '../../ui/legacy/legacy.js';
Tim van der Lippe0efccf02020-02-12 15:15:3914
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};
Tim van der Lippec59708f2021-03-31 15:07:19119const str_ = i18n.i18n.registerUIStrings('panels/application/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);
Tim van der Lippec59708f2021-03-31 15:07:19158 this.registerRequiredCSS('panels/application/backgroundServiceView.css', {enableLegacyPatching: false});
Tim van der Lippeaa61faf2021-04-07 15:32:07159 this.registerRequiredCSS('ui/legacy/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 {
Jecelyn90c04162021-04-07 08:41:35384 let url = 'https://developer.chrome.com/docs/devtools/javascript/background-services/?utm_source=devtools';
Rayan Kanso42c0f9e2019-09-02 12:21:09385
386 switch (this._serviceName) {
387 case Protocol.BackgroundService.ServiceName.BackgroundFetch:
388 url += '#fetch';
389 break;
390 case Protocol.BackgroundService.ServiceName.BackgroundSync:
391 url += '#sync';
392 break;
393 case Protocol.BackgroundService.ServiceName.PushMessaging:
394 url += '#push';
395 break;
396 case Protocol.BackgroundService.ServiceName.Notifications:
397 url += '#notifications';
398 break;
399 default:
400 break;
401 }
402
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01403 return UI.XLink.XLink.create(url, i18nString(UIStrings.learnMore));
Rayan Kanso42c0f9e2019-09-02 12:21:09404 }
405
Jan Scheffler1026b9d2021-02-26 17:12:00406 _showPreview(dataNode: EventDataNode|null): void {
Tim van der Lippe1d6e57a2019-09-30 11:55:34407 if (this._selectedEventNode && this._selectedEventNode === dataNode) {
Rayan Kansoc0bfdd82019-04-24 12:32:22408 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34409 }
Rayan Kansoc0bfdd82019-04-24 12:32:22410
411 this._selectedEventNode = dataNode;
412
Tim van der Lippe1d6e57a2019-09-30 11:55:34413 if (this._preview) {
Rayan Kansob451b4f2019-04-04 23:12:11414 this._preview.detach();
Tim van der Lippe1d6e57a2019-09-30 11:55:34415 }
Rayan Kansob451b4f2019-04-04 23:12:11416
Rayan Kansoc0bfdd82019-04-24 12:32:22417 if (this._selectedEventNode) {
418 this._preview = this._selectedEventNode.createPreview();
Rayan Kanso4476ca52019-07-22 11:51:24419 this._preview.show(this._previewPanel.contentElement);
420 return;
421 }
422
Tim van der Lippe0efccf02020-02-12 15:15:39423 this._preview = new UI.Widget.VBox();
Rayan Kanso4476ca52019-07-22 11:51:24424 this._preview.contentElement.classList.add('background-service-preview', 'fill');
425 const centered = this._preview.contentElement.createChild('div');
426
427 if (this._dataGrid.rootNode().children.length) {
Rayan Kansoc0bfdd82019-04-24 12:32:22428 // Inform users that grid entries are clickable.
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01429 centered.createChild('p').textContent = i18nString(UIStrings.selectAnEntryToViewMetadata);
Rayan Kansoc0bfdd82019-04-24 12:32:22430 } else if (this._recordButton.toggled()) {
431 // Inform users that we are recording/waiting for events.
Tim van der Lippe097cdec2020-01-06 14:44:17432 const featureName = BackgroundServiceView.getUIString(this._serviceName);
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01433 centered.createChild('p').textContent = i18nString(UIStrings.recordingSActivity, {PH1: featureName});
434 centered.createChild('p').textContent = i18nString(UIStrings.devtoolsWillRecordAllSActivity, {PH1: featureName});
Rayan Kansoc0bfdd82019-04-24 12:32:22435 } else {
Tim van der Lippe0efccf02020-02-12 15:15:39436 const landingRecordButton = UI.Toolbar.Toolbar.createActionButton(this._recordAction);
Rayan Kansoc0bfdd82019-04-24 12:32:22437
Tim van der Lippef49e2322020-05-01 15:03:09438 const recordKey = document.createElement('b');
439 recordKey.classList.add('background-service-shortcut');
Tim van der Lippe9c9fb122020-09-08 15:06:17440 recordKey.textContent = UI.ShortcutRegistry.ShortcutRegistry.instance()
441 .shortcutsForAction('background-service.toggle-recording')[0]
442 .title();
Rayan Kanso6156d222019-04-29 23:40:55443
Tim van der Lippe0efccf02020-02-12 15:15:39444 const inlineButton = UI.UIUtils.createInlineButton(landingRecordButton);
Rayan Kansof402ef32019-08-12 13:05:18445 inlineButton.classList.add('background-service-record-inline-button');
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01446 centered.createChild('p').appendChild(i18n.i18n.getFormatLocalizedString(
447 str_, UIStrings.clickTheRecordButtonSOrHitSTo, {PH1: inlineButton, PH2: recordKey}));
Rayan Kanso42c0f9e2019-09-02 12:21:09448
449 centered.appendChild(this._createLearnMoreLink());
Rayan Kansoc0bfdd82019-04-24 12:32:22450 }
Rayan Kansob451b4f2019-04-04 23:12:11451
452 this._preview.show(this._previewPanel.contentElement);
453 }
Rayan Kansob852ba82019-04-08 13:48:07454
455 /**
456 * Saves all currently displayed events in a file (JSON format).
457 */
Jan Scheffler1026b9d2021-02-26 17:12:00458 async _saveToFile(): Promise<void> {
Simon Zünd2c704cd2020-06-04 09:08:35459 const fileName = `${this._serviceName}-${Platform.DateUtilities.toISO8601Compact(new Date())}.json`;
Tim van der Lippe0efccf02020-02-12 15:15:39460 const stream = new Bindings.FileUtils.FileOutputStream();
Rayan Kansob852ba82019-04-08 13:48:07461
462 const accepted = await stream.open(fileName);
Tim van der Lippe1d6e57a2019-09-30 11:55:34463 if (!accepted) {
Rayan Kansob852ba82019-04-08 13:48:07464 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34465 }
Rayan Kansob852ba82019-04-08 13:48:07466
467 const events = this._model.getEvents(this._serviceName).filter(event => this._acceptEvent(event));
468 await stream.write(JSON.stringify(events, undefined, 2));
469 stream.close();
470 }
Tim van der Lippe097cdec2020-01-06 14:44:17471}
Rayan Kanso3252d5e2019-03-27 11:37:24472
Jan Scheffler1026b9d2021-02-26 17:12:00473export class EventDataNode extends DataGrid.DataGrid.DataGridNode<EventData> {
474 _eventMetadata: Protocol.BackgroundService.EventMetadata[];
475
476 constructor(data: EventData, eventMetadata: Protocol.BackgroundService.EventMetadata[]) {
Rayan Kansoaca06e72019-03-27 11:57:06477 super(data);
Rayan Kanso3252d5e2019-03-27 11:37:24478
Jack Franklin056c4002021-01-13 13:53:20479 this._eventMetadata = eventMetadata.sort((m1, m2) => Platform.StringUtilities.compare(m1.key, m2.key));
Rayan Kanso3252d5e2019-03-27 11:37:24480 }
481
Jan Scheffler1026b9d2021-02-26 17:12:00482 createPreview(): UI.Widget.VBox {
Tim van der Lippe0efccf02020-02-12 15:15:39483 const preview = new UI.Widget.VBox();
Rayan Kansoc0bfdd82019-04-24 12:32:22484 preview.element.classList.add('background-service-metadata');
485
486 for (const entry of this._eventMetadata) {
Tim van der Lippef49e2322020-05-01 15:03:09487 const div = document.createElement('div');
488 div.classList.add('background-service-metadata-entry');
Rayan Kansoc0bfdd82019-04-24 12:32:22489 div.createChild('div', 'background-service-metadata-name').textContent = entry.key + ': ';
Rayan Kanso4476ca52019-07-22 11:51:24490 if (entry.value) {
491 div.createChild('div', 'background-service-metadata-value source-code').textContent = entry.value;
492 } else {
493 div.createChild('div', 'background-service-metadata-value background-service-empty-value').textContent =
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01494 i18nString(UIStrings.empty);
Rayan Kanso4476ca52019-07-22 11:51:24495 }
Rayan Kansoc0bfdd82019-04-24 12:32:22496 preview.element.appendChild(div);
497 }
498
499 if (!preview.element.children.length) {
Tim van der Lippef49e2322020-05-01 15:03:09500 const div = document.createElement('div');
501 div.classList.add('background-service-metadata-entry');
Sigurd Schneiderfec75bb2021-03-19 10:23:34502 div.createChild('div', 'background-service-metadata-name background-service-empty-value').textContent =
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01503 i18nString(UIStrings.noMetadataForThisEvent);
Rayan Kansoc0bfdd82019-04-24 12:32:22504 preview.element.appendChild(div);
505 }
506
507 return preview;
Rayan Kansof40e3152019-03-11 13:49:43508 }
Tim van der Lippe097cdec2020-01-06 14:44:17509}
Rayan Kanso6156d222019-04-29 23:40:55510
Jan Scheffler1026b9d2021-02-26 17:12:00511let actionDelegateInstance: ActionDelegate;
Andres Olivares79578512021-02-02 00:27:49512
Jan Scheffler1026b9d2021-02-26 17:12:00513export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
514 static instance(opts: {
515 forceNew: boolean|null,
516 } = {forceNew: null}): ActionDelegate {
Andres Olivares79578512021-02-02 00:27:49517 const {forceNew} = opts;
518 if (!actionDelegateInstance || forceNew) {
519 actionDelegateInstance = new ActionDelegate();
520 }
521
522 return actionDelegateInstance;
523 }
524
Jan Scheffler1026b9d2021-02-26 17:12:00525 handleAction(context: UI.Context.Context, actionId: string): boolean {
Tim van der Lippe097cdec2020-01-06 14:44:17526 const view = context.flavor(BackgroundServiceView);
Rayan Kanso6156d222019-04-29 23:40:55527 switch (actionId) {
Alex Rudenko60a3e942020-11-02 12:27:57528 case 'background-service.toggle-recording': {
529 if (!view) {
530 throw new Error('BackgroundServiceView instance is missing');
531 }
Rayan Kanso6156d222019-04-29 23:40:55532 view._toggleRecording();
533 return true;
Alex Rudenko60a3e942020-11-02 12:27:57534 }
Rayan Kanso6156d222019-04-29 23:40:55535 }
536 return false;
537 }
Tim van der Lippe097cdec2020-01-06 14:44:17538}
Jan Scheffler1026b9d2021-02-26 17:12:00539export interface RecordingState {
540 isRecording: boolean;
541 serviceName: Protocol.BackgroundService.ServiceName;
542}
543export interface EventData {
544 id: number;
545 timestamp: string;
546 origin: string;
547 swScope: string;
548 eventName: string;
549 instanceId: string;
550}