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

chenyulin0719 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/yunikorn-web.git


The following commit(s) were added to refs/heads/master by this push:
     new f5df16e  [YUNIKORN-2605] Redesigned allocations display (#192)
f5df16e is described below

commit f5df16ee4a937051232571916971e675211203a4
Author: Denis Coric <[email protected]>
AuthorDate: Sat Jun 8 05:56:52 2024 +0000

    [YUNIKORN-2605] Redesigned allocations display (#192)
    
    Moved allocations in application page to the sidebar drawer.
    
    Closes: #192
    
    Signed-off-by: Yu-Lin Chen <[email protected]>
---
 .../components/apps-view/apps-view.component.html  | 128 +++++++++++++--------
 .../components/apps-view/apps-view.component.scss  |  77 +++++++++++++
 .../components/apps-view/apps-view.component.ts    |  31 +++--
 src/app/models/column-def.model.ts                 |   1 +
 src/app/utils/common.util.ts                       |  22 ++--
 5 files changed, 190 insertions(+), 69 deletions(-)

diff --git a/src/app/components/apps-view/apps-view.component.html 
b/src/app/components/apps-view/apps-view.component.html
index 8cf5896..fb80eda 100644
--- a/src/app/components/apps-view/apps-view.component.html
+++ b/src/app/components/apps-view/apps-view.component.html
@@ -43,7 +43,7 @@
     <mat-form-field class="search-wrapper white-mat-form-field">
       <input matInput type="text" [(ngModel)]="searchText" placeholder="Search 
By Application ID" #searchInput />
       <button class="clear-btn" *ngIf="searchText" (click)="onClearSearch()" 
matTooltip="Clear Search"
-        matTooltipShowDelay="500">
+              matTooltipShowDelay="500">
         <i class="far fa-times-circle"></i>
       </button>
       <i *ngIf="!searchText" class="fas fa-search search-icon"></i>
@@ -78,10 +78,10 @@
                   <ul class="mat-res-ul">
                     <ng-container *ngFor="let resource of 
formatResources(colValue); let i = index">
                       <li class="mat-res-li" *ngIf="i<2">
-                        {{resource}}
+                        {{ resource }}
                       </li>
                       <li class="mat-res-li" *ngIf="i>=2 && detailToggle">
-                        {{resource}}
+                        {{ resource }}
                       </li>
                     </ng-container>
                   </ul>
@@ -126,69 +126,95 @@
       <mat-header-row *matHeaderRowDef="appColumnIds"></mat-header-row>
 
       <mat-row *matRowDef="let row; columns: appColumnIds" 
[class.selected-row]="selectedRow === row"
-        (click)="toggleRowSelection(row)"></mat-row>
+               (click)="toggleRowSelection(row)"></mat-row>
 
       <mat-footer-row *matFooterRowDef="['noRecord']"
-        [ngStyle]="{ display: isAppDataSourceEmpty() ? '' : 'none' 
}"></mat-footer-row>
+                      [ngStyle]="{ display: isAppDataSourceEmpty() ? '' : 
'none' }"></mat-footer-row>
     </mat-table>
 
     <mat-paginator #appsViewMatPaginator [pageSizeOptions]="[10, 20, 50, 100]"
-      [ngStyle]="{ display: isAppDataSourceEmpty() ? 'none' : '' }" 
(page)="onPaginatorChanged()"
-      showFirstLastButtons></mat-paginator>
+                   [ngStyle]="{ display: isAppDataSourceEmpty() ? 'none' : '' 
}" (page)="onPaginatorChanged()"
+                   showFirstLastButtons></mat-paginator>
   </div>
 
