You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datalab.apache.org by hs...@apache.org on 2022/10/05 16:16:20 UTC

[incubator-datalab] branch feat/DATALAB-3064/add-new-platform created (now 8abd75529)

This is an automated email from the ASF dual-hosted git repository.

hshpak pushed a change to branch feat/DATALAB-3064/add-new-platform
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git


      at 8abd75529 implemented logic by add new platform, disconnect platform

This branch includes the following new commits:

     new 8abd75529 implemented logic by add new platform, disconnect platform

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datalab.apache.org
For additional commands, e-mail: commits-help@datalab.apache.org


[incubator-datalab] 01/01: implemented logic by add new platform, disconnect platform

Posted by hs...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hshpak pushed a commit to branch feat/DATALAB-3064/add-new-platform
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git

commit 8abd7552942815f14b22862d7e9f70663bf77c91
Author: Hennadii_Shpak <bo...@gmail.com>
AuthorDate: Wed Sep 28 15:19:20 2022 +0300

    implemented logic by add new platform, disconnect platform
---
 .../administration/management/management.model.ts  |   6 +
 .../resources/webapp/src/app/core/core.module.ts   |   4 +-
 .../services/applicationServiceFacade.service.ts   |  26 +++-
 .../services/connected-platform-api.service.ts     |  54 +++++++++
 .../app/core/services/image-page-resolve.guard.ts  |   4 +-
 ...ages-page.service.ts => images-page.service.ts} |   2 +-
 .../webapp/src/app/core/services/index.ts          |   2 +-
 .../audit/audit-grid/audit-grid.component.html     | 134 ++++++++++-----------
 .../audit/audit-grid/audit-grid.component.scss     |   2 +-
 ...utational-resource-create-dialog.component.html |   7 +-
 ...mputational-resource-create-dialog.component.ts |   6 +-
 .../connected-platform-dialog.component.html       |  61 ++++++++++
 .../connected-platform-dialog.component.scss       |  93 ++++++++++++++
 .../connected-platform-dialog.component.ts         |  63 ++++++++++
 .../connected-platforms.component.html             |  46 +++++--
 .../connected-platforms.component.scss             |  60 +++++++++
 .../connected-platforms.component.ts               |  99 ++++++++++-----
 ...ms.comnfig.ts => connected-platforms.config.ts} |  11 +-
 ...omponent.scss => connected-platforms.models.ts} |  22 ++--
 .../connected-platforms.module.ts                  |  17 ++-
 .../connected-platforms.service.ts                 |  59 +++++++++
 .../warning-dialog/warning-dialog.component.html   |  28 +++++
 .../warning-dialog.component.scss}                 |  20 +--
 .../warning-dialog/warning-dialog.component.ts     |  49 ++++++++
 .../src/app/resources/images/images.component.html |   3 +-
 .../src/app/resources/images/images.component.ts   |   8 +-
 .../src/app/resources/images/images.config.ts      |   3 +-
 .../src/app/resources/images/images.service.ts     |   4 +-
 .../webapp/src/app/resources/resources.module.ts   |   7 +-
 .../modal-parts/modal-btn/modal-btn.component.html |  34 ++++++
 .../modal-btn/modal-btn.component.scss}            |  22 ++--
 .../modal-parts/modal-btn/modal-btn.component.ts}  |  27 +++--
 .../modal-header/modal-header.component.html       |  27 +++++
 .../modal-header/modal-header.component.scss}      |  31 +++--
 .../modal-header/modal-header.component.ts}        |  25 ++--
 .../modal-parts/modal-parts.module.ts}             |  20 +--
 .../src/app/shared/navbar/navbar.component.html    |   1 +
 .../resources/webapp/src/assets/styles/_theme.scss |   6 +-
 38 files changed, 875 insertions(+), 218 deletions(-)

diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
index b94e61b7d..8c1103a64 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
@@ -85,8 +85,14 @@ export interface GeneralEnvironmentStatus {
   status: string;
   projectAssigned: boolean;
   bucketBrowser: object;
+  connectedPlatforms: ConnectedPlatformsStatus;
 }
 
