-
Notifications
You must be signed in to change notification settings - Fork 11
refactor: breadcrumb to support additional specifications #1254
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a710c40
39e81b6
d837182
f054311
d7307b4
305e1f1
f3e855d
e6895e8
ca25f5c
9c61b3d
8a0bdef
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,101 +1,86 @@ | ||
import { Inject, Injectable } from '@angular/core'; | ||
import { ActivatedRouteSnapshot, Resolve } from '@angular/router'; | ||
import { ActivatedRouteSnapshot } from '@angular/router'; | ||
import { Breadcrumb, NavigationService, TimeRangeService } from '@hypertrace/common'; | ||
import { BreadcrumbsService } from '@hypertrace/components'; | ||
import { GraphQlRequestCacheability, GraphQlRequestService } from '@hypertrace/graphql-client'; | ||
import { GraphQlRequestService } from '@hypertrace/graphql-client'; | ||
import { entityIdKey } from '@hypertrace/observability'; | ||
import { Observable } from 'rxjs'; | ||
import { map, switchMap, take } from 'rxjs/operators'; | ||
import { map, switchMap } from 'rxjs/operators'; | ||
import { EntityMetadata, EntityMetadataMap, ENTITY_METADATA } from '../../../shared/constants/entity-metadata'; | ||
import { Entity, ObservabilityEntityType } from '../../../shared/graphql/model/schema/entity'; | ||
import { GraphQlTimeRange } from '../../../shared/graphql/model/schema/timerange/graphql-time-range'; | ||
import { SpecificationBuilder } from '../../../shared/graphql/request/builders/specification/specification-builder'; | ||
import { Entity, entityTypeKey, ObservabilityEntityType } from '../../../shared/graphql/model/schema/entity'; | ||
import { | ||
EntityGraphQlQueryHandlerService, | ||
ENTITY_GQL_REQUEST | ||
} from '../../../shared/graphql/request/handlers/entities/query/entity/entity-graphql-query-handler.service'; | ||
EntityBreadcrumb, | ||
EntityBreadcrumbResolver | ||
} from '../../../shared/services/entity-breadcrumb/entity-breadcrumb.resolver'; | ||
import { EntityIconLookupService } from './../../../shared/services/entity/entity-icon-lookup.service'; | ||
|
||
@Injectable({ providedIn: 'root' }) | ||
export class ApiDetailBreadcrumbResolver implements Resolve<Observable<Breadcrumb>> { | ||
private readonly specificationBuilder: SpecificationBuilder = new SpecificationBuilder(); | ||
export class ApiDetailBreadcrumbResolver<T extends EntityBreadcrumb> extends EntityBreadcrumbResolver<T> { | ||
protected readonly apiEntityMetadata: EntityMetadata | undefined; | ||
|
||
public constructor( | ||
timeRangeService: TimeRangeService, | ||
graphQlQueryService: GraphQlRequestService, | ||
iconLookupService: EntityIconLookupService, | ||
private readonly navigationService: NavigationService, | ||
private readonly timeRangeService: TimeRangeService, | ||
private readonly graphQlQueryService: GraphQlRequestService, | ||
protected readonly breadcrumbService: BreadcrumbsService, | ||
@Inject(ENTITY_METADATA) private readonly entityMetadataMap: EntityMetadataMap | ||
) { | ||
super(timeRangeService, graphQlQueryService, iconLookupService); | ||
this.apiEntityMetadata = this.entityMetadataMap.get(ObservabilityEntityType.Api); | ||
} | ||
|
||
public async resolve(activatedRouteSnapshot: ActivatedRouteSnapshot): Promise<Observable<Breadcrumb>> { | ||
const id = activatedRouteSnapshot.paramMap.get('id') as string; | ||
const parentType = this.resolveParentType(); | ||
const parentEntityMetadata = this.resolveParentType(); | ||
|
||
return Promise.resolve( | ||
this.fetchEntity(id, parentType).pipe( | ||
take(1), | ||
this.fetchEntity(id, ObservabilityEntityType.Api).pipe( | ||
map(apiEntity => ({ | ||
...apiEntity, | ||
...this.getParentPartial(apiEntity, parentEntityMetadata) | ||
})), | ||
switchMap(api => [ | ||
...this.getParentBreadcrumbs(api, parentType), | ||
...this.getParentBreadcrumbs(api, parentEntityMetadata), | ||
this.createBreadcrumbForEntity(api, activatedRouteSnapshot) | ||
]) | ||
) | ||
); | ||
} | ||
|
||
protected createBreadcrumbForEntity( | ||
api: ApiBreadcrumbDetails, | ||
activatedRouteSnapshot: ActivatedRouteSnapshot | ||
): Breadcrumb { | ||
protected createBreadcrumbForEntity(api: Entity, activatedRouteSnapshot: ActivatedRouteSnapshot): EntityBreadcrumb { | ||
return { | ||
label: api.name, | ||
...api, | ||
label: api.name as string, | ||
icon: this.apiEntityMetadata?.icon, | ||
url: this.breadcrumbService.getPath(activatedRouteSnapshot) | ||
}; | ||
} | ||
|
||
protected getParentBreadcrumbs(api: ApiBreadcrumbDetails, parentEntityMetadata?: EntityMetadata): Breadcrumb[] { | ||
protected getParentBreadcrumbs( | ||
api: EntityBreadcrumb, | ||
parentEntityMetadata?: EntityMetadata | ||
): (EntityBreadcrumb | Breadcrumb)[] { | ||
return parentEntityMetadata !== undefined | ||
? [ | ||
{ | ||
label: api.parentName, | ||
[entityIdKey]: api.parentId as string, | ||
[entityTypeKey]: parentEntityMetadata.entityType, | ||
label: api.parentName as string, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. types are wrong here, shouldn't need to cast There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ts is not able to detect the types in the pipe -> map operator There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the type on line 42? Are we sure we're not just dropping it on 59? That map should produce a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (nit btw) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I am not able to make it work. IMO, We wouldn't have to cast if we can ensure that following code returns an
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can do that by assigning '' instead of undefined but i don't know if it would create any run time issue. So, I am ignoring it for this change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we could just make those two fields optional on |
||
icon: parentEntityMetadata?.icon, | ||
url: parentEntityMetadata?.detailPath(api.parentId) | ||
url: parentEntityMetadata?.detailPath(api.parentId as string) | ||
}, | ||
{ | ||
label: 'Endpoints', | ||
icon: this.apiEntityMetadata?.icon, | ||
url: parentEntityMetadata?.apisListPath?.(api.parentId) | ||
url: parentEntityMetadata?.apisListPath?.(api.parentId as string) | ||
} | ||
] | ||
: []; | ||
} | ||
|
||
private fetchEntity(id: string, parentEntityMetadata?: EntityMetadata): Observable<ApiBreadcrumbDetails> { | ||
return this.timeRangeService.getTimeRangeAndChanges().pipe( | ||
switchMap(timeRange => | ||
this.graphQlQueryService.query<EntityGraphQlQueryHandlerService, ApiBreadcrumbDetails>( | ||
{ | ||
requestType: ENTITY_GQL_REQUEST, | ||
entityType: ObservabilityEntityType.Api, | ||
id: id, | ||
properties: this.getAttributeKeys(parentEntityMetadata).map(attributeKey => | ||
this.specificationBuilder.attributeSpecificationForKey(attributeKey) | ||
), | ||
timeRange: new GraphQlTimeRange(timeRange.startTime, timeRange.endTime) | ||
}, | ||
{ cacheability: GraphQlRequestCacheability.NotCacheable } | ||
) | ||
), | ||
map(apiEntity => ({ | ||
...apiEntity, | ||
...this.getParentPartial(apiEntity, parentEntityMetadata) | ||
})) | ||
); | ||
} | ||
|
||
private getAttributeKeys(parentTypeMetadata?: EntityMetadata): string[] { | ||
protected getAttributeKeys(): string[] { | ||
const parentTypeMetadata = this.resolveParentType(); | ||
const parentAttributes = parentTypeMetadata | ||
? [this.getParentNameAttribute(parentTypeMetadata), this.getParentIdAttribute(parentTypeMetadata)] | ||
: []; | ||
|
@@ -142,7 +127,7 @@ export class ApiDetailBreadcrumbResolver implements Resolve<Observable<Breadcrum | |
} | ||
} | ||
|
||
export interface ApiBreadcrumbDetails extends Entity<ObservabilityEntityType.Api> { | ||
export interface ApiBreadcrumbDetails extends EntityBreadcrumb { | ||
name: string; | ||
parentName: string; | ||
parentId: string; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will have to keep an eye on this change. Hopefully it doesn't break any existing case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could change the default from cacheable to undefined too - use the default options.