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

hshpak pushed a commit to branch 
feat/DATALAB-3009/share-with-user-on-another-project-pop-up-layout
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git

commit 155875e660e5243d81e4f72f00ef722d56e33d34
Author: Hennadii_Shpak <[email protected]>
AuthorDate: Mon Sep 5 12:46:58 2022 +0300

    initial commit
---
 .../src/main/resources/webapp/angular.json         |   3 +-
 .../cluster-details/cluster-details.component.html |  30 +++---
 .../cluster-details/cluster-details.component.ts   |   9 +-
 .../image-action-dialog.component.html             |  31 ++----
 .../image-action-dialog.component.scss             |  74 -------------
 .../image-action-dialog.component.ts               |  23 ++++-
 .../image-action-dialog.module.ts                  |  11 +-
 ...ion-dialog.module.ts => image-action.config.ts} |  24 ++---
 ...tion-dialog.module.ts => image-action.model.ts} |  21 ++--
 .../share-dialog/share-dialog.component.html       | 111 ++++++++++++++++++++
 .../share-dialog/share-dialog.component.scss       | 114 +++++++++++++++++++++
 .../share-dialog/share-dialog.component.ts         | 110 ++++++++++++++++++++
 .../share-user-data/share-user-data.component.html |   6 ++
 .../share-user-data/share-user-data.component.scss |  43 ++++++++
 .../share-user-data/share-user-data.component.ts   |  22 ++++
 .../terminate-dialog.component.html}               |  27 +----
 .../terminate-dialog.component.scss}               |  66 +++++++++---
 .../terminate-dialog.component.ts}                 |  21 ++--
 .../src/app/resources/images/images.component.ts   |   4 +-
 .../src/app/resources/images/images.model.ts       |  19 +++-
 .../src/app/resources/images/images.service.ts     |  11 ++
 21 files changed, 585 insertions(+), 195 deletions(-)

diff --git a/services/self-service/src/main/resources/webapp/angular.json 
b/services/self-service/src/main/resources/webapp/angular.json
index 5390f53c9..cc3beda92 100644
--- a/services/self-service/src/main/resources/webapp/angular.json
+++ b/services/self-service/src/main/resources/webapp/angular.json
@@ -14,7 +14,8 @@
             "allowedCommonJsDependencies": [
               "chart.js",
               "ng-daterangepicker",
-              "moment-timezone"
+              "moment-timezone",
+              "rxjs-compat"
             ],
             "aot": true,
             "outputPath": "dist",
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.html
 
b/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.html
index b0d1eb66a..7870e7796 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.html
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.html
@@ -130,7 +130,7 @@
           <div class="m-top-10">
             <p *ngFor="let item of resource.computational_url" class="ellipsis 
flex" (mouseleave)="hideCopyIcon()">
               <span class="strong spark-url-desc">{{ item.description 
}}:</span>&nbsp;
-              <a 
+              <a
                 (click)="logAction(resource, environment, 'follow')"
                  href="{{item.url}}"
                  target="_blank"
@@ -145,8 +145,8 @@
               <span
                 (click)="logAction(resource, environment, 
'copy');$event.stopPropagation()"
                 *ngIf="isCopyIconVissible[item.description]"
-                [matTooltip]="isCopied ? 'Copy ' + item.description + 
(item.description.indexOf('url')  === -1 ? ' url' : ''): 'Copied'" 
-                matTooltipPosition="above" 
+                [matTooltip]="isCopied ? 'Copy ' + item.description + 
(item.description.indexOf('url')  === -1 ? ' url' : ''): 'Copied'"
+                matTooltipPosition="above"
                 class="copy-icon-wrapper"
               >
                 <span  class="link-icon" (click)="copyLink(item.url)" >
@@ -156,8 +156,8 @@
             </p>
           </div>
         </div>
-        <div 
-          class="checkbox-group" 
+        <div
+          class="checkbox-group"
           *ngIf="resource.image === 'docker.datalab-dataengine'
               && resource.status === 'running'
               && environment.image !== 'docker.datalab-zeppelin'
@@ -170,13 +170,13 @@
           <div class="checkbox-group">
             <form [formGroup]="configurationForm" novalidate>
               <div class="config-details" [ngClass]="{ show: 
