Custom Widget

Build your own custom widget to view and filter existing data

Configuring Custom Plugin

From your Custom Dashboards or Schemas Tabs configuration page, you can add the widgets:

You can also add a custom widget directly on your service page, but it will be applied and shown only in that service.

This will bring you to the custom plugin editor, which will be empty by default. Here you can build your widget and preview the output. Check the list of possible widgets and some samples below in this same page.

Custom Plugin JSON Format

A custom plugin is created by specifying an array of plugin option objects. The objects must follow this format:

export type ICustomPluginSchema =
  | ICustomPluginList
  | ICustomPluginCard
  | ICustomPluginSwaggerUI
  | ICustomPluginIframe
  | ICustomPluginDivider
  | ICustomPluginTable
  | ICustomPluginChart
  | ICustomPluginMarkdown;

export interface ICustomPluginList {
  displayType: "list";
  schema: string;
  title?: string;
  item?: {
    title: string;
    subtitle?: string;
    color?: string;
    icon?: string;
    tags?: string;
    url?: string;
  };
  maxItems?: number;
  sort?: IQueryBuilderSort;
  filters?: IQueryBuilderFilterCondition[];
  dateRange?: ICustomPluginDateRange;
}

export interface ICustomPluginCard {
  displayType: "card";
  schema: string;
  title?: string;
  item?: {
    title: string;
    subtitle?: string;
    icon?: string;
    url?: string;
  };
  maxItems?: number;
  sort?: IQueryBuilderSort;
  filters?: IQueryBuilderFilterCondition[];
  dateRange?: ICustomPluginDateRange;
}

export interface ICustomPluginSwaggerUI {
  displayType: "swaggerUI";
  schema: string;
  title?: string;
  item?: {
    subtitle?: string;
    title?: string;
    url?: string;
  };
  maxItems?: number;
  sort?: IDataFlexibilitySort;
  filters?: IDataFlexibilityFilterCondition[];
  dateRange?: ICustomPluginDateRange;
}

export interface ICustomPluginIframe {
  displayType: "iframe";
  schema: string;
  title?: string;
  url: string;
}

export interface ICustomPluginTable {
  displayType: "table";
  schema: string;
  path?: string;
  title?: string;
  menu?: ICustomPluginMenu;
  sort?: IDataFlexibilitySort;
  filters?: IDataFlexibilityFilterCondition[];
  pageSize?: number;
  columns?: string[];
  dateRange?: ICustomPluginDateRange;
}

export interface ICustomPluginMarkdown {
  displayType: "markdown";
  content?: string;
}

export interface ICustomPluginDivider {
  displayType: "divider";
  title?: string;
}

export enum QueryBuilderSortDirection {
  ASC = 'ASC',
  DESC = 'DESC',
}

export interface IQueryBuilderSort {
  field: string;
  direction: QueryBuilderSortDirection;
}

export enum QueryBuilderFilterType {
  compare = 'compare',
  or = 'or',
  and = 'and',
}

export type IQueryBuilderFilterCondition =
  | IQueryBuilderFilterCompare
  | IQueryBuilderFilterOr
  | IQueryBuilderFilterAnd;

export interface IQueryBuilderFilterCompare {
  type: QueryBuilderFilterType.compare;
  field: string;
  value: string | number | boolean | (string | number)[] | null;
  compare: QueryBuilderFilterCompare;
}

export interface IQueryBuilderFilterOr {
  type: QueryBuilderFilterType.or;
  conditions: IQueryBuilderFilterCondition[];
}

export interface IQueryBuilderFilterAnd {
  type: QueryBuilderFilterType.and;
  conditions: IQueryBuilderFilterCondition[];
}

type RelativeDateUnit = "day" | "week" | "month" | "quarter" | "year";

interface IDateRangeRelativeOption {
  title: string;
  start: {
    value: number;
    unit: RelativeDateUnit;
  };
  end: {
    value: number;
    unit: RelativeDateUnit;
  };
}

export interface ICustomPluginDateRange {
  enabled?: boolean;
  hideDefaultRelativeOptions?: boolean;
  relativeOptions?: IDateRangeRelativeOption[];
}

In addition to this JSON format and following display type examples, Chart Widgets are also available.

This likely looks more complicated than it actually is, especially since we allow complex filtering and sorting. Here's a simple example just to show a list of items with some detailed information inline:

