sisense.com
✅ You are viewing documentation for the latest version of Compose SDK.
Version:

3 | Compose Dashboard In Code

It’s time to detach ourselves from Fusion dashboards.

In the following examples, you'll learn how to programmatically create a dashboard based on the data fetched from Sisense using the generic Dashboard component — without relying on any pre-existing Fusion dashboards.

Note

The examples below assume that the app is already set up to connect to the Sample ECommerce data model in a Sisense instance using SisenseContextProvider – see Quickstart guides.

To keep the code concise, the examples are provided in React, but the same configurations can be adapted for Angular and Vue.

Create an Empty Dashboard

In this example, we'll start dashboardProps almost empty with just title and an empty array of WidgetProps.

React
import { Dashboard, DashboardProps, WidgetProps } from '@sisense/sdk-ui';
import { useMemo } from 'react';

const CodeExample = () => {
  // DashboardProps is a set of properties for the Dashboard component
  const dashboardProps: DashboardProps = useMemo(() => {
    const widgets: WidgetProps[] = [];    

    return { title: 'Fabulous ECommerce Dashboard', widgets };
  }, []);

  return <Dashboard {...dashboardProps} />;
};

export default CodeExample;

Empty Sample ECommerce Dashboard

Add a Chart Widget

Let's add a chart widget to the list of widgets. It is a simple indicator displaying Total Revenue.

React
import { Dashboard, DashboardProps, WidgetProps } from '@sisense/sdk-ui';
import * as DM from './sample-ecommerce';
import { useMemo } from 'react';
import { measureFactory } from '@sisense/sdk-data';

const CodeExample = () => {
  // DashboardProps is a set of properties for the Dashboard component
  const dashboardProps: DashboardProps = useMemo(() => {
    const widgets: WidgetProps[] = [
      {
        id: 'widget-1',
        widgetType: 'chart',
        chartType: 'indicator',
        title: 'Total Revenue',
        dataOptions: {
          value: [
            {
              column: measureFactory.sum(DM.Commerce.Revenue, 'Total Revenue').format('0,0$'),
            },
          ],
        },
      },
    ];

    return { title: 'Fabulous ECommerce Dashboard', widgets };
  }, []);

  return <Dashboard {...dashboardProps} />;
};

export default CodeExample;

Dashboard with One Widget

Let's take a closer look at WidgetProps:

  • id is needed for layout and widget options.
  • widgetType can be one of the four currently supported types: chart, pivot, text, and plugin.
  • filters is not provided as the dashboard does not have any filters yet.
  • layoutOptions helps to customize how widgets are laid out. If it is not provided, dashboard will use a simple vertical column layout by default.

This isn't a very interesting dashboard. Let’s improve this in the next example.

Add Dashboard Filters, Other Widgets, and Set Up Layout

Below is the code for the same Sample Ecommerce dashboard created programatically.

React
import {
  Dashboard,
  DashboardProps,
  IndicatorStyleOptions,
  LineStyleOptions,
  NumberFormatConfig,
  ScatterStyleOptions,
  StackableStyleOptions,
  WidgetProps,
  WidgetsPanelColumnLayout,
} from '@sisense/sdk-ui';
import * as DM from './sample-ecommerce';
import { useMemo } from 'react';
import { Filter, filterFactory, measureFactory } from '@sisense/sdk-data';

const seriesToColorMap = {
  Female: '#00cee6',
  Male: '#9b9bd7',
  Unspecified: '#6eda55',
};

export const getIndicatorStyleOptions = (
  title: string,
  secondaryTitle = '',
): IndicatorStyleOptions => {
  return {
    indicatorComponents: {
      title: {
        shouldBeShown: true,
        text: title,
      },
      secondaryTitle: {
        text: secondaryTitle,
      },
      ticks: {
        shouldBeShown: true,
      },
      labels: {
        shouldBeShown: true,
      },
    },
    subtype: 'indicator/gauge',
    skin: 1,
  };
};

