mirror of
https://github.com/apache/nifi.git
synced 2025-02-07 18:48:51 +00:00
[NIFI-12552] - Support client-side pagination on Summary tables (#8192)
* [NIFI-12552] - Support client-side pagination on Summary tables * updated the filter control to only show the label indicating matches when a filter is active. similar to how it is done for the events table * aligned cells like Run Status so the icon and text are vertically centered in the table cell * moving System Diagnostics out from the Summary page to the main application menu * reset summary listing table selection when pagination or filter changes. * remove area chart icon from the System Diagnostics menu option as it duplicates the Node Status History option * refactor selection clearing to its own action This closes #8192
This commit is contained in:
parent
689f990978
commit
3877146170
@ -114,6 +114,14 @@
|
||||
<i class="fa fa-fw fa-area-chart mr-2"></i>
|
||||
Node Status History
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="global-menu-item"
|
||||
[disabled]="!user.systemPermissions.canRead"
|
||||
(click)="viewSystemDiagnostics()">
|
||||
<i class="fa fa-fw mr-2"></i>
|
||||
System Diagnostics
|
||||
</button>
|
||||
<mat-divider></mat-divider>
|
||||
<button
|
||||
mat-menu-item
|
||||
|
@ -38,7 +38,8 @@ import { AsyncPipe, NgIf, NgOptimizedImage } from '@angular/common';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { FlowStatus } from './flow-status/flow-status.component';
|
||||
import * as StatusHistoryActions from '../../../../../state/status-history/status-history.actions';
|
||||
import { getNodeStatusHistoryAndOpenDialog } from '../../../../../state/status-history/status-history.actions';
|
||||
import { getSystemDiagnosticsAndOpenDialog } from '../../../../../state/system-diagnostics/system-diagnostics.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'fd-header',
|
||||
@ -88,11 +89,21 @@ export class HeaderComponent {
|
||||
|
||||
viewNodeStatusHistory(): void {
|
||||
this.store.dispatch(
|
||||
StatusHistoryActions.getNodeStatusHistoryAndOpenDialog({
|
||||
getNodeStatusHistoryAndOpenDialog({
|
||||
request: {
|
||||
source: 'menu'
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
viewSystemDiagnostics() {
|
||||
this.store.dispatch(
|
||||
getSystemDiagnosticsAndOpenDialog({
|
||||
request: {
|
||||
nodewise: false
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ export interface ProcessGroupStatusSnapshot extends BaseSnapshot {
|
||||
versionedFlowState?: VersionedFlowState;
|
||||
}
|
||||
|
||||
export interface AggregateSnapshot extends ProcessGroupStatusSnapshot {}
|
||||
export type AggregateSnapshot = ProcessGroupStatusSnapshot;
|
||||
|
||||
export interface PortStatusSnapshot extends BaseSnapshot {
|
||||
runStatus: string;
|
||||
|
@ -25,7 +25,7 @@ import {
|
||||
SummaryListingResponse
|
||||
} from './index';
|
||||
|
||||
const SUMMARY_LISTING_PREFIX: string = '[Summary Listing]';
|
||||
const SUMMARY_LISTING_PREFIX = '[Summary Listing]';
|
||||
|
||||
export const loadSummaryListing = createAction(
|
||||
`${SUMMARY_LISTING_PREFIX} Load Summary Listing`,
|
||||
@ -47,31 +47,53 @@ export const selectProcessorStatus = createAction(
|
||||
props<{ request: SelectProcessorStatusRequest }>()
|
||||
);
|
||||
|
||||
export const clearProcessorStatusSelection = createAction(`${SUMMARY_LISTING_PREFIX} Clear Processor Status Selection`);
|
||||
|
||||
export const selectProcessGroupStatus = createAction(
|
||||
`${SUMMARY_LISTING_PREFIX} Select Process Group Status`,
|
||||
props<{ request: SelectProcessGroupStatusRequest }>()
|
||||
);
|
||||
|
||||
export const clearProcessGroupStatusSelection = createAction(
|
||||
`${SUMMARY_LISTING_PREFIX} Clear Process Group Status Selection`
|
||||
);
|
||||
|
||||
export const selectInputPortStatus = createAction(
|
||||
`${SUMMARY_LISTING_PREFIX} Select Input Port Status`,
|
||||
props<{ request: SelectPortStatusRequest }>()
|
||||
);
|
||||
|
||||
export const clearInputPortStatusSelection = createAction(
|
||||
`${SUMMARY_LISTING_PREFIX} Clear Input Port Status Selection`
|
||||
);
|
||||
|
||||
export const selectOutputPortStatus = createAction(
|
||||
`${SUMMARY_LISTING_PREFIX} Select Output Port Status`,
|
||||
props<{ request: SelectPortStatusRequest }>()
|
||||
);
|
||||
|
||||
export const clearOutputPortStatusSelection = createAction(
|
||||
`${SUMMARY_LISTING_PREFIX} Clear Output Port Status Selection`
|
||||
);
|
||||
|
||||
export const selectConnectionStatus = createAction(
|
||||
`${SUMMARY_LISTING_PREFIX} Select Connection Status`,
|
||||
props<{ request: SelectConnectionStatusRequest }>()
|
||||
);
|
||||
|
||||
export const clearConnectionStatusSelection = createAction(
|
||||
`${SUMMARY_LISTING_PREFIX} Clear Connection Status Selection`
|
||||
);
|
||||
|
||||
export const selectRemoteProcessGroupStatus = createAction(
|
||||
`${SUMMARY_LISTING_PREFIX} Select Remote Process Group Status`,
|
||||
props<{ request: SelectRemoteProcessGroupStatusRequest }>()
|
||||
);
|
||||
|
||||
export const clearRemoteProcessGroupStatusSelection = createAction(
|
||||
`${SUMMARY_LISTING_PREFIX} Clear Remote Process Group Status Selection`
|
||||
);
|
||||
|
||||
export const navigateToViewProcessorStatusHistory = createAction(
|
||||
`${SUMMARY_LISTING_PREFIX} Navigate To Processor Status History`,
|
||||
props<{ id: string }>()
|
||||
|
@ -73,6 +73,17 @@ export class SummaryListingEffects {
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
clearProcessorStatusSelection$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(SummaryListingActions.clearProcessorStatusSelection),
|
||||
tap(() => {
|
||||
this.router.navigate(['/summary', 'processors']);
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
selectProcessGroupStatus$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
@ -85,6 +96,17 @@ export class SummaryListingEffects {
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
clearProcessGroupStatusSelection$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(SummaryListingActions.clearProcessGroupStatusSelection),
|
||||
tap(() => {
|
||||
this.router.navigate(['/summary', 'process-groups']);
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
selectInputPortStatus$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
@ -97,6 +119,17 @@ export class SummaryListingEffects {
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
clearInputPortStatusSelection$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(SummaryListingActions.clearInputPortStatusSelection),
|
||||
tap(() => {
|
||||
this.router.navigate(['/summary', 'input-ports']);
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
selectOutputPortStatus$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
@ -109,6 +142,17 @@ export class SummaryListingEffects {
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
clearOutputPortStatusSelection$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(SummaryListingActions.clearOutputPortStatusSelection),
|
||||
tap(() => {
|
||||
this.router.navigate(['/summary', 'output-ports']);
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
selectConnectionStatus$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
@ -121,6 +165,17 @@ export class SummaryListingEffects {
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
clearConnectionStatusSelection$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(SummaryListingActions.clearConnectionStatusSelection),
|
||||
tap(() => {
|
||||
this.router.navigate(['/summary', 'connections']);
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
selectRpgStatus$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
@ -133,6 +188,17 @@ export class SummaryListingEffects {
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
clearRpgStatusSelection = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(SummaryListingActions.clearRemoteProcessGroupStatusSelection),
|
||||
tap(() => {
|
||||
this.router.navigate(['/summary', 'remote-process-groups']);
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
navigateToProcessorStatusHistory$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
|
@ -14,134 +14,168 @@
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<div class="flex flex-col h-full gap-y-2">
|
||||
<div class="flex-1">
|
||||
<ng-container>
|
||||
<div class="port-status-table h-full flex flex-col">
|
||||
<!-- allow filtering of the table -->
|
||||
<summary-table-filter
|
||||
[filteredCount]="filteredCount"
|
||||
[totalCount]="totalCount"
|
||||
[filterableColumns]="filterableColumns"
|
||||
[includeStatusFilter]="true"
|
||||
[includePrimaryNodeOnlyFilter]="false"
|
||||
(filterChanged)="applyFilter($event)"></summary-table-filter>
|
||||
|
||||
<div class="port-status-table h-full flex flex-col">
|
||||
<!-- allow filtering of the table -->
|
||||
<summary-table-filter
|
||||
[filteredCount]="filteredCount"
|
||||
[totalCount]="totalCount"
|
||||
[filterableColumns]="filterableColumns"
|
||||
[includeStatusFilter]="true"
|
||||
[includePrimaryNodeOnlyFilter]="false"
|
||||
(filterChanged)="applyFilter($event)"></summary-table-filter>
|
||||
|
||||
<div class="flex-1 relative">
|
||||
<div class="listing-table overflow-y-auto border absolute inset-0">
|
||||
<table
|
||||
mat-table
|
||||
[dataSource]="dataSource"
|
||||
matSort
|
||||
matSortDisableClear
|
||||
(matSortChange)="sortData($event)"
|
||||
[matSortActive]="initialSortColumn"
|
||||
[matSortDirection]="initialSortDirection">
|
||||
<!-- More Details Column -->
|
||||
<ng-container matColumnDef="moreDetails">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item"></td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Name</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatName(item)">
|
||||
{{ formatName(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Run Status column -->
|
||||
<ng-container matColumnDef="runStatus">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Run Status</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1.5">
|
||||
<span [ngClass]="getRunStatusIcon(item)"></span>
|
||||
<span [title]="formatRunStatus(item)">{{ formatRunStatus(item) }}</span>
|
||||
|
||||
<ng-container *ngIf="item.processorStatusSnapshot as pg">
|
||||
<span
|
||||
*ngIf="pg.terminatedThreadCount > 0; else activeThreads"
|
||||
title="Threads: (Active / Terminated)"
|
||||
>({{ pg.activeThreadCount }}/{{ pg.terminatedThreadCount }})</span
|
||||
>
|
||||
<ng-template #activeThreads>
|
||||
<span *ngIf="pg.activeThreadCount > 0" title="Active Threads"
|
||||
>({{ pg.activeThreadCount }})</span
|
||||
>
|
||||
</ng-template>
|
||||
<div class="flex-1 relative">
|
||||
<div class="listing-table overflow-y-auto border absolute inset-0">
|
||||
<table
|
||||
mat-table
|
||||
[dataSource]="dataSource"
|
||||
matSort
|
||||
matSortDisableClear
|
||||
(matSortChange)="sortData($event)"
|
||||
[matSortActive]="initialSortColumn"
|
||||
[matSortDirection]="initialSortDirection">
|
||||
<!-- More Details Column -->
|
||||
<ng-container matColumnDef="moreDetails">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item"></td>
|
||||
</ng-container>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Input column -->
|
||||
<ng-container matColumnDef="in">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span [ngClass]="{ underline: multiSort.active === 'in' && multiSort.sortValueIndex === 0 }"
|
||||
>In</span
|
||||
>
|
||||
<span [ngClass]="{ underline: multiSort.active === 'in' && multiSort.sortValueIndex === 1 }"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatIn(item)">
|
||||
{{ formatIn(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Name</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatName(item)">
|
||||
{{ formatName(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Output column -->
|
||||
<ng-container matColumnDef="out">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{ underline: multiSort.active === 'out' && multiSort.sortValueIndex === 0 }">
|
||||
Out
|
||||
</span>
|
||||
<span
|
||||
[ngClass]="{ underline: multiSort.active === 'out' && multiSort.sortValueIndex === 1 }">
|
||||
(Size)
|
||||
</span>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatOut(item)">
|
||||
{{ formatOut(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Run Status column -->
|
||||
<ng-container matColumnDef="runStatus">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Run Status</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1.5 align-middle">
|
||||
<span [ngClass]="getRunStatusIcon(item)"></span>
|
||||
<span [title]="formatRunStatus(item)">{{ formatRunStatus(item) }}</span>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div
|
||||
class="pointer fa fa-long-arrow-right"
|
||||
[routerLink]="getPortLink(item)"
|
||||
(click)="$event.stopPropagation()"
|
||||
title="Go to {{ portType }}} port"></div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="item.processorStatusSnapshot as pg">
|
||||
<span
|
||||
*ngIf="pg.terminatedThreadCount > 0; else activeThreads"
|
||||
title="Threads: (Active / Terminated)"
|
||||
>({{ pg.activeThreadCount }}/{{ pg.terminatedThreadCount }})</span
|
||||
>
|
||||
<ng-template #activeThreads>
|
||||
<span *ngIf="pg.activeThreadCount > 0" title="Active Threads"
|
||||
>({{ pg.activeThreadCount }})</span
|
||||
>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
|
||||
<tr
|
||||
mat-row
|
||||
*matRowDef="let row; let even = even; columns: displayedColumns"
|
||||
[class.even]="even"
|
||||
(click)="select(row)"
|
||||
[class.selected]="isSelected(row)"></tr>
|
||||
</table>
|
||||
<!-- Input column -->
|
||||
<ng-container matColumnDef="in">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'in' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>In</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'in' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatIn(item)">
|
||||
{{ formatIn(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Output column -->
|
||||
<ng-container matColumnDef="out">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'out' && multiSort.sortValueIndex === 0
|
||||
}">
|
||||
Out
|
||||
</span>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'out' && multiSort.sortValueIndex === 1
|
||||
}">
|
||||
(Size)
|
||||
</span>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatOut(item)">
|
||||
{{ formatOut(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div
|
||||
class="pointer fa fa-long-arrow-right"
|
||||
[routerLink]="getPortLink(item)"
|
||||
(click)="$event.stopPropagation()"
|
||||
title="Go to {{ portType }}} port"></div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
|
||||
<tr
|
||||
mat-row
|
||||
*matRowDef="let row; let even = even; columns: displayedColumns"
|
||||
[class.even]="even"
|
||||
(click)="select(row)"
|
||||
[class.selected]="isSelected(row)"></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="flex justify-between align-middle">
|
||||
<div class="refresh-container flex items-center gap-x-2">
|
||||
<button class="nifi-button" (click)="refresh.next()">
|
||||
<i class="fa fa-refresh" [class.fa-spin]="summaryListingStatus === 'loading'"></i>
|
||||
</button>
|
||||
<div>Last updated:</div>
|
||||
<div class="refresh-timestamp">{{ loadedTimestamp }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<mat-paginator
|
||||
[pageSize]="100"
|
||||
[hidePageSize]="true"
|
||||
[showFirstLastButtons]="true"
|
||||
(page)="paginationChanged()"></mat-paginator>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { AfterViewInit, Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatSortModule, Sort, SortDirection } from '@angular/material/sort';
|
||||
import { MultiSort } from '../index';
|
||||
@ -29,25 +29,26 @@ import {
|
||||
import { ComponentType } from '../../../../../state/shared';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { NiFiCommon } from '../../../../../service/nifi-common.service';
|
||||
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
|
||||
|
||||
export type SupportedColumns = 'name' | 'runStatus' | 'in' | 'out';
|
||||
|
||||
@Component({
|
||||
selector: 'port-status-table',
|
||||
standalone: true,
|
||||
imports: [CommonModule, SummaryTableFilterModule, MatSortModule, MatTableModule, RouterLink],
|
||||
imports: [CommonModule, SummaryTableFilterModule, MatSortModule, MatTableModule, RouterLink, MatPaginatorModule],
|
||||
templateUrl: './port-status-table.component.html',
|
||||
styleUrls: ['./port-status-table.component.scss', '../../../../../../assets/styles/listing-table.scss']
|
||||
})
|
||||
export class PortStatusTable {
|
||||
export class PortStatusTable implements AfterViewInit {
|
||||
private _initialSortColumn: SupportedColumns = 'name';
|
||||
private _initialSortDirection: SortDirection = 'asc';
|
||||
private _portType!: 'input' | 'output';
|
||||
|
||||
filterableColumns: SummaryTableFilterColumn[] = [{ key: 'name', label: 'name' }];
|
||||
|
||||
totalCount: number = 0;
|
||||
filteredCount: number = 0;
|
||||
totalCount = 0;
|
||||
filteredCount = 0;
|
||||
|
||||
multiSort: MultiSort = {
|
||||
active: this._initialSortColumn,
|
||||
@ -60,8 +61,14 @@ export class PortStatusTable {
|
||||
|
||||
dataSource: MatTableDataSource<PortStatusSnapshotEntity> = new MatTableDataSource<PortStatusSnapshotEntity>();
|
||||
|
||||
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||
|
||||
constructor(private nifiCommon: NiFiCommon) {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.dataSource.paginator = this.paginator;
|
||||
}
|
||||
|
||||
@Input() set portType(type: 'input' | 'output') {
|
||||
if (type === 'input') {
|
||||
this.displayedColumns = ['moreDetails', 'name', 'runStatus', 'in', 'actions'];
|
||||
@ -120,11 +127,29 @@ export class PortStatusTable {
|
||||
}
|
||||
}
|
||||
|
||||
@Input() summaryListingStatus: string | null = null;
|
||||
@Input() loadedTimestamp: string | null = null;
|
||||
|
||||
@Output() refresh: EventEmitter<void> = new EventEmitter<void>();
|
||||
@Output() selectPort: EventEmitter<PortStatusSnapshotEntity> = new EventEmitter<PortStatusSnapshotEntity>();
|
||||
@Output() clearSelection: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
applyFilter(filter: SummaryTableFilterArgs) {
|
||||
this.dataSource.filter = JSON.stringify(filter);
|
||||
this.filteredCount = this.dataSource.filteredData.length;
|
||||
this.resetPaginator();
|
||||
this.selectNone();
|
||||
}
|
||||
|
||||
resetPaginator(): void {
|
||||
if (this.dataSource.paginator) {
|
||||
this.dataSource.paginator.firstPage();
|
||||
}
|
||||
}
|
||||
|
||||
paginationChanged(): void {
|
||||
// clear out any selection
|
||||
this.selectNone();
|
||||
}
|
||||
|
||||
formatName(port: PortStatusSnapshotEntity): string {
|
||||
@ -172,6 +197,10 @@ export class PortStatusTable {
|
||||
this.selectPort.next(port);
|
||||
}
|
||||
|
||||
private selectNone() {
|
||||
this.clearSelection.next();
|
||||
}
|
||||
|
||||
isSelected(port: PortStatusSnapshotEntity): boolean {
|
||||
if (this.selectedPortId) {
|
||||
return port.id === this.selectedPortId;
|
||||
@ -226,7 +255,7 @@ export class PortStatusTable {
|
||||
}
|
||||
return data.slice().sort((a, b) => {
|
||||
const isAsc: boolean = sort.direction === 'asc';
|
||||
let retVal: number = 0;
|
||||
let retVal = 0;
|
||||
switch (sort.active) {
|
||||
case 'name':
|
||||
retVal = this.nifiCommon.compareString(a.portStatusSnapshot.name, b.portStatusSnapshot.name);
|
||||
|
@ -16,7 +16,9 @@
|
||||
-->
|
||||
|
||||
<div class="summary-table-filter-container">
|
||||
<div class="value">Displaying {{ filteredCount }} of {{ totalCount }}</div>
|
||||
<div class="value {{ showFilterMatchedLabel ? 'visible' : 'invisible' }}">
|
||||
Filter matched {{ filteredCount }} of {{ totalCount }}
|
||||
</div>
|
||||
<form [formGroup]="filterForm">
|
||||
<div class="flex pt-1 gap-1 items-baseline">
|
||||
<div>
|
||||
|
@ -37,13 +37,14 @@ export interface SummaryTableFilterArgs {
|
||||
})
|
||||
export class SummaryTableFilter implements AfterViewInit {
|
||||
filterForm: FormGroup;
|
||||
private _filteredCount: number = 0;
|
||||
private _totalCount: number = 0;
|
||||
private _initialFilterColumn: string = 'name';
|
||||
private _filteredCount = 0;
|
||||
private _totalCount = 0;
|
||||
private _initialFilterColumn = 'name';
|
||||
showFilterMatchedLabel = false;
|
||||
|
||||
@Input() filterableColumns: SummaryTableFilterColumn[] = [];
|
||||
@Input() includeStatusFilter: boolean = false;
|
||||
@Input() includePrimaryNodeOnlyFilter: boolean = false;
|
||||
@Input() includeStatusFilter = false;
|
||||
@Input() includePrimaryNodeOnlyFilter = false;
|
||||
@Output() filterChanged: EventEmitter<SummaryTableFilterArgs> = new EventEmitter<SummaryTableFilterArgs>();
|
||||
|
||||
@Input() set filterTerm(term: string) {
|
||||
@ -133,5 +134,6 @@ export class SummaryTableFilter implements AfterViewInit {
|
||||
filterTerm,
|
||||
primaryOnly
|
||||
});
|
||||
this.showFilterMatchedLabel = filterTerm?.length > 0 || filterStatus !== 'All' || primaryOnly;
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import { MatInputModule } from '@angular/material/input';
|
||||
import { MatOptionModule } from '@angular/material/core';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { NgForOf, NgIf } from '@angular/common';
|
||||
import { NgClass, NgForOf, NgIf } from '@angular/common';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
|
||||
@NgModule({
|
||||
@ -35,7 +35,8 @@ import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
ReactiveFormsModule,
|
||||
NgForOf,
|
||||
NgIf,
|
||||
MatCheckboxModule
|
||||
MatCheckboxModule,
|
||||
NgClass
|
||||
],
|
||||
exports: [SummaryTableFilter],
|
||||
providers: []
|
||||
|
@ -21,30 +21,16 @@
|
||||
</div>
|
||||
|
||||
<ng-template #loaded>
|
||||
<div class="flex flex-col h-full gap-y-2">
|
||||
<div class="flex-1" *ngIf="currentUser$ | async as user">
|
||||
<ng-container>
|
||||
<connection-status-table
|
||||
[connections]="(connectionStatusSnapshots$ | async)!"
|
||||
[selectedConnectionId]="selectedConnectionId$ | async"
|
||||
(selectConnection)="selectConnection($event)"
|
||||
(viewStatusHistory)="viewStatusHistory($event)"
|
||||
initialSortColumn="sourceName"
|
||||
initialSortDirection="asc"></connection-status-table>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<div class="refresh-container flex items-center gap-x-2">
|
||||
<button class="nifi-button" (click)="refreshSummaryListing()">
|
||||
<i class="fa fa-refresh" [class.fa-spin]="(summaryListingStatus$ | async) === 'loading'"></i>
|
||||
</button>
|
||||
<div>Last updated:</div>
|
||||
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
||||
</div>
|
||||
<div *ngIf="(currentUser$ | async)?.systemPermissions?.canRead">
|
||||
<a (click)="openSystemDiagnostics()">System Diagnostics</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<connection-status-table
|
||||
[connections]="(connectionStatusSnapshots$ | async)!"
|
||||
[selectedConnectionId]="selectedConnectionId$ | async"
|
||||
[loadedTimestamp]="loadedTimestamp$ | async"
|
||||
[summaryListingStatus]="summaryListingStatus$ | async"
|
||||
(selectConnection)="selectConnection($event)"
|
||||
(clearSelection)="clearSelection()"
|
||||
(viewStatusHistory)="viewStatusHistory($event)"
|
||||
(refresh)="refreshSummaryListing()"
|
||||
initialSortColumn="sourceName"
|
||||
initialSortDirection="asc"></connection-status-table>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
@ -17,18 +17,13 @@
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import {
|
||||
ConnectionStatusSnapshotEntity,
|
||||
PortStatusSnapshotEntity,
|
||||
SummaryListingState
|
||||
} from '../../state/summary-listing';
|
||||
import { ConnectionStatusSnapshotEntity, SummaryListingState } from '../../state/summary-listing';
|
||||
import { initialState } from '../../state/summary-listing/summary-listing.reducer';
|
||||
import * as SummaryListingActions from '../../state/summary-listing/summary-listing.actions';
|
||||
import {
|
||||
selectConnectionIdFromRoute,
|
||||
selectConnectionStatus,
|
||||
selectConnectionStatusSnapshots,
|
||||
selectProcessorStatus,
|
||||
selectSummaryListingLoadedTimestamp,
|
||||
selectSummaryListingStatus,
|
||||
selectViewStatusHistory
|
||||
@ -36,12 +31,8 @@ import {
|
||||
import { selectCurrentUser } from '../../../../state/current-user/current-user.selectors';
|
||||
import { filter, switchMap, take } from 'rxjs';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import {
|
||||
getStatusHistoryAndOpenDialog,
|
||||
openStatusHistoryDialog
|
||||
} from '../../../../state/status-history/status-history.actions';
|
||||
import { getStatusHistoryAndOpenDialog } from '../../../../state/status-history/status-history.actions';
|
||||
import { ComponentType } from '../../../../state/shared';
|
||||
import { getSystemDiagnosticsAndOpenDialog } from '../../../../state/system-diagnostics/system-diagnostics.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'connection-status-listing',
|
||||
@ -101,6 +92,10 @@ export class ConnectionStatusListing {
|
||||
);
|
||||
}
|
||||
|
||||
clearSelection() {
|
||||
this.store.dispatch(SummaryListingActions.clearConnectionStatusSelection());
|
||||
}
|
||||
|
||||
viewStatusHistory(connection: ConnectionStatusSnapshotEntity): void {
|
||||
this.store.dispatch(
|
||||
SummaryListingActions.navigateToViewConnectionStatusHistory({
|
||||
@ -108,14 +103,4 @@ export class ConnectionStatusListing {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
openSystemDiagnostics() {
|
||||
this.store.dispatch(
|
||||
getSystemDiagnosticsAndOpenDialog({
|
||||
request: {
|
||||
nodewise: false
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -21,10 +21,11 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||
import { PortStatusTable } from '../common/port-status-table/port-status-table.component';
|
||||
import { ConnectionStatusTable } from './connection-status-table/connection-status-table.component';
|
||||
import { ProcessorStatusTable } from '../processor-status-listing/processor-status-table/processor-status-table.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ConnectionStatusListing],
|
||||
exports: [ConnectionStatusListing],
|
||||
imports: [CommonModule, NgxSkeletonLoaderModule, PortStatusTable, ConnectionStatusTable]
|
||||
imports: [CommonModule, NgxSkeletonLoaderModule, PortStatusTable, ConnectionStatusTable, ProcessorStatusTable]
|
||||
})
|
||||
export class ConnectionStatusListingModule {}
|
||||
|
@ -14,192 +14,236 @@
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<div class="connection-status-table h-full flex flex-col">
|
||||
<!-- allow filtering of the table -->
|
||||
<summary-table-filter
|
||||
[filteredCount]="filteredCount"
|
||||
[totalCount]="totalCount"
|
||||
[filterableColumns]="filterableColumns"
|
||||
[includeStatusFilter]="false"
|
||||
[includePrimaryNodeOnlyFilter]="false"
|
||||
filterColumn="sourceName"
|
||||
(filterChanged)="applyFilter($event)"></summary-table-filter>
|
||||
<div class="flex flex-col h-full gap-y-2">
|
||||
<div class="flex-1">
|
||||
<ng-container>
|
||||
<div class="connection-status-table h-full flex flex-col">
|
||||
<!-- allow filtering of the table -->
|
||||
<summary-table-filter
|
||||
[filteredCount]="filteredCount"
|
||||
[totalCount]="totalCount"
|
||||
[filterableColumns]="filterableColumns"
|
||||
[includeStatusFilter]="false"
|
||||
[includePrimaryNodeOnlyFilter]="false"
|
||||
filterColumn="sourceName"
|
||||
(filterChanged)="applyFilter($event)"></summary-table-filter>
|
||||
|
||||
<div class="flex-1 relative">
|
||||
<div class="listing-table overflow-y-auto border absolute inset-0">
|
||||
<table
|
||||
mat-table
|
||||
[dataSource]="dataSource"
|
||||
matSort
|
||||
matSortDisableClear
|
||||
(matSortChange)="sortData($event)"
|
||||
[matSortActive]="initialSortColumn"
|
||||
[matSortDirection]="initialSortDirection">
|
||||
<!-- More Details Column -->
|
||||
<ng-container matColumnDef="moreDetails">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item"></td>
|
||||
</ng-container>
|
||||
<div class="flex-1 relative">
|
||||
<div class="listing-table overflow-y-auto border absolute inset-0">
|
||||
<table
|
||||
mat-table
|
||||
[dataSource]="dataSource"
|
||||
matSort
|
||||
matSortDisableClear
|
||||
(matSortChange)="sortData($event)"
|
||||
[matSortActive]="initialSortColumn"
|
||||
[matSortDirection]="initialSortDirection">
|
||||
<!-- More Details Column -->
|
||||
<ng-container matColumnDef="moreDetails">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item"></td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Name</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatName(item)">
|
||||
{{ formatName(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Name</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatName(item)">
|
||||
{{ formatName(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Queued column -->
|
||||
<ng-container matColumnDef="queue">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'queue' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Queue</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'queue' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatQueue(item)">
|
||||
{{ formatQueue(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Queued column -->
|
||||
<ng-container matColumnDef="queue">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'queue' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Queue</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'queue' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatQueue(item)">
|
||||
{{ formatQueue(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Threshold column -->
|
||||
<ng-container matColumnDef="threshold">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Percent of threshold used for count and data size">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span>Threshold %:</span>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'threshold' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Queue</span
|
||||
>
|
||||
<span>|</span>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'threshold' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>Size</span
|
||||
>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatThreshold(item)">
|
||||
{{ formatThreshold(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Threshold column -->
|
||||
<ng-container matColumnDef="threshold">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Percent of threshold used for count and data size">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span>Threshold %:</span>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'threshold' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Queue</span
|
||||
>
|
||||
<span>|</span>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'threshold' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>Size</span
|
||||
>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatThreshold(item)">
|
||||
{{ formatThreshold(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Input column -->
|
||||
<ng-container matColumnDef="in">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span [ngClass]="{ underline: multiSort.active === 'in' && multiSort.sortValueIndex === 0 }"
|
||||
>In</span
|
||||
>
|
||||
<span [ngClass]="{ underline: multiSort.active === 'in' && multiSort.sortValueIndex === 1 }"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatIn(item)">
|
||||
{{ formatIn(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Input column -->
|
||||
<ng-container matColumnDef="in">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'in' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>In</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'in' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatIn(item)">
|
||||
{{ formatIn(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Source Column -->
|
||||
<ng-container matColumnDef="sourceName">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">From Source</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatSource(item)">
|
||||
{{ formatSource(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Source Column -->
|
||||
<ng-container matColumnDef="sourceName">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">
|
||||
From Source
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatSource(item)">
|
||||
{{ formatSource(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Output column -->
|
||||
<ng-container matColumnDef="out">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{ underline: multiSort.active === 'out' && multiSort.sortValueIndex === 0 }"
|
||||
>Out</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{ underline: multiSort.active === 'out' && multiSort.sortValueIndex === 1 }"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatOut(item)">
|
||||
{{ formatOut(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Output column -->
|
||||
<ng-container matColumnDef="out">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'out' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Out</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'out' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatOut(item)">
|
||||
{{ formatOut(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Destination Column -->
|
||||
<ng-container matColumnDef="destinationName">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">To Destination</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatDestination(item)">
|
||||
{{ formatDestination(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Destination Column -->
|
||||
<ng-container matColumnDef="destinationName">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">
|
||||
To Destination
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatDestination(item)">
|
||||
{{ formatDestination(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div
|
||||
class="pointer fa fa-long-arrow-right"
|
||||
[routerLink]="getConnectionLink(item)"
|
||||
(click)="$event.stopPropagation()"
|
||||
title="Go to connection"></div>
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div
|
||||
class="pointer fa fa-long-arrow-right"
|
||||
[routerLink]="getConnectionLink(item)"
|
||||
(click)="$event.stopPropagation()"
|
||||
title="Go to connection"></div>
|
||||
|
||||
<div
|
||||
class="pointer fa fa-area-chart"
|
||||
title="View Status History"
|
||||
(click)="viewStatusHistoryClicked($event, item)"></div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<div
|
||||
class="pointer fa fa-area-chart"
|
||||
title="View Status History"
|
||||
(click)="viewStatusHistoryClicked($event, item)"></div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
|
||||
<tr
|
||||
mat-row
|
||||
*matRowDef="let row; let even = even; columns: displayedColumns"
|
||||
[class.even]="even"
|
||||
(click)="select(row)"
|
||||
[class.selected]="isSelected(row)"></tr>
|
||||
</table>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
|
||||
<tr
|
||||
mat-row
|
||||
*matRowDef="let row; let even = even; columns: displayedColumns"
|
||||
[class.even]="even"
|
||||
(click)="select(row)"
|
||||
[class.selected]="isSelected(row)"></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="flex justify-between align-middle">
|
||||
<div class="refresh-container flex items-center gap-x-2">
|
||||
<button class="nifi-button" (click)="refresh.next()">
|
||||
<i class="fa fa-refresh" [class.fa-spin]="summaryListingStatus === 'loading'"></i>
|
||||
</button>
|
||||
<div>Last updated:</div>
|
||||
<div class="refresh-timestamp">{{ loadedTimestamp }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<mat-paginator
|
||||
[pageSize]="100"
|
||||
[hidePageSize]="true"
|
||||
[showFirstLastButtons]="true"
|
||||
(page)="paginationChanged()"></mat-paginator>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SummaryTableFilterModule } from '../../common/summary-table-filter/summary-table-filter.module';
|
||||
import { MatSortModule, Sort, SortDirection } from '@angular/material/sort';
|
||||
@ -29,13 +29,14 @@ import { ConnectionStatusSnapshot, ConnectionStatusSnapshotEntity } from '../../
|
||||
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
|
||||
import { ComponentType } from '../../../../../state/shared';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
|
||||
|
||||
export type SupportedColumns = 'name' | 'queue' | 'in' | 'out' | 'threshold' | 'sourceName' | 'destinationName';
|
||||
|
||||
@Component({
|
||||
selector: 'connection-status-table',
|
||||
standalone: true,
|
||||
imports: [CommonModule, SummaryTableFilterModule, MatSortModule, RouterLink, MatTableModule],
|
||||
imports: [CommonModule, SummaryTableFilterModule, MatSortModule, RouterLink, MatTableModule, MatPaginatorModule],
|
||||
templateUrl: './connection-status-table.component.html',
|
||||
styleUrls: ['./connection-status-table.component.scss', '../../../../../../assets/styles/listing-table.scss']
|
||||
})
|
||||
@ -49,8 +50,8 @@ export class ConnectionStatusTable {
|
||||
{ key: 'destinationName', label: 'destination' }
|
||||
];
|
||||
|
||||
totalCount: number = 0;
|
||||
filteredCount: number = 0;
|
||||
totalCount = 0;
|
||||
filteredCount = 0;
|
||||
|
||||
multiSort: MultiSort = {
|
||||
active: this._initialSortColumn,
|
||||
@ -73,8 +74,15 @@ export class ConnectionStatusTable {
|
||||
|
||||
dataSource: MatTableDataSource<ConnectionStatusSnapshotEntity> =
|
||||
new MatTableDataSource<ConnectionStatusSnapshotEntity>();
|
||||
|
||||
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||
|
||||
constructor(private nifiCommon: NiFiCommon) {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.dataSource.paginator = this.paginator;
|
||||
}
|
||||
|
||||
@Input() set initialSortColumn(initialSortColumn: SupportedColumns) {
|
||||
this._initialSortColumn = initialSortColumn;
|
||||
this.multiSort = { ...this.multiSort, active: initialSortColumn };
|
||||
@ -116,14 +124,36 @@ export class ConnectionStatusTable {
|
||||
}
|
||||
}
|
||||
|
||||
@Input() summaryListingStatus: string | null = null;
|
||||
@Input() loadedTimestamp: string | null = null;
|
||||
|
||||
@Output() refresh: EventEmitter<void> = new EventEmitter<void>();
|
||||
@Output() viewStatusHistory: EventEmitter<ConnectionStatusSnapshotEntity> =
|
||||
new EventEmitter<ConnectionStatusSnapshotEntity>();
|
||||
@Output() selectConnection: EventEmitter<ConnectionStatusSnapshotEntity> =
|
||||
new EventEmitter<ConnectionStatusSnapshotEntity>();
|
||||
@Output() clearSelection: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
resetPaginator(): void {
|
||||
if (this.dataSource.paginator) {
|
||||
this.dataSource.paginator.firstPage();
|
||||
}
|
||||
}
|
||||
|
||||
applyFilter(filter: SummaryTableFilterArgs) {
|
||||
this.dataSource.filter = JSON.stringify(filter);
|
||||
this.filteredCount = this.dataSource.filteredData.length;
|
||||
this.resetPaginator();
|
||||
this.selectNone();
|
||||
}
|
||||
|
||||
paginationChanged(): void {
|
||||
// clear out any selection
|
||||
this.selectNone();
|
||||
}
|
||||
|
||||
private selectNone() {
|
||||
this.clearSelection.next();
|
||||
}
|
||||
|
||||
getConnectionLink(connection: ConnectionStatusSnapshotEntity): string[] {
|
||||
@ -222,7 +252,7 @@ export class ConnectionStatusTable {
|
||||
}
|
||||
return data.slice().sort((a, b) => {
|
||||
const isAsc: boolean = sort.direction === 'asc';
|
||||
let retVal: number = 0;
|
||||
let retVal = 0;
|
||||
switch (sort.active) {
|
||||
case 'name':
|
||||
retVal = this.nifiCommon.compareString(
|
||||
|
@ -21,30 +21,16 @@
|
||||
</div>
|
||||
|
||||
<ng-template #loaded>
|
||||
<div class="flex flex-col h-full gap-y-2">
|
||||
<div class="flex-1" *ngIf="currentUser$ | async as user">
|
||||
<ng-container>
|
||||
<port-status-table
|
||||
[ports]="(portStatusSnapshots$ | async)!"
|
||||
[selectedPortId]="selectedPortId$ | async"
|
||||
portType="input"
|
||||
(selectPort)="selectPort($event)"
|
||||
initialSortColumn="name"
|
||||
initialSortDirection="asc"></port-status-table>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<div class="refresh-container flex items-center gap-x-2">
|
||||
<button class="nifi-button" (click)="refreshSummaryListing()">
|
||||
<i class="fa fa-refresh" [class.fa-spin]="(summaryListingStatus$ | async) === 'loading'"></i>
|
||||
</button>
|
||||
<div>Last updated:</div>
|
||||
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
||||
</div>
|
||||
<div *ngIf="(currentUser$ | async)?.systemPermissions?.canRead">
|
||||
<a (click)="openSystemDiagnostics()">System Diagnostics</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<port-status-table
|
||||
[ports]="(portStatusSnapshots$ | async)!"
|
||||
[selectedPortId]="selectedPortId$ | async"
|
||||
[loadedTimestamp]="loadedTimestamp$ | async"
|
||||
[summaryListingStatus]="summaryListingStatus$ | async"
|
||||
portType="input"
|
||||
(selectPort)="selectPort($event)"
|
||||
(clearSelection)="clearSelection()"
|
||||
(refresh)="refreshSummaryListing()"
|
||||
initialSortColumn="name"
|
||||
initialSortDirection="asc"></port-status-table>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
@ -27,7 +27,6 @@ import { PortStatusSnapshotEntity, SummaryListingState } from '../../state/summa
|
||||
import { Store } from '@ngrx/store';
|
||||
import { initialState } from '../../state/summary-listing/summary-listing.reducer';
|
||||
import * as SummaryListingActions from '../../state/summary-listing/summary-listing.actions';
|
||||
import { getSystemDiagnosticsAndOpenDialog } from '../../../../state/system-diagnostics/system-diagnostics.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'input-port-status-listing',
|
||||
@ -61,13 +60,7 @@ export class InputPortStatusListing {
|
||||
);
|
||||
}
|
||||
|
||||
openSystemDiagnostics() {
|
||||
this.store.dispatch(
|
||||
getSystemDiagnosticsAndOpenDialog({
|
||||
request: {
|
||||
nodewise: false
|
||||
}
|
||||
})
|
||||
);
|
||||
clearSelection() {
|
||||
this.store.dispatch(SummaryListingActions.clearInputPortStatusSelection());
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,10 @@ import { InputPortStatusListing } from './input-port-status-listing.component';
|
||||
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||
import { ProcessGroupStatusTable } from '../process-group-status-listing/process-group-status-table/process-group-status-table.component';
|
||||
import { PortStatusTable } from '../common/port-status-table/port-status-table.component';
|
||||
import { ProcessorStatusTable } from '../processor-status-listing/processor-status-table/processor-status-table.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [InputPortStatusListing],
|
||||
imports: [CommonModule, NgxSkeletonLoaderModule, ProcessGroupStatusTable, PortStatusTable]
|
||||
imports: [CommonModule, NgxSkeletonLoaderModule, ProcessGroupStatusTable, PortStatusTable, ProcessorStatusTable]
|
||||
})
|
||||
export class InputPortStatusListingModule {}
|
||||
|
@ -21,30 +21,16 @@
|
||||
</div>
|
||||
|
||||
<ng-template #loaded>
|
||||
<div class="flex flex-col h-full gap-y-2">
|
||||
<div class="flex-1" *ngIf="currentUser$ | async as user">
|
||||
<ng-container>
|
||||
<port-status-table
|
||||
[ports]="(portStatusSnapshots$ | async)!"
|
||||
[selectedPortId]="selectedPortId$ | async"
|
||||
portType="output"
|
||||
(selectPort)="selectPort($event)"
|
||||
initialSortColumn="name"
|
||||
initialSortDirection="asc"></port-status-table>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<div class="refresh-container flex items-center gap-x-2">
|
||||
<button class="nifi-button" (click)="refreshSummaryListing()">
|
||||
<i class="fa fa-refresh" [class.fa-spin]="(summaryListingStatus$ | async) === 'loading'"></i>
|
||||
</button>
|
||||
<div>Last updated:</div>
|
||||
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
||||
</div>
|
||||
<div *ngIf="(currentUser$ | async)?.systemPermissions?.canRead">
|
||||
<a (click)="openSystemDiagnostics()">System Diagnostics</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<port-status-table
|
||||
[ports]="(portStatusSnapshots$ | async)!"
|
||||
[selectedPortId]="selectedPortId$ | async"
|
||||
[loadedTimestamp]="loadedTimestamp$ | async"
|
||||
[summaryListingStatus]="summaryListingStatus$ | async"
|
||||
portType="output"
|
||||
(selectPort)="selectPort($event)"
|
||||
(clearSelection)="clearSelection()"
|
||||
(refresh)="refreshSummaryListing()"
|
||||
initialSortColumn="name"
|
||||
initialSortDirection="asc"></port-status-table>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
@ -17,8 +17,6 @@
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import {
|
||||
selectInputPortIdFromRoute,
|
||||
selectInputPortStatusSnapshots,
|
||||
selectOutputPortIdFromRoute,
|
||||
selectOutputPortStatusSnapshots,
|
||||
selectSummaryListingLoadedTimestamp,
|
||||
@ -29,7 +27,6 @@ import { Store } from '@ngrx/store';
|
||||
import { PortStatusSnapshotEntity, SummaryListingState } from '../../state/summary-listing';
|
||||
import { initialState } from '../../state/summary-listing/summary-listing.reducer';
|
||||
import * as SummaryListingActions from '../../state/summary-listing/summary-listing.actions';
|
||||
import { getSystemDiagnosticsAndOpenDialog } from '../../../../state/system-diagnostics/system-diagnostics.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'output-port-status-listing',
|
||||
@ -63,13 +60,7 @@ export class OutputPortStatusListing {
|
||||
);
|
||||
}
|
||||
|
||||
openSystemDiagnostics() {
|
||||
this.store.dispatch(
|
||||
getSystemDiagnosticsAndOpenDialog({
|
||||
request: {
|
||||
nodewise: false
|
||||
}
|
||||
})
|
||||
);
|
||||
clearSelection() {
|
||||
this.store.dispatch(SummaryListingActions.clearOutputPortStatusSelection());
|
||||
}
|
||||
}
|
||||
|
@ -20,10 +20,11 @@ import { CommonModule } from '@angular/common';
|
||||
import { OutputPortStatusListing } from './output-port-status-listing.component';
|
||||
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||
import { PortStatusTable } from '../common/port-status-table/port-status-table.component';
|
||||
import { ProcessorStatusTable } from '../processor-status-listing/processor-status-table/processor-status-table.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [OutputPortStatusListing],
|
||||
exports: [OutputPortStatusListing],
|
||||
imports: [CommonModule, NgxSkeletonLoaderModule, PortStatusTable]
|
||||
imports: [CommonModule, NgxSkeletonLoaderModule, PortStatusTable, ProcessorStatusTable]
|
||||
})
|
||||
export class OutputPortStatusListingModule {}
|
||||
|
@ -21,31 +21,17 @@
|
||||
</div>
|
||||
|
||||
<ng-template #loaded>
|
||||
<div class="flex flex-col h-full gap-y-2">
|
||||
<div class="flex-1" *ngIf="currentUser$ | async as user">
|
||||
<ng-container>
|
||||
<process-group-status-table
|
||||
[processGroups]="(processGroupStatusSnapshots$ | async)!"
|
||||
[selectedProcessGroupId]="selectedProcessGroupId$ | async"
|
||||
[rootProcessGroup]="(processGroupStatus$ | async)?.processGroupStatus?.aggregateSnapshot!"
|
||||
(viewStatusHistory)="viewStatusHistory($event)"
|
||||
(selectProcessGroup)="selectProcessGroup($event)"
|
||||
initialSortColumn="name"
|
||||
initialSortDirection="asc"></process-group-status-table>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<div class="refresh-container flex items-center gap-x-2">
|
||||
<button class="nifi-button" (click)="refreshSummaryListing()">
|
||||
<i class="fa fa-refresh" [class.fa-spin]="(summaryListingStatus$ | async) === 'loading'"></i>
|
||||
</button>
|
||||
<div>Last updated:</div>
|
||||
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
||||
</div>
|
||||
<div *ngIf="(currentUser$ | async)?.systemPermissions?.canRead">
|
||||
<a (click)="openSystemDiagnostics()">System Diagnostics</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<process-group-status-table
|
||||
[processGroups]="(processGroupStatusSnapshots$ | async)!"
|
||||
[selectedProcessGroupId]="selectedProcessGroupId$ | async"
|
||||
[rootProcessGroup]="(processGroupStatus$ | async)?.processGroupStatus?.aggregateSnapshot!"
|
||||
[loadedTimestamp]="loadedTimestamp$ | async"
|
||||
[summaryListingStatus]="summaryListingStatus$ | async"
|
||||
(viewStatusHistory)="viewStatusHistory($event)"
|
||||
(selectProcessGroup)="selectProcessGroup($event)"
|
||||
(clearSelection)="clearSelection()"
|
||||
(refresh)="refreshSummaryListing()"
|
||||
initialSortColumn="name"
|
||||
initialSortDirection="asc"></process-group-status-table>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
@ -18,32 +18,22 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { initialState } from '../../state/summary-listing/summary-listing.reducer';
|
||||
import * as SummaryListingActions from '../../state/summary-listing/summary-listing.actions';
|
||||
import {
|
||||
ProcessGroupStatusSnapshotEntity,
|
||||
ProcessorStatusSnapshotEntity,
|
||||
SummaryListingState
|
||||
} from '../../state/summary-listing';
|
||||
import { ProcessGroupStatusSnapshotEntity, SummaryListingState } from '../../state/summary-listing';
|
||||
import { Store } from '@ngrx/store';
|
||||
import {
|
||||
selectProcessGroupIdFromRoute,
|
||||
selectProcessGroupStatus,
|
||||
selectProcessGroupStatusItem,
|
||||
selectProcessGroupStatusSnapshots,
|
||||
selectProcessorStatus,
|
||||
selectProcessorStatusSnapshots,
|
||||
selectSummaryListingLoadedTimestamp,
|
||||
selectSummaryListingStatus,
|
||||
selectViewStatusHistory
|
||||
} from '../../state/summary-listing/summary-listing.selectors';
|
||||
import { filter, switchMap, take } from 'rxjs';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import {
|
||||
getStatusHistoryAndOpenDialog,
|
||||
openStatusHistoryDialog
|
||||
} from '../../../../state/status-history/status-history.actions';
|
||||
import { getStatusHistoryAndOpenDialog } from '../../../../state/status-history/status-history.actions';
|
||||
import { ComponentType } from '../../../../state/shared';
|
||||
import { selectCurrentUser } from '../../../../state/current-user/current-user.selectors';
|
||||
import { getSystemDiagnosticsAndOpenDialog } from '../../../../state/system-diagnostics/system-diagnostics.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'process-group-status-listing',
|
||||
@ -112,13 +102,7 @@ export class ProcessGroupStatusListing {
|
||||
);
|
||||
}
|
||||
|
||||
openSystemDiagnostics() {
|
||||
this.store.dispatch(
|
||||
getSystemDiagnosticsAndOpenDialog({
|
||||
request: {
|
||||
nodewise: false
|
||||
}
|
||||
})
|
||||
);
|
||||
clearSelection() {
|
||||
this.store.dispatch(SummaryListingActions.clearProcessGroupStatusSelection());
|
||||
}
|
||||
}
|
||||
|
@ -14,300 +14,363 @@
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<div class="process-group-status-table h-full flex flex-col">
|
||||
<!-- allow filtering of the table -->
|
||||
<summary-table-filter
|
||||
[filteredCount]="filteredCount"
|
||||
[totalCount]="totalCount"
|
||||
[filterableColumns]="filterableColumns"
|
||||
[includeStatusFilter]="false"
|
||||
[includePrimaryNodeOnlyFilter]="false"
|
||||
(filterChanged)="applyFilter($event)"></summary-table-filter>
|
||||
<div class="flex flex-col h-full gap-y-2">
|
||||
<div class="flex-1">
|
||||
<ng-container>
|
||||
<div class="process-group-status-table h-full flex flex-col">
|
||||
<!-- allow filtering of the table -->
|
||||
<summary-table-filter
|
||||
[filteredCount]="filteredCount"
|
||||
[totalCount]="totalCount"
|
||||
[filterableColumns]="filterableColumns"
|
||||
[includeStatusFilter]="false"
|
||||
[includePrimaryNodeOnlyFilter]="false"
|
||||
(filterChanged)="applyFilter($event)"></summary-table-filter>
|
||||
|
||||
<div class="flex-1 relative">
|
||||
<div class="listing-table overflow-y-auto border absolute inset-0">
|
||||
<table
|
||||
mat-table
|
||||
[dataSource]="dataSource"
|
||||
matSort
|
||||
matSortDisableClear
|
||||
(matSortChange)="sortData($event)"
|
||||
[matSortActive]="initialSortColumn"
|
||||
[matSortDirection]="initialSortDirection">
|
||||
<!-- More Details Column -->
|
||||
<ng-container matColumnDef="moreDetails">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<ng-container *ngIf="canRead(item)">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<!-- TODO - handle read only in configure component? -->
|
||||
<div
|
||||
class="pointer fa fa-info-circle"
|
||||
*ngIf="canRead(item)"
|
||||
title="View Process Group Details"></div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
<div class="flex-1 relative">
|
||||
<div class="listing-table overflow-y-auto border absolute inset-0">
|
||||
<table
|
||||
mat-table
|
||||
[dataSource]="dataSource"
|
||||
matSort
|
||||
matSortDisableClear
|
||||
(matSortChange)="sortData($event)"
|
||||
[matSortActive]="initialSortColumn"
|
||||
[matSortDirection]="initialSortDirection">
|
||||
<!-- More Details Column -->
|
||||
<ng-container matColumnDef="moreDetails">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<ng-container *ngIf="canRead(item)">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<!-- TODO - handle read only in configure component? -->
|
||||
<div
|
||||
class="pointer fa fa-info-circle"
|
||||
*ngIf="canRead(item)"
|
||||
title="View Process Group Details"></div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Name</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatName(item)">
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">
|
||||
{{ formatName(item) }}
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Name</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatName(item)">
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">
|
||||
{{ formatName(item) }}
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Version State column -->
|
||||
<ng-container matColumnDef="versionedFlowState">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Version State</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="flex items-center gap-x-1.5" [title]="formatVersionedFlowState(item)">
|
||||
<div [ngClass]="getVersionedFlowStateIcon(item)"></div>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap min-w-0">
|
||||
{{ formatVersionedFlowState(item) }}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Version State column -->
|
||||
<ng-container matColumnDef="versionedFlowState">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">
|
||||
Version State
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="flex items-center gap-x-1.5" [title]="formatVersionedFlowState(item)">
|
||||
<div [ngClass]="getVersionedFlowStateIcon(item)"></div>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap min-w-0">
|
||||
{{ formatVersionedFlowState(item) }}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Transferred column -->
|
||||
<ng-container matColumnDef="transferred">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1"
|
||||
title="Count / data size transferred to and from connections in the last 5 min">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'transferred' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Transferred</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'transferred' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatTransferred(item)">
|
||||
{{ formatTransferred(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Transferred column -->
|
||||
<ng-container matColumnDef="transferred">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1"
|
||||
title="Count / data size transferred to and from connections in the last 5 min">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'transferred' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Transferred</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'transferred' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatTransferred(item)">
|
||||
{{ formatTransferred(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Input column -->
|
||||
<ng-container matColumnDef="in">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span [ngClass]="{ underline: multiSort.active === 'in' && multiSort.sortValueIndex === 0 }"
|
||||
>In</span
|
||||
>
|
||||
<span [ngClass]="{ underline: multiSort.active === 'in' && multiSort.sortValueIndex === 1 }"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatIn(item)">
|
||||
{{ formatIn(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Input column -->
|
||||
<ng-container matColumnDef="in">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'in' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>In</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'in' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatIn(item)">
|
||||
{{ formatIn(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Read Write column -->
|
||||
<ng-container matColumnDef="readWrite">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header title="Data size in the last 5 minutes">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'readWrite' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Read</span
|
||||
>
|
||||
<span>|</span>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'readWrite' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>Write</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatReadWrite(item)">
|
||||
{{ formatReadWrite(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Read Write column -->
|
||||
<ng-container matColumnDef="readWrite">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Data size in the last 5 minutes">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'readWrite' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Read</span
|
||||
>
|
||||
<span>|</span>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'readWrite' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>Write</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatReadWrite(item)">
|
||||
{{ formatReadWrite(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Output column -->
|
||||
<ng-container matColumnDef="out">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{ underline: multiSort.active === 'out' && multiSort.sortValueIndex === 0 }"
|
||||
>Out</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{ underline: multiSort.active === 'out' && multiSort.sortValueIndex === 1 }"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatOut(item)">
|
||||
{{ formatOut(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Output column -->
|
||||
<ng-container matColumnDef="out">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'out' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Out</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'out' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatOut(item)">
|
||||
{{ formatOut(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Sent column -->
|
||||
<ng-container matColumnDef="sent">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{ underline: multiSort.active === 'sent' && multiSort.sortValueIndex === 0 }"
|
||||
>Sent</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{ underline: multiSort.active === 'sent' && multiSort.sortValueIndex === 1 }"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatSent(item)">
|
||||
{{ formatSent(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Sent column -->
|
||||
<ng-container matColumnDef="sent">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'sent' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Sent</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'sent' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatSent(item)">
|
||||
{{ formatSent(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Received column -->
|
||||
<ng-container matColumnDef="received">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'received' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Received</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'received' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatReceived(item)">
|
||||
{{ formatReceived(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Received column -->
|
||||
<ng-container matColumnDef="received">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'received' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Received</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'received' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatReceived(item)">
|
||||
{{ formatReceived(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Received column -->
|
||||
<ng-container matColumnDef="activeThreads">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Total active thread count within ProcessGroup (% of total active thread count compared to overall active thread count in root ProcessGroup) in the last 5 min">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'activeThreads' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Active Threads</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'activeThreads' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(%)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatActiveThreads(item)">
|
||||
{{ formatActiveThreads(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Received column -->
|
||||
<ng-container matColumnDef="activeThreads">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Total active thread count within ProcessGroup (% of total active thread count compared to overall active thread count in root ProcessGroup) in the last 5 min">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'activeThreads' &&
|
||||
multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Active Threads</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'activeThreads' &&
|
||||
multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(%)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatActiveThreads(item)">
|
||||
{{ formatActiveThreads(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Tasks column -->
|
||||
<ng-container matColumnDef="tasks">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Total task duration within ProcessGroup (% of total task duration compared to overall task duration in root ProcessGroup) in the last 5 min">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'tasks' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Total Task Duration</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'tasks' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(%)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatTasks(item)">
|
||||
{{ formatTasks(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Tasks column -->
|
||||
<ng-container matColumnDef="tasks">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Total task duration within ProcessGroup (% of total task duration compared to overall task duration in root ProcessGroup) in the last 5 min">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'tasks' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Total Task Duration</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'tasks' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(%)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatTasks(item)">
|
||||
{{ formatTasks(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div
|
||||
class="pointer fa fa-long-arrow-right"
|
||||
[routerLink]="getProcessGroupLink(item)"
|
||||
(click)="$event.stopPropagation()"
|
||||
title="Go to Process Group {{ item?.processGroupStatusSnapshot?.name }}"></div>
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div
|
||||
class="pointer fa fa-long-arrow-right"
|
||||
[routerLink]="getProcessGroupLink(item)"
|
||||
(click)="$event.stopPropagation()"
|
||||
title="Go to Process Group {{
|
||||
item?.processGroupStatusSnapshot?.name
|
||||
}}"></div>
|
||||
|
||||
<div
|
||||
class="pointer fa fa-area-chart"
|
||||
title="View Status History"
|
||||
(click)="viewStatusHistoryClicked($event, item)"></div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<div
|
||||
class="pointer fa fa-area-chart"
|
||||
title="View Status History"
|
||||
(click)="viewStatusHistoryClicked($event, item)"></div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
|
||||
<tr
|
||||
mat-row
|
||||
*matRowDef="let row; let even = even; columns: displayedColumns"
|
||||
[class.even]="even"
|
||||
(click)="select(row)"
|
||||
[class.selected]="isSelected(row)"></tr>
|
||||
</table>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
|
||||
<tr
|
||||
mat-row
|
||||
*matRowDef="let row; let even = even; columns: displayedColumns"
|
||||
[class.even]="even"
|
||||
(click)="select(row)"
|
||||
[class.selected]="isSelected(row)"></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="flex justify-between align-middle">
|
||||
<div class="refresh-container flex items-center gap-x-2">
|
||||
<button class="nifi-button" (click)="refresh.next()">
|
||||
<i class="fa fa-refresh" [class.fa-spin]="summaryListingStatus === 'loading'"></i>
|
||||
</button>
|
||||
<div>Last updated:</div>
|
||||
<div class="refresh-timestamp">{{ loadedTimestamp }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<mat-paginator
|
||||
[pageSize]="100"
|
||||
[hidePageSize]="true"
|
||||
[showFirstLastButtons]="true"
|
||||
(page)="paginationChanged()"></mat-paginator>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -15,25 +15,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { AfterViewInit, Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatSortModule, Sort, SortDirection } from '@angular/material/sort';
|
||||
import { MultiSort } from '../../common';
|
||||
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
|
||||
import { SummaryTableFilterModule } from '../../common/summary-table-filter/summary-table-filter.module';
|
||||
import {
|
||||
ProcessGroupStatusSnapshot,
|
||||
ProcessGroupStatusSnapshotEntity,
|
||||
ProcessorStatusSnapshot,
|
||||
ProcessorStatusSnapshotEntity,
|
||||
VersionedFlowState
|
||||
} from '../../../state/summary-listing';
|
||||
import { ProcessGroupStatusSnapshot, ProcessGroupStatusSnapshotEntity } from '../../../state/summary-listing';
|
||||
import {
|
||||
SummaryTableFilterArgs,
|
||||
SummaryTableFilterColumn
|
||||
} from '../../common/summary-table-filter/summary-table-filter.component';
|
||||
import { NiFiCommon } from '../../../../../service/nifi-common.service';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
|
||||
|
||||
export type SupportedColumns =
|
||||
| 'name'
|
||||
@ -50,17 +45,17 @@ export type SupportedColumns =
|
||||
@Component({
|
||||
selector: 'process-group-status-table',
|
||||
standalone: true,
|
||||
imports: [CommonModule, MatSortModule, MatTableModule, SummaryTableFilterModule, RouterLink],
|
||||
imports: [CommonModule, MatSortModule, MatTableModule, SummaryTableFilterModule, RouterLink, MatPaginatorModule],
|
||||
templateUrl: './process-group-status-table.component.html',
|
||||
styleUrls: ['./process-group-status-table.component.scss', '../../../../../../assets/styles/listing-table.scss']
|
||||
})
|
||||
export class ProcessGroupStatusTable {
|
||||
export class ProcessGroupStatusTable implements AfterViewInit {
|
||||
private _initialSortColumn: SupportedColumns = 'name';
|
||||
private _initialSortDirection: SortDirection = 'asc';
|
||||
|
||||
filterableColumns: SummaryTableFilterColumn[] = [{ key: 'name', label: 'name' }];
|
||||
totalCount: number = 0;
|
||||
filteredCount: number = 0;
|
||||
totalCount = 0;
|
||||
filteredCount = 0;
|
||||
|
||||
multiSort: MultiSort = {
|
||||
active: this._initialSortColumn,
|
||||
@ -92,6 +87,8 @@ export class ProcessGroupStatusTable {
|
||||
applyFilter(filter: SummaryTableFilterArgs) {
|
||||
this.dataSource.filter = JSON.stringify(filter);
|
||||
this.filteredCount = this.dataSource.filteredData.length;
|
||||
this.resetPaginator();
|
||||
this.selectNone();
|
||||
}
|
||||
|
||||
@Input() selectedProcessGroupId!: string;
|
||||
@ -138,10 +135,32 @@ export class ProcessGroupStatusTable {
|
||||
}
|
||||
}
|
||||
|
||||
@Input() summaryListingStatus: string | null = null;
|
||||
@Input() loadedTimestamp: string | null = null;
|
||||
|
||||
@Output() viewStatusHistory: EventEmitter<ProcessGroupStatusSnapshotEntity> =
|
||||
new EventEmitter<ProcessGroupStatusSnapshotEntity>();
|
||||
@Output() selectProcessGroup: EventEmitter<ProcessGroupStatusSnapshotEntity> =
|
||||
new EventEmitter<ProcessGroupStatusSnapshotEntity>();
|
||||
@Output() clearSelection: EventEmitter<void> = new EventEmitter<void>();
|
||||
@Output() refresh: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.dataSource.paginator = this.paginator;
|
||||
}
|
||||
|
||||
resetPaginator(): void {
|
||||
if (this.dataSource.paginator) {
|
||||
this.dataSource.paginator.firstPage();
|
||||
}
|
||||
}
|
||||
|
||||
paginationChanged(): void {
|
||||
// clear out any selection
|
||||
this.selectNone();
|
||||
}
|
||||
|
||||
formatName(pg: ProcessGroupStatusSnapshotEntity): string {
|
||||
return pg.processGroupStatusSnapshot.name;
|
||||
@ -169,6 +188,7 @@ export class ProcessGroupStatusTable {
|
||||
label: 'Sync failure'
|
||||
}
|
||||
};
|
||||
|
||||
formatVersionedFlowState(pg: ProcessGroupStatusSnapshotEntity): string {
|
||||
if (!pg.processGroupStatusSnapshot.versionedFlowState) {
|
||||
return '';
|
||||
@ -280,8 +300,8 @@ export class ProcessGroupStatusTable {
|
||||
return [];
|
||||
}
|
||||
|
||||
let aggregateDuration: number = 0;
|
||||
let aggregateActiveThreads: number = 0;
|
||||
let aggregateDuration = 0;
|
||||
let aggregateActiveThreads = 0;
|
||||
if (this.rootProcessGroup) {
|
||||
aggregateDuration = this.rootProcessGroup.processingNanos;
|
||||
aggregateActiveThreads = this.rootProcessGroup.activeThreadCount;
|
||||
@ -289,7 +309,7 @@ export class ProcessGroupStatusTable {
|
||||
|
||||
return data.slice().sort((a, b) => {
|
||||
const isAsc = sort.direction === 'asc';
|
||||
let retVal: number = 0;
|
||||
let retVal = 0;
|
||||
switch (sort.active) {
|
||||
case 'name':
|
||||
retVal = this.nifiCommon.compareString(this.formatName(a), this.formatName(b));
|
||||
@ -422,6 +442,7 @@ export class ProcessGroupStatusTable {
|
||||
select(pg: ProcessGroupStatusSnapshotEntity): void {
|
||||
this.selectProcessGroup.next(pg);
|
||||
}
|
||||
|
||||
isSelected(pg: ProcessGroupStatusSnapshotEntity): boolean {
|
||||
if (this.selectedProcessGroupId) {
|
||||
return pg.id === this.selectedProcessGroupId;
|
||||
@ -433,4 +454,8 @@ export class ProcessGroupStatusTable {
|
||||
event.stopPropagation();
|
||||
this.viewStatusHistory.next(pg);
|
||||
}
|
||||
|
||||
private selectNone() {
|
||||
this.clearSelection.next();
|
||||
}
|
||||
}
|
||||
|
@ -20,30 +20,16 @@
|
||||
</div>
|
||||
|
||||
<ng-template #loaded>
|
||||
<div class="flex flex-col h-full gap-y-2">
|
||||
<div class="flex-1" *ngIf="currentUser$ | async as user">
|
||||
<ng-container>
|
||||
<processor-status-table
|
||||
[processors]="(processorStatusSnapshots$ | async)!"
|
||||
[selectedProcessorId]="selectedProcessorId$ | async"
|
||||
(viewStatusHistory)="viewStatusHistory($event)"
|
||||
(selectProcessor)="selectProcessor($event)"
|
||||
initialSortColumn="name"
|
||||
initialSortDirection="asc"></processor-status-table>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<div class="refresh-container flex items-center gap-x-2">
|
||||
<button class="nifi-button" (click)="refreshSummaryListing()">
|
||||
<i class="fa fa-refresh" [class.fa-spin]="(summaryListingStatus$ | async) === 'loading'"></i>
|
||||
</button>
|
||||
<div>Last updated:</div>
|
||||
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
||||
</div>
|
||||
<div *ngIf="(currentUser$ | async)?.systemPermissions?.canRead">
|
||||
<a (click)="openSystemDiagnostics()">System Diagnostics</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<processor-status-table
|
||||
[processors]="(processorStatusSnapshots$ | async)!"
|
||||
[selectedProcessorId]="selectedProcessorId$ | async"
|
||||
[loadedTimestamp]="loadedTimestamp$ | async"
|
||||
[summaryListingStatus]="summaryListingStatus$ | async"
|
||||
(viewStatusHistory)="viewStatusHistory($event)"
|
||||
(selectProcessor)="selectProcessor($event)"
|
||||
(clearSelection)="clearSelection()"
|
||||
(refresh)="refreshSummaryListing()"
|
||||
initialSortColumn="name"
|
||||
initialSortDirection="asc"></processor-status-table>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { AfterViewInit, Component, ViewChild } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import {
|
||||
selectProcessorIdFromRoute,
|
||||
@ -28,14 +28,13 @@ import {
|
||||
import { ProcessorStatusSnapshotEntity, SummaryListingState } from '../../state/summary-listing';
|
||||
import { selectCurrentUser } from '../../../../state/current-user/current-user.selectors';
|
||||
import { initialState } from '../../state/summary-listing/summary-listing.reducer';
|
||||
import {
|
||||
getStatusHistoryAndOpenDialog,
|
||||
openStatusHistoryDialog
|
||||
} from '../../../../state/status-history/status-history.actions';
|
||||
import { getStatusHistoryAndOpenDialog } from '../../../../state/status-history/status-history.actions';
|
||||
import { ComponentType } from '../../../../state/shared';
|
||||
import { filter, switchMap, take } from 'rxjs';
|
||||
import { combineLatest, delay, filter, Subject, switchMap, take } from 'rxjs';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import * as SummaryListingActions from '../../state/summary-listing/summary-listing.actions';
|
||||
import { MatPaginator } from '@angular/material/paginator';
|
||||
import { ProcessorStatusTable } from './processor-status-table/processor-status-table.component';
|
||||
import { getSystemDiagnosticsAndOpenDialog } from '../../../../state/system-diagnostics/system-diagnostics.actions';
|
||||
|
||||
@Component({
|
||||
@ -43,7 +42,7 @@ import { getSystemDiagnosticsAndOpenDialog } from '../../../../state/system-diag
|
||||
templateUrl: './processor-status-listing.component.html',
|
||||
styleUrls: ['./processor-status-listing.component.scss']
|
||||
})
|
||||
export class ProcessorStatusListing {
|
||||
export class ProcessorStatusListing implements AfterViewInit {
|
||||
processorStatusSnapshots$ = this.store.select(selectProcessorStatusSnapshots);
|
||||
loadedTimestamp$ = this.store.select(selectSummaryListingLoadedTimestamp);
|
||||
summaryListingStatus$ = this.store.select(selectSummaryListingStatus);
|
||||
@ -51,6 +50,10 @@ export class ProcessorStatusListing {
|
||||
|
||||
currentUser$ = this.store.select(selectCurrentUser);
|
||||
|
||||
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||
@ViewChild(ProcessorStatusTable) table!: ProcessorStatusTable;
|
||||
private subject: Subject<void> = new Subject<void>();
|
||||
|
||||
constructor(private store: Store<SummaryListingState>) {
|
||||
this.store
|
||||
.select(selectViewStatusHistory)
|
||||
@ -79,6 +82,23 @@ export class ProcessorStatusListing {
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
combineLatest([this.processorStatusSnapshots$, this.loadedTimestamp$])
|
||||
.pipe(
|
||||
filter(([processors, ts]) => !!processors && !this.isInitialLoading(ts)),
|
||||
delay(0)
|
||||
)
|
||||
.subscribe(() => {
|
||||
this.subject.next();
|
||||
});
|
||||
|
||||
this.subject.subscribe(() => {
|
||||
if (this.table) {
|
||||
this.table.paginator = this.paginator;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
isInitialLoading(loadedTimestamp: string): boolean {
|
||||
return loadedTimestamp == initialState.loadedTimestamp;
|
||||
}
|
||||
@ -105,13 +125,7 @@ export class ProcessorStatusListing {
|
||||
);
|
||||
}
|
||||
|
||||
openSystemDiagnostics() {
|
||||
this.store.dispatch(
|
||||
getSystemDiagnosticsAndOpenDialog({
|
||||
request: {
|
||||
nodewise: false
|
||||
}
|
||||
})
|
||||
);
|
||||
clearSelection() {
|
||||
this.store.dispatch(SummaryListingActions.clearProcessorStatusSelection());
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,9 @@ import { RouterLink } from '@angular/router';
|
||||
import { NifiTooltipDirective } from '../../../../ui/common/tooltips/nifi-tooltip.directive';
|
||||
import { SummaryTableFilterModule } from '../common/summary-table-filter/summary-table-filter.module';
|
||||
import { ProcessorStatusTable } from './processor-status-table/processor-status-table.component';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { ProcessGroupStatusTable } from '../process-group-status-listing/process-group-status-table/process-group-status-table.component';
|
||||
import { RemoteProcessGroupStatusTable } from '../remote-process-group-status-listing/remote-process-group-status-table/remote-process-group-status-table.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ProcessorStatusListing],
|
||||
@ -49,7 +52,10 @@ import { ProcessorStatusTable } from './processor-status-table/processor-status-
|
||||
RouterLink,
|
||||
NifiTooltipDirective,
|
||||
SummaryTableFilterModule,
|
||||
ProcessorStatusTable
|
||||
ProcessorStatusTable,
|
||||
MatPaginatorModule,
|
||||
ProcessGroupStatusTable,
|
||||
RemoteProcessGroupStatusTable
|
||||
]
|
||||
})
|
||||
export class ProcessorStatusListingModule {}
|
||||
|
@ -14,224 +14,271 @@
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<div class="processor-status-table h-full flex flex-col">
|
||||
<!-- allow filtering of the table -->
|
||||
<summary-table-filter
|
||||
[filteredCount]="filteredCount"
|
||||
[totalCount]="totalCount"
|
||||
[filterableColumns]="filterableColumns"
|
||||
[includeStatusFilter]="true"
|
||||
[includePrimaryNodeOnlyFilter]="true"
|
||||
(filterChanged)="applyFilter($event)"></summary-table-filter>
|
||||
<div class="flex flex-col h-full gap-y-2">
|
||||
<div class="flex-1">
|
||||
<ng-container>
|
||||
<div class="processor-status-table h-full flex flex-col">
|
||||
<!-- allow filtering of the table -->
|
||||
<summary-table-filter
|
||||
[filteredCount]="filteredCount"
|
||||
[totalCount]="totalCount"
|
||||
[filterableColumns]="filterableColumns"
|
||||
[includeStatusFilter]="true"
|
||||
[includePrimaryNodeOnlyFilter]="true"
|
||||
(filterChanged)="applyFilter($event)"></summary-table-filter>
|
||||
|
||||
<div class="flex-1 relative">
|
||||
<div class="listing-table overflow-y-auto border absolute inset-0">
|
||||
<table
|
||||
mat-table
|
||||
[dataSource]="dataSource"
|
||||
matSort
|
||||
matSortDisableClear
|
||||
(matSortChange)="sortData($event)"
|
||||
[matSortActive]="initialSortColumn"
|
||||
[matSortDirection]="initialSortDirection">
|
||||
<!-- More Details Column -->
|
||||
<ng-container matColumnDef="moreDetails">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<ng-container *ngIf="canRead(item)">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<!-- TODO - handle read only in configure component? -->
|
||||
<div
|
||||
class="pointer fa fa-info-circle"
|
||||
*ngIf="canRead(item)"
|
||||
title="View Processor Details"></div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Name</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatName(item)">
|
||||
{{ formatName(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Type column -->
|
||||
<ng-container matColumnDef="type">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Type</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatType(item)">
|
||||
{{ formatType(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Process Group column -->
|
||||
<ng-container matColumnDef="processGroup">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Process Group</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatProcessGroup(item)">
|
||||
{{ formatProcessGroup(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Run Status column -->
|
||||
<ng-container matColumnDef="runStatus">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Run Status</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1.5">
|
||||
<span [ngClass]="getRunStatusIcon(item)"></span>
|
||||
<span [title]="formatRunStatus(item)">{{ formatRunStatus(item) }}</span>
|
||||
|
||||
<ng-container *ngIf="item.processorStatusSnapshot as pg">
|
||||
<span
|
||||
*ngIf="pg.terminatedThreadCount > 0; else activeThreads"
|
||||
title="Threads: (Active / Terminated)"
|
||||
>({{ pg.activeThreadCount }}/{{ pg.terminatedThreadCount }})</span
|
||||
>
|
||||
<ng-template #activeThreads>
|
||||
<span *ngIf="pg.activeThreadCount > 0" title="Active Threads"
|
||||
>({{ pg.activeThreadCount }})</span
|
||||
>
|
||||
</ng-template>
|
||||
<div class="flex-1 relative">
|
||||
<div class="listing-table overflow-y-auto border absolute inset-0">
|
||||
<table
|
||||
mat-table
|
||||
[dataSource]="dataSource"
|
||||
matSort
|
||||
matSortDisableClear
|
||||
(matSortChange)="sortData($event)"
|
||||
[matSortActive]="initialSortColumn"
|
||||
[matSortDirection]="initialSortDirection">
|
||||
<!-- More Details Column -->
|
||||
<ng-container matColumnDef="moreDetails">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<ng-container *ngIf="canRead(item)">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<!-- TODO - handle read only in configure component? -->
|
||||
<div
|
||||
class="pointer fa fa-info-circle"
|
||||
*ngIf="canRead(item)"
|
||||
title="View Processor Details"></div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Input column -->
|
||||
<ng-container matColumnDef="in">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span [ngClass]="{ underline: multiSort.active === 'in' && multiSort.sortValueIndex === 0 }"
|
||||
>In</span
|
||||
>
|
||||
<span [ngClass]="{ underline: multiSort.active === 'in' && multiSort.sortValueIndex === 1 }"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatIn(item)">
|
||||
{{ formatIn(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Name</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatName(item)">
|
||||
{{ formatName(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Read Write column -->
|
||||
<ng-container matColumnDef="readWrite">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header title="Data size in the last 5 minutes">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'readWrite' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Read</span
|
||||
>
|
||||
<span>|</span>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'readWrite' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>Write</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatReadWrite(item)">
|
||||
{{ formatReadWrite(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Type column -->
|
||||
<ng-container matColumnDef="type">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Type</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatType(item)">
|
||||
{{ formatType(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Output column -->
|
||||
<ng-container matColumnDef="out">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{ underline: multiSort.active === 'out' && multiSort.sortValueIndex === 0 }">
|
||||
Out
|
||||
</span>
|
||||
<span
|
||||
[ngClass]="{ underline: multiSort.active === 'out' && multiSort.sortValueIndex === 1 }">
|
||||
(Size)
|
||||
</span>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatOut(item)">
|
||||
{{ formatOut(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Process Group column -->
|
||||
<ng-container matColumnDef="processGroup">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">
|
||||
Process Group
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatProcessGroup(item)">
|
||||
{{ formatProcessGroup(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Tasks column -->
|
||||
<ng-container matColumnDef="tasks">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / duration in the last 5 minutes">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'tasks' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Tasks</span
|
||||
>
|
||||
<span>|</span>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'tasks' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>Time</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatTasks(item)">
|
||||
{{ formatTasks(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Run Status column -->
|
||||
<ng-container matColumnDef="runStatus">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Run Status</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1.5 align-middle">
|
||||
<span [ngClass]="getRunStatusIcon(item)"></span>
|
||||
<span [title]="formatRunStatus(item)">{{ formatRunStatus(item) }}</span>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div
|
||||
class="pointer fa fa-long-arrow-right"
|
||||
[routerLink]="getProcessorLink(item)"
|
||||
(click)="$event.stopPropagation()"
|
||||
title="Go to Processor in {{
|
||||
item?.processorStatusSnapshot?.processGroupNamePath
|
||||
}}"></div>
|
||||
<ng-container *ngIf="item.processorStatusSnapshot as pg">
|
||||
<span
|
||||
*ngIf="pg.terminatedThreadCount > 0; else activeThreads"
|
||||
title="Threads: (Active / Terminated)"
|
||||
>({{ pg.activeThreadCount }}/{{ pg.terminatedThreadCount }})</span
|
||||
>
|
||||
<ng-template #activeThreads>
|
||||
<span *ngIf="pg.activeThreadCount > 0" title="Active Threads"
|
||||
>({{ pg.activeThreadCount }})</span
|
||||
>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<div
|
||||
class="pointer fa fa-area-chart"
|
||||
title="View Status History"
|
||||
(click)="viewStatusHistoryClicked($event, item)"></div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Input column -->
|
||||
<ng-container matColumnDef="in">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'in' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>In</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'in' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatIn(item)">
|
||||
{{ formatIn(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
|
||||
<tr
|
||||
mat-row
|
||||
*matRowDef="let row; let even = even; columns: displayedColumns"
|
||||
[class.even]="even"
|
||||
(click)="select(row)"
|
||||
[class.selected]="isSelected(row)"></tr>
|
||||
</table>
|
||||
<!-- Read Write column -->
|
||||
<ng-container matColumnDef="readWrite">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Data size in the last 5 minutes">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'readWrite' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Read</span
|
||||
>
|
||||
<span>|</span>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'readWrite' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>Write</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatReadWrite(item)">
|
||||
{{ formatReadWrite(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Output column -->
|
||||
<ng-container matColumnDef="out">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'out' && multiSort.sortValueIndex === 0
|
||||
}">
|
||||
Out
|
||||
</span>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'out' && multiSort.sortValueIndex === 1
|
||||
}">
|
||||
(Size)
|
||||
</span>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatOut(item)">
|
||||
{{ formatOut(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Tasks column -->
|
||||
<ng-container matColumnDef="tasks">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / duration in the last 5 minutes">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'tasks' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Tasks</span
|
||||
>
|
||||
<span>|</span>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'tasks' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>Time</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatTasks(item)">
|
||||
{{ formatTasks(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div
|
||||
class="pointer fa fa-long-arrow-right"
|
||||
[routerLink]="getProcessorLink(item)"
|
||||
(click)="$event.stopPropagation()"
|
||||
title="Go to Processor in {{
|
||||
item?.processorStatusSnapshot?.processGroupNamePath
|
||||
}}"></div>
|
||||
|
||||
<div
|
||||
class="pointer fa fa-area-chart"
|
||||
title="View Status History"
|
||||
(click)="viewStatusHistoryClicked($event, item)"></div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
|
||||
<tr
|
||||
mat-row
|
||||
*matRowDef="let row; let even = even; columns: displayedColumns"
|
||||
[class.even]="even"
|
||||
(click)="select(row)"
|
||||
[class.selected]="isSelected(row)"></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="flex justify-between align-middle">
|
||||
<div class="refresh-container flex items-center gap-x-2">
|
||||
<button class="nifi-button" (click)="refresh.next()">
|
||||
<i class="fa fa-refresh" [class.fa-spin]="summaryListingStatus === 'loading'"></i>
|
||||
</button>
|
||||
<div>Last updated:</div>
|
||||
<div class="refresh-timestamp">{{ loadedTimestamp }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<mat-paginator
|
||||
[pageSize]="100"
|
||||
[hidePageSize]="true"
|
||||
[showFirstLastButtons]="true"
|
||||
(page)="paginationChanged()"></mat-paginator>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { AfterViewInit, Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
|
||||
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
|
||||
import { ProcessorStatusSnapshot, ProcessorStatusSnapshotEntity } from '../../../state/summary-listing';
|
||||
import { MatSortModule, Sort, SortDirection } from '@angular/material/sort';
|
||||
@ -29,6 +29,7 @@ import { NgClass, NgIf } from '@angular/common';
|
||||
import { ComponentType } from '../../../../../state/shared';
|
||||
import { MultiSort } from '../../common';
|
||||
import { NiFiCommon } from '../../../../../service/nifi-common.service';
|
||||
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
|
||||
|
||||
export type SupportedColumns = 'name' | 'type' | 'processGroup' | 'runStatus' | 'in' | 'out' | 'readWrite' | 'tasks';
|
||||
|
||||
@ -37,9 +38,9 @@ export type SupportedColumns = 'name' | 'type' | 'processGroup' | 'runStatus' |
|
||||
templateUrl: './processor-status-table.component.html',
|
||||
styleUrls: ['./processor-status-table.component.scss', '../../../../../../assets/styles/listing-table.scss'],
|
||||
standalone: true,
|
||||
imports: [RouterLink, SummaryTableFilterModule, MatTableModule, MatSortModule, NgClass, NgIf]
|
||||
imports: [RouterLink, SummaryTableFilterModule, MatTableModule, MatSortModule, NgClass, NgIf, MatPaginatorModule]
|
||||
})
|
||||
export class ProcessorStatusTable {
|
||||
export class ProcessorStatusTable implements AfterViewInit {
|
||||
private _initialSortColumn: SupportedColumns = 'name';
|
||||
private _initialSortDirection: SortDirection = 'asc';
|
||||
|
||||
@ -47,8 +48,8 @@ export class ProcessorStatusTable {
|
||||
{ key: 'name', label: 'name' },
|
||||
{ key: 'type', label: 'type' }
|
||||
];
|
||||
totalCount: number = 0;
|
||||
filteredCount: number = 0;
|
||||
totalCount = 0;
|
||||
filteredCount = 0;
|
||||
|
||||
multiSort: MultiSort = {
|
||||
active: this._initialSortColumn,
|
||||
@ -72,11 +73,19 @@ export class ProcessorStatusTable {
|
||||
dataSource: MatTableDataSource<ProcessorStatusSnapshotEntity> =
|
||||
new MatTableDataSource<ProcessorStatusSnapshotEntity>();
|
||||
|
||||
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||
|
||||
constructor(private nifiCommon: NiFiCommon) {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.dataSource.paginator = this.paginator;
|
||||
}
|
||||
|
||||
applyFilter(filter: SummaryTableFilterArgs) {
|
||||
this.dataSource.filter = JSON.stringify(filter);
|
||||
this.filteredCount = this.dataSource.filteredData.length;
|
||||
this.resetPaginator();
|
||||
this.selectNone();
|
||||
}
|
||||
|
||||
@Input() selectedProcessorId!: string;
|
||||
@ -131,10 +140,26 @@ export class ProcessorStatusTable {
|
||||
}
|
||||
}
|
||||
|
||||
@Input() summaryListingStatus: string | null = null;
|
||||
@Input() loadedTimestamp: string | null = null;
|
||||
|
||||
@Output() refresh: EventEmitter<void> = new EventEmitter<void>();
|
||||
@Output() viewStatusHistory: EventEmitter<ProcessorStatusSnapshotEntity> =
|
||||
new EventEmitter<ProcessorStatusSnapshotEntity>();
|
||||
@Output() selectProcessor: EventEmitter<ProcessorStatusSnapshotEntity> =
|
||||
new EventEmitter<ProcessorStatusSnapshotEntity>();
|
||||
@Output() clearSelection: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
resetPaginator(): void {
|
||||
if (this.dataSource.paginator) {
|
||||
this.dataSource.paginator.firstPage();
|
||||
}
|
||||
}
|
||||
|
||||
paginationChanged(): void {
|
||||
// clear out any selection
|
||||
this.selectNone();
|
||||
}
|
||||
|
||||
formatName(processor: ProcessorStatusSnapshotEntity): string {
|
||||
return processor.processorStatusSnapshot.name;
|
||||
@ -318,6 +343,7 @@ export class ProcessorStatusTable {
|
||||
select(processor: ProcessorStatusSnapshotEntity): void {
|
||||
this.selectProcessor.next(processor);
|
||||
}
|
||||
|
||||
isSelected(processor: ProcessorStatusSnapshotEntity): boolean {
|
||||
if (this.selectedProcessorId) {
|
||||
return processor.id === this.selectedProcessorId;
|
||||
@ -329,4 +355,8 @@ export class ProcessorStatusTable {
|
||||
event.stopPropagation();
|
||||
this.viewStatusHistory.next(processor);
|
||||
}
|
||||
|
||||
private selectNone() {
|
||||
this.clearSelection.next();
|
||||
}
|
||||
}
|
||||
|
@ -21,30 +21,16 @@
|
||||
</div>
|
||||
|
||||
<ng-template #loaded>
|
||||
<div class="flex flex-col h-full gap-y-2">
|
||||
<div class="flex-1" *ngIf="currentUser$ | async as user">
|
||||
<ng-container>
|
||||
<remote-process-group-status-table
|
||||
[remoteProcessGroups]="(rpgStatusSnapshots$ | async)!"
|
||||
[selectedRemoteProcessGroupId]="selectedRpgId$ | async"
|
||||
(selectRemoteProcessGroup)="selectRemoteProcessGroup($event)"
|
||||
(viewStatusHistory)="viewStatusHistory($event)"
|
||||
initialSortColumn="name"
|
||||
initialSortDirection="asc"></remote-process-group-status-table>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<div class="refresh-container flex items-center gap-x-2">
|
||||
<button class="nifi-button" (click)="refreshSummaryListing()">
|
||||
<i class="fa fa-refresh" [class.fa-spin]="(summaryListingStatus$ | async) === 'loading'"></i>
|
||||
</button>
|
||||
<div>Last updated:</div>
|
||||
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
||||
</div>
|
||||
<div *ngIf="(currentUser$ | async)?.systemPermissions?.canRead">
|
||||
<a (click)="openSystemDiagnostics()">System Diagnostics</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<remote-process-group-status-table
|
||||
[remoteProcessGroups]="(rpgStatusSnapshots$ | async)!"
|
||||
[selectedRemoteProcessGroupId]="selectedRpgId$ | async"
|
||||
[loadedTimestamp]="loadedTimestamp$ | async"
|
||||
[summaryListingStatus]="summaryListingStatus$ | async"
|
||||
(selectRemoteProcessGroup)="selectRemoteProcessGroup($event)"
|
||||
(clearSelection)="clearSelection()"
|
||||
(viewStatusHistory)="viewStatusHistory($event)"
|
||||
(refresh)="refreshSummaryListing()"
|
||||
initialSortColumn="name"
|
||||
initialSortDirection="asc"></remote-process-group-status-table>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
@ -29,14 +29,10 @@ import { Store } from '@ngrx/store';
|
||||
import { RemoteProcessGroupStatusSnapshotEntity, SummaryListingState } from '../../state/summary-listing';
|
||||
import { filter, switchMap, take } from 'rxjs';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import {
|
||||
getStatusHistoryAndOpenDialog,
|
||||
openStatusHistoryDialog
|
||||
} from '../../../../state/status-history/status-history.actions';
|
||||
import { getStatusHistoryAndOpenDialog } from '../../../../state/status-history/status-history.actions';
|
||||
import { ComponentType } from '../../../../state/shared';
|
||||
import { initialState } from '../../state/summary-listing/summary-listing.reducer';
|
||||
import * as SummaryListingActions from '../../state/summary-listing/summary-listing.actions';
|
||||
import { getSystemDiagnosticsAndOpenDialog } from '../../../../state/system-diagnostics/system-diagnostics.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'remote-process-group-status-listing',
|
||||
@ -96,6 +92,10 @@ export class RemoteProcessGroupStatusListing {
|
||||
);
|
||||
}
|
||||
|
||||
clearSelection() {
|
||||
this.store.dispatch(SummaryListingActions.clearRemoteProcessGroupStatusSelection());
|
||||
}
|
||||
|
||||
viewStatusHistory(rpg: RemoteProcessGroupStatusSnapshotEntity): void {
|
||||
this.store.dispatch(
|
||||
SummaryListingActions.navigateToViewRemoteProcessGroupStatusHistory({
|
||||
@ -103,14 +103,4 @@ export class RemoteProcessGroupStatusListing {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
openSystemDiagnostics() {
|
||||
this.store.dispatch(
|
||||
getSystemDiagnosticsAndOpenDialog({
|
||||
request: {
|
||||
nodewise: false
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -20,10 +20,11 @@ import { RemoteProcessGroupStatusListing } from './remote-process-group-status-l
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||
import { RemoteProcessGroupStatusTable } from './remote-process-group-status-table/remote-process-group-status-table.component';
|
||||
import { ProcessorStatusTable } from '../processor-status-listing/processor-status-table/processor-status-table.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [RemoteProcessGroupStatusListing],
|
||||
exports: [RemoteProcessGroupStatusListing],
|
||||
imports: [CommonModule, NgxSkeletonLoaderModule, RemoteProcessGroupStatusTable]
|
||||
imports: [CommonModule, NgxSkeletonLoaderModule, RemoteProcessGroupStatusTable, ProcessorStatusTable]
|
||||
})
|
||||
export class RemoteProcessGroupStatusListingModule {}
|
||||
|
@ -15,144 +15,177 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<div class="remote-process-group-status-table h-full flex flex-col">
|
||||
<!-- allow filtering of the table -->
|
||||
<summary-table-filter
|
||||
[filteredCount]="filteredCount"
|
||||
[totalCount]="totalCount"
|
||||
[filterableColumns]="filterableColumns"
|
||||
[includeStatusFilter]="false"
|
||||
[includePrimaryNodeOnlyFilter]="false"
|
||||
(filterChanged)="applyFilter($event)"></summary-table-filter>
|
||||
<div class="flex flex-col h-full gap-y-2">
|
||||
<div class="flex-1">
|
||||
<ng-container>
|
||||
<div class="remote-process-group-status-table h-full flex flex-col">
|
||||
<!-- allow filtering of the table -->
|
||||
<summary-table-filter
|
||||
[filteredCount]="filteredCount"
|
||||
[totalCount]="totalCount"
|
||||
[filterableColumns]="filterableColumns"
|
||||
[includeStatusFilter]="false"
|
||||
[includePrimaryNodeOnlyFilter]="false"
|
||||
(filterChanged)="applyFilter($event)"></summary-table-filter>
|
||||
|
||||
<div class="flex-1 relative">
|
||||
<div class="listing-table overflow-y-auto border absolute inset-0">
|
||||
<table
|
||||
mat-table
|
||||
[dataSource]="dataSource"
|
||||
matSort
|
||||
matSortDisableClear
|
||||
(matSortChange)="sortData($event)"
|
||||
[matSortActive]="initialSortColumn"
|
||||
[matSortDirection]="initialSortDirection">
|
||||
<!-- More Details Column -->
|
||||
<ng-container matColumnDef="moreDetails">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item"></td>
|
||||
</ng-container>
|
||||
<div class="flex-1 relative">
|
||||
<div class="listing-table overflow-y-auto border absolute inset-0">
|
||||
<table
|
||||
mat-table
|
||||
[dataSource]="dataSource"
|
||||
matSort
|
||||
matSortDisableClear
|
||||
(matSortChange)="sortData($event)"
|
||||
[matSortActive]="initialSortColumn"
|
||||
[matSortDirection]="initialSortDirection">
|
||||
<!-- More Details Column -->
|
||||
<ng-container matColumnDef="moreDetails">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item"></td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Name</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatName(item)">
|
||||
{{ formatName(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Name</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatName(item)">
|
||||
{{ formatName(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Target URI Column -->
|
||||
<ng-container matColumnDef="uri">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Target URI</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatUri(item)">
|
||||
{{ formatUri(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Target URI Column -->
|
||||
<ng-container matColumnDef="uri">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">
|
||||
Target URI
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatUri(item)">
|
||||
{{ formatUri(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Transmission Status column -->
|
||||
<ng-container matColumnDef="transmitting">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Transmitting</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1.5">
|
||||
<span [ngClass]="getTransmissionStatusIcon(item)"></span>
|
||||
<span [title]="formatTransmitting(item)">{{ formatTransmitting(item) }}</span>
|
||||
<span *ngIf="item.activeThreadCount > 0" title="Active Threads"
|
||||
>({{ item.activeThreadCount }})</span
|
||||
>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Transmission Status column -->
|
||||
<ng-container matColumnDef="transmitting">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Transmitting</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1.5 align-middle">
|
||||
<span [ngClass]="getTransmissionStatusIcon(item)"></span>
|
||||
<span [title]="formatTransmitting(item)">{{ formatTransmitting(item) }}</span>
|
||||
<span *ngIf="item.activeThreadCount > 0" title="Active Threads"
|
||||
>({{ item.activeThreadCount }})</span
|
||||
>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Sent column -->
|
||||
<ng-container matColumnDef="sent">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{ underline: multiSort.active === 'sent' && multiSort.sortValueIndex === 0 }"
|
||||
>Sent</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{ underline: multiSort.active === 'sent' && multiSort.sortValueIndex === 1 }"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatSent(item)">
|
||||
{{ formatSent(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Sent column -->
|
||||
<ng-container matColumnDef="sent">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'sent' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Sent</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'sent' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatSent(item)">
|
||||
{{ formatSent(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Received column -->
|
||||
<ng-container matColumnDef="received">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'received' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Received</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline: multiSort.active === 'received' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatReceived(item)">
|
||||
{{ formatReceived(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Received column -->
|
||||
<ng-container matColumnDef="received">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
title="Count / data size in the last 5 minutes">
|
||||
<div
|
||||
class="inline-block overflow-hidden overflow-ellipsis whitespace-nowrap space-x-1">
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'received' && multiSort.sortValueIndex === 0
|
||||
}"
|
||||
>Received</span
|
||||
>
|
||||
<span
|
||||
[ngClass]="{
|
||||
underline:
|
||||
multiSort.active === 'received' && multiSort.sortValueIndex === 1
|
||||
}"
|
||||
>(Size)</span
|
||||
>
|
||||
<span class="font-light">5 min</span>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatReceived(item)">
|
||||
{{ formatReceived(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div
|
||||
class="pointer fa fa-long-arrow-right"
|
||||
[routerLink]="getRemoteProcessGroupLink(item)"
|
||||
(click)="$event.stopPropagation()"
|
||||
title="Go to remote process group"></div>
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div
|
||||
class="pointer fa fa-long-arrow-right"
|
||||
[routerLink]="getRemoteProcessGroupLink(item)"
|
||||
(click)="$event.stopPropagation()"
|
||||
title="Go to remote process group"></div>
|
||||
|
||||
<div
|
||||
class="pointer fa fa-area-chart"
|
||||
title="View Status History"
|
||||
(click)="viewStatusHistoryClicked($event, item)"></div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<div
|
||||
class="pointer fa fa-area-chart"
|
||||
title="View Status History"
|
||||
(click)="viewStatusHistoryClicked($event, item)"></div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
|
||||
<tr
|
||||
mat-row
|
||||
*matRowDef="let row; let even = even; columns: displayedColumns"
|
||||
[class.even]="even"
|
||||
(click)="select(row)"
|
||||
[class.selected]="isSelected(row)"></tr>
|
||||
</table>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
|
||||
<tr
|
||||
mat-row
|
||||
*matRowDef="let row; let even = even; columns: displayedColumns"
|
||||
[class.even]="even"
|
||||
(click)="select(row)"
|
||||
[class.selected]="isSelected(row)"></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="flex justify-between align-middle">
|
||||
<div class="refresh-container flex items-center gap-x-2">
|
||||
<button class="nifi-button" (click)="refresh.next()">
|
||||
<i class="fa fa-refresh" [class.fa-spin]="summaryListingStatus === 'loading'"></i>
|
||||
</button>
|
||||
<div>Last updated:</div>
|
||||
<div class="refresh-timestamp">{{ loadedTimestamp }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<mat-paginator
|
||||
[pageSize]="100"
|
||||
[hidePageSize]="true"
|
||||
[showFirstLastButtons]="true"
|
||||
(page)="paginationChanged()"></mat-paginator>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { AfterViewInit, Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SummaryTableFilterModule } from '../../common/summary-table-filter/summary-table-filter.module';
|
||||
import { MatSortModule, Sort, SortDirection } from '@angular/material/sort';
|
||||
@ -26,27 +26,27 @@ import {
|
||||
import { MultiSort } from '../../common';
|
||||
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
|
||||
import {
|
||||
PortStatusSnapshot,
|
||||
RemoteProcessGroupStatusSnapshot,
|
||||
RemoteProcessGroupStatusSnapshotEntity
|
||||
} from '../../../state/summary-listing';
|
||||
import { NiFiCommon } from '../../../../../service/nifi-common.service';
|
||||
import { ComponentType } from '../../../../../state/shared';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
|
||||
|
||||
export type SupportedColumns = 'name' | 'uri' | 'transmitting' | 'sent' | 'received';
|
||||
|
||||
@Component({
|
||||
selector: 'remote-process-group-status-table',
|
||||
standalone: true,
|
||||
imports: [CommonModule, SummaryTableFilterModule, MatSortModule, MatTableModule, RouterLink],
|
||||
imports: [CommonModule, SummaryTableFilterModule, MatSortModule, MatTableModule, RouterLink, MatPaginatorModule],
|
||||
templateUrl: './remote-process-group-status-table.component.html',
|
||||
styleUrls: [
|
||||
'./remote-process-group-status-table.component.scss',
|
||||
'../../../../../../assets/styles/listing-table.scss'
|
||||
]
|
||||
})
|
||||
export class RemoteProcessGroupStatusTable {
|
||||
export class RemoteProcessGroupStatusTable implements AfterViewInit {
|
||||
private _initialSortColumn: SupportedColumns = 'name';
|
||||
private _initialSortDirection: SortDirection = 'asc';
|
||||
|
||||
@ -55,8 +55,8 @@ export class RemoteProcessGroupStatusTable {
|
||||
{ key: 'targetUri', label: 'uri' }
|
||||
];
|
||||
|
||||
totalCount: number = 0;
|
||||
filteredCount: number = 0;
|
||||
totalCount = 0;
|
||||
filteredCount = 0;
|
||||
|
||||
multiSort: MultiSort = {
|
||||
active: this._initialSortColumn,
|
||||
@ -70,6 +70,12 @@ export class RemoteProcessGroupStatusTable {
|
||||
dataSource: MatTableDataSource<RemoteProcessGroupStatusSnapshotEntity> =
|
||||
new MatTableDataSource<RemoteProcessGroupStatusSnapshotEntity>();
|
||||
|
||||
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.dataSource.paginator = this.paginator;
|
||||
}
|
||||
|
||||
constructor(private nifiCommon: NiFiCommon) {}
|
||||
|
||||
@Input() set initialSortColumn(initialSortColumn: SupportedColumns) {
|
||||
@ -113,14 +119,32 @@ export class RemoteProcessGroupStatusTable {
|
||||
}
|
||||
}
|
||||
|
||||
@Input() summaryListingStatus: string | null = null;
|
||||
@Input() loadedTimestamp: string | null = null;
|
||||
|
||||
@Output() refresh: EventEmitter<void> = new EventEmitter<void>();
|
||||
@Output() viewStatusHistory: EventEmitter<RemoteProcessGroupStatusSnapshotEntity> =
|
||||
new EventEmitter<RemoteProcessGroupStatusSnapshotEntity>();
|
||||
@Output() selectRemoteProcessGroup: EventEmitter<RemoteProcessGroupStatusSnapshotEntity> =
|
||||
new EventEmitter<RemoteProcessGroupStatusSnapshotEntity>();
|
||||
@Output() clearSelection: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
applyFilter(filter: SummaryTableFilterArgs) {
|
||||
this.dataSource.filter = JSON.stringify(filter);
|
||||
this.filteredCount = this.dataSource.filteredData.length;
|
||||
this.resetPaginator();
|
||||
this.selectNone();
|
||||
}
|
||||
|
||||
resetPaginator(): void {
|
||||
if (this.dataSource.paginator) {
|
||||
this.dataSource.paginator.firstPage();
|
||||
}
|
||||
}
|
||||
|
||||
paginationChanged(): void {
|
||||
// clear out any selection
|
||||
this.selectNone();
|
||||
}
|
||||
|
||||
getRemoteProcessGroupLink(rpg: RemoteProcessGroupStatusSnapshotEntity): string[] {
|
||||
@ -136,6 +160,10 @@ export class RemoteProcessGroupStatusTable {
|
||||
this.selectRemoteProcessGroup.next(rpg);
|
||||
}
|
||||
|
||||
private selectNone() {
|
||||
this.clearSelection.next();
|
||||
}
|
||||
|
||||
isSelected(rpg: RemoteProcessGroupStatusSnapshotEntity): boolean {
|
||||
if (this.selectedRemoteProcessGroupId) {
|
||||
return rpg.id === this.selectedRemoteProcessGroupId;
|
||||
@ -231,7 +259,7 @@ export class RemoteProcessGroupStatusTable {
|
||||
|
||||
return data.slice().sort((a, b) => {
|
||||
const isAsc: boolean = sort.direction === 'asc';
|
||||
let retVal: number = 0;
|
||||
let retVal = 0;
|
||||
switch (sort.active) {
|
||||
case 'name':
|
||||
retVal = this.nifiCommon.compareString(
|
||||
|
Loading…
x
Reference in New Issue
Block a user