Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(141)

Side by Side Diff: runtime/observatory/lib/src/elements/timeline_page.dart

Issue 2299613004: Converted Observatory timeline-page element (Closed)
Patch Set: Reverted change to service Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library timeline_page_element; 5 library timeline_page_element;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:html';
8 import 'dart:convert'; 9 import 'dart:convert';
9 import 'dart:html'; 10 import 'package:observatory/service.dart' as S;
10 import 'observatory_element.dart'; 11 import 'package:observatory/service_html.dart' as SH;
11 import 'package:observatory/elements.dart'; 12 import 'package:observatory/models.dart' as M;
12 import 'package:observatory/service_html.dart'; 13 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
13 import 'package:polymer/polymer.dart'; 14 import 'package:observatory/src/elements/helpers/tag.dart';
14 15 import 'package:observatory/src/elements/nav/bar.dart';
15 16 import 'package:observatory/src/elements/nav/notify.dart';
16 @CustomTag('timeline-page') 17 import 'package:observatory/src/elements/nav/refresh.dart';
17 class TimelinePageElement extends ObservatoryElement { 18 import 'package:observatory/src/elements/nav/top_menu.dart';
18 TimelinePageElement.created() : super.created() { 19 import 'package:observatory/src/elements/nav/vm_menu.dart';
19 } 20
20 21 enum _Profile {
22 none,
23 dart,
24 vm,
25 all,
26 custom
27 }
28
29 class TimelinePageElement extends HtmlElement implements Renderable {
30 static const tag = const Tag<TimelinePageElement>('timeline-page',
31 dependencies: const [
32 NavBarElement.tag,
33 NavTopMenuElement.tag,
34 NavVMMenuElement.tag,
35 NavRefreshElement.tag,
36 NavNotifyElement.tag
37 ]);
38
39 RenderingScheduler<TimelinePageElement> _r;
40
41 Stream<RenderedEvent<TimelinePageElement>> get onRendered => _r.onRendered;
42
43 M.VM _vm;
44 M.EventRepository _events;
45 M.NotificationRepository _notifications;
46 String _recorderName = '';
47 _Profile _profile = _Profile.none;
48 final Set<String> _availableStreams = new Set<String>();
49 final Set<String> _recordedStreams = new Set<String>();
50
51 M.VMRef get vm => _vm;
52 M.NotificationRepository get notifications => _notifications;
53
54 factory TimelinePageElement(M.VM vm, M.EventRepository events,
55 M.NotificationRepository notifications,
56 {RenderingQueue queue}) {
57 assert(vm != null);
58 assert(events != null);
59 assert(notifications != null);
60 TimelinePageElement e = document.createElement(tag.name);
61 e._r = new RenderingScheduler(e, queue: queue);
62 e._vm = vm;
63 e._events = events;
64 e._notifications = notifications;
65 return e;
66 }
67
68 TimelinePageElement.created() : super.created();
69
70 @override
21 attached() { 71 attached() {
22 super.attached(); 72 super.attached();
23 _resizeSubscription = window.onResize.listen((_) => _updateSize()); 73 _r.enable();
24 _updateSize();
25 _setupInitialState(); 74 _setupInitialState();
26 } 75 }
27 76
77 @override
28 detached() { 78 detached() {
29 super.detached(); 79 super.detached();
30 if (_resizeSubscription != null) { 80 _r.disable(notify: true);
31 _resizeSubscription.cancel(); 81 children = [];
32 } 82 }
33 } 83
34 84 IFrameElement _frame;
35 Future postMessage(String method) { 85 DivElement _content;
36 IFrameElement e = $['root']; 86
87 void render() {
88 if (_frame == null) {
89 _frame = new IFrameElement()..src = 'timeline.html';
90 }
91 if (_content == null) {
92 _content = new DivElement()..classes = ['content-centered-big'];
93 }
94 _content.children = [
95 new HeadingElement.h1()..text = 'Timeline settings',
96 new DivElement()..classes = ['memberList']
97 ..children = [
98 new DivElement()..classes = ['memberItem']
99 ..children = [
100 new DivElement()..classes = ['memberName']
101 ..text = 'Recorder:',
102 new DivElement()..classes = ['memberValue']
103 ..text = _recorderName
104 ],
105 new DivElement()..classes = ['memberItem']
106 ..children = [
107 new DivElement()..classes = ['memberName']
108 ..text = 'Recorded Streams Profile:',
109 new DivElement()..classes = ['memberValue']
110 ..children = _createProfileSelect()
111 ],
112 new DivElement()..classes = ['memberItem']
113 ..children = [
114 new DivElement()..classes = ['memberName']
115 ..text = 'Recorded Streams:',
116 new DivElement()..classes = ['memberValue']
117 ..children =
118 _availableStreams.map(_makeStreamToggle).toList()
119 ]
120 ]
121 ];
122 if (children.isEmpty) {
123 children = [
124 new NavBarElement(queue: _r.queue)
125 ..children = [
126 new NavTopMenuElement(queue: _r.queue),
127 new NavVMMenuElement(_vm, _events, last: true, queue: _r.queue),
128 new NavRefreshElement(queue: _r.queue)
129 ..onRefresh.listen((e) async {
130 e.element.disabled = true;
131 await _refresh();
132 e.element.disabled = false;
133 }),
134 new NavRefreshElement(label: 'clear', queue: _r.queue)
135 ..onRefresh.listen((e) async {
136 e.element.disabled = true;
137 await _clear();
138 e.element.disabled = false;
139 }),
140 new NavRefreshElement(label: 'save', queue: _r.queue)
141 ..onRefresh.listen((e) async {
142 e.element.disabled = true;
143 await _save();
144 e.element.disabled = false;
145 }),
146 new NavRefreshElement(label: 'load', queue: _r.queue)
147 ..onRefresh.listen((e) async {
148 e.element.disabled = true;
149 await _load();
150 e.element.disabled = false;
151 }),
152 new NavNotifyElement(_notifications, queue: _r.queue)
153 ],
154 _content,
155 new DivElement()..classes = ['iframe']
156 ..children = [
157 _frame
158 ]
159 ];
160 }
161 }
162
163 List<Element> _createProfileSelect() {
164 var s;
165 return [
166 s = new SelectElement()..classes = ['direction-select']
167 ..value = _profileToString(_profile)
168 ..children = _Profile.values.map((direction) {
169 return new OptionElement(value: _profileToString(direction),
170 selected: _profile == direction)
171 ..text = _profileToString(direction);
172 }).toList(growable: false)
173 ..onChange.listen((_) {
174 _profile = _Profile.values[s.selectedIndex];
175 _applyPreset();
176 _r.dirty();
177 })
178 ];
179 }
180
181 String _profileToString(_Profile profile) {
182 switch (profile) {
183 case _Profile.none: return 'none';
184 case _Profile.dart: return 'Dart Developer';
185 case _Profile.vm: return 'VM Developer';
186 case _Profile.all: return 'All';
187 case _Profile.custom: return 'Custom';
188 }
189 throw new Exception('Unkown Profile ${profile}');
190 }
191
192 Future _refresh() async {
193 S.VM vm = _vm as S.VM;
194 await vm.reload();
195 await vm.reloadIsolates();
196 return _postMessage('refresh');
197 }
198
199 Future _clear() async {
200 S.VM vm = _vm as S.VM;
201 await vm.invokeRpc('_clearVMTimeline', {});
202 return _postMessage('clear');
203 }
204
205 Future _save() async {
206 return _postMessage('save');
207 }
208
209 Future _load() async {
210 return _postMessage('load');
211 }
212
213 Future _postMessage(String method) {
214 S.VM vm = _vm as S.VM;
37 var isolateIds = new List(); 215 var isolateIds = new List();
38 for (var isolate in app.vm.isolates) { 216 for (var isolate in vm.isolates) {
39 isolateIds.add(isolate.id); 217 isolateIds.add(isolate.id);
40 } 218 }
41 var message = { 219 var message = {
42 'method': method, 220 'method': method,
43 'params': { 221 'params': {
44 'vmAddress': (app.vm as WebSocketVM).target.networkAddress, 222 'vmAddress': (vm as SH.WebSocketVM).target.networkAddress,
45 'isolateIds': isolateIds 223 'isolateIds': isolateIds
46 } 224 }
47 }; 225 };
48 e.contentWindow.postMessage(JSON.encode(message), window.location.href); 226 _frame.contentWindow.postMessage(JSON.encode(message), window.location.href) ;
49 return null; 227 return null;
50 } 228 }
51 229
52 void _processFlags(ServiceMap response) { 230 Future _setupInitialState() async {
53 // Grab the recorder name. 231 await _updateRecorderUI();
54 recorderName = response['recorderName']; 232 await _refresh();
55 // Update the set of available streams.
56 _availableStreams.clear();
57 response['availableStreams'].forEach(
58 (String streamName) => _availableStreams.add(streamName));
59 // Update the set of recorded streams.
60 _recordedStreams.clear();
61 response['recordedStreams'].forEach(
62 (String streamName) => _recordedStreams.add(streamName));
63 }
64
65 Future _applyStreamChanges() {
66 return app.vm.invokeRpc('_setVMTimelineFlags', {
67 'recordedStreams': '[${_recordedStreams.join(', ')}]',
68 });
69 }
70
71 HtmlElement _makeStreamToggle(String streamName) {
72 LabelElement label = new LabelElement();
73 label.style.paddingLeft = '8px';
74 SpanElement span = new SpanElement();
75 span.text = streamName;
76 InputElement checkbox = new InputElement();
77 checkbox.onChange.listen((_) {
78 if (checkbox.checked) {
79 _recordedStreams.add(streamName);
80 } else {
81 _recordedStreams.remove(streamName);
82 }
83 _applyStreamChanges();
84 _updateRecorderUI();
85 });
86 checkbox.type = 'checkbox';
87 checkbox.checked = _recordedStreams.contains(streamName);
88 label.children.add(checkbox);
89 label.children.add(span);
90 return label;
91 }
92
93 void _refreshRecorderUI() {
94 DivElement e = $['streamList'];
95 e.children.clear();
96
97 for (String streamName in _availableStreams) {
98 e.children.add(_makeStreamToggle(streamName));
99 }
100
101 streamPresetSelector = streamPresetFromRecordedStreams();
102 } 233 }
103 234
104 // Dart developers care about the following streams: 235 // Dart developers care about the following streams:
105 List<String> _dartPreset = 236 List<String> _dartPreset =
106 ['GC', 'Compiler', 'Dart']; 237 ['GC', 'Compiler', 'Dart'];
107 238
108 // VM developers care about the following streams: 239 // VM developers care about the following streams:
109 List<String> _vmPreset = 240 List<String> _vmPreset =
110 ['GC', 'Compiler', 'Dart', 'Debugger', 'Embedder', 'Isolate', 'VM']; 241 ['GC', 'Compiler', 'Dart', 'Debugger', 'Embedder', 'Isolate', 'VM'];
111 242
112 String streamPresetFromRecordedStreams() {
113 if (_availableStreams.length == 0) {
114 return 'None';
115 }
116 if (_recordedStreams.length == 0) {
117 return 'None';
118 }
119 if (_recordedStreams.length == _availableStreams.length) {
120 return 'All';
121 }
122 if ((_vmPreset.length == _recordedStreams.length) &&
123 _recordedStreams.containsAll(_vmPreset)) {
124 return 'VM';
125 }
126 if ((_dartPreset.length == _recordedStreams.length) &&
127 _recordedStreams.containsAll(_dartPreset)) {
128 return 'Dart';
129 }
130 return 'Custom';
131 }
132
133 void _applyPreset() { 243 void _applyPreset() {
134 switch (streamPresetSelector) { 244 switch (_profile) {
135 case 'None': 245 case _Profile.none:
136 _recordedStreams.clear(); 246 _recordedStreams.clear();
137 break; 247 break;
138 case 'All': 248 case _Profile.all:
139 _recordedStreams.clear(); 249 _recordedStreams.clear();
140 _recordedStreams.addAll(_availableStreams); 250 _recordedStreams.addAll(_availableStreams);
141 break; 251 break;
142 case 'VM': 252 case _Profile.vm:
143 _recordedStreams.clear(); 253 _recordedStreams.clear();
144 _recordedStreams.addAll(_vmPreset); 254 _recordedStreams.addAll(_vmPreset);
145 break; 255 break;
146 case 'Dart': 256 case _Profile.dart:
147 _recordedStreams.clear(); 257 _recordedStreams.clear();
148 _recordedStreams.addAll(_dartPreset); 258 _recordedStreams.addAll(_dartPreset);
149 break; 259 break;
150 case 'Custom': 260 case _Profile.custom:
151 return; 261 return;
152 } 262 }
153 _applyStreamChanges(); 263 _applyStreamChanges();
154 _updateRecorderUI(); 264 _updateRecorderUI();
155 } 265 }
156 266
157 Future _updateRecorderUI() async { 267 Future _updateRecorderUI() async {
268 S.VM vm = _vm as S.VM;
158 // Grab the current timeline flags. 269 // Grab the current timeline flags.
159 ServiceMap response = await app.vm.invokeRpc('_getVMTimelineFlags', {}); 270 S.ServiceMap response = await vm.invokeRpc('_getVMTimelineFlags', {});
160 assert(response['type'] == 'TimelineFlags'); 271 assert(response['type'] == 'TimelineFlags');
161 // Process them so we know available streams. 272 // Process them so we know available streams.
162 _processFlags(response); 273 _processFlags(response);
163 // Refresh the UI. 274 // Refresh the UI.
164 _refreshRecorderUI(); 275 _r.dirty();
165 } 276 }
166 277
167 Future _setupInitialState() async { 278 Element _makeStreamToggle(String streamName) {
168 await _updateRecorderUI(); 279 LabelElement label = new LabelElement();
169 SelectElement e = $['selectPreset']; 280 label.style.paddingLeft = '8px';
170 e.onChange.listen((_) { 281 SpanElement span = new SpanElement();
171 _applyPreset(); 282 span.text = streamName;
283 InputElement checkbox = new InputElement();
284 checkbox.onChange.listen((_) {
285 if (checkbox.checked) {
286 _recordedStreams.add(streamName);
287 } else {
288 _recordedStreams.remove(streamName);
289 }
290 _applyStreamChanges();
291 _updateRecorderUI();
172 }); 292 });
173 // Finally, trigger a reload so we start with the latest timeline. 293 checkbox.type = 'checkbox';
174 await refresh(); 294 checkbox.checked = _recordedStreams.contains(streamName);
295 label.children.add(checkbox);
296 label.children.add(span);
297 return label;
175 } 298 }
176 299
177 Future refresh() async { 300 Future _applyStreamChanges() {
178 await app.vm.reload(); 301 S.VM vm = _vm as S.VM;
179 await app.vm.reloadIsolates(); 302 return vm.invokeRpc('_setVMTimelineFlags', {
180 return postMessage('refresh'); 303 'recordedStreams': '[${_recordedStreams.join(', ')}]',
304 });
181 } 305 }
182 306
183 Future clear() async { 307 void _processFlags(S.ServiceMap response) {
184 await app.vm.invokeRpc('_clearVMTimeline', {}); 308 // Grab the recorder name.
185 return postMessage('clear'); 309 _recorderName = response['recorderName'];
310 // Update the set of available streams.
311 _availableStreams.clear();
312 response['availableStreams'].forEach(
313 (String streamName) => _availableStreams.add(streamName));
314 // Update the set of recorded streams.
315 _recordedStreams.clear();
316 response['recordedStreams'].forEach(
317 (String streamName) => _recordedStreams.add(streamName));
318 _r.dirty();
186 } 319 }
187
188 Future saveTimeline() async {
189 return postMessage('save');
190 }
191
192 Future loadTimeline() async {
193 return postMessage('load');
194 }
195
196 _updateSize() {
197 IFrameElement e = $['root'];
198 final totalHeight = window.innerHeight;
199 final top = e.offset.top;
200 final bottomMargin = 32;
201 final mainHeight = totalHeight - top - bottomMargin;
202 e.style.setProperty('height', '${mainHeight}px');
203 e.style.setProperty('width', '100%');
204 }
205
206
207 StreamSubscription _resizeSubscription;
208 @observable String recorderName;
209 @observable String streamPresetSelector = 'None';
210 final Set<String> _availableStreams = new Set<String>();
211 final Set<String> _recordedStreams = new Set<String>();
212 } 320 }
OLDNEW
« no previous file with comments | « runtime/observatory/lib/src/elements/css/shared.css ('k') | runtime/observatory/lib/src/elements/timeline_page.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698