Submit Requirements - rest-api, types

Change-Id: Ie80b59fffc13ac68b56a31a6e75661439420a941
diff --git a/polygerrit-ui/app/api/rest-api.ts b/polygerrit-ui/app/api/rest-api.ts
index fe9d00d..6c6fff0 100644
--- a/polygerrit-ui/app/api/rest-api.ts
+++ b/polygerrit-ui/app/api/rest-api.ts
@@ -418,6 +418,7 @@
   cherry_pick_of_patch_set?: PatchSetNum;
   contains_git_conflicts?: boolean;
   internalHost?: string; // TODO(TS): provide an explanation what is its
+  submit_requirements?: SubmitRequirementResultInfo[];
 }
 
 // The ID of the change in the format "'<project>~<branch>~<Change-Id>'"
@@ -1019,3 +1020,29 @@
   /** URL to the icon of the link. */
   image_url: string;
 }
+
+/**
+ * The SubmitRequirementResultInfo describes the result of evaluating
+ * a submit requirement on a change.
+ * https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#submit-requirement-result-info
+ */
+export declare interface SubmitRequirementResultInfo {
+  name: string;
+  description?: string;
+  status: string;
+  applicability_expression_result?: SubmitRequirementExpressionInfo;
+  submittability_expression_result: SubmitRequirementExpressionInfo;
+  override_expression_result?: SubmitRequirementExpressionInfo;
+}
+
+/**
+ * The SubmitRequirementExpressionInfo describes the result of evaluating
+ * a single submit requirement expression, for example label:code-review=+2.
+ * https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#submit-requirement-expression-info
+ */
+export declare interface SubmitRequirementExpressionInfo {
+  expression: string;
+  fulfilled: boolean;
+  passing_atoms: string;
+  failing_atoms: string;
+}
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
index 5c456ed..c79511f 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
@@ -489,7 +489,7 @@
     </section>
     <div class="separatedSection">
       <template is="dom-if" if="[[_isSubmitRequirementsUiEnabled]]">
-        <gr-submit-requirements></gr-submit-requirements>
+        <gr-submit-requirements change="[[change]]"></gr-submit-requirements>
       </template>
       <template is="dom-if" if="[[!_isSubmitRequirementsUiEnabled]]">
         <gr-change-requirements
diff --git a/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts b/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts
index 16e176c..c7c9612 100644
--- a/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts
+++ b/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts
@@ -15,25 +15,63 @@
  * limitations under the License.
  */
 import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html} from 'lit-element';
+import {css, customElement, html, property} from 'lit-element';
+import {ParsedChangeInfo} from '../../../types/types';
 
 @customElement('gr-submit-requirements')
 export class GrSubmitRequirements extends GrLitElement {
+  @property({type: Object})
+  change?: ParsedChangeInfo;
+
   static get styles() {
     return [
       css`
+        :host {
+          display: table;
+          width: 100%;
+        }
         .metadata-title {
           font-size: 100%;
           font-weight: var(--font-weight-bold);
           color: var(--deemphasized-text-color);
           padding-left: var(--metadata-horizontal-padding);
         }
+        section {
+          display: table-row;
+        }
+        .title {
+          min-width: 10em;
+          padding: var(--spacing-s) var(--spacing-m) 0
+            var(--requirements-horizontal-padding);
+        }
+        .value {
+          padding: var(--spacing-s) 0 0 0;
+        }
+        .title,
+        .value {
+          display: table-cell;
+          vertical-align: top;
+        }
       `,
     ];
   }
 
   render() {
-    return html`<h3 class="metadata-title">Submit Requirements</h3>`;
+    const submit_requirements = this.change?.submit_requirements ?? [];
+    return html`<h3 class="metadata-title">Submit Requirements</h3>
+
+      ${submit_requirements.map(
+        requirement => html`<section>
+          <div class="title">
+            <gr-limited-text
+              class="name"
+              limit="25"
+              text="${requirement.name}"
+            ></gr-limited-text>
+          </div>
+          <div class="value">${requirement.status}</div>
+        </section>`
+      )}`;
   }
 }
 
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
index 28bc229..ee9163b 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
@@ -156,6 +156,7 @@
 import {firePageError, fireServerError} from '../../../utils/event-util';
 import {ParsedChangeInfo} from '../../../types/types';
 import {ErrorCallback} from '../../../api/rest';
+import {FlagsService, KnownExperimentId} from '../../../services/flags/flags';
 
 const MAX_PROJECT_RESULTS = 25;
 // This value is somewhat arbitrary and not based on research or calculations.
@@ -291,14 +292,17 @@
   // The value is set in created, before any other actions
   private authService: AuthService;
 
+  private flagService: FlagsService;
+
   // The value is set in created, before any other actions
   private readonly _restApiHelper: GrRestApiHelper;
 
-  constructor(authService?: AuthService) {
+  constructor(authService?: AuthService, flagService?: FlagsService) {
     super();
     // TODO: Make the authService constructor parameter required when we have
     // changed all usages of this class to not instantiate via createElement().
     this.authService = authService ?? appContext.authService;
+    this.flagService = flagService ?? appContext.flagsService;
     this._restApiHelper = new GrRestApiHelper(
       this._cache,
       this.authService,
@@ -1148,7 +1152,8 @@
     if (
       window.DEFAULT_DETAIL_HEXES &&
       window.DEFAULT_DETAIL_HEXES.changePage &&
-      (!config || !(config.receive && config.receive.enable_signed_push))
+      (!config || !(config.receive && config.receive.enable_signed_push)) &&
+      !this.flagService?.isEnabled(KnownExperimentId.SUBMIT_REQUIREMENTS_UI)
     ) {
       return window.DEFAULT_DETAIL_HEXES.changePage;
     }
@@ -1169,6 +1174,9 @@
     if (config?.receive?.enable_signed_push) {
       options.push(ListChangesOption.PUSH_CERTIFICATES);
     }
+    if (this.flagService?.isEnabled(KnownExperimentId.SUBMIT_REQUIREMENTS_UI)) {
+      options.push(ListChangesOption.SUBMIT_REQUIREMENTS);
+    }
     return listChangesOptionsToHex(...options);
   }
 
diff --git a/polygerrit-ui/app/services/app-context-init.ts b/polygerrit-ui/app/services/app-context-init.ts
index f74962a..ade9529 100644
--- a/polygerrit-ui/app/services/app-context-init.ts
+++ b/polygerrit-ui/app/services/app-context-init.ts
@@ -73,7 +73,8 @@
     reportingService: () => new GrReporting(appContext.flagsService),
     eventEmitter: () => new EventEmitter(),
     authService: () => new Auth(appContext.eventEmitter),
-    restApiService: () => new GrRestApiInterface(appContext.authService),
+    restApiService: () =>
+      new GrRestApiInterface(appContext.authService, appContext.flagsService),
     changeService: () => new ChangeService(),
     commentsService: () => new CommentsService(appContext.restApiService),
     checksService: () => new ChecksService(appContext.reportingService),
diff --git a/polygerrit-ui/app/utils/change-util.ts b/polygerrit-ui/app/utils/change-util.ts
index c54c099..c94493b 100644
--- a/polygerrit-ui/app/utils/change-util.ts
+++ b/polygerrit-ui/app/utils/change-util.ts
@@ -105,6 +105,9 @@
    * deletions field (number of lines deleted)
    */
   SKIP_DIFFSTAT: 23,
+
+  /** Include the evaluated submit requirements for the caller. */
+  SUBMIT_REQUIREMENTS: 24,
 };
 
 export function listChangesOptionsToHex(...args: number[]) {