Skip to content

Commit

Permalink
Extended queue and partition with ID's
Browse files Browse the repository at this point in the history
Added column data that is available
  • Loading branch information
dcoric committed Dec 18, 2024
1 parent 0888c82 commit 92fee9e
Show file tree
Hide file tree
Showing 9 changed files with 264 additions and 101 deletions.
117 changes: 86 additions & 31 deletions web/src/app/allocations-drawer/allocations-drawer.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,75 @@
<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-clipboard copy-btn" (click)="copyLinkToClipboard()"
matTooltip="Click to copy the URL to this view" matTooltipShowDelay="500"></span>
<span
>{{ selectedRow?.applicationId }} ({{
selectedRow?.allocations?.length
}}
allocations)</span
>
<span
class="far fa-clipboard copy-btn"
(click)="copyLinkToClipboard()"
matTooltip="Click to copy the URL to this view"
matTooltipShowDelay="500"
></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>
<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"
[title]="element[columnDef.colId]">{{
element['priority'] }} </mat-cell>
<mat-cell
class="small"
*matCellDef="let element"
[style.flex]="columnDef?.colWidth || 1"
[title]="element[columnDef.colId]"
>{{ element['priority'] }}
</mat-cell>
</ng-container>

<ng-container *ngIf="columnDef.colId === 'log'; else renderNext_3">
<mat-cell class="small" *matCellDef="let element" [style.flex]="columnDef?.colWidth || 1"><a
href="{{ externalLogsBaseUrl }}{{ element['applicationId'] }}" target="_blank"
(click)="logClick($event)">Logs</a> </mat-cell>
<mat-cell
class="small"
*matCellDef="let element"
[style.flex]="columnDef?.colWidth || 1"
><a
href="{{ externalLogsBaseUrl }}{{ element['applicationId'] }}"
target="_blank"
(click)="logClick($event)"
>Logs</a
>
</mat-cell>
</ng-container>

<ng-container *ngIf="columnDef.colId === 'resource'; else renderNext_3">
<mat-cell *matCellDef="let element" class="allocations-data" [style.flex]="columnDef?.colWidth || 1"
<mat-cell
*matCellDef="let element"
class="allocations-data"
[style.flex]="columnDef?.colWidth || 1"
matTooltip="
{{element[columnDef.colId]}}" matTooltipShowDelay="500">
<ng-container *ngIf="columnDef.colFormatter; else showAllocRowData;">
<ng-container *ngIf="columnDef.colFormatter(element[columnDef.colId]) as colValue">
{{ element[columnDef.colId] }}"
matTooltipShowDelay="500"
>
<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">
<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 && element['expanded']">
<li class="mat-res-li" *ngIf="i >= 1 && element['expanded']">
{{ resource }}
</li>
</ng-container>
Expand All @@ -50,11 +83,24 @@
</mat-cell>
</ng-container>

<ng-container *ngIf="columnDef.colId === 'elapsedTime'; else renderNext_3">
<mat-cell
*matCellDef="let element"
[style.flex]="columnDef?.colWidth || 1"
[title]="element[columnDef.colId]"
>{{ calculateElapsedTime(element['requestTime'], element['allocationTime']) }}
</mat-cell>
</ng-container>

<ng-template #renderNext_3>
<mat-cell *matCellDef="let element" [class]="element['expanded'] ? '' : 'ellipsis'"
[style.flex]="columnDef?.colWidth || 1" matTooltip="{{element[columnDef.colId]}}"
matTooltipShowDelay="500">{{ element[columnDef.colId] || 'n/a'
}}</mat-cell>
<mat-cell
*matCellDef="let element"
[class]="element['expanded'] ? '' : 'ellipsis'"
[style.flex]="columnDef?.colWidth || 1"
matTooltip="{{ element[columnDef.colId] }}"
matTooltipShowDelay="500"
>{{ element[columnDef.colId] || 'n/a' }}</mat-cell
>
</ng-template>
</ng-container>

Expand All @@ -66,17 +112,26 @@

<mat-header-row *matHeaderRowDef="allocColumnIds"></mat-header-row>

