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 <borch...@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()">×</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()">×</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-unsubscr...@datalab.apache.org For additional commands, e-mail: commits-h...@datalab.apache.org