-  <div class="app-allocations" [ngStyle]="{ display: selectedRow ? '' : 'none' 
}">
-    <h3>Allocations</h3>
-    <mat-divider></mat-divider>
-
-    <div class="mat-elevation-z8">
-      <mat-table [dataSource]="allocDataSource" matSort #allocSort="matSort">
-        <ng-container [matColumnDef]="columnDef.colId" *ngFor="let columnDef 
of allocColumnDef">
-          <mat-header-cell *matHeaderCellDef mat-sort-header>{{ 
columnDef.colName }}</mat-header-cell>
+  <mat-drawer-container
+    class="flex-primary"
+    [hasBackdrop]="false"
+  >
+    <mat-drawer #matDrawer mode="over" position="end">
+      <mat-drawer-content>
+        <div class="header">
+          <span>{{ selectedRow?.applicationId }} ({{ 
selectedRow?.allocations?.length }} allocations)</span>
+          <span class="far fa-solid fa-xmark close-btn" 
(click)="closeDrawer()"></span>
+        </div>
+        <div class="content">
+
+          <mat-table [dataSource]="allocDataSource" matSort 
#allocSort="matSort">
+            <ng-container [matColumnDef]="columnDef.colId" *ngFor="let 
columnDef of allocColumnDef">
+              <mat-header-cell *matHeaderCellDef mat-sort-header 
[style.flex]="columnDef?.colWidth || 1">{{ columnDef.colName 
}}</mat-header-cell>
+
+              <ng-container *ngIf="columnDef.colId === 'priority'; else 
renderNext_3" >
+                <mat-cell class="small" *matCellDef="let element"
+                          [style.flex]="columnDef?.colWidth || 1"
+                          [style.min-height]="allocationsToggle ? '96px' : 
'unset'"
+                          [title]="element[columnDef.colId]"
+                >{{ element['priority'] }}  </mat-cell>
+              </ng-container>
 
-          <ng-container *ngIf="columnDef.colId === 'resource'; else 
renderNext_3">
-            <mat-cell *matCellDef="let element">
-              <ng-container *ngIf="columnDef.colFormatter; else 
showAllocRowData;">
-                <ng-container 
*ngIf="columnDef.colFormatter(element[columnDef.colId]) as colValue">
-                  <ul class="mat-res-ul">
-                    <ng-container *ngFor="let resource of 
formatResources(colValue); let i = index">
-                      <li class="mat-res-li" *ngIf="i<2">
-                        {{resource}}
-                      </li>
-                      <li class="mat-res-li" *ngIf="i>=2 && detailToggle">
-                        {{resource}}
-                      </li>
+              <ng-container *ngIf="columnDef.colId === 'resource'; else 
renderNext_3">
+                <mat-cell *matCellDef="let element" class="allocations-data" 
[style.flex]="columnDef?.colWidth || 1" >
+                  <ng-container *ngIf="columnDef.colFormatter; else 
showAllocRowData;">
+                    <ng-container 
*ngIf="columnDef.colFormatter(element[columnDef.colId]) as colValue">
+                      <ul class="mat-res-ul">
+                        <ng-container *ngFor="let resource of 
formatResources(colValue); let i = index">
+                          <li class="mat-res-li" *ngIf="i<1">
+                            {{ resource }}
+                          </li>
+                          <li class="mat-res-li" *ngIf="i>=1 && 
allocationsToggle">
+                            {{ resource }}
+                          </li>
+                        </ng-container>
+                      </ul>
                     </ng-container>
-                  </ul>
-                </ng-container>
+                  </ng-container>
+                  <ng-template #showAllocRowData>
+                    <span>{{ element[columnDef.colId] }}</span>
+                  </ng-template>
+                </mat-cell>
               </ng-container>
-              <ng-template #showAllocRowData>
-                <span>{{ element[columnDef.colId] }}</span>
+
+              <ng-template #renderNext_3>
+                <mat-cell *matCellDef="let element"
+                          [class]="allocationsToggle ? '' : 'ellipsis'"
+                          [style.flex]="columnDef?.colWidth || 1"
+                          [style.min-height]="allocationsToggle ? '96px' : 
'unset'"
+                          [title]="element[columnDef.colId]"
+                >{{ element[columnDef.colId] || 'n/a' }}</mat-cell>
               </ng-template>
