Skip to content

feat: tag search or filter in explorer #1079

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

Merged
merged 27 commits into from
Sep 1, 2021
Merged

feat: tag search or filter in explorer #1079

merged 27 commits into from
Sep 1, 2021

Conversation

itssharmasandeep
Copy link
Contributor

@itssharmasandeep itssharmasandeep commented Aug 23, 2021

Screen.Recording.2021-08-30.at.3.42.39.PM.mov

@itssharmasandeep itssharmasandeep requested a review from a team as a code owner August 23, 2021 15:55
@codecov
Copy link

codecov bot commented Aug 23, 2021

Codecov Report

Merging #1079 (be39e5e) into main (8c3fc8e) will decrease coverage by 0.02%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1079      +/-   ##
==========================================
- Coverage   85.13%   85.10%   -0.03%     
==========================================
  Files         821      822       +1     
  Lines       16993    17007      +14     
  Branches     2056     2056              
==========================================
+ Hits        14467    14474       +7     
- Misses       2495     2502       +7     
  Partials       31       31              
Impacted Files Coverage Δ
...rc/list-view/list-view-value-renderer.directive.ts 100.00% <100.00%> (ø)
...ts/components/src/list-view/list-view.component.ts 100.00% <100.00%> (ø)
...jects/components/src/list-view/list-view.module.ts 100.00% <100.00%> (ø)
projects/components/src/public-api.ts 100.00% <100.00%> (ø)
...nts/span-detail/tags/span-tags-detail.component.ts 94.44% <100.00%> (+1.58%) ⬆️
...onents/span-detail/tags/span-tags-detail.module.ts 100.00% <100.00%> (ø)
...components/src/tabs/content/tab-group.component.ts 29.16% <0.00%> (-29.17%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8c3fc8e...be39e5e. Read the comment docs.

@github-actions

This comment has been minimized.

@itssharmasandeep
Copy link
Contributor Author

@aaron-steinfeld @anandtiwary this is related to #1075
Please have a look.

@itssharmasandeep
Copy link
Contributor Author

itssharmasandeep commented Aug 24, 2021

Why I did not use ExploreFilterLinkComponent or ExploreService?

So the reason behind that is, list-view component is part of @hypertrace/components and Explore related things are of @hypertrace/observability, since observability is already dependent on components, do we want components to be dependent on observability? I'm sceptical about this.

Suppose if go with the approach of doing that then my suggestion would be to extend that component to take different icons and take data as well, instead of taking generated Url only.

cc: @aaron-steinfeld

@aaron-steinfeld
Copy link
Contributor

Why I did not use ExploreFilterLinkComponent or ExploreService?

So the reason behind that is, list-view component is part of @hypertrace/components and Explore related things are of @hypertrace/observability, since observability is already dependent on components, do we want components to be dependent on observability? I'm sceptical about this.

Suppose if go with the approach of doing that then my suggestion would be to extend that component to take different icons and take data as well, instead of taking generated Url only.

cc: @aaron-steinfeld

We certainly don't want the circular dependency, but my suggestion of using contents or templates passed in account for that. That's generally how you get component libraries to be flexible - rather than encoding behavior in the common components, you allow the flexibility for the parent to do it. For example, the table works this way - defined commonly with many specific renderers the table itself doesn't know about. So using it could look like (pseudo):

<list>
   <ng-container *listKeyRenderer="let key">
     {{key}}
   </ng-container>

   <ng-container *listValueRenderer="let value">
      <my-fancy-thing-here></my-fancy-thing-here>
    </ng-container>
 <list>

@itssharmasandeep
Copy link
Contributor Author

Why I did not use ExploreFilterLinkComponent or ExploreService?

So the reason behind that is, list-view component is part of @hypertrace/components and Explore related things are of @hypertrace/observability, since observability is already dependent on components, do we want components to be dependent on observability? I'm sceptical about this.
Suppose if go with the approach of doing that then my suggestion would be to extend that component to take different icons and take data as well, instead of taking generated Url only.
cc: @aaron-steinfeld

We certainly don't want the circular dependency, but my suggestion of using contents or templates passed in account for that. That's generally how you get component libraries to be flexible - rather than encoding behavior in the common components, you allow the flexibility for the parent to do it. For example, the table works this way - defined commonly with many specific renderers the table itself doesn't know about. So using it could look like (pseudo):

<list>
   <ng-container *listKeyRenderer="let key">
     {{key}}
   </ng-container>

   <ng-container *listValueRenderer="let value">
      <my-fancy-thing-here></my-fancy-thing-here>
    </ng-container>
 <list>

Okay, I got it. I am implementing the content to pass from parent, now the same thing is happening. This explore-filter-link.component is in the observability but our parent sits in distributed-tracing and importing the module for ExploreFilterLinkComponent (from @hypertrace/observability) is failing in distributed-tracing

Uncaught TypeError: Cannot read property 'ExploreFilterLinkModule' of undefined at Module.ExploreFilterLinkModule (explorer.module.ts:19) at Module.24640 (span-tags-detail.module.ts:9) at __webpack_require__ (bootstrap:19) at Module.33735 (span-detail.component.ts:57) at __webpack_require__ (bootstrap:19) at Module.84056 (span-detail-widget.model.ts:10) at __webpack_require__ (bootstrap:19) at Module.22478 (trace-detail-widget.module.ts:12) at __webpack_require__ (bootstrap:19) at Module.40099 (tracing-dashboard-properties.module.ts:7)

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@itssharmasandeep
Copy link
Contributor Author

@aaron-steinfeld I have changed the approach and used the existing features as well as the approach of passing template.
Please review this again.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@@ -31,6 +33,9 @@ export class ListViewComponent {

@Input()
public records?: ListViewRecord[];

@Input()
public action?: TemplateRef<unknown>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're getting close. This should work, but my suspicion is we'd get a lot more flexibility out of making this renderer the whole value renderer rather than always printing out the value as plaintext the following it with an optional additional renderer. A full value renderer can handle any use case this could, but also could do things like making the actual value itself the link - and IMO have a much more intuitive api.

The difference is code like:

        <ht-list-view [records]="tagRecords" [action]="tagAction" data-sensitive-pii></ht-list-view>
        <ng-template #tagAction let-tag>
          <ht-explore-filter-link
            *ngIf="this.getExploreNavigationParams(tag) | async as exploreNavigationParams"
            [paramsOrUrl]="exploreNavigationParams"
            htTooltip="See traces in Explorer"
          >
          </ht-explore-filter-link
        ></ng-template>

vs code like (this would render a bit differently, depends exactly where we want value - but it shows the flexibility).

        <ht-list-view [records]="tagRecords" data-sensitive-pii>
           <div *htListViewValueRenderer="let value">
              <ht-explore-filter-link 
                *ngIf="this.getExploreNavigationParams(tag) | async as exploreNavigationParams"
                [paramsOrUrl]="exploreNavigationParams"
                htTooltip="See traces in Explorer">
                {{ value }}
             </ht-explore-filter-link>
           </div>
       </ht-list-view>

Copy link
Contributor Author

@itssharmasandeep itssharmasandeep Aug 31, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, this action feature, is on a row level, not on the value level. So this design of having listviewvaluerenderer, I am not so sure about this. tagRecords already contains the value. This would have made more impact if we were going to have, different type of renderers for the both the columns (for key and value) like we have for the table. As far as I understand, list view has a sole purpose of showing the text value, right?
@aaron-steinfeld

Copy link
Contributor

@aaron-steinfeld aaron-steinfeld Aug 31, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I missed the video before and slightly misunderstood what was happening here (I thought the action was going inside the value column), but I think the point still holds. Even though you're making the action a sibling of value, thinking of it as part of the value is a generalized version with strictly more functionality. It takes away the assumption that the key and value have to be plaintext, so I could do something like this

        <ht-list-view [records]="tagRecords" data-sensitive-pii>
           <div *htListViewValueRenderer="let value">
               {{ value | prettyPrint }}
           </div>
       </ht-list-view>

So, this action feature, is on a row level, not on the value level. So this design of having listviewvaluerenderer, I am not so sure about this. tagRecords already contains the value.

Either one kind of works the same. I had used the value rather than the whole record because I thought that matched yours, but since it doesn't, changing the implicit binding to record is identical from the caller's perspective:

           <div *htListViewValueRenderer="let record">
               {{ record.value | prettyPrint }}
           </div>

And could also be given named bindings (similar to say, ngFor) like:

           <div *htListViewValueRenderer="let record; let key = key; let value = value;">
               {{ record.value | prettyPrint }}
           </div>

This would have made more impact if we were going to have, different type of renderers for the both the columns (for key and value) like we have for the table. As far as I understand, list view has a sole purpose of showing the text value, right?

I left the key renderer out of this because we didn't need it, but we could eventually add it. Rather than having the sole purpose of showing plaintext, I think the list's real difference from table is the lack of interactions - it doesn't have variable columns, sorting, paging - any of that stuff.

This is how a lot of the library components out there work - with some variation depending on use case. For material table, a cell is defined in a similar way - the main difference is that for mat table there's a generic cellDef directive assigned to a column based on dom location, while we can just enumerate two different directives since we know there's exactly two columns.

  <ng-container matColumnDef="position">
    <th mat-header-cell *matHeaderCellDef> No. </th>
    <td mat-cell *matCellDef="let element"> {{element.position}} </td>
  </ng-container>

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

</div>
<ng-template #defaultValueRenderer let-record
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is inside the ng for, but we only need the template defined once - it can move up to the top level.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

@@ -14,7 +15,7 @@ describe('Span detail component', () => {
component: SpanDetailComponent,
imports: [SpanDetailModule, HttpClientTestingModule, IconLibraryTestingModule],
declareComponent: false,
providers: [mockProvider(NavigationService)]
providers: [mockProvider(NavigationService), mockProvider(ExplorerService)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is failing due to its transitive dependencies on router, due to the new usage of a link component. It's tech debt that this test isn't shallow, so let's fix that :)

diff --git a/projects/observability/src/shared/components/span-detail/span-detail.component.test.ts b/projects/observability/src/shared/components/span-detail/span-detail.component.test.ts
index a169698..22b8fb7 100644
--- a/projects/observability/src/shared/components/span-detail/span-detail.component.test.ts
+++ b/projects/observability/src/shared/components/span-detail/span-detail.component.test.ts
@@ -1,21 +1,14 @@
-import { HttpClientTestingModule } from '@angular/common/http/testing';
 import { fakeAsync } from '@angular/core/testing';
-import { IconLibraryTestingModule } from '@hypertrace/assets-library';
-import { NavigationService } from '@hypertrace/common';
-import { createHostFactory, mockProvider, Spectator } from '@ngneat/spectator/jest';
-import { ExplorerService } from '../../../pages/explorer/explorer-service';
+import { createHostFactory, Spectator } from '@ngneat/spectator/jest';
 import { SpanData } from './span-data';
 import { SpanDetailComponent } from './span-detail.component';
-import { SpanDetailModule } from './span-detail.module';
 
 describe('Span detail component', () => {
   let spectator: Spectator<SpanDetailComponent>;
 
   const createHost = createHostFactory({
     component: SpanDetailComponent,
-    imports: [SpanDetailModule, HttpClientTestingModule, IconLibraryTestingModule],
-    declareComponent: false,
-    providers: [mockProvider(NavigationService), mockProvider(ExplorerService)]
+    shallow: true
   });
 
   test('should display child components', () => {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

@github-actions

This comment has been minimized.

@itssharmasandeep itssharmasandeep merged commit 2e8e867 into main Sep 1, 2021
@itssharmasandeep itssharmasandeep deleted the tags-search branch September 1, 2021 19:31
@github-actions
Copy link

github-actions bot commented Sep 1, 2021

Unit Test Results

    4 files  ±0  265 suites  ±0   17m 26s ⏱️ -36s
957 tests ±0  957 ✔️ ±0  0 💤 ±0  0 ❌ ±0 
964 runs  ±0  964 ✔️ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 2e8e867. ± Comparison against base commit 8c3fc8e.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants