npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@e-llm-studio/federated-dashboard-components

v1.0.1

Published

A React component library for building **config-driven executive dashboards**. The flagship export, `ExecutiveDashboardWrapper`, renders a complete dashboard — date filters, a multi-tier line-chart, KPI metric cards, a filter sidebar, and data tables — fr

Readme

@e-llm-studio/federated-dashboard-components

A React component library for building config-driven executive dashboards. The flagship export, ExecutiveDashboardWrapper, renders a complete dashboard — date filters, a multi-tier line-chart, KPI metric cards, a filter sidebar, and data tables — from a single configId. The wrapper fetches its own layout and data from the backend, so the host application only has to mount one component and (optionally) describe how its tables should render.

The package also ships the underlying building blocks (Graph, MetricCard, FTable, TableCard, DashboardCard, DashboardDateFilter, FiltersSidebar, chart primitives, and KPI formatting helpers) for teams that want to compose a dashboard by hand.


Table of contents

  1. Installation
  2. Quick start
  3. How it works (architecture)
  4. ExecutiveDashboardWrapper props
  5. The tables prop in depth
  6. Backend API contract
  7. Exported building blocks
  8. KPI formatting utilities
  9. TypeScript types reference
  10. Troubleshooting

1. Installation

npm install @e-llm-studio/federated-dashboard-components

Peer dependencies

These must be installed in the host application (they are intentionally not bundled, so a single copy is shared):

npm install react@^18.3.1 react-dom@^18.3.1 \
  primereact@^10.9.7 primeicons@^7.0.0 \
  lucide-react@^0.476.0 recharts@^2.13.0 \
  react-router-dom@^7.6.2

| Peer dependency | Version | Used for | | ------------------ | ---------- | ----------------------------------------- | | react / react-dom | ^18.3.1 | Core runtime | | primereact | ^10.9.7 | Underlying DataTable, sidebar, dropdowns | | primeicons | ^7.0.0 | Icon font used by PrimeReact widgets | | lucide-react | ^0.476.0 | Iconography (chart/KPI/table icons) | | recharts | ^2.13.0 | Line-chart rendering | | react-router-dom | ^7.6.2 | Router context expected by the demo shell |

Import the stylesheet once

The library ships a single extracted stylesheet. Import it once at your app root (it is side-effecting and required for correct layout):

import "@e-llm-studio/federated-dashboard-components/dist/styles.css";

You will typically also want PrimeReact's own base CSS in your app shell:

import "primereact/resources/themes/lara-light-indigo/theme.css"; // or your theme
import "primereact/resources/primereact.min.css";
import "primeicons/primeicons.css";

2. Quick start

The wrapper is fully self-contained. Give it a configId and a baseUrl; it does the rest.

import "@e-llm-studio/federated-dashboard-components/dist/styles.css";
import { ExecutiveDashboardWrapper } from "@e-llm-studio/federated-dashboard-components";

export function ClaimsDashboard() {
  return (
    <ExecutiveDashboardWrapper
      configId="6a579569dc07b01447bd9797"
      baseUrl="https://dev.appmod.ai"
    />
  );
}

That single mount will:

  1. Call the UI config API once to learn the dashboard's structure (graph tiers, plot options, KPI cards, sidebar filters, date presets, table layout).
  2. Seed the date range from the config's default preset.
  3. Call the data API to load graph series + KPI values, and re-call it every time the date range or applied filters change.
  4. Render a skeleton while loading and an inline error + Retry button on failure.

Exports: ExecutiveDashboardWrapper is exported from the package root (src/index.ts), alongside the presentational ExecutiveDashboard, the built-in API fetchers (fetchUIConfig, fetchDashboardData, DashboardApiError), and the full set of container / config / data types.

With custom table rendering

To control how the dashboard's tables look (links, badges, currency, impact chips), pass a tables config keyed by each table's key from the UI config. See §5 for the full walkthrough.

import type { DashboardTablesConfig } from "@e-llm-studio/federated-dashboard-components";