-            </mat-cell>
-          </ng-container>
+            </ng-container>
 
-          <ng-template #renderNext_3>
-            <mat-cell *matCellDef="let element">{{ element[columnDef.colId] || 
'n/a' }}</mat-cell>
-          </ng-template>
-        </ng-container>
+            <ng-container matColumnDef="noRecord">
+              <mat-footer-cell *matFooterCellDef>
+                <div class="no-record">No records found</div>
+              </mat-footer-cell>
+            </ng-container>
 
-        <ng-container matColumnDef="noRecord">
-          <mat-footer-cell *matFooterCellDef>
-            <div class="no-record">No records found</div>
-          </mat-footer-cell>
-        </ng-container>
+            <mat-header-row *matHeaderRowDef="allocColumnIds"></mat-header-row>
 
-        <mat-header-row *matHeaderRowDef="allocColumnIds"></mat-header-row>
+            <mat-row *matRowDef="let row; columns: allocColumnIds; let i = 
index" (click)="allocationsDetailToggle()"
+                     [ngClass]="{'even-row': i % 2 === 0, 'row': true}"
+            ></mat-row>
 
-        <mat-row *matRowDef="let row; columns: allocColumnIds"></mat-row>
+            <mat-footer-row *matFooterRowDef="['noRecord']"
+                            [ngStyle]="{ display: isAllocDataSourceEmpty() ? 
'' : 'none' }"></mat-footer-row>
+          </mat-table>
 
-        <mat-footer-row *matFooterRowDef="['noRecord']"
-          [ngStyle]="{ display: isAllocDataSourceEmpty() ? '' : 'none' 
}"></mat-footer-row>
-      </mat-table>
+          <mat-paginator #allocationMatPaginator [pageSizeOptions]="[10, 20, 
50, 100]"
+                         [ngStyle]="{ display: isAllocDataSourceEmpty() ? 
'none' : '' }"
+                         showFirstLastButtons></mat-paginator>
 
-      <mat-paginator #allocationMatPaginator [pageSizeOptions]="[10, 20, 50, 
100]"
-        [ngStyle]="{ display: isAllocDataSourceEmpty() ? 'none' : '' }" 
showFirstLastButtons></mat-paginator>
-    </div>
-  </div>
+        </div>
+      </mat-drawer-content>
+    </mat-drawer>
+  </mat-drawer-container>
 </div>
diff --git a/src/app/components/apps-view/apps-view.component.scss 
b/src/app/components/apps-view/apps-view.component.scss
index 8a8aa88..b2d4622 100644
--- a/src/app/components/apps-view/apps-view.component.scss
+++ b/src/app/components/apps-view/apps-view.component.scss
@@ -162,3 +162,80 @@
     text-align: center;
   }
 }
+
+
+.mat-drawer-container {
+  min-width: 430px;
+  width: 55%;
+  height: calc(100vh - 60px);
+  background: transparent;
+  pointer-events: none;
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  .mat-drawer {
+    pointer-events: auto;
+    width: 100%;
+    .content {
+      padding: 0 10px;
+    }
+  }
+  .close-btn {
+    float: right;
+    font-size: 1.2em;
+    cursor: pointer;
+    padding-right: 5px;
+    &:hover {
+      color: #f44336;
+    }
+  }
+  .header {
+    margin: 20px;
+    font-weight: 100;
+    font-size: 1em;
+  }
+  .content {
+    border-top: 1px solid #e1e1e1;
+  }
+  .item-wrapper {
+    .left-item {
+      text-align: right;
+    }
+    .left-item,
+    .right-item {
+      width: 50%;
+      padding: 6px;
+      padding-right: 0;
+      color: #666;
+    }
+    .right-item {
+      font-weight: 600;
+    }
+  }
+  .app-link {
+    text-decoration: none;
+    color: #666;
+    &:hover {
+      text-decoration: underline;
+    }
+  }
+
+  .row {
+    font-size: 0.9em;
+  }
+
+  .even-row {
+    background: #eee;
+  }
+
+  .ellipsis {
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    display: inline-block;
+  }
+
+  .row {
+    min-height: unset;
+  }
+}
diff --git a/src/app/components/apps-view/apps-view.component.ts 
b/src/app/components/apps-view/apps-view.component.ts
index b23a863..d16e811 100644
--- a/src/app/components/apps-view/apps-view.component.ts
+++ b/src/app/components/apps-view/apps-view.component.ts
@@ -34,6 +34,7 @@ import { CommonUtil } from '@app/utils/common.util';
 import { PartitionInfo } from '@app/models/partition-info.model';
 import { DropdownItem } from '@app/models/dropdown-item.model';
 import { QueueInfo } from '@app/models/queue-info.model';
