blob: 7a8af7fa10554928bf42c3bda9d204188cd74fec [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);
44 this.registerRequiredCSS('resources/backgroundServiceView.css');
Rayan Kanso6156d222019-04-29 23:40:5545 this.registerRequiredCSS('ui/emptyWidget.css');
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);
Rayan Kansoaca06e72019-03-27 11:57:0661 this._securityOriginManager.addEventListener(
62 SDK.SecurityOriginManager.Events.MainSecurityOriginChanged, () => this._onOriginChanged());
63
Rayan Kansocc02ea32019-05-02 21:26:5264
Tim van der Lippe0efccf02020-02-12 15:15:3965 /** @const {!UI.Action.Action} */
Paul Lewis24cb7402020-01-24 13:46:3566 this._recordAction =
Tim van der Lippe0efccf02020-02-12 15:15:3967 /** @type {!UI.Action.Action} */ (self.UI.actionRegistry.action('background-service.toggle-recording'));
68 /** @type {?UI.Toolbar.ToolbarButton} */
Rayan Kanso8fe8ee22019-03-04 14:58:4669 this._recordButton = null;
70
Tim van der Lippe0efccf02020-02-12 15:15:3971 /** @type {?UI.Toolbar.ToolbarCheckbox} */
Rayan Kansoaca06e72019-03-27 11:57:0672 this._originCheckbox = null;
73
Tim van der Lippe0efccf02020-02-12 15:15:3974 /** @type {?UI.Toolbar.ToolbarButton} */
Rayan Kansob852ba82019-04-08 13:48:0775 this._saveButton = null;
76
Tim van der Lippe0efccf02020-02-12 15:15:3977 /** @const {!UI.Toolbar.Toolbar} */
78 this._toolbar = new UI.Toolbar.Toolbar('background-service-toolbar', this.contentElement);
Rayan Kanso68904202019-02-21 14:16:2579 this._setupToolbar();
Rayan Kanso3252d5e2019-03-27 11:37:2480
Rayan Kansob451b4f2019-04-04 23:12:1181 /**
82 * This will contain the DataGrid for displaying events, and a panel at the bottom for showing
83 * extra metadata related to the selected event.
Tim van der Lippe0efccf02020-02-12 15:15:3984 * @const {!UI.SplitWidget.SplitWidget}
Rayan Kansob451b4f2019-04-04 23:12:1185 */
Tim van der Lippe0efccf02020-02-12 15:15:3986 this._splitWidget = new UI.SplitWidget.SplitWidget(/* isVertical= */ false, /* secondIsSidebar= */ true);
Rayan Kansob451b4f2019-04-04 23:12:1187 this._splitWidget.show(this.contentElement);
88
Tim van der Lippe0efccf02020-02-12 15:15:3989 /** @const {!DataGrid.DataGrid.DataGridImpl} */
Rayan Kanso3252d5e2019-03-27 11:37:2490 this._dataGrid = this._createDataGrid();
Rayan Kansob451b4f2019-04-04 23:12:1191
Tim van der Lippe0efccf02020-02-12 15:15:3992 /** @const {!UI.Widget.VBox} */
93 this._previewPanel = new UI.Widget.VBox();
Rayan Kansob451b4f2019-04-04 23:12:1194
Tim van der Lippe097cdec2020-01-06 14:44:1795 /** @type {?EventDataNode} */
Rayan Kansoc0bfdd82019-04-24 12:32:2296 this._selectedEventNode = null;
97
Tim van der Lippe0efccf02020-02-12 15:15:3998 /** @type {?UI.Widget.Widget} */
Rayan Kansob451b4f2019-04-04 23:12:1199 this._preview = null;
100
101 this._splitWidget.setMainWidget(this._dataGrid.asWidget());
102 this._splitWidget.setSidebarWidget(this._previewPanel);
103
104 this._showPreview(null);
Rayan Kanso68904202019-02-21 14:16:25105 }
106
107 /**
108 * Creates the toolbar UI element.
109 */
Rayan Kanso8fe8ee22019-03-04 14:58:46110 async _setupToolbar() {
Tim van der Lippe0efccf02020-02-12 15:15:39111 this._recordButton = UI.Toolbar.Toolbar.createActionButton(this._recordAction);
Rayan Kanso8fe8ee22019-03-04 14:58:46112 this._toolbar.appendToolbarItem(this._recordButton);
Rayan Kanso68904202019-02-21 14:16:25113
Tim van der Lippe0efccf02020-02-12 15:15:39114 const clearButton = new UI.Toolbar.ToolbarButton(ls`Clear`, 'largeicon-clear');
115 clearButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, () => this._clearEvents());
Rayan Kanso68904202019-02-21 14:16:25116 this._toolbar.appendToolbarItem(clearButton);
117
118 this._toolbar.appendSeparator();
119
Tim van der Lippe0efccf02020-02-12 15:15:39120 this._saveButton = new UI.Toolbar.ToolbarButton(ls`Save events`, 'largeicon-download');
Tim van der Lippe37a35ff2020-03-03 13:49:02121 this._saveButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, event => {
122 this._saveToFile();
123 });
Rayan Kansob852ba82019-04-08 13:48:07124 this._saveButton.setEnabled(false);
125 this._toolbar.appendToolbarItem(this._saveButton);
Rayan Kansoc0bfdd82019-04-24 12:32:22126
127 this._toolbar.appendSeparator();
128
Tim van der Lippe0efccf02020-02-12 15:15:39129 this._originCheckbox = new UI.Toolbar.ToolbarCheckbox(
Rayan Kansoe9d4f692020-02-05 13:46:10130 ls`Show events from other domains`, ls`Show events from other domains`, () => this._refreshView());
Rayan Kansoc0bfdd82019-04-24 12:32:22131 this._toolbar.appendToolbarItem(this._originCheckbox);
Rayan Kanso68904202019-02-21 14:16:25132 }
Rayan Kanso8fe8ee22019-03-04 14:58:46133
134 /**
Rayan Kansob451b4f2019-04-04 23:12:11135 * Displays all available events in the grid.
136 */
137 _refreshView() {
138 this._clearView();
139 const events = this._model.getEvents(this._serviceName).filter(event => this._acceptEvent(event));
Tim van der Lippe1d6e57a2019-09-30 11:55:34140 for (const event of events) {
Rayan Kansob451b4f2019-04-04 23:12:11141 this._addEvent(event);
Tim van der Lippe1d6e57a2019-09-30 11:55:34142 }
Rayan Kansob451b4f2019-04-04 23:12:11143 }
144
145 /**
146 * Clears the grid and panel.
147 */
148 _clearView() {
Rayan Kansoc0bfdd82019-04-24 12:32:22149 this._selectedEventNode = null;
Rayan Kansob451b4f2019-04-04 23:12:11150 this._dataGrid.rootNode().removeChildren();
Rayan Kansob852ba82019-04-08 13:48:07151 this._saveButton.setEnabled(false);
Rayan Kansoc0bfdd82019-04-24 12:32:22152 this._showPreview(null);
Rayan Kansob451b4f2019-04-04 23:12:11153 }
154
155 /**
Rayan Kanso8fe8ee22019-03-04 14:58:46156 * Called when the `Toggle Record` button is clicked.
157 */
158 _toggleRecording() {
159 this._model.setRecording(!this._recordButton.toggled(), this._serviceName);
160 }
161
162 /**
Rayan Kanso3252d5e2019-03-27 11:37:24163 * Called when the `Clear` button is clicked.
164 */
Rayan Kansob451b4f2019-04-04 23:12:11165 _clearEvents() {
Rayan Kanso3252d5e2019-03-27 11:37:24166 this._model.clearEvents(this._serviceName);
167 this._clearView();
168 }
169
170 /**
Tim van der Lippec02a97c2020-02-14 14:39:27171 * @param {!Common.EventTarget.EventTargetEvent} event
Rayan Kanso8fe8ee22019-03-04 14:58:46172 */
173 _onRecordingStateChanged(event) {
Tim van der Lippeff5ad472020-02-17 12:35:09174 const state = /** @type {!RecordingState} */ (event.data);
Tim van der Lippe1d6e57a2019-09-30 11:55:34175 if (state.serviceName !== this._serviceName) {
Rayan Kanso8fe8ee22019-03-04 14:58:46176 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34177 }
Rayan Kansoc0bfdd82019-04-24 12:32:22178
Tim van der Lippe1d6e57a2019-09-30 11:55:34179 if (state.isRecording === this._recordButton.toggled()) {
Rayan Kansoc0bfdd82019-04-24 12:32:22180 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34181 }
Rayan Kansoc0bfdd82019-04-24 12:32:22182
Rayan Kanso0b30aba2019-05-17 13:39:59183 this._recordButton.setToggled(state.isRecording);
Rayan Kansoc0bfdd82019-04-24 12:32:22184 this._showPreview(this._selectedEventNode);
Rayan Kanso8fe8ee22019-03-04 14:58:46185 }
Rayan Kansof40e3152019-03-11 13:49:43186
187 /**
Tim van der Lippec02a97c2020-02-14 14:39:27188 * @param {!Common.EventTarget.EventTargetEvent} event
Rayan Kansof40e3152019-03-11 13:49:43189 */
190 _onEventReceived(event) {
191 const serviceEvent = /** @type {!Protocol.BackgroundService.BackgroundServiceEvent} */ (event.data);
Tim van der Lippe1d6e57a2019-09-30 11:55:34192 if (!this._acceptEvent(serviceEvent)) {
Rayan Kansof40e3152019-03-11 13:49:43193 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34194 }
Rayan Kanso3252d5e2019-03-27 11:37:24195 this._addEvent(serviceEvent);
196 }
197
Rayan Kansoaca06e72019-03-27 11:57:06198 _onOriginChanged() {
199 // No need to refresh the view if we are already showing all events.
Tim van der Lippe1d6e57a2019-09-30 11:55:34200 if (this._originCheckbox.checked()) {
Rayan Kansoaca06e72019-03-27 11:57:06201 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34202 }
Rayan Kansoaca06e72019-03-27 11:57:06203 this._refreshView();
204 }
205
Rayan Kanso3252d5e2019-03-27 11:37:24206 /**
207 * @param {!Protocol.BackgroundService.BackgroundServiceEvent} serviceEvent
208 */
209 _addEvent(serviceEvent) {
Rayan Kansoaca06e72019-03-27 11:57:06210 const data = this._createEventData(serviceEvent);
Tim van der Lippe097cdec2020-01-06 14:44:17211 const dataNode = new EventDataNode(data, serviceEvent.eventMetadata);
Rayan Kanso3252d5e2019-03-27 11:37:24212 this._dataGrid.rootNode().appendChild(dataNode);
Rayan Kansob852ba82019-04-08 13:48:07213
Rayan Kansoc0bfdd82019-04-24 12:32:22214 if (this._dataGrid.rootNode().children.length === 1) {
215 this._saveButton.setEnabled(true);
216 this._showPreview(this._selectedEventNode);
217 }
Rayan Kanso3252d5e2019-03-27 11:37:24218 }
219
220 /**
Tim van der Lippe0efccf02020-02-12 15:15:39221 * @return {!DataGrid.DataGrid.DataGridImpl}
Rayan Kanso3252d5e2019-03-27 11:37:24222 */
223 _createDataGrid() {
Tim van der Lippe9a9aba82020-02-14 14:52:29224 const columns = /** @type {!Array<!DataGrid.DataGrid.ColumnDescriptor>} */ ([
Rayan Kansob852ba82019-04-08 13:48:07225 {id: 'id', title: ls`#`, weight: 1},
226 {id: 'timestamp', title: ls`Timestamp`, weight: 8},
Rayan Kansoc0bfdd82019-04-24 12:32:22227 {id: 'eventName', title: ls`Event`, weight: 10},
Rayan Kansob852ba82019-04-08 13:48:07228 {id: 'origin', title: ls`Origin`, weight: 10},
Rayan Kansocc02ea32019-05-02 21:26:52229 {id: 'swScope', title: ls`SW Scope`, weight: 2},
Rayan Kansob852ba82019-04-08 13:48:07230 {id: 'instanceId', title: ls`Instance ID`, weight: 10},
Rayan Kanso3252d5e2019-03-27 11:37:24231 ]);
Tim van der Lippe0efccf02020-02-12 15:15:39232 const dataGrid = new DataGrid.DataGrid.DataGridImpl({displayName: ls`Background Services`, columns});
Rayan Kanso3252d5e2019-03-27 11:37:24233 dataGrid.setStriped(true);
Rayan Kansob451b4f2019-04-04 23:12:11234
235 dataGrid.addEventListener(
Tim van der Lippe097cdec2020-01-06 14:44:17236 DataGrid.DataGrid.Events.SelectedNode, event => this._showPreview(/** @type {!EventDataNode} */ (event.data)));
Rayan Kansob451b4f2019-04-04 23:12:11237
Rayan Kanso3252d5e2019-03-27 11:37:24238 return dataGrid;
239 }
240
241 /**
Rayan Kansoaca06e72019-03-27 11:57:06242 * Creates the data object to pass to the DataGrid Node.
243 * @param {!Protocol.BackgroundService.BackgroundServiceEvent} serviceEvent
Tim van der Lippeff5ad472020-02-17 12:35:09244 * @return {!EventData}
Rayan Kansoaca06e72019-03-27 11:57:06245 */
246 _createEventData(serviceEvent) {
Rayan Kansocc02ea32019-05-02 21:26:52247 let swScope = '';
Rayan Kansoaca06e72019-03-27 11:57:06248
Rayan Kansocc02ea32019-05-02 21:26:52249 // Try to get the scope of the Service Worker registration to be more user-friendly.
250 const registration = this._serviceWorkerManager.registrations().get(serviceEvent.serviceWorkerRegistrationId);
Tim van der Lippe1d6e57a2019-09-30 11:55:34251 if (registration) {
Rayan Kansocc02ea32019-05-02 21:26:52252 swScope = registration.scopeURL.substr(registration.securityOrigin.length);
Tim van der Lippe1d6e57a2019-09-30 11:55:34253 }
Rayan Kansoaca06e72019-03-27 11:57:06254
255 return {
Rayan Kansoc79a8bb2019-05-29 21:08:38256 id: this._dataGrid.rootNode().children.length + 1,
Tim van der Lippe0efccf02020-02-12 15:15:39257 timestamp: UI.UIUtils.formatTimestamp(serviceEvent.timestamp * 1000, /* full= */ true),
Rayan Kansoaca06e72019-03-27 11:57:06258 origin: serviceEvent.origin,
Rayan Kansocc02ea32019-05-02 21:26:52259 swScope,
Rayan Kansoaca06e72019-03-27 11:57:06260 eventName: serviceEvent.eventName,
261 instanceId: serviceEvent.instanceId,
262 };
263 }
264
265 /**
Rayan Kanso3252d5e2019-03-27 11:37:24266 * Filtration function to know whether event should be shown or not.
267 * @param {!Protocol.BackgroundService.BackgroundServiceEvent} event
268 * @return {boolean}
269 */
270 _acceptEvent(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34271 if (event.service !== this._serviceName) {
Rayan Kansoaca06e72019-03-27 11:57:06272 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34273 }
Rayan Kansoaca06e72019-03-27 11:57:06274
Tim van der Lippe1d6e57a2019-09-30 11:55:34275 if (this._originCheckbox.checked()) {
Rayan Kansoaca06e72019-03-27 11:57:06276 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:34277 }
Rayan Kansoaca06e72019-03-27 11:57:06278
279 // Trim the trailing '/'.
280 const origin = event.origin.substr(0, event.origin.length - 1);
281
282 return this._securityOriginManager.securityOrigins().includes(origin);
Rayan Kanso3252d5e2019-03-27 11:37:24283 }
Rayan Kansob451b4f2019-04-04 23:12:11284
285 /**
Rayan Kanso42c0f9e2019-09-02 12:21:09286 * @return {!Element}
287 */
288 _createLearnMoreLink() {
289 let url =
290 'https://developers.google.com/web/tools/chrome-devtools/javascript/background-services?utm_source=devtools';
291
292 switch (this._serviceName) {
293 case Protocol.BackgroundService.ServiceName.BackgroundFetch:
294 url += '#fetch';
295 break;
296 case Protocol.BackgroundService.ServiceName.BackgroundSync:
297 url += '#sync';
298 break;
299 case Protocol.BackgroundService.ServiceName.PushMessaging:
300 url += '#push';
301 break;
302 case Protocol.BackgroundService.ServiceName.Notifications:
303 url += '#notifications';
304 break;
305 default:
306 break;
307 }
308
Tim van der Lippe0efccf02020-02-12 15:15:39309 return UI.XLink.XLink.create(url, ls`Learn more`);
Rayan Kanso42c0f9e2019-09-02 12:21:09310 }
311
312 /**
Tim van der Lippe097cdec2020-01-06 14:44:17313 * @param {?EventDataNode} dataNode
Rayan Kansob451b4f2019-04-04 23:12:11314 */
315 _showPreview(dataNode) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34316 if (this._selectedEventNode && this._selectedEventNode === dataNode) {
Rayan Kansoc0bfdd82019-04-24 12:32:22317 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34318 }
Rayan Kansoc0bfdd82019-04-24 12:32:22319
320 this._selectedEventNode = dataNode;
321
Tim van der Lippe1d6e57a2019-09-30 11:55:34322 if (this._preview) {
Rayan Kansob451b4f2019-04-04 23:12:11323 this._preview.detach();
Tim van der Lippe1d6e57a2019-09-30 11:55:34324 }
Rayan Kansob451b4f2019-04-04 23:12:11325
Rayan Kansoc0bfdd82019-04-24 12:32:22326 if (this._selectedEventNode) {
327 this._preview = this._selectedEventNode.createPreview();
Rayan Kanso4476ca52019-07-22 11:51:24328 this._preview.show(this._previewPanel.contentElement);
329 return;
330 }
331
Tim van der Lippe0efccf02020-02-12 15:15:39332 this._preview = new UI.Widget.VBox();
Rayan Kanso4476ca52019-07-22 11:51:24333 this._preview.contentElement.classList.add('background-service-preview', 'fill');
334 const centered = this._preview.contentElement.createChild('div');
335
336 if (this._dataGrid.rootNode().children.length) {
Rayan Kansoc0bfdd82019-04-24 12:32:22337 // Inform users that grid entries are clickable.
Rayan Kanso4476ca52019-07-22 11:51:24338 centered.createChild('p').textContent = ls`Select an entry to view metadata`;
Rayan Kansoc0bfdd82019-04-24 12:32:22339 } else if (this._recordButton.toggled()) {
340 // Inform users that we are recording/waiting for events.
Tim van der Lippe097cdec2020-01-06 14:44:17341 const featureName = BackgroundServiceView.getUIString(this._serviceName);
Rayan Kanso4476ca52019-07-22 11:51:24342 centered.createChild('p').textContent = ls`Recording ${featureName} activity...`;
343 centered.createChild('p').textContent =
344 ls`DevTools will record all ${featureName} activity for up to 3 days, even when closed.`;
Rayan Kansoc0bfdd82019-04-24 12:32:22345 } else {
Tim van der Lippe0efccf02020-02-12 15:15:39346 const landingRecordButton = UI.Toolbar.Toolbar.createActionButton(this._recordAction);
Rayan Kansoc0bfdd82019-04-24 12:32:22347
Tim van der Lippef49e2322020-05-01 15:03:09348 const recordKey = document.createElement('b');
349 recordKey.classList.add('background-service-shortcut');
Rayan Kanso6156d222019-04-29 23:40:55350 recordKey.textContent =
Jack Lynchb8fb3c72020-04-21 05:36:16351 self.UI.shortcutRegistry.shortcutsForAction('background-service.toggle-recording')[0].title();
Rayan Kanso6156d222019-04-29 23:40:55352
Tim van der Lippe0efccf02020-02-12 15:15:39353 const inlineButton = UI.UIUtils.createInlineButton(landingRecordButton);
Rayan Kansof402ef32019-08-12 13:05:18354 inlineButton.classList.add('background-service-record-inline-button');
Tim van der Lippe0efccf02020-02-12 15:15:39355 centered.createChild('p').appendChild(UI.UIUtils.formatLocalized(
356 'Click the record button %s or hit %s to start recording.', [inlineButton, recordKey]));
Rayan Kanso42c0f9e2019-09-02 12:21:09357
358 centered.appendChild(this._createLearnMoreLink());
Rayan Kansoc0bfdd82019-04-24 12:32:22359 }
Rayan Kansob451b4f2019-04-04 23:12:11360
361 this._preview.show(this._previewPanel.contentElement);
362 }
Rayan Kansob852ba82019-04-08 13:48:07363
364 /**
365 * Saves all currently displayed events in a file (JSON format).
366 */
367 async _saveToFile() {
Simon Zünd2c704cd2020-06-04 09:08:35368 const fileName = `${this._serviceName}-${Platform.DateUtilities.toISO8601Compact(new Date())}.json`;
Tim van der Lippe0efccf02020-02-12 15:15:39369 const stream = new Bindings.FileUtils.FileOutputStream();
Rayan Kansob852ba82019-04-08 13:48:07370
371 const accepted = await stream.open(fileName);
Tim van der Lippe1d6e57a2019-09-30 11:55:34372 if (!accepted) {
Rayan Kansob852ba82019-04-08 13:48:07373 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34374 }
Rayan Kansob852ba82019-04-08 13:48:07375
376 const events = this._model.getEvents(this._serviceName).filter(event => this._acceptEvent(event));
377 await stream.write(JSON.stringify(events, undefined, 2));
378 stream.close();
379 }
Tim van der Lippe097cdec2020-01-06 14:44:17380}
Rayan Kanso3252d5e2019-03-27 11:37:24381
Tim van der Lippe0efccf02020-02-12 15:15:39382export class EventDataNode extends DataGrid.DataGrid.DataGridNode {
Rayan Kanso3252d5e2019-03-27 11:37:24383 /**
Rayan Kansoaca06e72019-03-27 11:57:06384 * @param {!Object<string, string>} data
385 * @param {!Array<!Protocol.BackgroundService.EventMetadata>} eventMetadata
Rayan Kanso3252d5e2019-03-27 11:37:24386 */
Rayan Kansoaca06e72019-03-27 11:57:06387 constructor(data, eventMetadata) {
388 super(data);
Rayan Kanso3252d5e2019-03-27 11:37:24389
390 /** @const {!Array<!Protocol.BackgroundService.EventMetadata>} */
Rayan Kansoc79a8bb2019-05-29 21:08:38391 this._eventMetadata = eventMetadata.sort((m1, m2) => m1.key.compareTo(m2.key));
Rayan Kanso3252d5e2019-03-27 11:37:24392 }
393
394 /**
Tim van der Lippe0efccf02020-02-12 15:15:39395 * @return {!UI.Widget.VBox}
Rayan Kanso3252d5e2019-03-27 11:37:24396 */
Rayan Kansob451b4f2019-04-04 23:12:11397 createPreview() {
Tim van der Lippe0efccf02020-02-12 15:15:39398 const preview = new UI.Widget.VBox();
Rayan Kansoc0bfdd82019-04-24 12:32:22399 preview.element.classList.add('background-service-metadata');
400
401 for (const entry of this._eventMetadata) {
Tim van der Lippef49e2322020-05-01 15:03:09402 const div = document.createElement('div');
403 div.classList.add('background-service-metadata-entry');
Rayan Kansoc0bfdd82019-04-24 12:32:22404 div.createChild('div', 'background-service-metadata-name').textContent = entry.key + ': ';
Rayan Kanso4476ca52019-07-22 11:51:24405 if (entry.value) {
406 div.createChild('div', 'background-service-metadata-value source-code').textContent = entry.value;
407 } else {
408 div.createChild('div', 'background-service-metadata-value background-service-empty-value').textContent =
409 ls`empty`;
410 }
Rayan Kansoc0bfdd82019-04-24 12:32:22411 preview.element.appendChild(div);
412 }
413
414 if (!preview.element.children.length) {
Tim van der Lippef49e2322020-05-01 15:03:09415 const div = document.createElement('div');
416 div.classList.add('background-service-metadata-entry');
Rayan Kansoc0bfdd82019-04-24 12:32:22417 div.createChild('div', 'background-service-metadata-name').textContent = ls`No metadata for this event`;
418 preview.element.appendChild(div);
419 }
420
421 return preview;
Rayan Kansof40e3152019-03-11 13:49:43422 }
Tim van der Lippe097cdec2020-01-06 14:44:17423}
Rayan Kanso6156d222019-04-29 23:40:55424
425/**
Tim van der Lippe0efccf02020-02-12 15:15:39426 * @implements {UI.ActionDelegate.ActionDelegate}
Rayan Kanso6156d222019-04-29 23:40:55427 * @unrestricted
428 */
Tim van der Lippe097cdec2020-01-06 14:44:17429export class ActionDelegate {
Rayan Kanso6156d222019-04-29 23:40:55430 /**
431 * @override
Tim van der Lippe0efccf02020-02-12 15:15:39432 * @param {!UI.Context.Context} context
Rayan Kanso6156d222019-04-29 23:40:55433 * @param {string} actionId
434 * @return {boolean}
435 */
436 handleAction(context, actionId) {
Tim van der Lippe097cdec2020-01-06 14:44:17437 const view = context.flavor(BackgroundServiceView);
Rayan Kanso6156d222019-04-29 23:40:55438 switch (actionId) {
439 case 'background-service.toggle-recording':
440 view._toggleRecording();
441 return true;
442 }
443 return false;
444 }
Tim van der Lippe097cdec2020-01-06 14:44:17445}
Tim van der Lippeff5ad472020-02-17 12:35:09446
447/**
448 * @typedef {!{isRecording: boolean, serviceName: !Protocol.BackgroundService.ServiceName}}
449 */
450export let RecordingState;
451
452/**
453 * @typedef {{
454 * id: number,
455 * timestamp: string,
456 * origin: string,
457 * swScope: string,
458 * eventName: string,
459 * instanceId: string,
460 * }}
461 */
462export let EventData;