If the schema field is set to empty, the schema being edited itself is used as the data source.

[{
    "displayType": "list",
    "schema": "<your_schema_name_here>",
    "item": {
        "title": "{{ item.name }}",
        "subtitle": "{{ item.description }}"
    }
}]

And switching displayType to card looks like this:

The editor on the left-hand side will give you some hints if there are issues in the formatting for the code:

Complex examples

Here are a couple more examples of custom plugins with some varying configurations.

List View

This is an example of a plugin with some more detailed data, as well as a max number for the list of items.

Code snippet
[{
    "schema": "<your_schema_here>",
    "displayType": "list",
    "item": {
        "title": "{{ item.name }}",
        "subtitle": "{{ item.severity }}",
        "icon": "{{ item.priority }}"
    },
    "maxItems": 3
}]

This is an example of a plugin with filtering and sorting.

Code snippet
[{
    "schema": "<your_schema_here>",
    "displayType": "list",
    "item": {
        "title": "{{ item.name }}",
        "subtitle": "{{ item.severity }}"
    },
    "filters": [{
        "type": "compare",
        "field": "name",
        "value": "CVE-2024-0193",
        "compare": "like"
    }]
}]

Swagger UI

This is an example of a plugin with basic configuration.

Code snippet
[
  {
    "displayType": "swaggerUI",
    "schema": "",
    "item": {
      "title": "{{ item.name }}",
      "url": "{{ item.details.URL }}"
    }
  }
]

This is an example of a plugin with relational schema's detail. In this example, we are adding a SwaggerUI widget to the service schema. We assume that the service schema has a relation named apiDocs.

Code snippet
[
  {
    "displayType": "swaggerUI",
    "schema": "apiDocs",
    "item": {
      "title": "{{ item.name }}",
      "url": "{{ item.details.URL }}"
    }
  }
]

Iframe

This is an example of a plugin with static iframe url

Code snippet
[
  {
    "displayType": "iframe",
    "schema": "",
    "url": "https://www.youtube.com/embed/jmDIyhwnUEs?si=ira340kUNOfUwLfF"
  }
]

This is an example of a plugin with basic configuration

Code snippet
[
  {
    "displayType": "iframe",
    "schema": "",
    "url": "{{item.details.VideoURL}}"
  }
]

Table View

This is an example of a plugin with basic configuration

Code snippet
[{
    "displayType": "table",
    "schema": "<your_schema_here>",
}]

This is an example of a plugin with custom page size and sorting.

Code snippet
[{
    "displayType": "table",
    "schema": "scorecards",
    "pageSize": 12,
    "sort": {
        "field": "evaluatePercentage",
        "direction": "ASC"
    },
}]

This is an example of a plugin with filtering.

Code snippet
[{
    "displayType": "table",
    "schema": "scorecards",
    "pageSize": 12,
    "sort": {
        "field": "evaluatePercentage",
        "direction": "ASC"
    },
     "filters": [{
        "type": "compare",
        "field": "evaluatePercentage",
        "value": 10,
        "compare": "gte"
    }],
}]

This is an example of a plugin with custom columns.

Code snippet
[{
    "displayType": "table",
    "schema": "scorecards",
    "pageSize": 12,
    "sort": {
        "field": "evaluatePercentage",
        "direction": "ASC"
    },
     "filters": [{
        "type": "compare",
        "field": "evaluatePercentage",
        "value": 10,
        "compare": "gte"
    }],  
    "columns": ["name","evaluatePercentage"]
}]

Date Range

This is an example of a plugin using a date range with default options.

Code snippet
[
  {
    "displayType": "table",
    "schema": "<your_schema_here>",
    "columns": [
      "name",
      "accruedCosts",
      "priorPeriodCosts",
      "changeCosts"
    ],
    "dateRange": {
      "enabled": true
    }
  }
]

This is an example of a plugin using a date range without the default relative date options.

Code snippet
[
  {
    "displayType": "table",
    "schema": "<your_schema_here>",
    "columns": [
      "name",
      "accruedCosts",
      "priorPeriodCosts",
      "changeCosts"
    ],
    "dateRange": {
      "enabled": true,
      "hideDefaultRelativeOptions": true
    }
  }
]

This is an example of a plugin using a date range by adding custom relative date options.

