This is an automated email from the ASF dual-hosted git repository. dgnatyshyn pushed a commit to branch DLAB-2006 in repository https://gitbox.apache.org/repos/asf/incubator-dlab.git
commit 3ab0bd761549b5109f7da50bcb352f7fd336b4cd Author: Dmytro_Gnatyshyn <di1...@ukr.net> AuthorDate: Mon Aug 31 17:19:26 2020 +0300 [DLAB-2006]: [Billing][Audit]:Set of grid issues --- .../manage-environment-dilog.component.ts | 2 - .../reporting-grid/reporting-grid.component.html | 489 +++++++++++---------- .../reporting-grid/reporting-grid.component.scss | 15 +- .../reporting-grid/reporting-grid.component.ts | 28 +- .../install-libraries.component.html | 27 +- .../install-libraries.component.scss | 1 + .../install-libraries.component.ts | 23 +- .../webapp/src/assets/styles/_general.scss | 10 +- .../src/main/resources/webapp/src/styles.scss | 5 +- 9 files changed, 331 insertions(+), 269 deletions(-) diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/manage-environment/manage-environment-dilog.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/manage-environment/manage-environment-dilog.component.ts index 0c42312..7f28631 100644 --- a/services/self-service/src/main/resources/webapp/src/app/administration/management/manage-environment/manage-environment-dilog.component.ts +++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/manage-environment/manage-environment-dilog.component.ts @@ -60,8 +60,6 @@ export class ManageEnvironmentComponent implements OnInit { public onFormChange() { this.manageUsersForm.valueChanges.subscribe(value => { this.isFormChanged = JSON.stringify(this.initialFormState) === JSON.stringify(this.manageUsersForm.value); - console.log(JSON.stringify(this.initialFormState)); - console.log(JSON.stringify(this.manageUsersForm.value)); if ((this.getCurrentTotalValue() && this.getCurrentTotalValue() >= this.getCurrentUsersTotal())) { this.manageUsersForm.controls['projects']['controls'].forEach(v => { v.controls['budget'].errors && diff --git a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.html index 4464991..5fc1301 100644 --- a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.html +++ b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.html @@ -16,282 +16,285 @@ ~ specific language governing permissions and limitations ~ under the License. --> +<div class="billing-page-wrapper scrolling" #pageWrapper [ngClass]="{'scroll': reportData?.length < 5}" (scroll)="scrollTable($event)"> + <div class="wrapper" #wrapper> + <section class="table-wrapper" id="scrolling" #tableWrapper (scroll)="scrollTable($event)" [ngClass]="{'scroll': reportData?.length > 4, 'shadow-none': reportData?.length < 5}"> -<div class="wrapper" > -<section class="table-wrapper" id="scrolling" #tableWrapper (scroll)="scrollTable($event)" [ngClass]="{'scroll': reportData?.length > 4}"> + <!-- <div class="navigation-btn">--> + <!-- <div class="left">--> + <!-- <button mat-fab aria-label="Scroll left">--> + <!-- <mat-icon>keyboard_arrow_left</mat-icon>--> + <!-- </button>--> + <!-- </div>--> + <!-- <div class="right">--> + <!-- <button mat-fab aria-label="Scroll right">--> + <!-- <mat-icon>keyboard_arrow_right</mat-icon>--> + <!-- </button>--> + <!-- </div>--> + <!-- </div>--> + <table mat-table [dataSource]="reportData" class="data-grid reporting mat-elevation-z6" #table> -<!-- <div class="navigation-btn">--> -<!-- <div class="left">--> -<!-- <button mat-fab aria-label="Scroll left">--> -<!-- <mat-icon>keyboard_arrow_left</mat-icon>--> -<!-- </button>--> -<!-- </div>--> -<!-- <div class="right">--> -<!-- <button mat-fab aria-label="Scroll right">--> -<!-- <mat-icon>keyboard_arrow_right</mat-icon>--> -<!-- </button>--> -<!-- </div>--> -<!-- </div>--> - <table mat-table [dataSource]="reportData" class="data-grid reporting mat-elevation-z6" #table> - - <ng-container matColumnDef="name"> - <th mat-header-cell *matHeaderCellDef class="env_name label-header"> - <div class="label"><span class="text"> Resource name</span></div> - <button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()"> - <i class="material-icons"> - <span *ngIf="filteredReportData.dlab_id.length > 0; else dlab_id_filtered">filter_list</span> - <ng-template #dlab_id_filtered>more_vert</ng-template> - </i> - </button> - </th> - <td mat-cell *matCellDef="let element"><span class="table-item">{{element.dlabId}}</span></td> - <td mat-footer-cell *matFooterCellDef class="table-footer"></td> - </ng-container> + <ng-container matColumnDef="name"> + <th mat-header-cell *matHeaderCellDef class="env_name label-header"> + <div class="label"><span class="text"> Resource name</span></div> + <button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()"> + <i class="material-icons"> + <span *ngIf="filteredReportData.dlab_id.length > 0; else dlab_id_filtered">filter_list</span> + <ng-template #dlab_id_filtered>more_vert</ng-template> + </i> + </button> + </th> + <td mat-cell *matCellDef="let element"><span class="table-item">{{element.dlabId}}</span></td> + <td mat-footer-cell *matFooterCellDef class="table-footer"></td> + </ng-container> - <ng-container matColumnDef="user"> - <th mat-header-cell *matHeaderCellDef class="th_user label-header"> + <ng-container matColumnDef="user"> + <th mat-header-cell *matHeaderCellDef class="th_user label-header"> - <div class="label"> - <div class="sort sort-user"> - <div class="sort-arrow up" (click)="sortBy('user', 'down')" [ngClass]="{'active': !!this.active['userdown']}"></div> - <div class="sort-arrow down" (click)="sortBy('user', 'up')" [ngClass]="{'active': !!this.active['userup']}"></div> - </div> - <span class="text"> User </span> - </div> + <div class="label"> + <div class="sort sort-user"> + <div class="sort-arrow up" (click)="sortBy('user', 'down')" [ngClass]="{'active': !!this.active['userdown']}"></div> + <div class="sort-arrow down" (click)="sortBy('user', 'up')" [ngClass]="{'active': !!this.active['userup']}"></div> + </div> + <span class="text"> User </span> + </div> - <button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()"> - <i class="material-icons"> - <span *ngIf="filteredReportData.users.length > 0; else user_filtered">filter_list</span> - <ng-template #user_filtered>more_vert</ng-template> - </i> - </button> - </th> - <td mat-cell *matCellDef=" let element"> {{element.user}} </td> - <td mat-footer-cell *matFooterCellDef class="table-footer"></td> - </ng-container> + <button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()"> + <i class="material-icons"> + <span *ngIf="filteredReportData.users.length > 0; else user_filtered">filter_list</span> + <ng-template #user_filtered>more_vert</ng-template> + </i> + </button> + </th> + <td mat-cell *matCellDef=" let element"> {{element.user}} </td> + <td mat-footer-cell *matFooterCellDef class="table-footer"></td> + </ng-container> - <ng-container matColumnDef="project"> - <th mat-header-cell *matHeaderCellDef class="th_project label-header"> + <ng-container matColumnDef="project"> + <th mat-header-cell *matHeaderCellDef class="th_project label-header"> - <div class="label"> - <div class="sort sort-project"> - <div class="sort-arrow up" (click)="sortBy('project', 'down')" [ngClass]="{'active': !!this.active['projectdown']}"></div> - <div class="sort-arrow down" (click)="sortBy('project', 'up')" [ngClass]="{'active': !!this.active['projectup']}"></div> - </div> - <span class="text">Project</span> - </div> + <div class="label"> + <div class="sort sort-project"> + <div class="sort-arrow up" (click)="sortBy('project', 'down')" [ngClass]="{'active': !!this.active['projectdown']}"></div> + <div class="sort-arrow down" (click)="sortBy('project', 'up')" [ngClass]="{'active': !!this.active['projectup']}"></div> + </div> + <span class="text">Project</span> + </div> - <button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()"> - <i class="material-icons"> - <span *ngIf="filteredReportData.projects.length > 0; else project_filtered">filter_list</span> - <ng-template #project_filtered>more_vert</ng-template> - </i> - </button> - </th> - <td mat-cell *matCellDef="let element"> {{element.project}} </td> - <td mat-footer-cell *matFooterCellDef class="table-footer"></td> - </ng-container> + <button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()"> + <i class="material-icons"> + <span *ngIf="filteredReportData.projects.length > 0; else project_filtered">filter_list</span> + <ng-template #project_filtered>more_vert</ng-template> + </i> + </button> + </th> + <td mat-cell *matCellDef="let element"> {{element.project}} </td> + <td mat-footer-cell *matFooterCellDef class="table-footer"></td> + </ng-container> - <ng-container matColumnDef="type"> - <th mat-header-cell *matHeaderCellDef class="th_type label-header"> - <div class="label"><span class="text"> Resource Type</span> </div> - <button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()"> - <i class="material-icons"> - <span *ngIf="filteredReportData.resource_type.length > 0; else type_filtered">filter_list</span> - <ng-template #type_filtered>more_vert</ng-template> - </i> - </button> - </th> - <td mat-cell *matCellDef="let element"> {{element.resource_type | titlecase}} </td> - <td mat-footer-cell *matFooterCellDef class="table-footer"></td> - </ng-container> + <ng-container matColumnDef="type"> + <th mat-header-cell *matHeaderCellDef class="th_type label-header"> + <div class="label"><span class="text"> Resource Type</span> </div> + <button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()"> + <i class="material-icons"> + <span *ngIf="filteredReportData.resource_type.length > 0; else type_filtered">filter_list</span> + <ng-template #type_filtered>more_vert</ng-template> + </i> + </button> + </th> + <td mat-cell *matCellDef="let element"> {{element.resource_type | titlecase}} </td> + <td mat-footer-cell *matFooterCellDef class="table-footer"></td> + </ng-container> - <ng-container matColumnDef="status"> - <th mat-header-cell *matHeaderCellDef class="th_status label-header"> - <div class="label"><span class="text"> Status</span> </div> - <button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()"> - <i class="material-icons"> - <span *ngIf="filteredReportData.statuses.length > 0; else status_filtered">filter_list</span> - <ng-template #status_filtered>more_vert</ng-template> - </i> - </button> - </th> - <td mat-cell *matCellDef="let element"> + <ng-container matColumnDef="status"> + <th mat-header-cell *matHeaderCellDef class="th_status label-header"> + <div class="label"><span class="text"> Status</span> </div> + <button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()"> + <i class="material-icons"> + <span *ngIf="filteredReportData.statuses.length > 0; else status_filtered">filter_list</span> + <ng-template #status_filtered>more_vert</ng-template> + </i> + </button> + </th> + <td mat-cell *matCellDef="let element"> <span class="status" ngClass="{{ element.status.toLowerCase() || '' }}" - *ngIf="element.status">{{ element.status.toLowerCase() }}</span> - <span *ngIf="!element.status">N/A</span> - </td> - <td mat-footer-cell *matFooterCellDef class="table-footer"></td> - </ng-container> + *ngIf="element.status">{{ element.status.toLowerCase() }}</span> + <span *ngIf="!element.status">N/A</span> + </td> + <td mat-footer-cell *matFooterCellDef class="table-footer"></td> + </ng-container> - <ng-container matColumnDef="shape"> - <th mat-header-cell *matHeaderCellDef class="th_shape label-header"> - <div class="label"><span class="text"> Instance size</span></div> - <button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()"> - <i class="material-icons"> + <ng-container matColumnDef="shape"> + <th mat-header-cell *matHeaderCellDef class="th_shape label-header"> + <div class="label"><span class="text"> Instance size</span></div> + <button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()"> + <i class="material-icons"> <span *ngIf="filteredReportData['shapes'].length > 0; else shape_filtered">filter_list</span> - <ng-template #shape_filtered>more_vert</ng-template> - </i> - </button> - </th> - <td mat-cell *matCellDef="let element"> - <ng-container *ngIf="element.shape"> - <div *ngFor="let shape of shapeSplit(element.shape)">{{shape}}</div> + <ng-template #shape_filtered>more_vert</ng-template> + </i> + </button> + </th> + <td mat-cell *matCellDef="let element"> + <ng-container *ngIf="element.shape"> + <div *ngFor="let shape of shapeSplit(element.shape)">{{shape}}</div> + </ng-container> + </td> + <td mat-footer-cell *matFooterCellDef class="table-footer"></td> </ng-container> - </td> - <td mat-footer-cell *matFooterCellDef class="table-footer"></td> - </ng-container> - <ng-container matColumnDef="service"> - <th mat-header-cell *matHeaderCellDef class="service label-header"> - <div class="label"><span class="text"> Product</span> </div> - <button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()"> - <i class="material-icons"> + <ng-container matColumnDef="service"> + <th mat-header-cell *matHeaderCellDef class="service label-header"> + <div class="label"><span class="text"> Product</span> </div> + <button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()"> + <i class="material-icons"> <span - *ngIf="filteredReportData['shapes'].length > 0; else service_filtered">filter_list</span> - <ng-template #service_filtered>more_vert</ng-template> - </i> - </button> - </th> - <td mat-cell *matCellDef="let element"> - {{ element.product }} -<!-- <span *ngIf="element.product">{{ element.product }}</span>--> - </td> - <td mat-footer-cell *matFooterCellDef class="table-footer"></td> - </ng-container> + *ngIf="filteredReportData['products'].length > 0; else service_filtered">filter_list</span> + <ng-template #service_filtered>more_vert</ng-template> + </i> + </button> + </th> + <td mat-cell *matCellDef="let element"> + {{ element.product }} + <!-- <span *ngIf="element.product">{{ element.product }}</span>--> + </td> + <td mat-footer-cell *matFooterCellDef class="table-footer"></td> + </ng-container> - <ng-container matColumnDef="empty"> - <th mat-header-cell *matHeaderCellDef class="th_empty label-header"> - </th> - <td mat-cell *matCellDef="let element"> - </td> - <td mat-footer-cell *matFooterCellDef class="table-footer total-cost" [colSpan]="2"> + <ng-container matColumnDef="empty"> + <th mat-header-cell *matHeaderCellDef class="th_empty label-header"> + </th> + <td mat-cell *matCellDef="let element"> + </td> + <td mat-footer-cell *matFooterCellDef class="table-footer total-cost" [colSpan]="2" [ngClass]="{'right-sticky': reportData?.length < 5}"> <span class="strong"> Total <span *ngIf="reportData?.length"> {{ fullReport['total_cost'] }} {{ fullReport['currency'] }}</span> </span> - </td> - </ng-container> + </td> + </ng-container> - <ng-container matColumnDef="charge" stickyEnd> - <th mat-header-cell *matHeaderCellDef class="th_charges label-header"> - <div class="label"> - <div class="sort"> - <div class="sort-arrow up" (click)="sortBy('cost', 'down')" [ngClass]="{'active': !!this.active['costdown']}"></div> - <div class="sort-arrow down" (click)="sortBy('cost', 'up')" [ngClass]="{'active': !!this.active['costup']}"></div> - </div> - <span class="text">Service Charges</span> - </div> - </th> + <ng-container matColumnDef="charge" stickyEnd> + <th mat-header-cell *matHeaderCellDef class="th_charges label-header" [ngClass]="{'right-sticky': reportData?.length < 5}"> + <div class="label"> + <div class="sort"> + <div class="sort-arrow up" (click)="sortBy('cost', 'down')" [ngClass]="{'active': !!this.active['costdown']}"></div> + <div class="sort-arrow down" (click)="sortBy('cost', 'up')" [ngClass]="{'active': !!this.active['costup']}"></div> + </div> + <span class="text">Service Charges</span> + </div> + </th> - <td mat-cell *matCellDef="let element"> - {{ element.cost }} {{ element['currency'] }} - </td> - <td mat-footer-cell *matFooterCellDef class="table-footer total-cost d-none"> - </td> - </ng-container> + <td mat-cell *matCellDef="let element" [ngClass]="{'right-sticky': reportData?.length < 5}" > + {{ element.cost }} {{ element['currency'] }} + </td > + <td mat-footer-cell *matFooterCellDef class="table-footer total-cost d-none"> + </td> + </ng-container> - <!-- ----------------FILTER --> - <ng-container matColumnDef="name-filter"> - <th mat-header-cell *matHeaderCellDef class="filter-row-item"> - <div class="input-wrapper"> - <input #nameFilter type="text" placeholder="Filter by environment name" class="form-control filter-field" - [value]="filtered?.dlab_id" (input)="filteredReportData.dlab_id = $event.target['value']" /> - </div> - </th> - </ng-container> - <ng-container matColumnDef="user-filter"> - <th mat-header-cell *matHeaderCellDef class="filter-row-item"> - <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)" [type]="'users'" - [items]="filterConfiguration.users" [model]="filteredReportData.users"></multi-select-dropdown> - </th> - </ng-container> - <ng-container matColumnDef="project-filter"> - <th mat-header-cell *matHeaderCellDef class="filter-row-item"> - <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)" [type]="'projects'" - [items]="filterConfiguration.projects" [model]="filteredReportData.projects"></multi-select-dropdown> - </th> - </ng-container> - <ng-container matColumnDef="type-filter"> - <th mat-header-cell *matHeaderCellDef class="filter-row-item"> - <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)" [type]="'resource_type'" - [items]="filterConfiguration.resource_type" [model]="filteredReportData.resource_type"> - </multi-select-dropdown> - </th> - </ng-container> - <ng-container matColumnDef="status-filter"> - <th mat-header-cell *matHeaderCellDef class="filter-row-item"> - <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)" [type]="'statuses'" - [items]="filterConfiguration.statuses" [model]="filteredReportData.statuses"></multi-select-dropdown> - </th> - </ng-container> - <ng-container matColumnDef="shape-filter"> - <th mat-header-cell *matHeaderCellDef class="filter-row-item"> - <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)" - [type]="'shapes'" [items]="filterConfiguration['shapes']" - [model]="filteredReportData['shapes']"></multi-select-dropdown> - </th> - </ng-container> + <!-- ----------------FILTER --> + <ng-container matColumnDef="name-filter"> + <th mat-header-cell *matHeaderCellDef class="filter-row-item"> + <div class="input-wrapper"> + <input #nameFilter type="text" placeholder="Filter by environment name" class="form-control filter-field" + [value]="filtered?.dlab_id" (input)="filteredReportData.dlab_id = $event.target['value']" /> + </div> + </th> + </ng-container> + <ng-container matColumnDef="user-filter"> + <th mat-header-cell *matHeaderCellDef class="filter-row-item"> + <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)" [type]="'users'" + [items]="filterConfiguration.users" [model]="filteredReportData.users"></multi-select-dropdown> + </th> + </ng-container> + <ng-container matColumnDef="project-filter"> + <th mat-header-cell *matHeaderCellDef class="filter-row-item"> + <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)" [type]="'projects'" + [items]="filterConfiguration.projects" [model]="filteredReportData.projects"></multi-select-dropdown> + </th> + </ng-container> + <ng-container matColumnDef="type-filter"> + <th mat-header-cell *matHeaderCellDef class="filter-row-item"> + <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)" [type]="'resource_type'" + [items]="filterConfiguration.resource_type" [model]="filteredReportData.resource_type"> + </multi-select-dropdown> + </th> + </ng-container> + <ng-container matColumnDef="status-filter"> + <th mat-header-cell *matHeaderCellDef class="filter-row-item"> + <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)" [type]="'statuses'" + [items]="filterConfiguration.statuses" [model]="filteredReportData.statuses"></multi-select-dropdown> + </th> + </ng-container> + <ng-container matColumnDef="shape-filter"> + <th mat-header-cell *matHeaderCellDef class="filter-row-item"> + <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)" + [type]="'shapes'" [items]="filterConfiguration['shapes']" + [model]="filteredReportData['shapes']"></multi-select-dropdown> + </th> + </ng-container> - <ng-container matColumnDef="empty-filter"> - <th mat-header-cell *matHeaderCellDef class="filter-row-item"> - </th> - </ng-container> + <ng-container matColumnDef="empty-filter"> + <th mat-header-cell *matHeaderCellDef class="filter-row-item"> + </th> + </ng-container> - <ng-container matColumnDef="service-filter"> - <th mat-header-cell *matHeaderCellDef class="filter-row-item"> - <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)" - [type]="['products']" - [items]="filterConfiguration['products']" - [model]="filteredReportData['products']"></multi-select-dropdown> - </th> - </ng-container> - <ng-container matColumnDef="actions" stickyEnd> - <th mat-header-cell *matHeaderCellDef class="filter-row-item"> - <div class="actions"> - <button mat-icon-button class="btn reset" (click)="resetFiltering(); isFiltered = !isFiltered"> - <i class="material-icons">close</i> - </button> + <ng-container matColumnDef="service-filter"> + <th mat-header-cell *matHeaderCellDef class="filter-row-item"> + <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)" + [type]="['products']" + [items]="filterConfiguration['products']" + [model]="filteredReportData['products']"></multi-select-dropdown> + </th> + </ng-container> + <ng-container matColumnDef="actions" stickyEnd> + <th mat-header-cell *matHeaderCellDef class="filter-row-item" [ngClass]="{'right-sticky': reportData?.length < 5}"> + <div class="actions"> + <button mat-icon-button class="btn reset" (click)="resetFiltering(); isFiltered = !isFiltered"> + <i class="material-icons">close</i> + </button> - <button mat-icon-button class="btn apply" (click)="filter_btnClick()" [disabled]="isFilterChanged()"> - <i class="material-icons">done</i> - </button> - </div> - </th> - </ng-container> - <ng-container matColumnDef="placeholder"> - <td mat-footer-cell *matFooterCellDef colspan="9" class="info"> - <span>No data available</span> - </td> - </ng-container> + <button mat-icon-button class="btn apply" (click)="filter_btnClick()" [disabled]="isFilterChanged()"> + <i class="material-icons">done</i> + </button> + </div> + </th> + </ng-container> + <ng-container matColumnDef="placeholder"> + <td mat-footer-cell *matFooterCellDef colspan="9" class="info"> + <span>No data available</span> + </td> + </ng-container> - <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true" class="header-row"></tr> + <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true" class="header-row"></tr> - <tr [hidden]="!collapseFilterRow" mat-header-row *matHeaderRowDef="displayedFilterColumns; sticky: true" - class="filter-row"></tr> - <tr mat-row *matRowDef="let row; columns: displayedColumns;" class="content-row"></tr> + <tr [hidden]="!collapseFilterRow" mat-header-row *matHeaderRowDef="displayedFilterColumns; sticky: true" + class="filter-row"></tr> + <tr mat-row *matRowDef="let row; columns: displayedColumns;" class="content-row"></tr> - <tr [hidden]="!reportData?.length" mat-footer-row *matFooterRowDef="displayedColumns; sticky: true" - class="header-row"></tr> - <tr [hidden]="reportData?.length" mat-footer-row *matFooterRowDef="['placeholder']"></tr> - </table> -</section> - <div class="buttons" *ngIf="tableWrapper.offsetWidth - tableEl['offsetWidth'] < 0 && reportData?.length"> - <div class="button-container"> - <button mat-mini-fab aria-label="Scroll left" (click)="sctollTo('left')" [ngClass]="{'not-allowed': tableWrapper.scrollLeft === 0 }"> - <mat-icon [ngClass]="{'highlight': tableWrapper.scrollLeft !== 0}">keyboard_arrow_left</mat-icon> - </button> - </div> - <div class="button-container"> - <button mat-mini-fab aria-label="Scroll right" - (click)="sctollTo('right')" - [ngClass]="{'not-allowed': !isMaxRight }" - > - <mat-icon [ngClass]="{'highlight': checkMaxRight() }">keyboard_arrow_right</mat-icon> - </button> + <tr [hidden]="!reportData?.length" mat-footer-row *matFooterRowDef="displayedColumns; sticky: true" + class="header-row"></tr> + <tr [hidden]="reportData?.length" mat-footer-row *matFooterRowDef="['placeholder']"></tr> + </table> + </section> + <div class="buttons" *ngIf="tableWrapper.offsetWidth - tableEl['offsetWidth'] < 0 && reportData?.length"> + <div class="button-container"> + <button mat-mini-fab aria-label="Scroll left" (click)="sctollTo('left')" [ngClass]="{'not-allowed': tableWrapper.scrollLeft === 0 && reportData?.length > 4 || pageWrapper.scrollLeft === 0 && reportData?.length < 5}"> + <mat-icon [ngClass]="{'highlight': tableWrapper.scrollLeft !== 0 || pageWrapper.scrollLeft !== 0 && reportData?.length < 5}">keyboard_arrow_left</mat-icon> + </button> + </div> + <div class="button-container"> + <button mat-mini-fab aria-label="Scroll right" + (click)="sctollTo('right')" + [ngClass]="{'not-allowed': !(isMaxRight | async)}" + > + <mat-icon [ngClass]="{'highlight': isMaxRight | async }">keyboard_arrow_right</mat-icon> + </button> + </div> </div> </div> + + </div> diff --git a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.scss b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.scss index 9f60383..c6a5961 100644 --- a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.scss +++ b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.scss @@ -16,6 +16,18 @@ * specific language governing permissions and limitations * under the License. */ +.billing-page-wrapper{ + height: calc(100vh - 130px); + scroll-behavior: smooth; + margin-left: -15px; + padding-left: 15px; + margin-right: -15px; + padding-right: 15px; + &.scroll{ + overflow: auto; + } +} + .table-wrapper { width: 100%; @@ -193,6 +205,7 @@ .table-footer.mat-column-charge{ text-align: right; background-color: #f8f8f8; + z-index: 100 !important; } .header-row { @@ -304,7 +317,7 @@ padding-right: 25px; position: sticky; right: 0; - z-index: 17; + z-index: 101; } } diff --git a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.ts index 25c7c7c..67ceeb7 100644 --- a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.ts +++ b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.ts @@ -30,8 +30,9 @@ import { ChangeDetectionStrategy } from '@angular/core'; import { ReportingConfigModel } from '../../../../dictionary/global.dictionary'; -import {fromEvent, of} from 'rxjs'; +import {BehaviorSubject, fromEvent, Observable, of, Subject, timer} from 'rxjs'; import {logger} from 'codelyzer/util/logger'; +import {take} from 'rxjs/operators'; @Component({ selector: 'dlab-reporting-grid', @@ -54,6 +55,8 @@ export class ReportingGridComponent implements OnInit, AfterViewInit { @ViewChild('nameFilter', { static: false }) filter; @ViewChild('tableWrapper', { static: false }) tableWrapper; + @ViewChild('wrapper', { static: false }) wrapper; + @ViewChild('pageWrapper', { static: false }) pageWrapper; @ViewChild('table', { static: false }) table; @Output() filterReport: EventEmitter<{}> = new EventEmitter(); @@ -64,11 +67,11 @@ export class ReportingGridComponent implements OnInit, AfterViewInit { @HostListener('window:resize', ['$event']) onResize(event) { this.isScrollButtonsVisible = this.tableWrapper.nativeElement.offsetWidth - this.table._elementRef.nativeElement.offsetWidth < 0; - this.isMaxRight = this.checkMaxRight(); + this.checkMaxRight(); } @HostListener('scroll', ['$event']) scrollTable($event: Event) { - this.isMaxRight = this.checkMaxRight(); + this.checkMaxRight(); } @@ -76,7 +79,7 @@ export class ReportingGridComponent implements OnInit, AfterViewInit { displayedColumns: string[] = ['name', 'user', 'project', 'type', 'status', 'shape', 'service', 'empty', 'charge']; displayedFilterColumns: string[] = ['name-filter', 'user-filter', 'project-filter', 'type-filter', 'status-filter', 'shape-filter', 'service-filter', 'empty-filter', 'actions']; filtered: any; - isMaxRight: boolean; + isMaxRight: Subject<boolean> = new BehaviorSubject(false); constructor(private changeDetector: ChangeDetectorRef) { } @@ -84,7 +87,7 @@ export class ReportingGridComponent implements OnInit, AfterViewInit { ngOnInit() { window.setTimeout(() => { this.isScrollButtonsVisible = this.tableWrapper.nativeElement.offsetWidth - this.table._elementRef.nativeElement.offsetWidth < 0; - this.isMaxRight = this.checkMaxRight(); + this.checkMaxRight(); this.tableEl = this.table._elementRef.nativeElement; }, 1000); } @@ -165,14 +168,25 @@ export class ReportingGridComponent implements OnInit, AfterViewInit { public sctollTo(direction: string) { if (direction === 'left') { this.tableWrapper.nativeElement.scrollLeft = 0; + this.pageWrapper.nativeElement.scrollLeft = 0; } else { this.tableWrapper.nativeElement.scrollLeft = this.tableWrapper.nativeElement.offsetWidth; + this.pageWrapper.nativeElement.scrollLeft = this.pageWrapper.nativeElement.offsetWidth; } } private checkMaxRight() { - return this.isMaxRight = this.tableWrapper.nativeElement.offsetWidth + - this.tableWrapper.nativeElement.scrollLeft + 2 <= this.table._elementRef.nativeElement.offsetWidth; + console.log('work'); + if (this.reportData && this.reportData.length < 5) { + const arg = this.pageWrapper.nativeElement.offsetWidth - 15 + + this.pageWrapper.nativeElement.scrollLeft + 2 <= this.table._elementRef.nativeElement.offsetWidth; + return this.isMaxRight.next(arg); + } else { + const arg = this.tableWrapper.nativeElement.offsetWidth + + this.tableWrapper.nativeElement.scrollLeft + 2 <= this.table._elementRef.nativeElement.offsetWidth; + return this.isMaxRight.next(arg); + } + } public isFilterChanged() { diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.html index 5e2fa7c..c54f165 100644 --- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.html +++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.html @@ -31,7 +31,7 @@ <div *ngIf="notebook?.status === 'running'" class="top-wrapper"> <div class="loading-block" *ngIf="!libs_uploaded && uploading && data.status === 'running'"> <div class="uploading"> - <p>Please wait until DLab loads full list of available libraries for you...</p> + <p>Please wait until DLab loads list of available groups for your resource...</p> <img src="assets/img/gif-spinner.gif" alt="loading"> </div> </div> @@ -86,15 +86,18 @@ </div> </mat-option> </ng-template> - <mat-option *ngIf="model.isEmpty(filteredList) && !validity_format && isAutoComplete"> + <mat-option *ngIf="model.isEmpty(filteredList) && !validity_format && autoComplete === 'ENABLED'"> <span class="configuring">No matches found</span> </mat-option> - <mat-option *ngIf="validity_format?.length > 0 && isAutoComplete"> + <mat-option *ngIf="validity_format?.length > 0 && autoComplete === 'ENABLED'"> <span class="configuring" >{{ validity_format }}</span > </mat-option> - <mat-option *ngIf="!isAutoComplete && lib.name?.length > 1"> + <mat-option *ngIf="autoComplete === 'NONE' && lib.name?.length > 1"> <span class="configuring" >Autocomplete is currently unavailable for {{groupsListMap[group]}} group</span > </mat-option> + <mat-option *ngIf="autoComplete === 'UPDATING' && lib.name?.length > 1"> + <span class="configuring" >Autocomplete is currently loading for {{groupsListMap[group]}} group</span > + </mat-option> </mat-autocomplete> </div> <div class="control-group control-select"> @@ -109,12 +112,22 @@ (keyup)="validateVersion(lib.version)" (keydown.enter)="addLibrary(lib)" > - <span class="error-message version-error" *ngIf="isVersionInvalid">Library version can only contain Latin letters, numbers and special characters -, _, :, /, ~, ., +.</span> + <span + class="error-message version-error" + *ngIf="isVersionInvalid"> + Library version can only contain Latin letters, numbers and special characters -, _, :, /, ~, ., +. + </span> <span class="plus-icon" - [ngClass]="{'not-allow': lib.name?.length < 2 || (isAutoComplete && !isLibSelected ) || this.selectedLib?.isInSelectedList || isVersionInvalid}" + [ngClass]="{'not-allow': lib.name?.length < 2 + || (autoComplete === 'ENABLED' && !isLibSelected ) + || this.selectedLib?.isInSelectedList || isVersionInvalid || autoComplete === 'UPDATING'}" + matTooltip="Library is in selected list" matTooltipPosition="above" [matTooltipDisabled]="!this.selectedLib?.isInSelectedList" > - <mat-icon (click)="addLibrary(lib)" [ngClass]="{'not-allowed': lib.name?.length < 2 || (isAutoComplete && !isLibSelected) || this.selectedLib?.isInSelectedList || isVersionInvalid}">add</mat-icon> + <mat-icon + (click)="addLibrary(lib)" + [ngClass]="{'not-allowed': lib.name?.length < 2 || (autoComplete === 'ENABLED' && !isLibSelected) + || this.selectedLib?.isInSelectedList || isVersionInvalid || autoComplete === 'UPDATING'}">add</mat-icon> </span> </div> </div> diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.scss index 50ba25f..53c453b 100644 --- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.scss +++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.scss @@ -48,6 +48,7 @@ justify-content: center; .uploading { + padding-top: 200px; flex-direction: column; align-items: center; align-self: center; diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.ts index 668bfab..28afa05 100644 --- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.ts +++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.ts @@ -28,7 +28,7 @@ import { InstallLibrariesModel } from './install-libraries.model'; import { LibrariesInstallationService } from '../../../core/services'; import {SortUtils, HTTP_STATUS_CODES, PATTERNS} from '../../../core/util'; import {FilterLibsModel} from './filter-libs.model'; -import {Subject} from 'rxjs'; +import {Subject, timer} from 'rxjs'; interface Library { name: string; @@ -36,7 +36,7 @@ interface Library { } interface GetLibrary { - autoComplete: boolean; + autoComplete: string; libraries: Library[]; } @@ -78,7 +78,7 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { public filterConfiguration: FilterLibsModel = new FilterLibsModel('', [], [], [], []); public filterModel: FilterLibsModel = new FilterLibsModel('', [], [], [], []); public filtered: boolean; - public isAutoComplete: boolean; + public autoComplete: string; public filtredNotebookLibs: Array<any> = []; @ViewChild('groupSelect', { static: false }) group_select; @ViewChild('resourceSelect', { static: false }) resource_select; @@ -123,7 +123,8 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { uploadLibGroups(): void { this.libs_uploaded = false; this.uploading = true; - this.librariesInstallationService.getGroupsList(this.notebook.project, this.notebook.name, this.model.computational_name) + + setTimeout(() => this.librariesInstallationService.getGroupsList(this.notebook.project, this.notebook.name, this.model.computational_name) .pipe( takeUntil(this.unsubscribe$), ) @@ -139,7 +140,8 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { this.group_select && this.group_select.setDefaultOptions( this.groupsList, 'Select group', 'group_lib', null, 'list', this.groupsListMap); }, - error => this.toastr.error(error.message || 'Groups list loading failed!', 'Oops!')); + error => this.toastr.error(error.message || 'Groups list loading failed!', 'Oops!')), 1000); + } private getResourcesList() { @@ -211,7 +213,7 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { return lib.name.toLowerCase() === item.name.substring(0, item.name.lastIndexOf(':')).toLowerCase(); }); } - } else if ( !this.isAutoComplete ) { + } else if ( !this.autoComplete ) { this.selectedLib = { name: this.lib.name, version: this.lib.version, @@ -408,7 +410,14 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { takeUntil(this.unsubscribe$) ) .subscribe((libs: GetLibrary) => { - this.isAutoComplete = libs.autoComplete; + if (libs.autoComplete === 'UPDATING') { + timer(500000).pipe( + take(1) + ).subscribe(_ => { + this.getMatchedLibs(); + }); + } + this.autoComplete = libs.autoComplete; this.filteredList = libs.libraries; this.filteredList.forEach(lib => { lib.isInSelectedList = this.model.selectedLibs.some(el => el.name.toLowerCase() === lib.name.toLowerCase()); diff --git a/services/self-service/src/main/resources/webapp/src/assets/styles/_general.scss b/services/self-service/src/main/resources/webapp/src/assets/styles/_general.scss index 9b305f0..875b874 100644 --- a/services/self-service/src/main/resources/webapp/src/assets/styles/_general.scss +++ b/services/self-service/src/main/resources/webapp/src/assets/styles/_general.scss @@ -186,7 +186,7 @@ input[type=file]::-webkit-file-upload-button { position: absolute; display: flex; justify-content: space-around; - z-index: 1000; + z-index: 10; bottom: 9px; left: 0; right: 0; @@ -206,4 +206,12 @@ input[type=file]::-webkit-file-upload-button { } } +.shadow-none{ + box-shadow: none !important; +} + +.right-sticky{ + right: -15px !important; +} + diff --git a/services/self-service/src/main/resources/webapp/src/styles.scss b/services/self-service/src/main/resources/webapp/src/styles.scss index 31f512e..bd79768 100644 --- a/services/self-service/src/main/resources/webapp/src/styles.scss +++ b/services/self-service/src/main/resources/webapp/src/styles.scss @@ -378,17 +378,19 @@ input[type='number'] { text-align: center; } } -#scrolling{ +#scrolling, .scrolling{ scrollbar-width: thin; } #scrolling::-webkit-scrollbar, +.scrolling::-webkit-scrollbar, .list-selected mat-chip-list .mat-chip-list-wrapper::-webkit-scrollbar { width: 5px; height: 5px; } #scrolling::-webkit-scrollbar-track, +.scrolling::-webkit-scrollbar-track, .list-selected mat-chip-list .mat-chip-list-wrapper::-webkit-scrollbar-track { box-shadow: none; -webkit-box-shadow: none; @@ -396,6 +398,7 @@ input[type='number'] { } #scrolling::-webkit-scrollbar-thumb, +.scrolling::-webkit-scrollbar-thumb, .list-selected mat-chip-list .mat-chip-list-wrapper::-webkit-scrollbar-thumb { background-color: #f6fafe; background-color: rgba(0, 0, 0, 0.4); --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@dlab.apache.org For additional commands, e-mail: commits-h...@dlab.apache.org