From b8d0dd57944ba367d5acc2fbdcb475247abf4f95 Mon Sep 17 00:00:00 2001 From: Richard Cox Date: Tue, 5 May 2020 17:21:30 +0100 Subject: [PATCH 01/14] Fix row highlight (see app github tab commit table) - wasn't showing after list in list changes - fixes #4243 --- .../list/list-table/table-row/table-row.component.html | 4 ++-- .../list/list-table/table-row/table-row.component.scss | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/frontend/packages/core/src/shared/components/list/list-table/table-row/table-row.component.html b/src/frontend/packages/core/src/shared/components/list/list-table/table-row/table-row.component.html index a9cd96a7f3..be2ec31af4 100644 --- a/src/frontend/packages/core/src/shared/components/list/list-table/table-row/table-row.component.html +++ b/src/frontend/packages/core/src/shared/components/list/list-table/table-row/table-row.component.html @@ -1,5 +1,5 @@
+ [ngClass]="{'table-row-wrapper__blocked': isBlocked$ | async, 'table-row-wrapper__warning': inWarningState$ | async,'table-row-wrapper__errored': inErrorState$ | async }">
Deleting
@@ -11,7 +11,7 @@
+ [hideToggle]="true" [ngClass]="{'table-row-wrapper__highlighted': isHighlighted$ | async}"> Date: Wed, 6 May 2020 09:07:14 +0100 Subject: [PATCH 02/14] Improve metrics view --- .../cf-endpoint-details.component.scss | 2 +- .../packages/core/sass/_all-theme.scss | 4 +- .../packages/core/src/base-entity-types.ts | 10 ++- .../metrics-endpoint-details.component.html | 9 ++ .../metrics-endpoint-details.component.scss | 16 ++++ ...metrics-endpoint-details.component.spec.ts | 31 +++++++ .../metrics-endpoint-details.component.ts | 75 ++++++++++++++++ .../src/features/metrics/metrics.helpers.ts | 74 +++++++++++++++ .../src/features/metrics/metrics.module.ts | 15 ++-- .../metrics/metrics/metrics.component.html | 90 ++++++++++--------- .../metrics/metrics/metrics.component.scss | 80 ++++++++++++++++- .../metrics/metrics.component.theme.scss | 15 ++++ .../metrics/metrics/metrics.component.ts | 61 ++++++------- .../store/src/actions/metrics-api.actions.ts | 18 +++- .../store/src/effects/metrics.effects.ts | 4 +- .../src/reducers/system-endpoints.reducer.ts | 13 +++ .../store/src/types/endpoint.types.ts | 5 +- 17 files changed, 432 insertions(+), 90 deletions(-) create mode 100644 src/frontend/packages/core/src/features/metrics/metrics-endpoint-details/metrics-endpoint-details.component.html create mode 100644 src/frontend/packages/core/src/features/metrics/metrics-endpoint-details/metrics-endpoint-details.component.scss create mode 100644 src/frontend/packages/core/src/features/metrics/metrics-endpoint-details/metrics-endpoint-details.component.spec.ts create mode 100644 src/frontend/packages/core/src/features/metrics/metrics-endpoint-details/metrics-endpoint-details.component.ts create mode 100644 src/frontend/packages/core/src/features/metrics/metrics.helpers.ts create mode 100644 src/frontend/packages/core/src/features/metrics/metrics/metrics.component.theme.scss diff --git a/src/frontend/packages/cloud-foundry/src/shared/components/cf-endpoint-details/cf-endpoint-details.component.scss b/src/frontend/packages/cloud-foundry/src/shared/components/cf-endpoint-details/cf-endpoint-details.component.scss index 5b7707aa0e..4a125b2a60 100644 --- a/src/frontend/packages/cloud-foundry/src/shared/components/cf-endpoint-details/cf-endpoint-details.component.scss +++ b/src/frontend/packages/cloud-foundry/src/shared/components/cf-endpoint-details/cf-endpoint-details.component.scss @@ -11,6 +11,6 @@ align-items: center; display: flex; justify-content: center; - width: 32px; + margin-right: 8px; } } diff --git a/src/frontend/packages/core/sass/_all-theme.scss b/src/frontend/packages/core/sass/_all-theme.scss index a6fdef57e5..4f657dbc93 100644 --- a/src/frontend/packages/core/sass/_all-theme.scss +++ b/src/frontend/packages/core/sass/_all-theme.scss @@ -67,6 +67,7 @@ @import '../../cloud-foundry/src/features/applications/application-wall/application-wall.component.theme'; @import '../../core/src/features/error-page/error-page/error-page.component.theme'; @import '../../core/src/features/endpoints/backup-restore/restore-endpoints/restore-endpoints.component.theme'; +@import '../../core/src/features/metrics/metrics/metrics.component.theme'; // Defaults $side-nav-light-text: #fff; @@ -160,7 +161,8 @@ $side-nav-light-active: #484848; @include code-block-theme($theme, $app-theme); @include copy-to-clipboard-theme($theme, $app-theme); @include app-user-avatar-theme($theme, $app-theme); - @include restore-endpoints-theme($theme, $app-theme) + @include restore-endpoints-theme($theme, $app-theme); + @include metrics-component-theme($theme, $app-theme); } @function app-generate-nav-theme($theme, $nav-theme: null) { diff --git a/src/frontend/packages/core/src/base-entity-types.ts b/src/frontend/packages/core/src/base-entity-types.ts index 33ba893917..37f2c840ac 100644 --- a/src/frontend/packages/core/src/base-entity-types.ts +++ b/src/frontend/packages/core/src/base-entity-types.ts @@ -1,8 +1,9 @@ -import { systemEndpointsReducer } from '../../store/src/reducers/system-endpoints.reducer'; +import { StratosCatalogEndpointEntity, StratosCatalogEntity } from '../../store/src/entity-catalog/entity-catalog-entity'; import { addOrUpdateUserFavoriteMetadataReducer, deleteUserFavoriteMetadataReducer, } from '../../store/src/reducers/favorite.reducer'; +import { systemEndpointsReducer } from '../../store/src/reducers/system-endpoints.reducer'; import { endpointEntitySchema, STRATOS_ENDPOINT_TYPE, @@ -10,8 +11,10 @@ import { userFavoritesEntitySchema, userProfileEntitySchema, } from './base-entity-schemas'; -import { StratosCatalogEndpointEntity, StratosCatalogEntity } from '../../store/src/entity-catalog/entity-catalog-entity'; import { BaseEndpointAuth } from './features/endpoints/endpoint-auth'; +import { + MetricsEndpointDetailsComponent, +} from './features/metrics/metrics-endpoint-details/metrics-endpoint-details.component'; // // These types are used to represent the base stratos types. @@ -94,7 +97,8 @@ export function generateStratosEntities() { tokenSharing: true, logoUrl: '/core/assets/endpoint-icons/metrics.svg', authTypes: [BaseEndpointAuth.UsernamePassword, BaseEndpointAuth.None], - renderPriority: 1 + renderPriority: 1, + listDetailsComponent: MetricsEndpointDetailsComponent, }, metadata => `/endpoints/metrics/${metadata.guid}` ) diff --git a/src/frontend/packages/core/src/features/metrics/metrics-endpoint-details/metrics-endpoint-details.component.html b/src/frontend/packages/core/src/features/metrics/metrics-endpoint-details/metrics-endpoint-details.component.html new file mode 100644 index 0000000000..d15144178e --- /dev/null +++ b/src/frontend/packages/core/src/features/metrics/metrics-endpoint-details/metrics-endpoint-details.component.html @@ -0,0 +1,9 @@ +
+
+ warning + {{ info.ok }} + / {{info.total}} + sources + source +
+
diff --git a/src/frontend/packages/core/src/features/metrics/metrics-endpoint-details/metrics-endpoint-details.component.scss b/src/frontend/packages/core/src/features/metrics/metrics-endpoint-details/metrics-endpoint-details.component.scss new file mode 100644 index 0000000000..c18a9f0f79 --- /dev/null +++ b/src/frontend/packages/core/src/features/metrics/metrics-endpoint-details/metrics-endpoint-details.component.scss @@ -0,0 +1,16 @@ +.metrics-details { + display: flex; + flex-direction: column; + + &__line { + align-items: center; + display: flex; + } + + &__icon { + align-items: center; + display: flex; + justify-content: center; + margin-right: 8px; + } +} diff --git a/src/frontend/packages/core/src/features/metrics/metrics-endpoint-details/metrics-endpoint-details.component.spec.ts b/src/frontend/packages/core/src/features/metrics/metrics-endpoint-details/metrics-endpoint-details.component.spec.ts new file mode 100644 index 0000000000..5676ad6173 --- /dev/null +++ b/src/frontend/packages/core/src/features/metrics/metrics-endpoint-details/metrics-endpoint-details.component.spec.ts @@ -0,0 +1,31 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SharedModule } from '../../../shared/shared.module'; +import { CoreModule } from './../../../core/core.module'; +import { MetricsEndpointDetailsComponent } from './metrics-endpoint-details.component'; + +describe('MetricsEndpointDetailsComponent', () => { + let component: MetricsEndpointDetailsComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + CoreModule, + SharedModule + ], + declarations: [ MetricsEndpointDetailsComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MetricsEndpointDetailsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/frontend/packages/core/src/features/metrics/metrics-endpoint-details/metrics-endpoint-details.component.ts b/src/frontend/packages/core/src/features/metrics/metrics-endpoint-details/metrics-endpoint-details.component.ts new file mode 100644 index 0000000000..0fd3561fcc --- /dev/null +++ b/src/frontend/packages/core/src/features/metrics/metrics-endpoint-details/metrics-endpoint-details.component.ts @@ -0,0 +1,75 @@ +import { Component, Input } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { MetricsStratosAction } from 'frontend/packages/store/src/actions/metrics-api.actions'; +import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; +import { filter, map, tap } from 'rxjs/operators'; + +import { AppState } from '../../../../../store/src/app-state'; +import { EndpointListDetailsComponent } from '../../../shared/components/list/list-types/endpoint/endpoint-list.helpers'; +import { mapMetricsData } from '../metrics.helpers'; +import { MetricsEndpointProvider, MetricsService } from '../services/metrics-service'; +import { EndpointModel } from './../../../../../store/src/types/endpoint.types'; + + +interface MetricsDetailsInfo { + ok: number; + total: number; + warning: boolean; + plural: boolean; +} + +@Component({ + selector: 'app-metrics-endpoint-details', + templateUrl: './metrics-endpoint-details.component.html', + styleUrls: ['./metrics-endpoint-details.component.scss'] +}) +export class MetricsEndpointDetailsComponent extends EndpointListDetailsComponent { + + data$: Observable; + + // The guid of the metrics endpoint that this row shows + guid$ = new BehaviorSubject(null); + + constructor( + public store: Store, + private metricsService: MetricsService + ) { + super(); + + // Raw endpoint data for this metrics endpoint + this.data$ = combineLatest( + this.metricsService.metricsEndpoints$, + this.guid$.asObservable()).pipe( + map(([endpoints, guid]) => endpoints.find((item) => item.provider.guid === guid)), + filter(provider => !!provider), + tap(data => { + if (!this.hasStratosData(data)) { + this.store.dispatch(new MetricsStratosAction(data.provider.guid)); + } + }), + map((provider) => this.processProvider(provider)) + ); + } + + private hasStratosData(provider: MetricsEndpointProvider): boolean { + const data = provider.provider; + return data && data.metadata && data.metadata.metrics_stratos && Array.isArray(data.metadata.metrics_stratos); + } + + private processProvider(provider: MetricsEndpointProvider): MetricsDetailsInfo { + const hasStratosData = this.hasStratosData(provider); + const parsed = mapMetricsData(provider); + const known = parsed.filter(item => item.known).length; + return { + ok: known, + total: hasStratosData ? parsed.length : -1, + warning: known === 0, + plural: hasStratosData ? parsed.length !== 1 : known !== 1, + }; + } + + @Input() + set row(data: EndpointModel) { + this.guid$.next(data.guid); + } +} diff --git a/src/frontend/packages/core/src/features/metrics/metrics.helpers.ts b/src/frontend/packages/core/src/features/metrics/metrics.helpers.ts new file mode 100644 index 0000000000..f3bb9d0763 --- /dev/null +++ b/src/frontend/packages/core/src/features/metrics/metrics.helpers.ts @@ -0,0 +1,74 @@ +import { Observable, of as observableOf } from 'rxjs'; + +import { StratosStatus } from '../../shared/shared.types'; +import { EndpointIcon, getFullEndpointApiUrl } from '../endpoints/endpoint-helpers'; +import { entityCatalog } from './../../../../store/src/entity-catalog/entity-catalog.service'; +import { MetricsEndpointProvider } from './services/metrics-service'; + +// Info for an endpoint that a metrics endpoint provides for +export interface MetricsEndpointInfo { + name: string; + icon: EndpointIcon; + type: string; + known: boolean; + url: string; + metadata: { + metrics_job?: string; + metrics_environment?: string; + }; + status: Observable; +} + +// Process the endpoint and Stratos marker file data to give a single list of endpoitns +// linked to this metrics endpoint, comprising those that are known in Stratos and those that are not +export function mapMetricsData(ep: MetricsEndpointProvider): MetricsEndpointInfo[] { + const data: MetricsEndpointInfo[] = []; + + // Add all of the known endpoints first + ep.endpoints.forEach(endpoint => { + const catalogEndpoint = entityCatalog.getEndpoint(endpoint.cnsi_type, endpoint.sub_type); + + data.push({ + known: true, + name: endpoint.name, + url: getFullEndpointApiUrl(endpoint), + type: catalogEndpoint.definition.label, + icon: { + name: catalogEndpoint.definition.icon, + font: 'stratos-icons' + }, + metadata: { + metrics_job: endpoint.metadata ? endpoint.metadata.metrics_job : null, + metrics_environment: endpoint.metadata ? endpoint.metadata.metrics_environment : null + }, + status: observableOf(StratosStatus.OK) + }); + }); + + // Add all of the potentially unknown endpoints + if (ep.provider && ep.provider.metadata && ep.provider.metadata && ep.provider.metadata.metrics_stratos + && Array.isArray(ep.provider.metadata.metrics_stratos)) { + ep.provider.metadata.metrics_stratos.forEach(endp => { + // See if we already know about this endpoint + const hasEndpoint = data.findIndex(i => i.url === endp.url || i.url === endp.cfEndpoint) !== -1; + if (!hasEndpoint) { + const catalogEndpoint = entityCatalog.getEndpoint(endp.type, ''); + data.push({ + known: false, + name: '', + url: endp.cfEndpoint || endp.url, + type: catalogEndpoint.definition.label, + icon: { + name: catalogEndpoint.definition.icon, + font: 'stratos-icons' + }, + metadata: { + metrics_job: endp.job + }, + status: observableOf(StratosStatus.WARNING) + }); + } + }); + } + return data; + } diff --git a/src/frontend/packages/core/src/features/metrics/metrics.module.ts b/src/frontend/packages/core/src/features/metrics/metrics.module.ts index 7aa2a94888..9c14db9211 100644 --- a/src/frontend/packages/core/src/features/metrics/metrics.module.ts +++ b/src/frontend/packages/core/src/features/metrics/metrics.module.ts @@ -1,10 +1,12 @@ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { MetricsComponent } from './metrics/metrics.component'; -import { MetricsRoutingModule } from './metrics.routing'; -import { MetricsService } from './services/metrics-service'; +import { NgModule } from '@angular/core'; + import { CoreModule } from '../../core/core.module'; import { SharedModule } from '../../shared/shared.module'; +import { MetricsEndpointDetailsComponent } from './metrics-endpoint-details/metrics-endpoint-details.component'; +import { MetricsRoutingModule } from './metrics.routing'; +import { MetricsComponent } from './metrics/metrics.component'; +import { MetricsService } from './services/metrics-service'; @NgModule({ imports: [ @@ -13,9 +15,12 @@ import { SharedModule } from '../../shared/shared.module'; SharedModule, MetricsRoutingModule, ], - declarations: [MetricsComponent], + declarations: [MetricsComponent, MetricsEndpointDetailsComponent], providers: [ MetricsService, + ], + entryComponents: [ + MetricsEndpointDetailsComponent, ] }) export class MetricsModule { } diff --git a/src/frontend/packages/core/src/features/metrics/metrics/metrics.component.html b/src/frontend/packages/core/src/features/metrics/metrics/metrics.component.html index 3d5b4dfaf9..6407fa952b 100644 --- a/src/frontend/packages/core/src/features/metrics/metrics/metrics.component.html +++ b/src/frontend/packages/core/src/features/metrics/metrics/metrics.component.html @@ -1,4 +1,4 @@ -{{ (metricsEndpoint$ | async)?.entity.provider.name }} +{{ (metricsEndpoint$ | async)?.provider.name }}
@@ -6,57 +6,67 @@
equalizer
-
{{ ep.entity.provider.name }}
+
{{ ep.provider.name }}

- {{ ep.entity.provider.token_endpoint }} + {{ ep.provider.token_endpoint }}

+
+

This metrics endpoint does not provide a Stratos metadata file

+
-
-

Provides metrics for the following endpoints:

-
- -
-

Does not provide metrics for any endpoints

-
- -
-
- - -
- {{ ep.metadata[svc.guid].icon.name }} -