| <!-- |
| The common.js file must be included before this file. |
| |
| This in an HTML Import-able file that contains the definition |
| of the following elements: |
| |
| <arb-status-sk> |
| |
| To use this file import it: |
| |
| <link href="/res/imp/arb-status-sk.html" rel="import" /> |
| |
| Usage: |
| |
| <arb-status-sk></arb-status-sk> |
| |
| Properties: |
| reload - How often (in seconds) to reload data. |
| |
| Methods: |
| None. |
| |
| Events: |
| None |
| --> |
| <link rel="import" href="/res/common/imp/human-date-sk.html"> |
| <link rel="import" href="/res/common/imp/styles-sk.html"> |
| <link rel="import" href="/res/common/imp/url-params-sk.html"> |
| <link rel="import" href="/res/imp/bower_components/iron-flex-layout/iron-flex-layout-classes.html"> |
| <link rel="import" href="/res/imp/bower_components/paper-button/paper-button.html"> |
| <link rel="import" href="/res/imp/bower_components/paper-dialog/paper-dialog.html"> |
| <link rel="import" href="/res/imp/bower_components/paper-dropdown-menu/paper-dropdown-menu.html"> |
| <link rel="import" href="/res/imp/bower_components/paper-input/paper-input.html"> |
| <link rel="import" href="/res/imp/bower_components/paper-item/paper-item.html"> |
| <link rel="import" href="/res/imp/bower_components/paper-listbox/paper-listbox.html"> |
| <link rel="import" href="/res/imp/bower_components/paper-spinner/paper-spinner.html"> |
| <link rel="import" href="/res/imp/bower_components/paper-tabs/paper-tabs.html"> |
| <link rel="stylesheet" href="/res/common/css/md.css"> |
| <dom-module id="arb-status-sk"> |
| <style include="iron-flex iron-flex-alignment iron-positioning styles-sk"> |
| :host { |
| font-family: sans-serif; |
| } |
| #loadstatus { |
| font-size: 0.8em; |
| padding: 0px 15px; |
| } |
| #tabsContainer { |
| width: 400px; |
| } |
| a,a.visited { |
| color: #1f78b4; |
| } |
| |
| paper-tabs { |
| background: #A6CEE3; |
| color: #555; |
| } |
| paper-tab.iron-selected { |
| background: #1F78B4; |
| color: white; |
| border: #1F78B4 solid 2px; |
| } |
| paper-tab { |
| border: white solid 2px; |
| } |
| |
| .big { |
| font-size: 1.3em; |
| } |
| .small { |
| font-size: 0.8em; |
| } |
| .hidden { |
| display: none; |
| } |
| .nowrap { |
| white-space: nowrap; |
| } |
| .rollCandidate { |
| height: 80px; |
| } |
| .trybot { |
| margin: 5px; |
| } |
| </style> |
| <template> |
| <div id="tabsContainer"> |
| <paper-tabs id="tabs" attr-for-selected="id" selected="{{selectedTab}}" no-bar> |
| <paper-tab id="status">Roller Status</paper-tab> |
| <paper-tab id="manual">Trigger Manual Rolls</paper-tab> |
| </paper-tabs> |
| </div> |
| <div id="statusDisplay"> |
| <div class="horizontal layout center" id="loadstatus"> |
| <paper-input type="number" value="{{reload}}" label="Reload (s)" prevent-invalid-input></paper-input> |
| <div class="flex"></div> |
| <div>Last loaded at <span>{{_lastLoaded}}</span></div> |
| </div> |
| <div class="table"> |
| <template is="dom-if" if="{{_exists(parentWaterfall)}}"> |
| <div class="tr"> |
| <div class="td nowrap">Parent Repo Build Status</div> |
| <div class="td nowrap unknown"> |
| <span class="big"><a href$="{{parentWaterfall}}" target="_blank">{{parentWaterfall}}</a></span> |
| </div> |
| </div> |
| </template> |
| <div class="tr"> |
| <div class="td nowrap">Current Mode:</div> |
| <div class="td nowrap unknown"> |
| <span class="big">{{mode}}</span> |
| </div> |
| </div> |
| <div class="tr"> |
| <div class="td nowrap">Set By:</div> |
| <div class="td nowrap unknown"> |
| <!-- No line break below, or we get a space before the colon, eg. |
| user@google.com : Mode change message --> |
| <span>[[modeChangeBy]]</span><template is="dom-if" if="{{modeChangeMsg}}"><span>: [[modeChangeMsg]]</span></template> |
| </div> |
| </div> |
| <div class="tr"> |
| <div class="td nowrap">Change Mode:</div> |
| <div class="td nowrap"> |
| <template is="dom-repeat" items="{{modeButtons}}"> |
| <button class$="{{_buttonClass(item)}}" on-tap="_buttonPressed" disabled$="{{_modeChangePending}}" value="{{item.value}}">{{item.label}}</button> |
| </template> |
| <paper-spinner active$="{{_modeChangePending}}"></paper-spinner> |
| </div> |
| </div> |
| <div class="tr"> |
| <div class="td nowrap">Status:</div> |
| <div class="td nowrap"> |
| <span class$="{{_statusClass(status)}}"><span class="big">{{status}}</span></span> |
| <template is="dom-if" if="{{_isThrottled(status)}}"> |
| <span>until <human-date-sk date="[[throttledUntil]]" seconds></human-date-sk></span> |
| <button on-tap="_unthrottle">Force Unthrottle</button> |
| </template> |
| </div> |
| </div> |
| <template is="dom-if" if="{{_computeShowError(_editRights,error)}}"> |
| <div class="tr"> |
| <div class="td nowrap">Error:</div> |
| <div class="td"><pre>{{error}}</pre></div> |
| </div> |
| </template> |
| <div class="tr"> |
| <div class="td nowrap">Current Roll:</div> |
| <div class="td"> |
| <div> |
| <template is="dom-if" if="{{_exists(currentRoll)}}"> |
| <a href="{{_issueURL(currentRoll)}}" class="big" target="_blank">{{currentRoll.subject}}</a> |
| </template> |
| <template is="dom-if" if="{{!_exists(currentRoll)}}"> |
| <span>(none)</span> |
| </template> |
| </div> |
| <div> |
| <template is="dom-repeat" items="{{currentRoll.tryResults}}"> |
| <div class="trybot"> |
| <template is="dom-if" if="{{_exists(item.url)}}"> |
| <a href="{{item.url}}" class$="{{_trybotClass(item)}}" target="_blank">{{item.builder}}</a> |
| </template> |
| <template is="dom-if" if="{{!_exists(item.url)}}"> |
| <span class="nowrap" class$="{{_trybotClass(item)}}">{{item.builder}}</span> |
| </template> |
| <template is="dom-if" if="{{!_isCQ(item)}}"> |
| <span class="nowrap small">({{item.category}})</span> |
| </template> |
| </div> |
| </template> |
| </div> |
| </div> |
| </div> |
| <template is="dom-if" if="{{_exists(lastRoll)}}"> |
| <div class="tr"> |
| <div class="td nowrap">Previous roll result:</div> |
| <div class="td"> |
| <span class$="{{_rollClass(lastRoll)}}">{{_rollResult(lastRoll)}}</span> |
| <a href="{{_issueURL(lastRoll)}}" target="_blank" class="small">(detail)</a> |
| </div> |
| </div> |
| </template> |
| <div class="tr"> |
| <div class="td nowrap">History:</div> |
| <div class="td"> |
| <div class="table"> |
| <div class="tr"> |
| <div class="th">Roll</div> |
| <div class="th">Last Modified</div> |
| <div class="th">Result</div> |
| </div> |
| <template is="dom-repeat" items="{{recent}}"> |
| <div class="tr"> |
| <div class="td"><a href="{{_issueURL(item)}}" target="_blank">{{item.subject}}</a></div> |
| <div class="td"><human-date-sk date="{{item.modified}}" diff></human-date-sk> ago</div> |
| <div class="td"><span class$="{{_rollClass(item)}}">{{_rollResult(item)}}</span></div> |
| </div> |
| </template> |
| </div> |
| </div> |
| </div> |
| <div class="tr"> |
| <div class="td nowrap">Full History:</div> |
| <div class="td"> |
| <a href$="{{fullHistoryUrl}}" target="_blank"> |
| {{fullHistoryUrl}} |
| </a> |
| </div> |
| </div> |
| <div class="tr"> |
| <div class="td nowrap">Strategy for choosing next roll revision:</div> |
| <div class="td nowrap"> |
| <paper-dropdown-menu id="strategyDropDown"> |
| <paper-listbox id="strategyMenu" class="dropdown-content" selected="{{_selectedStrategy}}" id="strategy_listbox" attr-for-selected="value"> |
| <template is="dom-repeat" items="[[validStrategies]]"> |
| <paper-item value="[[item]]">[[item]]</paper-item> |
| </template> |
| </paper-listbox> |
| </paper-dropdown-menu> |
| </div> |
| </div> |
| <div class="tr"> |
| <div class="td nowrap">Set By:</div> |
| <div class="td nowrap unknown"> |
| <!-- No line break below, or we get a space before the colon, eg. |
| user@google.com : Strategy change message --> |
| <span>[[strategyChangeBy]]</span><template is="dom-if" if="{{strategyChangeMsg}}"><span>: [[strategyChangeMsg]]</span></template> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div id="rollCandidates" class="hidden"> |
| <div class="table"> |
| <template is="dom-if" if="{{!supportsManualRolls}}"> |
| This roller does not support manual rolls. If you want this feature, |
| update the config file for the roller to enable it. Note that some |
| rollers cannot support manual rolls for technical reasons. |
| </template> |
| <template is="dom-if" if="{{supportsManualRolls}}"> |
| <template is="dom-if" if="{{!rollCandidates}}"> |
| The roller is up to date; there are no revisions which could be manually rolled. |
| </template> |
| <template is="dom-if" if="{{rollCandidates}}"> |
| <div class="tr"> |
| <div class="th">Revision</div> |
| <div class="th">Description</div> |
| <div class="th">Timestamp</div> |
| <div class="th">Requester</div> |
| <div class="th">Requested at</div> |
| <div class="th">Roll</div> |
| </div> |
| <template is="dom-repeat" items="[[rollCandidates]]"> |
| <div class="tr rollCandidate"> |
| <div class="td"> |
| <template is="dom-if" if="{{item.revision.url}}"> |
| <a href="[[item.revision.url]]" target="_blank">[[item.revision.display]]</a> |
| </template> |
| <template is="dom-if" if="{{!item.revision.url}}"> |
| [[item.revision.display]] |
| </template> |
| </div> |
| <div class="td">[[_revDescription(item.revision.description)]]</div> |
| <div class="td"><human-date-sk date="[[item.revision.timestamp]]"></human-date-sk></div> |
| <div class="td">[[item.requester]]</div> |
| <div class="td"><human-date-sk date="[[item.timestamp]]"></human-date-sk></div> |
| <div class="td"> |
| <template is="dom-if" if="{{_reqHasURL(item)}}"> |
| <a href="{{item.url}}", target="_blank">{{item.url}}</a> |
| </template> |
| <template is="dom-if" if="{{_reqHasStatus(item)}}"> |
| [[item.status]] |
| </template> |
| <template is="dom-if" if="{{_reqHasButton(item)}}"> |
| <button on-tap="_requestManualRoll" data-rev$="{{item.revision.id}}" class="requestRoll">Request Roll</button> |
| </template> |
| <template is="dom-if" if="{{_reqHasResult(item)}}"> |
| <span class$="{{_reqResultClass(item)}}">[[item.result]]</span> |
| </template> |
| </div> |
| </div> |
| </template> |
| </template> |
| </template> |
| </div> |
| </div> |
| <!-- Warning for future travelers: paper-dialog doesn't like to be inside of |
| divs. It's best left just inside the top-level <template> --> |
| <paper-dialog id="mode_change_dialog" modal on-iron-overlay-closed="_changeMode"> |
| <h2>Enter a message:</h2> |
| <paper-input type="text" id="mode_change_msg"></paper-input> |
| <paper-button dialog-dismiss>Cancel</paper-button> |
| <paper-button dialog-confirm>Submit</paper-button> |
| </paper-dialog> |
| <paper-dialog id="strategy_change_dialog" modal on-iron-overlay-closed="_changeStrategy"> |
| <h2>Enter a message:</h2> |
| <paper-input type="text" id="strategy_change_msg"></paper-input> |
| <paper-button dialog-dismiss>Cancel</paper-button> |
| <paper-button dialog-confirm>Submit</paper-button> |
| </paper-dialog> |
| <url-param-sk name="tab" value="{{selectedTab}}" default="status"></url-param-sk> |
| </template> |
| <script> |
| Polymer({ |
| is: 'arb-status-sk', |
| properties: { |
| mode: { |
| type: String, |
| value: "(not yet loaded)", |
| readOnly: true, |
| }, |
| modeChangeBy: { |
| type: String, |
| value: "", |
| readOnly: true, |
| }, |
| modeChangeMsg: { |
| type: String, |
| value: "", |
| readOnly: true, |
| }, |
| status: { |
| type: String, |
| value: "(not yet loaded)", |
| readOnly: true, |
| }, |
| currentRoll: { |
| type: Object, |
| value: null, |
| readOnly: true, |
| }, |
| error: { |
| type: String, |
| value: null, |
| readOnly: true, |
| }, |
| fullHistoryUrl: { |
| type: String, |
| value: "", |
| readOnly: true, |
| }, |
| issueUrlBase: { |
| type: String, |
| value: "", |
| readOnly: true, |
| }, |
| lastRoll: { |
| type: Object, |
| value: null, |
| readOnly: true, |
| }, |
| recent: { |
| type: Array, |
| value: function() { return []; }, |
| readOnly: true, |
| }, |
| reload: { |
| type: Number, |
| observer: "_reloadChanged", |
| value: 60, |
| }, |
| initialSelectedMode: { |
| type: Number, |
| value: 0, |
| readOnly: true, |
| }, |
| modeButtons: { |
| type: Array, |
| value: function() { return []; }, |
| readOnly: true, |
| }, |
| parentWaterfall: { |
| type: String, |
| value: null, |
| readOnly: true, |
| }, |
| rollCandidates: { |
| type: Array, |
| value: null, |
| }, |
| selectedTab: { |
| type: String, |
| observer: "tabChanged", |
| }, |
| strategy: { |
| type: String, |
| value: "(not yet loaded)", |
| readOnly: true, |
| }, |
| strategyChangeBy: { |
| type: String, |
| value: "", |
| readOnly: true, |
| }, |
| strategyChangeMsg: { |
| type: String, |
| value: "", |
| readOnly: true, |
| }, |
| supportsManualRolls: { |
| type: Boolean, |
| readOnly: true, |
| }, |
| throttledUntil: { |
| type: Number, |
| value: 0, |
| readOnly: true, |
| }, |
| validModes: { |
| type: Array, |
| value: function() { return []; }, |
| readOnly: true, |
| }, |
| validStrategies: { |
| type: Array, |
| value: function() { return []; }, |
| readOnly: true, |
| }, |
| _editRights: { |
| type: Boolean, |
| value: false, |
| }, |
| _lastLoaded: { |
| type: String, |
| value: "not yet loaded", |
| }, |
| _modeChangePending: { |
| type: Boolean, |
| value: false, |
| }, |
| _selectedMode: { |
| type: String, |
| value: "", |
| }, |
| _selectedStrategy: { |
| type: String, |
| value: "", |
| observer: "_selectedStrategyChanged", |
| }, |
| _timeout: { |
| type: Object, |
| value: null, |
| }, |
| }, |
| |
| ready: function() { |
| sk.Login.then(function(status) { |
| this._editRights = status.IsAGoogler; |
| }.bind(this)); |
| this._reload(); |
| }, |
| |
| _buttonClass: function(mode) { |
| return mode.class; |
| }, |
| |
| _buttonPressed: function(e) { |
| if (!this._editRights) { |
| sk.errorMessage("You must be logged in with an @google.com account to set the ARB mode."); |
| return |
| } |
| var mode = e.srcElement.value; |
| if (mode == this.mode) { |
| return; |
| } |
| this._selectedMode = mode; |
| this.$.mode_change_dialog.open(); |
| }, |
| |
| _changeMode: function(e) { |
| if (e.detail.canceled || !e.detail.confirmed) { |
| this._selectedMode = ""; |
| return; |
| } |
| var url = window.location.pathname + "/json/mode"; |
| var body = JSON.stringify({ |
| "message": this.$.mode_change_msg.value, |
| "mode": this._selectedMode, |
| }); |
| sk.errorMessage("Mode change in progress. This may take some time."); |
| this._modeChangePending = true; |
| sk.post(url, body).then(JSON.parse).then(function (json) { |
| this._update(json); |
| this._modeChangePending = false; |
| this.$.mode_change_msg.value; |
| sk.errorMessage("Success!"); |
| }.bind(this), function(err) { |
| this._modeChangePending = false; |
| sk.errorMessage("Failed to change the mode: " + err); |
| }); |
| }, |
| |
| _changeStrategy: function(e) { |
| if (e.detail.canceled || !e.detail.confirmed) { |
| return; |
| } |
| var url = window.location.pathname + "/json/strategy"; |
| var body = JSON.stringify({ |
| "message": this.$.strategy_change_msg.value, |
| "strategy": this._selectedStrategy, |
| }); |
| sk.errorMessage("Strategy change in progress. This may take some time."); |
| sk.post(url, body).then(JSON.parse).then(function (json) { |
| this._update(json); |
| this.$.strategy_change_msg.value = ""; |
| sk.errorMessage("Success!"); |
| }.bind(this), function(err) { |
| sk.errorMessage("Failed to change the strategy: " + err); |
| }); |
| }, |
| |
| _computeShowError: function(editRights, error) { |
| return editRights && error; |
| }, |
| |
| _issueURL: function(issue) { |
| if (issue) { |
| return this.issueUrlBase + issue.issue; |
| } |
| }, |
| |
| _exists: function(obj) { |
| return !!obj; |
| }, |
| |
| _getModeButtonLabel: function(currentMode, mode) { |
| // TODO(borenet): This is a hack; it doesn't respect this.validModes. |
| return { |
| "running": { |
| "stopped": "stop", |
| "dry run": "switch to dry run", |
| }, |
| "stopped": { |
| "running": "resume", |
| "dry run": "switch to dry run", |
| }, |
| "dry run": { |
| "running": "switch to normal mode", |
| "stopped": "stop", |
| }, |
| }[currentMode][mode]; |
| }, |
| |
| _isCQ: function(tryjob) { |
| return tryjob.category === "cq"; |
| }, |
| |
| _isThrottled: function(st) { |
| return st.indexOf("throttle") >= 0; |
| }, |
| |
| _reloadChanged: function() { |
| this._resetTimeout(); |
| }, |
| |
| _resetTimeout: function() { |
| if (this._timeout) { |
| window.clearTimeout(this._timeout); |
| } |
| if (this.reload > 0) { |
| this._timeout = window.setTimeout(function () { |
| this._reload(); |
| }.bind(this), this.reload * 1000); |
| } |
| }, |
| |
| _reload: function() { |
| var url = window.location.pathname + "/json/status"; |
| console.log("Loading status from " + url); |
| |
| sk.get(url).then(JSON.parse).then(function(json) { |
| this._update(json); |
| }.bind(this)).catch(function(err) { |
| sk.errorMessage(err); |
| this._resetTimeout(); |
| }.bind(this)); |
| }, |
| |
| _reqHasURL: function(req) { |
| return !!req.url; |
| }, |
| |
| _reqHasStatus: function(req) { |
| return !req.url && req.status; |
| }, |
| |
| _reqHasButton: function(req) { |
| return !req.url && !req.status; |
| }, |
| |
| _reqHasResult: function(req) { |
| return !!req.result; |
| }, |
| |
| _reqResultClass: function(req) { |
| return { |
| "SUCCESS": "fg-success", |
| "FAILURE": "fg-failure", |
| }[req.result]; |
| }, |
| |
| _reqResultText: function(req) { |
| return req.result; |
| }, |
| |
| _requestManualRoll: function(e) { |
| var url = window.location.pathname + "/json/manual"; |
| var rev = sk.findParent(e.target, "BUTTON").dataset.rev; |
| var body = JSON.stringify({ |
| "revision": rev, |
| }); |
| sk.post(url, body).then(JSON.parse).then(function(json) { |
| for (var i = 0; i < this.rollCandidates.length; i++) { |
| var rc = this.rollCandidates[i]; |
| if (rc.revision.id == json.revision) { |
| // The returned manual roll request's revision field only contains |
| // the revision ID; we want the whole object, so replace it. |
| json.revision = rc.revision; |
| this.set("rollCandidates." + i, json); |
| break; |
| } |
| } |
| }.bind(this), function(err) { |
| sk.errorMessage("Failed to request manual roll: " + err); |
| }); |
| }, |
| |
| _revDescription: function(desc) { |
| return sk.truncate(desc, 100); |
| }, |
| |
| _rollClass: function(roll) { |
| if (!roll) { |
| return "unknown"; |
| } |
| return { |
| "succeeded": "fg-success", |
| "failed": "fg-failure", |
| "in progress": "fg-unknown", |
| "dry run succeeded": "fg-success", |
| "dry run failed": "fg-failure", |
| "dry run in progress": "fg-unknown", |
| }[roll.result] || "fg-unknown"; |
| }, |
| |
| _rollResult: function(roll) { |
| if (!roll) { |
| return "unknown"; |
| } |
| return roll.result; |
| }, |
| |
| _statusClass: function(status) { |
| return { |
| "idle": "fg-unknown", |
| "active": "fg-unknown", |
| "success": "fg-success", |
| "failure": "fg-failure", |
| "throttled": "fg-failure", |
| "dry run idle": "fg-unknown", |
| "dry run active": "fg-unknown", |
| "dry run success": "fg-success", |
| "dry run success; leaving open": "fg-success", |
| "dry run failure": "fg-failure", |
| "dry run throttled": "fg-failure", |
| "stopped": "fg-failure", |
| }[status] || ""; |
| }, |
| |
| _selectedStrategyChanged: function(e) { |
| if (!this._selectedStrategy || this._selectedStrategy == this.strategy) { |
| return; |
| } |
| if (!this._editRights) { |
| sk.errorMessage("You must be logged in with an @google.com account to set the ARB strategy."); |
| return |
| } |
| this.$.strategy_change_dialog.open(); |
| }, |
| |
| tabChanged: function() { |
| if (this.selectedTab == "status") { |
| this.$.statusDisplay.classList.remove("hidden"); |
| this.$.rollCandidates.classList.add("hidden"); |
| } else if (this.selectedTab == "manual") { |
| this.$.statusDisplay.classList.add("hidden"); |
| this.$.rollCandidates.classList.remove("hidden"); |
| } |
| }, |
| |
| _trybotClass: function(trybot) { |
| if (trybot.status == "STARTED") { |
| return "fg-unknown"; |
| } else if (trybot.status == "COMPLETED") { |
| return { |
| "CANCELED": "fg-failure", |
| "FAILURE": "fg-failure", |
| "SUCCESS": "fg-success", |
| }[trybot.result] || ""; |
| } else { |
| return "fg-unknown"; |
| } |
| }, |
| |
| _unthrottle: function() { |
| var url = window.location.pathname + "/json/unthrottle"; |
| console.log("Unthrottling: " + url); |
| |
| sk.post(url).then(function(json) { |
| sk.errorMessage("Successfully unthrottled the roller. May take a minute or so to start up.") |
| }.bind(this)).catch(function(err) { |
| sk.errorMessage(err); |
| }.bind(this)); |
| }, |
| |
| _update: function(json) { |
| this._setCurrentRoll(json.currentRoll); |
| this._setError(json.error); |
| this._setFullHistoryUrl(json.fullHistoryUrl); |
| this._setIssueUrlBase(json.issueUrlBase); |
| this._setLastRoll(json.lastRoll); |
| this._setMode(json.mode.mode); |
| this._setModeChangeBy(json.mode.user); |
| this._setModeChangeMsg(json.mode.message); |
| this._setParentWaterfall(json.parentWaterfall); |
| this._setRecent(json.recent); |
| this._setInitialSelectedMode(json.validModes.indexOf(json.mode).toString()); |
| this._setStatus(json.status); |
| this._setStrategy(json.strategy.strategy); |
| this._setStrategyChangeBy(json.strategy.user); |
| this._setStrategyChangeMsg(json.strategy.message); |
| this._setSupportsManualRolls(json.supportsManualRolls); |
| this._setThrottledUntil(json.throttledUntil); |
| this._setValidModes(json.validModes); |
| this._setValidStrategies(json.validStrategies); |
| var modeButtons = []; |
| for (var i = 0; i < this.validModes.length; i++) { |
| var m = this.validModes[i]; |
| if (m != this.mode) { |
| modeButtons.push({ |
| "label": this._getModeButtonLabel(this.mode, m), |
| "value": m, |
| }); |
| } |
| } |
| this._setModeButtons(modeButtons); |
| |
| var rollCandidates = null; |
| if (json.notRolledRevs) { |
| rollCandidates = []; |
| var manualByRev = {}; |
| if (json.manualRequests) { |
| for (var i = 0; i < json.manualRequests.length; i++) { |
| var req = json.manualRequests[i]; |
| manualByRev[req.revision] = req; |
| } |
| } |
| for (var i = 0; i < json.notRolledRevs.length; i++) { |
| var rev = json.notRolledRevs[i]; |
| var req = manualByRev[rev.id]; |
| if (!req && this.currentRoll && this.currentRoll.rollingTo == rev.id) { |
| req = { |
| "requester": "autoroller", |
| "status": "STARTED", |
| "timestamp": this.currentRoll.created, |
| "url": this._issueURL(this.currentRoll), |
| }; |
| } else if (!req) { |
| req = {}; |
| } |
| // The manual roll request's revision field only contains the |
| // revision ID; we want the whole object, so replace it. |
| req.revision = rev; |
| rollCandidates.push(req); |
| } |
| } |
| this.set("rollCandidates", rollCandidates); |
| |
| this._lastLoaded = new Date().toLocaleTimeString(); |
| this._resetTimeout(); |
| this._selectedStrategy = json.strategy.strategy |
| console.log("Reloaded status."); |
| }, |
| }); |
| </script> |
| </dom-module> |