const scatterStyleOptions: ScatterStyleOptions = {
  xAxis: {
    logarithmic: true,
  },
  yAxis: {
    logarithmic: true,
  },
  height: 454,
};

const barStyleOptions: StackableStyleOptions = {
  subtype: 'bar/stacked',
  height: 454,
};

const numberFormat: NumberFormatConfig = {
  name: 'Numbers',
  decimalScale: 2,
  trillion: true,
  billion: true,
  million: true,
  kilo: true,
  thousandSeparator: true,
  prefix: false,
  symbol: '$',
};

const lineChartStyleOptions: LineStyleOptions = {
  subtype: 'line/spline',
  lineWidth: { width: 'bold' },
  yAxis: {
    title: { enabled: true, text: 'SALES' },
  },
  y2Axis: {
    title: { enabled: true, text: 'QUANTITY' },
  },
  markers: {
    enabled: true,
    fill: 'hollow',
  },
  height: 454,
};

const CodeExample = () => {
  // DashboardProps is a set of properties for the Dashboard component
  const dashboardProps: DashboardProps = useMemo(() => {
    const widgets: WidgetProps[] = [
      {
        id: 'widget-1',
        widgetType: 'chart',
        chartType: 'indicator',
        title: 'Total Revenue',
        dataOptions: {
          value: [
            {
              column: DM.Measures.SumRevenue,
              numberFormatConfig: numberFormat,
            },
          ],
          secondary: [],
          min: [measureFactory.constant(0)],
          max: [measureFactory.constant(125000000)],
        },
        styleOptions: getIndicatorStyleOptions('Total Revenue'),
      },
      {
        id: 'widget-2',
        widgetType: 'chart',
        chartType: 'indicator',
        title: 'Total Units Sold',
        dataOptions: {
          value: [DM.Measures.Quantity],
          secondary: [],
          min: [measureFactory.constant(0)],
          max: [measureFactory.constant(250000)],
        },
        styleOptions: getIndicatorStyleOptions('Total Units Sold'),
      },
      {
        id: 'widget-3',
        widgetType: 'chart',
        chartType: 'indicator',
        title: 'Total Sales',
        dataOptions: {
          value: [measureFactory.countDistinct(DM.Commerce.VisitID)],
          secondary: [],
          min: [measureFactory.constant(0)],
          max: [measureFactory.constant(100000)],
        },
        styleOptions: getIndicatorStyleOptions('Total Sales'),
      },
      {
        id: 'widget-4',
        widgetType: 'chart',
        chartType: 'indicator',
        title: 'Total Brands',
        dataOptions: {
          value: [measureFactory.countDistinct(DM.Brand.BrandID)],
          secondary: [],
          min: [measureFactory.constant(0)],
          max: [measureFactory.constant(2500)],
        },
        styleOptions: getIndicatorStyleOptions('Total Brands'),
      },
      {
        id: 'widget-5',
        widgetType: 'chart',
        chartType: 'line',
        title: 'REVENUE vs.UNITS SOLD',
        dataOptions: {
          category: [
            {
              column: DM.Commerce.Date.Months,
              dateFormat: 'yy-MM',
            },
          ],
          value: [
            DM.Measures.SumRevenue,
            {
              column: DM.Measures.Quantity,
              showOnRightAxis: true,
              chartType: 'column',
            },
          ],
          breakBy: [],
        },
        styleOptions: lineChartStyleOptions,
      },
      {
        id: 'widget-6',
        widgetType: 'chart',
        chartType: 'pie',
        title: 'GENDER BREAKDOWN',
        dataOptions: {
          category: [DM.Commerce.Gender],
          value: [DM.Measures.SumRevenue],
        },
        filters: [filterFactory.members(DM.Commerce.Gender, ['Male', 'Female'])],
        styleOptions: scatterStyleOptions,
      },
      {
        id: 'widget-7',
        widgetType: 'chart',
        chartType: 'pie',
        title: 'AGE RANGE BREAKDOWN',
        dataOptions: {
          category: [DM.Commerce.AgeRange],
          value: [DM.Measures.SumRevenue],
        },
        filters: [filterFactory.members(DM.Commerce.Gender, ['Male', 'Female'])],
        styleOptions: scatterStyleOptions,
      },
      {
        id: 'widget-8',
        widgetType: 'chart',
        chartType: 'scatter',
        title: 'TOP CATEGORIES BY REVENUE, UNITS SOLD AND GENDER',
        dataOptions: {
          x: DM.Measures.SumRevenue,
          y: DM.Measures.Quantity,
          breakByPoint: DM.Category.Category,
          breakByColor: DM.Commerce.Gender,
          size: DM.Measures.SumCost,
          seriesToColorMap,
        },
        filters: [
          filterFactory.members(DM.Commerce.Gender, ['Male', 'Female']),
          filterFactory.topRanking(DM.Category.Category, DM.Measures.SumRevenue, 10),
        ],
        styleOptions: scatterStyleOptions,
      },
      {
        id: 'widget-9',
        widgetType: 'chart',
        chartType: 'bar',
        title: 'TOP 3 CATEGORIES BY REVENUE AND AGE',
        dataOptions: {
          category: [DM.Commerce.AgeRange],
          value: [DM.Measures.SumRevenue],
          breakBy: [DM.Category.Category],
        },
        filters: [filterFactory.topRanking(DM.Category.Category, DM.Measures.SumRevenue, 3)],
        styleOptions: barStyleOptions,
      },
    ];

    const filters: Filter[] = [
      filterFactory.members(DM.Commerce.Date.Years, ['2013-01-01T00:00:00']),
      filterFactory.members(DM.Country.Country, []),
      filterFactory.greaterThan(DM.Commerce.Revenue, 0),
    ];

    const widgetsPanelLayout: WidgetsPanelColumnLayout = {
      columns: [
        {
          widthPercentage: 20,
          rows: [
            { cells: [{ widthPercentage: 100, widgetId: 'widget-1' }] },
            { cells: [{ widthPercentage: 100, widgetId: 'widget-2' }] },
            { cells: [{ widthPercentage: 100, widgetId: 'widget-3' }] },
            { cells: [{ widthPercentage: 100, widgetId: 'widget-4' }] },
          ],
        },
        {
          widthPercentage: 40,
          rows: [
            { cells: [{ widthPercentage: 100, widgetId: 'widget-5' }] },
            {
              cells: [
                { widthPercentage: 50, widgetId: 'widget-6' },
                { widthPercentage: 50, widgetId: 'widget-7' },
              ],
            },
          ],
        },
        {
          widthPercentage: 40,
          rows: [
            { cells: [{ widthPercentage: 100, widgetId: 'widget-8' }] },
            { cells: [{ widthPercentage: 100, widgetId: 'widget-9' }] },
          ],
        },
      ],
    };

    return {
      title: 'Fabulous ECommerce Dashboard',
      widgets,
      filters,
      layoutOptions: { widgetsPanel: widgetsPanelLayout },
    };
  }, []);

  return <Dashboard {...dashboardProps} />;
};

export default CodeExample;

Sample ECommerce Dashboard In Code

The dashboard is fully interactive. Cross filtering and drilldown work as expected.

At first glance, this code may seem like a significant leap from the previous example. However, upon closer inspection, you'll notice there's no advanced coding or complex algorithms involved. It's simply a standard configuration of dashboard elements: 9 widgets, 3 dashboard filters, and a widget layout.
The Compose SDK handles all the internal wiring and interactions for you.

Learn More

In this section you learned how to compose a dashboard fully in code using the Dashboard component.

To deepen your understanding, check out the API Doc and Compose SDK Playground.

Last Updated: