This is an automated email from the ASF dual-hosted git repository. ytykhun pushed a commit to branch DATALAB-2347 in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git
commit 62374eab25f04cc30874348a1152ed4cbab7d300 Author: Yurii Tykhun <[email protected]> AuthorDate: Fri Jul 30 18:12:36 2021 +0300 [DATALAB-2347] refactored Project list component --- .../project-list/project-list.component.html | 193 ++++++++++----------- .../project-list/project-list.component.scss | 68 ++++---- .../project/project-list/project-list.component.ts | 88 +++++----- 3 files changed, 176 insertions(+), 173 deletions(-) diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.html index e407d30..27e2ba4 100644 --- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.html +++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.html @@ -18,107 +18,106 @@ --> <div class="table-wrapper scrolling"> <table mat-table [dataSource]="dataSource" class="projects-table mat-elevation-z6 selection"> - <ng-container matColumnDef="name"> - <th mat-header-cell *matHeaderCellDef class="name"> Project name </th> - <td mat-cell *matCellDef="let element" class="name project-name"> {{element.name}} </td> - </ng-container> + <ng-container matColumnDef="name"> + <th mat-header-cell *matHeaderCellDef class="name"> Project name </th> + <td mat-cell *matCellDef="let element" class="name project-name"> {{element.name}} </td> + </ng-container> - <ng-container matColumnDef="groups"> - <th mat-header-cell *matHeaderCellDef class="groups"> Group </th> - <td mat-cell *matCellDef="let element" class="groups"> - <div class="mat-chip-list-wrap scrolling"> - <mat-chip-list> - <mat-chip *ngFor="let group of element.groups" - [matTooltip]="group" - matTooltipPosition="above" - class="ellipsis" - > - {{ group }} - </mat-chip> - </mat-chip-list> - </div> - </td> - </ng-container> - - <ng-container matColumnDef="endpoints"> - <th mat-header-cell *matHeaderCellDef class="endpoints"> - <span class="label-endpoint"> Endpoint </span> - <span class="label-endpoint-status"> Endpoint status </span> - <span class="label-status">Edge node status </span> - </th> - <td mat-cell *matCellDef="let element" class="source endpoints"> - <div *ngIf="!element.endpoints?.length; else list"> - <span *ngIf="!element.endpoints.length" class="no-details">no details</span> - </div> - <ng-template #list> - <div *ngFor="let endpoint of element.endpoints" class="resource-wrap"> - <div class="resource-name"> - <a class="project-endpoint-name"> - {{ endpoint.name }} - </a> - </div> - <div class="resource-status"> - <span [ngClass]="{'active' : endpoint.endpointStatus === 'ACTIVE', 'failed': endpoint.endpointStatus === 'INACTIVE'}"> - {{ (endpoint.endpointStatus | titlecase) || 'N/A'}} - </span> - </div> - - <span class="status resource-status" - [ngClass]="endpoint?.status.toLowerCase() || ''">{{ endpoint?.status.toLowerCase() }}</span> + <ng-container matColumnDef="groups"> + <th mat-header-cell *matHeaderCellDef class="groups"> Group </th> + <td mat-cell *matCellDef="let element" class="groups"> + <div class="mat-chip-list-wrap scrolling"> + <mat-chip-list> + <mat-chip + *ngFor="let group of element.groups" + [matTooltip]="group" + matTooltipPosition="above" + class="ellipsis" + > + {{ group }} + </mat-chip> + </mat-chip-list> </div> - </ng-template> - </td> - </ng-container> + </td> + </ng-container> - <ng-container matColumnDef="actions"> - <th mat-header-cell *matHeaderCellDef class="project-actions"> - <span class="label"> Actions </span> - </th> - <td mat-cell *matCellDef="let element" class="settings"> - <span #settings (click)="actions.toggle($event, settings)" class="actions"></span> - <bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left"> - <ul class="list-unstyled actions-list"> - <div class="active-items"></div> - <li class="project-seting-item" *ngIf="element.areStoppedNode" (click)="openEdgeDialog('start', element)"> - <i class="material-icons">play_circle_outline</i> - <a class="action"> - Start edge node - </a> - </li> - <li class="project-seting-item" *ngIf="element.areRunningNode" (click)="openEdgeDialog('stop', element )"> - <i class="material-icons">pause_circle_outline</i> - <a class="action" > - Stop edge node - </a> - </li> - <!-- <li class="project-seting-item " *ngIf="element.areTerminatedNode" (click)="openEdgeDialog('recreate', element)"> - <i class="material-icons">refresh</i> - <a class="action"> - Recreate edge node - </a> - </li> --> - <li class="project-seting-item " *ngIf="element.areStoppedNode || element.areRunningNode" (click)="openEdgeDialog('terminate', element)"> - <i class="material-icons">phonelink_off</i> - <a class="action"> - Terminate edge node - </a> - </li> - <li class="project-seting-item" (click)="editProject(element)" *ngIf="!isProjectAdmin"> - <i class="material-icons">mode_edit</i> - <a > - Edit project - </a> - </li> - </ul> - </bubble-up> - </td> - <td class="settings"> + <ng-container matColumnDef="endpoints"> + <th mat-header-cell *matHeaderCellDef class="endpoints"> + <span class="label-endpoint"> Endpoint </span> + <span class="label-endpoint-status"> Endpoint status </span> + <span class="label-status">Edge node status </span> + </th> + <td mat-cell *matCellDef="let element" class="source endpoints"> + <div *ngIf="!element.endpoints?.length; else list"> + <span *ngIf="!element.endpoints.length" class="no-details">no details</span> + </div> + <ng-template #list> + <div *ngFor="let endpoint of element.endpoints" class="resource-wrap"> + <div class="resource-name"> + <a class="project-endpoint-name"> + {{ endpoint.name }} + </a> + </div> + <div class="resource-status"> + <span [ngClass]="{'active' : endpoint.endpointStatus === 'ACTIVE', 'failed': endpoint.endpointStatus === 'INACTIVE'}"> + {{ (endpoint.endpointStatus | titlecase) || 'N/A'}} + </span> + </div> - </td> + <span class="status resource-status" [ngClass]="endpoint?.status.toLowerCase() || ''"> + {{ endpoint?.status.toLowerCase() }} + </span> + </div> + </ng-template> + </td> + </ng-container> - </ng-container> + <ng-container matColumnDef="actions"> + <th mat-header-cell *matHeaderCellDef class="project-actions"> + <span class="label"> Actions </span> + </th> + <td mat-cell *matCellDef="let element" class="settings"> + <span #settings (click)="actions.toggle($event, settings)" class="actions"></span> + <bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left"> + <ul class="list-unstyled actions-list"> + <div class="active-items"></div> + <li class="project-seting-item" *ngIf="element.areStoppedNode" (click)="openEdgeDialog('start', element)"> + <i class="material-icons">play_circle_outline</i> + <a class="action"> + Start edge node + </a> + </li> + <li class="project-seting-item" *ngIf="element.areRunningNode" (click)="openEdgeDialog('stop', element )"> + <i class="material-icons">pause_circle_outline</i> + <a class="action" > + Stop edge node + </a> + </li> + <!-- <li class="project-seting-item " *ngIf="element.areTerminatedNode" (click)="openEdgeDialog('recreate', element)"> + <i class="material-icons">refresh</i> + <a class="action"> + Recreate edge node + </a> + </li> --> + <li class="project-seting-item " *ngIf="element.areStoppedNode || element.areRunningNode" (click)="openEdgeDialog('terminate', element)"> + <i class="material-icons">phonelink_off</i> + <a class="action"> + Terminate edge node + </a> + </li> + <li class="project-seting-item" (click)="editProject(element)" *ngIf="!isProjectAdmin"> + <i class="material-icons">mode_edit</i> + <a > + Edit project + </a> + </li> + </ul> + </bubble-up> + </td> + <td class="settings"></td> + </ng-container> - <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> - <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> -</table> + <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> + <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> + </table> </div> diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.scss index 140feb4..836b822 100644 --- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.scss +++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.scss @@ -17,13 +17,12 @@ * under the License. */ - -.table-wrapper{ - height: calc(100vh - 120px); - overflow: auto; +.table-wrapper { position: relative; - margin: 0 -15px -15px -15px; + margin: 0 -15px -15px -15px; padding: 0 15px 15px 15px; + height: calc(100vh - 120px); + overflow: auto; .mat-header-cell { position: sticky; top: 0; @@ -31,6 +30,7 @@ background: white; } } + table { width: 100%; @@ -41,16 +41,16 @@ table { .name { width: 25%; padding: 20px 0 10px 24px; - &.project-name{ + &.project-name { padding-top: 10px; } } - th.name{ + th.name { padding-top: 10px; } - .mat-header-row{ + .mat-header-row { padding-top: 12px; } @@ -59,13 +59,15 @@ table { padding: 15px 0; .resource-wrap { - .resource-name, .resource-status { + .resource-name, + .resource-status { width: 30%; padding-left: 0; } } - .label-endpoint, .label-endpoint-status { + .label-endpoint, + .label-endpoint-status { display: inline-block; width: 30%; } @@ -75,7 +77,7 @@ table { } &.source { - &.endpoints .resource-wrap{ + &.endpoints .resource-wrap { justify-content: flex-start; } .no-details { @@ -94,19 +96,19 @@ table { } .project-actions { - color: #607d8b; width: 10%; + padding: 10px 24px; + color: #607d8b; text-align: right; vertical-align: top; - padding: 10px 24px; - &.mat-header-cell{ + &.mat-header-cell { padding-top: 19px; - color: rgba(0,0,0,.54); + color: rgba(0, 0, 0, 0.54); } span:not(.mat-header-cell span) { - transition: all .5s ease-in-out; + transition: all 0.5s ease-in-out; cursor: pointer; .mat-icon { @@ -126,47 +128,49 @@ td.settings { vertical-align: middle !important; text-align: right; .actions { - margin-top: 3px; - background-image: url(../../../../assets/svg/settings_icon.svg); + display: inline-block; width: 16px; height: 16px; - display: inline-block; + margin-top: 3px; + background-image: url(../../../../assets/svg/settings_icon.svg); text-align: center; cursor: pointer; } } -.project-seting-item{ + +.project-seting-item { display: flex; - padding: 10px; align-items: center; + padding: 10px; border-bottom: 1px solid #edf1f5; cursor: pointer; color: #577289; - &:last-child{ + &:last-child { border-bottom: none; } - &:hover{ + &:hover { color: #36afd5; - transition: all .45s ease-in-out; + transition: all 0.45s ease-in-out; } - a{ + a { padding-left: 5px; } } + .material-icons { font-size: 18px; padding-top: 1px; } -.list-menu{ +.list-menu { min-width: 205px; } -.project-endpoint-name{ - color: #577289; +.project-endpoint-name { + color: #577289; } -.actions-list{ +.actions-list { padding: 10px 15px; } @@ -174,8 +178,4 @@ td.settings { max-width: 200px !important; white-space: nowrap; display: inline-block; -} - - - - +} \ No newline at end of file diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.ts index 6ee2f2a..41a2127 100644 --- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.ts +++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.ts @@ -17,7 +17,7 @@ * under the License. */ -import {Component, OnInit, Output, EventEmitter, OnDestroy, Inject, Input} from '@angular/core'; +import { Component, OnInit, Output, EventEmitter, OnDestroy, Inject, Input } from '@angular/core'; import { ToastrService } from 'ngx-toastr'; import { MatTableDataSource } from '@angular/material/table'; import { Subscription } from 'rxjs'; @@ -25,11 +25,8 @@ import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material/dial import { ProjectDataService } from '../project-data.service'; import { Project, Endpoint } from '../project.component'; -import { CheckUtils } from '../../../core/util'; import {ProgressBarService} from '../../../core/services/progress-bar.service'; import {EdgeActionDialogComponent} from '../../../shared/modal-dialog/edge-action-dialog'; -import {EndpointService} from '../../../core/services'; - @Component({ selector: 'project-list', @@ -47,16 +44,14 @@ export class ProjectListComponent implements OnInit, OnDestroy { @Output() toggleStatus: EventEmitter<{}> = new EventEmitter(); private subscriptions: Subscription = new Subscription(); - constructor( + constructor ( public toastr: ToastrService, private projectDataService: ProjectDataService, private progressBarService: ProgressBarService, @Inject(MAT_DIALOG_DATA) public data: any, public dialogRef: MatDialogRef<ProjectListComponent>, public dialog: MatDialog, - ) { - } - + ) { } ngOnInit() { this.getProjectList(); @@ -68,23 +63,30 @@ export class ProjectListComponent implements OnInit, OnDestroy { private getProjectList() { this.progressBarService.startProgressBar(); - this.subscriptions.add(this.projectDataService._projects.subscribe((value: Project[]) => { - this.projectList = value; - if (this.projectList) { - this.projectList.forEach(project => { - project.areRunningNode = this.areResoursesInStatuses(project.endpoints, ['RUNNING']); - project.areStoppedNode = this.areResoursesInStatuses(project.endpoints, ['STOPPED']); - project.areTerminatedNode = this.areResoursesInStatuses(project.endpoints, ['TERMINATED', 'FAILED']); - }); - } - if (value) this.dataSource = new MatTableDataSource(value); - this.progressBarService.stopProgressBar(); - }, () => this.progressBarService.stopProgressBar())); + this.subscriptions.add(this.projectDataService._projects + .subscribe( + (value: Project[]) => { + this.projectList = value; + if (this.projectList) { + this.projectList.forEach(project => { + project.areRunningNode = this.areResoursesInStatuses(project.endpoints, ['RUNNING']); + project.areStoppedNode = this.areResoursesInStatuses(project.endpoints, ['STOPPED']); + project.areTerminatedNode = this.areResoursesInStatuses(project.endpoints, ['TERMINATED', 'FAILED']); + }); + } + if (value) this.dataSource = new MatTableDataSource(value); + this.progressBarService.stopProgressBar(); + }, + () => this.progressBarService.stopProgressBar() + ) + ); } public showActiveInstances(): void { const filteredList = this.projectList.map(project => { - project.endpoints = project.endpoints.filter((endpoint: Endpoint) => endpoint.status !== 'TERMINATED' && endpoint.status !== 'TERMINATING' && endpoint.status !== 'FAILED'); + project.endpoints = project.endpoints.filter((endpoint: Endpoint) => { + return endpoint.status !== 'TERMINATED' && endpoint.status !== 'TERMINATING' && endpoint.status !== 'FAILED' + }); return project; }); @@ -96,32 +98,34 @@ export class ProjectListComponent implements OnInit, OnDestroy { } public openEdgeDialog(action, project) { - const endpoints = project.endpoints.filter(endpoint => { - if (action === 'stop') { - return endpoint.status === 'RUNNING'; - } - if (action === 'start') { - return endpoint.status === 'STOPPED'; - } - if (action === 'terminate') { - return endpoint.status === 'RUNNING' || endpoint.status === 'STOPPED'; - } - if (action === 'recreate') { - return endpoint.status === 'TERMINATED' || endpoint.status === 'FAILED'; - } - }); - if (action === 'terminate' && endpoints.length === 1) { - this.toggleStatus.emit({project, endpoint: endpoints, action, oneEdge: true}); - } else { - this.dialog.open(EdgeActionDialogComponent, {data: {type: action, item: endpoints}, panelClass: 'modal-sm'}) - .afterClosed().subscribe(endpoint => { + const endpoints = project.endpoints.filter(endpoint => { + if (action === 'stop') { + return endpoint.status === 'RUNNING'; + } + if (action === 'start') { + return endpoint.status === 'STOPPED'; + } + if (action === 'terminate') { + return endpoint.status === 'RUNNING' || endpoint.status === 'STOPPED'; + } + if (action === 'recreate') { + return endpoint.status === 'TERMINATED' || endpoint.status === 'FAILED'; + } + }); + if (action === 'terminate' && endpoints.length === 1) { + this.toggleStatus.emit({ project, endpoint: endpoints, action, oneEdge: true }); + } else { + this.dialog.open(EdgeActionDialogComponent, { data: { type: action, item: endpoints }, panelClass: 'modal-sm' }) + .afterClosed().subscribe( + endpoint => { if (endpoint && endpoint.length) { this.toggleStatus.emit({project, endpoint, action}); } - }, error => this.toastr.error(error.message || `Endpoint ${action} failed!`, 'Oops!') + }, + error => this.toastr.error(error.message || `Endpoint ${action} failed!`, 'Oops!') ); - } } + } public areResoursesInStatuses(resources, statuses: Array<string>) { return resources.some(resource => statuses.some(status => resource.status === status)); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