<mat-row *matRowDef="let row; columns: allocColumnIds; let i = index" (click)="allocationsDetailToggle(i)"
[ngClass]="{'even-row': i % 2 === 0, 'row': true}"></mat-row>
<mat-row
*matRowDef="let row; columns: allocColumnIds; let i = index"
(click)="allocationsDetailToggle(i)"
[ngClass]="{ 'even-row': i % 2 === 0, row: true }"
></mat-row>

<mat-footer-row *matFooterRowDef="['noRecord']"
[ngStyle]="{ display: isAllocDataSourceEmpty() ? '' : 'none' }"></mat-footer-row>
<mat-footer-row
*matFooterRowDef="['noRecord']"
[ngStyle]="{ display: isAllocDataSourceEmpty() ? '' : 'none' }"
></mat-footer-row>
</mat-table>

<mat-paginator #allocationMatPaginator [pageSizeOptions]="[10, 20, 50, 100]" [pageSize]="50"
[ngStyle]="{ display: isAllocDataSourceEmpty() ? 'none' : '' }" showFirstLastButtons></mat-paginator>

<mat-paginator
#allocationMatPaginator
[pageSizeOptions]="[10, 20, 50, 100]"
[pageSize]="50"
[ngStyle]="{ display: isAllocDataSourceEmpty() ? 'none' : '' }"
showFirstLastButtons
></mat-paginator>
</div>
</mat-drawer-content>
</mat-drawer>
</mat-drawer-container>
</mat-drawer-container>
97 changes: 64 additions & 33 deletions web/src/app/allocations-drawer/allocations-drawer.component.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
import { Component, EventEmitter, Injectable, Input, OnInit, Output, ViewChild } from "@angular/core";
import { MatPaginator } from "@angular/material/paginator";
import { MatDrawer } from "@angular/material/sidenav";
import { MatSort } from "@angular/material/sort";
import { MatTableDataSource } from "@angular/material/table";
import { AllocationInfo } from "@app/models/alloc-info.model";
import { AppInfo } from "@app/models/app-info.model";
import { ColumnDef } from "@app/models/column-def.model";
import { EnvConfigService } from "@app/services/envconfig/envconfig.service";
import { CommonUtil } from "@app/utils/common.util";
import {
Component,
EventEmitter,
Injectable,
Input,
OnInit,
Output,
ViewChild,
} from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatDrawer } from '@angular/material/sidenav';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { AllocationInfo } from '@app/models/alloc-info.model';
import { AppInfo } from '@app/models/app-info.model';
import { ColumnDef } from '@app/models/column-def.model';
import { EnvConfigService } from '@app/services/envconfig/envconfig.service';
import { CommonUtil } from '@app/utils/common.util';

