diff --git a/README.md b/README.md
index db38e0447..5cd380eeb 100644
--- a/README.md
+++ b/README.md
@@ -1,48 +1,455 @@
-# Hypertrace UI
+
+
+
+
-
-[](https://codecov.io/gh/hypertrace/hypertrace-ui)
+
Hypertrace-UI
+
+ User interface for an open source distributed tracing & observability platform!
+
+ More about hypertrace ยป
+
+
+
-## Prerequisites
+## Table of Contents
-Install Node + NPM
+- [Setup](#setup)
+- [Technologies](#technologies)
+- [Code Architecture](#code-architecture)
+- [The Essentials](#the-essentials)
+ - [Angular Specifics](#angular-specifics)
+ - [Tables](#tables)
+ - [Cell Renderers](#cell-renderers)
+ - [Dashboards](#dasboards)
+ - [Widget](#widget)
+ - [Widget Renderer](#widget-renderer)
+ - [Data Source](#data-source)
+ - [Graphql Handlers](#graphql-handlers)
+- [Testing](#testing)
+- [Best Practices](#best-practices)
+- [Contributions](#contributions)
+- [Others](#others)
+ - [Building Image locally](#building-image-locally)
+ - [Docker Image Source](#docker-image-source)
## Setup
-- Install Dependencies
+Install `Node` and `npm`, if not done already ([Node and Npm](https://www.npmjs.com/get-npm)). Recommended node version is `16+`.
+[Fork](<(https://docs.github.com/en/github/getting-started-with-github/fork-a-repo)>) or clone the repository and Use following commands.
- `npm install`
+```sh
+cd
+npm ci
+```
+
+once done, start a development server
-## Development server
+```sh
+npm start
+```
-Run `npm start` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
+Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
-## Running unit tests
+To run unit test cases (execute the unit tests via Jest)
-Run `npm run test` to execute the unit tests via Jest
+```sh
+npm run test
+```
## Technologies
-1. Angular
-2. Typescript
-3. RxJS
-4. [D3](https://d3js.org/)
-5. [Spectator](https://github.com/ngneat/spectator) (_Unit Testing_)
+Hypertrace-ui uses `angular` as the framework. On top of angular, following technologies are being used.
-## UI Architecture
+1. `Typescript` : As a core language, hypertrace-ui uses typescript instead of traditional javascript. Learn more about Typescript [here](https://www.typescriptlang.org/docs/)
+2. `RxJS` : For reactive programming, hypertrace-ui uses RxJs library. Learn more about RxJs [here](https://rxjs.dev/api)
+3. `D3.js` : Charts are the core part for hypertrace-ui. Charts are custom build here and use D3.js library. Learn more about D3.js [here](https://d3js.org/)
+4. `Spectator`: For unit testing, hypertrace-ui uses spectator library. Learn more about Spectator [here](https://github.com/ngneat/spectator)
+5. `Hyperdash & Hyperdash-Angular`: Hyperdash is dashboarding framework/library and hyperdash-angular is a wrapper, specific to angular. Learn more about dasboards in [dashboards](#dashboards) section.
-|
|
-| :------------------------------------------------------------------------------------------------: | --- |
-| _Hypertrace UI Architecture_ | d |
+## Code Architecture
-## Building Image locally
+Hypertrace-UI code is divided into many smaller projects which gives the code base a better structure. Here are the projects.
-Hypertrace UI uses gradle to build a docker image. Gradle wrapper is already part of the source code. To build Hypertrace UI image, run:
+1. `Assest Library` : This consists of the assets which are being used in the application. For example; images, icons etc. Check this out [here](https://github.com/hypertrace/hypertrace-ui/tree/main/projects/assets-library)
+2. `Common` : This consists of the common code/features such as application constants, colors, telemetry, utilities (with common angular pipes) etc. Check this out [here](https://github.com/hypertrace/hypertrace-ui/tree/main/projects/common)
+3. `Components` : Hypertrace-ui has a wide variety of custom made angular components. This is the place for generic components (eg. `Input` Component) and directives(eg. `LoadAsync` Directive). Check this out [here](https://github.com/hypertrace/hypertrace-ui/tree/main/projects/components)
+4. `Dashboards` : This consists of the common code for dashboards such as base model, properties etc. Check this out [here](https://github.com/hypertrace/hypertrace-ui/tree/main/projects/dashboards)
+5. `Graphql-Client` : Hypertrace-ui uses [apollo graphql](https://www.apollographql.com/) for API calls. This is the place where all the base graphql request related code is present such as graphql arguments, resolvers, builders etc. Check this out [here](https://github.com/hypertrace/hypertrace-ui/tree/main/projects/graphql-client)
+6. `Observability` : This consists of all the different pages, components, services related to distributed tracing and observability. This project is the home for charts as well. Check this out [here](https://github.com/hypertrace/hypertrace-ui/tree/main/projects/observability)
+7. `Test Utils` : This consists of some unit test utilities for dashboards etc.. Check this out [here](https://github.com/hypertrace/hypertrace-ui/tree/main/projects/test-utils)
+8. `UI App` : This is not a project but a entry point for hypertrace-ui app. This consists of the home page, routes, config module etc. Check this out [here](https://github.com/hypertrace/hypertrace-ui/tree/main/src)
+
+`NOTE` : Each project contains a barrel file named `public-api.ts`. This handles all the exports at a single place which improves the importing in the app.
+For example
+
+```ts
+@import { Color } from '@hypertrace/common'
+```
+
+## The Essentials
+
+Let's talk about the essentials for development in hypertrace-ui.
+
+### Angular Specifics
+
+Since hypertrace-ui uses `angular` as core framework, all the concepts specific to angular are being used and applied in hypertrace-ui. Such as `components`, `directives`, `pipes`, `dependency injection`, `services`, `modules`, `lazy loading` etc. Check out the angular [docs](https://angular.io/docs) for more info.
+
+`NOTE` : Test file name ends with `.test.ts` instead of `.spec.ts` for better readability.
+
+### Dashboards
+
+Hypertrace-UI uses dashboards to build custom pages. These dashboards are widely used in the application. These dashboards are build using `Hyperdash` and `Hyperdash-Angular` libraries. Check out both here ([Hyperdash](https://github.com/hypertrace/hyperdash/blob/main/README.md) & [Hyperdash angular](https://github.com/hypertrace/hyperdash-angular/blob/main/README.md))
+
+Let's check this example.
+
+`in Template`
+
+```html
+
+```
+
+`in Component`
+
+```ts
+public readonly location: string = 'HELLO_LOCATION';
+public readonly defaultJson: ModelJson = {
+ type: 'hello-widget',
+ name: 'name'
+ children: [],
+ data: {
+ 'upper-case': false,
+ type: 'hello-data-source'
+ }
+}
+```
+
+Now let's break this down.
+
+- It will create a dasboard for a unique location.
+- Dasboards are designed in a way that it takes a modal json as input property and renders the corresponding widgets.
+- There are 3 core concepts - widget , widget renderer and data source.
+
+Let's talk about these individually.
+
+#### Widget
+
+To create a widget, we need to create model class.
+
+Continue with the above `ModelJson`. Let's create `hello-widget.model.ts`
+
+```ts
+import { Model, ModelProperty, STRING_PROPERTY } from '@hypertrace/hyperdash';
+
+@Model({
+ type: 'hello-widget'
+})
+export class HelloWidgetModel {
+ @ModelProperty({
+ type: STRING_PROPERTY.type,
+ key: 'name',
+ required: false
+ })
+ public name?: string;
+}
+```
+
+Now let's break this down.
+
+- We have used decorator `Model` by which we're registering this widget (on build) for usage.
+- `type` property is the unique string to define each widget. If we look closely we have used the same string as a type in the model json as well.
+- We have used decorator `ModelProperty` for defining the custom properties like in this case `name`.
+
+But the question is how this class will render the dom? let's find out in next section!
+
+#### Widget Renderer
+
+Now after creating the widget model, let's create widget renderer component.
+
+Using the same example. Let's create `hello-widget-renderer.component.ts
+
+```ts
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { Renderer } from '@hypertrace/hyperdash';
+import { Observable } from 'rxjs';
+import { WidgetRenderer } from '../widget-renderer';
+import { HelloWidgetModel } from './hello-widget.model';
+
+@Renderer({ modelClass: HelloWidgetModel })
+@Component({
+ selector: 'ht-hello-widget-renderer',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ template: ` {{ data }} {{ this.model.name }}
`
+})
+export class HelloWidgetRendererComponent extends WidgetRenderer {
+ protected fetchData(): Observable {
+ return this.api.getData();
+ }
+}
+```
+
+Now let's break this down.
+
+- We have used decorator `Renderer` by which we're registering this widget renderer (on build) for usage.
+- `modelClass` property is the same class for which we're building this renderer, in this case it is `HelloWidgetModel`.
+- Now after extending the `WidgetRenderer` class, we have access to the `name` property which we defined in the model class.
+- `fetchData` method is used to give us access to `this.data$` observable.
+- `htLoadAsync` directive is used to resolve the data observable, which can be done with `async` pipe as well.
+
+How are we getting data? Now let's understand this in the next section.
+
+#### Data Source
+
+Now after creating the widget renderer we need the data which we are using in the renderer component.
+
+Continue with the above `ModelJson`. Let's create `hello-data-source.model.ts`
+
+```ts
+import { Model, ModelProperty, STRING_PROPERTY} from '@hypertrace/hyperdash';
+import { Observable, of } from 'rxjs';
+
+@Model({
+ type: 'hello-data-source'
+})
+export class HelloDataSourceModel {
+ @ModelProperty({
+ key: 'upper-case',
+ required: false,
+ type: STRING_PROPERTY.type
+ })
+ public upperCase: boolean = false;
+
+ public getData(): Observable {
+ return of(this.upperCase ? 'HELLO' ? 'Hello')
+ }
+}
+```
+
+Now let's break this down.
+
+- We have used decorator `Model` by which we're registering this data source (on build) for usage.
+- `type` property is the unique string to define each data source. If we look closely we have used the same string as a type in the model json as well for key `data`.
+- We have used decorator `ModelPropery` for defining custom properties; like in this case `upper-case`.
+- We have implemented `getData` method, and the same method is being used in the renderer component `return this.api.getData()`.
+
+Now after implemening all this we can use these as shown above and render custom data.
+
+_Why we're doing this_? Answer is simple, once we do all this, we can just write few lines of json to render a whole widget. For more complex examples please check `home.dashboard.ts` and its constituent widgets.
+
+### Tables
+
+Table is a custom component in the hypertrace-ui. The following example shows how to add table inside another component.
+
+Here is what table API Says:
+
+```ts
+@Input()
+public data?: TableDataSource;
+```
+
+```ts
+@Input()
+public columnConfigs?: TableColumnConfig[];
+```
+
+So Let's use this.
+`in Template`
+```html
+
```
+
+`in Component`
+
+```ts
+public datasource?: TableDataSource = {
+ getData : () => of({
+ data: [{name: 'test-name1'}, {name: 'test-name2'}],
+ totalCount: 2
+ })
+};
+public readonly columnConfigs: TableColumnConfig[] = [
+ {
+ id: 'name',
+ title: 'Name'
+ visible: true,
+ sortable: false,
+ width: '48px',
+ }
+];
+```
+
+Now let's break this down.
+
+- It will create a table with a single column (In column configs we have only mentioned one column) and two rows (in the data source we have mentioned data as array of two objects.).
+- If we look closely, table column config's id is same as the key we have used the key in data which is `name`. This is a must for the table to render the data correctly.
+
+There are more features in the table component, like custom controls, configurations (for pagination and many other). We highly recommend you to check out the `table.component.ts` to learn about tables and check out all the different examples present in the application.
+
+#### Cell Renderers
+
+Continuing from tables, let's talk about custom table cell renderers. In hypertrace-ui, we can create a custom table cell renderer to handle presentation of a cell data. These are nothing but angular component with another decorator `TableCellRenderer`
+
+Now let's see how we can create a custom cell renderer. for example `hello-table-cell-renderer.component.ts`
+
+```ts
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { TableCellRenderer } from '../../table-cell-renderer';
+import { TableCellRendererBase } from '../../table-cell-renderer-base';
+import { CoreTableCellParserType } from '../../types/core-table-cell-parser-type';
+import { TableCellAlignmentType } from '../../types/table-cell-alignment-type';
+
+@Component({
+ selector: 'ht-hello-table-cell-renderer',
+ styleUrls: ['./hello-table-cell-renderer.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ template: ` Hello {{ this.value }}
`
+})
+@TableCellRenderer({
+ type: 'hello',
+ alignment: TableCellAlignmentType.Left,
+ parser: CoreTableCellParserType.NoOp
+})
+export class HelloTableCellRendererComponent extends TableCellRendererBase {}
+```
+
+Now let's break this down.
+
+- We have used decorator `TableCellRenderer` by which we're registering this cell renderer (on build) for usage.
+- `type` property is the unique string to define each cell renderer.
+- `alignment` is used for the cell alignment, could be - left, right and center
+- `parser` is used to parse the data. It can also be defined similar to a cell renderer. Suppose we are getting data as `['test1', 'test2']` and we want it to be marshalled into `{value1: 'test1', value2: 'test2'}` then we can create a custom parser and can handle the transformation. For no operation we use `CoreTableCellParserType.NoOp`
+
+`Usage` : Once this is done, we can use this in our table using `display` property. This will be same as the type of the cell renderer.
+
+`Module import`
+
+```ts
+TableModule.withCellRenderers([HelloTableCellRendererComponent]);
+```
+
+`in Component`
+
+```ts
+public readonly columnConfigs: TableColumnConfig[] = [
+ {
+ id: 'name',
+ title: 'Name'
+ display: 'hello'
+ visible: true,
+ sortable: false,
+ width: '48px',
+ }
+];
+```
+
+`NOTE`: We highly recommend you to check out all the existing example of table and cell renderers to learn more.
+
+## GraphQl Handlers
+
+There are two type of graphql handlers we use.
+
+1. `Query` : To get the data from server / backend.
+2. `Mutation` : For delete, post and put use cases.
+
+Let's see an example of a query graphql-handler:
+
+```ts
+import { Injectable } from '@angular/core';
+import { GraphQlHandlerType, GraphQlQueryHandler, GraphQlSelection } from '@hypertrace/graphql-client';
+
+@Injectable({ providedIn: 'root' })
+export class HelloGraphQlQueryHandlerService implements GraphQlQueryHandler {
+ public readonly type: GraphQlHandlerType.Query = GraphQlHandlerType.Query;
+
+ public matchesRequest(request: unknown): request is GraphQlHelloRequest {
+ return (
+ typeof request === 'object' &&
+ request !== null &&
+ (request as Partial).requestType === HELLO_GQL_REQUEST
+ );
+ }
+
+ public convertRequest(request: GraphQlHelloRequest): GraphQlSelection {
+ return {
+ path: 'getHello',
+ children: [
+ {
+ path: 'result'
+ }
+ ]
+ };
+ }
+
+ public convertResponse(response: ExportSpansResponse): string | undefined {
+ return response.result;
+ }
+}
+
+export const HELLO_GQL_REQUEST = Symbol('GraphQL Hello Request');
+
+export interface GraphQlHelloRequest {
+ requestType: typeof HELLO_GQL_REQUEST;
+}
+
+export interface GraphQlHelloResponse {
+ result: string;
+}
+```
+
+Let's break this down.
+
+- We have used a unique symbol, as a type for the request.
+- Two interfaces `GraphQlHelloRequest` and `GraphQlHelloResponse` for request and response.
+- `matchesRequest` method is used to verify the request.
+- `convertRequest` method is used for converting request into graphql selection.
+- `convertResponse` method is used to convert the response into desired format.
+
+`Usage` : Now once this is done, we can use this in the service/component
+
+`Module import`
+
+```ts
+GraphQlModule.withHandlerProviders([HelloGraphQlQueryHandlerService]);
+```
+
+`in Component/Service`
+
+```ts
+// Injection
+private readonly graphQlQueryService: GraphQlRequestService
+
+// Usage
+this.graphQlQueryService.query({
+ requestType: HELLO_GQL_REQUEST
+})
+```
+
+## Testing
+
+Testing is an integral part of hypertrace-ui and hypertrace-ui maintains a good amount of code coverage using unit tests! We use `Spectator` library to test components. services, directives, pipes, dashboards etc. We always write `shallow` tests.
+
+## Best Pratices
+
+1. `Naming`: Always write a file and class name which is easy to understand and specific to use case. for example - asynchronous loading -> directive name is `LoadAsyncDirective`. Use `ht` as prefix in component selectors, pipes, directives etc. There is lint rule as well.
+2. `Linting`: For a consistent in file code structure, linting is used and a requirement before merging the code.
+
+## Contributions
+
+Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
+
+## Others
+
+These are some extra things that might be useful.
+
+#### Building Image locally
+
+Hypertrace UI uses gradle to build a docker image. Gradle wrapper is already part of the source code. To build Hypertrace UI image, run:
+
+```sh
./gradlew dockerBuildImages
```
-## Docker Image Source:
+#### Docker Image Source:
- [DockerHub > Hypertrace UI](https://hub.docker.com/r/hypertrace/hypertrace-ui)