[NIFI-13974] - Improve UX of Status History dialog (select all nodes, scrolling left panel) (#9493)

This closes #9493
This commit is contained in:
Rob Fellows 2024-11-07 09:08:29 -05:00 committed by GitHub
parent 4e4ce6f470
commit 11cb2c56e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 117 additions and 76 deletions

View File

@ -55,87 +55,103 @@
@if (instances.length > 0 && fieldDescriptors.length > 0) {
@if (componentDetails$ | async; as componentDetails) {
<div class="flex flex-1 w-full gap-x-4">
<div class="component-details flex flex-col gap-y-3">
@for (detail of details; track detail) {
@if (detail.key && detail.value) {
<div class="component-details-panel relative h-full">
<div
class="component-details flex flex-col gap-y-3 overflow-y-auto absolute inset-0">
@for (detail of details; track detail) {
@if (detail.key && detail.value) {
<div class="flex flex-col">
<div>{{ detail.key }}</div>
<div
[title]="detail.value"
class="tertiary-color overflow-ellipsis overflow-hidden whitespace-nowrap font-medium">
{{ detail.value }}
</div>
</div>
}
}
<div class="flex flex-col">
<div>Start</div>
<div class="tertiary-color font-medium">
{{ minDate }}
</div>
</div>
<div class="flex flex-col">
<div>End</div>
<div class="tertiary-color font-medium">
{{ maxDate }}
</div>
</div>
<div class="flex flex-col">
<div class="detail-item">
<div>Min / Max / Mean</div>
<div class="tertiary-color font-medium">
{{ clusterStats.min }} / {{ clusterStats.max }} /
{{ clusterStats.mean }}
</div>
</div>
<div class="legend-entry flex justify-between items-center mr-1">
<mat-label
[ngStyle]="{
color: getColor(
nodeStats,
NIFI_NODE_CONFIG.nifiInstanceId
)
}"
>NiFi
</mat-label>
<mat-checkbox
value="nifi-instance-id"
(change)="selectNode($event)"
[checked]="
!!instanceVisibility['nifi-instance-id']
"></mat-checkbox>
</div>
</div>
@if (!!nodes && nodes.length > 0) {
<div class="flex flex-col">
<div>{{ detail.key }}</div>
<div
[title]="detail.value"
class="tertiary-color overflow-ellipsis overflow-hidden whitespace-nowrap font-medium">
{{ detail.value }}
<div class="flex justify-between items-center border-b mr-1">
<mat-label class="font-bold secondary-color"
>Nodes
</mat-label>
<mat-checkbox
class="tertiary-checkbox"
[checked]="areAllNodesSelected(instanceVisibility)"
[indeterminate]="
areAnyNodesSelected(instanceVisibility)
"
(change)="selectAllNodesChanged($event)"></mat-checkbox>
</div>
<div>
<div>Min / Max / Mean</div>
<div class="tertiary-color font-medium">
{{ nodeStats.min }} / {{ nodeStats.max }} /
{{ nodeStats.mean }}
</div>
</div>
<div class="legend-entry mr-1">
@for (node of nodes; track node.id) {
@if (node.snapshots?.length) {
<div class="flex justify-between items-start">
<mat-label
[ngStyle]="{
color: getColor(nodeStats, node.id)
}"
>{{ node.label }}
</mat-label>
<mat-checkbox
[value]="node.id"
(change)="selectNode($event)"
[checked]="
!!instanceVisibility[node.id]
"></mat-checkbox>
</div>
}
}
</div>
</div>
}
}
<div class="flex flex-col">
<div>Start</div>
<div class="tertiary-color font-medium">
{{ minDate }}
</div>
</div>
<div class="flex flex-col">
<div>End</div>
<div class="tertiary-color font-medium">
{{ maxDate }}
</div>
</div>
<div class="flex flex-col">
<div class="font-bold">NiFi</div>
<div class="detail-item">
<div>Min / Max / Mean</div>
<div class="tertiary-color font-medium">
{{ clusterStats.min }} / {{ clusterStats.max }} /
{{ clusterStats.mean }}
</div>
</div>
<div class="legend-entry">
<mat-checkbox
value="nifi-instance-id"
(change)="selectNode($event)"
[checked]="
!!instanceVisibility['nifi-instance-id']
"></mat-checkbox>
<mat-label
[ngStyle]="{
color: getColor(nodeStats, NIFI_NODE_CONFIG.nifiInstanceId)
}"
>NiFi</mat-label
>
</div>
</div>
@if (!!nodes && nodes.length > 0) {
<div class="flex flex-col">
<div>Nodes</div>
<div>
<div>Min / Max / Mean</div>
<div class="tertiary-color font-medium">
{{ nodeStats.min }} / {{ nodeStats.max }} /
{{ nodeStats.mean }}
</div>
</div>
<div class="legend-entry">
@for (node of nodes; track node) {
@if (node.snapshots?.length) {
<div class="flex">
<mat-checkbox
[value]="node.id"
(change)="selectNode($event)"
[checked]="
!!instanceVisibility[node.id]
"></mat-checkbox>
<mat-label
[ngStyle]="{
color: getColor(nodeStats, node.id)
}"
>{{ node.label }}</mat-label
>
</div>
}
}
</div>
</div>
}
</div>
<div class="chart-panel grow flex flex-col">
@if (fieldDescriptors$ | async) {

View File

@ -55,6 +55,7 @@
min-width: 495px;
}
.component-details-panel,
.component-details {
min-width: 300px;
max-width: 300px;

View File

@ -244,6 +244,30 @@ export class StatusHistory extends CloseOnEscapeDialog implements OnInit, AfterV
protected readonly TextTip = TextTip;
areAllNodesSelected(instanceVisibility: any): boolean {
const unChecked = Object.entries(instanceVisibility)
.filter(([node, checked]) => node !== 'nifi-instance-id' && !checked)
.map(([, checked]) => checked);
return unChecked.length === 0;
}
areAnyNodesSelected(instanceVisibility: any): boolean {
const checked = Object.entries(instanceVisibility)
.filter(([node, checked]) => node !== 'nifi-instance-id' && checked)
.map(([, checked]) => checked);
return checked.length > 0 && checked.length < this.nodes.length;
}
selectAllNodesChanged(event: MatCheckboxChange) {
const checked: boolean = event.checked;
const tmpInstanceVisibility: any = {};
this.nodes.forEach((node: Instance) => {
tmpInstanceVisibility[node.id] = checked;
});
tmpInstanceVisibility['nifi-instance-id'] = this.instanceVisibility['nifi-instance-id'];
this.instanceVisibility = tmpInstanceVisibility;
}
selectNode(event: MatCheckboxChange) {
const instanceId: string = event.source.value;
const checked: boolean = event.checked;