Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Title

Dashlet

Selector

<sb-dashlet>

Use Case

Dashlets are reporting widgets that can be embedded in any contextual workflow - whether on a consumption, creation or administration screen. Any solution that needs to use dashlets can configure the dashlet with a data source, type of visualisation (bar, line, pi, table, map etc), legends, filters etc.

Description

This generic component/widget will be used to render a chart, table, dataset, map or any other report type. It can make use of multiple libraries & also support building custom components with a common interface.

🧐 Interface Design

Interface Diagrams

...

IBase<T> if the base interface providing common properties and behaviours.

...

Code Block
breakoutModewide
languagejs
interface IBase <T><T extends object> {

    reportType: IReportType;

    readonly _defaultConfig: object; // default configurations as per the reportType

    height: string; 
    
    width: string;
    
    id: string;
    
    config: object; // input configuration for the dashlets component. It should be as per the report type. Refer to next sections for more details as per the report Type

    data: <T>[] | IDataLocationIData; // input data either in JSON format, url or API configuration;

    state: EventEmitter<IReportState>;

    initialize(config: object, data: T[]); // Get the initialisation options used for rendering.

    reset(): void; // resets the component to initial view

    destroy(): void; // performs cleanup post the component is destroyed;

    update(config); // updates and re renders the view

    fetchData<T>(): Promise<T[]> | Observable<T[]>;

    /* genetic methods for addition and removal of data;
        addData();
        removeData
    */
}


/*
##########################################################################
*
*.         depenedent interfaces are as follows:-
*
##########################################################################
*/


type IReportType = "chart" | "table" | "etc"

type methodType = "GET" | "POST";

interface IApiConfig {
    url: string;
    headers: {
        [header: string]: string | string[];
    };
    methodType: methodType;
    params: {
        [param: string]: string | string[];
    };
    response: {
        path: string;  //Gets the value at path of response object;
    }
}

interface IDataSchema {
    type: string,
    enum?: string[],
    default?: string,
    format?: string; //url, date etc
    items?: IDataSchema // if type is array
}

interface IData<T IDataLocationextends object> {
    values?: T[]
    location?: {
        apiConfig?: IApiConfig;
        url?: string;
    },
    dataSchema?: {
        [key: string]: IDataSchema;
    }
}

type IReportState = "initialized" | "rendered" | "destroyed" | "etc";  // pending or done state;

interface EventEmitter<T>{
    emit(value? : T);
    subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): Subscription;
}

...

Code Block
breakoutModewide
interface IChart extends IBase {
    
    readonly reportType: IReportType = "chart"
  
    readonly _defaultConfig: IChartConfig; // default config for tooltips colors legend etc.
    
    type: IChartType;

    config: IChartOptions; 

    chartClick: EventEmitter<any>;
    chartHover: EventEmitter<any>;

    chartBuilder(config); // (prepares / converts) input chart config as per the underlying chart library used.

    refreshChart(); // refreshes and updates the chart either at specific interval or explicitly triggerd

    addData({ label, data, config }); //appends the label and data at the end;

    removeData(); //pops the last data and label
    removeData(label: string) // removes a specific label

    getTelemetry();

    // mergeData(data1, data2, ...dataN): any[];

    getCurrentSelection(); 
    
    getDatasetAtIndex(index: number);
}

/*
##########################################################################
*
*.         depenedent interfaces are as follows:-
*
##########################################################################
*/


type IChartType = "bar" | "line" | "pie" | "etc";

type IChartOptions = {
    labels? : string[], // if labels are passed explicitely
    labelExpr ? : string; // column name to use as x-axis labels;
    datasets: IDataset[]; // datasets - y axis data
    tooltip?: object;
    legend?: object
    animation?: object;
    colors?: object;
    title?: string | object;
    description?: string;
    subtitle?: string;
    caption?: object;
    filters?: IFilterConfig;
    scales?: {
        axes: any;
        [key: string]: any;
    };
    [key: string]: any;
};

type IDataset  = {
    label: string;
    dataExpr?: string;
    data: any[];
}

...

Code Block
breakoutModewide
interface ITable extends IBase {

    readonly reportType: IReportType = "table"

    readonly _defaultConfiguration: ITableConfig;

    config: ITableConfig;

    getRowsCount(); // rows count
    getRowAtIndex(index: number);   //get row at index number
    rowSelector(selectors); //fetch first row matching the config
    rowSelectorAll(selectors); // fetch rows matching a config

    addRow(data: object); // add a new row to the table by passing row configuration
    removeRow(index?: string); //removes row from the end or  at specific index;
    addColumn(config: ITableConfiguration); // adds a new column at the end
    removeColumn(columnName: string); // removes a column

    rowClick: EventEmitter<any>; // row click  event emitter
    rowHover: EventEmitter<any>; // mouse over event emitter

    exportTable(exportType: string); // exports the table into a type
    sortTable(sortByColumnName: string, orderBy: "asc" | "desc");
}


/*
##########################################################################
*
*.         depenedent interfaces are as follows:-
*
##########################################################################
*/

interface ITableConfig {
  paging: boolean; // to show pagination below the table
  info: boolean; // to show count or other info below the table
  [otherTableLevelConfig: string]: any;
  columnConfig: {
      title?: string;    // header name for the column
      searchable?: boolean; // if the column is searchable or not - will be used by the search bar at the top
      orderable?: boolean;  // if the column can be ordered or sorted in asecending or descending fashion
      data?: string;  // key in the input JSON to be used as column
      visible?: boolean; // hides or shows a column within a table
      render?: () => any;  // method to override the view and customise it like showing a button or chip instead of normal text
      autoWidth?: boolean;
      widthSize?: string; // customised width either in percentage or fixed width
      [key: string]: any; //any other metadata
      }
}

