hypertrace-ui icon indicating copy to clipboard operation
hypertrace-ui copied to clipboard

Feature: Support for custom dashboards

Open akashmane1598 opened this issue 3 years ago • 6 comments

Use Case

To enable customising dashboard layouts by passing custom JSON for widgets instead of .dashboard.ts

Proposal

All dashboards in hypertrace are powered through a JSON object which are exported from the respective .dashboard.ts file. This limits the users from creating custom dashboards as per their need. To add support for custom dashboards we can fetch the JSON config before loading the dashboard screen. For the first phase this config can be served via static JSON files as well

akashmane1598 avatar Apr 18 '22 11:04 akashmane1598

@anandtiwary @aaron-steinfeld @itssharmasandeep @arjunlalb

jaywalker21 avatar Apr 21 '22 16:04 jaywalker21

We plan to add a network call to fetch the custom JSON whose implementation will be somewhat similar to what is done in the snippet. Screenshot 2022-04-22 at 8 30 57 AM

Need more clarity on where should this be done. Whether in navigable-dashboard.component or application-aware-dashboard.component or to have a wrapper component that would fetch the JSON and pass it down. Also if there can be any other alternative for this.

@jaywalker21 @anandtiwary @aaron-steinfeld

akashmane2209 avatar Apr 22 '22 05:04 akashmane2209

There's already a dashboard persistence service that would be the place to start looking for this, I believe the current implementation uses local storage, so swapping in a different store that's loading from remote would be straightforward. The problem we still have to solve however is how to make that configurable without modifying source.

aaron-steinfeld avatar Apr 22 '22 12:04 aaron-steinfeld

Hey @aaron-steinfeld Yes, we can swap the store for the dashboard persistence service but need some help on whether to make changes in the navigable dashboard or app aware dashboard because these are shared components across all the repo and we won't be having custom JSON for all the pages. Also, what are your thoughts on creating a wrapper that would notify the navigable dashboard component whether to use default JSON or to fetch it from an API?

akashmane2209 avatar Apr 26 '22 09:04 akashmane2209

@akashmane2209 - that's what the persistence service already does, everything you're describing is already built with the exception of remote persistence. NavigableDashboardComponent takes in a nav location (and optionally a default JSON, but in practice we don't use this any more).

So let's look at API overview:

    <ht-navigable-dashboard
      *htLoadAsync="this.filterConfig$ as filterConfig"
      navLocation="${apiOverviewDashboard.location}"
      [filterConfig]="filterConfig"
    >
    </ht-navigable-dashboard>

NavigableDashboard accepts a constant location (i.e. a key to indicate which dashboard it's looking for), and asks dashboard persistence service to give it the dashboard: this.dashboardPersistenceService.getForLocation(this.navLocation)

At the same time in the API overview module, we import NavigableDashboardModule.withDefaultDashboards(apiOverviewDashboard), registering the default JSON for that location with the dashboard persistence service.

So now the persistence service tries to query the store for that location, falling back to that registered default:

  public getForLocation(locationKey: string): Observable<PersistedDashboard> {
    return this.getById(this.getLocationId(locationKey)).pipe(
      catchError(() => this.getDefaultForLocation(locationKey))
    );
  }

  public getById(id: string): Observable<PersistedDashboard> {
    return this.dashboardStore.read(id);
  }

Sorry for the confusing explanation, hopefully it makes sense! The conclusion I'm driving at though is that by changing to a different implementation of DashboardStore (which is just an interface, currently implemented via a browser local storage version), it can be set up to use a remote URL and have exactly the behavior you're looking for:

export interface DashboardStore {
  read(id: string): Observable<PersistedDashboard>;
  readAll(): Observable<PersistedDashboard>;
  create(dashboard: DashboardCreationData): Observable<PersistedDashboard>;
  update(dashboard: DashboardUpdateData): Observable<PersistedDashboard>;
  upsert(dashboard: DashboardUpsertData): Observable<PersistedDashboard>;
  delete(id: string): Observable<void>;
}

aaron-steinfeld avatar Apr 26 '22 14:04 aaron-steinfeld

Okay understood. Let me try updating the service and check.

akashmane1598 avatar Apr 26 '22 14:04 akashmane1598