configuration?.nativeElement['checked'] || false }">
-                <textarea 
-                  formControlName="configuration_parameters" 
+                <textarea
+                  formControlName="configuration_parameters"
                   placeholder="Cluster configuration template, JSON"
                   data-gramm_editor="false"
                 ></textarea>
                 <span class="danger_color"
-                  
*ngIf="!configurationForm.controls.configuration_parameters.valid 
+                  
*ngIf="!configurationForm.controls.configuration_parameters.valid
                       && 
configurationForm.controls['configuration_parameters'].dirty">
                       Configuration parameters is not in a valid format
                 </span>
@@ -185,23 +185,23 @@
           </div>
         </div>
         <div *ngIf="environment.image === 'docker.datalab-zeppelin' && 
resource.status === 'running'">
-          <small>Spark default configuration for Apache Zeppelin can not be 
changed from DataLab UI. 
+          <small>Spark default configuration for Apache Zeppelin can not be 
changed from DataLab UI.
             Currently it can be done directly through Apache Zeppelin 
interpreter menu.
-              For more details please refer for Apache Zeppelin 
+              For more details please refer for Apache Zeppelin
               <a 
href="https://zeppelin.apache.org/docs/0.9.0/usage/interpreter/overview.html"; 
target="_blank">official
                   documentation</a>.
           </small>
         </div>
         <div class="text-center m-top-30" 
*ngIf="configuration?.nativeElement['checked'] || false">
-          <button 
-            mat-raised-button type="button" 
-            (click)="dialogRef.close()" 
+          <button
+            mat-raised-button type="button"
+            (click)="dialogRef.close()"
             class="butt action"
           >
             Cancel
           </button>
-          <button 
-            mat-raised-button type="submit" 
+          <button
+            mat-raised-button type="submit"
             [disabled]="!configurationForm.valid"
             class="butt butt-success action"
             [ngClass]="{'not-allowed': !configurationForm.valid}"
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.ts
 