Title: name to be shown on the left side of date picker dialog. Start: relative date reference for the initial date. Ex. "2-week" is 2 weeks prior to today. End: relative date reference for the ending date. Ex. "0-day" is today. Value: number field. Unit: can be one of the following; "day", "week", "month", "quarter", or "year".

Code snippet
[
  {
    "displayType": "table",
    "schema": "<your_schema_here>",
    "columns": [
      "name",
      "accruedCosts",
      "priorPeriodCosts",
      "changeCosts"
    ],
    "dateRange": {
      "enabled": true,
      "hideDefaultRelativeOptions": true,
      "relativeOptions": [
        {
          "title": "Past 2 weeks",
          "start": {
            "value": 2,
            "unit": "week"
          },
          "end": {
            "value": 0,
            "unit": "day"
          }
        }
      ]
    }
  }
]

Markdown text

This is an example of a plugin with markdown text.

Code snippet
[
  {
    "displayType": "markdown",
    "content": "# Welcome to My Project\n\n#### \n\n~~Introduction Welcome to my project! This project is focused on providing an amazing experience through the use of modern web technologies.~~"
  }
]

DORA Metrics widgets samples

The widgets shared here use data from Deploys and Incidents schemas and it's relation with each other and services to live calculate and display the 4 Dora Metrics. This data is modelled using configure8 Data Flexibility feature. Check the full docs and samples about the schemas here: Deploys, Incidents.

Full Organization DORA Dashboard

You can build a dashboard that display data from all ORG (across all services) with the following JSON samples. This is how the dashboard looks:

Start by clicking the "Customize" button on the bottom of the Dashboard Menu. There you can add a new page. On the new page, click on the ... box at the top right and start adding tabs and widgets.

Sample JSON code for the widgets

Deployment Frequency:

[
  {
    "displayType": "chart",
    "variant": "line",
    "dateRange": {
      "enabled": true
    },
    "options": {
      "datasets": [
        {
          "color": "green",
          "identifier": "deploys",
          "aggregate": {
            "field": "Start",
            "modifier": "by_date"
          },
          "maxItems": 200,
          "filters": [
            {
              "compare": "gte",
              "field": "Start",
              "type": "compare",
              "value": {
                "context": "startDate"
              }
            },
            {
              "compare": "lte",
              "field": "Start",
              "type": "compare",
              "value": {
                "context": "endDate"
              }
            }
          ],
          "sort": {
            "direction": "ASC",
            "field": "value"
          }
        }
      ],
      "indexAxis": "x"
    }
  }
]

Lead Time for Changes:

[
  {
    "displayType": "chart",
    "variant": "line",
    "dateRange": {
      "enabled": true
    },
    "options": {
      "datasets": [
        {
          "color": "orange",
          "identifier": "deploys",
          "aggregate": {
            "field": "Start",
            "modifier": "by_date"
          },
          "maxItems": 200,
          "data": "{{item.DurationAVG}}",
          "filters": [
            {
              "compare": "gte",
              "field": "Start",
              "type": "compare",
              "value": {
                "context": "startDate"
              }
            },
            {
              "compare": "lte",
              "field": "Start",
              "type": "compare",
              "value": {
                "context": "endDate"
              }
            }
          ],
          "sort": {
            "direction": "ASC",
            "field": "value"
          }
        }
      ],
      "indexAxis": "x"
    }
  }
]

Change Failure Rate:

[
  {
    "displayType": "chart",
    "variant": "line",
    "dateRange": {
      "enabled": true
    },
    "options": {
      "datasets": [
        {
          "identifier": "ExtendedServices",
          "data": "{{item.DORACFR}}",
          "aggregate": {
            "field": "ServiceDeploys.Start",
            "modifier": "by_date"
          },
          "maxItems": 200,
          "filters": [
            {
              "compare": "gte",
              "field": "ServiceDeploys.Start",
              "type": "compare",
              "value": {
                "context": "startDate"
              }
            },
            {
              "compare": "lte",
              "field": "ServiceDeploys.Start",
              "type": "compare",
              "value": {
                "context": "endDate"
              }
            }
          ],
          "sort": {
            "direction": "ASC",
            "field": "value"
          },
          "color": "orange"
        }
      ]
    }
  }
]

Mean Time to Restore:

[
  {
    "displayType": "chart",
    "variant": "line",
    "dateRange": {
      "enabled": true
    },
    "options": {
      "datasets": [
        {
          "color": "red",
          "identifier": "incidents",
          "aggregate": {
            "field": "Start",
            "modifier": "by_date"
          },
          "maxItems": 200,
          "filters": [
            {
              "compare": "gte",
              "field": "Start",
              "type": "compare",
              "value": {
                "context": "startDate"
              }
            },
            {
              "compare": "lte",
              "field": "Start",
              "type": "compare",
              "value": {
                "context": "endDate"
              }
            }
          ],
          "data": "{{item.DurationAVG}}",
          "sort": {
            "direction": "ASC",
            "field": "value"
          }
        }
      ],
      "indexAxis": "x"
    }
  }
]

Service tab with DORA Dashboard

You can create a similar view in a tab for every service:

For that you need to extend the Service Schema and add a new tab.

Sample JSON code for the Services Widgets

Deployment Frequency:

[
  {
    "displayType": "chart",
    "variant": "line",
    "dateRange": {
      "enabled": true
    },
    "options": {
      "datasets": [
        {
          "color": "green",
          "schema": "ServiceDeploys",
          "aggregate": {
            "field": "Start",
            "modifier": "by_date"
          },
          "maxItems": 200,
          "filters": [
            {
              "compare": "gte",
              "field": "Start",
              "type": "compare",
              "value": {
                "context": "startDate"
              }
            },
            {
              "compare": "lte",
              "field": "Start",
              "type": "compare",
              "value": {
                "context": "endDate"
              }
            }
          ],
          "sort": {
            "direction": "ASC",
            "field": "value"
          }
        }
      ],
      "indexAxis": "x"
    }
  }
]

Lead Time for Changes:

[
  {
    "displayType": "chart",
    "variant": "line",
    "dateRange": {
      "enabled": true
    },
    "options": {
      "datasets": [
        {
          "color": "orange",
          "schema": "ServiceDeploys",
          "aggregate": {
            "field": "Start",
            "modifier": "by_date"
          },
          "maxItems": 200,
          "data": "{{item.DurationAVG}}",
          "filters": [
            {
              "compare": "gte",
              "field": "Start",
              "type": "compare",
              "value": {
                "context": "startDate"
              }
            },
            {
              "compare": "lte",
              "field": "Start",
              "type": "compare",
              "value": {
                "context": "endDate"
              }
            }
          ],
          "sort": {
            "direction": "ASC",
            "field": "value"
          }
        }
      ],
      "indexAxis": "x"
    }
  }
]
```

Change Failure Rate:

[
  {
    "displayType": "chart",
    "variant": "line",
    "dateRange": {
      "enabled": true
    },
    "options": {
      "datasets": [
        {
          "schema": "",
          "data": "{{item.DORACFR}}",
          "aggregate": {
            "field": "ServiceDeploys.Start",
            "modifier": "by_date"
          },
          "maxItems": 200,
          "filters": [
            {
              "compare": "gte",
              "field": "ServiceDeploys.Start",
              "type": "compare",
              "value": {
                "context": "startDate"
              }
            },
            {
              "compare": "lte",
              "field": "ServiceDeploys.Start",
              "type": "compare",
              "value": {
                "context": "endDate"
              }
            }
          ],
          "sort": {
            "direction": "ASC",
            "field": "value"
          },
          "color": "orange"
        }
      ]
    }
  }
]
```

Mean Time to Restore:

[
  {
    "displayType": "chart",
    "variant": "line",
    "dateRange": {
      "enabled": true
    },
    "options": {
      "datasets": [
        {
          "color": "red",
          "schema": "ServiceIncidents",
          "aggregate": {
            "field": "Start",
            "modifier": "by_date"
          },
          "maxItems": 200,
          "filters": [
            {
              "compare": "gte",
              "field": "Start",
              "type": "compare",
              "value": {
                "context": "startDate"
              }
            },
            {
              "compare": "lte",
              "field": "Start",
              "type": "compare",
              "value": {
                "context": "endDate"
              }
            }
          ],
          "data": "{{item.DurationAVG}}",
          "sort": {
            "direction": "ASC",
            "field": "value"
          }
        }
      ],
      "indexAxis": "x"
    }
  }
]

Last updated

Copyright © 2023 configure8, Inc. All rights reserved.