Add a loading state to the checks model and use it for the summary

Change-Id: Ia8d4158538ead1eb0dc779fe175a0c4118cfb741
diff --git a/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts b/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
index beec0a4..538fa4969 100644
--- a/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
@@ -22,7 +22,8 @@
 import {KnownExperimentId} from '../../../services/flags/flags';
 import {
   allRuns$,
-  aPluginHasRegistered,
+  aPluginHasRegistered$,
+  someProvidersAreLoading$,
 } from '../../../services/checks/checks-model';
 import {
   Category,
@@ -262,13 +263,17 @@
   @property()
   showChecksSummary = false;
 
+  @property()
+  someProvidersAreLoading = false;
+
   /** Is reset when rendering beings and decreases while chips are rendered. */
   private detailsQuota = DETAILS_QUOTA;
 
   constructor() {
     super();
     this.subscribe('runs', allRuns$);
-    this.subscribe('showChecksSummary', aPluginHasRegistered);
+    this.subscribe('showChecksSummary', aPluginHasRegistered$);
+    this.subscribe('someProvidersAreLoading', someProvidersAreLoading$);
   }
 
   static get styles() {
@@ -312,7 +317,8 @@
 
   renderChecksZeroState() {
     if (this.runs.some(isRunningOrHasCompleted)) return;
-    return html`<span class="font-small zeroState">No results</span>`;
+    const msg = this.someProvidersAreLoading ? 'Loading...' : 'No results';
+    return html`<span class="font-small zeroState">${msg}</span>`;
   }
 
   renderChecksChipForCategory(category: Category) {
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
index 3d7646f..84bad5c 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
@@ -171,7 +171,7 @@
 import {fireTitleChange} from '../../../utils/event-util';
 import {GerritView} from '../../../services/router/router-model';
 import {takeUntil} from 'rxjs/operators';
-import {aPluginHasRegistered} from '../../../services/checks/checks-model';
+import {aPluginHasRegistered$} from '../../../services/checks/checks-model';
 import {Subject} from 'rxjs';
 import {GrRelatedChangesListExperimental} from '../gr-related-changes-list-experimental/gr-related-changes-list-experimental';
 
@@ -594,7 +594,7 @@
   /** @override */
   ready() {
     super.ready();
-    aPluginHasRegistered.pipe(takeUntil(this.disconnected$)).subscribe(b => {
+    aPluginHasRegistered$.pipe(takeUntil(this.disconnected$)).subscribe(b => {
       this._showChecksTab = b;
     });
     this._isNewChangeSummaryUiEnabled = this.flagsService.isEnabled(
diff --git a/polygerrit-ui/app/services/checks/checks-model.ts b/polygerrit-ui/app/services/checks/checks-model.ts
index 6705a85..28aca73 100644
--- a/polygerrit-ui/app/services/checks/checks-model.ts
+++ b/polygerrit-ui/app/services/checks/checks-model.ts
@@ -34,6 +34,7 @@
 
 interface ChecksProviderState {
   pluginName: string;
+  loading: boolean;
   config?: ChecksApiConfig;
   runs: CheckRun[];
   actions: Action[];
@@ -50,11 +51,18 @@
 // Re-exporting as Observable so that you can only subscribe, but not emit.
 export const checksState$: Observable<ChecksState> = privateState$;
 
-export const aPluginHasRegistered = checksState$.pipe(
+export const aPluginHasRegistered$ = checksState$.pipe(
   map(state => Object.keys(state).length > 0),
   distinctUntilChanged()
 );
 
+export const someProvidersAreLoading$ = checksState$.pipe(
+  map(state => {
+    return Object.values(state).some(providerState => providerState.loading);
+  }),
+  distinctUntilChanged()
+);
+
 export const allActions$ = checksState$.pipe(
   map(state => {
     return Object.values(state).reduce(
@@ -106,6 +114,7 @@
   const nextState = {...privateState$.getValue()};
   nextState[pluginName] = {
     pluginName,
+    loading: false,
     config,
     runs: [],
     actions: [],
@@ -177,6 +186,15 @@
   status: RunStatus.COMPLETED,
 };
 
+export function updateStateSetLoading(pluginName: string) {
+  const nextState = {...privateState$.getValue()};
+  nextState[pluginName] = {
+    ...nextState[pluginName],
+    loading: true,
+  };
+  privateState$.next(nextState);
+}
+
 export function updateStateSetResults(
   pluginName: string,
   runs: CheckRun[],
@@ -185,6 +203,7 @@
   const nextState = {...privateState$.getValue()};
   nextState[pluginName] = {
     ...nextState[pluginName],
+    loading: false,
     runs: [...runs],
     actions: [...actions],
   };
diff --git a/polygerrit-ui/app/services/checks/checks-service.ts b/polygerrit-ui/app/services/checks/checks-service.ts
index 2e63f98..b11eada 100644
--- a/polygerrit-ui/app/services/checks/checks-service.ts
+++ b/polygerrit-ui/app/services/checks/checks-service.ts
@@ -30,7 +30,11 @@
   ResponseCode,
 } from '../../api/checks';
 import {change$, currentPatchNum$} from '../change/change-model';
-import {updateStateSetProvider, updateStateSetResults} from './checks-model';
+import {
+  updateStateSetLoading,
+  updateStateSetProvider,
+  updateStateSetResults,
+} from './checks-model';
 import {
   BehaviorSubject,
   combineLatest,
@@ -83,6 +87,7 @@
               patchsetNumber: patchNum,
               repo: change.project,
             };
+            updateStateSetLoading(pluginName);
             return from(this.providers[pluginName].fetch(data));
           }
         ),