Kaynağa Gözat

Update the web user interface aesthetically (#263)

Update the web user interface aesthetically.
The Refine menu is greyed-out for pages besides the Graph.
The description box now opens upon clicking the filename in the top-right.
Taco de Wolff 7 yıl önce
ebeveyn
işleme
71d5bade98

+ 1
- 0
CONTRIBUTORS Dosyayı Görüntüle

@@ -11,4 +11,5 @@
11 11
 Raul Silvera <rsilvera@google.com>
12 12
 Tipp Moseley <tipp@google.com>
13 13
 Hyoun Kyu Cho <netforce@google.com>
14
+Taco de Wolff <tacodewolff@gmail.com>
14 15
 

+ 2
- 2
internal/driver/testdata/pprof.cpu.flat.addresses.weblist Dosyayı Görüntüle

@@ -61,7 +61,7 @@ function pprof_toggle_asm(e) {
61 61
 
62 62
 <div class="legend">File: testbinary<br>
63 63
 Type: cpu<br>
64
-Duration: 10s, Total samples = 1.12s (11.20%)<br>Total: 1.12s</div><h1>line1000</h1>testdata/file1000.src
64
+Duration: 10s, Total samples = 1.12s (11.20%)<br>Total: 1.12s</div><h2>line1000</h2><p class="filename">testdata/file1000.src</p>
65 65
 <pre onClick="pprof_toggle_asm(event)">
66 66
   Total:       1.10s      1.10s (flat, cum) 98.21%
67 67
 <span class=line>      1</span> <span class=deadsrc>       1.10s      1.10s           line1 </span><span class=asm>               1.10s      1.10s     1000:     instruction one                                                              <span class=unimportant>file1000.src:1</span>
@@ -77,7 +77,7 @@ Duration: 10s, Total samples = 1.12s (11.20%)<br>Total: 1.12s</div><h1>line1000<
77 77
 <span class=line>      6</span> <span class=nop>           .          .           line6 </span>
78 78
 <span class=line>      7</span> <span class=nop>           .          .           line7 </span>
79 79
 </pre>
80
-<h1>line3000</h1>testdata/file3000.src
80
+<h2>line3000</h2><p class="filename">testdata/file3000.src</p>
81 81
 <pre onClick="pprof_toggle_asm(event)">
82 82
   Total:        10ms      1.12s (flat, cum)   100%
83 83
 <span class=line>      1</span> <span class=nop>           .          .           line1 </span>

+ 209
- 154
internal/driver/webhtml.go Dosyayı Görüntüle

@@ -21,189 +21,242 @@ func addTemplates(templates *template.Template) {
21 21
 	template.Must(templates.Parse(`
22 22
 {{define "css"}}
23 23
 <style type="text/css">
24
-html {
25
-  height: 100%;
26
-  min-height: 100%;
27
-  margin: 0px;
24
+* {
25
+  margin: 0;
26
+  padding: 0;
27
+  box-sizing: border-box;
28 28
 }
29
-body {
30
-  margin: 0px;
31
-  width: 100%;
29
+html, body {
32 30
   height: 100%;
33
-  min-height: 100%;
34
-  overflow: hidden;
35 31
 }
36
-#graphcontainer {
32
+body {
33
+  font-family: 'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
34
+  font-size: 13px;
35
+  line-height: 1.4;
37 36
   display: flex;
38 37
   flex-direction: column;
39
-  height: 100%;
40
-  min-height: 100%;
41
-  width: 100%;
42
-  min-width: 100%;
43
-  margin: 0px;
44 38
 }
45
-#graph {
46
-  flex: 1 1 auto;
47
-  overflow: hidden;
39
+a {
40
+  color: #2a66d9;
48 41
 }
49
-svg {
42
+.header {
43
+  display: flex;
44
+  align-items: center;
45
+  height: 44px;
46
+  min-height: 44px;
47
+  background-color: #eee;
48
+  color: #212121;
49
+  padding: 0 1rem;
50
+}
51
+.header > div {
52
+  margin: 0 0.125em;
53
+}
54
+.header .title h1 {
55
+  font-size: 1.75em;
56
+  margin-right: 1rem;
57
+}
58
+.header .title a {
59
+  color: #212121;
60
+  text-decoration: none;
61
+}
62
+.header .title a:hover {
63
+  text-decoration: underline;
64
+}
65
+.header .description {
50 66
   width: 100%;
51
-  height: auto;
67
+  text-align: right;
68
+  white-space: nowrap;
52 69
 }
53
-button {
54
-  margin-top: 5px;
55
-  margin-bottom: 5px;
70
+@media screen and (max-width: 799px) {
71
+	.header input {
72
+		display: none;
73
+	}
56 74
 }
57
-#detailtext {
75
+#detailsbox {
58 76
   display: none;
77
+  z-index: 1;
59 78
   position: fixed;
60
-  top: 20px;
61
-  right: 10px;
79
+  top: 40px;
80
+  right: 20px;
62 81
   background-color: #ffffff;
63
-  min-width: 160px;
64
-  border: 1px solid #888;
65
-  box-shadow: 4px 4px 4px 0px rgba(0,0,0,0.2);
66
-  z-index: 1;
82
+  box-shadow: 0 1px 5px rgba(0,0,0,.3);
83
+  line-height: 24px;
84
+  padding: 1em;
85
+  text-align: left;
67 86
 }
68
-#closedetails {
69
-  float: right;
70
-  margin: 2px;
87
+.header input {
88
+  background: white url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' style='pointer-events:none;display:block;width:100%25;height:100%25;fill:#757575'%3E%3Cpath d='M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61.0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z'/%3E%3C/svg%3E") no-repeat 4px center/20px 20px;
89
+  border: 1px solid #d1d2d3;
90
+  border-radius: 2px 0 0 2px;
91
+  padding: 0.25em;
92
+  padding-left: 28px;
93
+  margin-left: 1em;
94
+  font-family: 'Roboto', 'Noto', sans-serif;
95
+  font-size: 1em;
96
+  line-height: 24px;
97
+  color: #212121;
98
+}
99
+.downArrow {
100
+  border-top: .36em solid #ccc;
101
+  border-left: .36em solid transparent;
102
+  border-right: .36em solid transparent;
103
+  margin-bottom: .05em;
104
+  margin-left: .5em;
105
+  transition: border-top-color 200ms;
106
+}
107
+.menu-item {
108
+  height: 100%;
109
+  text-transform: uppercase;
110
+  font-family: 'Roboto Medium', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
111
+  position: relative;
71 112
 }
72
-#home {
73
-  font-size: 14pt;
74
-  padding-left: 0.5em;
75
-  padding-right: 0.5em;
76
-  float: right;
113
+.menu-item.disabled {
114
+  opacity: 0.5;
77 115
 }
78
-.menubar {
79
-  display: inline-block;
80
-  background-color: #f8f8f8;
81
-  border: 1px solid #ccc;
82
-  width: 100%;
116
+.menu-item .menu-name:hover {
117
+  opacity: 0.75;
83 118
 }
84
-.menu-header {
85
-  position: relative;
86
-  display: inline-block;
87
-  padding: 2px 2px;
88
-  font-size: 14pt;
119
+.menu-item .menu-name:hover .downArrow {
120
+  border-top-color: #666;
121
+}
122
+.menu-item.disabled .menu-name:hover {
123
+  opacity: 1;
89 124
 }
90
-.menu {
125
+.menu-item.disabled .menu-name:hover .downArrow {
126
+  border-top-color: #ccc;
127
+}
128
+.menu-name {
129
+  height: 100%;
130
+  padding: 0 0.5em;
131
+  display: flex;
132
+  align-items: center;
133
+  justify-content: center;
134
+}
135
+.submenu {
91 136
   display: none;
92
-  position: absolute;
93
-  background-color: #f8f8f8;
94
-  border: 1px solid #888;
95
-  box-shadow: 4px 4px 4px 0px rgba(0,0,0,0.2);
96 137
   z-index: 1;
97
-  margin-top: 2px;
138
+  margin-top: -4px;
139
+  min-width: 10em;
140
+  position: absolute;
98 141
   left: 0px;
99
-  min-width: 5em;
142
+  background-color: white;
143
+  box-shadow: 0 1px 5px rgba(0,0,0,.3);
144
+  font-size: 100%;
145
+  text-transform: none;
100 146
 }
101
-.menu-header, .menu {
102
-  cursor: default;
147
+.menu-item, .submenu {
103 148
   user-select: none;
104 149
   -moz-user-select: none;
105 150
   -ms-user-select: none;
106 151
   -webkit-user-select: none;
107 152
 }
108
-.menu hr {
109
-  background-color: #fff;
110
-  margin-top: 0px;
111
-  margin-bottom: 0px;
153
+.submenu hr {
154
+  border: 0;
155
+  border-top: 2px solid #eee;
112 156
 }
113
-.menu a, .menu button {
157
+.submenu a {
114 158
   display: block;
115
-  width: 100%;
116
-  margin: 0px;
117
-  padding: 2px 0px 2px 0px;
118
-  text-align: left;
159
+  padding: .5em 1em;
119 160
   text-decoration: none;
120
-  color: #000;
121
-  background-color: #f8f8f8;
122
-  font-size: 12pt;
123
-  border: none;
124 161
 }
125
-.menu-header:hover {
126
-  background-color: #ccc;
162
+.submenu a:hover, .submenu a.active {
163
+  color: white;
164
+  background-color: #6b82d6;
127 165
 }
128
-.menu a:hover, .menu button:hover {
129
-  background-color: #ccc;
130
-}
131
-.menu a.disabled {
166
+.submenu a.disabled {
132 167
   color: gray;
133 168
   pointer-events: none;
134 169
 }
135
-#searchbox {
136
-  margin-left: 10pt;
170
+
171
+#content {
172
+  overflow-y: scroll;
173
+  padding: 1em;
174
+}
175
+#top {
176
+  overflow-y: scroll;
177
+}
178
+#graph {
179
+  overflow: hidden;
137 180
 }
138
-#bodycontainer {
181
+#graph svg {
139 182
   width: 100%;
140
-  height: 100%;
141
-  max-height: 100%;
142
-  overflow: scroll;
143
-  padding-top: 5px;
183
+  height: auto;
184
+  padding: 10px;
185
+}
186
+#content.source .filename {
187
+  margin-top: 0;
188
+  margin-bottom: 1em;
189
+  font-size: 120%;
144 190
 }
145
-#toptable {
191
+#content.source pre {
192
+  margin-bottom: 3em;
193
+}
194
+table {
146 195
   border-spacing: 0px;
147 196
   width: 100%;
148 197
   padding-bottom: 1em;
198
+  white-space: nowrap;
149 199
 }
150
-#toptable tr th {
151
-  border-bottom: 1px solid black;
200
+table thead {
201
+  font-family: 'Roboto Medium', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
202
+}
203
+table tr th {
204
+  background-color: #ddd;
152 205
   text-align: right;
153
-  padding-left: 1em;
154
-  padding-top: 0.2em;
155
-  padding-bottom: 0.2em;
206
+  padding: .3em .5em;
156 207
 }
157
-#toptable tr td {
158
-  padding-left: 1em;
159
-  font: monospace;
208
+table tr td {
209
+  padding: .3em .5em;
160 210
   text-align: right;
161
-  white-space: nowrap;
162
-  cursor: default;
163 211
 }
164
-#toptable tr th:nth-child(6),
165
-#toptable tr th:nth-child(7),
166
-#toptable tr td:nth-child(6),
167
-#toptable tr td:nth-child(7) {
212
+#top table tr th:nth-child(6),
213
+#top table tr th:nth-child(7),
214
+#top table tr td:nth-child(6),
215
+#top table tr td:nth-child(7) {
168 216
   text-align: left;
169 217
 }
170
-#toptable tr td:nth-child(6) {
171
-  max-width: 30em;  // Truncate very long names
218
+#top table tr td:nth-child(6) {
219
+  width: 100%;
220
+  text-overflow: ellipsis;
172 221
   overflow: hidden;
222
+  white-space: nowrap;
173 223
 }
174 224
 #flathdr1, #flathdr2, #cumhdr1, #cumhdr2, #namehdr {
175 225
   cursor: ns-resize;
176 226
 }
177 227
 .hilite {
178
-  background-color: #ccf;
228
+  background-color: #ebf5fb; 
229
+  font-weight: bold;
179 230
 }
180 231
 </style>
181 232
 {{end}}
182 233
 
183 234
 {{define "header"}}
184
-<div id="detailtext">
185
-<button id="closedetails">Close</button>
186
-{{range .Legend}}<div>{{.}}</div>{{end}}
235
+<div class="header">
236
+<div class="title">
237
+<h1><a href="/">pprof</a></h1>
187 238
 </div>
188 239
 
189
-<div class="menubar">
190
-
191
-<div class="menu-header">
240
+<div id="view" class="menu-item">
241
+<div class="menu-name">
192 242
 View
193
-<div class="menu">
243
+<i class="downArrow"></i>
244
+</div>
245
+<div class="submenu">
194 246
 <a title="{{.Help.top}}"  href="/top" id="topbtn">Top</a>
195 247
 <a title="{{.Help.graph}}" href="/" id="graphbtn">Graph</a>
196 248
 <a title="{{.Help.peek}}" href="/peek" id="peek">Peek</a>
197 249
 <a title="{{.Help.list}}" href="/source" id="list">Source</a>
198 250
 <a title="{{.Help.disasm}}" href="/disasm" id="disasm">Disassemble</a>
199
-<hr>
200
-<button title="{{.Help.details}}" id="details">Details</button>
201 251
 </div>
202 252
 </div>
203 253
 
204
-<div class="menu-header">
254
+<div id="refine" class="menu-item disabled">
255
+<div class="menu-name">
205 256
 Refine
206
-<div class="menu">
257
+<i class="downArrow"></i>
258
+</div>
259
+<div class="submenu">
207 260
 <a title="{{.Help.focus}}" href="{{.BaseURL}}" id="focus">Focus</a>
208 261
 <a title="{{.Help.ignore}}" href="{{.BaseURL}}" id="ignore">Ignore</a>
209 262
 <a title="{{.Help.hide}}" href="{{.BaseURL}}" id="hide">Hide</a>
@@ -213,11 +266,17 @@ Refine
213 266
 </div>
214 267
 </div>
215 268
 
216
-<input id="searchbox" type="text" placeholder="Search regexp" autocomplete="off" autocapitalize="none" size=40>
217
-
218
-<span id="home">{{.Title}}</span>
269
+<div>
270
+<input id="search" type="text" placeholder="Search regexp" autocomplete="off" autocapitalize="none" size=40>
271
+</div>
219 272
 
220
-</div> <!-- menubar -->
273
+<div class="description">
274
+<a title="{{.Help.details}}" href="#" id="details">{{.Title}}</a>
275
+<div id="detailsbox">
276
+{{range .Legend}}<div>{{.}}</div>{{end}}
277
+</div>
278
+</div>
279
+</div>
221 280
 
222 281
 <div id="errors">{{range .Errors}}<div>{{.}}</div>{{end}}</div>
223 282
 {{end}}
@@ -231,13 +290,9 @@ Refine
231 290
 {{template "css" .}}
232 291
 </head>
233 292
 <body>
234
-
235 293
 {{template "header" .}}
236
-<div id="graphcontainer">
237 294
 <div id="graph">
238 295
 {{.HTMLBody}}
239
-</div>
240
-
241 296
 </div>
242 297
 {{template "script" .}}
243 298
 <script>viewer({{.BaseURL}}, {{.Nodes}})</script>
@@ -477,13 +532,14 @@ function initMenus() {
477 532
   }
478 533
 
479 534
   // Set click handlers on every menu header.
480
-  for (const menu of document.getElementsByClassName("menu")) {
535
+  for (const menu of document.getElementsByClassName("submenu")) {
481 536
     const hdr = menu.parentElement;
482 537
     if (hdr == null) return;
538
+    if (hdr.classList.contains("disabled")) return;
483 539
     function showMenu(e) {
484 540
       // menu is a child of hdr, so this event can fire for clicks
485 541
       // inside menu. Ignore such clicks.
486
-      if (e.target != hdr) return;
542
+      if (e.target.parentElement != hdr) return;
487 543
       activeMenu = menu;
488 544
       activeMenuHdr = hdr;
489 545
       menu.style.display = "block";
@@ -497,7 +553,7 @@ function initMenus() {
497 553
     document.addEventListener(t, (e) => {
498 554
       // Note: to avoid unnecessary flicker, if the down event is inside
499 555
       // the active menu header, do not retract the menu.
500
-      if (activeMenuHdr != e.target.closest(".menu-header")) {
556
+      if (activeMenuHdr != e.target.closest(".menu-item")) {
501 557
         cancelActiveMenu();
502 558
       }
503 559
     }, { passive: true, capture: true });
@@ -505,7 +561,7 @@ function initMenus() {
505 561
 
506 562
   // If there is an active menu and an up event inside, retract the menu.
507 563
   document.addEventListener("mouseup", (e) => {
508
-    if (activeMenu == e.target.closest(".menu")) {
564
+    if (activeMenu == e.target.closest(".submenu")) {
509 565
       cancelActiveMenu();
510 566
     }
511 567
   }, { passive: true, capture: true });
@@ -515,7 +571,7 @@ function viewer(baseUrl, nodes) {
515 571
   'use strict';
516 572
 
517 573
   // Elements
518
-  const search = document.getElementById("searchbox")
574
+  const search = document.getElementById("search")
519 575
   const graph0 = document.getElementById("graph0")
520 576
   const svg = (graph0 == null ? null : graph0.parentElement)
521 577
   const toptable = document.getElementById("toptable")
@@ -526,14 +582,16 @@ function viewer(baseUrl, nodes) {
526 582
   let searchAlarm = null
527 583
   let buttonsEnabled = true
528 584
 
529
-  function handleDetails() {
530
-    const detailsText = document.getElementById("detailtext")
531
-    if (detailsText != null) detailsText.style.display = "block"
532
-  }
533
-
534
-  function handleCloseDetails() {
535
-    const detailsText = document.getElementById("detailtext")
536
-    if (detailsText != null) detailsText.style.display = "none"
585
+  function handleDetails(e) {
586
+    e.preventDefault()
587
+    const detailsText = document.getElementById("detailsbox")
588
+    if (detailsText != null) {
589
+      if (detailsText.style.display === "block") {
590
+        detailsText.style.display = "none"
591
+      } else {
592
+        detailsText.style.display = "block"
593
+      }
594
+    }
537 595
   }
538 596
 
539 597
   function handleKey(e) {
@@ -753,6 +811,9 @@ function viewer(baseUrl, nodes) {
753 811
         link.classList.toggle("disabled", !enable)
754 812
       }
755 813
     }
814
+    if (document.getElementById("graph") !== null) {
815
+      document.getElementById("refine").classList.remove("disabled")
816
+    }
756 817
   }
757 818
 
758 819
   // Initialize button states
@@ -782,7 +843,6 @@ function viewer(baseUrl, nodes) {
782 843
   }
783 844
 
784 845
   addAction("details", handleDetails)
785
-  addAction("closedetails", handleCloseDetails)
786 846
 
787 847
   search.addEventListener("input", handleSearch)
788 848
   search.addEventListener("keydown", handleKey)
@@ -807,21 +867,21 @@ function viewer(baseUrl, nodes) {
807 867
 </style>
808 868
 </head>
809 869
 <body>
810
-
811 870
 {{template "header" .}}
812
-
813
-<div id="bodycontainer">
871
+<div id="top">
814 872
 <table id="toptable">
873
+<thead>
815 874
 <tr>
816
-<th id="flathdr1">Flat
817
-<th id="flathdr2">Flat%
818
-<th>Sum%
819
-<th id="cumhdr1">Cum
820
-<th id="cumhdr2">Cum%
821
-<th id="namehdr">Name
822
-<th>Inlined?</tr>
823
-<tbody id="rows">
824
-</tbody>
875
+<th id="flathdr1">Flat</th>
876
+<th id="flathdr2">Flat%</th>
877
+<th>Sum%</th>
878
+<th id="cumhdr1">Cum</th>
879
+<th id="cumhdr2">Cum%</th>
880
+<th id="namehdr">Name</th>
881
+<th>Inlined?</th>
882
+</tr>
883
+</thead>
884
+<tbody id="rows"></tbody>
825 885
 </table>
826 886
 </div>
827 887
 
@@ -910,6 +970,7 @@ function makeTopTable(total, entries) {
910 970
 viewer({{.BaseURL}}, {{.Nodes}})
911 971
 makeTopTable({{.Total}}, {{.Top}})
912 972
 </script>
973
+
913 974
 </body>
914 975
 </html>
915 976
 {{end}}
@@ -925,13 +986,10 @@ makeTopTable({{.Total}}, {{.Top}})
925 986
 {{template "weblistjs" .}}
926 987
 </head>
927 988
 <body>
928
-
929 989
 {{template "header" .}}
930
-
931
-<div id="bodycontainer">
990
+<div id="content" class="source">
932 991
 {{.HTMLBody}}
933 992
 </div>
934
-
935 993
 {{template "script" .}}
936 994
 <script>viewer({{.BaseURL}}, null)</script>
937 995
 </body>
@@ -947,15 +1005,12 @@ makeTopTable({{.Total}}, {{.Top}})
947 1005
 {{template "css" .}}
948 1006
 </head>
949 1007
 <body>
950
-
951 1008
 {{template "header" .}}
952
-
953
-<div id="bodycontainer">
1009
+<div id="content">
954 1010
 <pre>
955 1011
 {{.TextBody}}
956 1012
 </pre>
957 1013
 </div>
958
-
959 1014
 {{template "script" .}}
960 1015
 <script>viewer({{.BaseURL}}, null)</script>
961 1016
 </body>

+ 1
- 1
internal/report/source.go Dosyayı Görüntüle

@@ -338,7 +338,7 @@ func printHeader(w io.Writer, rpt *Report) {
338 338
 
339 339
 // printFunctionHeader prints a function header for a weblist report.
340 340
 func printFunctionHeader(w io.Writer, name, path string, flatSum, cumSum int64, rpt *Report) {
341
-	fmt.Fprintf(w, `<h1>%s</h1>%s
341
+	fmt.Fprintf(w, `<h2>%s</h2><p class="filename">%s</p>
342 342
 <pre onClick="pprof_toggle_asm(event)">
343 343
   Total:  %10s %10s (flat, cum) %s
344 344
 `,