👾 Boss Level — Module 12
Boss Fight: Build a Real App
Hands-onThe Capstone: Build a 3-Page App
Combine everything you've learned into one app:
Page 1: Overview — KPI cards + CPU timeseries chart
Page 2: Host Explorer — DataTable with row actions + intent navigation
Page 3: External Feed — App function proxying an external API
Page 1: Overview
export const Overview = () => {
const kpis = useDql({ query: `fetch dt.entity.host | summarize count()` });
const cpu = useDql({
query: `timeseries avg(dt.host.cpu.usage), from:-2h`
});
return (
<Flex flexDirection="column" gap={16}>
<KpiCard title="Total Hosts" value={kpis.data?.records[0]?.count} />
<div style={{ height: 300 }}>
<TimeseriesChart data={convertToTimeseries(cpu.data)} />
</div>
</Flex>
);
};
Page 2: Host Explorer
export const HostExplorer = () => {
const { data } = useDql({
query: `fetch dt.entity.host | fields entity.name, cpuCores, osType`
});
return (
<DataTable data={data?.records} columns={convertToColumns(data)}>
<DataTable.RowActions>
{(row) => (
<IntentButton appId="dynatrace.notebooks" intentId="view-query"
payload={{ "dt.query": `fetch dt.entity.host | filter id == "${row.id}"` }}>
Open in Notebooks
</IntentButton>
)}
</DataTable.RowActions>
</DataTable>
);
};
Page 3: External Feed
// api/external-feed.function.ts
export default async function handler() {
const res = await fetch("https://api.example.com/status");
return new Response(JSON.stringify(await res.json()));
}
// ui/app/pages/Feed.tsx
const { data } = useAppFunction({ id: "external-feed" });
💡 This is the pattern for every production app: DQL for internal data, app functions for external data, intents for navigation.
What's Next
Module 13 — Secret levels: state persistence, filters, toasts, design tokens.