@Injectable()
@Component({
selector: "app-allocations-drawer",
templateUrl: "./allocations-drawer.component.html",
styleUrls: ["./allocations-drawer.component.scss"],
selector: 'app-allocations-drawer',
templateUrl: './allocations-drawer.component.html',
styleUrls: ['./allocations-drawer.component.scss'],
})
export class AllocationsDrawerComponent implements OnInit {
@ViewChild("matDrawer", { static: false }) matDrawer!: MatDrawer;
@ViewChild("allocationMatPaginator", { static: true }) allocPaginator!: MatPaginator;
@ViewChild("allocSort", { static: true }) allocSort!: MatSort;
@ViewChild('matDrawer', { static: false }) matDrawer!: MatDrawer;
@ViewChild('allocationMatPaginator', { static: true }) allocPaginator!: MatPaginator;
@ViewChild('allocSort', { static: true }) allocSort!: MatSort;
@Input() allocDataSource!: MatTableDataSource<AllocationInfo & { expanded: boolean }>;
@Input() selectedRow!: AppInfo | null;
@Input() externalLogsBaseUrl!: string | null;
Expand All @@ -41,41 +49,50 @@ export class AllocationsDrawerComponent implements OnInit {

ngOnInit(): void {
this.allocColumnDef = [
{ colId: "displayName", colName: "Display Name", colWidth: 1 },
{ colId: "allocationKey", colName: "Allocation Key", colWidth: 1 },
{ colId: "nodeId", colName: "Node ID", colWidth: 1 },
{ colId: 'displayName', colName: 'Display Name', colWidth: 1 },
{ colId: 'allocationKey', colName: 'Allocation Key', colWidth: 1 },
{ colId: 'nodeId', colName: 'Node ID', colWidth: 1 },
{
colId: "log",
colName: "Log Link",
colId: 'log',
colName: 'Log Link',
colWidth: 1,
},
{
colId: "resource",
colName: "Resource",
colId: 'resource',
colName: 'Resource',
colFormatter: CommonUtil.resourceColumnFormatter,
colWidth: 1,
},
{ colId: "priority", colName: "Priority", colWidth: 0.5 },
{ colId: 'priority', colName: 'Priority', colWidth: 0.5 },
{
colId: 'elapsedTime',
colName: 'Time to Allocation',
colWidth: 0.8,
},
];
this.allocColumnIds = this.allocColumnDef.map((col) => col.colId);
this.externalLogsBaseUrl = this.envConfig.getExternalLogsBaseUrl();
}

formatResources(colValue: string): string[] {
const arr: string[] = colValue.split("<br/>");
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"));
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");
arr.unshift('CPU: n/a');
}
if (!hasMemory) {
arr.unshift("Memory: n/a");
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 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;
Expand Down Expand Up @@ -116,8 +133,22 @@ export class AllocationsDrawerComponent implements OnInit {
}

copyLinkToClipboard() {
const url = window.location.href.split("?")[0];
const url = window.location.href.split('?')[0];
const copyString = `${url}?partition=${this.partitionSelected}&queue=${this.leafQueueSelected}&applicationId=${this?.selectedRow?.applicationId}`;
navigator.clipboard.writeText(copyString).catch((error) => console.error("Writing to the clipboard is not allowed. ", error));
navigator.clipboard
.writeText(copyString)
.catch((error) => console.error('Writing to the clipboard is not allowed. ', error));
}

calculateElapsedTime(requestTime: string, allocationTime: string): string {
if (!requestTime) {
return 'n/a';
}

const request = parseInt(requestTime) / 1_000_000; // nanoseconds to milliseconds
const allocation = parseInt(allocationTime) / 1_000_000; // nanoseconds to milliseconds
const diffInSeconds = Math.floor((allocation - request) / 1000);

return `${diffInSeconds}s`;
}
}
4 changes: 3 additions & 1 deletion web/src/app/models/alloc-info.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export class AllocationInfo {
public queueName: string,
public nodeId: string,
public applicationId: string,
public partition: string
public partition: string,
public requestTime: string,
public allocationTime: string
) {}
}
38 changes: 30 additions & 8 deletions web/src/app/models/app-info.model.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
import { NOT_AVAILABLE } from "@app/utils/constants";
import * as moment from "moment";
import { AllocationInfo } from "./alloc-info.model";
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { NOT_AVAILABLE } from '@app/utils/constants';
import * as moment from 'moment';
import { AllocationInfo } from './alloc-info.model';

export class AppInfo {
isSelected = false;

constructor(
public id: string,
public applicationId: string,
public usedResource: string,
public pendingResource: string,
Expand All @@ -20,21 +39,21 @@ export class AppInfo {

get formattedSubmissionTime() {
const millisecs = Math.round(this.submissionTime / (1000 * 1000));
return moment(millisecs).format("YYYY/MM/DD HH:mm:ss");
return moment(millisecs).format('YYYY/MM/DD HH:mm:ss');
}

get formattedlastStateChangeTime() {
if (this.lastStateChangeTime == null) {
return "n/a";
return 'n/a';
}
const millisecs = Math.round(this.lastStateChangeTime! / (1000 * 1000));
return moment(millisecs).format("YYYY/MM/DD HH:mm:ss");
return moment(millisecs).format('YYYY/MM/DD HH:mm:ss');
}

get formattedFinishedTime() {
if (this.finishedTime) {
const millisecs = Math.round(this.finishedTime / (1000 * 1000));
return moment(millisecs).format("YYYY/MM/DD HH:mm:ss");
return moment(millisecs).format('YYYY/MM/DD HH:mm:ss');
}

return NOT_AVAILABLE;
Expand All @@ -56,5 +75,8 @@ export class AppInfo {
}

export class StateLog {
constructor(public time: number, public applicationState: string) {}
constructor(
public time: number,
public applicationState: string
) {}
}
Loading

0 comments on commit 92fee9e

Please sign in to comment.