const TABLES: DashboardTablesConfig = {
  top_plant_locations_by_claim_cost: {
    tableProps: { showGridlines: true },
    card: {
      title: { fontSize: 16, color: "#111827" },
      icon: { size: 18, color: "#059669" },
    },
    columns: [
      {
        key: "plant_location",
        header: "Plant Location",
        body: (row) => <a href="#">{row.plant_location}</a>,
      },
      {
        key: "claim_count",
        header: "Claim Count",
        body: (row) => <span>{row.claim_count}</span>,
      },
    ],
  },
};

<ExecutiveDashboardWrapper
  configId="6a579569dc07b01447bd9797"
  baseUrl="https://dev.appmod.ai"
  tables={TABLES}
/>;

A full worked example (money/impact/status cell helpers, a custom app header) lives in src/App.tsx.


3. How it works (architecture)

                       ┌──────────────────────────────┐
   configId, baseUrl → │  ExecutiveDashboardWrapper    │
                       │  (state + data orchestration) │
                       └──────────────┬───────────────┘
                                      │
          ┌───────────────────────────┼───────────────────────────┐
          │ 1. UI config API (once)   │ 2. Data API (on range/     │
          │    /federated/filters/ui  │    filter change)          │
          │    + .../distinct-value   │    /federated/filters/      │
          │                           │    get-data                 │
          ▼                           ▼                             │
     structure & labels          numeric series + KPI values        │
          └───────────────┬───────────────────────────────────────┘
                          ▼
                 ┌────────────────────┐
                 │  ExecutiveDashboard │  (presentational)
                 │  • DashboardDateFilter
                 │  • Graph (tiers + plot selectors)
                 │  • MetricCard × N
                 │  • FiltersSidebar
                 │  • TableCard × N
                 └────────────────────┘
  • State lives in the wrapper (ExecutiveDashboardWrapper.tsx): selected plot-by option per tier, filter values (draft vs. applied), and the active date range. All fetches are AbortController-guarded, so rapid filter changes cancel in-flight requests.
  • Two logical fetch phases. The UI config load also fetches the distinct values for each sidebar filter and merges them in as options. The data load is re-run whenever dateRange or appliedFilters change.
  • The inner ExecutiveDashboard is presentational — it receives everything as props and reports interactions back up via callbacks.

4. ExecutiveDashboardWrapper props

Defined by the DashboardContainerProps interface in src/types/index.ts. All props below are wired and consumed by the wrapper.

| Prop | Type | Required | Description | | ------------------ | ------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | configId | string | ✅ Yes | Identifies which dashboard config to load. Sent as config_id in the body of every API call. | | baseUrl | string | No | API origin. Defaults to "https://dev.appmod.ai". Trailing slashes are trimmed. Override for other environments (staging, prod, localhost). | | graphEmptyState | React.ReactNode | No | Custom node shown inside the graph area when no series have data. Falls back to a built-in empty state when omitted. | | tables | DashboardTablesConfig | No | Per-table render config keyed by the table key from the UI config's tableBuilder. Tables without an entry auto-render as plain text. See §5. | | tableLayout | DashboardTableLayoutConfig | No | Grid layout for the tables section — how many tables sit per row, which options the toolbar offers, and how narrow a card may get before the grid reflows. See §5.1. | | sectionOrder | DashboardSectionKey[] | No | Vertical order of the dashboard sections, by UI config key — e.g. ["tableBuilder", "kpiCards", "graphBuilder"]. Partial lists are allowed. See §4.1. | | hiddenSections | DashboardSectionKey[] | No | Parts to leave out entirely, e.g. ["graphBuilder", "sidebarFilters"]. Applied after sectionOrder, and unlike it, also accepts the pinned dateFilters / sidebarFilters. See §4.1. | | fetchUIConfig | FetchUIConfig | No | Override the built-in UI-config fetcher — (config, signal?) => Promise<DashboardUIConfig>. Useful for mocks/tests or a custom transport. Defaults to the built-in /federated/filters/ui fetcher. | | fetchDashboardData | FetchDashboardData | No | Override the built-in data fetcher — (config, params, signal?) => Promise<DashboardDataResponse>. Defaults to the built-in /federated/filters/get-data fetcher. | | initialStartDate | Date | No | Force the initial range start instead of deriving it from the config's default preset. Must be paired with initialEndDate. | | initialEndDate | Date | No | Force the initial range end. Must be paired with initialStartDate. | | onDateChange | (payload: any) => void | No | Fires whenever the resolved date range changes (payload carries { startDate, endDate }). | | onFiltersApplied | (filters: Record<string, string \| string[]>) => void | No | Fires after the sidebar's Apply is pressed, with the applied filter values. | | renderLoading | () => React.ReactNode | No | Replace the default skeleton loader. | | renderError | (error: Error, retry: () => void) => React.ReactNode | No | Replace the default inline error + retry UI. retry re-runs the UI-config load. |

