Skip to main content

The Data-Driven Dashboard

So far, all our views have been generated from <ResourceSchema>. But a real admin dashboard usually has a home page with KPI cards, charts, and summaries. In this chapter, we will build one using Strato Admin's headless data hooks and Cloudscape's chart components.

The Headless Paradigm​

Strato Admin separates data fetching from rendering. The same hooks that power <List> and <Detail> are available to you directly. This means you can build any custom UI while still benefiting from caching, loading states, and your configured data provider.

Setting Up a Custom Dashboard​

<Admin> accepts a dashboard prop — a React component that is rendered when the user navigates to /.

Create src/Dashboard.tsx:

src/Dashboard.tsx
export const Dashboard = () => {
return (
<div style={{ padding: '2rem' }}>
<h1>StratoShop Overview</h1>
{/* We'll fill this in below */}
</div>
);
};

Register it in App.tsx:

src/App.tsx
import { Dashboard } from './Dashboard';

const App = () => (
<Admin dataProvider={dataProvider} dashboard={Dashboard}>
{/* resources */}
</Admin>
);

Fetching Data with useGetList​

The useGetList hook fetches a paginated, sorted, filtered list of records — the same way <List> does internally.

Let's fetch the 5 most recent orders to display in a summary table:

src/Dashboard.tsx
import { useGetList } from '@strato-admin/admin';
import Table from '@cloudscape-design/components/table';
import Box from '@cloudscape-design/components/box';
import Spinner from '@cloudscape-design/components/spinner';

export const RecentOrders = () => {
const { data: orders, isPending } = useGetList('orders', {
sort: { field: 'date', order: 'DESC' },
pagination: { page: 1, perPage: 5 },
});

if (isPending) return <Spinner />;

return (
<Table
columnDefinitions={[
{ id: 'id', header: 'Order #', cell: (item) => item.id },
{ id: 'customer', header: 'Customer', cell: (item) => item.customer_id },
{ id: 'total', header: 'Total', cell: (item) => `$${item.total}` },
{ id: 'status', header: 'Status', cell: (item) => item.status },
]}
items={orders ?? []}
header={<Box variant="h2">Recent Orders</Box>}
/>
);
};

Adding a Chart​

Cloudscape includes BarChart and LineChart components. Let's aggregate order totals by month to build a revenue chart.

src/Dashboard.tsx
import { useGetList } from '@strato-admin/admin';
import BarChart from '@cloudscape-design/components/bar-chart';
import Box from '@cloudscape-design/components/box';
import Spinner from '@cloudscape-design/components/spinner';

const groupByMonth = (orders: any[]) => {
const totals: Record<string, number> = {};
for (const order of orders) {
const month = new Date(order.date).toLocaleString('en', { month: 'short', year: '2-digit' });
totals[month] = (totals[month] ?? 0) + order.total;
}
return Object.entries(totals).map(([x, y]) => ({ x, y }));
};

export const RevenueChart = () => {
const { data: orders, isPending } = useGetList('orders', {
sort: { field: 'date', order: 'ASC' },
pagination: { page: 1, perPage: 1000 },
});

if (isPending) return <Spinner />;

const series = [{ title: 'Revenue', type: 'bar' as const, data: groupByMonth(orders ?? []) }];

return <BarChart series={series} xTitle="Month" yTitle="Revenue ($)" height={300} empty={<Box>No data</Box>} />;
};

Putting it Together​

Compose both components in your Dashboard:

src/Dashboard.tsx
import ContentLayout from '@cloudscape-design/components/content-layout';
import Grid from '@cloudscape-design/components/grid';
import Header from '@cloudscape-design/components/header';

export const Dashboard = () => (
<ContentLayout header={<Header variant="h1">StratoShop Overview</Header>}>
<Grid gridDefinition={[{ colspan: { default: 12, l: 8 } }, { colspan: { default: 12, l: 4 } }]}>
<RevenueChart />
<RecentOrders />
</Grid>
</ContentLayout>
);

How it Works​

  • useGetList(resource, params) returns { data, total, isPending, error }. It is backed by the same data provider and caching layer as the standard <List> component.
  • No schema required: The dashboard doesn't use <ResourceSchema> at all. You get raw records and render them however you like.
  • Cloudscape components: Any Cloudscape component can be used freely inside your dashboard. The design system handles spacing, colors, and responsive behavior.

Summary​

In this chapter, we've learned how to:

  • Register a custom dashboard component with <Admin>.
  • Use useGetList to fetch data without a standard List view.
  • Transform raw records for use in Cloudscape chart components.

Next Steps​

In the next chapter, we will make StratoShop accessible to a global audience by adding Internationalization (i18n).