Filters Config and Component Design

...

How To Pass Data Into The Component

There are 3 ways to pass data into the Components

  1. pass JSON directly into the component

  2. use a url to point to fetch the JSON file

  3. pass API config into the component

** The property implements the IData interface

Code Block
data: IData;
Code Block
languagejson
interface IData <T extends object> {
    values?: T[];
    location: {
        apiConfig?: IApiConfig;
        url?: string;
    };
    dataSchema?: {
        [key: string]: IDataSchema;
    }
}
Code Block
interface IApiConfig {
    url: string;
    headers: {
        [header: string]: string | string[];
    };
    methodType: methodType;
    params: {
        [param: string]: string | string[];
    };
    response: {
        path: string;  //Gets the value at path of response object;
    }
}
Code Block
interface interface IDataSchema {
    type: string,
    enum?: string[],
    default?: string,
    format?: string; //url, date etc
    items?: IDataSchema // if type is array
}

Attribute Name

Description

values: Array<object>

if JSON needs to be passed directly

Ex- [{"<metric1>":"<value1>", "<metric2>":"<value2>"}]

apiConfig: IApiConfig

This property is used to pass API configuration like url, headers, params, methodType etc to the component.

Component will fetch the response and <reponse.path> is used to get the JSON value at the path of the response object

url: string

Url to point to the JSON file if apiConfig isn’t specified

dataSchema: IDataSchema

data schema can also be passed for the component for validation purposes.

...

Filters Config and Component Design

This component and interface it to make a generic filter which will serve all for all the reportTypes.

...

Property

Description

type

chartType like bar, line, pie etc

config

config JSON as per the interfaces mentioned in the previous sections

data

pass data or API details as per the IDataLocation IData interface mentioned in the previous sections.Section <How to pass data into the component>

id <optional>

unique id. If not passed a uuid is assigned by the component

height or Width <optional>

If not passed 100% is assumed

events

certain event listeners exposed by the component

...

Code Block
breakoutModewide
languagehtml
<sb-dashlet [type]="string" [config]="config" [data]="data | IDataLocation" , [id]="string | uuid" [height]="string"
    [width]="string" (...anyOtherEvent)="eventListener($event)">

</sb-dashlet></sb-dashlet>

...

Examples Of Using this component

** Please Note that for the next couple of examples we’ll be be passing data/JSON directly into the component.

The data will be as follows and has metrics for Tamil Nadu state Unique Devices Count <Portal and App> :-

Code Block
breakoutModewide
languagejson
let data =  [
        {
            "District": "Ariyalur",
            "Unique Devices on app": "6443.0",
            "Unique Devices on portal": "1332.0"
        },
        {
            "District": "Chennai",
            "Unique Devices on app": "81222.0",
            "Unique Devices on portal": "12349.0"
        },
        {
            "District": "Coimbatore",
            "Unique Devices on app": "49100.0",
            "Unique Devices on portal": "5690.0"
        },
        {
            "District": "Cuddalore",
            "Unique Devices on app": "4330.0",
            "Unique Devices on portal": "6524.0"
        },
        {
            "District": "Dharmapuri",
            "Unique Devices on app": "7133.0",
            "Unique Devices on portal": "8236.0"
        }
    ]

...

    ]

Example of a Line Chart using the Component

Brief Description:- In this chart we’ll plot District on the x-axis and Unique Devices on app & Unique Devices on portal keys on the y-axis from the above dataset.

Chart with Config is as follows:-

...

Code Block
breakoutModewide
languagehtml
<sb-dashlet [type]="'line'" [data]="data" [config]="config" (chartClick)="chartClickHandler($event)" (chartHover)="chartHoverHandler($event)"></sb-dashlet>

...

Map Using Dashlet Component

Brief Description :- We’ll plot the districts and corresponding info on the Tamil Nadu state map.

Same can be extended to show complete India Map as well with different states information

...

Code Block
breakoutModewide
languagehtml
<sb-dashlet [type]="'map'" [data]="data" [config]="config" (featureClicked)="eventListener($event)">
</sb-dashlet>

<script>

    let config = {
        state: 'Tamil Nadu',
        districts: ['Ariyalur', 'Chennai', 'Coimbatore', 'Cuddalore', 'Dharmapuri'],
        metrics: ['Unique Devices on app', Unique Devices on portal],
        title: 'Tamil Nadu Weekly Usage'
        // country: 'India', // Optional - to show india map with states
        // states: ['Karnataka'], // Optional - list of states to show on the map
    }


  // default config can be overridden with new configurations...

    let otherOptions = {
        initialCoordinate: [20, 78],
        latBounds: [6.4626999, 68.1097],
        lonBounds: [35.513327, 97.39535869999999],
        initialZoomLevel: 5,
        controlTitle: 'Tamil Nadu Weekly Usage',
        tileLayer: {
            urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
            options: {
                attributions: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
            }
        },
        rootStyle: {
            fillColor: '#007cbe'
        },
        otherOptions: any
    };
</script>

...

Table Example using Dashlet Component

This Example will plot the same datasource in Table format as shown in the image below

Image Modified

Code Block
breakoutModewide
languagehtml
<sb-dashlet type="'table'" [data]="data" [config]="config" (rowClickHandler)="eventListener($click)"> 
</sb-dashlet>

<script>

    let columnsConfiguration = {
          paging: true,
          info: true,
          columnConfig: [
              { title: "District", data: "District", searchable: true, orderable: true, autoWidth: true, visible: true },
              { title: "Unique App Count", data: "Unique Devices on app", searchable: true, orderable: true, autoWidth: true, visible: true },
              { title: "Unique Portal Count", data: "Unique Devices on portal", searchable: true, orderable: true, autoWidth: true, visible: true },
          ]
    }

</script>

...