Skip to content

Commit 2e8e867

Browse files
feat: tag search or filter in explorer (#1079)
1 parent 8c3fc8e commit 2e8e867

11 files changed

+97
-28
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Directive, TemplateRef } from '@angular/core';
2+
3+
@Directive({
4+
selector: '[htListViewValueRenderer]'
5+
})
6+
export class ListViewValueRendererDirective {
7+
public constructor(private readonly templateRef: TemplateRef<unknown>) {}
8+
9+
public getTemplateRef(): TemplateRef<unknown> {
10+
return this.templateRef;
11+
}
12+
}

projects/components/src/list-view/list-view.component.scss

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
@import 'font';
2-
@import 'color-palette';
1+
@import 'mixins';
32

43
$key-width: 40%;
5-
$value-width: 60%;
4+
$value-width: auto;
65
$horizontal-offset: 12px;
76

87
@mixin grid-view {

projects/components/src/list-view/list-view.component.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { CommonModule } from '@angular/common';
22
import { Component } from '@angular/core';
33
import { ComponentFixture, TestBed } from '@angular/core/testing';
4+
import { NavigationService } from '@hypertrace/common';
5+
import { mockProvider } from '@ngneat/spectator/jest';
46
import { ListViewComponent, ListViewHeader, ListViewRecord } from './list-view.component';
57

68
describe('List View Component', () => {
@@ -32,7 +34,8 @@ describe('List View Component', () => {
3234
beforeEach(() => {
3335
TestBed.configureTestingModule({
3436
declarations: [TestHostComponent, ListViewComponent],
35-
imports: [CommonModule]
37+
imports: [CommonModule],
38+
providers: [mockProvider(NavigationService)]
3639
});
3740

3841
fixture = TestBed.createComponent(TestHostComponent);

projects/components/src/list-view/list-view.component.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
2-
1+
import { ChangeDetectionStrategy, Component, ContentChild, Input } from '@angular/core';
2+
import { ListViewValueRendererDirective } from './list-view-value-renderer.directive';
33
@Component({
44
selector: 'ht-list-view',
55
styleUrls: ['./list-view.component.scss'],
66
changeDetection: ChangeDetectionStrategy.OnPush,
77
template: `
8+
<ng-template #defaultValueRenderer let-record
9+
><span>{{ record.value }}</span></ng-template
10+
>
811
<div class="list-view">
912
<div *ngIf="this.header" class="header-row">
1013
<div class="header-key-label">
@@ -19,7 +22,12 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
1922
<span>{{ record.key }}</span>
2023
</div>
2124
<div class="value">
22-
<span>{{ record.value }}</span>
25+
<ng-container
26+
*ngTemplateOutlet="
27+
this.valueRenderer ? this.valueRenderer!.getTemplateRef() : defaultValueRenderer;
28+
context: { $implicit: record }
29+
"
30+
></ng-container>
2331
</div>
2432
</div>
2533
</div>
@@ -31,6 +39,9 @@ export class ListViewComponent {
3139

3240
@Input()
3341
public records?: ListViewRecord[];
42+
43+
@ContentChild(ListViewValueRendererDirective)
44+
public valueRenderer?: ListViewValueRendererDirective;
3445
}
3546

3647
export interface ListViewHeader {
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { CommonModule } from '@angular/common';
22
import { NgModule } from '@angular/core';
3+
import { ListViewValueRendererDirective } from './list-view-value-renderer.directive';
34
import { ListViewComponent } from './list-view.component';
45

56
@NgModule({
6-
declarations: [ListViewComponent],
7-
exports: [ListViewComponent],
7+
declarations: [ListViewComponent, ListViewValueRendererDirective],
8+
exports: [ListViewComponent, ListViewValueRendererDirective],
89
imports: [CommonModule]
910
})
1011
export class ListViewModule {}

projects/components/src/public-api.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,8 @@ export * from './link/link.component';
167167
export * from './link/link.module';
168168

169169
// List View
170-
export { ListViewComponent, ListViewHeader, ListViewRecord } from './list-view/list-view.component';
171-
export { ListViewModule } from './list-view/list-view.module';
170+
export * from './list-view/list-view.component';
171+
export * from './list-view/list-view.module';
172172

173173
// Load Async
174174
export { LoadAsyncDirective } from './load-async/load-async.directive';

projects/observability/src/shared/components/span-detail/span-detail.component.test.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,14 @@
1-
import { HttpClientTestingModule } from '@angular/common/http/testing';
21
import { fakeAsync } from '@angular/core/testing';
3-
import { IconLibraryTestingModule } from '@hypertrace/assets-library';
4-
import { NavigationService } from '@hypertrace/common';
5-
import { createHostFactory, mockProvider, Spectator } from '@ngneat/spectator/jest';
2+
import { createHostFactory, Spectator } from '@ngneat/spectator/jest';
63
import { SpanData } from './span-data';
74
import { SpanDetailComponent } from './span-detail.component';
8-
import { SpanDetailModule } from './span-detail.module';
95

106
describe('Span detail component', () => {
117
let spectator: Spectator<SpanDetailComponent>;
128

139
const createHost = createHostFactory({
1410
component: SpanDetailComponent,
15-
imports: [SpanDetailModule, HttpClientTestingModule, IconLibraryTestingModule],
16-
declareComponent: false,
17-
providers: [mockProvider(NavigationService)]
11+
shallow: true
1812
});
1913

2014
test('should display child components', () => {

projects/observability/src/shared/components/span-detail/tags/span-tags-detail.component.scss

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,19 @@
77
height: 100%;
88
width: 100%;
99
overflow: auto;
10+
11+
.tag-value {
12+
width: 100%;
13+
display: grid;
14+
grid-template-columns: auto min-content;
15+
16+
.filter-link {
17+
visibility: hidden;
18+
margin-left: 12px;
19+
}
20+
21+
&:hover .filter-link {
22+
visibility: visible;
23+
}
24+
}
1025
}

projects/observability/src/shared/components/span-detail/tags/span-tags-detail.component.test.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { CommonModule } from '@angular/common';
22
import { HttpClientTestingModule } from '@angular/common/http/testing';
3-
import { createHostFactory, Spectator } from '@ngneat/spectator/jest';
4-
3+
import { MemoizeModule } from '@hypertrace/common';
54
import {
65
JsonViewerModule,
76
LabelModule,
@@ -10,6 +9,10 @@ import {
109
LoadAsyncModule,
1110
ToggleButtonModule
1211
} from '@hypertrace/components';
12+
import { createHostFactory, mockProvider, Spectator } from '@ngneat/spectator/jest';
13+
import { MockComponent } from 'ng-mocks';
14+
import { ExplorerService } from '../../../../pages/explorer/explorer-service';
15+
import { ExploreFilterLinkComponent } from '../../explore-filter-link/explore-filter-link.component';
1316
import { SpanTagsDetailComponent } from './span-tags-detail.component';
1417

1518
describe('Span Tags Detail Component', () => {
@@ -24,8 +27,11 @@ describe('Span Tags Detail Component', () => {
2427
JsonViewerModule,
2528
LabelModule,
2629
LoadAsyncModule,
27-
HttpClientTestingModule
28-
]
30+
HttpClientTestingModule,
31+
MemoizeModule
32+
],
33+
declarations: [MockComponent(ExploreFilterLinkComponent)],
34+
providers: [mockProvider(ExplorerService)]
2935
});
3036

3137
test('should display tag records', () => {

projects/observability/src/shared/components/span-detail/tags/span-tags-detail.component.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';
2-
import { Dictionary, TypedSimpleChanges } from '@hypertrace/common';
3-
import { ListViewRecord } from '@hypertrace/components';
2+
import { Dictionary, NavigationParams, TypedSimpleChanges } from '@hypertrace/common';
3+
import { FilterOperator, ListViewRecord } from '@hypertrace/components';
44
import { isNil } from 'lodash-es';
55
import { EMPTY, Observable, of } from 'rxjs';
6+
import { ExplorerService } from '../../../../pages/explorer/explorer-service';
7+
import { ScopeQueryParam } from '../../../../pages/explorer/explorer.component';
68

79
@Component({
810
selector: 'ht-span-tags-detail',
@@ -11,7 +13,16 @@ import { EMPTY, Observable, of } from 'rxjs';
1113
template: `
1214
<div class="tags-details">
1315
<ng-container *htLoadAsync="this.tagRecords$ as tagRecords">
14-
<ht-list-view [records]="tagRecords" data-sensitive-pii></ht-list-view>
16+
<ht-list-view [records]="tagRecords" data-sensitive-pii
17+
><div class="tag-value" *htListViewValueRenderer="let record">
18+
<div class="value">{{ record.value }}</div>
19+
<ht-explore-filter-link
20+
class="filter-link"
21+
[paramsOrUrl]="this.getExploreNavigationParams | htMemoize: record | async"
22+
htTooltip="See traces in Explorer"
23+
>
24+
</ht-explore-filter-link></div
25+
></ht-list-view>
1526
</ng-container>
1627
</div>
1728
`
@@ -22,12 +33,19 @@ export class SpanTagsDetailComponent implements OnChanges {
2233

2334
public tagRecords$?: Observable<ListViewRecord[]>;
2435

36+
public constructor(private readonly explorerService: ExplorerService) {}
37+
2538
public ngOnChanges(changes: TypedSimpleChanges<this>): void {
2639
if (changes.tags && this.tags) {
2740
this.buildTagRecords();
2841
}
2942
}
3043

44+
public getExploreNavigationParams = (tag: ListViewRecord): Observable<NavigationParams> =>
45+
this.explorerService.buildNavParamsWithFilters(ScopeQueryParam.EndpointTraces, [
46+
{ field: 'tags', operator: FilterOperator.ContainsKeyValue, value: [tag.key, tag.value] }
47+
]);
48+
3149
private buildTagRecords(): void {
3250
if (isNil(this.tags)) {
3351
this.tagRecords$ = EMPTY;

0 commit comments

Comments
 (0)