+export interface ConnectedPlatformsStatus {
+  add: boolean;
+  disconnect: boolean;
+  view: boolean;
+}
 
 export class ManagementConfigModel {
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/core.module.ts b/services/self-service/src/main/resources/webapp/src/app/core/core.module.ts
index b1fb27d86..5ea5b4fa3 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/core.module.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/core.module.ts
@@ -49,7 +49,7 @@ import { ErrorInterceptor } from './interceptors/error.interceptor';
 
 import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
 import {  ConfigurationService } from './services/configutration.service';
-import {AuditGuard, OdahuDeploymentService, UserImagesPageService} from './services';
+import {AuditGuard, OdahuDeploymentService, ImagesPageService} from './services';
 import {  ProjectAdminGuard } from './services/projectAdmin.guard';
 
 @NgModule({
@@ -90,7 +90,7 @@ export class CoreModule {
         UserAccessKeyService,
         ConfigurationService,
         OdahuDeploymentService,
-        UserImagesPageService,
+        ImagesPageService,
 
         { provide: MatDialogRef, useValue: {} },
         { provide: MAT_DIALOG_DATA, useValue: [] },
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts
index 69cd6e607..032565e54 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts
@@ -24,7 +24,8 @@ import { HttpClient } from '@angular/common/http';
 import { Dictionary } from '../collections';
 import { environment } from '../../../environments/environment';
 import { HTTPMethod } from '../util';
-import { ImageActionType, ImageFilterFormValue, ImageParams } from '../../resources/images';
+import { ImageFilterFormValue, ImageParams } from '../../resources/images';
+import { AddPlatformFromValue } from '../../resources/connected-platforms/connected-platforms.models';
 
 // we can now access environment.apiUrl
 const API_URL = environment.apiUrl;
@@ -84,6 +85,7 @@ export class ApplicationServiceFacade {
   private static readonly CONFIG = 'config';
   private static readonly QUOTA = 'quota';
   private static readonly IMAGE_PAGE = 'image_page';
+  private static readonly CONNECTED_PLATFORMS = 'connected_platforms';
 
   private requestRegistry: Dictionary<string>;
 
@@ -201,6 +203,26 @@ export class ApplicationServiceFacade {
       params
       );
   }
+  buildGetConnectedPlatformsPage(): Observable<any> {
+    return this.buildRequest(HTTPMethod.GET,
+      `${this.requestRegistry.Item(ApplicationServiceFacade.CONNECTED_PLATFORMS)}/user`,
+      null
+      );
+  }
+
+  buildAddPlatform(platformParams: AddPlatformFromValue): Observable<any> {
+    return this.buildRequest(HTTPMethod.POST,
+      this.requestRegistry.Item(ApplicationServiceFacade.CONNECTED_PLATFORMS),
+      platformParams
+    );
+  }
+
+  buildDisconnectPlatform(platformName: string): Observable<any> {
+    return this.buildRequest(HTTPMethod.DELETE,
+      `${this.requestRegistry.Item(ApplicationServiceFacade.CONNECTED_PLATFORMS)}/${platformName}`,
+      null
+    );
+  }
 
   public buildGetTemplatesRequest(params): Observable<any> {
     return this.buildRequest(HTTPMethod.GET,
@@ -750,6 +772,8 @@ export class ApplicationServiceFacade {
       '/api/infrastructure/info');
     this.requestRegistry.Add(ApplicationServiceFacade.IMAGE_PAGE,
       '/api/infrastructure_provision/exploratory_environment/image/user');
+    this.requestRegistry.Add(ApplicationServiceFacade.CONNECTED_PLATFORMS,
+      '/api/connected_platforms');
     this.requestRegistry.Add(ApplicationServiceFacade.EXPLORATORY_ENVIRONMENT,
       '/api/infrastructure_provision/exploratory_environment');
     this.requestRegistry.Add(ApplicationServiceFacade.TEMPLATES,
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/connected-platform-api.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/connected-platform-api.service.ts
new file mode 100644
index 000000000..bd7153080
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/connected-platform-api.service.ts
@@ -0,0 +1,54 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Injectable } from '@angular/core';
+import { ApplicationServiceFacade } from './applicationServiceFacade.service';
+import { catchError } from 'rxjs/operators';
+import { ErrorUtils } from '../util';
+import { Observable } from 'rxjs';
+import { AddPlatformFromValue, ConnectedPlatformsInfo } from '../../resources/connected-platforms/connected-platforms.models';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class ConnectedPlatformApiService {
+
+  constructor(
+    private applicationServiceFacade: ApplicationServiceFacade
+  ) { }
+
+  getConnectedPlatformsPage(): Observable<ConnectedPlatformsInfo> {
+    return this.applicationServiceFacade.buildGetConnectedPlatformsPage()
+      .pipe(
+        catchError(ErrorUtils.handleServiceError)
+      );
+  }
+
+  addPlatform(platformParams: AddPlatformFromValue) {
+    return  this.applicationServiceFacade.buildAddPlatform(platformParams).pipe(
+      catchError(ErrorUtils.handleServiceError)
+    );
+  }
+
+  disconnectPlatform(platformName: string) {
+    return  this.applicationServiceFacade.buildDisconnectPlatform(platformName).pipe(
+      catchError(ErrorUtils.handleServiceError)
+    );
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/image-page-resolve.guard.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/image-page-resolve.guard.ts
index bf643e851..98483f506 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/image-page-resolve.guard.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/image-page-resolve.guard.ts
@@ -4,7 +4,7 @@ import { Observable, of  } from 'rxjs';
 
 import { ProjectImagesInfo } from '../../resources/images';
 import { switchMap, take } from 'rxjs/operators';
-import { UserImagesPageService } from './user-images-page.service';
+import { ImagesPageService } from './images-page.service';
 
 @Injectable({
   providedIn: 'root'
@@ -12,7 +12,7 @@ import { UserImagesPageService } from './user-images-page.service';
 export class ImagePageResolveGuard implements Resolve<ProjectImagesInfo> {
   constructor(
     private router: Router,
-    private userImagesPageService: UserImagesPageService
+    private userImagesPageService: ImagesPageService
   ) {}
 
   resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<ProjectImagesInfo> {
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/user-images-page.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/images-page.service.ts
similarity index 98%
rename from services/self-service/src/main/resources/webapp/src/app/core/services/user-images-page.service.ts
rename to services/self-service/src/main/resources/webapp/src/app/core/services/images-page.service.ts
index fe41b1483..b87d2bf0c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/user-images-page.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/images-page.service.ts
@@ -33,7 +33,7 @@ import {
 import { ShareDialogData, UserData } from '../../resources/exploratory/image-action-dialog/image-action.model';
 
 @Injectable()
-export class UserImagesPageService {
+export class ImagesPageService {
   constructor(
     private applicationServiceFacade: ApplicationServiceFacade
   ) { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/index.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/index.ts
index 712ffb4ea..b4c34fab2 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/index.ts
@@ -41,4 +41,4 @@ export * from './project.service';
 export * from './odahu-deployment.service';
 export * from './endpoint.service';
 export * from './image-page-resolve.guard';
-export * from './user-images-page.service';
+export * from './images-page.service';
diff --git a/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.html
index 1e3b8dfbc..69aa1e2f7 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.html
@@ -23,10 +23,10 @@
     <ng-container matColumnDef="date">
       <th mat-header-cell *matHeaderCellDef class="th_date label-header">
         <div class="label"><span class="text">Date</span></div>
-        <button 
-          mat-icon-button 
-          aria-label="More" 
-          class="ar" 
+        <button
+          mat-icon-button
+          aria-label="More"
+          class="ar"
           (click)="toggleFilterRow()"
         >
           <i class="material-icons">
@@ -42,10 +42,10 @@
     <ng-container matColumnDef="user">
       <th mat-header-cell *matHeaderCellDef class="th_user label-header" [ngStyle]="{'z-index': 99}">
         <div class="label"><span class="audit-user"> User</span></div>
-        <button 
-          mat-icon-button 
-          aria-label="More" 
-          class="ar" 
+        <button
+          mat-icon-button
+          aria-label="More"
+          class="ar"
           (click)="toggleFilterRow()"
         >
           <i class="material-icons">
@@ -67,10 +67,10 @@
         <div class="label">
           <span class="text"> Action </span>
         </div>
-        <button 
-          mat-icon-button 
-          aria-label="More" 
-          class="ar" 
+        <button
+          mat-icon-button
+          aria-label="More"
+          class="ar"
           (click)="toggleFilterRow()"
         >
           <i class="material-icons">
@@ -100,10 +100,10 @@
     <ng-container matColumnDef="project">
       <th mat-header-cell *matHeaderCellDef class="th_project label-header">
         <div class="label"><span class="text">Project</span></div>
-        <button 
-          mat-icon-button 
-          aria-label="More" 
-          class="ar" 
+        <button
+          mat-icon-button
+          aria-label="More"
+          class="ar"
           (click)="toggleFilterRow()"
         >
           <i class="material-icons">
@@ -123,10 +123,10 @@
     <ng-container matColumnDef="resource-type">
       <th mat-header-cell *matHeaderCellDef class="th_resource-type label-header">
         <div class="label"><span class="text">Resource type</span></div>
-        <button 
-          mat-icon-button 
-          aria-label="More" 
-          class="ar" 
+        <button
+          mat-icon-button
+          aria-label="More"
+          class="ar"
           (click)="toggleFilterRow()"
         >
           <i class="material-icons">
@@ -146,15 +146,15 @@
         <div class="pagination-wrapper">
           <div class="selected-items-wrapper">
             <span>Items per page:</span>
-            <div class="select-wrapper">
+            <div class="select__wrapper">
               <div class="mat-reset">
                 <div class="control selector-wrapper">
                   <mat-form-field>
                     <mat-label></mat-label>
                     <mat-select [(value)]="showItemsPrPage">
-                      <mat-option 
-                        *ngFor="let item of itemsPrPage" 
-                        [value]="item" 
+                      <mat-option
+                        *ngFor="let item of itemsPrPage"
+                        [value]="item"
                         (click)="setItemsPrPage(item)"
                       >
                         {{ item }}
@@ -173,36 +173,36 @@
           </span>
           <span>
             <span [ngClass]="{'not-active':  !isNavigationDisabled || firstItem === 1}">
-              <span 
-                class="navigation-butts" 
-                (click)="loadItemsForPage('first')" 
+              <span
+                class="navigation-butts"
+                (click)="loadItemsForPage('first')"
                 [ngClass]="{'not-allowed': firstItem === 1 || !isNavigationDisabled}"
               >
                 <i class="material-icons">first_page</i>
               </span>
             </span>
             <span [ngClass]="{'not-active': firstItem === 1 || !isNavigationDisabled}">
-              <span 
-                class="navigation-butts" 
-                (click)="loadItemsForPage('previous')" 
+              <span
+                class="navigation-butts"
+                (click)="loadItemsForPage('previous')"
                 [ngClass]="{'not-allowed': firstItem === 1 || !isNavigationDisabled}"
               >
                 <i class="material-icons">keyboard_arrow_left</i>
               </span>
             </span>
             <span [ngClass]="{'not-active': lastItem >= allItems || !isNavigationDisabled}">
-              <span 
-                class="navigation-butts" 
-                (click)="loadItemsForPage('next')" 
+              <span
+                class="navigation-butts"
+                (click)="loadItemsForPage('next')"
                 [ngClass]="{'not-allowed': lastItem >= allItems || !isNavigationDisabled}"
               >
                 <i class="material-icons">keyboard_arrow_right</i>
               </span>
             </span>
             <span [ngClass]="{'not-active': lastItem >= allItems || !isNavigationDisabled}">
-              <span 
-                class="navigation-butts" 
-                (click)="loadItemsForPage('last')" 
+              <span
+                class="navigation-butts"
+                (click)="loadItemsForPage('last')"
                 [ngClass]="{'not-allowed': lastItem >= allItems || !isNavigationDisabled}"
               >
                 <i class="material-icons">last_page</i>
@@ -216,10 +216,10 @@
     <ng-container matColumnDef="resource">
       <th mat-header-cell *matHeaderCellDef class="th_resource label-header">
         <div class="label"><span class="text">Resource</span></div>
-        <button 
-          mat-icon-button 
-          aria-label="More" 
-          class="ar" 
+        <button
+          mat-icon-button
+          aria-label="More"
+          class="ar"
           (click)="toggleFilterRow()"
         >
           <i class="material-icons">
@@ -230,7 +230,7 @@
       </th>
       <td mat-cell *matCellDef="let element" class="th_resource">
         <div class="table-item-wrapper">
-          <span 
+          <span
             class="ellipsis"
             [matTooltip]="element.resourceName || 'N/A'"
             matTooltipPosition="above">
@@ -251,11 +251,11 @@
     <!--   AUDIT FILTER-->
     <ng-container matColumnDef="user-filter">
       <th mat-header-cell *matHeaderCellDef class="filter-row-item">
-        <multi-select-dropdown 
-          *ngIf="filterConfiguration" 
-          (selectionChange)="onUpdate($event)" 
+        <multi-select-dropdown
+          *ngIf="filterConfiguration"
+          (selectionChange)="onUpdate($event)"
           [type]="'users'"
-          [items]="filterConfiguration.users" 
+          [items]="filterConfiguration.users"
           [model]="filterAuditData.users"
         ></multi-select-dropdown>
       </th>
@@ -263,11 +263,11 @@
 
     <ng-container matColumnDef="project-filter">
       <th mat-header-cell *matHeaderCellDef class="filter-row-item">
-        <multi-select-dropdown 
-          *ngIf="filterConfiguration" 
-          (selectionChange)="onUpdate($event)" 
+        <multi-select-dropdown
+          *ngIf="filterConfiguration"
+          (selectionChange)="onUpdate($event)"
           [type]="'projects'"
-          [items]="filterConfiguration.projects" 
+          [items]="filterConfiguration.projects"
           [model]="filterAuditData.projects"
         ></multi-select-dropdown>
       </th>
@@ -277,10 +277,10 @@
       <th mat-header-cell *matHeaderCellDef class="filter-row-item">
         <multi-select-dropdown
           class="audit-resources"
-          *ngIf="filterConfiguration" 
-          (selectionChange)="onUpdate($event)" 
+          *ngIf="filterConfiguration"
+          (selectionChange)="onUpdate($event)"
           [type]="'resources'"
-          [items]="filterConfiguration.resources" 
+          [items]="filterConfiguration.resources"
           [model]="filterAuditData.resources"
         ></multi-select-dropdown>
       </th>
@@ -288,11 +288,11 @@
 
     <ng-container matColumnDef="resource-type-filter">
       <th mat-header-cell *matHeaderCellDef class="filter-row-item">
-        <multi-select-dropdown 
-          *ngIf="filterConfiguration" 
-          (selectionChange)="onUpdate($event)" 
+        <multi-select-dropdown
+          *ngIf="filterConfiguration"
+          (selectionChange)="onUpdate($event)"
           [type]="'resource_types'"
-          [items]="filterConfiguration.resource_types" 
+          [items]="filterConfiguration.resource_types"
           [model]="filterAuditData.resource_types"
         ></multi-select-dropdown>
       </th>
@@ -309,19 +309,19 @@
     <ng-container matColumnDef="filter-buttons" stickyEnd>
       <th mat-header-cell *matHeaderCellDef class="filter-row-item">
         <div class="actions audit-actions">
-          <button 
-            mat-icon-button 
-            class="btn reset" 
-            (click)="resetFilterConfigurations()" 
+          <button
+            mat-icon-button
+            class="btn reset"
+            (click)="resetFilterConfigurations()"
             [disabled]="!isFilterSelected"
           >
             <i class="material-icons">close</i>
           </button>
 
-          <button 
-            mat-icon-button 
-            class="btn apply" 
-            (click)="buildAuditGrid(true)" 
+          <button
+            mat-icon-button
+            class="btn apply"
+            (click)="buildAuditGrid(true)"
             [disabled]="isNavigationDisabled"
           >
             <i class="material-icons">done</i>
@@ -341,9 +341,9 @@
 
     <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true" class="header-row"></tr>
 
-    <tr 
-      [hidden]="!collapseFilterRow" 
-      mat-header-row 
+    <tr
+      [hidden]="!collapseFilterRow"
+      mat-header-row
       *matHeaderRowDef="displayedFilterColumns; sticky: true"
       class="filter-row"
     ></tr>
diff --git a/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.scss b/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.scss
index bbee3d383..7775d3b1c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.scss
@@ -288,7 +288,7 @@
   display: flex;
   align-items: center;
 
-  .select-wrapper {
+  .select__wrapper {
     margin-left: 20px;
     width: 80px;
   }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
index ced2fa9bb..dc516ad70 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
@@ -29,7 +29,7 @@
           <div class="col">
             <div
               class="control-group"
-              *ngIf="(clusterTypes | isElementAvailable : isHasHDInside) || this.PROVIDER !== providerList.azure"
+              *ngIf="(clusterTypes | isElementAvailable : hasHDInside) || this.PROVIDER !== providerList.azure"
               [hidden]="clusterTypes.length === 1"
             >
               <label class="label">Select cluster type</label>
@@ -133,7 +133,7 @@
             </div>
 
             <div class="control-group"
-                 *ngIf="(clusterTypes | isElementAvailable : isHasHDInside) || PROVIDER !== providerList.azure"
+                 *ngIf="(clusterTypes | isElementAvailable : hasHDInside) || PROVIDER !== providerList.azure"
                  [hidden]="!selectedImage.templates.length"
             >
               <label class="label">Select template</label>
@@ -370,7 +370,8 @@
         </div>
         <div
           class="checkbox-group control-group m-top-10"
-          [hidden]="PROVIDER === 'gcp' && selectedImage?.image === 'docker.datalab-dataengine-service'"
+          [hidden]="PROVIDER === 'gcp' && selectedImage?.image === 'docker.datalab-dataengine-service'
+           || templateNameControl.value === templateName.hdInsight"
           *ngIf="notebook_instance?.image !== 'docker.datalab-zeppelin'"
         >
           <div class="d-flex cursor-pointer label" (click)="addAdditionalParams('configuration')">
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
index e8daab11e..41a517826 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
@@ -45,6 +45,7 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
   readonly CLUSTER_CONFIGURATION = CLUSTER_CONFIGURATION;
   readonly CheckUtils = CheckUtils;
   readonly providerList: typeof Providers = Providers;
+  readonly templateName: typeof ImageTemplateName = ImageTemplateName;
 
   notebook_instance: any;
   resourcesList: any;
@@ -158,7 +159,7 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
       );
   }
 
-  public isHasHDInside(templateList: ComputationalTemplate[]): boolean {
+  public hasHDInside(templateList: ComputationalTemplate[]): boolean {
     return  templateList.some(({template_name}) => template_name === ImageTemplateName.hdInsight);
   }
 
@@ -392,4 +393,7 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
   get instanceSpot() {
     return this.resourceForm.controls['emr_slave_instance_spot'].value;
   }
+  get templateNameControl(): FormControl {
+    return  this.resourceForm.get('template_name') as FormControl;
+  }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.html
new file mode 100644
index 000000000..3ca47cf20
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.html
@@ -0,0 +1,61 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+  <div id="dialog-box" class="dialog__wrapper">
+    <header class="dialog-header">
+      <h4 class="modal-title">
+        {{modalTitle.addPlatform}}
+      </h4>
+      <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+    </header>
+    <div class="dialog-content">
+      <form [formGroup]="connectedPlatformForm">
+          <div class="control__wrapper">
+            <label>Select platform</label>
+            <mat-form-field class="select__wrapper" appearance="fill">
+              <mat-select placeholder="Select platform" name="platformType" formControlName="type">
+                <mat-option *ngIf="!data.types.length" disabled="true">
+                  No platforms to add
+                </mat-option><mat-option *ngFor="let type of data.types" [value]="type">
+                  {{type}}
+                </mat-option>
+              </mat-select>
+              <button class="caret">
+                <i class="material-icons">keyboard_arrow_down</i>
+              </button>
+            </mat-form-field>
+          </div>
+
+        <div class="control__wrapper">
+          <label>Platform url</label>
+          <div class="input__wrapper">
+            <input placeholder="Platform url" type="text" formControlName="url">
+          </div>
+        </div>
+
+        <div class="control__wrapper">
+          <label>Name</label>
+          <div class="input__wrapper">
+            <input placeholder="Enter name" type="text" formControlName="name">
+          </div>
+        </div>
+        <datalab-modal-btn [confirmBtnName]="confirmButtonName.add" (closeEvent)="onBtnClick($event)"></datalab-modal-btn>
+      </form>
+    </div>
+  </div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.scss
new file mode 100644
index 000000000..f012798cf
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.scss
@@ -0,0 +1,93 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+.dialog-content {
+  padding: 25px 30px;
+}
+
+.control__wrapper {
+  display: flex;
+  justify-content: space-between;
+  align-items: baseline;
+  margin-bottom: 20px;
+}
+
+.select__wrapper {
+  position: relative;
+  width: 285px;
+  height: 36px;
+
+  & ::ng-deep .mat-form-field-wrapper {
+    padding: 0;
+  }
+
+  &.mat-form-field .mat-form-field-flex {
+    background-color: red !important;
+  }
+
+  & ::ng-deep .mat-form-field-appearance-fill .mat-form-field-flex {
+    padding: 0;
+  }
+
+  & ::ng-deep .mat-form-field-infix {
+    border-top: none;
+  }
+
+  & ::ng-deep .mat-form-field-underline::before {
+    height: 0;
+  }
+
+  & ::ng-deep .mat-form-field-ripple {
+    display: none;
+  }
+
+  & ::ng-deep .mat-select-arrow {
+    border: none;
+
+  }
+
+  ::ng-deep .mat-select-placeholder {
+    font-size: 15px;
+  }
+}
+
+.caret {
+  position: absolute;
+  top: -9px;
+  right: -11px;
+  width: 40px;
+  height: 40px;
+  color: #35afd5;
+  background-color: transparent;
+  border: none;
+  border-left: 1px solid #ececec;
+  outline: none;
+  cursor: pointer;
+}
+
+::ng-deep {
+  .mat-form-field .mat-form-field-flex{
+    background-color: white;
+    box-shadow: 0px 3px 1px -2px rgb(0 0 0 / 20%), 0px 2px 2px 0px rgb(0 0 0 / 14%), 0px 1px 5px 0px rgb(0 0 0 / 12%);
+  }
+}
+
+.input__wrapper {
+  width: 285px;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.ts
new file mode 100644
index 000000000..9e0f5c458
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.ts
@@ -0,0 +1,63 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, Inject, OnInit } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { FormBuilder, FormGroup } from '@angular/forms';
+import { ModalTitle } from '../../images';
+import { AddModalData, AddPlatformFromValue } from '../connected-platforms.models';
+import { ConfirmButtonNames } from '../connected-platforms.config';
+
+@Component({
+  selector: 'datalab-connected-platform-dialog',
+  templateUrl: './connected-platform-dialog.component.html',
+  styleUrls: ['./connected-platform-dialog.component.scss']
+})
+export class ConnectedPlatformDialogComponent implements OnInit {
+  readonly modalTitle: typeof ModalTitle = ModalTitle;
+  readonly confirmButtonName: typeof ConfirmButtonNames = ConfirmButtonNames;
+
+  connectedPlatformForm!: FormGroup;
+
+  constructor(
+    public dialogRef: MatDialogRef<ConnectedPlatformDialogComponent>,
+    private fb: FormBuilder,
+    @Inject(MAT_DIALOG_DATA) public data: AddModalData
+  ) { }
+
+  ngOnInit(): void {
+    this.initForm();
+  }
+
+  onBtnClick(flag: boolean): void {
+    let responseObj: AddPlatformFromValue;
+    if (flag) {
+      responseObj = this.connectedPlatformForm.value;
+    }
+    this.dialogRef.close(responseObj);
+  }
+
+  private initForm(): void {
+    this.connectedPlatformForm = this.fb.group({
+      type: '',
+      url: '',
+      name: ''
+    });
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.html
index 7343c83ef..43042832c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.html
@@ -20,6 +20,8 @@
 <section class="connected-platforms__wrapper base-retreat">
   <nav class="sub-nav">
     <button
+      *ngIf="(connectedPlatformsStatus$ | async)?.add"
+      (click)="onAddNew()"
       mat-raised-button
       class="butt butt-create"
     >
@@ -29,27 +31,55 @@
 
   <mat-divider></mat-divider>
 
-  <table mat-table [dataSource]="dataSource" class="mat-elevation-z8 table">
+  <table mat-table [dataSource]="(platformPageData$ | async).userPlatforms" class="mat-elevation-z8 table">
 
     <ng-container matColumnDef="platformName">
       <th mat-header-cell *matHeaderCellDef>{{tableHeaderCellTitles.platformName}}</th>
-      <td mat-cell class="column" *matCellDef="let element"> {{element.platformName}} </td>
+      <td mat-cell class="column" *matCellDef="let element"> {{element.name}} </td>
     </ng-container>
 
     <ng-container matColumnDef="linkToPlatform">
       <th mat-header-cell *matHeaderCellDef>{{tableHeaderCellTitles.linkToPlatform}}</th>
       <td class="column" mat-cell *matCellDef="let element">
-        <a class="link" [href]="element.linkToPlatform | normalizeLink" target="_blank">
-          {{element.linkToPlatform}}
+        <a class="link" [href]="element.url | normalizeLink" target="_blank">
+          {{element.url}}
         </a>
       </td>
     </ng-container>
 
     <ng-container matColumnDef="actions">
-      <th mat-header-cell *matHeaderCellDef>{{tableHeaderCellTitles.actions}}</th>
-      <td mat-cell *matCellDef="let element"><span class="actions">
-        <img class="action-icon" [src]="'assets/svg/settings_icon.svg'" alt="setting-icon">
-      </span></td>
+      <th
+        mat-header-cell
+        [ngClass]="{'hided-table-title': !(connectedPlatformsStatus$ | async)?.disconnect}"
+        *matHeaderCellDef
+      >
+        {{tableHeaderCellTitles.actions}}
+      </th>
+      <td mat-cell class="action-cell" *matCellDef="let element">
+        <span class="actions-menu"
+              #settings
+              (click)="actions.toggle($event, settings)">
+          <img
+            *ngIf="(connectedPlatformsStatus$ | async)?.disconnect"
+            class="action-icon"
+            [src]="'assets/svg/settings_icon.svg'"
+            alt="setting-icon"
+          >
+        </span>
+        <bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left">
+          <ul class="list-unstyled">
+            <li>
+              <button
+                class="action-button__disconnect"
+                (click)="onPlatformDisconnect(element)"
+              >
+                <i class="material-icons icon">cast</i>
+                <span>Disconnect</span>
+              </button>
+            </li>
+          </ul>
+        </bubble-up>
+      </td>
     </ng-container>
 
     <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss
index 4bf890f70..d73d9b45f 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss
@@ -33,3 +33,63 @@
 .link {
   text-decoration: underline;
 }
+
+.hided-table-title {
+  color: transparent;
+}
+
+.table-cell {
+  position: relative;
+}
+
+.list-menu {
+  left: auto;
+  top: 30px !important;
+  width: 190px;
+  max-height: calc(100vh / 2 - 70px);
+  margin-left: 0;
+  box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12);
+  border: none;
+}
+
+.actions-menu {
+  position: relative;
+  width: 190px;
+}
+
+.action-button__disconnect {
+  display: flex;
+  align-items: center;
+  width: 100%;
+  padding: 10px 15px;
+  background-color: transparent;
+  color: rgb(87, 114, 137);
+  border: none;
+  outline: none;
+
+  &:hover {
+    color: #35afd5;
+    cursor: pointer;
+  }
+}
+
+.action-cell {
+  position: relative;
+}
+
+.icon {
+  position: relative;
+  margin-right: 10px;
+
+  &::before {
+    position: absolute;
+    top: 12px;
+    left: -8px;
+    width: 39px;
+    height: 1px;
+    rotate: 40deg;
+    content: '';
+    background-color: black;
+    transform: rotateX(1deg);
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.ts
index 29b815939..16b83a2a9 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.ts
@@ -18,30 +18,18 @@
  */
 
 import { Component, OnInit } from '@angular/core';
-import { GeneralEnvironmentStatus } from '../../administration/management/management.model';
-import { HealthStatusService } from '../../core/services';
+import { BehaviorSubject, EMPTY, Observable, pipe } from 'rxjs';
+import { switchMap, take, tap } from 'rxjs/operators';
+import { MatDialog } from '@angular/material/dialog';
 import { ToastrService } from 'ngx-toastr';
-import { ConnectedPlatformDisplayedColumns, Image_Table_Titles } from './connected-platforms.comnfig';
-
-const mockedData = [
-  {
-    platformName: 'azure',
-    linkToPlatform: 'www.google.com/'
-  },
-  {
-    platformName: 'azure',
-    linkToPlatform: 'google.com'
-  },
-  {
-    platformName: 'azure',
-    linkToPlatform: 'google.com'
-  },
-  {
-    platformName: 'azure',
-    linkToPlatform: 'google.com'
-  },
-];
 
+import { ConnectedPlatformsStatus, GeneralEnvironmentStatus } from '../../administration/management/management.model';
+import { HealthStatusService } from '../../core/services';
+import { ConnectedPlatformsTableTitles, ConnectedPlatformDisplayedColumns } from './connected-platforms.config';
+import { ConnectedPlatformDialogComponent } from './connected-platform-dialog/connected-platform-dialog.component';
+import { ConnectedPlatformsInfo, Platform } from './connected-platforms.models';
+import { ConnectedPlatformsService } from './connected-platforms.service';
+import { WarningDialogComponent } from './warning-dialog/warning-dialog.component';
 
 @Component({
   selector: 'datalab-connected-platforms',
@@ -49,28 +37,77 @@ const mockedData = [
   styleUrls: ['./connected-platforms.component.scss']
 })
 export class ConnectedPlatformsComponent implements OnInit {
-  readonly tableHeaderCellTitles: typeof Image_Table_Titles = Image_Table_Titles;
+  readonly tableHeaderCellTitles: typeof ConnectedPlatformsTableTitles = ConnectedPlatformsTableTitles;
+
+  // tslint:disable-next-line:max-line-length
+  private readonly connectedPlatformsStatus$$: BehaviorSubject<ConnectedPlatformsStatus> = new BehaviorSubject<ConnectedPlatformsStatus>({} as ConnectedPlatformsStatus);
+  readonly connectedPlatformsStatus$: Observable<ConnectedPlatformsStatus> = this.connectedPlatformsStatus$$.asObservable();
 
-  healthStatus: GeneralEnvironmentStatus;
+  platformPageData$: Observable<ConnectedPlatformsInfo>;
 
   displayedColumns: typeof ConnectedPlatformDisplayedColumns = ConnectedPlatformDisplayedColumns;
-  dataSource = mockedData;
 
   constructor(
     private healthStatusService: HealthStatusService,
     public toastr: ToastrService,
+    private dialog: MatDialog,
+    private connectedPlatformsService: ConnectedPlatformsService
   ) { }
 
   ngOnInit(): void {
     this.getEnvironmentHealthStatus();
+    this.getConnectedPlatformPageInfo();
+    this.initPageData();
   }
 
-  private getEnvironmentHealthStatus(): void {
-    this.healthStatusService.getEnvironmentHealthStatus().subscribe(
-      (result: GeneralEnvironmentStatus) => {
-        this.healthStatus = result;
-      },
-      error => this.toastr.error(error.message, 'Oops!')
+  onAddNew(): void {
+    this.dialog.open(ConnectedPlatformDialogComponent, {
+      data: this.connectedPlatformsService.addModalData,
+      panelClass: 'modal-lg'
+    })
+      .afterClosed()
+      .pipe(
+        this.getModalAction(this.connectedPlatformsService.addPlatform),
+      ).subscribe();
+  }
+
+  onPlatformDisconnect({name}: Platform): void {
+    this.dialog.open(WarningDialogComponent,
+      {
+        data: name,
+        panelClass: 'modal-sm'
+      })
+      .afterClosed()
+      .pipe(
+        this.getModalAction(this.connectedPlatformsService.disconnectPlatform)
+      ).subscribe();
+  }
+
+  private getModalAction(callback: Function) {
+    callback = callback.bind(this.connectedPlatformsService);
+    return pipe(
+      switchMap((arg) => {
+        if (arg) {
+          return callback(arg);
+        }
+        return EMPTY;
+      }),
+      switchMap(() => this.connectedPlatformsService.getConnectedPlatformPageInfo())
     );
   }
+
+  private getEnvironmentHealthStatus(): void {
+    this.healthStatusService.getEnvironmentHealthStatus().pipe(
+      tap((response: GeneralEnvironmentStatus) => this.connectedPlatformsStatus$$.next(response.connectedPlatforms)),
+      take(1)
+    ).subscribe();
+  }
+
+  private getConnectedPlatformPageInfo(): void {
+    this.connectedPlatformsService.getConnectedPlatformPageInfo().subscribe();
+  }
+
+  private initPageData(): void {
+    this.platformPageData$ = this.connectedPlatformsService.platformPageData$;
+  }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.comnfig.ts b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.config.ts
similarity index 85%
copy from services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.comnfig.ts
copy to services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.config.ts
index 0a24005b0..708ff528e 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.comnfig.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.config.ts
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-export enum Image_Table_Titles {
+export enum ConnectedPlatformsTableTitles {
   platformName = 'Platform name',
   linkToPlatform = 'Link to platform',
   actions = 'Actions'
@@ -28,3 +28,12 @@ export const ConnectedPlatformDisplayedColumns = [
   'linkToPlatform',
   'actions',
 ];
+
+export enum ModalTitles {
+  disconnect= 'Disconnect platform'
+}
+
+export enum ConfirmButtonNames {
+  yes = 'Yes',
+  add = 'Add'
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.models.ts
similarity index 70%
copy from services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss
copy to services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.models.ts
index 4bf890f70..d51487953 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.models.ts
@@ -17,19 +17,19 @@
  * under the License.
  */
 
-.table {
-  width: 100%;
+export interface ConnectedPlatformsInfo {
+  userPlatforms: Platform[];
+  types: string[];
+  platformNames: string[];
 }
 
-.column {
-  width: 20%;
+export interface Platform {
+  name: string;
+  type: string;
+  user: string;
+  url: string;
 }
 
-.action-icon,
-.link {
-  cursor: pointer;
-}
+export type AddModalData = Omit<ConnectedPlatformsInfo, 'userPlatforms'>;
 
-.link {
-  text-decoration: underline;
-}
+export type AddPlatformFromValue = Omit<Platform, 'user'>;
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.module.ts b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.module.ts
index f5ad17999..17fb763b8 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.module.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.module.ts
@@ -24,17 +24,28 @@ import { ConnectedPlatformsRoutingModule } from './connected-platforms-routing.m
 import { ConnectedPlatformsComponent } from './connected-platforms.component';
 import { MaterialModule } from '../../shared/material.module';
 import { NormalizeLinkPipeModule } from '../../core/pipes';
+import { BubbleModule } from '../../shared';
+import { WarningDialogComponent } from './warning-dialog/warning-dialog.component';
+import { ModalPartsModule } from '../../shared/modal-parts/modal-parts.module';
+import { ConnectedPlatformDialogComponent } from './connected-platform-dialog/connected-platform-dialog.component';
+import { ReactiveFormsModule } from '@angular/forms';
 
 
 @NgModule({
   declarations: [
-    ConnectedPlatformsComponent
+    ConnectedPlatformsComponent,
+    WarningDialogComponent,
+    ConnectedPlatformDialogComponent
   ],
   imports: [
     CommonModule,
     MaterialModule,
     NormalizeLinkPipeModule,
-    ConnectedPlatformsRoutingModule
-  ]
+    ConnectedPlatformsRoutingModule,
+    BubbleModule,
+    ModalPartsModule,
+    ReactiveFormsModule
+  ],
+  entryComponents: [ ConnectedPlatformDialogComponent, WarningDialogComponent ]
 })
 export class ConnectedPlatformsModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.service.ts b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.service.ts
new file mode 100644
index 000000000..3a986164a
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.service.ts
@@ -0,0 +1,59 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Injectable } from '@angular/core';
+import { ConnectedPlatformApiService } from '../../core/services/connected-platform-api.service';
+import { tap } from 'rxjs/operators';
+import { BehaviorSubject, Observable } from 'rxjs';
+import { AddModalData, AddPlatformFromValue, ConnectedPlatformsInfo } from './connected-platforms.models';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class ConnectedPlatformsService {
+  // tslint:disable-next-line:max-line-length
+  private platformPageData$$: BehaviorSubject<ConnectedPlatformsInfo> = new BehaviorSubject<ConnectedPlatformsInfo>({} as ConnectedPlatformsInfo);
+  platformPageData$: Observable<ConnectedPlatformsInfo> = this.platformPageData$$.asObservable();
+  addModalData: AddModalData;
+
+  constructor(
+    private connectedPlatformPageService: ConnectedPlatformApiService
+  ) { }
+
+  getConnectedPlatformPageInfo(): Observable<ConnectedPlatformsInfo> {
+    return this.connectedPlatformPageService.getConnectedPlatformsPage()
+      .pipe(
+        tap( result => this.platformPageData$$.next(result)),
+        tap( result => this.getAddModalData(result)),
+      );
+  }
+
+  addPlatform(platformParams: AddPlatformFromValue): Observable<any> {
+    return this.connectedPlatformPageService.addPlatform(platformParams);
+  }
+
+  disconnectPlatform(platformName: string): Observable<any> {
+    return this.connectedPlatformPageService.disconnectPlatform(platformName);
+  }
+
+  private getAddModalData(info: ConnectedPlatformsInfo): void {
+    const { platformNames, types } = info;
+    this.addModalData = { platformNames, types };
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.html
new file mode 100644
index 000000000..32d382c05
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.html
@@ -0,0 +1,28 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<datalab-modal-header (close)="onClose()" [modalTitle]="title.disconnect"></datalab-modal-header>
+<div class="dialog-content">
+  <p class="content red">The <span class="platform-name">{{data}}</span> will be disconnected from this account.</p>
+  <datalab-modal-btn
+    [needAdditionalQuestion]="true"
+    (closeEvent)="onBtnClick($event)"
+    [confirmBtnName]="confirmButtonName.yes"
+  ></datalab-modal-btn>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.scss
similarity index 80%
copy from services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss
copy to services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.scss
index 4bf890f70..310d4b09f 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.scss
@@ -17,19 +17,21 @@
  * under the License.
  */
 
-.table {
-  width: 100%;
+.dialog-content {
+  padding: 25px 30px;
 }
 
-.column {
-  width: 20%;
+.red {
+  color: red;
 }
 
-.action-icon,
-.link {
-  cursor: pointer;
+.content {
+  margin-bottom: 50px;
+  padding-top: 20px;
+  text-align: center;
+  font-weight: 400;
 }
 
-.link {
-  text-decoration: underline;
+.platform-name {
+  font-weight: 700;
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.ts
new file mode 100644
index 000000000..f30f0d3be
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.ts
@@ -0,0 +1,49 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, Inject } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { ConfirmButtonNames, ModalTitles } from '../connected-platforms.config';
+
+@Component({
+  selector: 'datalab-warning-dialog',
+  templateUrl: './warning-dialog.component.html',
+  styleUrls: ['./warning-dialog.component.scss']
+})
+export class WarningDialogComponent {
+  readonly title: typeof ModalTitles = ModalTitles;
+  readonly confirmButtonName: typeof ConfirmButtonNames = ConfirmButtonNames;
+
+  constructor(
+    public dialogRef: MatDialogRef<WarningDialogComponent>,
+    @Inject(MAT_DIALOG_DATA) public data: string
+  ) { }
+
+  onClose(): void {
+    this.dialogRef.close();
+  }
+
+  onBtnClick(isConfirm: boolean): void {
+    let platformName;
+    if (isConfirm) {
+      platformName = this.data;
+    }
+    this.dialogRef.close(platformName);
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.html
index 12321aba0..35559f707 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.html
@@ -308,7 +308,8 @@
                 </span>
                 <span
                   *ngIf="element.imageUserPermissions | isElementAvailable: isObjectFieldTrue"
-                  #settings class="actions"
+                  class="actions"
+                  #settings
                   (click)="actions.toggle($event, settings)"
                 ></span>
               </div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.ts
index 6487cd088..a0301623d 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.ts
@@ -78,7 +78,6 @@ export class ImagesComponent implements OnInit, OnDestroy {
   readonly imageActionType: typeof ImageActions = ImageActions;
 
   isActionsOpen: boolean = false;
-  healthStatus: GeneralEnvironmentStatus;
   dataSource: Observable<ImageModel[]>;
   projectSource: Observable<ProjectModel[]>;
   checkboxSelected: boolean = false;
@@ -265,12 +264,7 @@ export class ImagesComponent implements OnInit, OnDestroy {
   }
 
   private getEnvironmentHealthStatus(): void {
-    this.healthStatusService.getEnvironmentHealthStatus().subscribe(
-      (result: GeneralEnvironmentStatus) => {
-        this.healthStatus = result;
-      },
-      error => this.toastr.error(error.message, 'Oops!')
-    );
+    this.healthStatusService.getEnvironmentHealthStatus().subscribe();
   }
 
   private initFilteredColumnState(): void {
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.config.ts b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.config.ts
index 60a3ab54b..247f47d76 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.config.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.config.ts
@@ -122,7 +122,8 @@ export enum ImageActions {
 export enum ModalTitle {
   share = 'Share image',
   terminate = 'Terminate image',
-  unShare = '! Warning'
+  unShare = '! Warning',
+  addPlatform = 'Add platform'
 }
 
 export enum URL_Chunk {
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.service.ts b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.service.ts
index b5d74f5fb..a258f5337 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.service.ts
@@ -14,7 +14,7 @@ import {
   ImageActionType,
   ImageActionModalData
 } from './images.model';
-import { ApplicationServiceFacade, UserImagesPageService } from '../../core/services';
+import { ApplicationServiceFacade, ImagesPageService } from '../../core/services';
 import { ChangedColumnStartValue, FilterFormInitialValue, ModalTitle, SharingStatus } from './images.config';
 import { ShareDialogData, UserData } from '../exploratory/image-action-dialog/image-action.model';
 
@@ -45,7 +45,7 @@ export class ImagesService {
 
   constructor(
     private applicationServiceFacade: ApplicationServiceFacade,
-    private userImagesPageService: UserImagesPageService
+    private userImagesPageService: ImagesPageService
   ) { }
 
   getImagePageInfo(): Observable<ProjectImagesInfo> {
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources.module.ts b/services/self-service/src/main/resources/webapp/src/app/resources/resources.module.ts
index 6bef1c4e2..fe9561f04 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources.module.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources.module.ts
@@ -32,13 +32,13 @@ import { BucketDataService } from './bucket-browser/bucket-data.service';
 import { ConvertFileSizePipeModule } from '../core/pipes/convert-file-size';
 import { BucketBrowserModule } from './bucket-browser/bucket-browser.module';
 import { ImagesComponent } from './images/images.component';
-import {CheckboxModule} from '../shared/checkbox';
-import {BubbleModule} from '../shared';
+import { CheckboxModule } from '../shared/checkbox';
+import { BubbleModule } from '../shared';
 import { IsElementAvailablePipeModule, NormalizeDropdownMultiValuePipeModule } from '../core/pipes';
 import { LocalDatePipeModule } from '../core/pipes/local-date-pipe';
 import { ImageActionDialogModule } from './exploratory/image-action-dialog/image-action-dialog.module';
 import { ImageDetailDialogModule } from './exploratory/image-detail-dialog/image-detail-dialog.module';
-import {LibraryInfoModalModule} from './exploratory/library-info-modal/library-info-modal.module';
+import { LibraryInfoModalModule } from './exploratory/library-info-modal/library-info-modal.module';
 import { PageFilterComponent } from './exploratory/page-filter/page-filter.component';
 import { DirectivesModule } from '../core/directives';
 
@@ -69,7 +69,6 @@ import { DirectivesModule } from '../core/directives';
     ConfirmDeleteAccountDialogComponent,
     ImagesComponent,
     PageFilterComponent,
-
   ],
   entryComponents: [ManageUngitComponent, ConfirmDeleteAccountDialogComponent],
   providers: [BucketDataService],
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.html b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.html
new file mode 100644
index 000000000..0a5089c4b
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.html
@@ -0,0 +1,34 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+<div class="component__wrapper">
+  <p *ngIf="needAdditionalQuestion" class="question center">
+    Do you want proceed?
+  </p>
+  <div class="button__wrapper">
+    <button type="button" class="butt mat-raised-button" (click)="close()">No</button>
+    <button
+      [disabled]="isConfirmBtnDisabled"
+      type="button"
+      class="butt butt-success mat-raised-button"
+      (click)="close(true)">
+      {{confirmBtnName}}
+    </button>
+  </div>
+</div>
+
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.scss
similarity index 85%
copy from services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss
copy to services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.scss
index 4bf890f70..d46002dc1 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.scss
@@ -1,4 +1,4 @@
-/*!
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -17,19 +17,13 @@
  * under the License.
  */
 
-.table {
-  width: 100%;
+.button__wrapper {
+  text-align: center;
 }
 
-.column {
-  width: 20%;
-}
-
-.action-icon,
-.link {
-  cursor: pointer;
-}
-
-.link {
-  text-decoration: underline;
+.question {
+  margin-bottom: 20px;
+  text-align: center;
+  color: #718ba6;
+  font-weight: bold;
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.comnfig.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.ts
similarity index 60%
rename from services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.comnfig.ts
rename to services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.ts
index 0a24005b0..4aa51fb0c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.comnfig.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.ts
@@ -17,14 +17,21 @@
  * under the License.
  */
 
-export enum Image_Table_Titles {
-  platformName = 'Platform name',
-  linkToPlatform = 'Link to platform',
-  actions = 'Actions'
-}
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+
+@Component({
+  selector: 'datalab-modal-btn',
+  templateUrl: './modal-btn.component.html',
+  styleUrls: ['./modal-btn.component.scss']
+})
+export class ModalBtnComponent {
+  @Input() isConfirmBtnDisabled: boolean;
+  @Input() confirmBtnName: string;
+  @Input() needAdditionalQuestion: boolean = false;
 
-export const ConnectedPlatformDisplayedColumns = [
-  'platformName',
-  'linkToPlatform',
-  'actions',
-];
+  @Output() closeEvent: EventEmitter<boolean> = new EventEmitter<boolean>();
+
+  close(flag: boolean = false): void {
+    this.closeEvent.emit(flag);
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.html b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.html
new file mode 100644
index 000000000..83650e21b
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.html
@@ -0,0 +1,27 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<div>
+  <header class="dialog-header">
+    <h4 class="modal-title">
+      {{modalTitle}}
+    </h4>
+    <button type="button" class="close" (click)="onClose()">&times;</button>
+  </header>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.scss
similarity index 70%
copy from services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss
copy to services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.scss
index 4bf890f70..ece700481 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.scss
@@ -17,19 +17,26 @@
  * under the License.
  */
 
-.table {
-  width: 100%;
+.dialog-header {
+  position: relative;
+  padding-left: 30px;
+  height: 50px;
+  background: #f6fafe;
+  line-height: 50px;
 }
 
-.column {
-  width: 20%;
-}
-
-.action-icon,
-.link {
+.close {
+  position: absolute;
+  top: 0;
+  right: 0;
+  height: 50px;
+  width: 50px;
+  font-size: 24px;
+  font-weight: 300;
+  border: 0;
+  background: none;
+  color: #577289;
+  outline: none;
   cursor: pointer;
-}
-
-.link {
-  text-decoration: underline;
+  transition: all 0.5s ease-in-out;
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.ts
similarity index 67%
copy from services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss
copy to services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.ts
index 4bf890f70..7ef9b6d62 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.ts
@@ -17,19 +17,20 @@
  * under the License.
  */
 
-.table {
-  width: 100%;
-}
+import { Component, EventEmitter, Input, Output } from '@angular/core';
 
-.column {
-  width: 20%;
-}
+@Component({
+  selector: 'datalab-modal-header',
+  templateUrl: './modal-header.component.html',
+  styleUrls: ['./modal-header.component.scss']
+})
+export class ModalHeaderComponent {
+  @Input() modalTitle: string;
 
-.action-icon,
-.link {
-  cursor: pointer;
-}
+  @Output() close: EventEmitter<any> = new EventEmitter<any>();
+
+  onClose(): void {
+    this.close.emit();
+  }
 
-.link {
-  text-decoration: underline;
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.module.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-parts.module.ts
similarity index 67%
copy from services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.module.ts
copy to services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-parts.module.ts
index f5ad17999..3559594eb 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.module.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-parts.module.ts
@@ -19,22 +19,22 @@
 
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
+import { ModalHeaderComponent } from './modal-header/modal-header.component';
+import { ModalBtnComponent } from './modal-btn/modal-btn.component';
 
-import { ConnectedPlatformsRoutingModule } from './connected-platforms-routing.module';
-import { ConnectedPlatformsComponent } from './connected-platforms.component';
-import { MaterialModule } from '../../shared/material.module';
-import { NormalizeLinkPipeModule } from '../../core/pipes';
 
 
 @NgModule({
   declarations: [
-    ConnectedPlatformsComponent
+    ModalHeaderComponent,
+    ModalBtnComponent
   ],
   imports: [
-    CommonModule,
-    MaterialModule,
-    NormalizeLinkPipeModule,
-    ConnectedPlatformsRoutingModule
+    CommonModule
+  ],
+  exports: [
+    ModalBtnComponent,
+    ModalHeaderComponent
   ]
 })
-export class ConnectedPlatformsModule { }
+export class ModalPartsModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html
index f724f6786..78ea73c1e 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html
@@ -129,6 +129,7 @@
             </a>
 
             <a
+              *ngIf="healthStatus.connectedPlatforms?.view"
               class="sub-nav-item"
               [style.margin-left.px]="isExpanded ? '30' : '0'"
               [routerLink]="[routerList.connectedPlatforms]"
diff --git a/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss b/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss
index becd4a2e5..e78e6ba2c 100644
--- a/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss
+++ b/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss
@@ -147,7 +147,7 @@
 }
 
 .audit {
-  .select-wrapper {
+  .select__wrapper {
     .mat-reset {
       .selector-wrapper {
         height: 25px;
@@ -1056,8 +1056,8 @@ mat-progress-bar {
   }
 }
 .configuration-wrapper {
-  box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 
-              0px 6px 10px 0px rgba(0, 0, 0, 0.14), 
+  box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2),
+              0px 6px 10px 0px rgba(0, 0, 0, 0.14),
               0px 1px 18px 0px rgba(0, 0, 0, 0.12);
 
   .mat-tab-header {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datalab.apache.org
For additional commands, e-mail: commits-help@datalab.apache.org