mirror of
https://github.com/apache/nifi.git
synced 2025-02-14 14:05:26 +00:00
Nifi 12505 system diagnostics (#8190)
* [NIFI-12505] System Diagnostics * Refactor Status History dialog to use the load and open action pattern. * address review feedback This closes #8190
This commit is contained in:
parent
a73d812c23
commit
e15aecce67
@ -39,6 +39,7 @@ import { AboutEffects } from './state/about/about.effects';
|
|||||||
import { StatusHistoryEffects } from './state/status-history/status-history.effects';
|
import { StatusHistoryEffects } from './state/status-history/status-history.effects';
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
import { ControllerServiceStateEffects } from './state/contoller-service-state/controller-service-state.effects';
|
import { ControllerServiceStateEffects } from './state/contoller-service-state/controller-service-state.effects';
|
||||||
|
import { SystemDiagnosticsEffects } from './state/system-diagnostics/system-diagnostics.effects';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -62,7 +63,8 @@ import { ControllerServiceStateEffects } from './state/contoller-service-state/c
|
|||||||
ExtensionTypesEffects,
|
ExtensionTypesEffects,
|
||||||
AboutEffects,
|
AboutEffects,
|
||||||
StatusHistoryEffects,
|
StatusHistoryEffects,
|
||||||
ControllerServiceStateEffects
|
ControllerServiceStateEffects,
|
||||||
|
SystemDiagnosticsEffects
|
||||||
),
|
),
|
||||||
StoreDevtoolsModule.instrument({
|
StoreDevtoolsModule.instrument({
|
||||||
maxAge: 25,
|
maxAge: 25,
|
||||||
|
@ -41,6 +41,9 @@
|
|||||||
<div>Last updated:</div>
|
<div>Last updated:</div>
|
||||||
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div *ngIf="(currentUser$ | async)?.systemPermissions?.canRead">
|
||||||
|
<a (click)="openSystemDiagnostics()">System Diagnostics</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -36,8 +36,12 @@ import {
|
|||||||
import { selectUser } from '../../../../state/user/user.selectors';
|
import { selectUser } from '../../../../state/user/user.selectors';
|
||||||
import { filter, switchMap, take } from 'rxjs';
|
import { filter, switchMap, take } from 'rxjs';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { openStatusHistoryDialog } from '../../../../state/status-history/status-history.actions';
|
import {
|
||||||
|
getStatusHistoryAndOpenDialog,
|
||||||
|
openStatusHistoryDialog
|
||||||
|
} from '../../../../state/status-history/status-history.actions';
|
||||||
import { ComponentType } from '../../../../state/shared';
|
import { ComponentType } from '../../../../state/shared';
|
||||||
|
import { getSystemDiagnosticsAndOpenDialog } from '../../../../state/system-diagnostics/system-diagnostics.actions';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'connection-status-listing',
|
selector: 'connection-status-listing',
|
||||||
@ -67,7 +71,7 @@ export class ConnectionStatusListing {
|
|||||||
.subscribe((connection) => {
|
.subscribe((connection) => {
|
||||||
if (connection) {
|
if (connection) {
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
openStatusHistoryDialog({
|
getStatusHistoryAndOpenDialog({
|
||||||
request: {
|
request: {
|
||||||
source: 'summary',
|
source: 'summary',
|
||||||
componentType: ComponentType.Connection,
|
componentType: ComponentType.Connection,
|
||||||
@ -104,4 +108,14 @@ export class ConnectionStatusListing {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openSystemDiagnostics() {
|
||||||
|
this.store.dispatch(
|
||||||
|
getSystemDiagnosticsAndOpenDialog({
|
||||||
|
request: {
|
||||||
|
nodewise: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,9 @@
|
|||||||
<div>Last updated:</div>
|
<div>Last updated:</div>
|
||||||
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div *ngIf="(currentUser$ | async)?.systemPermissions?.canRead">
|
||||||
|
<a (click)="openSystemDiagnostics()">System Diagnostics</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -27,6 +27,7 @@ import { PortStatusSnapshotEntity, SummaryListingState } from '../../state/summa
|
|||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { initialState } from '../../state/summary-listing/summary-listing.reducer';
|
import { initialState } from '../../state/summary-listing/summary-listing.reducer';
|
||||||
import * as SummaryListingActions from '../../state/summary-listing/summary-listing.actions';
|
import * as SummaryListingActions from '../../state/summary-listing/summary-listing.actions';
|
||||||
|
import { getSystemDiagnosticsAndOpenDialog } from '../../../../state/system-diagnostics/system-diagnostics.actions';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'input-port-status-listing',
|
selector: 'input-port-status-listing',
|
||||||
@ -59,4 +60,14 @@ export class InputPortStatusListing {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openSystemDiagnostics() {
|
||||||
|
this.store.dispatch(
|
||||||
|
getSystemDiagnosticsAndOpenDialog({
|
||||||
|
request: {
|
||||||
|
nodewise: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,9 @@
|
|||||||
<div>Last updated:</div>
|
<div>Last updated:</div>
|
||||||
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div *ngIf="(currentUser$ | async)?.systemPermissions?.canRead">
|
||||||
|
<a (click)="openSystemDiagnostics()">System Diagnostics</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -29,6 +29,7 @@ import { Store } from '@ngrx/store';
|
|||||||
import { PortStatusSnapshotEntity, SummaryListingState } from '../../state/summary-listing';
|
import { PortStatusSnapshotEntity, SummaryListingState } from '../../state/summary-listing';
|
||||||
import { initialState } from '../../state/summary-listing/summary-listing.reducer';
|
import { initialState } from '../../state/summary-listing/summary-listing.reducer';
|
||||||
import * as SummaryListingActions from '../../state/summary-listing/summary-listing.actions';
|
import * as SummaryListingActions from '../../state/summary-listing/summary-listing.actions';
|
||||||
|
import { getSystemDiagnosticsAndOpenDialog } from '../../../../state/system-diagnostics/system-diagnostics.actions';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'output-port-status-listing',
|
selector: 'output-port-status-listing',
|
||||||
@ -61,4 +62,14 @@ export class OutputPortStatusListing {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openSystemDiagnostics() {
|
||||||
|
this.store.dispatch(
|
||||||
|
getSystemDiagnosticsAndOpenDialog({
|
||||||
|
request: {
|
||||||
|
nodewise: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,9 @@
|
|||||||
<div>Last updated:</div>
|
<div>Last updated:</div>
|
||||||
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div *ngIf="(currentUser$ | async)?.systemPermissions?.canRead">
|
||||||
|
<a (click)="openSystemDiagnostics()">System Diagnostics</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -37,9 +37,13 @@ import {
|
|||||||
} from '../../state/summary-listing/summary-listing.selectors';
|
} from '../../state/summary-listing/summary-listing.selectors';
|
||||||
import { filter, switchMap, take } from 'rxjs';
|
import { filter, switchMap, take } from 'rxjs';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { openStatusHistoryDialog } from '../../../../state/status-history/status-history.actions';
|
import {
|
||||||
|
getStatusHistoryAndOpenDialog,
|
||||||
|
openStatusHistoryDialog
|
||||||
|
} from '../../../../state/status-history/status-history.actions';
|
||||||
import { ComponentType } from '../../../../state/shared';
|
import { ComponentType } from '../../../../state/shared';
|
||||||
import { selectUser } from '../../../../state/user/user.selectors';
|
import { selectUser } from '../../../../state/user/user.selectors';
|
||||||
|
import { getSystemDiagnosticsAndOpenDialog } from '../../../../state/system-diagnostics/system-diagnostics.actions';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'process-group-status-listing',
|
selector: 'process-group-status-listing',
|
||||||
@ -70,7 +74,7 @@ export class ProcessGroupStatusListing {
|
|||||||
.subscribe((pg) => {
|
.subscribe((pg) => {
|
||||||
if (pg) {
|
if (pg) {
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
openStatusHistoryDialog({
|
getStatusHistoryAndOpenDialog({
|
||||||
request: {
|
request: {
|
||||||
source: 'summary',
|
source: 'summary',
|
||||||
componentType: ComponentType.ProcessGroup,
|
componentType: ComponentType.ProcessGroup,
|
||||||
@ -107,4 +111,14 @@ export class ProcessGroupStatusListing {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openSystemDiagnostics() {
|
||||||
|
this.store.dispatch(
|
||||||
|
getSystemDiagnosticsAndOpenDialog({
|
||||||
|
request: {
|
||||||
|
nodewise: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,9 @@
|
|||||||
<div>Last updated:</div>
|
<div>Last updated:</div>
|
||||||
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div *ngIf="(currentUser$ | async)?.systemPermissions?.canRead">
|
||||||
|
<a (click)="openSystemDiagnostics()">System Diagnostics</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -28,11 +28,15 @@ import {
|
|||||||
import { ProcessorStatusSnapshotEntity, SummaryListingState } from '../../state/summary-listing';
|
import { ProcessorStatusSnapshotEntity, SummaryListingState } from '../../state/summary-listing';
|
||||||
import { selectUser } from '../../../../state/user/user.selectors';
|
import { selectUser } from '../../../../state/user/user.selectors';
|
||||||
import { initialState } from '../../state/summary-listing/summary-listing.reducer';
|
import { initialState } from '../../state/summary-listing/summary-listing.reducer';
|
||||||
import { openStatusHistoryDialog } from '../../../../state/status-history/status-history.actions';
|
import {
|
||||||
|
getStatusHistoryAndOpenDialog,
|
||||||
|
openStatusHistoryDialog
|
||||||
|
} from '../../../../state/status-history/status-history.actions';
|
||||||
import { ComponentType } from '../../../../state/shared';
|
import { ComponentType } from '../../../../state/shared';
|
||||||
import { filter, switchMap, take } from 'rxjs';
|
import { filter, switchMap, take } from 'rxjs';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import * as SummaryListingActions from '../../state/summary-listing/summary-listing.actions';
|
import * as SummaryListingActions from '../../state/summary-listing/summary-listing.actions';
|
||||||
|
import { getSystemDiagnosticsAndOpenDialog } from '../../../../state/system-diagnostics/system-diagnostics.actions';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'processor-status-listing',
|
selector: 'processor-status-listing',
|
||||||
@ -63,7 +67,7 @@ export class ProcessorStatusListing {
|
|||||||
.subscribe((processor) => {
|
.subscribe((processor) => {
|
||||||
if (processor) {
|
if (processor) {
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
openStatusHistoryDialog({
|
getStatusHistoryAndOpenDialog({
|
||||||
request: {
|
request: {
|
||||||
source: 'summary',
|
source: 'summary',
|
||||||
componentType: ComponentType.Processor,
|
componentType: ComponentType.Processor,
|
||||||
@ -100,4 +104,14 @@ export class ProcessorStatusListing {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openSystemDiagnostics() {
|
||||||
|
this.store.dispatch(
|
||||||
|
getSystemDiagnosticsAndOpenDialog({
|
||||||
|
request: {
|
||||||
|
nodewise: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,9 @@
|
|||||||
<div>Last updated:</div>
|
<div>Last updated:</div>
|
||||||
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div *ngIf="(currentUser$ | async)?.systemPermissions?.canRead">
|
||||||
|
<a (click)="openSystemDiagnostics()">System Diagnostics</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -29,10 +29,14 @@ import { Store } from '@ngrx/store';
|
|||||||
import { RemoteProcessGroupStatusSnapshotEntity, SummaryListingState } from '../../state/summary-listing';
|
import { RemoteProcessGroupStatusSnapshotEntity, SummaryListingState } from '../../state/summary-listing';
|
||||||
import { filter, switchMap, take } from 'rxjs';
|
import { filter, switchMap, take } from 'rxjs';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { openStatusHistoryDialog } from '../../../../state/status-history/status-history.actions';
|
import {
|
||||||
|
getStatusHistoryAndOpenDialog,
|
||||||
|
openStatusHistoryDialog
|
||||||
|
} from '../../../../state/status-history/status-history.actions';
|
||||||
import { ComponentType } from '../../../../state/shared';
|
import { ComponentType } from '../../../../state/shared';
|
||||||
import { initialState } from '../../state/summary-listing/summary-listing.reducer';
|
import { initialState } from '../../state/summary-listing/summary-listing.reducer';
|
||||||
import * as SummaryListingActions from '../../state/summary-listing/summary-listing.actions';
|
import * as SummaryListingActions from '../../state/summary-listing/summary-listing.actions';
|
||||||
|
import { getSystemDiagnosticsAndOpenDialog } from '../../../../state/system-diagnostics/system-diagnostics.actions';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'remote-process-group-status-listing',
|
selector: 'remote-process-group-status-listing',
|
||||||
@ -62,7 +66,7 @@ export class RemoteProcessGroupStatusListing {
|
|||||||
.subscribe((rpg) => {
|
.subscribe((rpg) => {
|
||||||
if (rpg) {
|
if (rpg) {
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
openStatusHistoryDialog({
|
getStatusHistoryAndOpenDialog({
|
||||||
request: {
|
request: {
|
||||||
source: 'summary',
|
source: 'summary',
|
||||||
componentType: ComponentType.RemoteProcessGroup,
|
componentType: ComponentType.RemoteProcessGroup,
|
||||||
@ -99,4 +103,14 @@ export class RemoteProcessGroupStatusListing {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openSystemDiagnostics() {
|
||||||
|
this.store.dispatch(
|
||||||
|
getSystemDiagnosticsAndOpenDialog({
|
||||||
|
request: {
|
||||||
|
nodewise: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Client } from './client.service';
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class SystemDiagnosticsService {
|
||||||
|
private static readonly API: string = '../nifi-api';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private httpClient: HttpClient,
|
||||||
|
private client: Client
|
||||||
|
) {}
|
||||||
|
|
||||||
|
getSystemDiagnostics(nodewise?: boolean) {
|
||||||
|
if (nodewise) {
|
||||||
|
const params = {
|
||||||
|
nodewise: true
|
||||||
|
};
|
||||||
|
return this.httpClient.get(`${SystemDiagnosticsService.API}/system-diagnostics`, { params });
|
||||||
|
}
|
||||||
|
return this.httpClient.get(`${SystemDiagnosticsService.API}/system-diagnostics`);
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,8 @@ import { statusHistoryFeatureKey, StatusHistoryState } from './status-history';
|
|||||||
import { statusHistoryReducer } from './status-history/status-history.reducer';
|
import { statusHistoryReducer } from './status-history/status-history.reducer';
|
||||||
import { controllerServiceStateFeatureKey, ControllerServiceState } from './contoller-service-state';
|
import { controllerServiceStateFeatureKey, ControllerServiceState } from './contoller-service-state';
|
||||||
import { controllerServiceStateReducer } from './contoller-service-state/controller-service-state.reducer';
|
import { controllerServiceStateReducer } from './contoller-service-state/controller-service-state.reducer';
|
||||||
|
import { systemDiagnosticsFeatureKey, SystemDiagnosticsState } from './system-diagnostics';
|
||||||
|
import { systemDiagnosticsReducer } from './system-diagnostics/system-diagnostics.reducer';
|
||||||
|
|
||||||
export interface NiFiState {
|
export interface NiFiState {
|
||||||
router: RouterReducerState;
|
router: RouterReducerState;
|
||||||
@ -35,6 +37,7 @@ export interface NiFiState {
|
|||||||
[aboutFeatureKey]: AboutState;
|
[aboutFeatureKey]: AboutState;
|
||||||
[statusHistoryFeatureKey]: StatusHistoryState;
|
[statusHistoryFeatureKey]: StatusHistoryState;
|
||||||
[controllerServiceStateFeatureKey]: ControllerServiceState;
|
[controllerServiceStateFeatureKey]: ControllerServiceState;
|
||||||
|
[systemDiagnosticsFeatureKey]: SystemDiagnosticsState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const rootReducers: ActionReducerMap<NiFiState> = {
|
export const rootReducers: ActionReducerMap<NiFiState> = {
|
||||||
@ -43,5 +46,6 @@ export const rootReducers: ActionReducerMap<NiFiState> = {
|
|||||||
[extensionTypesFeatureKey]: extensionTypesReducer,
|
[extensionTypesFeatureKey]: extensionTypesReducer,
|
||||||
[aboutFeatureKey]: aboutReducer,
|
[aboutFeatureKey]: aboutReducer,
|
||||||
[statusHistoryFeatureKey]: statusHistoryReducer,
|
[statusHistoryFeatureKey]: statusHistoryReducer,
|
||||||
[controllerServiceStateFeatureKey]: controllerServiceStateReducer
|
[controllerServiceStateFeatureKey]: controllerServiceStateReducer,
|
||||||
|
[systemDiagnosticsFeatureKey]: systemDiagnosticsReducer
|
||||||
};
|
};
|
||||||
|
@ -20,14 +20,24 @@ import { StatusHistoryRequest, StatusHistoryResponse } from './index';
|
|||||||
|
|
||||||
const STATUS_HISTORY_PREFIX: string = '[Status History]';
|
const STATUS_HISTORY_PREFIX: string = '[Status History]';
|
||||||
|
|
||||||
export const loadStatusHistory = createAction(
|
export const reloadStatusHistory = createAction(
|
||||||
`${STATUS_HISTORY_PREFIX} Load Status History`,
|
`${STATUS_HISTORY_PREFIX} Reload Status History`,
|
||||||
props<{ request: StatusHistoryRequest }>()
|
props<{ request: StatusHistoryRequest }>()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getStatusHistoryAndOpenDialog = createAction(
|
||||||
|
`${STATUS_HISTORY_PREFIX} Get Status History and Open Dialog`,
|
||||||
|
props<{ request: StatusHistoryRequest }>()
|
||||||
|
);
|
||||||
|
|
||||||
|
export const reloadStatusHistorySuccess = createAction(
|
||||||
|
`${STATUS_HISTORY_PREFIX} Reload Status History Success`,
|
||||||
|
props<{ response: StatusHistoryResponse }>()
|
||||||
|
);
|
||||||
|
|
||||||
export const loadStatusHistorySuccess = createAction(
|
export const loadStatusHistorySuccess = createAction(
|
||||||
`${STATUS_HISTORY_PREFIX} Load Status History Success`,
|
`${STATUS_HISTORY_PREFIX} Load Status History Success`,
|
||||||
props<{ response: StatusHistoryResponse }>()
|
props<{ request: StatusHistoryRequest; response: StatusHistoryResponse }>()
|
||||||
);
|
);
|
||||||
|
|
||||||
export const openStatusHistoryDialog = createAction(
|
export const openStatusHistoryDialog = createAction(
|
||||||
|
@ -36,9 +36,9 @@ export class StatusHistoryEffects {
|
|||||||
private dialog: MatDialog
|
private dialog: MatDialog
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
loadStatusHistory$ = createEffect(() =>
|
reloadStatusHistory$ = createEffect(() =>
|
||||||
this.actions$.pipe(
|
this.actions$.pipe(
|
||||||
ofType(StatusHistoryActions.loadStatusHistory),
|
ofType(StatusHistoryActions.reloadStatusHistory),
|
||||||
map((action) => action.request),
|
map((action) => action.request),
|
||||||
switchMap((request: StatusHistoryRequest) =>
|
switchMap((request: StatusHistoryRequest) =>
|
||||||
from(
|
from(
|
||||||
@ -46,7 +46,7 @@ export class StatusHistoryEffects {
|
|||||||
.getProcessorStatusHistory(request.componentType, request.componentId)
|
.getProcessorStatusHistory(request.componentType, request.componentId)
|
||||||
.pipe(
|
.pipe(
|
||||||
map((response: any) =>
|
map((response: any) =>
|
||||||
StatusHistoryActions.loadStatusHistorySuccess({
|
StatusHistoryActions.reloadStatusHistorySuccess({
|
||||||
response: {
|
response: {
|
||||||
statusHistory: {
|
statusHistory: {
|
||||||
canRead: response.canRead,
|
canRead: response.canRead,
|
||||||
@ -68,6 +68,47 @@ export class StatusHistoryEffects {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
getStatusHistoryAndOpenDialog$ = createEffect(() =>
|
||||||
|
this.actions$.pipe(
|
||||||
|
ofType(StatusHistoryActions.getStatusHistoryAndOpenDialog),
|
||||||
|
map((action) => action.request),
|
||||||
|
switchMap((request) =>
|
||||||
|
from(
|
||||||
|
this.statusHistoryService
|
||||||
|
.getProcessorStatusHistory(request.componentType, request.componentId)
|
||||||
|
.pipe(
|
||||||
|
map((response: any) =>
|
||||||
|
StatusHistoryActions.loadStatusHistorySuccess({
|
||||||
|
request,
|
||||||
|
response: {
|
||||||
|
statusHistory: {
|
||||||
|
canRead: response.canRead,
|
||||||
|
statusHistory: response.statusHistory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
),
|
||||||
|
catchError((error) =>
|
||||||
|
of(
|
||||||
|
StatusHistoryActions.statusHistoryApiError({
|
||||||
|
error: error.error
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
loadStatusHistorySuccess$ = createEffect(() =>
|
||||||
|
this.actions$.pipe(
|
||||||
|
ofType(StatusHistoryActions.loadStatusHistorySuccess),
|
||||||
|
map((action) => action.request),
|
||||||
|
switchMap((request) => of(StatusHistoryActions.openStatusHistoryDialog({ request })))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
openStatusHistoryDialog$ = createEffect(
|
openStatusHistoryDialog$ = createEffect(
|
||||||
() =>
|
() =>
|
||||||
this.actions$.pipe(
|
this.actions$.pipe(
|
||||||
|
@ -19,10 +19,12 @@ import { StatusHistoryEntity, StatusHistoryState } from './index';
|
|||||||
import { createReducer, on } from '@ngrx/store';
|
import { createReducer, on } from '@ngrx/store';
|
||||||
import {
|
import {
|
||||||
clearStatusHistory,
|
clearStatusHistory,
|
||||||
loadStatusHistory,
|
reloadStatusHistory,
|
||||||
loadStatusHistorySuccess,
|
loadStatusHistorySuccess,
|
||||||
statusHistoryApiError,
|
statusHistoryApiError,
|
||||||
viewStatusHistoryComplete
|
viewStatusHistoryComplete,
|
||||||
|
reloadStatusHistorySuccess,
|
||||||
|
getStatusHistoryAndOpenDialog
|
||||||
} from './status-history.actions';
|
} from './status-history.actions';
|
||||||
import { produce } from 'immer';
|
import { produce } from 'immer';
|
||||||
|
|
||||||
@ -36,12 +38,12 @@ export const initialState: StatusHistoryState = {
|
|||||||
export const statusHistoryReducer = createReducer(
|
export const statusHistoryReducer = createReducer(
|
||||||
initialState,
|
initialState,
|
||||||
|
|
||||||
on(loadStatusHistory, (state) => ({
|
on(reloadStatusHistory, getStatusHistoryAndOpenDialog, (state) => ({
|
||||||
...state,
|
...state,
|
||||||
status: 'loading' as const
|
status: 'loading' as const
|
||||||
})),
|
})),
|
||||||
|
|
||||||
on(loadStatusHistorySuccess, (state, { response }) => ({
|
on(loadStatusHistorySuccess, reloadStatusHistorySuccess, (state, { response }) => ({
|
||||||
...state,
|
...state,
|
||||||
error: null,
|
error: null,
|
||||||
status: 'success' as const,
|
status: 'success' as const,
|
||||||
|
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
export const systemDiagnosticsFeatureKey = 'systemDiagnostics';
|
||||||
|
|
||||||
|
export interface SystemDiagnostics {
|
||||||
|
aggregateSnapshot: SystemDiagnosticSnapshot;
|
||||||
|
nodeSnapshots?: NodeSnapshot[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RepositoryStorageUsage {
|
||||||
|
freeSpace: string;
|
||||||
|
freeSpaceBytes: number;
|
||||||
|
totalSpace: string;
|
||||||
|
totalSpaceBytes: number;
|
||||||
|
usedSpace: string;
|
||||||
|
usedSpaceBytes: number;
|
||||||
|
utilization: string;
|
||||||
|
identifier?: string;
|
||||||
|
}
|
||||||
|
export interface GarbageCollection {
|
||||||
|
collectionCount: number;
|
||||||
|
collectionMillis: number;
|
||||||
|
collectionTime: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VersionInfo {
|
||||||
|
buildBranch: string;
|
||||||
|
buildRevision: string;
|
||||||
|
buildTag: string;
|
||||||
|
buildTimestamp: string;
|
||||||
|
javaVendor: string;
|
||||||
|
javaVersion: string;
|
||||||
|
niFiVersion: string;
|
||||||
|
osArchitecture: string;
|
||||||
|
osName: string;
|
||||||
|
osVersion: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodeSnapshot {
|
||||||
|
address: string;
|
||||||
|
apiPort: number;
|
||||||
|
nodeId: string;
|
||||||
|
snapshot: SystemDiagnosticSnapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SystemDiagnosticSnapshot {
|
||||||
|
availableProcessors: number;
|
||||||
|
contentRepositoryStorageUsage: RepositoryStorageUsage[];
|
||||||
|
daemonThreads: number;
|
||||||
|
flowFileRepositoryStorageUsage: RepositoryStorageUsage;
|
||||||
|
freeHeap: string;
|
||||||
|
freeHeapBytes: number;
|
||||||
|
freeNonHeap: string;
|
||||||
|
freeNonHeapBytes: number;
|
||||||
|
garbageCollection: GarbageCollection[];
|
||||||
|
heapUtilization: string;
|
||||||
|
maxHeap: string;
|
||||||
|
maxHeapBytes: number;
|
||||||
|
maxNonHeap: string;
|
||||||
|
maxNonHeapBytes: number;
|
||||||
|
processorLoadAverage: number;
|
||||||
|
provenanceRepositoryStorageUsage: RepositoryStorageUsage[];
|
||||||
|
statsLastRefreshed: string;
|
||||||
|
totalHeap: string;
|
||||||
|
totalHeapBytes: number;
|
||||||
|
totalNonHeap: string;
|
||||||
|
totalNonHeapBytes: string;
|
||||||
|
totalThreads: number;
|
||||||
|
uptime: string;
|
||||||
|
usedHeap: string;
|
||||||
|
usedHeapBytes: number;
|
||||||
|
usedNonHeap: string;
|
||||||
|
usedNonHeapBytes: number;
|
||||||
|
versionInfo: VersionInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SystemDiagnosticsRequest {
|
||||||
|
nodewise: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OpenSystemDiagnosticsDialogRequest {}
|
||||||
|
|
||||||
|
export interface SystemDiagnosticsResponse {
|
||||||
|
systemDiagnostics: SystemDiagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SystemDiagnosticsState {
|
||||||
|
systemDiagnostics: SystemDiagnostics | null;
|
||||||
|
loadedTimestamp: string;
|
||||||
|
error: string | null;
|
||||||
|
status: 'pending' | 'loading' | 'error' | 'success';
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { createAction, props } from '@ngrx/store';
|
||||||
|
import { OpenSystemDiagnosticsDialogRequest, SystemDiagnosticsRequest, SystemDiagnosticsResponse } from './index';
|
||||||
|
|
||||||
|
const SYSTEM_DIAGNOSTICS_PREFIX: string = '[System Diagnostics]';
|
||||||
|
|
||||||
|
export const reloadSystemDiagnostics = createAction(
|
||||||
|
`${SYSTEM_DIAGNOSTICS_PREFIX} Load System Diagnostics`,
|
||||||
|
props<{ request: SystemDiagnosticsRequest }>()
|
||||||
|
);
|
||||||
|
|
||||||
|
export const loadSystemDiagnosticsSuccess = createAction(
|
||||||
|
`${SYSTEM_DIAGNOSTICS_PREFIX} Load System Diagnostics Success`,
|
||||||
|
props<{ response: SystemDiagnosticsResponse }>()
|
||||||
|
);
|
||||||
|
|
||||||
|
export const reloadSystemDiagnosticsSuccess = createAction(
|
||||||
|
`${SYSTEM_DIAGNOSTICS_PREFIX} Reload System Diagnostics Success`,
|
||||||
|
props<{ response: SystemDiagnosticsResponse }>()
|
||||||
|
);
|
||||||
|
|
||||||
|
export const getSystemDiagnosticsAndOpenDialog = createAction(
|
||||||
|
`${SYSTEM_DIAGNOSTICS_PREFIX} Get System Diagnostics and Open Dialog`,
|
||||||
|
props<{ request: SystemDiagnosticsRequest }>()
|
||||||
|
);
|
||||||
|
|
||||||
|
export const openSystemDiagnosticsDialog = createAction(`${SYSTEM_DIAGNOSTICS_PREFIX} Open System Diagnostics Dialog`);
|
||||||
|
|
||||||
|
export const systemDiagnosticsApiError = createAction(
|
||||||
|
`${SYSTEM_DIAGNOSTICS_PREFIX} Load System Diagnostics Error`,
|
||||||
|
props<{ error: string }>()
|
||||||
|
);
|
||||||
|
|
||||||
|
export const resetSystemDiagnostics = createAction(`${SYSTEM_DIAGNOSTICS_PREFIX} Clear System Diagnostics`);
|
||||||
|
|
||||||
|
export const viewSystemDiagnosticsComplete = createAction(
|
||||||
|
`${SYSTEM_DIAGNOSTICS_PREFIX} View System Diagnostics Complete`
|
||||||
|
);
|
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { act, Actions, createEffect, ofType } from '@ngrx/effects';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { NiFiState } from '../index';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { SystemDiagnosticsService } from '../../service/system-diagnostics.service';
|
||||||
|
import * as SystemDiagnosticsActions from './system-diagnostics.actions';
|
||||||
|
import { catchError, from, map, of, switchMap, tap } from 'rxjs';
|
||||||
|
import { SystemDiagnosticsRequest } from './index';
|
||||||
|
import { SystemDiagnosticsDialog } from '../../ui/common/system-diagnostics-dialog/system-diagnostics-dialog.component';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class SystemDiagnosticsEffects {
|
||||||
|
constructor(
|
||||||
|
private actions$: Actions,
|
||||||
|
private store: Store<NiFiState>,
|
||||||
|
private systemDiagnosticsService: SystemDiagnosticsService,
|
||||||
|
private dialog: MatDialog
|
||||||
|
) {}
|
||||||
|
|
||||||
|
reloadSystemDiagnostics$ = createEffect(() =>
|
||||||
|
this.actions$.pipe(
|
||||||
|
ofType(SystemDiagnosticsActions.reloadSystemDiagnostics),
|
||||||
|
map((action) => action.request),
|
||||||
|
switchMap((request: SystemDiagnosticsRequest) =>
|
||||||
|
from(this.systemDiagnosticsService.getSystemDiagnostics(request.nodewise)).pipe(
|
||||||
|
map((response: any) =>
|
||||||
|
SystemDiagnosticsActions.reloadSystemDiagnosticsSuccess({
|
||||||
|
response: {
|
||||||
|
systemDiagnostics: response.systemDiagnostics
|
||||||
|
}
|
||||||
|
})
|
||||||
|
),
|
||||||
|
catchError((error) =>
|
||||||
|
of(
|
||||||
|
SystemDiagnosticsActions.systemDiagnosticsApiError({
|
||||||
|
error: error.error
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
getSystemDiagnosticsAndOpenDialog$ = createEffect(() =>
|
||||||
|
this.actions$.pipe(
|
||||||
|
ofType(SystemDiagnosticsActions.getSystemDiagnosticsAndOpenDialog),
|
||||||
|
map((action) => action.request),
|
||||||
|
switchMap((request) =>
|
||||||
|
from(this.systemDiagnosticsService.getSystemDiagnostics(request.nodewise)).pipe(
|
||||||
|
map((response: any) =>
|
||||||
|
SystemDiagnosticsActions.loadSystemDiagnosticsSuccess({
|
||||||
|
response: {
|
||||||
|
systemDiagnostics: response.systemDiagnostics
|
||||||
|
}
|
||||||
|
})
|
||||||
|
),
|
||||||
|
catchError((error) =>
|
||||||
|
of(
|
||||||
|
SystemDiagnosticsActions.systemDiagnosticsApiError({
|
||||||
|
error: error.error
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
loadSystemDiagnosticsSuccess$ = createEffect(() =>
|
||||||
|
this.actions$.pipe(
|
||||||
|
ofType(SystemDiagnosticsActions.loadSystemDiagnosticsSuccess),
|
||||||
|
switchMap(() => of(SystemDiagnosticsActions.openSystemDiagnosticsDialog()))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
openSystemDiagnosticsDialog$ = createEffect(
|
||||||
|
() =>
|
||||||
|
this.actions$.pipe(
|
||||||
|
ofType(SystemDiagnosticsActions.openSystemDiagnosticsDialog),
|
||||||
|
tap(() => {
|
||||||
|
this.dialog
|
||||||
|
.open(SystemDiagnosticsDialog, { panelClass: 'large-dialog' })
|
||||||
|
.afterClosed()
|
||||||
|
.subscribe(() => {
|
||||||
|
this.store.dispatch(SystemDiagnosticsActions.viewSystemDiagnosticsComplete());
|
||||||
|
});
|
||||||
|
})
|
||||||
|
),
|
||||||
|
{ dispatch: false }
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { SystemDiagnosticsState } from './index';
|
||||||
|
import { createReducer, on } from '@ngrx/store';
|
||||||
|
import {
|
||||||
|
reloadSystemDiagnostics,
|
||||||
|
loadSystemDiagnosticsSuccess,
|
||||||
|
resetSystemDiagnostics,
|
||||||
|
systemDiagnosticsApiError,
|
||||||
|
viewSystemDiagnosticsComplete,
|
||||||
|
getSystemDiagnosticsAndOpenDialog,
|
||||||
|
reloadSystemDiagnosticsSuccess
|
||||||
|
} from './system-diagnostics.actions';
|
||||||
|
|
||||||
|
export const initialSystemDiagnosticsState: SystemDiagnosticsState = {
|
||||||
|
systemDiagnostics: null,
|
||||||
|
status: 'pending',
|
||||||
|
error: null,
|
||||||
|
loadedTimestamp: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
export const systemDiagnosticsReducer = createReducer(
|
||||||
|
initialSystemDiagnosticsState,
|
||||||
|
|
||||||
|
on(reloadSystemDiagnostics, getSystemDiagnosticsAndOpenDialog, (state) => ({
|
||||||
|
...state,
|
||||||
|
status: 'loading' as const
|
||||||
|
})),
|
||||||
|
|
||||||
|
on(loadSystemDiagnosticsSuccess, reloadSystemDiagnosticsSuccess, (state, { response }) => ({
|
||||||
|
...state,
|
||||||
|
error: null,
|
||||||
|
status: 'success' as const,
|
||||||
|
loadedTimestamp: response.systemDiagnostics.aggregateSnapshot.statsLastRefreshed,
|
||||||
|
systemDiagnostics: response.systemDiagnostics
|
||||||
|
})),
|
||||||
|
|
||||||
|
on(systemDiagnosticsApiError, (state, { error }) => ({
|
||||||
|
...state,
|
||||||
|
error,
|
||||||
|
status: 'error' as const
|
||||||
|
})),
|
||||||
|
|
||||||
|
on(resetSystemDiagnostics, (state) => ({
|
||||||
|
...initialSystemDiagnosticsState
|
||||||
|
})),
|
||||||
|
|
||||||
|
on(viewSystemDiagnosticsComplete, (state) => ({
|
||||||
|
...initialSystemDiagnosticsState
|
||||||
|
}))
|
||||||
|
);
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { createFeatureSelector, createSelector } from '@ngrx/store';
|
||||||
|
import { systemDiagnosticsFeatureKey, SystemDiagnosticsState } from './index';
|
||||||
|
|
||||||
|
export const selectSystemDiagnosticsState = createFeatureSelector<SystemDiagnosticsState>(systemDiagnosticsFeatureKey);
|
||||||
|
|
||||||
|
export const selectSystemDiagnostics = createSelector(
|
||||||
|
selectSystemDiagnosticsState,
|
||||||
|
(state: SystemDiagnosticsState) => state.systemDiagnostics
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectSystemDiagnosticsLoadedTimestamp = createSelector(
|
||||||
|
selectSystemDiagnosticsState,
|
||||||
|
(state: SystemDiagnosticsState) => state.loadedTimestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectSystemDiagnosticsError = createSelector(
|
||||||
|
selectSystemDiagnosticsState,
|
||||||
|
(state: SystemDiagnosticsState) => state.error
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectSystemDiagnosticsStatus = createSelector(
|
||||||
|
selectSystemDiagnosticsState,
|
||||||
|
(state: SystemDiagnosticsState) => state.status
|
||||||
|
);
|
@ -621,13 +621,14 @@ export class StatusHistoryChart {
|
|||||||
const marginTop: any = controlContainer.computedStyleMap().get('margin-top');
|
const marginTop: any = controlContainer.computedStyleMap().get('margin-top');
|
||||||
const statusHistory = document.getElementsByClassName('status-history')![0];
|
const statusHistory = document.getElementsByClassName('status-history')![0];
|
||||||
const dialogContent = statusHistory.getElementsByClassName('dialog-content')![0];
|
const dialogContent = statusHistory.getElementsByClassName('dialog-content')![0];
|
||||||
|
const descriptorContainer = document.getElementsByClassName('selected-descriptor-container')![0];
|
||||||
const dialogStyles: any = dialogContent.computedStyleMap();
|
const dialogStyles: any = dialogContent.computedStyleMap();
|
||||||
const bodyHeight = document.body.getBoundingClientRect().height;
|
const bodyHeight = document.body.getBoundingClientRect().height;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
bodyHeight -
|
bodyHeight -
|
||||||
controlContainer.clientHeight -
|
controlContainer.clientHeight -
|
||||||
50 -
|
descriptorContainer.clientHeight -
|
||||||
parseInt(marginTop.value, 10) -
|
parseInt(marginTop.value, 10) -
|
||||||
parseInt(dialogStyles.get('top')?.value) -
|
parseInt(dialogStyles.get('top')?.value) -
|
||||||
parseInt(dialogStyles.get('bottom')?.value)
|
parseInt(dialogStyles.get('bottom')?.value)
|
||||||
|
@ -35,12 +35,12 @@
|
|||||||
*ngIf="componentDetails$ | async; let componentDetails"
|
*ngIf="componentDetails$ | async; let componentDetails"
|
||||||
class="flex flex-1 w-full gap-x-4">
|
class="flex flex-1 w-full gap-x-4">
|
||||||
<div class="component-details flex flex-col gap-y-3">
|
<div class="component-details flex flex-col gap-y-3">
|
||||||
<div
|
<ng-container *ngFor="let entry of Object.entries(componentDetails)">
|
||||||
*ngFor="let entry of Object.entries(componentDetails)"
|
<div *ngIf="entry[0] && entry[1]" class="flex flex-col">
|
||||||
class="flex flex-col">
|
<div>{{ entry[0] }}</div>
|
||||||
<div>{{ entry[0] }}</div>
|
<div class="value">{{ entry[1] }}</div>
|
||||||
<div class="value">{{ entry[1] }}</div>
|
</div>
|
||||||
</div>
|
</ng-container>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<div>Start</div>
|
<div>Start</div>
|
||||||
<div class="value">{{ minDate }}</div>
|
<div class="value">{{ minDate }}</div>
|
||||||
@ -89,7 +89,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="chart-panel grow flex flex-col">
|
<div class="chart-panel grow flex flex-col">
|
||||||
<div *ngIf="fieldDescriptors$ | async">
|
<div class="selected-descriptor-container" *ngIf="fieldDescriptors$ | async">
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-select formControlName="fieldDescriptor">
|
<mat-select formControlName="fieldDescriptor">
|
||||||
<ng-container *ngFor="let descriptor of fieldDescriptors">
|
<ng-container *ngFor="let descriptor of fieldDescriptors">
|
||||||
|
@ -65,6 +65,10 @@
|
|||||||
.mat-mdc-dialog-content {
|
.mat-mdc-dialog-content {
|
||||||
max-height: unset;
|
max-height: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selected-descriptor-container {
|
||||||
|
height: 68px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ import {
|
|||||||
StatusHistoryState
|
StatusHistoryState
|
||||||
} from '../../../state/status-history';
|
} from '../../../state/status-history';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { loadStatusHistory } from '../../../state/status-history/status-history.actions';
|
import { reloadStatusHistory } from '../../../state/status-history/status-history.actions';
|
||||||
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||||
import {
|
import {
|
||||||
selectStatusHistory,
|
selectStatusHistory,
|
||||||
@ -115,8 +115,6 @@ export class StatusHistory implements OnInit, AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.refresh();
|
|
||||||
|
|
||||||
this.statusHistory$.pipe(filter((entity) => !!entity)).subscribe((entity: StatusHistoryEntity) => {
|
this.statusHistory$.pipe(filter((entity) => !!entity)).subscribe((entity: StatusHistoryEntity) => {
|
||||||
if (entity) {
|
if (entity) {
|
||||||
this.instances = [];
|
this.instances = [];
|
||||||
@ -171,9 +169,6 @@ export class StatusHistory implements OnInit, AfterViewInit {
|
|||||||
this.maxDate = this.nifiCommon.formatDateTime(new Date(maxDate));
|
this.maxDate = this.nifiCommon.formatDateTime(new Date(maxDate));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
ngAfterViewInit(): void {
|
|
||||||
this.fieldDescriptors$
|
this.fieldDescriptors$
|
||||||
.pipe(
|
.pipe(
|
||||||
filter((descriptors) => !!descriptors),
|
filter((descriptors) => !!descriptors),
|
||||||
@ -184,8 +179,11 @@ export class StatusHistory implements OnInit, AfterViewInit {
|
|||||||
|
|
||||||
// select the first field description by default
|
// select the first field description by default
|
||||||
this.statusHistoryForm.get('fieldDescriptor')?.setValue(descriptors[0]);
|
this.statusHistoryForm.get('fieldDescriptor')?.setValue(descriptors[0]);
|
||||||
|
this.selectedDescriptor = descriptors[0];
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
// when the selected descriptor changes, update the chart
|
// when the selected descriptor changes, update the chart
|
||||||
this.statusHistoryForm.get('fieldDescriptor')?.valueChanges.subscribe((descriptor: FieldDescriptor) => {
|
this.statusHistoryForm.get('fieldDescriptor')?.valueChanges.subscribe((descriptor: FieldDescriptor) => {
|
||||||
if (this.instances.length > 0) {
|
if (this.instances.length > 0) {
|
||||||
@ -199,7 +197,7 @@ export class StatusHistory implements OnInit, AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
refresh() {
|
refresh() {
|
||||||
this.store.dispatch(loadStatusHistory({ request: this.request }));
|
this.store.dispatch(reloadStatusHistory({ request: this.request }));
|
||||||
}
|
}
|
||||||
|
|
||||||
getSelectOptionTipData(descriptor: FieldDescriptor): TextTipInput {
|
getSelectOptionTipData(descriptor: FieldDescriptor): TextTipInput {
|
||||||
|
@ -0,0 +1,264 @@
|
|||||||
|
<!--
|
||||||
|
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
~ contributor license agreements. See the NOTICE file distributed with
|
||||||
|
~ this work for additional information regarding copyright ownership.
|
||||||
|
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
~ (the "License"); you may not use this file except in compliance with
|
||||||
|
~ the License. You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<ng-container *ngIf="(systemDiagnostics$ | async)?.aggregateSnapshot; let systemDiagnostics">
|
||||||
|
<h2 mat-dialog-title>System Diagnostics</h2>
|
||||||
|
<div class="system-diagnostics">
|
||||||
|
<mat-dialog-content>
|
||||||
|
<div class="dialog-content">
|
||||||
|
<mat-tab-group>
|
||||||
|
<mat-tab label="JVM">
|
||||||
|
<div class="tab-content py-4 h-full w-full">
|
||||||
|
<div class="inset-0 flex gap-y-4">
|
||||||
|
<div class="flex flex-col flex-1 gap-y-4">
|
||||||
|
<section>
|
||||||
|
<div class="section-header">Heap ({{ systemDiagnostics.heapUtilization }})</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-y-3">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div>Max</div>
|
||||||
|
<div class="value">{{ systemDiagnostics.maxHeap }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div>Total</div>
|
||||||
|
<div class="value">{{ systemDiagnostics.totalHeap }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div>Used</div>
|
||||||
|
<div class="value">{{ systemDiagnostics.usedHeap }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div>Free</div>
|
||||||
|
<div class="value">{{ systemDiagnostics.freeHeap }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<div class="section-header">Garbage Collection</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-y-3" *ngIf="sortedGarbageCollections">
|
||||||
|
<div class="flex flex-col" *ngFor="let gc of sortedGarbageCollections">
|
||||||
|
<div>{{ gc.name }}</div>
|
||||||
|
<div class="value">
|
||||||
|
{{ gc.collectionCount }} times ({{ gc.collectionTime }})
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col flex-1 gap-y-4">
|
||||||
|
<section>
|
||||||
|
<div class="section-header">Non Heap</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-y-3">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div>Max</div>
|
||||||
|
<div class="value">{{ systemDiagnostics.maxNonHeap }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div>Total</div>
|
||||||
|
<div class="value">{{ systemDiagnostics.totalNonHeap }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div>Used</div>
|
||||||
|
<div class="value">{{ systemDiagnostics.usedNonHeap }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div>Free</div>
|
||||||
|
<div class="value">{{ systemDiagnostics.freeNonHeap }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<div class="section-header">Runtime</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-y-3">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div>Uptime</div>
|
||||||
|
<div class="value">{{ systemDiagnostics.uptime }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="System">
|
||||||
|
<div class="tab-content py-4 gap-y-6 h-full w-full flex flex-col">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex flex-col flex-1 gap-y-4">
|
||||||
|
<div class="flex flex-col gap-y-3">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div>Available Cores</div>
|
||||||
|
<div class="value">{{ systemDiagnostics.availableProcessors }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col flex-1 gap-y-4">
|
||||||
|
<div class="flex flex-col gap-y-3">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="flex gap-x-3 items-center">
|
||||||
|
<div>Core Load Average</div>
|
||||||
|
<div
|
||||||
|
class="fa fa-question-circle"
|
||||||
|
nifiTooltip
|
||||||
|
[tooltipComponentType]="TextTip"
|
||||||
|
[tooltipInputData]="getCoreLoadTooltip()"></div>
|
||||||
|
</div>
|
||||||
|
<div class="value">
|
||||||
|
{{ formatFloat(systemDiagnostics.processorLoadAverage) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="flex flex-col pr-4">
|
||||||
|
<div class="section-header">FlowFile Repository Usage</div>
|
||||||
|
<div>
|
||||||
|
<div class="capitalize">Usage:</div>
|
||||||
|
<mat-progress-bar
|
||||||
|
mode="determinate"
|
||||||
|
[value]="
|
||||||
|
getRepositoryStorageUsagePercent(
|
||||||
|
systemDiagnostics.flowFileRepositoryStorageUsage
|
||||||
|
)
|
||||||
|
">
|
||||||
|
</mat-progress-bar>
|
||||||
|
<div class="value">
|
||||||
|
{{ systemDiagnostics.flowFileRepositoryStorageUsage.utilization }}
|
||||||
|
({{ systemDiagnostics.flowFileRepositoryStorageUsage.usedSpace }}
|
||||||
|
of
|
||||||
|
{{ systemDiagnostics.flowFileRepositoryStorageUsage.totalSpace }})
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="flex flex-col pr-4">
|
||||||
|
<div class="section-header">Content Repository Usage</div>
|
||||||
|
<div class="repository-storage-container flex flex-col gap-y-2">
|
||||||
|
<div *ngFor="let repo of systemDiagnostics.contentRepositoryStorageUsage">
|
||||||
|
<div class="capitalize">Usage for {{ repo.identifier }}:</div>
|
||||||
|
<mat-progress-bar
|
||||||
|
mode="determinate"
|
||||||
|
[value]="getRepositoryStorageUsagePercent(repo)">
|
||||||
|
</mat-progress-bar>
|
||||||
|
<div class="value">
|
||||||
|
{{ repo.utilization }} ({{ repo.usedSpace }} of {{ repo.totalSpace }})
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="flex flex-col pr-4">
|
||||||
|
<div class="section-header">Provenance Repository Usage</div>
|
||||||
|
<div class="repository-storage-container flex flex-col gap-y-2">
|
||||||
|
<div *ngFor="let repo of systemDiagnostics.provenanceRepositoryStorageUsage">
|
||||||
|
<div class="capitalize">Usage for {{ repo.identifier }}:</div>
|
||||||
|
<mat-progress-bar
|
||||||
|
mode="determinate"
|
||||||
|
[value]="getRepositoryStorageUsagePercent(repo)">
|
||||||
|
</mat-progress-bar>
|
||||||
|
<div class="value">
|
||||||
|
{{ repo.utilization }} ({{ repo.usedSpace }} of {{ repo.totalSpace }})
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="Version">
|
||||||
|
<div class="tab-content py-4 h-full w-full">
|
||||||
|
<div class="inset-0 flex flex-col gap-y-4">
|
||||||
|
<section>
|
||||||
|
<div class="section-header">NiFi</div>
|
||||||
|
|
||||||
|
<dl class="setting-attributes-list">
|
||||||
|
<dt>NiFi Version</dt>
|
||||||
|
<dd>{{ systemDiagnostics.versionInfo.niFiVersion }}</dd>
|
||||||
|
|
||||||
|
<dt>Tag</dt>
|
||||||
|
<dd>{{ systemDiagnostics.versionInfo.buildTag }}</dd>
|
||||||
|
|
||||||
|
<dt>Build Date/Time</dt>
|
||||||
|
<dd>{{ systemDiagnostics.versionInfo.buildTimestamp }}</dd>
|
||||||
|
|
||||||
|
<dt>Branch</dt>
|
||||||
|
<dd>{{ systemDiagnostics.versionInfo.buildBranch }}</dd>
|
||||||
|
|
||||||
|
<dt>Revision</dt>
|
||||||
|
<dd>{{ systemDiagnostics.versionInfo.buildRevision }}</dd>
|
||||||
|
</dl>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<div class="section-header">Java</div>
|
||||||
|
|
||||||
|
<dl class="setting-attributes-list">
|
||||||
|
<dt>Version</dt>
|
||||||
|
<dd>{{ systemDiagnostics.versionInfo.javaVersion }}</dd>
|
||||||
|
|
||||||
|
<dt>Vendor</dt>
|
||||||
|
<dd>{{ systemDiagnostics.versionInfo.javaVendor }}</dd>
|
||||||
|
</dl>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<div class="section-header">Operating System</div>
|
||||||
|
|
||||||
|
<dl class="setting-attributes-list">
|
||||||
|
<dt>Name</dt>
|
||||||
|
<dd>{{ systemDiagnostics.versionInfo.osName }}</dd>
|
||||||
|
|
||||||
|
<dt>Version</dt>
|
||||||
|
<dd>{{ systemDiagnostics.versionInfo.osVersion }}</dd>
|
||||||
|
|
||||||
|
<dt>Architecture</dt>
|
||||||
|
<dd>{{ systemDiagnostics.versionInfo.osArchitecture }}</dd>
|
||||||
|
</dl>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</div>
|
||||||
|
</mat-dialog-content>
|
||||||
|
<mat-dialog-actions>
|
||||||
|
<div class="flex flex-1 justify-between">
|
||||||
|
<div class="refresh-container flex items-center gap-x-2">
|
||||||
|
<button class="nifi-button" (click)="refreshSystemDiagnostics()">
|
||||||
|
<i class="fa fa-refresh" [class.fa-spin]="(status$ | async) === 'loading'"></i>
|
||||||
|
</button>
|
||||||
|
<div>Last updated:</div>
|
||||||
|
<div class="refresh-timestamp">{{ loadedTimestamp$ | async }}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button color="primary" mat-raised-button mat-dialog-close>Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-dialog-actions>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
@ -0,0 +1,67 @@
|
|||||||
|
/*!
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@use '@angular/material' as mat;
|
||||||
|
|
||||||
|
.system-diagnostics {
|
||||||
|
@include mat.button-density(-1);
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
.mdc-dialog__content {
|
||||||
|
padding: 0 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
.dialog-content {
|
||||||
|
min-height: 500px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content {
|
||||||
|
position: relative;
|
||||||
|
height: 480px;
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
color: #728e9b;
|
||||||
|
font-size: 15px;
|
||||||
|
font-family: 'Roboto Slab';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-attributes-list {
|
||||||
|
dt {
|
||||||
|
float: left;
|
||||||
|
clear: left;
|
||||||
|
padding: 0 0.5em 0.2em 0;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
dd {
|
||||||
|
margin-left: 9em;
|
||||||
|
padding-bottom: 0.2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-mdc-form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-dialog-actions {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { SystemDiagnosticsDialog } from './system-diagnostics-dialog.component';
|
||||||
|
import { provideMockStore } from '@ngrx/store/testing';
|
||||||
|
import { initialSystemDiagnosticsState } from '../../../state/system-diagnostics/system-diagnostics.reducer';
|
||||||
|
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||||
|
|
||||||
|
describe('SystemDiagnosticsDialog', () => {
|
||||||
|
let component: SystemDiagnosticsDialog;
|
||||||
|
let fixture: ComponentFixture<SystemDiagnosticsDialog>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [SystemDiagnosticsDialog],
|
||||||
|
providers: [
|
||||||
|
{ provide: MAT_DIALOG_DATA, useValue: {} },
|
||||||
|
provideMockStore({ initialState: initialSystemDiagnosticsState })
|
||||||
|
]
|
||||||
|
});
|
||||||
|
fixture = TestBed.createComponent(SystemDiagnosticsDialog);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component, Inject, OnInit, signal } from '@angular/core';
|
||||||
|
import { CommonModule, NgForOf } from '@angular/common';
|
||||||
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
|
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
|
||||||
|
import {
|
||||||
|
GarbageCollection,
|
||||||
|
OpenSystemDiagnosticsDialogRequest,
|
||||||
|
RepositoryStorageUsage,
|
||||||
|
SystemDiagnosticsState
|
||||||
|
} from '../../../state/system-diagnostics';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import {
|
||||||
|
selectSystemDiagnostics,
|
||||||
|
selectSystemDiagnosticsLoadedTimestamp,
|
||||||
|
selectSystemDiagnosticsStatus
|
||||||
|
} from '../../../state/system-diagnostics/system-diagnostics.selectors';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { reloadSystemDiagnostics } from '../../../state/system-diagnostics/system-diagnostics.actions';
|
||||||
|
import { NiFiCommon } from '../../../service/nifi-common.service';
|
||||||
|
import { filter } from 'rxjs';
|
||||||
|
import { TextTip } from '../tooltips/text-tip/text-tip.component';
|
||||||
|
import { NifiTooltipDirective } from '../tooltips/nifi-tooltip.directive';
|
||||||
|
import { TextTipInput } from '../../../state/shared';
|
||||||
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'system-diagnostics-dialog',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
MatTabsModule,
|
||||||
|
MatDialogModule,
|
||||||
|
MatButtonModule,
|
||||||
|
NgForOf,
|
||||||
|
NifiTooltipDirective,
|
||||||
|
MatProgressBarModule
|
||||||
|
],
|
||||||
|
templateUrl: './system-diagnostics-dialog.component.html',
|
||||||
|
styleUrls: ['./system-diagnostics-dialog.component.scss']
|
||||||
|
})
|
||||||
|
export class SystemDiagnosticsDialog implements OnInit {
|
||||||
|
systemDiagnostics$ = this.store.select(selectSystemDiagnostics);
|
||||||
|
loadedTimestamp$ = this.store.select(selectSystemDiagnosticsLoadedTimestamp);
|
||||||
|
status$ = this.store.select(selectSystemDiagnosticsStatus);
|
||||||
|
sortedGarbageCollections: GarbageCollection[] | null = null;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private store: Store<SystemDiagnosticsState>,
|
||||||
|
private nifiCommon: NiFiCommon,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public request: OpenSystemDiagnosticsDialogRequest
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.systemDiagnostics$.pipe(filter((diagnostics) => !!diagnostics)).subscribe((diagnostics) => {
|
||||||
|
const sorted = diagnostics!.aggregateSnapshot.garbageCollection.slice();
|
||||||
|
sorted.sort((a, b) => {
|
||||||
|
return this.nifiCommon.compareString(a.name, b.name);
|
||||||
|
});
|
||||||
|
this.sortedGarbageCollections = sorted;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshSystemDiagnostics() {
|
||||||
|
this.store.dispatch(
|
||||||
|
reloadSystemDiagnostics({
|
||||||
|
request: {
|
||||||
|
nodewise: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
formatFloat(value: number): string {
|
||||||
|
return this.nifiCommon.formatFloat(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCoreLoadTooltip(): TextTipInput {
|
||||||
|
return {
|
||||||
|
text: 'Core load average for the last minute. Not available on all platforms.'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getRepositoryStorageUsagePercent(repoStorage: RepositoryStorageUsage): number {
|
||||||
|
return (repoStorage.usedSpaceBytes / repoStorage.totalSpaceBytes) * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected readonly TextTip = TextTip;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user