blob: 3963aa125f3f40b5d33e64676f276da96d3c081b [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
Tim van der Lippe0efccf02020-02-12 15:15:395import * as Bindings from '../bindings/bindings.js';
Tim van der Lippec02a97c2020-02-14 14:39:276import * as Common from '../common/common.js'; // eslint-disable-line no-unused-vars
Tim van der Lippe0efccf02020-02-12 15:15:397import * as DataGrid from '../data_grid/data_grid.js';
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:018import * as i18n from '../i18n/i18n.js';
Simon Zünd2c704cd2020-06-04 09:08:359import * as Platform from '../platform/platform.js';
Tim van der Lippe0efccf02020-02-12 15:15:3910import * as SDK from '../sdk/sdk.js';
11import * as UI from '../ui/ui.js';
12
Paul Lewisddf58342020-01-15 14:18:0713import {BackgroundServiceModel, Events} from './BackgroundServiceModel.js'; // eslint-disable-line no-unused-vars
14
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:0115export const UIStrings = {
16 /**
17 *@description Text in Background Service View of the Application panel
18 */
19 backgroundFetch: 'Background Fetch',
20 /**
21 *@description Text in Background Service View of the Application panel
22 */
23 backgroundSync: 'Background Sync',
24 /**
25 *@description Text in Background Service View of the Application panel
26 */
27 pushMessaging: 'Push Messaging',
28 /**
29 *@description Text in Background Service View of the Application panel
30 */
31 notifications: 'Notifications',
32 /**
33 *@description Text in Background Service View of the Application panel
34 */
35 paymentHandler: 'Payment Handler',
36 /**
37 *@description Text in the Periodic Background Service View of the Application panel
38 */
39 periodicBackgroundSync: 'Periodic Background Sync',
40 /**
41 *@description Text to clear content
42 */
43 clear: 'Clear',
44 /**
45 *@description Tooltip text that appears when hovering over the largeicon download button in the Background Service View of the Application panel
46 */
47 saveEvents: 'Save events',
48 /**
49 *@description Text in Background Service View of the Application panel
50 */
51 showEventsFromOtherDomains: 'Show events from other domains',
52 /**
53 *@description Title of an action under the Background Services category that can be invoked through the Command Menu
54 */
55 stopRecordingEvents: 'Stop recording events',
56 /**
57 *@description Title of an action under the Background Services category that can be invoked through the Command Menu
58 */
59 startRecordingEvents: 'Start recording events',
60 /**
61 *@description Text for timestamps of items
62 */
63 timestamp: 'Timestamp',
64 /**
65 *@description Text that refers to some events
66 */
67 event: 'Event',
68 /**
69 *@description Text for the origin of something
70 */
71 origin: 'Origin',
72 /**
73 *@description Text in Background Service View of the Application panel
74 */
75 swScope: 'SW Scope',
76 /**
77 *@description Text in Background Service View of the Application panel
78 */
79 instanceId: 'Instance ID',
80 /**
81 *@description Text in Application Panel Sidebar of the Application panel
82 */
83 backgroundServices: 'Background Services',
84 /**
85 *@description Text that is usually a hyperlink to more documentation
86 */
87 learnMore: 'Learn more',
88 /**
89 *@description Text in Background Service View of the Application panel
90 */
91 selectAnEntryToViewMetadata: 'Select an entry to view metadata',
92 /**
93 *@description Text in Background Service View of the Application panel
94 *@example {Background Fetch} PH1
95 */
96 recordingSActivity: 'Recording {PH1} activity...',
97 /**
98 *@description Inform users that DevTools are recording/waiting for events in the Periodic Background Sync tool of the Application panel
99 *@example {Background Fetch} PH1
100 */
101 devtoolsWillRecordAllSActivity: 'DevTools will record all {PH1} activity for up to 3 days, even when closed.',
102 /**
103 *@description Text in Background Service View of the Application panel
104 *@example {record} PH1
105 *@example {Ctrl + R} PH2
106 */
107 clickTheRecordButtonSOrHitSTo: 'Click the record button {PH1} or hit {PH2} to start recording.',
108 /**
109 *@description Text to show an item is empty
110 */
111 empty: 'empty',
112 /**
113 *@description Text in Background Service View of the Application panel
114 */
115 noMetadataForThisEvent: 'No metadata for this event',
116};
117const str_ = i18n.i18n.registerUIStrings('resources/BackgroundServiceView.js', UIStrings);
118const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
Tim van der Lippe0efccf02020-02-12 15:15:39119export class BackgroundServiceView extends UI.Widget.VBox {
Rayan Kanso68904202019-02-21 14:16:25120 /**
Rayan Kansoc0bfdd82019-04-24 12:32:22121 * @param {string} serviceName The name of the background service.
122 * @return {string} The UI String to display.
123 */
124 static getUIString(serviceName) {
125 switch (serviceName) {
126 case Protocol.BackgroundService.ServiceName.BackgroundFetch:
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01127 return i18nString(UIStrings.backgroundFetch);
Rayan Kansoc0bfdd82019-04-24 12:32:22128 case Protocol.BackgroundService.ServiceName.BackgroundSync:
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01129 return i18nString(UIStrings.backgroundSync);
Fergus Dall0be4f4c2019-05-21 00:01:29130 case Protocol.BackgroundService.ServiceName.PushMessaging:
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01131 return i18nString(UIStrings.pushMessaging);
Fergus Dall0be4f4c2019-05-21 00:01:29132 case Protocol.BackgroundService.ServiceName.Notifications:
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01133 return i18nString(UIStrings.notifications);
Rayan Kanso8d7918a2019-07-03 21:03:38134 case Protocol.BackgroundService.ServiceName.PaymentHandler:
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01135 return i18nString(UIStrings.paymentHandler);
Rayan Kanso54809672019-07-24 18:40:28136 case Protocol.BackgroundService.ServiceName.PeriodicBackgroundSync:
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01137 return i18nString(UIStrings.periodicBackgroundSync);
Rayan Kansoc0bfdd82019-04-24 12:32:22138 default:
139 return '';
140 }
141 }
142
143 /**
Rayan Kanso8fe8ee22019-03-04 14:58:46144 * @param {!Protocol.BackgroundService.ServiceName} serviceName
Paul Lewisddf58342020-01-15 14:18:07145 * @param {!BackgroundServiceModel} model
Rayan Kanso68904202019-02-21 14:16:25146 */
Rayan Kanso8fe8ee22019-03-04 14:58:46147 constructor(serviceName, model) {
Rayan Kanso68904202019-02-21 14:16:25148 super(true);
Jack Franklin71519f82020-11-03 12:08:59149 this.registerRequiredCSS('resources/backgroundServiceView.css', {enableLegacyPatching: true});
Jack Franklin7cdd3422020-12-07 11:32:12150 this.registerRequiredCSS('ui/emptyWidget.css', {enableLegacyPatching: false});
Rayan Kanso68904202019-02-21 14:16:25151
Rayan Kanso8fe8ee22019-03-04 14:58:46152 /** @const {!Protocol.BackgroundService.ServiceName} */
Rayan Kanso68904202019-02-21 14:16:25153 this._serviceName = serviceName;
154
Paul Lewisddf58342020-01-15 14:18:07155 /** @const {!BackgroundServiceModel} */
Rayan Kanso8fe8ee22019-03-04 14:58:46156 this._model = model;
Paul Lewisddf58342020-01-15 14:18:07157 this._model.addEventListener(Events.RecordingStateChanged, this._onRecordingStateChanged, this);
158 this._model.addEventListener(Events.BackgroundServiceEventReceived, this._onEventReceived, this);
Rayan Kanso8fe8ee22019-03-04 14:58:46159 this._model.enable(this._serviceName);
160
Tim van der Lippe0efccf02020-02-12 15:15:39161 /** @const {?SDK.ServiceWorkerManager.ServiceWorkerManager} */
162 this._serviceWorkerManager = this._model.target().model(SDK.ServiceWorkerManager.ServiceWorkerManager);
Rayan Kansoaca06e72019-03-27 11:57:06163
Tim van der Lippe0efccf02020-02-12 15:15:39164 /** @const {?SDK.SecurityOriginManager.SecurityOriginManager} */
165 this._securityOriginManager = this._model.target().model(SDK.SecurityOriginManager.SecurityOriginManager);
Alex Rudenko60a3e942020-11-02 12:27:57166 if (!this._securityOriginManager) {
167 throw new Error('SecurityOriginManager instance is missing');
168 }
Rayan Kansoaca06e72019-03-27 11:57:06169 this._securityOriginManager.addEventListener(
170 SDK.SecurityOriginManager.Events.MainSecurityOriginChanged, () => this._onOriginChanged());
171
Rayan Kansocc02ea32019-05-02 21:26:52172
Andres Olivares6ff6d042020-11-17 14:31:57173 /** @type {!UI.ActionRegistration.Action} */
Paul Lewis24cb7402020-01-24 13:46:35174 this._recordAction =
Andres Olivares6ff6d042020-11-17 14:31:57175 /** @type {!UI.ActionRegistration.Action} */ (
Tim van der Lippe177c0b22020-08-19 14:56:02176 UI.ActionRegistry.ActionRegistry.instance().action('background-service.toggle-recording'));
Rayan Kanso8fe8ee22019-03-04 14:58:46177
Alex Rudenko60a3e942020-11-02 12:27:57178 /**
179 * Initialised in the _setupToolbar() call below.
180 * @type {!UI.Toolbar.ToolbarToggle}
181 */
182 this._recordButton;
Rayan Kansoaca06e72019-03-27 11:57:06183
Alex Rudenko60a3e942020-11-02 12:27:57184 /**
185 * Initialised in the _setupToolbar() call below.
186 * @type {!UI.Toolbar.ToolbarCheckbox}
187 */
188 this._originCheckbox;
189
190 /**
191 * Initialised in the _setupToolbar() call below.
192 * @type {!UI.Toolbar.ToolbarButton}
193 */
194 this._saveButton;
Rayan Kansob852ba82019-04-08 13:48:07195
Tim van der Lippe0efccf02020-02-12 15:15:39196 /** @const {!UI.Toolbar.Toolbar} */
197 this._toolbar = new UI.Toolbar.Toolbar('background-service-toolbar', this.contentElement);
Rayan Kanso68904202019-02-21 14:16:25198 this._setupToolbar();
Rayan Kanso3252d5e2019-03-27 11:37:24199
Rayan Kansob451b4f2019-04-04 23:12:11200 /**
201 * This will contain the DataGrid for displaying events, and a panel at the bottom for showing
202 * extra metadata related to the selected event.
Tim van der Lippe0efccf02020-02-12 15:15:39203 * @const {!UI.SplitWidget.SplitWidget}
Rayan Kansob451b4f2019-04-04 23:12:11204 */
Tim van der Lippe0efccf02020-02-12 15:15:39205 this._splitWidget = new UI.SplitWidget.SplitWidget(/* isVertical= */ false, /* secondIsSidebar= */ true);
Rayan Kansob451b4f2019-04-04 23:12:11206 this._splitWidget.show(this.contentElement);
207
Tim van der Lippe0efccf02020-02-12 15:15:39208 /** @const {!DataGrid.DataGrid.DataGridImpl} */
Rayan Kanso3252d5e2019-03-27 11:37:24209 this._dataGrid = this._createDataGrid();
Rayan Kansob451b4f2019-04-04 23:12:11210
Tim van der Lippe0efccf02020-02-12 15:15:39211 /** @const {!UI.Widget.VBox} */
212 this._previewPanel = new UI.Widget.VBox();
Rayan Kansob451b4f2019-04-04 23:12:11213
Tim van der Lippe097cdec2020-01-06 14:44:17214 /** @type {?EventDataNode} */
Rayan Kansoc0bfdd82019-04-24 12:32:22215 this._selectedEventNode = null;
216
Tim van der Lippe0efccf02020-02-12 15:15:39217 /** @type {?UI.Widget.Widget} */
Rayan Kansob451b4f2019-04-04 23:12:11218 this._preview = null;
219
220 this._splitWidget.setMainWidget(this._dataGrid.asWidget());
221 this._splitWidget.setSidebarWidget(this._previewPanel);
222
223 this._showPreview(null);
Rayan Kanso68904202019-02-21 14:16:25224 }
225
226 /**
227 * Creates the toolbar UI element.
228 */
Rayan Kanso8fe8ee22019-03-04 14:58:46229 async _setupToolbar() {
Alex Rudenko60a3e942020-11-02 12:27:57230 this._recordButton =
231 /** @type {!UI.Toolbar.ToolbarToggle} */ (UI.Toolbar.Toolbar.createActionButton(this._recordAction));
Rayan Kanso8fe8ee22019-03-04 14:58:46232 this._toolbar.appendToolbarItem(this._recordButton);
Rayan Kanso68904202019-02-21 14:16:25233
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01234 const clearButton = new UI.Toolbar.ToolbarButton(i18nString(UIStrings.clear), 'largeicon-clear');
Tim van der Lippe0efccf02020-02-12 15:15:39235 clearButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, () => this._clearEvents());
Rayan Kanso68904202019-02-21 14:16:25236 this._toolbar.appendToolbarItem(clearButton);
237
238 this._toolbar.appendSeparator();
239
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01240 this._saveButton = new UI.Toolbar.ToolbarButton(i18nString(UIStrings.saveEvents), 'largeicon-download');
Tim van der Lippe37a35ff2020-03-03 13:49:02241 this._saveButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, event => {
242 this._saveToFile();
243 });
Rayan Kansob852ba82019-04-08 13:48:07244 this._saveButton.setEnabled(false);
245 this._toolbar.appendToolbarItem(this._saveButton);
Rayan Kansoc0bfdd82019-04-24 12:32:22246
247 this._toolbar.appendSeparator();
248
Tim van der Lippe0efccf02020-02-12 15:15:39249 this._originCheckbox = new UI.Toolbar.ToolbarCheckbox(
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01250 i18nString(UIStrings.showEventsFromOtherDomains), i18nString(UIStrings.showEventsFromOtherDomains),
251 () => this._refreshView());
Rayan Kansoc0bfdd82019-04-24 12:32:22252 this._toolbar.appendToolbarItem(this._originCheckbox);
Rayan Kanso68904202019-02-21 14:16:25253 }
Rayan Kanso8fe8ee22019-03-04 14:58:46254
255 /**
Rayan Kansob451b4f2019-04-04 23:12:11256 * Displays all available events in the grid.
257 */
258 _refreshView() {
259 this._clearView();
260 const events = this._model.getEvents(this._serviceName).filter(event => this._acceptEvent(event));
Tim van der Lippe1d6e57a2019-09-30 11:55:34261 for (const event of events) {
Rayan Kansob451b4f2019-04-04 23:12:11262 this._addEvent(event);
Tim van der Lippe1d6e57a2019-09-30 11:55:34263 }
Rayan Kansob451b4f2019-04-04 23:12:11264 }
265
266 /**
267 * Clears the grid and panel.
268 */
269 _clearView() {
Rayan Kansoc0bfdd82019-04-24 12:32:22270 this._selectedEventNode = null;
Rayan Kansob451b4f2019-04-04 23:12:11271 this._dataGrid.rootNode().removeChildren();
Rayan Kansob852ba82019-04-08 13:48:07272 this._saveButton.setEnabled(false);
Rayan Kansoc0bfdd82019-04-24 12:32:22273 this._showPreview(null);
Rayan Kansob451b4f2019-04-04 23:12:11274 }
275
276 /**
Rayan Kanso8fe8ee22019-03-04 14:58:46277 * Called when the `Toggle Record` button is clicked.
278 */
279 _toggleRecording() {
280 this._model.setRecording(!this._recordButton.toggled(), this._serviceName);
281 }
282
283 /**
Rayan Kanso3252d5e2019-03-27 11:37:24284 * Called when the `Clear` button is clicked.
285 */
Rayan Kansob451b4f2019-04-04 23:12:11286 _clearEvents() {
Rayan Kanso3252d5e2019-03-27 11:37:24287 this._model.clearEvents(this._serviceName);
288 this._clearView();
289 }
290
291 /**
Tim van der Lippec02a97c2020-02-14 14:39:27292 * @param {!Common.EventTarget.EventTargetEvent} event
Rayan Kanso8fe8ee22019-03-04 14:58:46293 */
294 _onRecordingStateChanged(event) {
Tim van der Lippeff5ad472020-02-17 12:35:09295 const state = /** @type {!RecordingState} */ (event.data);
Tim van der Lippe1d6e57a2019-09-30 11:55:34296 if (state.serviceName !== this._serviceName) {
Rayan Kanso8fe8ee22019-03-04 14:58:46297 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34298 }
Rayan Kansoc0bfdd82019-04-24 12:32:22299
Tim van der Lippe1d6e57a2019-09-30 11:55:34300 if (state.isRecording === this._recordButton.toggled()) {
Rayan Kansoc0bfdd82019-04-24 12:32:22301 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34302 }
Rayan Kansoc0bfdd82019-04-24 12:32:22303
Rayan Kanso0b30aba2019-05-17 13:39:59304 this._recordButton.setToggled(state.isRecording);
Christy Chen13a12ff2020-08-20 07:43:26305 this._updateRecordButtonTooltip();
Rayan Kansoc0bfdd82019-04-24 12:32:22306 this._showPreview(this._selectedEventNode);
Rayan Kanso8fe8ee22019-03-04 14:58:46307 }
Rayan Kansof40e3152019-03-11 13:49:43308
Christy Chen13a12ff2020-08-20 07:43:26309 _updateRecordButtonTooltip() {
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01310 const buttonTooltip = this._recordButton.toggled() ? i18nString(UIStrings.stopRecordingEvents) :
311 i18nString(UIStrings.startRecordingEvents);
Christy Chen13a12ff2020-08-20 07:43:26312 this._recordButton.setTitle(buttonTooltip, 'background-service.toggle-recording');
313 }
314
Rayan Kansof40e3152019-03-11 13:49:43315 /**
Tim van der Lippec02a97c2020-02-14 14:39:27316 * @param {!Common.EventTarget.EventTargetEvent} event
Rayan Kansof40e3152019-03-11 13:49:43317 */
318 _onEventReceived(event) {
319 const serviceEvent = /** @type {!Protocol.BackgroundService.BackgroundServiceEvent} */ (event.data);
Tim van der Lippe1d6e57a2019-09-30 11:55:34320 if (!this._acceptEvent(serviceEvent)) {
Rayan Kansof40e3152019-03-11 13:49:43321 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34322 }
Rayan Kanso3252d5e2019-03-27 11:37:24323 this._addEvent(serviceEvent);
324 }
325
Rayan Kansoaca06e72019-03-27 11:57:06326 _onOriginChanged() {
327 // No need to refresh the view if we are already showing all events.
Tim van der Lippe1d6e57a2019-09-30 11:55:34328 if (this._originCheckbox.checked()) {
Rayan Kansoaca06e72019-03-27 11:57:06329 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34330 }
Rayan Kansoaca06e72019-03-27 11:57:06331 this._refreshView();
332 }
333
Rayan Kanso3252d5e2019-03-27 11:37:24334 /**
335 * @param {!Protocol.BackgroundService.BackgroundServiceEvent} serviceEvent
336 */
337 _addEvent(serviceEvent) {
Rayan Kansoaca06e72019-03-27 11:57:06338 const data = this._createEventData(serviceEvent);
Tim van der Lippe097cdec2020-01-06 14:44:17339 const dataNode = new EventDataNode(data, serviceEvent.eventMetadata);
Rayan Kanso3252d5e2019-03-27 11:37:24340 this._dataGrid.rootNode().appendChild(dataNode);
Rayan Kansob852ba82019-04-08 13:48:07341
Rayan Kansoc0bfdd82019-04-24 12:32:22342 if (this._dataGrid.rootNode().children.length === 1) {
343 this._saveButton.setEnabled(true);
344 this._showPreview(this._selectedEventNode);
345 }
Rayan Kanso3252d5e2019-03-27 11:37:24346 }
347
348 /**
Alex Rudenko60a3e942020-11-02 12:27:57349 * @return {!DataGrid.DataGrid.DataGridImpl<!Object<string, string|number>>}
Rayan Kanso3252d5e2019-03-27 11:37:24350 */
351 _createDataGrid() {
Tim van der Lippe9a9aba82020-02-14 14:52:29352 const columns = /** @type {!Array<!DataGrid.DataGrid.ColumnDescriptor>} */ ([
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01353 {id: 'id', title: '#', weight: 1},
354 {id: 'timestamp', title: i18nString(UIStrings.timestamp), weight: 8},
355 {id: 'eventName', title: i18nString(UIStrings.event), weight: 10},
356 {id: 'origin', title: i18nString(UIStrings.origin), weight: 10},
357 {id: 'swScope', title: i18nString(UIStrings.swScope), weight: 2},
358 {id: 'instanceId', title: i18nString(UIStrings.instanceId), weight: 10},
Rayan Kanso3252d5e2019-03-27 11:37:24359 ]);
Alex Rudenko60a3e942020-11-02 12:27:57360 const dataGrid = new DataGrid.DataGrid.DataGridImpl({
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01361 displayName: i18nString(UIStrings.backgroundServices),
Alex Rudenko60a3e942020-11-02 12:27:57362 columns,
363 editCallback: undefined,
364 refreshCallback: undefined,
365 deleteCallback: undefined
366 });
Rayan Kanso3252d5e2019-03-27 11:37:24367 dataGrid.setStriped(true);
Rayan Kansob451b4f2019-04-04 23:12:11368
369 dataGrid.addEventListener(
Tim van der Lippe097cdec2020-01-06 14:44:17370 DataGrid.DataGrid.Events.SelectedNode, event => this._showPreview(/** @type {!EventDataNode} */ (event.data)));
Rayan Kansob451b4f2019-04-04 23:12:11371
Rayan Kanso3252d5e2019-03-27 11:37:24372 return dataGrid;
373 }
374
375 /**
Rayan Kansoaca06e72019-03-27 11:57:06376 * Creates the data object to pass to the DataGrid Node.
377 * @param {!Protocol.BackgroundService.BackgroundServiceEvent} serviceEvent
Tim van der Lippeff5ad472020-02-17 12:35:09378 * @return {!EventData}
Rayan Kansoaca06e72019-03-27 11:57:06379 */
380 _createEventData(serviceEvent) {
Rayan Kansocc02ea32019-05-02 21:26:52381 let swScope = '';
Rayan Kansoaca06e72019-03-27 11:57:06382
Rayan Kansocc02ea32019-05-02 21:26:52383 // Try to get the scope of the Service Worker registration to be more user-friendly.
Alex Rudenko60a3e942020-11-02 12:27:57384 const registration = this._serviceWorkerManager ?
385 this._serviceWorkerManager.registrations().get(serviceEvent.serviceWorkerRegistrationId) :
386 undefined;
Tim van der Lippe1d6e57a2019-09-30 11:55:34387 if (registration) {
Rayan Kansocc02ea32019-05-02 21:26:52388 swScope = registration.scopeURL.substr(registration.securityOrigin.length);
Tim van der Lippe1d6e57a2019-09-30 11:55:34389 }
Rayan Kansoaca06e72019-03-27 11:57:06390
391 return {
Rayan Kansoc79a8bb2019-05-29 21:08:38392 id: this._dataGrid.rootNode().children.length + 1,
Tim van der Lippe0efccf02020-02-12 15:15:39393 timestamp: UI.UIUtils.formatTimestamp(serviceEvent.timestamp * 1000, /* full= */ true),
Rayan Kansoaca06e72019-03-27 11:57:06394 origin: serviceEvent.origin,
Rayan Kansocc02ea32019-05-02 21:26:52395 swScope,
Rayan Kansoaca06e72019-03-27 11:57:06396 eventName: serviceEvent.eventName,
397 instanceId: serviceEvent.instanceId,
398 };
399 }
400
401 /**
Rayan Kanso3252d5e2019-03-27 11:37:24402 * Filtration function to know whether event should be shown or not.
403 * @param {!Protocol.BackgroundService.BackgroundServiceEvent} event
404 * @return {boolean}
405 */
406 _acceptEvent(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34407 if (event.service !== this._serviceName) {
Rayan Kansoaca06e72019-03-27 11:57:06408 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34409 }
Rayan Kansoaca06e72019-03-27 11:57:06410
Tim van der Lippe1d6e57a2019-09-30 11:55:34411 if (this._originCheckbox.checked()) {
Rayan Kansoaca06e72019-03-27 11:57:06412 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:34413 }
Rayan Kansoaca06e72019-03-27 11:57:06414
415 // Trim the trailing '/'.
416 const origin = event.origin.substr(0, event.origin.length - 1);
417
418 return this._securityOriginManager.securityOrigins().includes(origin);
Rayan Kanso3252d5e2019-03-27 11:37:24419 }
Rayan Kansob451b4f2019-04-04 23:12:11420
421 /**
Rayan Kanso42c0f9e2019-09-02 12:21:09422 * @return {!Element}
423 */
424 _createLearnMoreLink() {
425 let url =
426 'https://developers.google.com/web/tools/chrome-devtools/javascript/background-services?utm_source=devtools';
427
428 switch (this._serviceName) {
429 case Protocol.BackgroundService.ServiceName.BackgroundFetch:
430 url += '#fetch';
431 break;
432 case Protocol.BackgroundService.ServiceName.BackgroundSync:
433 url += '#sync';
434 break;
435 case Protocol.BackgroundService.ServiceName.PushMessaging:
436 url += '#push';
437 break;
438 case Protocol.BackgroundService.ServiceName.Notifications:
439 url += '#notifications';
440 break;
441 default:
442 break;
443 }
444
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01445 return UI.XLink.XLink.create(url, i18nString(UIStrings.learnMore));
Rayan Kanso42c0f9e2019-09-02 12:21:09446 }
447
448 /**
Tim van der Lippe097cdec2020-01-06 14:44:17449 * @param {?EventDataNode} dataNode
Rayan Kansob451b4f2019-04-04 23:12:11450 */
451 _showPreview(dataNode) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34452 if (this._selectedEventNode && this._selectedEventNode === dataNode) {
Rayan Kansoc0bfdd82019-04-24 12:32:22453 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34454 }
Rayan Kansoc0bfdd82019-04-24 12:32:22455
456 this._selectedEventNode = dataNode;
457
Tim van der Lippe1d6e57a2019-09-30 11:55:34458 if (this._preview) {
Rayan Kansob451b4f2019-04-04 23:12:11459 this._preview.detach();
Tim van der Lippe1d6e57a2019-09-30 11:55:34460 }
Rayan Kansob451b4f2019-04-04 23:12:11461
Rayan Kansoc0bfdd82019-04-24 12:32:22462 if (this._selectedEventNode) {
463 this._preview = this._selectedEventNode.createPreview();
Rayan Kanso4476ca52019-07-22 11:51:24464 this._preview.show(this._previewPanel.contentElement);
465 return;
466 }
467
Tim van der Lippe0efccf02020-02-12 15:15:39468 this._preview = new UI.Widget.VBox();
Rayan Kanso4476ca52019-07-22 11:51:24469 this._preview.contentElement.classList.add('background-service-preview', 'fill');
470 const centered = this._preview.contentElement.createChild('div');
471
472 if (this._dataGrid.rootNode().children.length) {
Rayan Kansoc0bfdd82019-04-24 12:32:22473 // Inform users that grid entries are clickable.
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01474 centered.createChild('p').textContent = i18nString(UIStrings.selectAnEntryToViewMetadata);
Rayan Kansoc0bfdd82019-04-24 12:32:22475 } else if (this._recordButton.toggled()) {
476 // Inform users that we are recording/waiting for events.
Tim van der Lippe097cdec2020-01-06 14:44:17477 const featureName = BackgroundServiceView.getUIString(this._serviceName);
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01478 centered.createChild('p').textContent = i18nString(UIStrings.recordingSActivity, {PH1: featureName});
479 centered.createChild('p').textContent = i18nString(UIStrings.devtoolsWillRecordAllSActivity, {PH1: featureName});
Rayan Kansoc0bfdd82019-04-24 12:32:22480 } else {
Tim van der Lippe0efccf02020-02-12 15:15:39481 const landingRecordButton = UI.Toolbar.Toolbar.createActionButton(this._recordAction);
Rayan Kansoc0bfdd82019-04-24 12:32:22482
Tim van der Lippef49e2322020-05-01 15:03:09483 const recordKey = document.createElement('b');
484 recordKey.classList.add('background-service-shortcut');
Tim van der Lippe9c9fb122020-09-08 15:06:17485 recordKey.textContent = UI.ShortcutRegistry.ShortcutRegistry.instance()
486 .shortcutsForAction('background-service.toggle-recording')[0]
487 .title();
Rayan Kanso6156d222019-04-29 23:40:55488
Tim van der Lippe0efccf02020-02-12 15:15:39489 const inlineButton = UI.UIUtils.createInlineButton(landingRecordButton);
Rayan Kansof402ef32019-08-12 13:05:18490 inlineButton.classList.add('background-service-record-inline-button');
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01491 centered.createChild('p').appendChild(i18n.i18n.getFormatLocalizedString(
492 str_, UIStrings.clickTheRecordButtonSOrHitSTo, {PH1: inlineButton, PH2: recordKey}));
Rayan Kanso42c0f9e2019-09-02 12:21:09493
494 centered.appendChild(this._createLearnMoreLink());
Rayan Kansoc0bfdd82019-04-24 12:32:22495 }
Rayan Kansob451b4f2019-04-04 23:12:11496
497 this._preview.show(this._previewPanel.contentElement);
498 }
Rayan Kansob852ba82019-04-08 13:48:07499
500 /**
501 * Saves all currently displayed events in a file (JSON format).
502 */
503 async _saveToFile() {
Simon Zünd2c704cd2020-06-04 09:08:35504 const fileName = `${this._serviceName}-${Platform.DateUtilities.toISO8601Compact(new Date())}.json`;
Tim van der Lippe0efccf02020-02-12 15:15:39505 const stream = new Bindings.FileUtils.FileOutputStream();
Rayan Kansob852ba82019-04-08 13:48:07506
507 const accepted = await stream.open(fileName);
Tim van der Lippe1d6e57a2019-09-30 11:55:34508 if (!accepted) {
Rayan Kansob852ba82019-04-08 13:48:07509 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34510 }
Rayan Kansob852ba82019-04-08 13:48:07511
512 const events = this._model.getEvents(this._serviceName).filter(event => this._acceptEvent(event));
513 await stream.write(JSON.stringify(events, undefined, 2));
514 stream.close();
515 }
Tim van der Lippe097cdec2020-01-06 14:44:17516}
Rayan Kanso3252d5e2019-03-27 11:37:24517
Alex Rudenko60a3e942020-11-02 12:27:57518/**
519 * @extends {DataGrid.DataGrid.DataGridNode<!Object<string, string|number>>}
520 */
Tim van der Lippe0efccf02020-02-12 15:15:39521export class EventDataNode extends DataGrid.DataGrid.DataGridNode {
Rayan Kanso3252d5e2019-03-27 11:37:24522 /**
Alex Rudenko60a3e942020-11-02 12:27:57523 * @param {!Object<string, string|number>} data
Rayan Kansoaca06e72019-03-27 11:57:06524 * @param {!Array<!Protocol.BackgroundService.EventMetadata>} eventMetadata
Rayan Kanso3252d5e2019-03-27 11:37:24525 */
Rayan Kansoaca06e72019-03-27 11:57:06526 constructor(data, eventMetadata) {
527 super(data);
Rayan Kanso3252d5e2019-03-27 11:37:24528
529 /** @const {!Array<!Protocol.BackgroundService.EventMetadata>} */
Jack Franklin056c4002021-01-13 13:53:20530 this._eventMetadata = eventMetadata.sort((m1, m2) => Platform.StringUtilities.compare(m1.key, m2.key));
Rayan Kanso3252d5e2019-03-27 11:37:24531 }
532
533 /**
Tim van der Lippe0efccf02020-02-12 15:15:39534 * @return {!UI.Widget.VBox}
Rayan Kanso3252d5e2019-03-27 11:37:24535 */
Rayan Kansob451b4f2019-04-04 23:12:11536 createPreview() {
Tim van der Lippe0efccf02020-02-12 15:15:39537 const preview = new UI.Widget.VBox();
Rayan Kansoc0bfdd82019-04-24 12:32:22538 preview.element.classList.add('background-service-metadata');
539
540 for (const entry of this._eventMetadata) {
Tim van der Lippef49e2322020-05-01 15:03:09541 const div = document.createElement('div');
542 div.classList.add('background-service-metadata-entry');
Rayan Kansoc0bfdd82019-04-24 12:32:22543 div.createChild('div', 'background-service-metadata-name').textContent = entry.key + ': ';
Rayan Kanso4476ca52019-07-22 11:51:24544 if (entry.value) {
545 div.createChild('div', 'background-service-metadata-value source-code').textContent = entry.value;
546 } else {
547 div.createChild('div', 'background-service-metadata-value background-service-empty-value').textContent =
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01548 i18nString(UIStrings.empty);
Rayan Kanso4476ca52019-07-22 11:51:24549 }
Rayan Kansoc0bfdd82019-04-24 12:32:22550 preview.element.appendChild(div);
551 }
552
553 if (!preview.element.children.length) {
Tim van der Lippef49e2322020-05-01 15:03:09554 const div = document.createElement('div');
555 div.classList.add('background-service-metadata-entry');
Vidal Guillermo Diazleal Ortega0a997bb2021-02-09 04:33:01556 div.createChild('div', 'background-service-metadata-name').textContent =
557 i18nString(UIStrings.noMetadataForThisEvent);
Rayan Kansoc0bfdd82019-04-24 12:32:22558 preview.element.appendChild(div);
559 }
560
561 return preview;
Rayan Kansof40e3152019-03-11 13:49:43562 }
Tim van der Lippe097cdec2020-01-06 14:44:17563}
Rayan Kanso6156d222019-04-29 23:40:55564
Andres Olivares79578512021-02-02 00:27:49565/** @type {!ActionDelegate} */
566let actionDelegateInstance;
567
Rayan Kanso6156d222019-04-29 23:40:55568/**
Andres Olivares6ff6d042020-11-17 14:31:57569 * @implements {UI.ActionRegistration.ActionDelegate}
Rayan Kanso6156d222019-04-29 23:40:55570 */
Tim van der Lippe097cdec2020-01-06 14:44:17571export class ActionDelegate {
Rayan Kanso6156d222019-04-29 23:40:55572 /**
Andres Olivares79578512021-02-02 00:27:49573 * @param {{forceNew: ?boolean}} opts
574 */
575 static instance(opts = {forceNew: null}) {
576 const {forceNew} = opts;
577 if (!actionDelegateInstance || forceNew) {
578 actionDelegateInstance = new ActionDelegate();
579 }
580
581 return actionDelegateInstance;
582 }
583
584 /**
Rayan Kanso6156d222019-04-29 23:40:55585 * @override
Tim van der Lippe0efccf02020-02-12 15:15:39586 * @param {!UI.Context.Context} context
Rayan Kanso6156d222019-04-29 23:40:55587 * @param {string} actionId
588 * @return {boolean}
589 */
590 handleAction(context, actionId) {
Tim van der Lippe097cdec2020-01-06 14:44:17591 const view = context.flavor(BackgroundServiceView);
Rayan Kanso6156d222019-04-29 23:40:55592 switch (actionId) {
Alex Rudenko60a3e942020-11-02 12:27:57593 case 'background-service.toggle-recording': {
594 if (!view) {
595 throw new Error('BackgroundServiceView instance is missing');
596 }
Rayan Kanso6156d222019-04-29 23:40:55597 view._toggleRecording();
598 return true;
Alex Rudenko60a3e942020-11-02 12:27:57599 }
Rayan Kanso6156d222019-04-29 23:40:55600 }
601 return false;
602 }
Tim van der Lippe097cdec2020-01-06 14:44:17603}
Tim van der Lippeff5ad472020-02-17 12:35:09604
605/**
606 * @typedef {!{isRecording: boolean, serviceName: !Protocol.BackgroundService.ServiceName}}
607 */
Alex Rudenko60a3e942020-11-02 12:27:57608// @ts-ignore typedef
Tim van der Lippeff5ad472020-02-17 12:35:09609export let RecordingState;
610
611/**
612 * @typedef {{
613 * id: number,
614 * timestamp: string,
615 * origin: string,
616 * swScope: string,
617 * eventName: string,
618 * instanceId: string,
619 * }}
620 */
Alex Rudenko60a3e942020-11-02 12:27:57621// @ts-ignore typedef
Tim van der Lippeff5ad472020-02-17 12:35:09622export let EventData;