[ZEPPELIN-4542] Websocket client support of auto-reconnect

### What is this PR for?

Websocket client support of auto-reconnect

### What type of PR is it?
[Feature]

### What is the Jira issue?

https://issues.apache.org/jira/browse/ZEPPELIN-4542

### How should this be tested?

N/A

### Screenshots (if appropriate)

N/A

### Questions:
* Does the licenses files need update? No
* Is there breaking changes for older versions? No
* Does this needs documentation? No

Author: Hsuan Lee <hsuangm@gmail.com>

Closes #3590 from hsuanxyz/feat/network-reconnect and squashes the following commits:

ab8da4584 [Hsuan Lee] feat: support the websocket reconnect
diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
index 65ceec6..4505e36 100644
--- a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
+++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
@@ -116,6 +116,10 @@
     this.send<OP.PING>(OP.PING);
   }
 
+  close() {
+    this.close$.next();
+  }
+
   opened(): Observable<Event> {
     return this.open$.asObservable();
   }
diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html
index c41cf78..a955afa 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html
@@ -10,8 +10,7 @@
   ~ limitations under the License.
   -->
 
-<div class="content" [class.blur]="!websocketConnected">
+<div class="content">
   <zeppelin-header *ngIf="!publishMode"></zeppelin-header>
   <router-outlet (activate)="onActivate($event)"></router-outlet>
 </div>
-<zeppelin-spin *ngIf="!websocketConnected" [transparent]="true">Connecting WebSocket ...</zeppelin-spin>
diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less
index 63064aa..dfe293f 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less
@@ -18,9 +18,5 @@
     min-height: 100vh;
     display: block;
     position: relative;
-
-    &.blur {
-      filter: blur(4px);
-    }
   }
 });
diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
index 410ef17..19175cb 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
@@ -10,16 +10,15 @@
  * limitations under the License.
  */
 
-import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, OnDestroy, OnInit } from '@angular/core';
 import { Subject } from 'rxjs';
-import { filter, map, startWith, takeUntil, tap } from 'rxjs/operators';
+import { takeUntil } from 'rxjs/operators';
 
-import { ActivatedRoute, NavigationEnd, Route, Router } from '@angular/router';
-import { publishedSymbol, Published } from '@zeppelin/core/paragraph-base/published';
+import { publishedSymbol } from '@zeppelin/core/paragraph-base/published';
 import { HeliumManagerService } from '@zeppelin/helium-manager';
 import { MessageService } from '@zeppelin/services';
 import { setTheme } from '@zeppelin/visualizations/g2.config';
-import { log } from 'ng-zorro-antd/core';
+import { NzMessageService } from 'ng-zorro-antd/message';
 
 @Component({
   selector: 'zeppelin-workspace',
@@ -29,26 +28,48 @@
 })
 export class WorkspaceComponent implements OnInit, OnDestroy {
   private destroy$ = new Subject();
-  websocketConnected = false;
+  private messageId = null;
   publishMode = false;
 
   constructor(
     public messageService: MessageService,
     private cdr: ChangeDetectorRef,
+    private nzMessageService: NzMessageService,
     private heliumManagerService: HeliumManagerService
   ) {}
 
-  onActivate(e) {
-    this.publishMode = e && e[publishedSymbol];
+  onActivate(component) {
+    this.publishMode = component && component[publishedSymbol];
     this.cdr.markForCheck();
   }
 
-  ngOnInit() {
+  /**
+   * Close the old connection manually when the network is offline
+   * and connect a new, the {@link MessageService} will auto-retry
+   */
+  @HostListener('window:offline')
+  onOffline() {
+    this.messageService.close();
+    this.messageService.connect();
+  }
+
+  setUpWebsocketReconnectMessage() {
     this.messageService.connectedStatus$.pipe(takeUntil(this.destroy$)).subscribe(data => {
-      this.websocketConnected = data;
+      if (!data) {
+        if (this.messageId === null) {
+          this.messageId = this.nzMessageService.loading('Connecting WebSocket ...', { nzDuration: 0 }).messageId;
+        }
+      } else {
+        this.nzMessageService.remove(this.messageId);
+        this.messageId = null;
+      }
       this.cdr.markForCheck();
     });
+  }
+
+  ngOnInit() {
     setTheme();
+    this.setUpWebsocketReconnectMessage();
     this.heliumManagerService.initPackages();
   }
 
diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts
index f6e01e2..3be5f54 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts
@@ -19,9 +19,11 @@
 import { HeliumManagerModule } from '@zeppelin/helium-manager';
 import { ShareModule } from '@zeppelin/share';
 
-import { WorkspaceRoutingModule } from './workspace-routing.module';
+import { NzMessageModule } from 'ng-zorro-antd/message';
 import { WorkspaceComponent } from './workspace.component';
 
+import { WorkspaceRoutingModule } from './workspace-routing.module';
+
 @NgModule({
   declarations: [WorkspaceComponent],
   imports: [
@@ -31,7 +33,8 @@
     HttpClientModule,
     ShareModule,
     RouterModule,
-    HeliumManagerModule
+    HeliumManagerModule,
+    NzMessageModule
   ]
 })
 export class WorkspaceModule {}
diff --git a/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html
index c7d8cc5..33a5d87 100644
--- a/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html
+++ b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html
@@ -12,7 +12,7 @@
 
 <div nz-row class="modal">
   <div nz-col [nzSm]="8" [nzXs]="0" class="about-logo">
-    <img src="../../assets/images/zeppelin_svg_logo.svg" alt="Apache Zeppelin" title="Apache Zeppelin"/>
+    <img src="assets/images/zeppelin_svg_logo.svg" alt="Apache Zeppelin" title="Apache Zeppelin"/>
   </div>
   <div nz-col [nzSm]="16" [nzXs]="24" class="content">
     <h3>Apache Zeppelin</h3>