| OLD | NEW |
| 1 <!-- | 1 <!-- |
| 2 Copyright 2016 The LUCI Authors. All rights reserved. | 2 Copyright 2016 The LUCI Authors. All rights reserved. |
| 3 Use of this source code is governed under the Apache License, Version 2.0 | 3 Use of this source code is governed under the Apache License, Version 2.0 |
| 4 that can be found in the LICENSE file. | 4 that can be found in the LICENSE file. |
| 5 --> | 5 --> |
| 6 | 6 |
| 7 <link rel="import" href="../bower_components/polymer/polymer.html"> | 7 <link rel="import" href="../bower_components/polymer/polymer.html"> |
| 8 <link rel="import" href="../bower_components/google-signin/google-signin-aware.h
tml"> | 8 <link rel="import" href="../bower_components/google-signin/google-signin-aware.h
tml"> |
| 9 <link rel="import" href="../bower_components/iron-icons/iron-icons.html"> | 9 <link rel="import" href="../bower_components/iron-icons/iron-icons.html"> |
| 10 <link rel="import" href="../bower_components/iron-icons/av-icons.html"> | 10 <link rel="import" href="../bower_components/iron-icons/av-icons.html"> |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 This must be after "rpc-client" so we get the signin event after it | 172 This must be after "rpc-client" so we get the signin event after it |
| 173 does. | 173 does. |
| 174 --> | 174 --> |
| 175 <google-signin-aware | 175 <google-signin-aware |
| 176 id="aware" | 176 id="aware" |
| 177 on-google-signin-aware-success="_onSignin"></google-signin-aware> | 177 on-google-signin-aware-success="_onSignin"></google-signin-aware> |
| 178 | 178 |
| 179 <!-- Stream view options. --> | 179 <!-- Stream view options. --> |
| 180 <div id="mainView"> | 180 <div id="mainView"> |
| 181 <div id="buttons"> | 181 <div id="buttons"> |
| 182 <!-- If we have exactly one stream, we will enable users to split. --> | 182 <template is="dom-if" if="{{showPlayPause}}"> |
| 183 <template is="dom-if" if="{{showStreamingControls}}"> | |
| 184 <paper-icon-button class="paper-icon-button-highlight" toggles | |
| 185 title="Stick to bottom." icon="icons:update" | |
| 186 active="{{follow}}"> | |
| 187 </paper-icon-button> | |
| 188 | |
| 189 <paper-icon-button class="paper-icon-button-highlight" toggles | 183 <paper-icon-button class="paper-icon-button-highlight" toggles |
| 190 title="Auto-Load" icon="{{playingIconName}}" | 184 title="Auto-Load" icon="{{playingIconName}}" |
| 191 active="{{playing}}"> | 185 active="{{playing}}"> |
| 192 </paper-icon-button> | 186 </paper-icon-button> |
| 187 </template> |
| 193 | 188 |
| 194 <template is="dom-if" if="{{canSplit}}"> | 189 <template is="dom-if" if="{{showSplitButton}}"> |
| 195 <paper-icon-button | 190 <paper-icon-button |
| 196 title="Jump to latest." | 191 title="Jump to latest." |
| 197 icon="editor:vertical-align-bottom" | 192 icon="editor:vertical-align-bottom" |
| 198 on-tap="_splitClicked"> | 193 on-tap="_splitClicked"> |
| 194 </paper-icon-button> |
| 195 </template> |
| 196 |
| 197 <template is="dom-if" if="{{showStreamControls}}"> |
| 198 <template is="dom-if" if="{{showSplitControls}}"> |
| 199 <paper-icon-button toggles |
| 200 title="Load new logs, or backfill from top." |
| 201 icon="{{backfillIconName}}" |
| 202 active="{{backfill}}"> |
| 199 </paper-icon-button> | 203 </paper-icon-button> |
| 200 </template> | |
| 201 | 204 |
| 202 <template is="dom-if" if="{{isSplit}}"> | |
| 203 <paper-icon-button title="Scroll to split" | 205 <paper-icon-button title="Scroll to split" |
| 204 icon="editor:vertical-align-center" on-tap="_scrollToSplit"> | 206 icon="editor:vertical-align-center" on-tap="_scrollToSplit"> |
| 205 </paper-icon-button> | 207 </paper-icon-button> |
| 206 </template> | 208 </template> |
| 207 | 209 |
| 208 <template is="dom-if" if="{{isSplit}}"> | |
| 209 <paper-icon-button toggles | |
| 210 title="Load new logs, or backfill from top." | |
| 211 icon="{{backfillIconName}}" | |
| 212 active="{{backfill}}"> | |
| 213 </paper-icon-button> | |
| 214 </template> | |
| 215 </template> | |
| 216 | |
| 217 <template is="dom-if" if="{{_not(playing)}}"> | |
| 218 <paper-button class="paper-button-highlight" toggles raised | 210 <paper-button class="paper-button-highlight" toggles raised |
| 219 active="{{wrapLines}}"> | 211 active="{{wrapLines}}"> |
| 220 Wrap | 212 Wrap |
| 221 </paper-button> | 213 </paper-button> |
| 222 | 214 |
| 223 <template is="dom-if" if="{{metadata}}"> | 215 <template is="dom-if" if="{{metadata}}"> |
| 224 <paper-button class="paper-button-highlight" toggles raised | 216 <paper-button class="paper-button-highlight" toggles raised |
| 225 active="{{showMetadata}}"> | 217 active="{{showMetadata}}"> |
| 226 Metadata | 218 Metadata |
| 227 </paper-button> | 219 </paper-button> |
| 228 </template> | 220 </template> |
| 229 </template> | 221 </template> |
| 230 </div> | 222 </div> |
| 231 | 223 |
| 232 <!-- Display current fetching status, if stream data is still loading. --> | 224 <!-- Display current fetching status, if stream data is still loading. --> |
| 233 <div id="streamStatus"> | 225 <div id="streamStatus"> |
| 234 <template is="dom-if" if="{{streamStatus}}"> | 226 <template is="dom-if" if="{{streamStatus}}"> |
| 235 <table> | 227 <table> |
| 236 <template is="dom-repeat" items="{{streamStatus}}"> | 228 <template is="dom-repeat" items="{{streamStatus}}"> |
| 237 <tr> | 229 <tr> |
| 238 <td>{{item.name}}</td> | 230 <td>{{item.name}}</td> |
| 239 <td>{{item.desc}}</td> | 231 <td>{{item.desc}}</td> |
| 240 </tr> | 232 </tr> |
| 241 </template> | 233 </template> |
| 242 </table> | 234 </table> |
| 243 </template> | 235 </template> |
| 244 </div> | 236 </div> |
| 245 | 237 |
| 246 <!-- Muxed log content. --> | 238 <!-- Muxed log content. --> |
| 247 <div id="logContent" | 239 <div id="logContent"> |
| 248 on-mousewheel="_handleMouseWheel"> | |
| 249 <div id="logs"> | 240 <div id="logs"> |
| 250 <!-- Content will be populated with JavaScript as logs are loaded. | 241 <!-- Content will be populated with JavaScript as logs are loaded. |
| 251 | 242 |
| 252 <div class="log-entry"> | 243 <div class="log-entry"> |
| 253 <div class="log-entry-meta"> | 244 <div class="log-entry-meta"> |
| 254 <div class="log-entry-meta-line">(Meta 0)</div> | 245 <div class="log-entry-meta-line">(Meta 0)</div> |
| 255 ... | 246 ... |
| 256 <div class="log-entry-meta-line">(Meta N)</div> | 247 <div class="log-entry-meta-line">(Meta N)</div> |
| 257 </div> | 248 </div> |
| 258 <div class="log-entry-content"> | 249 <div class="log-entry-content"> |
| 259 LINE #0 | 250 LINE #0 |
| 260 ... | 251 ... |
| 261 LINE #N | 252 LINE #N |
| 262 </div> | 253 </div> |
| 263 </div> | 254 </div> |
| 264 ... | 255 ... |
| 265 | 256 |
| 266 | 257 |
| 267 Note that we can't use templating to show/hide the log dividers, | 258 Note that we can't use templating to show/hide the log dividers, |
| 268 since our positional log insertion requires them to be present and | 259 since our positional log insertion requires them to be present and |
| 269 move along with insertions as points of reference. | 260 move along with insertions as points of reference. |
| 270 --> | 261 --> |
| 271 | 262 |
| 272 <div id="logSplit" class="logFetchButtonContainer"> | 263 <div id="logSplit" class="logFetchButtonContainer"> |
| 273 <!-- Insert point (prepend for head, append for tail). --> | 264 <!-- Insert point (prepend for head, append for tail). --> |
| 274 <paper-button id="logSplitUp" | 265 <paper-button id="logSplitUp" |
| 275 class="logFetchButton logSplitUpButton giant" | 266 class="logFetchButton logSplitUpButton giant" |
| 276 text="Load Above" | 267 text="Load Above" |
| 277 disabled="[[streamAnchorsNotClickable]]" | 268 disabled="[[playing]]" |
| 278 on-click="_handleUpClick"> | 269 on-click="_handleUpClick"> |
| 279 <iron-icon icon="file-upload"></iron-icon> | 270 <iron-icon icon="file-upload"></iron-icon> |
| 280 </paper-button> | 271 </paper-button> |
| 281 <paper-button id="logSplitDown" | 272 <paper-button id="logSplitDown" |
| 282 class="logFetchButton logSplitDownButton giant" | 273 class="logFetchButton logSplitDownButton giant" |
| 283 text="Load Below" | 274 text="Load Below" |
| 284 disabled="[[streamAnchorsNotClickable]]" | 275 disabled="[[playing]]" |
| 285 on-click="_handleDownClick"> | 276 on-click="_handleDownClick"> |
| 286 <iron-icon icon="file-download"></iron-icon> | 277 <iron-icon icon="file-download"></iron-icon> |
| 287 </paper-button> | 278 </paper-button> |
| 288 </div> | 279 </div> |
| 289 | 280 |
| 290 <div id="logBottom" class="logFetchButtonContainer"> | 281 <div id="logBottom" class="logFetchButtonContainer"> |
| 291 <!-- | 282 <!-- |
| 292 Bottom of the log stream (red bottom line). When tail is complete, | 283 Bottom of the log stream (red bottom line). When tail is complete, |
| 293 all future logs get prepended to this. | 284 all future logs get prepended to this. |
| 294 --> | 285 --> |
| 295 <paper-button id="logBottomButton" | 286 <paper-button id="logBottomButton" |
| 296 class="logFetchButton logBottomButton giant" | 287 class="logFetchButton logBottomButton giant" |
| 297 disabled="[[streamAnchorsNotClickable]]" | 288 disabled="[[playing]]" |
| 298 on-click="_handleBottomClick"> | 289 on-click="_handleBottomClick"> |
| 299 <iron-icon icon="arrow-drop-down"></iron-icon> | 290 <iron-icon icon="arrow-drop-down"></iron-icon> |
| 300 </paper-button> | 291 </paper-button> |
| 301 </div> | 292 </div> |
| 302 <div id="logEnd"></div> | 293 <div id="logEnd"></div> |
| 303 </div> | 294 </div> |
| 304 </div> | 295 </div> |
| 305 | 296 |
| 306 </div> | 297 </div> |
| 307 | 298 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 * The smaller the value, the smoother the page will behave while logs are | 347 * The smaller the value, the smoother the page will behave while logs are |
| 357 * loading. However, the logs will also load slower because of forced | 348 * loading. However, the logs will also load slower because of forced |
| 358 * renders in between elements. | 349 * renders in between elements. |
| 359 */ | 350 */ |
| 360 burst: { | 351 burst: { |
| 361 type: Number, | 352 type: Number, |
| 362 value: 1000, | 353 value: 1000, |
| 363 notify: true, | 354 notify: true, |
| 364 }, | 355 }, |
| 365 | 356 |
| 357 /** If populated, the stream name at the top will link to this URL. */ |
| 358 streamLinkUrl: { |
| 359 type: String, |
| 360 value: null, |
| 361 notify: true, |
| 362 }, |
| 363 |
| 366 /** | 364 /** |
| 367 * If true, render metadata blocks alongside their log entries. | 365 * If true, render metadata blocks alongside their log entries. |
| 368 * | 366 * |
| 369 * This will cause significantly more HTML elements during rendering (so | 367 * This will cause significantly more HTML elements during rendering (so |
| 370 * that each metadata element can show up next to its row) and greatly | 368 * that each metadata element can show up next to its row) and greatly |
| 371 * slow the viewer down. | 369 * slow the viewer down. |
| 372 */ | 370 */ |
| 373 metadata: { | 371 metadata: { |
| 374 type: Boolean, | 372 type: Boolean, |
| 375 value: false, | 373 value: false, |
| 376 }, | 374 }, |
| 377 | 375 |
| 378 /** If true, show log metadata column. */ | 376 /** If true, show log metadata column. */ |
| 379 showMetadata: { | 377 showMetadata: { |
| 380 type: Boolean, | 378 type: Boolean, |
| 381 value: false, | 379 value: false, |
| 382 observer: "_showMetadataChanged", | 380 observer: "_showMetadataChanged", |
| 383 }, | 381 }, |
| 384 | 382 |
| 385 /** If true, wrap log lines to the screen. */ | 383 /** If true, wrap log lines to the screen. */ |
| 386 wrapLines: { | 384 wrapLines: { |
| 387 type: Boolean, | 385 type: Boolean, |
| 388 value: false, | 386 value: false, |
| 389 observer: "_wrapLinesChanged", | 387 observer: "_wrapLinesChanged", |
| 390 }, | 388 }, |
| 391 | 389 |
| 392 /** | 390 /** Whether or not to show play/pause button. */ |
| 393 * If true, automatically scroll the page to the bottom of the logs | 391 showPlayPause: { |
| 394 * while they are streaming. | 392 type: Boolean, |
| 395 */ | 393 value: true, |
| 396 follow: { | 394 readOnly: true, |
| 395 }, |
| 396 |
| 397 /** Whether or not to show stream control buttons. */ |
| 398 showStreamControls: { |
| 397 type: Boolean, | 399 type: Boolean, |
| 398 value: false, | 400 value: false, |
| 399 observer: "_followChanged", | 401 readOnly: true, |
| 400 }, | 402 }, |
| 401 | 403 |
| 402 /** | 404 /** Whether or not to show the "split streams" button. */ |
| 403 * True if the stream is capable of being split. | 405 showSplitButton: { |
| 404 * | 406 type: Boolean, |
| 405 * This is set by the viewer via "_updateControls". | 407 value: false, |
| 406 * | 408 readOnly: true, |
| 407 * A split is a visual break in the log continuity, where content above | 409 }, |
| 408 * the split contains logs starting at the beginning of the stream, while | 410 |
| 409 * content below the split contains data from the last log entry in the | 411 /** Whether or not to show the split controls. */ |
| 410 * stream at the time of the split. | 412 showSplitControls: { |
| 411 */ | |
| 412 canSplit: { | |
| 413 type: Boolean, | 413 type: Boolean, |
| 414 value: false, | 414 value: false, |
| 415 readOnly: true, | 415 readOnly: true, |
| 416 }, | 416 }, |
| 417 | 417 |
| 418 /** | 418 /** |
| 419 * True if log streaming controls should be visible. | |
| 420 * | |
| 421 * This is set by the viewer via "_updateControls". | |
| 422 */ | |
| 423 showStreamingControls: { | |
| 424 type: Boolean, | |
| 425 value: true, | |
| 426 readOnly: true, | |
| 427 }, | |
| 428 | |
| 429 /** | |
| 430 * True if the view is currently split. | |
| 431 * | |
| 432 * This is set by the viewer via "_updateControls". | |
| 433 */ | |
| 434 isSplit: { | |
| 435 type: Boolean, | |
| 436 value: false, | |
| 437 readOnly: true, | |
| 438 }, | |
| 439 | |
| 440 /** | |
| 441 * True if the stream anchors (split bar buttons) can be clicked. | |
| 442 */ | |
| 443 streamAnchorsNotClickable: { | |
| 444 type: Boolean, | |
| 445 computed: | |
| 446 '_computeAnchorsNotClickable(playing, showStreamingControls)', | |
| 447 }, | |
| 448 | |
| 449 /** | |
| 450 * True if the viewer should automatically load more logs after the | 419 * True if the viewer should automatically load more logs after the |
| 451 * previous batch has finished. | 420 * previous batch has finished. |
| 452 */ | 421 */ |
| 453 playing: { | 422 playing: { |
| 454 type: Boolean, | 423 type: Boolean, |
| 455 value: false, | 424 value: false, |
| 456 observer: "_playingChanged", | 425 observer: "_playingChanged", |
| 457 }, | 426 }, |
| 458 | 427 |
| 459 /** | 428 /** |
| (...skipping 16 matching lines...) Expand all Loading... |
| 476 }, | 445 }, |
| 477 | 446 |
| 478 /** | 447 /** |
| 479 * (Computed) the iron-icon name of the backfill button icon. | 448 * (Computed) the iron-icon name of the backfill button icon. |
| 480 */ | 449 */ |
| 481 backfillIconName: { | 450 backfillIconName: { |
| 482 type: String, | 451 type: String, |
| 483 computed: '_computeBackfillIconName(backfill)', | 452 computed: '_computeBackfillIconName(backfill)', |
| 484 }, | 453 }, |
| 485 | 454 |
| 486 /** If populated, the stream name at the top will link to this URL. */ | |
| 487 streamLinkUrl: { | |
| 488 type: String, | |
| 489 value: null, | |
| 490 notify: true, | |
| 491 }, | |
| 492 | |
| 493 /** | 455 /** |
| 494 * The current stream status. This is an Array of objects: | 456 * The current stream status. This is an Array of objects: |
| 495 * obj.name is the name of the stream. | 457 * obj.name is the name of the stream. |
| 496 * obj.desc is the status description of the stream. | 458 * obj.desc is the status description of the stream. |
| 497 */ | 459 */ |
| 498 streamStatus: { | 460 streamStatus: { |
| 499 type: Array, | 461 type: Array, |
| 500 value: null, | 462 value: null, |
| 501 notify: true, | 463 notify: true, |
| 502 readOnly: true, | 464 readOnly: true, |
| 503 }, | 465 }, |
| 504 | 466 |
| 505 /** | 467 /** |
| 506 * The text content of the status element at the bottom of the page. | 468 * The text content of the status element at the bottom of the page. |
| 507 */ | 469 */ |
| 508 statusBar: { | 470 statusBar: { |
| 509 type: String, | 471 type: String, |
| 510 value: null, | 472 value: null, |
| 511 readOnly: true, | 473 readOnly: true, |
| 512 }, | 474 }, |
| 513 }, | 475 }, |
| 514 | 476 |
| 515 created: function() { | 477 created: function() { |
| 516 this._view = new LogDog.View(this); | 478 this._view = new LogDog.View(this); |
| 517 }, | 479 }, |
| 518 | 480 |
| 519 attached: function() { | 481 attached: function() { |
| 520 this._view.reset(); | 482 this._view.reset(); |
| 483 this.$.logContent.addEventListener('wheel', |
| 484 this._handleMouseWheel.bind(this)); |
| 521 }, | 485 }, |
| 522 | 486 |
| 523 detached: function() { | 487 detached: function() { |
| 524 this._view.detach(); | 488 this._view.detach(); |
| 489 this.$.logContent.removeEventListener('wheel', |
| 490 this._handleMouseWheel.bind(this)); |
| 525 }, | 491 }, |
| 526 | 492 |
| 527 stop: function() { | 493 stop: function() { |
| 528 this._view.stop(); | 494 this._view.stop(); |
| 529 }, | 495 }, |
| 530 | 496 |
| 531 _polymerAppendChild: function(e) { | 497 _polymerAppendChild: function(e) { |
| 532 Polymer.dom(this.root).appendChild(e); | 498 Polymer.dom(this.root).appendChild(e); |
| 533 }, | 499 }, |
| 534 | 500 |
| 535 _handleMouseWheel: function(e) { | 501 _handleMouseWheel: function(e) { |
| 536 this._view.handleMouseWheel(); | 502 this._view.handleMouseWheel(e.deltaY >= 0); |
| 537 }, | 503 }, |
| 538 | 504 |
| 539 _handleDownClick: function(e) { | 505 _handleDownClick: function(e) { |
| 540 this._view.handleDownClick(); | 506 this._view.handleDownClick(); |
| 541 }, | 507 }, |
| 542 | 508 |
| 543 _handleUpClick: function(e) { | 509 _handleUpClick: function(e) { |
| 544 this._view.handleUpClick(); | 510 this._view.handleUpClick(); |
| 545 }, | 511 }, |
| 546 | 512 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 562 }, | 528 }, |
| 563 | 529 |
| 564 /** | 530 /** |
| 565 * Callback when "wrapLines" has changed. This adds/removes the | 531 * Callback when "wrapLines" has changed. This adds/removes the |
| 566 * "wrapLines" CSS class to the log data. | 532 * "wrapLines" CSS class to the log data. |
| 567 */ | 533 */ |
| 568 _wrapLinesChanged: function(v) { | 534 _wrapLinesChanged: function(v) { |
| 569 this.toggleClass("wrapLines", v, this.$.logs); | 535 this.toggleClass("wrapLines", v, this.$.logs); |
| 570 }, | 536 }, |
| 571 | 537 |
| 572 /** Callback when "follow" has changed. */ | 538 /** Callback when "playing" has changed. */ |
| 573 _playingChanged: function(v) { | 539 _playingChanged: function(v) { |
| 574 this._view.handlePlayingChanged(v); | 540 this._view.handlePlayPauseChanged(v); |
| 575 }, | 541 }, |
| 576 | 542 |
| 577 _computePlayingIconName: function(playing) { | 543 _computePlayingIconName: function(playing) { |
| 578 return ( (playing) ? | 544 return ( (playing) ? |
| 579 "av:pause-circle-outline" : "av:play-circle-outline" ); | 545 "av:pause-circle-outline" : "av:play-circle-outline" ); |
| 580 }, | 546 }, |
| 581 | 547 |
| 582 /** Callback when "follow" has changed. */ | 548 /** Callback when "backfill" has changed. */ |
| 583 _backfillChanged: function(v) { | 549 _backfillChanged: function(v) { |
| 584 this._view.handleBackfillChanged(v); | 550 this._view.handleBackfillChanged(v); |
| 585 }, | 551 }, |
| 586 | 552 |
| 587 _computeBackfillIconName: function(backfill) { | 553 _computeBackfillIconName: function(backfill) { |
| 588 return ( (backfill) ? | 554 return ( (backfill) ? |
| 589 "editor:border-bottom" : "editor:border-top" ); | 555 "editor:border-bottom" : "editor:border-top" ); |
| 590 }, | 556 }, |
| 591 | 557 |
| 592 /** Callback when "follow" has changed. */ | |
| 593 _followChanged: function(v) { | |
| 594 this._view.handleFollowChanged(v); | |
| 595 }, | |
| 596 | |
| 597 /** Callback when "split" button has been clicked. */ | 558 /** Callback when "split" button has been clicked. */ |
| 598 _splitClicked: function() { | 559 _splitClicked: function() { |
| 599 this._view.handleSplitClicked(); | 560 this._view.handleSplitClicked(); |
| 600 }, | 561 }, |
| 601 | 562 |
| 602 /** Callback when "split" button has been clicked. */ | 563 /** Callback when "split" button has been clicked. */ |
| 603 _scrollToSplit: function() { | 564 _scrollToSplit: function() { |
| 604 this._view.handleScrollToSplitClicked(); | 565 this._view.handleScrollToSplitClicked(); |
| 605 }, | 566 }, |
| 606 | 567 |
| 607 _updateSplitVisible: function(v) { | 568 _updateSplitVisible: function(v) { |
| 608 this.toggleClass("logFetchButtonVisible", v, this.$.logSplit); | 569 this.toggleClass("logFetchButtonVisible", v, this.$.logSplit); |
| 609 }, | |
| 610 | |
| 611 _updateBottomVisible: function(v) { | |
| 612 this.toggleClass("logFetchButtonVisible", v, this.$.logBottom); | 570 this.toggleClass("logFetchButtonVisible", v, this.$.logBottom); |
| 613 }, | 571 }, |
| 614 | 572 |
| 615 _computeAnchorsNotClickable: function(playing, showStreamingControls, | |
| 616 rendering) { | |
| 617 // Anchors are not clickable if we're playing or the controls are | |
| 618 // not visible. | |
| 619 return ( playing || (!showStreamingControls) || rendering ); | |
| 620 }, | |
| 621 | |
| 622 /** Filter function to invert a value. */ | |
| 623 _not: function(v) { | |
| 624 return (!v); | |
| 625 }, | |
| 626 | |
| 627 _onSignin: function() { | 573 _onSignin: function() { |
| 628 this._view.handleSignin(); | 574 this._view.handleSignin(); |
| 629 }, | 575 }, |
| 630 }); | 576 }); |
| 631 </script> | 577 </script> |
| OLD | NEW |