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]