b/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.ts
index 1e6526b9e..1c6842c6d 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.ts
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.ts
@@ -74,6 +74,7 @@ export class DetailComputationalResourcesComponent implements 
OnInit {
     if (this.resource.image === 'docker.datalab-dataengine') {
       this.getClusterConfiguration();
     }
+    console.log(this.resource);
   }
 
   public isEllipsisActive($event): void {
@@ -139,9 +140,9 @@ export class DetailComputationalResourcesComponent 
implements OnInit {
     };
 
     this.auditService.sendDataToAudit(
-      { 
-        resource_name: resource.computational_name, 
-        info: JSON.stringify(clusterInfo), 
+      {
+        resource_name: resource.computational_name,
+        info: JSON.stringify(clusterInfo),
         type: 'COMPUTE'
       }
     ).subscribe();
@@ -154,7 +155,7 @@ export class DetailComputationalResourcesComponent 
implements OnInit {
   public showCopyIcon(element) {
     this.isCopyIconVissible[element] = true;
   }
-  
+
   public hideCopyIcon() {
     for (const key in this.isCopyIconVissible) {
       this.isCopyIconVissible[key] = false;
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.html
 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.html
index c09683c24..297a95bb7 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.html
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.html
@@ -19,35 +19,22 @@
 
 <div id="dialog-box">
   <header class="dialog-header">
-    <h4 class="modal-title">{{data.title}}</h4>
+    <h4 class="modal-title">{{data.title}}<span *ngIf="data.actionType === 
actionType.share">: {{data.imageName}}</span></h4>
     <button type="button" class="close" 
(click)="dialogRef.close()">&times;</button>
   </header>
   <section class="content">
-    <p class="description" *ngIf="data.actionType === actionType.share">
-      The image
-      <span class="shared-image-name">{{data.imageName}} </span>
-      <span>will be shared with all current user groups on the project with 
all the data and code.</span>
-    </p>
-    <div *ngIf="data.actionType === actionType.terminate" 
class="terminate-action__wrapper">
-      <div class="list-header sans terminate-action__header--wrapper">
-        <div class="image">Image</div>
-        <div class="status">Further status</div>
-      </div>
-      <div class="scrolling-content scrolling terminate-image-list__wrapper">
-        <div class="image-name ellipsis">{{data.imageName}}</div>
-        <div class="status terminated">Terminated</div>
-      </div>
-      <p *ngIf="data.isShared" class="shared-warning">!The image is shared 
with other users.</p>
-    </div>
-    <p class="question center">
-      Do you want proceed?
-    </p>
-    <div class="text-center m-top-30 m-bott-10">
+    <ng-content select="[datalab-share-dialog]">
+    </ng-content>
+    <ng-content select="[datalab-terminate-dialog]">
+    </ng-content>
+    <div [hidden]="activeTabConfig && activeTabConfig.shareWith" 
class="text-center m-top-30 m-bott-10">
       <button type="button" class="butt mat-raised-button" 
(click)="dialogRef.close()">No</button>
       <button
+        [disabled]="isApplyBtnDisabled"
         type="button"
         class="butt butt-success mat-raised-button"
-        (click)="dialogRef.close(true)">Yes
+        (click)="dialogRef.close(true)">
+        {{confirmBtnName}}
       </button>
     </div>
   </section>
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.scss
 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.scss
index 6facffe45..ec94d5903 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.scss
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.scss
@@ -23,77 +23,3 @@
   padding: 20px 30px;
   font-weight: 600;
 }
-
-.question {
-  color: #718ba6;
-}
-
-.center {
-  text-align: center;
-}
-
-.description {
-  margin-bottom: 20px;
-  color: #35afd5;
-  font-size: 14px;
-  text-align: center;
-  font-weight: 200;
-}
-
-.image-name {
-  font-weight: 200;
-}
-
-.shared-image-name {
-  font-weight: 600;
-}
-
-.image-list {
-  display: flex;
-  justify-content: space-between;
-}
-
-.terminate-action__wrapper {
-  width: 100%;
-}
-
-.terminate-image-list__wrapper {
-  margin-bottom: 10px;
-  border-bottom: 1px solid rgba(0,0,0,.08);
-}
-
-.terminate-action__header--wrapper,
-.terminate-image-list__wrapper {
-  display: flex;
-  justify-content: space-between;
-  padding: 10px 20px;
-  line-height: 26px;
-
-  & > .status {
-    text-align: right;
-  }
-}
-
-.terminate-action__header--wrapper {
-  margin-top: 26px;
-}
-
-.content {
-  & .terminate-image-list__wrapper {
-    & > .status {
-      font-weight: 300;
-    }
-  }
-}
-
-.shared-warning {
-  margin-bottom: 10px;
-  color: red;
-  text-align: center;
-  font-weight: 400;
-}
-
-.question,
-.shared-warning {
-  line-height: 1;
-}
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.ts
 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.ts
index bcb2feaf0..2b7e46a1a 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.ts
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.ts
@@ -17,19 +17,38 @@
  * under the License.
  */
 
-import { Component, Inject } from '@angular/core';
+import { Component, Inject, Input, OnInit } from '@angular/core';
 import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
 import { ImageActions, ImageActionModalData } from '../../images';
+import { DialogWindowTabConfig } from './image-action.model';
 
 @Component({
   selector: 'datalab-image-action-dialog',
   templateUrl: './image-action-dialog.component.html',
   styleUrls: ['./image-action-dialog.component.scss']
 })
-export class ImageActionDialogComponent {
+export class ImageActionDialogComponent implements OnInit {
+  @Input() activeTabConfig: DialogWindowTabConfig;
+  @Input() isApplyBtnDisabled: Boolean;
+
   readonly actionType: typeof ImageActions = ImageActions;
+
+  confirmBtnName!: string;
+
   constructor(
     public dialogRef: MatDialogRef<ImageActionDialogComponent>,
     @Inject(MAT_DIALOG_DATA) public data: ImageActionModalData,
   ) { }
+
+  ngOnInit(): void {
+    this.createConfirmBtnName();
+  }
+
+  private createConfirmBtnName(): void {
+    const btnNameObj = {
+      share: 'Share',
+      terminate: 'Yes'
+    };
+    this.confirmBtnName = btnNameObj[this.data.actionType];
+  }
 }
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.module.ts
 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.module.ts
index 9dff0d351..0892178e1 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.module.ts
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.module.ts
@@ -20,15 +20,18 @@
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { ImageActionDialogComponent } from './image-action-dialog.component';
-import { NotificationDialogComponent } from 
'../../../shared/modal-dialog/notification-dialog';
 import { MaterialModule } from '../../../shared/material.module';
+import { TerminateDialogComponent } from 
'./terminate-dialog/terminate-dialog.component';
+import { ShareDialogComponent } from './share-dialog/share-dialog.component';
+import { FormsModule } from '@angular/forms';
+import { ShareUserDataComponent } from 
'./share-user-data/share-user-data.component';
 
 
 
 @NgModule({
-  declarations: [ ImageActionDialogComponent ],
-  imports: [ CommonModule, MaterialModule ],
-  entryComponents: [ImageActionDialogComponent],
+  declarations: [ ImageActionDialogComponent, TerminateDialogComponent, 
ShareDialogComponent, ShareUserDataComponent ],
+  imports: [ CommonModule, MaterialModule, FormsModule ],
+  entryComponents: [TerminateDialogComponent , ShareDialogComponent],
   exports: [ ImageActionDialogComponent ]
 })
 export class ImageActionDialogModule { }
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.module.ts
 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action.config.ts
similarity index 58%
copy from 
services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.module.ts
copy to 
services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action.config.ts
index 9dff0d351..4afac79bb 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.module.ts
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action.config.ts
@@ -17,18 +17,16 @@
  * under the License.
  */
 
-import { NgModule } from '@angular/core';
-import { CommonModule } from '@angular/common';
-import { ImageActionDialogComponent } from './image-action-dialog.component';
-import { NotificationDialogComponent } from 
'../../../shared/modal-dialog/notification-dialog';
-import { MaterialModule } from '../../../shared/material.module';
+export enum SharePlaceholder {
+  groupOrNameSearchInput = 'Enter user login or group name'
+}
 
+export enum TabName {
+  shareImage = 'shareImage',
+  shareWith = 'shareWith'
+}
 
-
-@NgModule({
-  declarations: [ ImageActionDialogComponent ],
-  imports: [ CommonModule, MaterialModule ],
-  entryComponents: [ImageActionDialogComponent],
-  exports: [ ImageActionDialogComponent ]
-})
-export class ImageActionDialogModule { }
+export enum UserDataTypeConfig {
+  group = 'GROUP',
+  user = 'USER'
+}
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.module.ts
 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action.model.ts
similarity index 58%
copy from 
services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.module.ts
copy to 
services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action.model.ts
index 9dff0d351..8c16eecd5 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.module.ts
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action.model.ts
@@ -17,18 +17,15 @@
  * under the License.
  */
 
-import { NgModule } from '@angular/core';
-import { CommonModule } from '@angular/common';
-import { ImageActionDialogComponent } from './image-action-dialog.component';
-import { NotificationDialogComponent } from 
'../../../shared/modal-dialog/notification-dialog';
-import { MaterialModule } from '../../../shared/material.module';
+export interface DialogWindowTabConfig {
+  shareImage: boolean;
+  shareWith: boolean;
+}
 
+export interface UserData {
+  value: string;
+  type: UserDataType;
+}
 
+export type UserDataType = 'USER' | 'GROUP';
 
-@NgModule({
-  declarations: [ ImageActionDialogComponent ],
-  imports: [ CommonModule, MaterialModule ],
-  entryComponents: [ImageActionDialogComponent],
-  exports: [ ImageActionDialogComponent ]
-})
-export class ImageActionDialogModule { }
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.html
 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.html
new file mode 100644
index 000000000..8b7f10eb1
--- /dev/null
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.html
@@ -0,0 +1,111 @@
+<!--
+  ~ 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-image-action-dialog [activeTabConfig]="activeTabConfig" 
[isApplyBtnDisabled]="isApplyBtnDisabled">
+  <div datalab-share-dialog class="wrapper">
+    <ul class="title__list">
+      <li
+        class="title__item active-tab"
+        [ngClass]="{'active-tab': activeTabConfig.shareImage}"
+        (click)="onTabTitle(tabsName.shareImage)"
+      >
+        <button class="title__btn">
+          <h4 class="title">
+            SHARE IMAGE
+          </h4>
+        </button>
+      </li>
+      <li
+        class="title__item"
+        [ngClass]="{'active-tab': activeTabConfig.shareWith}"
+        (click)="onTabTitle(tabsName.shareWith)"
+      >
+        <button class="title__btn">
+          <h4 class="title">
+            SHARED WITH
+          </h4>
+        </button>
+      </li>
+    </ul>
+
+    <div *ngIf="activeTabConfig.shareImage" class="search-input__wrapper">
+
+<!--      TODO REMOVE IT WHEN REMOVING THE RADIO BUTTON FROM APP-->
+
+      <div class="radio__wrapper">
+        <div class="radio-input__wrapper">
+          <label>
+            user
+            <input
+              name="user-radio"
+              type="radio"
+              [(ngModel)]="userNameOrGroup"
+              [value]="userDataTypeConfig.user">
+          </label>
+          <label>
+            user group
+            <input
+              name="group-radio"
+              type="radio"
+              [(ngModel)]="userNameOrGroup"
+              [value]="userDataTypeConfig.group">
+          </label>
+        </div>
+        <span [hidden]="!isSearchUserTouched" class="error">Select with whom 
to share the image</span>
+      </div>
+      <div class="input__wrapper">
+        <input
+          class="search-input"
+          [placeholder]="placeholder.groupOrNameSearchInput"
+          [(ngModel)]="searchInput"
+          #searchUser="ngModel"
+          (keydown.enter)="onAddUser()"
+          required
+        >
+        <button
+          class="add-person__btn"
+          mat-icon-button
+          [disabled]="isAddUserDataBtnDisabled"
+          (click)="onAddUser()"
+        >
+          <mat-icon> person_add </mat-icon>
+        </button>
+        <span [hidden]="!isUserInputEmpty" class="error">This field is 
required</span>
+        <span [hidden]="!isLongInputMessage" class="error">Length can`t be 
more than 25 symbols</span>
+      </div>
+      <div class="user-list__wrapper scrolling">
+        <ul class="user-list">
+          <li *ngFor="let entity of temporaryUserList" class="user-list__item">
+            <datalab-share-user-data 
(removeUserData)="onRemoveUserData($event, tabsName.shareImage)" 
[userData]="entity"></datalab-share-user-data>
+          </li>
+        </ul>
+      </div>
+    </div>
+
+    <div *ngIf="activeTabConfig.shareWith" class="share-with__wrapper">
+      <div class="user-list__wrapper scrolling">
+        <ul class="user-list">
+          <li *ngFor="let entity of userList" class="user-list__item">
+            <datalab-share-user-data 
(removeUserData)="onRemoveUserData($event, tabsName.shareWith)" 
[userData]="entity"></datalab-share-user-data>
+          </li>
+        </ul>
+      </div>
+    </div>
+  </div>
+</datalab-image-action-dialog>
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.scss
 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.scss
new file mode 100644
index 000000000..ab614f5c6
--- /dev/null
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.scss
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+.title{
+  color: #718ba6;
+  font-weight: 400;
+
+  &__list {
+    display: flex;
+    justify-content: space-between;
+    margin-bottom: 30px;
+  }
+
+  &__item {
+    width: 49%;
+    text-align: center;
+    border-bottom: 1px solid rgba(0,0,0,.08);
+  }
+
+  &__btn {
+    width: 100%;
+    background-color: transparent;
+    border: none;
+    outline: none;
+    cursor: pointer;
+  }
+}
+
+.search-input {
+  width: 80%;
+  color: #718ba6;
+  border: none;
+  border-bottom: 1px solid rgba(0,0,0,.08);
+  outline: none;
+
+  &::placeholder {
+    color: #c6bcbc;
+  }
+
+  &__wrapper {
+  }
+}
+
+.active-tab {
+  border-bottom: 2px solid #35afd5;
+}
+
+.error {
+  font-weight: 200;
+}
+
+.add-person__btn {
+  position: absolute;
+  top: -12px;
+  right: 10px;
+}
+
+.user-list {
+  display: flex;
+  flex-wrap: wrap;
+  max-height: 80px;
+  padding: 10px 0;
+
+  &__wrapper{
+    overflow-y: scroll;
+  }
+
+  &__item {
+    position: relative;
+    margin-right: 20px;
+    margin-bottom: 20px;
+  }
+}
+
+.input__wrapper {
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  height: 35px;
+}
+
+// TODO REMOVE IT WHEN REMOVING THE RADIO BUTTON FROM APP
+//start
+.radio__wrapper {
+  margin-bottom: 20px;
+  padding-left: 10px;
+  text-align: start;
+}
+input[name="user-radio"] {
+  margin-right: 20px;
+}
+
+label {
+  font-weight: 300;
+}
+//end
+
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.ts
 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.ts
new file mode 100644
index 000000000..df605e04d
--- /dev/null
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.ts
@@ -0,0 +1,110 @@
+/*
+ * 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 { AfterViewInit, ChangeDetectionStrategy, Component, Inject, OnInit, 
ViewChild } from '@angular/core';
+import { MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { ImageActionModalData } from '../../../images';
+import { SharePlaceholder, TabName, UserDataTypeConfig } from 
'../image-action.config';
+import { DialogWindowTabConfig, UserData, UserDataType } from 
'../image-action.model';
+import { NgModel } from '@angular/forms';
+
+const mockedUserList: UserData[] = [
+  {
+    value: 'Biba',
+    type: 'GROUP'
+  },
+  {
+    value: 'Boba',
+    type: 'USER'
+  },
+  {
+    value: '[email protected]',
+    type: 'USER'
+  },
+  {
+    value: '[email protected]',
+    type: 'GROUP'
+  },
+];
+
+@Component({
+  selector: 'datalab-share-dialog',
+  templateUrl: './share-dialog.component.html',
+  styleUrls: ['./share-dialog.component.scss'],
+  changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class ShareDialogComponent {
+  @ViewChild('searchUser') searchUser: NgModel;
+
+  readonly placeholder: typeof SharePlaceholder = SharePlaceholder;
+  readonly tabsName: typeof TabName = TabName;
+  readonly userDataTypeConfig: typeof UserDataTypeConfig = UserDataTypeConfig;
+
+  userList: UserData[] = mockedUserList;
+  temporaryUserList: UserData[] = [];
+  userNameOrGroup: UserDataType;
+  activeTabConfig: DialogWindowTabConfig = {
+    shareImage: true,
+    shareWith: false
+  };
+  searchInput = '';
+
+  onAddUser(): void {
+    if (!this.searchInput) {
+      return;
+    }
+    const newUserEntity: UserData = {
+      value: this.searchInput,
+      type: this.userNameOrGroup
+    };
+    this.temporaryUserList = [...this.temporaryUserList, newUserEntity];
+    this.searchInput = '';
+  }
+
+  onTabTitle(tabName: keyof DialogWindowTabConfig): void {
+    Object.keys(this.activeTabConfig).forEach(item => 
this.activeTabConfig[item] = false);
+    this.activeTabConfig = {...this.activeTabConfig, [tabName]: true};
+  }
+
+  onRemoveUserData(userName: string, tabName: TabName): void {
+    this.temporaryUserList = this.temporaryUserList.filter(({value}) => value 
!== userName);
+  }
+
+  get isApplyBtnDisabled(): boolean {
+    return this.searchInput.length > 25 || 
!Boolean(this.temporaryUserList.length);
+  }
+
+  get isAddUserDataBtnDisabled(): boolean {
+    return !Boolean(this.userNameOrGroup) || this.searchInput.length > 25 || 
!Boolean(this.searchInput.length);
+  }
+
+  get isSearchUserTouched(): boolean {
+    return this.searchUser?.control.touched && !Boolean(this.userNameOrGroup);
+  }
+
+  get isUserInputEmpty(): boolean {
+    return this.searchUser?.control.touched
+      && !Boolean(this.searchInput.length)
+      && !Boolean(this.temporaryUserList.length);
+  }
+
+  get isLongInputMessage() {
+    return this.searchInput.length > 25;
+  }
+}
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.html
 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.html
new file mode 100644
index 000000000..81c60d5b1
--- /dev/null
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.html
@@ -0,0 +1,6 @@
+<div class="user-data__wrapper">
+  <span><mat-icon class="user-data__icon">{{userData.type === 'GROUP' ? 
'people' : 'person'}}</mat-icon></span>
+  <span class="user-data__name">{{userData.value}}
+    <button type="button" (click)="removeUser(userData.value)" 
class="close-btn">&times;</button>
+</span>
+</div>
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.scss
 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.scss
new file mode 100644
index 000000000..5bee7b44a
--- /dev/null
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.scss
@@ -0,0 +1,43 @@
+.user-data {
+  &__name {
+    position: relative;
+    padding: 2px 20px 2px 10px;
+    font-size: 13px;
+    font-weight: 400;
+    border-radius: 5px;
+  }
+
+  &__icon {
+    position: absolute;
+    top: -5px;
+    left: 0;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 30px;
+    height: 30px;
+    color: white;
+    font-size: 18px;
+    border-radius: 50%;
+  }
+
+  &__icon,
+  &__name {
+    background-color: #D3F0F4;
+  }
+
+  &__wrapper {
+    position: relative;
+    padding-left: 24px;
+  }
+}
+
+.close-btn {
+  position: absolute;
+  top: 2px;
+  right: 4px;
+  background-color: transparent;
+  border: none;
+  outline: none;
+  cursor: pointer;
+}
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.ts
 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.ts
new file mode 100644
index 000000000..6550f2e58
--- /dev/null
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.ts
@@ -0,0 +1,22 @@
+import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, 
Output } from '@angular/core';
+import { UserData } from '../image-action.model';
+
+@Component({
+  selector: 'datalab-share-user-data',
+  templateUrl: './share-user-data.component.html',
+  styleUrls: ['./share-user-data.component.scss'],
+})
+export class ShareUserDataComponent implements OnInit {
+  @Input() userData: UserData;
+
+  @Output() removeUserData: EventEmitter<string> = new EventEmitter<string>();
+
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+
+  removeUser(userData: string): void {
+    this.removeUserData.emit(userData);
+  }
+}
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.html
 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.html
similarity index 60%
copy from 
services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.html
copy to 
services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.html
index c09683c24..532f4e2d0 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.html
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.html
@@ -17,18 +17,9 @@
   ~ under the License.
   -->
 
-<div id="dialog-box">
-  <header class="dialog-header">
-    <h4 class="modal-title">{{data.title}}</h4>
-    <button type="button" class="close" 
(click)="dialogRef.close()">&times;</button>
-  </header>
-  <section class="content">
-    <p class="description" *ngIf="data.actionType === actionType.share">
-      The image
-      <span class="shared-image-name">{{data.imageName}} </span>
-      <span>will be shared with all current user groups on the project with 
all the data and code.</span>
-    </p>
-    <div *ngIf="data.actionType === actionType.terminate" 
class="terminate-action__wrapper">
+<datalab-image-action-dialog>
+  <div datalab-terminate-dialog class="wrapper">
+    <div  class="terminate-action__wrapper">
       <div class="list-header sans terminate-action__header--wrapper">
         <div class="image">Image</div>
         <div class="status">Further status</div>
@@ -42,13 +33,5 @@
     <p class="question center">
       Do you want proceed?
     </p>
-    <div class="text-center m-top-30 m-bott-10">
-      <button type="button" class="butt mat-raised-button" 
(click)="dialogRef.close()">No</button>
-      <button
-        type="button"
-        class="butt butt-success mat-raised-button"
-        (click)="dialogRef.close(true)">Yes
-      </button>
-    </div>
-  </section>
-</div>
+  </div>
+</datalab-image-action-dialog>
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.ts
 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.scss
similarity index 52%
copy from 
services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.ts
copy to 
services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.scss
index bcb2feaf0..3b9c2a38f 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.ts
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.scss
@@ -17,19 +17,55 @@
  * under the License.
  */
 
-import { Component, Inject } from '@angular/core';
-import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
-import { ImageActions, ImageActionModalData } from '../../images';
-
-@Component({
-  selector: 'datalab-image-action-dialog',
-  templateUrl: './image-action-dialog.component.html',
-  styleUrls: ['./image-action-dialog.component.scss']
-})
-export class ImageActionDialogComponent {
-  readonly actionType: typeof ImageActions = ImageActions;
-  constructor(
-    public dialogRef: MatDialogRef<ImageActionDialogComponent>,
-    @Inject(MAT_DIALOG_DATA) public data: ImageActionModalData,
-  ) { }
+.terminate-action__wrapper {
+  width: 100%;
+}
+
+.terminate-image-list__wrapper {
+  margin-bottom: 10px;
+  border-bottom: 1px solid rgba(0,0,0,.08);
+}
+
+.terminate-action__header--wrapper,
+.terminate-image-list__wrapper {
+  display: flex;
+  justify-content: space-between;
+  padding: 10px 20px;
+  line-height: 26px;
+
+  & > .status {
+    text-align: right;
+  }
+}
+
+.terminate-action__header--wrapper {
+  margin-top: 26px;
+}
+
+.wrapper {
+  & .terminate-image-list__wrapper {
+    & > .status {
+      font-weight: 300;
+    }
+  }
+}
+
+.shared-warning {
+  margin-bottom: 10px;
+  color: red;
+  text-align: center;
+  font-weight: 400;
+}
+
+.question,
+.shared-warning {
+  line-height: 1;
+}
+
+.question {
+  color: #718ba6;
+}
+
+.center {
+  text-align: center;
 }
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.ts
 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.ts
similarity index 64%
copy from 
services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.ts
copy to 
services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.ts
index bcb2feaf0..0cba6292f 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.ts
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.ts
@@ -17,19 +17,22 @@
  * under the License.
  */
 
-import { Component, Inject } from '@angular/core';
-import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
-import { ImageActions, ImageActionModalData } from '../../images';
+import { Component, Inject, OnInit } from '@angular/core';
+import { MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { ImageActionModalData } from '../../../images';
 
 @Component({
-  selector: 'datalab-image-action-dialog',
-  templateUrl: './image-action-dialog.component.html',
-  styleUrls: ['./image-action-dialog.component.scss']
+  selector: 'datalab-terminate-dialog',
+  templateUrl: './terminate-dialog.component.html',
+  styleUrls: ['./terminate-dialog.component.scss']
 })
-export class ImageActionDialogComponent {
-  readonly actionType: typeof ImageActions = ImageActions;
+export class TerminateDialogComponent implements OnInit {
+
   constructor(
-    public dialogRef: MatDialogRef<ImageActionDialogComponent>,
     @Inject(MAT_DIALOG_DATA) public data: ImageActionModalData,
   ) { }
+
+  ngOnInit(): void {
+  }
+
 }
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 a27af583a..dca4feafb 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
@@ -54,6 +54,7 @@ import { ImagesService } from './images.service';
 import { ProgressBarService } from '../../core/services/progress-bar.service';
 import { ImageDetailDialogComponent } from 
'../exploratory/image-detail-dialog/image-detail-dialog.component';
 import { ActivatedRoute } from '@angular/router';
+import { TerminateDialogComponent } from 
'../exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component';
 
 @Component({
   selector: 'datalab-images',
@@ -164,8 +165,9 @@ export class ImagesComponent implements OnInit, OnDestroy {
     const imageInfo = this.imagesService.createImageRequestInfo(image);
     const data = this.imagesService.createActionDialogConfig(image, 
actionType);
     const requestCallback = 
this.imagesService.getRequestByAction(actionType).bind(this.imagesService);
+    const component = this.imagesService.getComponentByAction(actionType);
 
-    this.dialog.open(ImageActionDialogComponent, {
+    this.dialog.open(component, {
       data,
       panelClass: 'modal-sm'
     }).afterClosed()
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.model.ts
 
b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.model.ts
index 7957a0dda..09b32cce8 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.model.ts
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.model.ts
@@ -1,4 +1,21 @@
-import { ImageActions } from './images.config';
+/*
+ * 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.
+ */
 
 export interface ProjectImagesInfo {
   filterData: ImageFilterFormDropdownData;
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 b58d610d4..a3dfee632 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
@@ -16,6 +16,9 @@ import {
 } from './images.model';
 import { ApplicationServiceFacade, UserImagesPageService } from 
'../../core/services';
 import { ChangedColumnStartValue, FilterFormInitialValue, ModalTitle, 
SharedStatus } from './images.config';
+import { ShareDialogComponent } from 
'../exploratory/image-action-dialog/share-dialog/share-dialog.component';
+import { TerminateDialogComponent } from 
'../exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component';
+import { ComponentType } from 'ngx-toastr';
 
 @Injectable({
   providedIn: 'root'
@@ -203,6 +206,14 @@ export class ImagesService {
     return callbackList[actionType];
   }
 
+  getComponentByAction(actionType): ComponentType<unknown> {
+    const componentList = {
+      share: ShareDialogComponent,
+      terminate: TerminateDialogComponent
+    };
+    return componentList[actionType];
+  }
+
   initImagePageInfo(imagePageInfo: ProjectImagesInfo): void {
     this.getImagePageData(imagePageInfo.projectImagesInfos);
     this.getDropdownDataList(imagePageInfo.filterData);


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to