+import { MatDrawer } from '@angular/material/sidenav';
 
 @Component({
   selector: 'app-applications-view',
@@ -47,6 +48,7 @@ export class AppsViewComponent implements OnInit {
   @ViewChild('allocSort', { static: true }) allocSort!: MatSort;
   @ViewChild('searchInput', { static: true }) searchInput!: ElementRef;
   @ViewChild('queueSelect', { static: false }) queueSelect!: MatSelect;
+  @ViewChild('matDrawer', { static: false }) matDrawer!: MatDrawer;
 
   appDataSource = new MatTableDataSource<AppInfo>([]);
   appColumnDef: ColumnDef[] = [];
@@ -65,6 +67,7 @@ export class AppsViewComponent implements OnInit {
   leafQueueSelected = '';
 
   detailToggle: boolean = false;
+  allocationsToggle: boolean = false;
 
   constructor(
     private scheduler: SchedulerService,
@@ -105,14 +108,19 @@ export class AppsViewComponent implements OnInit {
       },
     ];
 
-    this.appColumnIds = this.appColumnDef.map((col) => 
col.colId).concat('indicatorIcon');
+    this.appColumnIds = this.appColumnDef.map((col) => col.colId);
 
     this.allocColumnDef = [
-      { colId: 'displayName', colName: 'Display Name' },
-      { colId: 'allocationKey', colName: 'Allocation Key' },
-      { colId: 'nodeId', colName: 'Node ID' },
-      { colId: 'resource', colName: 'Resource', colFormatter: 
CommonUtil.resourceColumnFormatter },
-      { colId: 'priority', colName: 'Priority' },
+      { colId: 'displayName', colName: 'Display Name', colWidth: 1 },
+      { colId: 'allocationKey', colName: 'Allocation Key', colWidth: 1 },
+      { colId: 'nodeId', colName: 'Node ID', colWidth: 1 },
+      {
+        colId: 'resource',
+        colName: 'Resource',
+        colFormatter: CommonUtil.resourceColumnFormatter,
+        colWidth: 1,
+      },
+      { colId: 'priority', colName: 'Priority', colWidth: 0.5 },
     ];
 
     this.allocColumnIds = this.allocColumnDef.map((col) => col.colId);
@@ -135,7 +143,6 @@ export class AppsViewComponent implements OnInit {
           list.forEach((part) => {
             this.partitionList.push(new PartitionInfo(part.name, part.name));
           });
-
           this.partitionSelected = CommonUtil.getStoredPartition(list[0].name);
           this.fetchQueuesForPartition(this.partitionSelected);
         } else {
@@ -270,6 +277,7 @@ export class AppsViewComponent implements OnInit {
     } else {
       this.selectedRow = row;
       row.isSelected = true;
+      this.matDrawer.open();
       if (row.allocations) {
         this.allocDataSource.data = row.allocations;
       }
@@ -387,4 +395,13 @@ export class AppsViewComponent implements OnInit {
   toggle() {
     this.detailToggle = !this.detailToggle;
   }
+
+  allocationsDetailToggle() {
+    this.allocationsToggle = !this.allocationsToggle;
+  }
+
+  closeDrawer() {
+    this.matDrawer.close();
+    this.removeRowSelection();
+  }
 }
diff --git a/src/app/models/column-def.model.ts 
b/src/app/models/column-def.model.ts
index 4a39254..055f81b 100644
--- a/src/app/models/column-def.model.ts
+++ b/src/app/models/column-def.model.ts
@@ -20,4 +20,5 @@ export interface ColumnDef {
   colId: string;
   colName: string;
   colFormatter?: (val: any) => any;
+  colWidth?: number;
 }
diff --git a/src/app/utils/common.util.ts b/src/app/utils/common.util.ts
index c810873..a5183c0 100644
--- a/src/app/utils/common.util.ts
+++ b/src/app/utils/common.util.ts
@@ -34,7 +34,7 @@ export class CommonUtil {
     const units: readonly string[] = ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 
'EiB'];
     let unit: string = 'B';
     let toValue = +value;
-    for (let i = 0, unitslen = units.length; toValue / 1024 >= 1 && i < 
unitslen;i = i + 1) {
+    for (let i = 0, unitslen = units.length; toValue / 1024 >= 1 && i < 
unitslen; i = i + 1) {
       toValue = toValue / 1024;
       unit = units[i];
     }
@@ -45,7 +45,7 @@ export class CommonUtil {
     const units: readonly string[] = ['kB', 'MB', 'GB', 'TB', 'PB', 'EB'];
     let unit: string = 'B';
     let toValue = +value;
-    for (let i = 0, unitslen = units.length; toValue / 1000 >= 1 && i < 
unitslen;i = i + 1) {
+    for (let i = 0, unitslen = units.length; toValue / 1000 >= 1 && i < 
unitslen; i = i + 1) {
       toValue = toValue / 1000;
       unit = units[i];
     }
@@ -63,7 +63,7 @@ export class CommonUtil {
     if (toValue > 0) {
       unit = units[0];
     }
-    for (let i = 1, unitslen = units.length; toValue / 1000 >= 1 && i < 
unitslen;i = i + 1) {
+    for (let i = 1, unitslen = units.length; toValue / 1000 >= 1 && i < 
unitslen; i = i + 1) {
       toValue = toValue / 1000;
       unit = units[i];
     }
@@ -74,7 +74,7 @@ export class CommonUtil {
     const units: readonly string[] = ['k', 'M', 'G', 'T', 'P', 'E'];
     let unit: string = '';
     let toValue = +value;
-    for (let i = 0, unitslen = units.length; toValue / 1000 >= 1 && i < 
unitslen;i = i + 1) {
+    for (let i = 0, unitslen = units.length; toValue / 1000 >= 1 && i < 
unitslen; i = i + 1) {
       toValue = toValue / 1000;
       unit = units[i];
     }
@@ -101,18 +101,18 @@ export class CommonUtil {
   static resourcesCompareFn(a: string, b: string): number {
     // define the order of resources
     const resourceOrder: { [key: string]: number } = {
-      "memory": 1,
-      "vcore": 2,
-      "pods": 3,
-      "ephemeral-storage": 4
+      memory: 1,
+      vcore: 2,
+      pods: 3,
+      'ephemeral-storage': 4,
     };
     const orderA = a in resourceOrder ? resourceOrder[a] : 
Number.MAX_SAFE_INTEGER;
     const orderB = b in resourceOrder ? resourceOrder[b] : 
Number.MAX_SAFE_INTEGER;
-  
+
     if (orderA !== orderB) {
-      return orderA - orderB;  // Resources in the order defined above
+      return orderA - orderB; // Resources in the order defined above
     } else {
-      return a.localeCompare(b);  // Other resources will be in lexicographic 
order
+      return a.localeCompare(b); // Other resources will be in lexicographic 
order
     }
   }
 


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

Reply via email to