Notes

  • initialStartDate / initialEndDate only seed the first render. If only one is provided, the wrapper falls back to the config's default preset.
  • Fetcher overrides receive an AbortController signal and are expected to honour it — the wrapper cancels in-flight requests when inputs change.
<ExecutiveDashboardWrapper
  configId="6a579569dc07b01447bd9797"
  initialStartDate={new Date("2026-01-01")}
  initialEndDate={new Date("2026-04-18")}
  onDateChange={(p) => console.log("range:", p)}
  onFiltersApplied={(f) => console.log("filters:", f)}
  renderLoading={() => <MySpinner />}
  renderError={(err, retry) => <MyError message={err.message} onRetry={retry} />}
/>

4.1 Section order (sectionOrder / hiddenSections)

Everything in the dashboard body can be re-ordered by passing the same keys the API sends — today graphBuilder, kpiCards and tableBuilder:

// Tables on top, then the KPI cards, then the chart.
<ExecutiveDashboardWrapper
  configId="6a579569dc07b01447bd9797"
  sectionOrder={["tableBuilder", "kpiCards", "graphBuilder"]}
/>

Two parts have a fixed position: the date filter bar stays pinned at the top and the filters sidebar is an overlay, so its position never affects the layout. sectionOrder therefore ignores dateFilters / sidebarFilters — handy when you're just reordering the config's key list wholesale:

// Same result as above.
sectionOrder={["dateFilters", "sidebarFilters", "tableBuilder", "kpiCards", "graphBuilder"]}

Fixed position doesn't mean permanent, though — hiddenSections can remove them:

hiddenSections={["dateFilters", "sidebarFilters"]}   // both gone

New sections work automatically. When the backend grows another section, pass its key the same way — sectionOrder={["kpiCards", "pieChartBuilder", "graphBuilder"]}. Nothing about ordering needs to change: the order is resolved against whatever sections the dashboard currently renders, and the prop type accepts any string, so a new key never trips the type checker.

Details:

  • Partial lists are fine. Anything omitted keeps its default position, so sectionOrder={["tableBuilder"]} alone means "tables first, then the rest as usual".
  • hiddenSections drops a part — separate from sectionOrder, so nothing disappears just for being left out of the order. It's applied last, so hiding always wins, and it accepts the pinned parts as well as the body sections:
    sectionOrder={["kpiCards", "graphBuilder"]}
    hiddenSections={["tableBuilder", "sidebarFilters"]}
    Hiding sidebarFilters also removes the Filter button (and its count) from the date bar, since there'd be no panel left for it to open. Hiding dateFilters only removes the bar — the dashboard still loads data for the config's default date range.
  • Key matching is forgiving — case-insensitive, and spaces/underscores/dashes are ignored, so "Table Builder", "table_builder" and "tableBuilder" are the same key.
  • Unknown keys are ignored, not thrown — they'd usually come from config. In development an ignored key logs a console warning naming it and listing the available sections, so a typo is easy to spot. Duplicates collapse.

Driving the order from the backend config

The UI config payload may also carry the order as data.sectionOrder, which is useful when the layout should travel with the dashboard config instead of being hard-coded in the host app:

{
  "data": {
    "sectionOrder": ["tableBuilder", "kpiCards", "graphBuilder"],
    "dateFilters": { "...": "..." },
    "graphBuilder": { "...": "..." },
    "kpiCards": ["..."],
    "tableBuilder": ["..."]
  }
}

The sectionOrder prop wins over data.sectionOrder, so a host can always override what the config asks for. Both go through the same resolution, so the same keys work in either place.

The resolver is exported if a host needs the same behaviour in its own layout UI:

import {
  DASHBOARD_SECTION_KEYS,  // ["graphBuilder", "kpiCards", "tableBuilder"]
  PINNED_SECTION_KEYS,     // ["dateFilters", "sidebarFilters"]
  resolveSectionOrder,     // (order?, hidden?, configOrder?, available?) → string[]
  isSectionHidden,         // (hidden, "dateFilters") → boolean
} from "@e-llm-studio/federated-dashboard-components";

Ordering within a section still comes from the config: KPI cards honour displayOrder, graph tiers/series honour theirs, and table placement inside the grid is controlled by tableLayout.spans.


5. The tables prop in depth

The UI config's tableBuilder defines which tables exist and their raw columns. The tables prop lets the host app decide how each of those tables renders — custom cell JSX, headers, per-column styles, and the surrounding card chrome (icon + title). It's optional and partial: any table key you don't provide falls back to auto-generated plain-text columns.

type DashboardTablesConfig = Record<string, DashboardTableRenderConfig>;

The keys must match tableBuilder[].key from the UI config.

DashboardTableRenderConfig

| Field | Type | Description | | ------------ | --------------------------- | ------------------------------------------------------------------------------------------------------- | | columns | FTableColumn[] | Required. Column render definitions (see below). | | tableProps | Record<string, any> | Passthrough props merged onto the underlying PrimeReact DataTable (e.g. { showGridlines: true }). | | card | DashboardTableCardStyles | Styling for the card wrapping the table (shell, header, title, icon). |

FTableColumn

| Field | Type | Description | | ---------------- | ------------------------------------ | ----------------------------------------------------------------------- | | key | string | Row field / column identity. | | header | React.ReactNode | Header cell content (string or JSX). | | body | (row: TableRow) => React.ReactNode | Cell renderer for each row. TableRow is Record<string, any>. | | style | React.CSSProperties | Applied to both header and body cells of the column. | | headerStyle | React.CSSProperties | Header-cell (<th>) only; overrides style for the header. | | bodyStyle | React.CSSProperties | Body-cell (<td>) only; overrides style for rows. | | headerClassName| string | Class on the header cell. | | bodyClassName | string | Class on body cells. |

DashboardTableCardStyles

| Field | Type | Description | | -------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | root | React.CSSProperties | The card shell. Set width here to size the whole card — the table fills it. | | header | React.CSSProperties | The header row (icon + title + search/expand controls). | | title | React.CSSProperties | The title text (font, colour, padding). | | icon | { size?: number; color?: string; background?: string; style?: CSSProperties } | Glyph size/colour, chip background, and an escape hatch for other icon-container CSS. |

Sizing tip: To make a table narrower, set card.root.width (e.g. "60%"). Sizing only the table leaves the card full-width.

Full table example

import type { DashboardTablesConfig, FTableColumn, TableRow } from "@e-llm-studio/federated-dashboard-components";

const money = (v: any) => (Number.isFinite(Number(v)) ? `$${v}` : String(v ?? ""));

const linkCol = (field: string, header: string): FTableColumn => ({
  key: field,
  header,
  body: (row) => <a href="#" style={{ color: "#7c3aed" }}>{row[field]}</a>,
});

const TABLES: DashboardTablesConfig = {
  claim_cost_by_incident_type: {
    tableProps: { showGridlines: true },
    card: {
      header: { padding: "10px" },
      title: { fontSize: 16, color: "#111827" },
      icon: { size: 18, color: "#059669" },
    },
    columns: [
      linkCol("incident_type", "Incident Type"),
      { key: "total_claim_cost", header: "Total Claim Cost", body: (r) => money(r.total_claim_cost) },
      { key: "litigation_rate", header: "Litigation Rate", body: (r) => `${r.litigation_rate} %` },
    ],
  },
};

