|  | (function() { | 
|  | 'use strict'; | 
|  |  | 
|  | const Defs = {}; | 
|  |  | 
|  | const Statuses = window.Gerrit.Checks.Statuses; | 
|  | const StatusPriorityOrder = [ | 
|  | Statuses.FAILED, | 
|  | Statuses.SCHEDULED, | 
|  | Statuses.RUNNING, | 
|  | Statuses.SUCCESSFUL, | 
|  | Statuses.NOT_STARTED, | 
|  | Statuses.NOT_RELEVANT, | 
|  | ]; | 
|  |  | 
|  | const STATE_ALL = 'ALL'; | 
|  | const CheckStateFilters = [STATE_ALL, ...StatusPriorityOrder]; | 
|  |  | 
|  | const CHECKS_POLL_INTERVAL_MS = 60 * 1000; | 
|  | const CHECKS_LIMIT = 20; | 
|  |  | 
|  | /** | 
|  | * @typedef {{ | 
|  | *   _number: number, | 
|  | * }} | 
|  | */ | 
|  | Defs.Change; | 
|  | /** | 
|  | * @typedef {{ | 
|  | *   _number: number, | 
|  | * }} | 
|  | */ | 
|  | Defs.Revision; | 
|  |  | 
|  | const LoadingStatus = { | 
|  | LOADING: 0, | 
|  | EMPTY: 1, | 
|  | RESULTS: 2, | 
|  | NOT_CONFIGURED: 3, | 
|  | }; | 
|  |  | 
|  | Polymer({ | 
|  | is: 'gr-checks-view', | 
|  |  | 
|  | properties: { | 
|  | revision: { | 
|  | type: Object, | 
|  | observer: '_handleRevisionUpdate', | 
|  | }, | 
|  | change: Object, | 
|  | /** @type {function(number, number): !Promise<!Object>} */ | 
|  | getChecks: Function, | 
|  | /** @type {function(string): !Promise<Boolean>} */ | 
|  | isConfigured: Function, | 
|  | /** @type {function(string, string): !Promise<!Object>} */ | 
|  | pluginRestApi: Object, | 
|  | _checks: Array, | 
|  | _status: { | 
|  | type: Object, | 
|  | value: LoadingStatus.LOADING, | 
|  | }, | 
|  | _visibleChecks: { | 
|  | type: Array, | 
|  | }, | 
|  | _statuses: Array, | 
|  | pollChecksInterval: Number, | 
|  | visibilityChangeListenerAdded: { | 
|  | type: Boolean, | 
|  | value: false, | 
|  | }, | 
|  | _createCheckerCapability: { | 
|  | type: Boolean, | 
|  | value: false, | 
|  | }, | 
|  | _patchSetDropdownItems: { | 
|  | type: Array, | 
|  | value() { return []; }, | 
|  | computed: '_computePatchSetDropdownItems(change)', | 
|  | }, | 
|  | _currentPatchSet: { | 
|  | type: Number, | 
|  | }, | 
|  | _currentStatus: { | 
|  | type: String, | 
|  | value: STATE_ALL, | 
|  | }, | 
|  | _showBlockingChecksOnly: { | 
|  | type: Boolean, | 
|  | value: false, | 
|  | }, | 
|  | _showAllChecks: { | 
|  | type: Boolean, | 
|  | value: false, | 
|  | }, | 
|  | _filteredChecks: Array, | 
|  | _showMoreChecksButton: { | 
|  | type: Boolean, | 
|  | value: false, | 
|  | notify: true, | 
|  | }, | 
|  | }, | 
|  |  | 
|  | observers: [ | 
|  | '_pollChecksRegularly(change, _currentPatchSet, getChecks)', | 
|  | '_updateVisibleChecks(_checks.*, _currentStatus, ' + | 
|  | '_showBlockingChecksOnly, _showAllChecks)', | 
|  | ], | 
|  |  | 
|  | attached() { | 
|  | this.pluginRestApi = this.plugin.restApi(); | 
|  | this._statuses = CheckStateFilters.map(state => { | 
|  | return { | 
|  | text: state, | 
|  | value: state, | 
|  | }; | 
|  | }); | 
|  | this._initCreateCheckerCapability(); | 
|  | }, | 
|  |  | 
|  | detached() { | 
|  | clearInterval(this.pollChecksInterval); | 
|  | this.unlisten(document, 'visibilitychange', '_onVisibililityChange'); | 
|  | }, | 
|  |  | 
|  | _toggleShowChecks() { | 
|  | this._showAllChecks = !this._showAllChecks; | 
|  | }, | 
|  |  | 
|  | _computePatchSetDropdownItems(change) { | 
|  | return Object.values(change.revisions) | 
|  | .filter(patch => patch._number !== 'edit') | 
|  | .map(patch => { | 
|  | return { | 
|  | text: 'Patchset ' + patch._number, | 
|  | value: patch._number, | 
|  | }; | 
|  | }) | 
|  | .sort((a, b) => b.value - a.value); | 
|  | }, | 
|  |  | 
|  | _computeShowText(showAllChecks) { | 
|  | return showAllChecks ? 'Show Less' : 'Show All'; | 
|  | }, | 
|  |  | 
|  | _updateVisibleChecks(checksRecord, status, showBlockingChecksOnly, | 
|  | showAllChecks) { | 
|  | const checks = checksRecord.base; | 
|  | if (!checks) return []; | 
|  | this._filteredChecks = checks.filter(check => { | 
|  | if (showBlockingChecksOnly && (!check.blocking || | 
|  | !check.blocking.length)) return false; | 
|  | return status === STATE_ALL || check.state === status; | 
|  | }); | 
|  | /* The showCheckMessage property is notified for change because the | 
|  | changes to showCheckMessage are not reflected to the dom as the object | 
|  | check has the same reference as before | 
|  | If not notified, then the message for the check is not displayed after | 
|  | clicking the toggle | 
|  | */ | 
|  | this._showMoreChecksButton = this._filteredChecks.length > CHECKS_LIMIT; | 
|  | this._visibleChecks = this._filteredChecks.slice(0, showAllChecks ? | 
|  | undefined : CHECKS_LIMIT); | 
|  | this._visibleChecks.forEach((val, idx) => | 
|  | this.notifyPath(`_visibleChecks.${idx}.showCheckMessage`)); | 
|  | }, | 
|  |  | 
|  | _handleRevisionUpdate(revision) { | 
|  | this._currentPatchSet = revision._number; | 
|  | }, | 
|  |  | 
|  | _handlePatchSetChanged(e) { | 
|  | // gr-dropdown-list returns value of type "String" | 
|  | const patchSet = parseInt(e.detail.value); | 
|  | if (patchSet === this._currentPatchSet) return; | 
|  | this._currentPatchSet = patchSet; | 
|  | }, | 
|  |  | 
|  | _handleBlockingCheckboxClicked() { | 
|  | this._showBlockingChecksOnly = !this._showBlockingChecksOnly; | 
|  | }, | 
|  |  | 
|  | _handleStatusFilterChanged(e) { | 
|  | const status = e.detail.value; | 
|  | if (status === this._currentStatus) return; | 
|  | this._currentStatus = status; | 
|  | }, | 
|  |  | 
|  | _handleCheckersListResize() { | 
|  | // Force polymer to recalculate position of overlay when length of | 
|  | // checkers changes | 
|  | this.$.listOverlay.refit(); | 
|  | }, | 
|  |  | 
|  | _initCreateCheckerCapability() { | 
|  | return this.pluginRestApi.getAccount().then(account => { | 
|  | if (!account) { return; } | 
|  | return this.pluginRestApi | 
|  | .getAccountCapabilities(['checks-administrateCheckers']) | 
|  | .then(capabilities => { | 
|  | if (capabilities['checks-administrateCheckers']) { | 
|  | this._createCheckerCapability = true; | 
|  | } | 
|  | }); | 
|  | }); | 
|  | }, | 
|  |  | 
|  | _handleConfigureClicked() { | 
|  | this.$$('gr-checkers-list')._showConfigureOverlay(); | 
|  | }, | 
|  |  | 
|  | _orderChecks(a, b) { | 
|  | if (a.state != b.state) { | 
|  | const indexA = StatusPriorityOrder.indexOf(a.state); | 
|  | const indexB = StatusPriorityOrder.indexOf(b.state); | 
|  | if (indexA != -1 && indexB != -1) { | 
|  | return indexA - indexB; | 
|  | } | 
|  | return indexA == -1 ? 1 : -1; | 
|  | } | 
|  | if (a.state === Statuses.FAILED) { | 
|  | if (a.blocking && b.blocking && | 
|  | a.blocking.length !== b.blocking.length) { | 
|  | return a.blocking.length == 0 ? 1 : -1; | 
|  | } | 
|  | } | 
|  | return a.checker_name.localeCompare(b.checker_name); | 
|  | }, | 
|  |  | 
|  | _handleRetryCheck(e) { | 
|  | const uuid = e.detail.uuid; | 
|  | const retryCheck = (change, revision, uuid) => this.pluginRestApi.post( | 
|  | '/changes/' + change + '/revisions/' + revision + '/checks/' + uuid | 
|  | + '/rerun' | 
|  | ); | 
|  | retryCheck(this.change._number, this.revision._number, uuid).then( | 
|  | res => { | 
|  | this._fetchChecks(this.change, this.revision._number, | 
|  | this.getChecks); | 
|  | }, error => { | 
|  | this.fire('show-error', {message: error.message}); | 
|  | } | 
|  | ); | 
|  | }, | 
|  |  | 
|  | /** | 
|  | * Merge new checks into old checks to maintain showCheckMessage | 
|  | * property | 
|  | * Loop over checks to make sure no new checks are missed | 
|  | * Merge new check object into prev check | 
|  | * Remove any check that is not returned the next time | 
|  | * Ensure message is updated | 
|  | */ | 
|  | _updateChecks(checks) { | 
|  | return checks.map( | 
|  | check => { | 
|  | const prevCheck = this._checks.find( | 
|  | c => c.checker_uuid === check.checker_uuid | 
|  | ); | 
|  | if (!prevCheck) return Object.assign({}, check); | 
|  | return Object.assign({}, prevCheck, check, | 
|  | {showCheckMessage: prevCheck.showCheckMessage}); | 
|  | }); | 
|  | }, | 
|  |  | 
|  | /** | 
|  | * @param {!Defs.Change} change | 
|  | * @param {!Defs.Revision} revision | 
|  | * @param {function(number, number): !Promise<!Object>} getChecks | 
|  | */ | 
|  | _fetchChecks(change, revisionNumber, getChecks) { | 
|  | if (!getChecks || !change || !revisionNumber) return; | 
|  |  | 
|  | getChecks(change._number, revisionNumber).then(checks => { | 
|  | if (revisionNumber !== this._currentPatchSet) return; | 
|  | if (checks && checks.length) { | 
|  | checks.sort((a, b) => this._orderChecks(a, b)); | 
|  | if (!this._checks) { | 
|  | this._checks = checks; | 
|  | } else { | 
|  | this._checks = this._updateChecks(checks); | 
|  | } | 
|  | this.set('_status', LoadingStatus.RESULTS); | 
|  | } else { | 
|  | this._checkConfigured(); | 
|  | } | 
|  | }, error => { | 
|  | this._checks = []; | 
|  | this.set('_status', LoadingStatus.EMPTY); | 
|  | }); | 
|  | }, | 
|  |  | 
|  | _onVisibililityChange() { | 
|  | if (document.hidden) { | 
|  | clearInterval(this.pollChecksInterval); | 
|  | return; | 
|  | } | 
|  | this._pollChecksRegularly(this.change, this._currentPatchSet, | 
|  | this.getChecks); | 
|  | }, | 
|  |  | 
|  | _toggleCheckMessage(e) { | 
|  | const uuid = e.detail.uuid; | 
|  | if (!uuid) { | 
|  | console.warn('uuid not found'); | 
|  | return; | 
|  | } | 
|  | const idx = this._checks.findIndex(check => check.checker_uuid === uuid); | 
|  | if (idx == -1) { | 
|  | console.warn('check not found'); | 
|  | return; | 
|  | } | 
|  | // Update subproperty of _checks[idx] so that it reflects to polymer | 
|  | this.set(`_checks.${idx}.showCheckMessage`, | 
|  | !this._checks[idx].showCheckMessage); | 
|  | }, | 
|  |  | 
|  | _pollChecksRegularly(change, revisionNumber, getChecks) { | 
|  | if (!change || !revisionNumber || !getChecks) return; | 
|  | if (this.pollChecksInterval) { | 
|  | clearInterval(this.pollChecksInterval); | 
|  | } | 
|  | const poll = () => this._fetchChecks(change, revisionNumber, getChecks); | 
|  | poll(); | 
|  | this.pollChecksInterval = setInterval(poll, CHECKS_POLL_INTERVAL_MS); | 
|  | if (!this.visibilityChangeListenerAdded) { | 
|  | this.visibilityChangeListenerAdded = true; | 
|  | this.listen(document, 'visibilitychange', '_onVisibililityChange'); | 
|  | } | 
|  | }, | 
|  |  | 
|  | _checkConfigured() { | 
|  | const repository = this.change['project']; | 
|  | this.isConfigured(repository).then(configured => { | 
|  | const status = | 
|  | configured ? LoadingStatus.EMPTY : LoadingStatus.NOT_CONFIGURED; | 
|  | this.set('_status', status); | 
|  | }); | 
|  | }, | 
|  |  | 
|  | _isLoading(status) { | 
|  | return status === LoadingStatus.LOADING; | 
|  | }, | 
|  |  | 
|  | _isEmpty(status) { | 
|  | return status === LoadingStatus.EMPTY; | 
|  | }, | 
|  |  | 
|  | _hasResults(status) { | 
|  | return status === LoadingStatus.RESULTS; | 
|  | }, | 
|  |  | 
|  | _isNotConfigured(status) { | 
|  | return status === LoadingStatus.NOT_CONFIGURED; | 
|  | }, | 
|  |  | 
|  | _computeHeaderClass(currentPatchSet, sortedAllPatchsets) { | 
|  | if (!sortedAllPatchsets | 
|  | || sortedAllPatchsets.length < 1 | 
|  | || !currentPatchSet) { | 
|  | return ''; | 
|  | } | 
|  | return currentPatchSet === sortedAllPatchsets[0].value ? | 
|  | '' : 'oldPatchset'; | 
|  | }, | 
|  | }); | 
|  | })(); |