From 24211454f5ca76cdb0d953f5096791cc69d13538 Mon Sep 17 00:00:00 2001 From: Jason Robbins Date: Wed, 27 Sep 2023 15:04:30 -0700 Subject: [PATCH] Implement pre-vote dialog for API Owners. (#3366) * Implement pre-vote dialog for API Owners. * Update client-src/elements/chromedash-prevote-dialog.js Co-authored-by: Kyle Ju * Remove unneeded logging --------- Co-authored-by: Kyle Ju --- client-src/elements/chromedash-gate-column.js | 20 ++- .../elements/chromedash-preflight-dialog.js | 2 +- .../elements/chromedash-prevote-dialog.js | 122 ++++++++++++++++++ 3 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 client-src/elements/chromedash-prevote-dialog.js diff --git a/client-src/elements/chromedash-gate-column.js b/client-src/elements/chromedash-gate-column.js index c5339d11..9d867809 100644 --- a/client-src/elements/chromedash-gate-column.js +++ b/client-src/elements/chromedash-gate-column.js @@ -6,6 +6,9 @@ import { somePendingPrereqs, somePendingGates, } from './chromedash-preflight-dialog'; +import { + maybeOpenPrevoteDialog, +} from './chromedash-prevote-dialog'; import {autolink, showToastMessage, findProcessStage, renderAbsoluteDate, renderRelativeDate, } from './utils.js'; @@ -271,7 +274,7 @@ export class ChromedashGateColumn extends LitElement { this.showSaved = false; } - handleSave() { + saveVote() { this.submittingComment = true; window.csClient.setVote( this.feature.id, this.gate.id, @@ -288,6 +291,21 @@ export class ChromedashGateColumn extends LitElement { }); } + handleSave() { + Promise.all([ + window.csClient.getGates(this.feature.id), + ]).then(([gatesRes]) => { + this.featureGates = gatesRes.gates; + const vote = this.voteSelectRef.value.value; + maybeOpenPrevoteDialog(this.featureGates, this.stage, this.gate, vote) + .then(() => { + this.saveVote(); + }); + }).catch(() => { + showToastMessage('Some errors occurred. Please refresh the page or try again later.'); + }); + } + handleCancel() { this._fireEvent('close', {}); } diff --git a/client-src/elements/chromedash-preflight-dialog.js b/client-src/elements/chromedash-preflight-dialog.js index 0621123e..b61a52a4 100644 --- a/client-src/elements/chromedash-preflight-dialog.js +++ b/client-src/elements/chromedash-preflight-dialog.js @@ -32,7 +32,7 @@ export function somePendingGates(featureGates, feStage) { } -function findPendingGates(featureGates, feStage) { +export function findPendingGates(featureGates, feStage) { const gatesForStage = featureGates.filter(g => g.stage_id == feStage.id); const otherGates = gatesForStage.filter(g => g.team_name != 'API Owners'); const pendingGates = otherGates.filter(g => diff --git a/client-src/elements/chromedash-prevote-dialog.js b/client-src/elements/chromedash-prevote-dialog.js new file mode 100644 index 00000000..b7cc23b6 --- /dev/null +++ b/client-src/elements/chromedash-prevote-dialog.js @@ -0,0 +1,122 @@ +import {LitElement, css, html} from 'lit'; +import {SHARED_STYLES} from '../css/shared-css.js'; +import {findPendingGates} from './chromedash-preflight-dialog'; +import {VOTE_OPTIONS} from './form-field-enums'; + +let prevoteDialogEl; + + +function shouldShowPrevoteDialog(pendingGates, gate, vote) { + return (pendingGates.length > 0 && + gate.team_name == 'API Owners' && + vote == VOTE_OPTIONS.APPROVED[0]); +} + + +export async function maybeOpenPrevoteDialog( + featrureGates, stage, gate, vote) { + const pendingGates = findPendingGates(featrureGates, stage); + if (shouldShowPrevoteDialog(pendingGates, gate, vote)) { + return new Promise((resolve) => { + openPrevoteDialog(pendingGates, resolve); + }); + } else { + return Promise.resolve(); + } +} + + +async function openPrevoteDialog(pendingGates, resolve) { + if (!prevoteDialogEl) { + prevoteDialogEl = document.createElement('chromedash-prevote-dialog'); + document.body.appendChild(prevoteDialogEl); + } + await prevoteDialogEl.updateComplete; + prevoteDialogEl.pendingGates = pendingGates; + prevoteDialogEl.resolve = resolve; + prevoteDialogEl.show(); +} + + +class ChromedashPrevoteDialog extends LitElement { + static get properties() { + return { + pendingGates: {type: Array}, + resolve: {attribute: false}, + }; + } + + constructor() { + super(); + this.pendingGates = []; + this.resolve = function() { + console.log('Missing resolve action'); + }; + } + + static get styles() { + return [ + ...SHARED_STYLES, + css` + #prereqs-list li { + margin-left: 8px; + margin-bottom: 8px; + list-style: circle; + } + #prereqs-header { + margin-bottom: 8px; + } + sl-button { + float: right; + margin: var(--content-padding-half); + } + `, + ]; + } + + show() { + this.shadowRoot.querySelector('sl-dialog').show(); + } + + hide() { + this.shadowRoot.querySelector('sl-dialog').hide(); + } + + handleCancel() { + // Note: promise is never resolved. + this.hide(); + } + + handleProceed() { + this.resolve(); + this.hide(); + } + + renderGateItem(gate) { + return html` +
  • ${gate.team_name}
  • + `; + } + + render() { + return html` + +
    + The following prerequisite gates are missing approvals: +
    +
    +
      + ${this.pendingGates.map((gate) => this.renderGateItem(gate))} +
    +
    + Approve anyway + Don't approve yet +
    `; + } +} + +customElements.define('chromedash-prevote-dialog', ChromedashPrevoteDialog);