5.1 Table grid layout (tableLayout)

When the UI config has more than one table, a small toolbar appears above the tables section with one icon per layout — 1 / 2 / 3 tables per row. Picking an icon re-flows the tables into that many columns.

The layout is always responsive: minColumnWidth is the narrowest a table card may become, and the grid drops columns automatically as the container (not the window) gets narrower — 3-up becomes 2-up, then 1-up. The user's choice is remembered, so widening the container restores it. An option that can't fit at the current width is dimmed in the toolbar.

<ExecutiveDashboardWrapper
  configId="6a579569dc07b01447bd9797"
  tables={TABLES}
  tableLayout={{
    options: [1, 2, 3],     // icons offered in the toolbar
    defaultColumns: 2,      // start 2-up
    minColumnWidth: 420,    // drop a column below this per-card width
    gap: 16,
    toggleLabel: "Layout",
  }}
/>

| Field | Type | Default | Description | | ----------------- | ------------------------------------------- | ----------- | ---------------------------------------------------------------------- | | spans | Record<string, TableSpan> | TableSpan[] | — | Per-table width — see below. | | totalColumns | number | 12 | Grid columns the spans values are expressed in. | | defaultSpan | TableSpan | full width | Width for tables missing from spans. | | options | number[] | [1, 2, 3] | Column counts offered as toolbar icons (14 have dedicated icons). | | defaultColumns | number \| "custom" | see note | Layout on first render. Defaults to "custom" when spans is set, else 1. | | columns | number \| "custom" | — | Controlled layout. Pair with onColumnsChange to own the state. | | onColumnsChange | (columns: number \| "custom") => void | — | Fires when the user picks a layout. | | showToggle | boolean | true | Hide the toolbar and keep the configured column count. Auto-hidden for 1 table. | | toggleLabel | string | — | Caption rendered left of the toggle. | | minColumnWidth | number | 380 | Narrowest a card may get before a column is dropped — this drives the reflow. | | gap | number | 12 | Gap between cards, in px. | | equalHeights | boolean | true | Stretch every card in a row to the tallest one. false lets each card hug its own content. |

Cards in the same row are height-matched by default, so a 5-row table beside a 10-row one no longer renders short — the shorter table's card fills the row height. To cap how tall a row can get, give the table a scroll height via tables[key].tableProps, e.g. { scrollHeight: "360px" }.

Per-table widths (spans)

Uniform 1/2/3-up is the user's control. spans is the host's control: it sets the width of each table individually, so table 1 can own a full row while tables 2 and 3 sit side by side and table 4 goes full width again.

tableLayout={{
  spans: {
    revenue_summary: "full",   // row 1 — on its own
    claims_by_type:  "1/2",    // row 2 — side by side
    claims_by_plant: "1/2",    //
    litigation_log:  "full",   // row 3 — on its own
  },
}}

Keys are the table's key from the UI config's tableBuilder. An array works too and is read in table order — handy when the layout is positional:

tableLayout={{ spans: ["full", "1/2", "1/2", "full"] }}

Accepted values (TableSpan): "full", any fraction string ("1/2", "1/3", "2/3", "1/4", "3/4", …), or a raw column count against totalColumns (6 is half of the default 12-column grid). Rows are formed by CSS grid auto-placement, so spans that overflow a row simply wrap.

This stays responsive. No table is ever rendered narrower than minColumnWidth; spans widen instead. With the four-table layout above at minColumnWidth: 380:

| Container width | Result | | --------------- | --------------------------------------------------- | | ≥ 772px | [T1] / [T2 + T3] / [T4] — the configured shape | | < 772px | [T1] / [T2] / [T3] / [T4] — all full width |

(772px = two 380px cards plus the 12px gap.) Raise minColumnWidth to make it break to one column earlier, lower it to hold two columns longer.

When spans is set, the toolbar grows an extra icon for the configured layout and starts on it. The user can still switch to a uniform 1/2/3-up and click back to the configured one. Pass showToggle: false to lock the layout down.

