This is an automated email from the ASF dual-hosted git repository.
ccondit 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 f510bd2 [YUNIKORN-1914] Change display for resource lists (#130)
f510bd2 is described below
commit f510bd24341980b3125215559e80f78ff4585b9b
Author: wusamzong <[email protected]>
AuthorDate: Tue Sep 26 11:48:08 2023 -0500
[YUNIKORN-1914] Change display for resource lists (#130)
Closes: #130
Signed-off-by: Craig Condit <[email protected]>
---
json-db.json | 23 ++--
.../components/apps-view/apps-view.component.html | 115 ++++++++++++-------
.../components/apps-view/apps-view.component.scss | 123 ++++++++++++++++-----
.../components/apps-view/apps-view.component.ts | 26 +++++
.../nodes-view/nodes-view.component.html | 57 +++++++---
.../nodes-view/nodes-view.component.scss | 62 ++++++++++-
.../components/nodes-view/nodes-view.component.ts | 29 ++++-
7 files changed, 337 insertions(+), 98 deletions(-)
diff --git a/json-db.json b/json-db.json
index f713dd4..8f3ed37 100644
--- a/json-db.json
+++ b/json-db.json
@@ -263,7 +263,8 @@
"usedResource": {
"memory": 50000000,
"pods": 1,
- "vcore": 10
+ "vcore": 10,
+ "nvidia.com/gpu": 5
},
"maxUsedResource": {
"memory": 50000000,
@@ -297,7 +298,8 @@
"resource": {
"memory": 50000000,
"pods": 1,
- "vcore": 10
+ "vcore": 10,
+ "nvidia.com/gpu": 5
},
"priority": "0",
"nodeId": "lima-rancher-desktop",
@@ -545,17 +547,22 @@
"hugepages-64Ki": 0,
"memory": 4110970880,
"pods": 110,
- "vcore": 2000
+ "vcore": 2000,
+ "nvidia.com/gpu": 10,
+ "amd.com/gpu": 10,
+ "gpu.intel.com/i915": 10
},
"allocated": {
"memory": 200000000,
"pods": 4,
- "vcore": 40
+ "vcore": 40,
+ "nvidia.com/gpu": 5
},
"occupied": {
"memory": 1325400064,
"pods": 4,
- "vcore": 500
+ "vcore": 500,
+ "nvidia.com/gpu": 5
},
"available": {
"ephemeral-storage": 99833802265,
@@ -565,7 +572,8 @@
"hugepages-64Ki": 0,
"memory": 2585570816,
"pods": 102,
- "vcore": 1460
+ "vcore": 1460,
+ "nvidia.com/gpu": 5
},
"utilized": {
"memory": 4,
@@ -645,7 +653,8 @@
"resource": {
"memory": 50000000,
"pods": 1,
- "vcore": 10
+ "vcore": 10,
+ "nvidia.com/gpu": 5
},
"priority": "0",
"nodeId": "lima-rancher-desktop",
diff --git a/src/app/components/apps-view/apps-view.component.html
b/src/app/components/apps-view/apps-view.component.html
index 631634e..6635cd9 100644
--- a/src/app/components/apps-view/apps-view.component.html
+++ b/src/app/components/apps-view/apps-view.component.html
@@ -17,48 +17,57 @@
-->
<div class="top-section">
- <div class="dropdown-wrapper">
- <label class="dropdown-label">Partition: </label>
- <mat-form-field>
- <mat-select
- [(value)]="partitionSelected"
- (selectionChange)="onPartitionSelectionChanged($event)"
- >
- <mat-option *ngFor="let part of partitionList" [value]="part.value">
- {{ part.name }}
- </mat-option>
- </mat-select>
- </mat-form-field>
+ <div class="left-side">
+ <div class="dropdown-wrapper">
+ <label class="dropdown-label">Partition: </label>
+ <mat-form-field>
+ <mat-select
+ [(value)]="partitionSelected"
+ (selectionChange)="onPartitionSelectionChanged($event)"
+ >
+ <mat-option *ngFor="let part of partitionList" [value]="part.value">
+ {{ part.name }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ </div>
+ <div class="dropdown-wrapper">
+ <label class="dropdown-label">Queue: </label>
+ <mat-form-field>
+ <mat-select [(value)]="leafQueueSelected"
(selectionChange)="onQueueSelectionChanged($event)">
+ <mat-option *ngFor="let queue of leafQueueList"
[value]="queue.value">
+ {{ queue.name }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ </div>
</div>
- <div class="dropdown-wrapper">
- <label class="dropdown-label">Queue: </label>
- <mat-form-field>
- <mat-select [(value)]="leafQueueSelected"
(selectionChange)="onQueueSelectionChanged($event)">
- <mat-option *ngFor="let queue of leafQueueList" [value]="queue.value">
- {{ queue.name }}
- </mat-option>
- </mat-select>
+ <div class="right-side">
+ <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"
+ >
+ <i class="far fa-times-circle"></i>
+ </button>
+ <i *ngIf="!searchText" class="fas fa-search search-icon"></i>
</mat-form-field>
+ <div class="btn-wrapper">
+ <button class="btn" (click)="toggle()"
[style.background-color]="detailToggle ? '#313d54' : '#f5f5f5'">
+ <i class="material-icons __icon" [style.color]="detailToggle ?
'#f5f5f5' : '#313d54' ">more_horiz</i>
+ </button>
+ </div>
</div>
- <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"
- >
- <i class="far fa-times-circle"></i>
- </button>
- <i *ngIf="!searchText" class="fas fa-search search-icon"></i>
- </mat-form-field>
</div>
<div class="apps-view">
<div class="mat-elevation-z8">
@@ -78,7 +87,18 @@
<ng-container *ngIf="columnDef.colId === 'usedResource'; else
renderNext_1">
<mat-cell *matCellDef="let element">
<ng-container *ngIf="columnDef.colFormatter; else
showAppRawData">
- <span
[innerHTML]="columnDef.colFormatter(element[columnDef.colId])"></span>
+ <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>
+ </ul>
+ </ng-container>
</ng-container>
<ng-template #showAppRawData>
<span>{{ element[columnDef.colId] }}</span>
@@ -150,8 +170,19 @@
<ng-container *ngIf="columnDef.colId === 'resource'; else
renderNext_3">
<mat-cell *matCellDef="let element">
- <ng-container *ngIf="columnDef.colFormatter; else
showAllocRowData">
- <span
[innerHTML]="columnDef.colFormatter(element[columnDef.colId])"></span>
+ <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>
+ </ul>
+ </ng-container>
</ng-container>
<ng-template #showAllocRowData>
<span>{{ element[columnDef.colId] }}</span>
diff --git a/src/app/components/apps-view/apps-view.component.scss
b/src/app/components/apps-view/apps-view.component.scss
index 040b978..c91e654 100644
--- a/src/app/components/apps-view/apps-view.component.scss
+++ b/src/app/components/apps-view/apps-view.component.scss
@@ -15,47 +15,86 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+@import "https://fonts.googleapis.com/icon?family=Material+Icons";
-.top-section {
+ .top-section {
width: 100%;
height: 100%;
display: flex;
- .search-wrapper {
- width: 300px;
- position: absolute;
- right: 20px;
- input {
- width: calc(100% - 22px);
- color: #333;
- }
- .clear-btn {
- outline: none;
- border: none;
- padding: 0 0 0 4px;
- cursor: pointer;
- background: transparent;
- i {
- font-size: 18px;
- &:hover {
- color: #f44336;
- }
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ .left-side{
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ .dropdown-wrapper {
+ padding-right: 40px;
+ .dropdown-label {
+ color: #333;
+ font-size: 1.2em;
+ margin-right: 10px;
}
}
- .search-icon {
- margin-left: 4px;
- font-size: 17px;
- }
}
- .dropdown-wrapper {
- padding-right: 40px;
- .dropdown-label {
- color: #333;
- font-size: 1.2em;
- margin-right: 10px;
+ .right-side{
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ .btn-wrapper {
+ filter: drop-shadow(0px 2px 1px rgba(90, 90, 90, 0.5));
+ &:hover{
+ filter: drop-shadow(0px 3px 3px rgba(90, 90, 90, 0.5));
+ }
+ :hover{
+ cursor: pointer;
+ }
+ .btn{
+ display: block;
+ border: none;
+ padding: 13px 24px;
+ border-radius: 5px;
+ font-size: 24px;
+ transform: translateY(-13px);
+ }
+ .material-icons{
+ transform: translateY(2px);
+ }
+ }
+ .search-wrapper {
+ width: 300px;
+ right: 20px;
+ padding-right: 20px;
+ input {
+ width: calc(100% - 22px);
+ color: #333;
+ }
+ .clear-btn {
+ outline: none;
+ border: none;
+ padding: 0 0 0 4px;
+ cursor: pointer;
+ background: transparent;
+ i {
+ font-size: 18px;
+ &:hover {
+ color: #f44336;
+ }
+ }
+ }
+ .search-icon {
+ margin-left: 4px;
+ font-size: 17px;
+ }
}
}
}
+.mdc-button .mdc-button__label{
+ display: flex;
+ align-items: center;
+}
+
.apps-view {
width: 100%;
height: 100%;
@@ -66,6 +105,24 @@
}
.mat-mdc-cell {
color: #333;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ .mat-res-ul{
+ padding: 0;
+ margin: 0;
+ .mat-res-li{
+ list-style-type: none;
+ }
+ }
+ .mat-toggle-more {
+ display: block;
+ color: #a1a3b7;
+ padding: 5px 45px 0 0;
+ &:hover {
+ color: #8d00d4;
+ }
+ }
}
.mat-mdc-row {
&:hover {
@@ -76,6 +133,12 @@
background: #303d54;
.mat-mdc-cell {
color: #fff;
+ .mat-toggle-more {
+ color: #b8bbff;
+ &:hover {
+ color: #b871dc;
+ }
+ }
}
}
}
diff --git a/src/app/components/apps-view/apps-view.component.ts
b/src/app/components/apps-view/apps-view.component.ts
index 7d691d1..fa94c35 100644
--- a/src/app/components/apps-view/apps-view.component.ts
+++ b/src/app/components/apps-view/apps-view.component.ts
@@ -61,6 +61,8 @@ export class AppsViewComponent implements OnInit {
partitionSelected = '';
leafQueueList: DropdownItem[] = [];
leafQueueSelected = '';
+
+ detailToggle: boolean = false;
constructor(
private scheduler: SchedulerService,
@@ -301,4 +303,28 @@ export class AppsViewComponent implements OnInit {
this.removeRowSelection();
}
}
+
+ formatResources(colValue:string):string[]{
+ const arr:string[]=colValue.split("<br/>")
+ // Check if there are "cpu" or "Memory" elements in the array
+ const hasCpu = arr.some((item) => item.toLowerCase().includes("cpu"));
+ const hasMemory = arr.some((item) =>
item.toLowerCase().includes("memory"));
+ if (!hasCpu) {
+ arr.unshift("CPU: n/a");
+ }
+ if (!hasMemory) {
+ arr.unshift("Memory: n/a");
+ }
+
+ // Concatenate the two arrays, with "cpu" and "Memory" elements first
+ const cpuAndMemoryElements = arr.filter((item) =>
item.toLowerCase().includes("CPU") || item.toLowerCase().includes("Memory"));
+ const otherElements = arr.filter((item) =>
!item.toLowerCase().includes("CPU") && !item.toLowerCase().includes("Memory"));
+ const result = cpuAndMemoryElements.concat(otherElements);
+
+ return result;
+ }
+
+ toggle(){
+ this.detailToggle = !this.detailToggle;
+ }
}
diff --git a/src/app/components/nodes-view/nodes-view.component.html
b/src/app/components/nodes-view/nodes-view.component.html
index 177d64f..076e283 100644
--- a/src/app/components/nodes-view/nodes-view.component.html
+++ b/src/app/components/nodes-view/nodes-view.component.html
@@ -17,17 +17,24 @@
-->
<div class="top-part">
- <label class="part-label">Partition: </label>
- <mat-form-field>
- <mat-select
- [(value)]="partitionSelected"
- (selectionChange)="onPartitionSelectionChanged($event)"
- >
- <mat-option *ngFor="let part of partitionList" [value]="part.value">
- {{ part.name }}
- </mat-option>
- </mat-select>
- </mat-form-field>
+ <div class="dropdown-wrapper">
+ <label class="part-label">Partition: </label>
+ <mat-form-field>
+ <mat-select
+ [(value)]="partitionSelected"
+ (selectionChange)="onPartitionSelectionChanged($event)"
+ >
+ <mat-option *ngFor="let part of partitionList" [value]="part.value">
+ {{ part.name }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ </div>
+ <div class="btn-wrapper">
+ <button class="btn" (click)="toggle()"
[style.background-color]="detailToggle ? '#313d54' : '#f5f5f5'">
+ <i class="material-icons __icon" [style.color]="detailToggle ? '#f5f5f5'
: '#313d54' ">more_horiz</i>
+ </button>
+ </div>
</div>
<div class="nodes-view">
<div class="mat-elevation-z8">
@@ -43,7 +50,18 @@
>
<mat-cell *matCellDef="let element">
<ng-container *ngIf="columnDef.colFormatter; else showNodeRawData">
- <span
[innerHTML]="columnDef.colFormatter(element[columnDef.colId])"></span>
+ <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>
+ </ul>
+ </ng-container>
</ng-container>
<ng-template #showNodeRawData>
<span>{{ element[columnDef.colId] }}</span>
@@ -107,8 +125,19 @@
<ng-container *ngIf="columnDef.colId === 'resource'; else
renderNext_2">
<mat-cell *matCellDef="let element">
<ng-container *ngIf="columnDef.colFormatter; else
showAllocRowData">
- <span
[innerHTML]="columnDef.colFormatter(element[columnDef.colId])"></span>
- </ng-container>
+ <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>
+ </ul>
+ </ng-container>
+ </ng-container>
<ng-template #showAllocRowData>
<span>{{ element[columnDef.colId] }}</span>
</ng-template>
diff --git a/src/app/components/nodes-view/nodes-view.component.scss
b/src/app/components/nodes-view/nodes-view.component.scss
index 67eea13..545d27b 100644
--- a/src/app/components/nodes-view/nodes-view.component.scss
+++ b/src/app/components/nodes-view/nodes-view.component.scss
@@ -15,12 +15,42 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+@import "https://fonts.googleapis.com/icon?family=Material+Icons";
-.part-label {
- color: #333;
- font-size: 1.2em;
- margin-right: 10px;
+.top-part{
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ .dropdown-wrapper{
+ padding-right: 40px;
+ .part-label {
+ color: #333;
+ font-size: 1.2em;
+ margin-right: 10px;
+ }
+ }
+ .btn-wrapper {
+ filter: drop-shadow(0px 2px 1px rgba(90, 90, 90, 0.5));
+ &:hover{
+ filter: drop-shadow(0px 3px 3px rgba(90, 90, 90, 0.5));
+ }
+ :hover{
+ cursor: pointer;
+ }
+ .btn{
+ display: block;
+ border: none;
+ padding: 13px 24px;
+ border-radius: 5px;
+ font-size: 24px;
+ transform: translateY(-13px);
+ }
+ .material-icons{
+ transform: translateY(2px);
+ }
+ }
}
+
.nodes-view {
width: 100%;
height: 100%;
@@ -31,6 +61,24 @@
}
.mat-mdc-cell {
color: #333;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ .mat-res-ul{
+ padding: 0;
+ margin: 0;
+ .mat-res-li{
+ list-style-type: none;
+ }
+ }
+ .mat-toggle-more {
+ display: block;
+ color: #a1a3b7;
+ padding: 5px 45px 0 0;
+ &:hover {
+ color: #8d00d4;
+ }
+ }
}
.mat-mdc-row {
&:hover {
@@ -41,6 +89,12 @@
background: #303d54;
.mat-mdc-cell {
color: #fff;
+ .mat-toggle-more {
+ color: #b8bbff;
+ &:hover {
+ color: #b871dc;
+ }
+ }
}
}
}
diff --git a/src/app/components/nodes-view/nodes-view.component.ts
b/src/app/components/nodes-view/nodes-view.component.ts
index 6bdb19a..e7dffd8 100644
--- a/src/app/components/nodes-view/nodes-view.component.ts
+++ b/src/app/components/nodes-view/nodes-view.component.ts
@@ -22,7 +22,7 @@ import { MatSelectChange } from '@angular/material/select';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { NgxSpinnerService } from 'ngx-spinner';
-import { finalize } from 'rxjs/operators';
+import { finalize, flatMap } from 'rxjs/operators';
import { SchedulerService } from '@app/services/scheduler/scheduler.service';
import { NodeInfo } from '@app/models/node-info.model';
@@ -53,6 +53,8 @@ export class NodesViewComponent implements OnInit {
partitionList: PartitionInfo[] = [];
partitionSelected = '';
+ detailToggle: boolean = false;
+
constructor(private scheduler: SchedulerService, private spinner:
NgxSpinnerService) {}
ngOnInit() {
@@ -135,6 +137,7 @@ export class NodesViewComponent implements OnInit {
)
.subscribe((data) => {
this.nodeDataSource.data = data;
+ console.log(data);
});
}
@@ -190,4 +193,28 @@ export class NodesViewComponent implements OnInit {
this.clearRowSelection();
this.fetchNodeListForPartition(this.partitionSelected);
}
+
+ formatResources(colValue:string):string[]{
+ const arr:string[]=colValue.split("<br/>")
+ // Check if there are "cpu" or "Memory" elements in the array
+ const hasCpu = arr.some((item) => item.toLowerCase().includes("cpu"));
+ const hasMemory = arr.some((item) =>
item.toLowerCase().includes("memory"));
+ if (!hasCpu) {
+ arr.unshift("CPU: n/a");
+ }
+ if (!hasMemory) {
+ arr.unshift("Memory: n/a");
+ }
+
+ // Concatenate the two arrays, with "cpu" and "Memory" elements first
+ const cpuAndMemoryElements = arr.filter((item) =>
item.toLowerCase().includes("CPU") || item.toLowerCase().includes("Memory"));
+ const otherElements = arr.filter((item) =>
!item.toLowerCase().includes("CPU") && !item.toLowerCase().includes("Memory"));
+ const result = cpuAndMemoryElements.concat(otherElements);
+
+ return result;
+ }
+
+ toggle(){
+ this.detailToggle = !this.detailToggle;
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]