blob: c2344b9d07e4adec6db67023aecbb8a65b1cdfee [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';
Simon Zünd2c704cd2020-06-04 09:08:358import * as Platform from '../platform/platform.js';
Tim van der Lippe0efccf02020-02-12 15:15:399import * as SDK from '../sdk/sdk.js';
10import * as UI from '../ui/ui.js';
11
Paul Lewisddf58342020-01-15 14:18:0712import {BackgroundServiceModel, Events} from './BackgroundServiceModel.js'; // eslint-disable-line no-unused-vars
13
Tim van der Lippe0efccf02020-02-12 15:15:3914export class BackgroundServiceView extends UI.Widget.VBox {
Rayan Kanso68904202019-02-21 14:16:2515 /**
Rayan Kansoc0bfdd82019-04-24 12:32:2216 * @param {string} serviceName The name of the background service.
17 * @return {string} The UI String to display.
18 */
19 static getUIString(serviceName) {
20 switch (serviceName) {
21 case Protocol.BackgroundService.ServiceName.BackgroundFetch:
22 return ls`Background Fetch`;
23 case Protocol.BackgroundService.ServiceName.BackgroundSync:
24 return ls`Background Sync`;
Fergus Dall0be4f4c2019-05-21 00:01:2925 case Protocol.BackgroundService.ServiceName.PushMessaging:
26 return ls`Push Messaging`;
27 case Protocol.BackgroundService.ServiceName.Notifications:
28 return ls`Notifications`;
Rayan Kanso8d7918a2019-07-03 21:03:3829 case Protocol.BackgroundService.ServiceName.PaymentHandler:
30 return ls`Payment Handler`;
Rayan Kanso54809672019-07-24 18:40:2831 case Protocol.BackgroundService.ServiceName.PeriodicBackgroundSync:
32 return ls`Periodic Background Sync`;
Rayan Kansoc0bfdd82019-04-24 12:32:2233 default:
34 return '';
35 }
36 }
37
38 /**
Rayan Kanso8fe8ee22019-03-04 14:58:4639 * @param {!Protocol.BackgroundService.ServiceName} serviceName
Paul Lewisddf58342020-01-15 14:18:0740 * @param {!BackgroundServiceModel} model
Rayan Kanso68904202019-02-21 14:16:2541 */
Rayan Kanso8fe8ee22019-03-04 14:58:4642 constructor(serviceName, model) {
Rayan Kanso68904202019-02-21 14:16:2543 super(true);
Jack Franklin71519f82020-11-03 12:08:5944 this.registerRequiredCSS('resources/backgroundServiceView.css', {enableLegacyPatching: true});
45 this.registerRequiredCSS('ui/emptyWidget.css', {enableLegacyPatching: true});
Rayan Kanso68904202019-02-21 14:16:2546
Rayan Kanso8fe8ee22019-03-04 14:58:4647 /** @const {!Protocol.BackgroundService.ServiceName} */
Rayan Kanso68904202019-02-21 14:16:2548 this._serviceName = serviceName;
49
Paul Lewisddf58342020-01-15 14:18:0750 /** @const {!BackgroundServiceModel} */
Rayan Kanso8fe8ee22019-03-04 14:58:4651 this._model = model;
Paul Lewisddf58342020-01-15 14:18:0752 this._model.addEventListener(Events.RecordingStateChanged, this._onRecordingStateChanged, this);
53 this._model.addEventListener(Events.BackgroundServiceEventReceived, this._onEventReceived, this);
Rayan Kanso8fe8ee22019-03-04 14:58:4654 this._model.enable(this._serviceName);
55
Tim van der Lippe0efccf02020-02-12 15:15:3956 /** @const {?SDK.ServiceWorkerManager.ServiceWorkerManager} */
57 this._serviceWorkerManager = this._model.target().model(SDK.ServiceWorkerManager.ServiceWorkerManager);
Rayan Kansoaca06e72019-03-27 11:57:0658
Tim van der Lippe0efccf02020-02-12 15:15:3959 /** @const {?SDK.SecurityOriginManager.SecurityOriginManager} */
60 this._securityOriginManager = this._model.target().model(SDK.SecurityOriginManager.SecurityOriginManager);
Alex Rudenko60a3e942020-11-02 12:27:5761 if (!this._securityOriginManager) {
62 throw new Error('SecurityOriginManager instance is missing');
63 }
Rayan Kansoaca06e72019-03-27 11:57:0664 this._securityOriginManager.addEventListener(
65 SDK.SecurityOriginManager.Events.MainSecurityOriginChanged, () => this._onOriginChanged());
66
Rayan Kansocc02ea32019-05-02 21:26:5267
Alex Rudenko60a3e942020-11-02 12:27:5768 /** @type {!UI.Action.Action} */
Paul Lewis24cb7402020-01-24 13:46:3569 this._recordAction =
Tim van der Lippe177c0b22020-08-19 14:56:0270 /** @type {!UI.Action.Action} */ (
71 UI.ActionRegistry.ActionRegistry.instance().action('background-service.toggle-recording'));
Rayan Kanso8fe8ee22019-03-04 14:58:4672
Alex Rudenko60a3e942020-11-02 12:27:5773 /**
74 * Initialised in the _setupToolbar() call below.
75 * @type {!UI.Toolbar.ToolbarToggle}
76 */
77 this._recordButton;
Rayan Kansoaca06e72019-03-27 11:57:0678
Alex Rudenko60a3e942020-11-02 12:27:5779 /**
80 * Initialised in the _setupToolbar() call below.
81 * @type {!UI.Toolbar.ToolbarCheckbox}
82 */
83 this._originCheckbox;
84
85 /**
86 * Initialised in the _setupToolbar() call below.
87 * @type {!UI.Toolbar.ToolbarButton}
88 */
89 this._saveButton;
Rayan Kansob852ba82019-04-08 13:48:0790
Tim van der Lippe0efccf02020-02-12 15:15:3991 /** @const {!UI.Toolbar.Toolbar} */
92 this._toolbar = new UI.Toolbar.Toolbar('background-service-toolbar', this.contentElement);
Rayan Kanso68904202019-02-21 14:16:2593 this._setupToolbar();
Rayan Kanso3252d5e2019-03-27 11:37:2494
Rayan Kansob451b4f2019-04-04 23:12:1195 /**
96 * This will contain the DataGrid for displaying events, and a panel at the bottom for showing
97 * extra metadata related to the selected event.
Tim van der Lippe0efccf02020-02-12 15:15:3998 * @const {!UI.SplitWidget.SplitWidget}
Rayan Kansob451b4f2019-04-04 23:12:1199 */
Tim van der Lippe0efccf02020-02-12 15:15:39100 this._splitWidget = new UI.SplitWidget.SplitWidget(/* isVertical= */ false, /* secondIsSidebar= */ true);
Rayan Kansob451b4f2019-04-04 23:12:11101 this._splitWidget.show(this.contentElement);
102
Tim van der Lippe0efccf02020-02-12 15:15:39103 /** @const {!DataGrid.DataGrid.DataGridImpl} */
Rayan Kanso3252d5e2019-03-27 11:37:24104 this._dataGrid = this._createDataGrid();
Rayan Kansob451b4f2019-04-04 23:12:11105
Tim van der Lippe0efccf02020-02-12 15:15:39106 /** @const {!UI.Widget.VBox} */
107 this._previewPanel = new UI.Widget.VBox();
Rayan Kansob451b4f2019-04-04 23:12:11108
Tim van der Lippe097cdec2020-01-06 14:44:17109 /** @type {?EventDataNode} */
Rayan Kansoc0bfdd82019-04-24 12:32:22110 this._selectedEventNode = null;
111
Tim van der Lippe0efccf02020-02-12 15:15:39112 /** @type {?UI.Widget.Widget} */
Rayan Kansob451b4f2019-04-04 23:12:11113 this._preview = null;
114
115 this._splitWidget.setMainWidget(this._dataGrid.asWidget());
116 this._splitWidget.setSidebarWidget(this._previewPanel);
117
118 this._showPreview(null);
Rayan Kanso68904202019-02-21 14:16:25119 }
120
121 /**
122 * Creates the toolbar UI element.
123 */
Rayan Kanso8fe8ee22019-03-04 14:58:46124 async _setupToolbar() {
Alex Rudenko60a3e942020-11-02 12:27:57125 this._recordButton =
126 /** @type {!UI.Toolbar.ToolbarToggle} */ (UI.Toolbar.Toolbar.createActionButton(this._recordAction));
Rayan Kanso8fe8ee22019-03-04 14:58:46127 this._toolbar.appendToolbarItem(this._recordButton);
Rayan Kanso68904202019-02-21 14:16:25128
Tim van der Lippe0efccf02020-02-12 15:15:39129 const clearButton = new UI.Toolbar.ToolbarButton(ls`Clear`, 'largeicon-clear');
130 clearButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, () => this._clearEvents());
Rayan Kanso68904202019-02-21 14:16:25131 this._toolbar.appendToolbarItem(clearButton);
132
133 this._toolbar.appendSeparator();
134
Tim van der Lippe0efccf02020-02-12 15:15:39135 this._saveButton = new UI.Toolbar.ToolbarButton(ls`Save events`, 'largeicon-download');
Tim van der Lippe37a35ff2020-03-03 13:49:02136 this._saveButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, event => {
137 this._saveToFile();
138 });
Rayan Kansob852ba82019-04-08 13:48:07139 this._saveButton.setEnabled(false);
140 this._toolbar.appendToolbarItem(this._saveButton);
Rayan Kansoc0bfdd82019-04-24 12:32:22141
142 this._toolbar.appendSeparator();
143
Tim van der Lippe0efccf02020-02-12 15:15:39144 this._originCheckbox = new UI.Toolbar.ToolbarCheckbox(
Rayan Kansoe9d4f692020-02-05 13:46:10145 ls`Show events from other domains`, ls`Show events from other domains`, () => this._refreshView());
Rayan Kansoc0bfdd82019-04-24 12:32:22146 this._toolbar.appendToolbarItem(this._originCheckbox);
Rayan Kanso68904202019-02-21 14:16:25147 }
Rayan Kanso8fe8ee22019-03-04 14:58:46148
149 /**
Rayan Kansob451b4f2019-04-04 23:12:11150 * Displays all available events in the grid.
151 */
152 _refreshView() {
153 this._clearView();
154 const events = this._model.getEvents(this._serviceName).filter(event => this._acceptEvent(event));
Tim van der Lippe1d6e57a2019-09-30 11:55:34155 for (const event of events) {
Rayan Kansob451b4f2019-04-04 23:12:11156 this._addEvent(event);
Tim van der Lippe1d6e57a2019-09-30 11:55:34157 }
Rayan Kansob451b4f2019-04-04 23:12:11158 }
159
160 /**
161 * Clears the grid and panel.
162 */
163 _clearView() {
Rayan Kansoc0bfdd82019-04-24 12:32:22164 this._selectedEventNode = null;
Rayan Kansob451b4f2019-04-04 23:12:11165 this._dataGrid.rootNode().removeChildren();
Rayan Kansob852ba82019-04-08 13:48:07166 this._saveButton.setEnabled(false);
Rayan Kansoc0bfdd82019-04-24 12:32:22167 this._showPreview(null);
Rayan Kansob451b4f2019-04-04 23:12:11168 }
169
170 /**
Rayan Kanso8fe8ee22019-03-04 14:58:46171 * Called when the `Toggle Record` button is clicked.
172 */
173 _toggleRecording() {
174 this._model.setRecording(!this._recordButton.toggled(), this._serviceName);
175 }
176
177 /**
Rayan Kanso3252d5e2019-03-27 11:37:24178 * Called when the `Clear` button is clicked.
179 */
Rayan Kansob451b4f2019-04-04 23:12:11180 _clearEvents() {
Rayan Kanso3252d5e2019-03-27 11:37:24181 this._model.clearEvents(this._serviceName);
182 this._clearView();
183 }
184
185 /**
Tim van der Lippec02a97c2020-02-14 14:39:27186 * @param {!Common.EventTarget.EventTargetEvent} event
Rayan Kanso8fe8ee22019-03-04 14:58:46187 */
188 _onRecordingStateChanged(event) {
Tim van der Lippeff5ad472020-02-17 12:35:09189 const state = /** @type {!RecordingState} */ (event.data);
Tim van der Lippe1d6e57a2019-09-30 11:55:34190 if (state.serviceName !== this._serviceName) {
Rayan Kanso8fe8ee22019-03-04 14:58:46191 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34192 }
Rayan Kansoc0bfdd82019-04-24 12:32:22193
Tim van der Lippe1d6e57a2019-09-30 11:55:34194 if (state.isRecording === this._recordButton.toggled()) {
Rayan Kansoc0bfdd82019-04-24 12:32:22195 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34196 }
Rayan Kansoc0bfdd82019-04-24 12:32:22197
Rayan Kanso0b30aba2019-05-17 13:39:59198 this._recordButton.setToggled(state.isRecording);
Christy Chen13a12ff2020-08-20 07:43:26199 this._updateRecordButtonTooltip();
Rayan Kansoc0bfdd82019-04-24 12:32:22200 this._showPreview(this._selectedEventNode);
Rayan Kanso8fe8ee22019-03-04 14:58:46201 }
Rayan Kansof40e3152019-03-11 13:49:43202
Christy Chen13a12ff2020-08-20 07:43:26203 _updateRecordButtonTooltip() {
204 const buttonTooltip = this._recordButton.toggled() ? ls`Stop recording events` : ls`Start recording events`;
205 this._recordButton.setTitle(buttonTooltip, 'background-service.toggle-recording');
206 }
207
Rayan Kansof40e3152019-03-11 13:49:43208 /**
Tim van der Lippec02a97c2020-02-14 14:39:27209 * @param {!Common.EventTarget.EventTargetEvent} event
Rayan Kansof40e3152019-03-11 13:49:43210 */
211 _onEventReceived(event) {
212 const serviceEvent = /** @type {!Protocol.BackgroundService.BackgroundServiceEvent} */ (event.data);
Tim van der Lippe1d6e57a2019-09-30 11:55:34213 if (!this._acceptEvent(serviceEvent)) {
Rayan Kansof40e3152019-03-11 13:49:43214 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34215 }
Rayan Kanso3252d5e2019-03-27 11:37:24216 this._addEvent(serviceEvent);
217 }
218
Rayan Kansoaca06e72019-03-27 11:57:06219 _onOriginChanged() {
220 // No need to refresh the view if we are already showing all events.
Tim van der Lippe1d6e57a2019-09-30 11:55:34221 if (this._originCheckbox.checked()) {
Rayan Kansoaca06e72019-03-27 11:57:06222 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34223 }
Rayan Kansoaca06e72019-03-27 11:57:06224 this._refreshView();
225 }
226
Rayan Kanso3252d5e2019-03-27 11:37:24227 /**
228 * @param {!Protocol.BackgroundService.BackgroundServiceEvent} serviceEvent
229 */
230 _addEvent(serviceEvent) {
Rayan Kansoaca06e72019-03-27 11:57:06231 const data = this._createEventData(serviceEvent);
Tim van der Lippe097cdec2020-01-06 14:44:17232 const dataNode = new EventDataNode(data, serviceEvent.eventMetadata);
Rayan Kanso3252d5e2019-03-27 11:37:24233 this._dataGrid.rootNode().appendChild(dataNode);
Rayan Kansob852ba82019-04-08 13:48:07234
Rayan Kansoc0bfdd82019-04-24 12:32:22235 if (this._dataGrid.rootNode().children.length === 1) {
236 this._saveButton.setEnabled(true);
237 this._showPreview(this._selectedEventNode);
238 }
Rayan Kanso3252d5e2019-03-27 11:37:24239 }
240
241 /**
Alex Rudenko60a3e942020-11-02 12:27:57242 * @return {!DataGrid.DataGrid.DataGridImpl<!Object<string, string|number>>}
Rayan Kanso3252d5e2019-03-27 11:37:24243 */
244 _createDataGrid() {
Tim van der Lippe9a9aba82020-02-14 14:52:29245 const columns = /** @type {!Array<!DataGrid.DataGrid.ColumnDescriptor>} */ ([
Rayan Kansob852ba82019-04-08 13:48:07246 {id: 'id', title: ls`#`, weight: 1},
247 {id: 'timestamp', title: ls`Timestamp`, weight: 8},
Rayan Kansoc0bfdd82019-04-24 12:32:22248 {id: 'eventName', title: ls`Event`, weight: 10},
Rayan Kansob852ba82019-04-08 13:48:07249 {id: 'origin', title: ls`Origin`, weight: 10},
Rayan Kansocc02ea32019-05-02 21:26:52250 {id: 'swScope', title: ls`SW Scope`, weight: 2},
Rayan Kansob852ba82019-04-08 13:48:07251 {id: 'instanceId', title: ls`Instance ID`, weight: 10},
Rayan Kanso3252d5e2019-03-27 11:37:24252 ]);
Alex Rudenko60a3e942020-11-02 12:27:57253 const dataGrid = new DataGrid.DataGrid.DataGridImpl({
254 displayName: ls`Background Services`,
255 columns,
256 editCallback: undefined,
257 refreshCallback: undefined,
258 deleteCallback: undefined
259 });
Rayan Kanso3252d5e2019-03-27 11:37:24260 dataGrid.setStriped(true);
Rayan Kansob451b4f2019-04-04 23:12:11261
262 dataGrid.addEventListener(
Tim van der Lippe097cdec2020-01-06 14:44:17263 DataGrid.DataGrid.Events.SelectedNode, event => this._showPreview(/** @type {!EventDataNode} */ (event.data)));
Rayan Kansob451b4f2019-04-04 23:12:11264
Rayan Kanso3252d5e2019-03-27 11:37:24265 return dataGrid;
266 }
267
268 /**
Rayan Kansoaca06e72019-03-27 11:57:06269 * Creates the data object to pass to the DataGrid Node.
270 * @param {!Protocol.BackgroundService.BackgroundServiceEvent} serviceEvent
Tim van der Lippeff5ad472020-02-17 12:35:09271 * @return {!EventData}
Rayan Kansoaca06e72019-03-27 11:57:06272 */
273 _createEventData(serviceEvent) {
Rayan Kansocc02ea32019-05-02 21:26:52274 let swScope = '';
Rayan Kansoaca06e72019-03-27 11:57:06275
Rayan Kansocc02ea32019-05-02 21:26:52276 // Try to get the scope of the Service Worker registration to be more user-friendly.
Alex Rudenko60a3e942020-11-02 12:27:57277 const registration = this._serviceWorkerManager ?
278 this._serviceWorkerManager.registrations().get(serviceEvent.serviceWorkerRegistrationId) :
279 undefined;
Tim van der Lippe1d6e57a2019-09-30 11:55:34280 if (registration) {
Rayan Kansocc02ea32019-05-02 21:26:52281 swScope = registration.scopeURL.substr(registration.securityOrigin.length);
Tim van der Lippe1d6e57a2019-09-30 11:55:34282 }
Rayan Kansoaca06e72019-03-27 11:57:06283
284 return {
Rayan Kansoc79a8bb2019-05-29 21:08:38285 id: this._dataGrid.rootNode().children.length + 1,
Tim van der Lippe0efccf02020-02-12 15:15:39286 timestamp: UI.UIUtils.formatTimestamp(serviceEvent.timestamp * 1000, /* full= */ true),
Rayan Kansoaca06e72019-03-27 11:57:06287 origin: serviceEvent.origin,
Rayan Kansocc02ea32019-05-02 21:26:52288 swScope,
Rayan Kansoaca06e72019-03-27 11:57:06289 eventName: serviceEvent.eventName,
290 instanceId: serviceEvent.instanceId,
291 };
292 }
293
294 /**
Rayan Kanso3252d5e2019-03-27 11:37:24295 * Filtration function to know whether event should be shown or not.
296 * @param {!Protocol.BackgroundService.BackgroundServiceEvent} event
297 * @return {boolean}
298 */
299 _acceptEvent(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34300 if (event.service !== this._serviceName) {
Rayan Kansoaca06e72019-03-27 11:57:06301 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34302 }
Rayan Kansoaca06e72019-03-27 11:57:06303
Tim van der Lippe1d6e57a2019-09-30 11:55:34304 if (this._originCheckbox.checked()) {
Rayan Kansoaca06e72019-03-27 11:57:06305 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:34306 }
Rayan Kansoaca06e72019-03-27 11:57:06307
308 // Trim the trailing '/'.
309 const origin = event.origin.substr(0, event.origin.length - 1);
310
311 return this._securityOriginManager.securityOrigins().includes(origin);
Rayan Kanso3252d5e2019-03-27 11:37:24312 }
Rayan Kansob451b4f2019-04-04 23:12:11313
314 /**
Rayan Kanso42c0f9e2019-09-02 12:21:09315 * @return {!Element}
316 */
317 _createLearnMoreLink() {
318 let url =
319 'https://developers.google.com/web/tools/chrome-devtools/javascript/background-services?utm_source=devtools';
320
321 switch (this._serviceName) {
322 case Protocol.BackgroundService.ServiceName.BackgroundFetch:
323 url += '#fetch';
324 break;
325 case Protocol.BackgroundService.ServiceName.BackgroundSync:
326 url += '#sync';
327 break;
328 case Protocol.BackgroundService.ServiceName.PushMessaging:
329 url += '#push';
330 break;
331 case Protocol.BackgroundService.ServiceName.Notifications:
332 url += '#notifications';
333 break;
334 default:
335 break;
336 }
337
Tim van der Lippe0efccf02020-02-12 15:15:39338 return UI.XLink.XLink.create(url, ls`Learn more`);
Rayan Kanso42c0f9e2019-09-02 12:21:09339 }
340
341 /**
Tim van der Lippe097cdec2020-01-06 14:44:17342 * @param {?EventDataNode} dataNode
Rayan Kansob451b4f2019-04-04 23:12:11343 */
344 _showPreview(dataNode) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34345 if (this._selectedEventNode && this._selectedEventNode === dataNode) {
Rayan Kansoc0bfdd82019-04-24 12:32:22346 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34347 }
Rayan Kansoc0bfdd82019-04-24 12:32:22348
349 this._selectedEventNode = dataNode;
350
Tim van der Lippe1d6e57a2019-09-30 11:55:34351 if (this._preview) {
Rayan Kansob451b4f2019-04-04 23:12:11352 this._preview.detach();
Tim van der Lippe1d6e57a2019-09-30 11:55:34353 }
Rayan Kansob451b4f2019-04-04 23:12:11354
Rayan Kansoc0bfdd82019-04-24 12:32:22355 if (this._selectedEventNode) {
356 this._preview = this._selectedEventNode.createPreview();
Rayan Kanso4476ca52019-07-22 11:51:24357 this._preview.show(this._previewPanel.contentElement);
358 return;
359 }
360
Tim van der Lippe0efccf02020-02-12 15:15:39361 this._preview = new UI.Widget.VBox();
Rayan Kanso4476ca52019-07-22 11:51:24362 this._preview.contentElement.classList.add('background-service-preview', 'fill');
363 const centered = this._preview.contentElement.createChild('div');
364
365 if (this._dataGrid.rootNode().children.length) {
Rayan Kansoc0bfdd82019-04-24 12:32:22366 // Inform users that grid entries are clickable.
Rayan Kanso4476ca52019-07-22 11:51:24367 centered.createChild('p').textContent = ls`Select an entry to view metadata`;
Rayan Kansoc0bfdd82019-04-24 12:32:22368 } else if (this._recordButton.toggled()) {
369 // Inform users that we are recording/waiting for events.
Tim van der Lippe097cdec2020-01-06 14:44:17370 const featureName = BackgroundServiceView.getUIString(this._serviceName);
Rayan Kanso4476ca52019-07-22 11:51:24371 centered.createChild('p').textContent = ls`Recording ${featureName} activity...`;
372 centered.createChild('p').textContent =
373 ls`DevTools will record all ${featureName} activity for up to 3 days, even when closed.`;
Rayan Kansoc0bfdd82019-04-24 12:32:22374 } else {
Tim van der Lippe0efccf02020-02-12 15:15:39375 const landingRecordButton = UI.Toolbar.Toolbar.createActionButton(this._recordAction);
Rayan Kansoc0bfdd82019-04-24 12:32:22376
Tim van der Lippef49e2322020-05-01 15:03:09377 const recordKey = document.createElement('b');
378 recordKey.classList.add('background-service-shortcut');
Tim van der Lippe9c9fb122020-09-08 15:06:17379 recordKey.textContent = UI.ShortcutRegistry.ShortcutRegistry.instance()
380 .shortcutsForAction('background-service.toggle-recording')[0]
381 .title();
Rayan Kanso6156d222019-04-29 23:40:55382
Tim van der Lippe0efccf02020-02-12 15:15:39383 const inlineButton = UI.UIUtils.createInlineButton(landingRecordButton);
Rayan Kansof402ef32019-08-12 13:05:18384 inlineButton.classList.add('background-service-record-inline-button');
Tim van der Lippe0efccf02020-02-12 15:15:39385 centered.createChild('p').appendChild(UI.UIUtils.formatLocalized(
386 'Click the record button %s or hit %s to start recording.', [inlineButton, recordKey]));
Rayan Kanso42c0f9e2019-09-02 12:21:09387
388 centered.appendChild(this._createLearnMoreLink());
Rayan Kansoc0bfdd82019-04-24 12:32:22389 }
Rayan Kansob451b4f2019-04-04 23:12:11390
391 this._preview.show(this._previewPanel.contentElement);
392 }
Rayan Kansob852ba82019-04-08 13:48:07393
394 /**
395 * Saves all currently displayed events in a file (JSON format).
396 */
397 async _saveToFile() {
Simon Zünd2c704cd2020-06-04 09:08:35398 const fileName = `${this._serviceName}-${Platform.DateUtilities.toISO8601Compact(new Date())}.json`;
Tim van der Lippe0efccf02020-02-12 15:15:39399 const stream = new Bindings.FileUtils.FileOutputStream();
Rayan Kansob852ba82019-04-08 13:48:07400
401 const accepted = await stream.open(fileName);
Tim van der Lippe1d6e57a2019-09-30 11:55:34402 if (!accepted) {
Rayan Kansob852ba82019-04-08 13:48:07403 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34404 }
Rayan Kansob852ba82019-04-08 13:48:07405
406 const events = this._model.getEvents(this._serviceName).filter(event => this._acceptEvent(event));
407 await stream.write(JSON.stringify(events, undefined, 2));
408 stream.close();
409 }
Tim van der Lippe097cdec2020-01-06 14:44:17410}
Rayan Kanso3252d5e2019-03-27 11:37:24411
Alex Rudenko60a3e942020-11-02 12:27:57412/**
413 * @extends {DataGrid.DataGrid.DataGridNode<!Object<string, string|number>>}
414 */
Tim van der Lippe0efccf02020-02-12 15:15:39415export class EventDataNode extends DataGrid.DataGrid.DataGridNode {
Rayan Kanso3252d5e2019-03-27 11:37:24416 /**
Alex Rudenko60a3e942020-11-02 12:27:57417 * @param {!Object<string, string|number>} data
Rayan Kansoaca06e72019-03-27 11:57:06418 * @param {!Array<!Protocol.BackgroundService.EventMetadata>} eventMetadata
Rayan Kanso3252d5e2019-03-27 11:37:24419 */
Rayan Kansoaca06e72019-03-27 11:57:06420 constructor(data, eventMetadata) {
421 super(data);
Rayan Kanso3252d5e2019-03-27 11:37:24422
423 /** @const {!Array<!Protocol.BackgroundService.EventMetadata>} */
Rayan Kansoc79a8bb2019-05-29 21:08:38424 this._eventMetadata = eventMetadata.sort((m1, m2) => m1.key.compareTo(m2.key));
Rayan Kanso3252d5e2019-03-27 11:37:24425 }
426
427 /**
Tim van der Lippe0efccf02020-02-12 15:15:39428 * @return {!UI.Widget.VBox}
Rayan Kanso3252d5e2019-03-27 11:37:24429 */
Rayan Kansob451b4f2019-04-04 23:12:11430 createPreview() {
Tim van der Lippe0efccf02020-02-12 15:15:39431 const preview = new UI.Widget.VBox();
Rayan Kansoc0bfdd82019-04-24 12:32:22432 preview.element.classList.add('background-service-metadata');
433
434 for (const entry of this._eventMetadata) {
Tim van der Lippef49e2322020-05-01 15:03:09435 const div = document.createElement('div');
436 div.classList.add('background-service-metadata-entry');
Rayan Kansoc0bfdd82019-04-24 12:32:22437 div.createChild('div', 'background-service-metadata-name').textContent = entry.key + ': ';
Rayan Kanso4476ca52019-07-22 11:51:24438 if (entry.value) {
439 div.createChild('div', 'background-service-metadata-value source-code').textContent = entry.value;
440 } else {
441 div.createChild('div', 'background-service-metadata-value background-service-empty-value').textContent =
442 ls`empty`;
443 }
Rayan Kansoc0bfdd82019-04-24 12:32:22444 preview.element.appendChild(div);
445 }
446
447 if (!preview.element.children.length) {
Tim van der Lippef49e2322020-05-01 15:03:09448 const div = document.createElement('div');
449 div.classList.add('background-service-metadata-entry');
Rayan Kansoc0bfdd82019-04-24 12:32:22450 div.createChild('div', 'background-service-metadata-name').textContent = ls`No metadata for this event`;
451 preview.element.appendChild(div);
452 }
453
454 return preview;
Rayan Kansof40e3152019-03-11 13:49:43455 }
Tim van der Lippe097cdec2020-01-06 14:44:17456}
Rayan Kanso6156d222019-04-29 23:40:55457
458/**
Tim van der Lippe0efccf02020-02-12 15:15:39459 * @implements {UI.ActionDelegate.ActionDelegate}
Rayan Kanso6156d222019-04-29 23:40:55460 * @unrestricted
461 */
Tim van der Lippe097cdec2020-01-06 14:44:17462export class ActionDelegate {
Rayan Kanso6156d222019-04-29 23:40:55463 /**
464 * @override
Tim van der Lippe0efccf02020-02-12 15:15:39465 * @param {!UI.Context.Context} context
Rayan Kanso6156d222019-04-29 23:40:55466 * @param {string} actionId
467 * @return {boolean}
468 */
469 handleAction(context, actionId) {
Tim van der Lippe097cdec2020-01-06 14:44:17470 const view = context.flavor(BackgroundServiceView);
Rayan Kanso6156d222019-04-29 23:40:55471 switch (actionId) {
Alex Rudenko60a3e942020-11-02 12:27:57472 case 'background-service.toggle-recording': {
473 if (!view) {
474 throw new Error('BackgroundServiceView instance is missing');
475 }
Rayan Kanso6156d222019-04-29 23:40:55476 view._toggleRecording();
477 return true;
Alex Rudenko60a3e942020-11-02 12:27:57478 }
Rayan Kanso6156d222019-04-29 23:40:55479 }
480 return false;
481 }
Tim van der Lippe097cdec2020-01-06 14:44:17482}
Tim van der Lippeff5ad472020-02-17 12:35:09483
484/**
485 * @typedef {!{isRecording: boolean, serviceName: !Protocol.BackgroundService.ServiceName}}
486 */
Alex Rudenko60a3e942020-11-02 12:27:57487// @ts-ignore typedef
Tim van der Lippeff5ad472020-02-17 12:35:09488export let RecordingState;
489
490/**
491 * @typedef {{
492 * id: number,
493 * timestamp: string,
494 * origin: string,
495 * swScope: string,
496 * eventName: string,
497 * instanceId: string,
498 * }}
499 */
Alex Rudenko60a3e942020-11-02 12:27:57500// @ts-ignore typedef
Tim van der Lippeff5ad472020-02-17 12:35:09501export let EventData;