The same grid is exported standalone as TableGrid if you're composing table cards yourself:

import { TableGrid, TableCard } from "@e-llm-studio/federated-dashboard-components";

<TableGrid defaultColumns={2} minColumnWidth={400}>
  <TableCard title="Claims" table={{ rows, columns }} />
  <TableCard title="Providers" table={{ rows: rows2, columns: columns2 }} />
</TableGrid>;

6. Backend API contract

The wrapper (via src/api/dashboardApi.ts) calls three POST JSON endpoints, all relative to baseUrl. Each responds with an envelope:

{
  "success": true,
  "request_id": "…",
  "data": { /* … */ },
  "error": null | { "errorMessage": "…", "errorType": "…" }
}

A non-2xx status, or success: false, throws a DashboardApiError (surfaced in the wrapper's error UI).

6.1 POST /federated/filters/ui — structure & labels

Request: { "config_id": "<configId>" }

Returns the dashboard layout: dateFilters, sidebarFilters, graphBuilder (tiers → plot options → series), kpiCards, and optional tableBuilder. See DashboardUIData in §9.

6.2 POST /federated/filters/distinct-value — filter options

Request: { "config_id": "<configId>" }

Returns { "sidebarFilters": { "<schemaFilterName>": string[] } }. The wrapper merges these arrays into each sidebar filter definition as its options.

UI config (6.1) and distinct values (6.2) are fetched in parallel and merged into a single DashboardUIConfig.

6.3 POST /federated/filters/get-data — the numbers

Request:

{
  "config_id": "<configId>",
  "dateFilters": { "startDate": "<ISO>", "endDate": "<ISO>" },
  "sidebarFilters": { "<schemaFilterName>": ["value", …] }
}

Filter normalisation: single-select values become one-element arrays; empty / unset filters are dropped from the payload.

Response data shape (DashboardDataResponse):

{
  "graph": {
    "<graphKey>": [
      { "key": "<tierKey>", "plotbyoptions": { "<plotOptionKey>": { "<seriesKey>": [ { "x": "D1", "y": 58 }, … ] } } }
    ]
  },
  "kpiCards": {
    // either a bare value…
    "Fill Rate Impact": "2.8k",
    // …or an object carrying a baseline for indicator colouring:
    "Total Claim Cost": { "currentValue": 8421316, "baselineValue": 7900000 }
  },
  "table": {
    "<tableKey>": [ { /* row */ }, … ]
  }
}

7. Exported building blocks

If you're composing a dashboard by hand rather than using the wrapper, the following are exported from the package root (see src/index.ts):

Components

| Export | Notes | | --------------------- | -------------------------------------------------------- | | Graph | Multi-pane line chart. Props: GraphProps. | | LineChart | Single line chart primitive. | | PlotBySelector | Dropdown used to switch a tier's plotted metric. | | DashboardDateFilter | Date-range picker with presets + refresh/filter buttons. | | MetricCard | KPI card. Props: MetricCardProps. | | FiltersSidebar | Slide-out filter panel. Props: FiltersSidebarProps. | | FTable | Low-level table. Props: FTableProps. | | TableCard | FTable wrapped in a titled/iconed card. Props: TableCardProps. | | TableGrid | Responsive N-per-row grid + layout toggle for table cards. Props: TableGridProps. | | TableLayoutToggle | The 1/2/3-per-row icon group on its own. Props: TableLayoutToggleProps. | | useResponsiveColumns| Hook behind the grid — caps a desired column count to what the container fits. | | DashboardCard | Rich content card (sections, tags, events, news, grid). |

Chart primitives (shadcn/Recharts port)

ChartContainer, ChartTooltip, ChartTooltipContent, ChartLegend, ChartLegendContent, useChart, plus the ChartConfig type and the DEFAULT_COLORS / colorForIndex palette helpers.

Date presets

DATE_PRESETS and related exports from datePreset — e.g. DAYS_7, DAYS_15, DAYS_30, THIS_MONTH, CUSTOM. Each preset with a getRange() returns { startDate, endDate }.


8. KPI formatting utilities

Exported from the package root for formatting/colouring KPI values consistently (see src/utils/index.ts):

| Export | Signature / purpose | | --------------------- | ----------------------------------------------------------------------------------------------------------- | | formatKpiValue | Format a raw KPI value using a format string (compacts numbers, preserves suffixes like %). | | getKpiDelta | Compute the delta (absolute + %) and sentiment between a current and baseline value. Returns KpiDelta. | | getKpiSentiment | (current, baseline, indicatorLogic) → "positive" \| "negative" \| "neutral". | | getKpiValueColor | Resolve a display colour from sentiment, with optional per-sentiment overrides. | | isKpiValueObject | Type guard: is a raw value the { currentValue, baselineValue } object form? | | KPI_SENTIMENT_COLORS| Default positive/negative colour map. | | compactNumber | 8421316 → "8.4M" style compaction. |

IndicatorLogic is one of "higher_better" | "lower_better" | "neutral" — it tells the sentiment helpers whether an increase is good or bad.

import {
  getKpiDelta,
  getKpiValueColor,
} from "@e-llm-studio/federated-dashboard-components";

const delta = getKpiDelta(8421316, 7900000, "higher_better");
// → { …, sentiment: "positive" }
const color = getKpiValueColor(8421316, 7900000, "higher_better");

9. TypeScript types reference

All types below are exported (or defined) in src/types/index.ts and re-exported from the root where noted.

  • Container: DashboardContainerProps — the wrapper's prop bag (§4).
  • UI config: DashboardUIConfigDashboardUIData{ dateFilters, sidebarFilters, graphBuilder, kpiCards, tableBuilder, sectionOrder? }.
    • DateFiltersConfigdatepresets, defaultPreset, showFilterButton, showFilterCount, showLiveButton, liveDurationMs.
    • SidebarFilterConfiglabel, description, schemaFilterName, type.
    • GraphBuilderConfigtitle, subtitle, icon, axis, tiers[], legend.
    • GraphTierConfigkey, title, displayOrder, plotOptions[], yAxis, series[].
    • PlotOptionConfig, SeriesConfig, LegendConfig, KpiCardConfig.
  • Data: DashboardDataResponse, TierData, PlotByOptions, SeriesDataMap, DataPoint.
  • Query: DashboardQueryParams{ startDate?, endDate?, filters? }.
  • Tables: DashboardTablesConfig, DashboardTableRenderConfig, DashboardTableCardStyles, DashboardTableLayoutConfig, TableBuilderConfig, TableColumnConfig, FTableColumn, TableRow.
  • Layout: DashboardSectionKey — a section named by its UI config key ("graphBuilder" | "kpiCards" | "tableBuilder", plus any future one, since any string is accepted). Used by sectionOrder / hiddenSections (§4.1).
  • KPI: KpiValueObject, KpiDelta, KpiSentiment, IndicatorLogic.
  • Fetchers: FetchUIConfig, FetchDashboardData (function types for the pluggable fetchers).

10. Troubleshooting

| Symptom | Likely cause / fix | | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | ExecutiveDashboardWrapper is undefined on import | Ensure you're on a build that exports it from the root; it is exported from src/index.ts. | | Blank / unstyled layout | You didn't import dist/styles.css (and/or PrimeReact's theme CSS). See §1. | | Requests hit the wrong host / 404 | baseUrl defaults to https://dev.appmod.ai. For another environment pass an explicit absolute baseUrl. | | "Failed to load dashboard" with a Retry button | An API returned non-2xx or success: false. Check the three endpoints in §6 and the config_id. | | Tables render as plain text | No matching entry in tables for that tableBuilder[].key. Keys must match exactly. See §5. | | Peer dependency warnings on install | Install the peers listed in §1 at compatible versions. |


Package: @e-llm-studio/federated-dashboard-components · Entry: src/index.ts · Wrapper: src/ExecutiveDashboardWrapper.tsx · API layer: src/api/dashboardApi.ts