From 2ac23a4de5bd43d77c8652d55a8b8f89470a88f9 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Wed, 20 May 2026 13:18:45 -0400 Subject: [PATCH] Fix docs app demo iframe assets (#4194) --- docs/apps/demos/bar-chart.html | 76 -- docs/apps/demos/contacts.html | 172 --- docs/apps/demos/dashboard.html | 157 --- docs/apps/demos/data-table.html | 90 -- docs/apps/demos/hitchhikers.html | 1105 ------------------ docs/apps/demos/pie-chart.html | 60 - docs/apps/demos/reactive.html | 167 --- docs/apps/demos/team-directory-reactive.html | 237 ---- docs/apps/demos/team-directory.html | 127 -- docs/apps/fastmcp-app.mdx | 3 +- docs/apps/overview.mdx | 3 +- docs/apps/prefab.mdx | 13 +- docs/apps/quickstart.mdx | 5 +- docs/prefab-demo-payloads.js | 1 + docs/snippets/prefab-demo-frame.mdx | 66 ++ 15 files changed, 81 insertions(+), 2201 deletions(-) delete mode 100644 docs/apps/demos/bar-chart.html delete mode 100644 docs/apps/demos/contacts.html delete mode 100644 docs/apps/demos/dashboard.html delete mode 100644 docs/apps/demos/data-table.html delete mode 100644 docs/apps/demos/hitchhikers.html delete mode 100644 docs/apps/demos/pie-chart.html delete mode 100644 docs/apps/demos/reactive.html delete mode 100644 docs/apps/demos/team-directory-reactive.html delete mode 100644 docs/apps/demos/team-directory.html create mode 100644 docs/prefab-demo-payloads.js create mode 100644 docs/snippets/prefab-demo-frame.mdx diff --git a/docs/apps/demos/bar-chart.html b/docs/apps/demos/bar-chart.html deleted file mode 100644 index 81372d859..000000000 --- a/docs/apps/demos/bar-chart.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - Prefab - - - - - - -
- - - \ No newline at end of file diff --git a/docs/apps/demos/contacts.html b/docs/apps/demos/contacts.html deleted file mode 100644 index 5831d639c..000000000 --- a/docs/apps/demos/contacts.html +++ /dev/null @@ -1,172 +0,0 @@ - - - - Prefab - - - - - - -
- - - \ No newline at end of file diff --git a/docs/apps/demos/dashboard.html b/docs/apps/demos/dashboard.html deleted file mode 100644 index 21c1c8924..000000000 --- a/docs/apps/demos/dashboard.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - Prefab - - - - - - -
- - - \ No newline at end of file diff --git a/docs/apps/demos/data-table.html b/docs/apps/demos/data-table.html deleted file mode 100644 index fe84abcd4..000000000 --- a/docs/apps/demos/data-table.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - Prefab - - - - - - -
- - - \ No newline at end of file diff --git a/docs/apps/demos/hitchhikers.html b/docs/apps/demos/hitchhikers.html deleted file mode 100644 index 7f26f9796..000000000 --- a/docs/apps/demos/hitchhikers.html +++ /dev/null @@ -1,1105 +0,0 @@ - - - - Prefab Showcase - - - - - - -
- - - \ No newline at end of file diff --git a/docs/apps/demos/pie-chart.html b/docs/apps/demos/pie-chart.html deleted file mode 100644 index c712eeb33..000000000 --- a/docs/apps/demos/pie-chart.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - Prefab - - - - - - -
- - - \ No newline at end of file diff --git a/docs/apps/demos/reactive.html b/docs/apps/demos/reactive.html deleted file mode 100644 index 29f05e2d3..000000000 --- a/docs/apps/demos/reactive.html +++ /dev/null @@ -1,167 +0,0 @@ - - - - Prefab - - - - - - -
- - - \ No newline at end of file diff --git a/docs/apps/demos/team-directory-reactive.html b/docs/apps/demos/team-directory-reactive.html deleted file mode 100644 index f2ab5bf7e..000000000 --- a/docs/apps/demos/team-directory-reactive.html +++ /dev/null @@ -1,237 +0,0 @@ - - - - Prefab - - - - - - -
- - - \ No newline at end of file diff --git a/docs/apps/demos/team-directory.html b/docs/apps/demos/team-directory.html deleted file mode 100644 index be577ddde..000000000 --- a/docs/apps/demos/team-directory.html +++ /dev/null @@ -1,127 +0,0 @@ - - - - Prefab - - - - - - -
- - - \ No newline at end of file diff --git a/docs/apps/fastmcp-app.mdx b/docs/apps/fastmcp-app.mdx index f3463da66..55b3b7ed7 100644 --- a/docs/apps/fastmcp-app.mdx +++ b/docs/apps/fastmcp-app.mdx @@ -8,12 +8,13 @@ tag: NEW import { VersionBadge } from '/snippets/version-badge.mdx' import PrefabPinWarning from '/snippets/prefab-pin-warning.mdx' +import { PrefabDemoFrame } from '/snippets/prefab-demo-frame.mdx' - + Search a list, fill out a form, click save, the list updates. That pattern — UI that reads and writes data on the server — needs two things: backend tools that actually do the work, and a way to call them from the UI. `FastMCPApp` handles the wiring. diff --git a/docs/apps/overview.mdx b/docs/apps/overview.mdx index ed04580f6..ff9557058 100644 --- a/docs/apps/overview.mdx +++ b/docs/apps/overview.mdx @@ -8,6 +8,7 @@ mode: center import { VersionBadge } from '/snippets/version-badge.mdx' import PrefabPinWarning from '/snippets/prefab-pin-warning.mdx' +import { PrefabDemoFrame } from '/snippets/prefab-demo-frame.mdx' @@ -21,7 +22,7 @@ A FastMCP app is a tool that returns an interactive UI instead of text. When the maskImage: 'linear-gradient(to bottom, black 75%, transparent)', WebkitMaskImage: 'linear-gradient(to bottom, black 75%, transparent)', }}> - + The dashboard above is a [Prefab](https://prefab.prefect.io) showcase — a taste of what you can deliver from a FastMCP tool. Every card, chart, slider, dialog, and carousel is a Python component. Build a composition like this, add `@mcp.tool(app=True)`, and the host renders it inside the conversation. diff --git a/docs/apps/prefab.mdx b/docs/apps/prefab.mdx index 1bebc73de..e6ff7070f 100644 --- a/docs/apps/prefab.mdx +++ b/docs/apps/prefab.mdx @@ -8,12 +8,13 @@ tag: NEW import { VersionBadge } from '/snippets/version-badge.mdx' import PrefabPinWarning from '/snippets/prefab-pin-warning.mdx' +import { PrefabDemoFrame } from '/snippets/prefab-demo-frame.mdx' - + Believe it or not, that dashboard is a FastMCP tool. The chart has tooltips. The table is sortable. The badges are styled by deal stage. The whole thing is about 40 lines of Python, and the user sees it right inside their conversation instead of a wall of JSON. @@ -23,7 +24,7 @@ The pattern behind every example on this page is the same: add `app=True` to you Most tools return data the user wants to explore. A `DataTable` is often the smallest useful upgrade — your data goes from a JSON blob to a searchable, sortable table: - + ```python from prefab_ui.components import DataTable, DataTableColumn @@ -62,7 +63,7 @@ That's it. Add `app=True`, return a Prefab component instead of raw dicts. FastM When numbers tell a better story as a visual, swap in a chart. The API is the same: pass your data as a list of dicts, tell the chart which keys to plot. - + ```python @mcp.tool(app=True) @@ -88,7 +89,7 @@ def quarterly_revenue(year: int) -> BarChart: Each `ChartSeries` plots a different key from the data. `BarChart`, `LineChart`, `AreaChart`, `PieChart`, `RadarChart`, and `RadialChart` all follow the same pattern. Hover over the bars to see tooltips. - + ```python @mcp.tool(app=True) @@ -116,7 +117,7 @@ See the [Prefab chart docs](https://prefab.prefect.io/docs/components) for stack Tables and charts are useful on their own, but the real power comes from composing them. `Column` stacks children vertically, `Row` lays them out side by side, and `with` blocks establish nesting — the indentation is the layout. - + ```python expandable @mcp.tool(app=True) @@ -184,7 +185,7 @@ Notice how `Badge` components can be placed inside table cells — any Prefab co Everything above renders once from the data your Python provides. But interactive tools can also respond to user input in real time, without any server round-trips. Prefab's state system lets components read and write client-side values, so the UI updates instantly as the user interacts with it. - + Try switching regions in the dropdown, and toggling the switch on and off. diff --git a/docs/apps/quickstart.mdx b/docs/apps/quickstart.mdx index 7b87d1981..2221b9de9 100644 --- a/docs/apps/quickstart.mdx +++ b/docs/apps/quickstart.mdx @@ -7,12 +7,13 @@ tag: NEW --- import { VersionBadge } from '/snippets/version-badge.mdx' +import { PrefabDemoFrame } from '/snippets/prefab-demo-frame.mdx' By the end of this page, you'll have a working tool that returns this: - + A pie chart the user can hover, a table they can sort and search — and a single Python tool. @@ -103,7 +104,7 @@ The UI above renders once from your Python. Prefab apps can also respond to user Click a row in the demo below to see a detail card appear: - + Add a few imports, give each member a couple more fields, wire up a click handler, and render a detail card when something's selected: diff --git a/docs/prefab-demo-payloads.js b/docs/prefab-demo-payloads.js new file mode 100644 index 000000000..885ce713b --- /dev/null +++ b/docs/prefab-demo-payloads.js @@ -0,0 +1 @@ +window.__FASTMCP_PREFAB_DEMOS__ = {"bar-chart":"\n\n\n Prefab\n \n \n \n \n\n\n
\n \n\n","contacts":"\n\n\n Prefab\n \n \n \n \n\n\n
\n \n\n","dashboard":"\n\n\n Prefab\n \n \n \n \n\n\n
\n \n\n","data-table":"\n\n\n Prefab\n \n \n \n \n\n\n
\n \n\n","hitchhikers":"\n\n\n Prefab Showcase\n \n \n \n \n\n\n
\n \n\n","pie-chart":"\n\n\n Prefab\n \n \n \n \n\n\n
\n \n\n","reactive":"\n\n\n Prefab\n \n \n \n \n\n\n
\n \n\n","team-directory-reactive":"\n\n\n Prefab\n \n \n \n \n\n\n
\n \n\n","team-directory":"\n\n\n Prefab\n \n \n \n \n\n\n
\n \n\n"}; diff --git a/docs/snippets/prefab-demo-frame.mdx b/docs/snippets/prefab-demo-frame.mdx new file mode 100644 index 000000000..c7d639ece --- /dev/null +++ b/docs/snippets/prefab-demo-frame.mdx @@ -0,0 +1,66 @@ +export const PrefabDemoFrame = ({ demo, height, title }) => { + const [blobUrl, setBlobUrl] = React.useState(null); + + React.useEffect(() => { + let active = true; + let objectUrl = null; + let payloadsPromise = window.__FASTMCP_PREFAB_DEMOS_PROMISE__; + + if (window.__FASTMCP_PREFAB_DEMOS__) { + payloadsPromise = Promise.resolve(window.__FASTMCP_PREFAB_DEMOS__); + } else if (!payloadsPromise) { + payloadsPromise = new Promise((resolve, reject) => { + const script = document.createElement("script"); + script.src = "/prefab-demo-payloads.js"; + script.onload = () => resolve(window.__FASTMCP_PREFAB_DEMOS__); + script.onerror = reject; + document.head.appendChild(script); + }); + window.__FASTMCP_PREFAB_DEMOS_PROMISE__ = payloadsPromise; + } + + payloadsPromise + .then((payloads) => { + const html = payloads[demo]; + if (!html) { + throw new Error(`Unknown Prefab demo: ${demo}`); + } + objectUrl = URL.createObjectURL( + new Blob([html], { type: "text/html" }), + ); + if (active) { + setBlobUrl(objectUrl); + } else { + URL.revokeObjectURL(objectUrl); + } + }); + + return () => { + active = false; + if (objectUrl) { + URL.revokeObjectURL(objectUrl); + } + }; + }, [demo]); + + if (!blobUrl) { + return
; + } + + return ( +