Repository navigation
feat(appkit): add dev-only design pages plugin and ui-only template - #680
Conversation
📦 Bundle size reportCompared against
|
| dist | raw | gzip |
|---|---|---|
| JS (runtime) | 1.3 MB (+44 KB) | 478 KB (+16 KB) |
| Type declarations | 470 KB (+1.8 KB) | 169 KB (+910 B) |
| Source maps | 2.6 MB (+75 KB) | 888 KB (+24 KB) |
| Other | 11 KB | 3.7 KB |
| Total | 4.4 MB (+121 KB) | 1.5 MB (+41 KB) |
Per-entry composition (own code — deps external (as shipped))
| Entry | Initial (gz) | Lazy (gz) | Total (gz) | node_modules (min) | Own code (min) |
|---|---|---|---|---|---|
. |
107 KB (+60 B) | 2.5 KB | 110 KB (+60 B) | external | 347 KB (+77 B) |
./beta |
113 KB (+9.9 KB) | 485 B | 114 KB (+9.9 KB) | external | 338 KB (+27 KB) |
./testing |
46 KB | 33 KB (+73 B) | 79 KB (+73 B) | external | 229 KB (+175 B) |
./tsdown |
520 B | 0 B | 520 B | external | 813 B |
./type-generator |
26 KB (+31 B) | 0 B | 26 KB (+31 B) | external | 74 KB (+42 B) |
Chunks:
| Entry | Chunk | Load | Size (gz) |
|---|---|---|---|
. |
index.js |
initial | 103 KB |
. |
utils.js |
initial | 4.6 KB |
. |
remote-tunnel-manager.js |
lazy | 2.5 KB |
./beta |
beta.js |
initial | 93 KB |
./beta |
modular.js |
initial | 6.0 KB |
./beta |
stream-manager.js |
initial | 5.9 KB |
./beta |
service-context.js |
initial | 4.3 KB |
./beta |
databricks.js |
initial | 3.3 KB |
./beta |
client.js |
initial | 649 B |
./beta |
index.js |
initial | 20 B |
./beta |
supervisor-api.js |
lazy | 193 B |
./beta |
databricks.js |
lazy | 177 B |
./beta |
index.js |
lazy | 115 B |
./testing |
manifest.js |
initial | 33 KB |
./testing |
index.js |
initial | 10 KB |
./testing |
wide-event-emitter.js |
initial | 2.9 KB |
./testing |
index.js |
lazy | 29 KB |
./testing |
remote-tunnel-manager.js |
lazy | 2.5 KB |
./testing |
utils.js |
lazy | 1.8 KB |
./tsdown |
index.js |
initial | 520 B |
./type-generator |
index.js |
initial | 26 KB |
@databricks/appkit-ui
npm tarball (packed): 404 KB (+7.5 KB) — gzipped download (dist + bin; excludes release-only docs/NOTICE).
| dist | raw | gzip |
|---|---|---|
| JS (runtime) | 436 KB (+6.9 KB) | 149 KB (+2.7 KB) |
| Type declarations | 270 KB (+2.6 KB) | 100 KB (+1.3 KB) |
| Source maps | 861 KB (+13 KB) | 290 KB (+5.4 KB) |
| CSS | 16 KB | 3.2 KB |
| Total | 1.5 MB (+23 KB) | 542 KB (+9.4 KB) |
Per-entry composition (consumer bundle — deps bundled, peerDeps external)
| Entry | Initial (gz) | Lazy (gz) | Total (gz) | node_modules (min) | Own code (min) |
|---|---|---|---|---|---|
./js |
5.3 KB | 49 KB | 55 KB | 208 KB | 14 KB |
./js/beta |
2.1 KB | 0 B | 2.1 KB | 0 B | 5.0 KB |
./react |
440 KB (+42 B) | 49 KB | 489 KB (+42 B) | 1.4 MB | 178 KB (+129 B) |
./react/beta |
14 KB (+9.2 KB) | 0 B | 14 KB (+9.2 KB) | 25 KB (+25 KB) | 16 KB (+3.4 KB) |
Chunks:
| Entry | Chunk | Load | Size (gz) |
|---|---|---|---|
./js |
index.js |
initial | 5.2 KB |
./js |
chunk |
initial | 120 B |
./js |
apache-arrow |
lazy | 49 KB |
./js/beta |
beta.js |
initial | 2.1 KB |
./react |
index.js |
initial | 438 KB |
./react |
tslib |
initial | 2.1 KB |
./react |
apache-arrow |
lazy | 49 KB |
./react/beta |
beta.js |
initial | 14 KB |
|
Review 1 · Fail · 3 critical, 2 major Does the change do what the task asked? No. Gate: major and worse must be fixed. The canvas, multi-selection, notes, persistence across a real restart, and production 404 work, and the automated suite passes. The handoff is not reliable: normal selections can lack source locations, contain stale props, and include screenshots missing visible content. Valid wrapped components are also omitted, and concurrent reads can falsely report no pending selections. Required
|
|
Review 2 · Pass Does the change do what the task asked? Yes. Gate: major and worse must be fixed. The five earlier findings are fixed, and I found no regressions from those fixes. Browser checks against the built UI package, the full test suite, typechecking, and read-only lint/format checks passed. There are no remaining findings in this round. No findings. |
af1f4a2 to
aa65b0d
Compare
|
Review 5 · Fail · 1 critical, 1 major Does the change do what the task asked? No. Gate: major and worse must be fixed. The design canvas, selection handoff, persistence and production 404 behavior work in the exercised cases, and all 50 targeted tests pass. The screenshot requirement is incomplete: selecting an absolutely positioned element can silently save an entirely blank image. The added CLI also omits declared resource defaults from deployment variables in an unusual supported case. Required
|
🤖 AppKit PR bot🔬 Run evalsStart an eval for this PR from the evals-monitor app: Go to Evals Monitor → 📦 Try this PR's app templateScaffolds a new app from this PR's SDK build. Run it in any folder (requires the GitHub CLI — gh run download 43015404883 -R databricks/appkit -n appkit-template-0.92.0-pr.5d55b05-work-1-design-plugin-dev-only-design-680 -D appkit-pr-680 \
&& unzip -o "appkit-pr-680/appkit-template-0.92.0-pr.5d55b05-work-1-design-plugin-dev-only-design-680.zip" -d "appkit-pr-680" \
&& databricks apps init --template "appkit-pr-680"The template pins |
aa65b0d to
4d00fbf
Compare
|
Review 6 · Pass Does the change do what the task asked? Yes. Gate: major and worse must be fixed. Both previous findings are fixed at the reviewed commit. Chrome reproduced the blank screenshot with the previous code and verified the saved JPEG with the fix; actual plugin-add runs preserved manifest defaults in deployment YAML. The focused regression checks passed, with no remaining findings in this round. No findings. |
4d00fbf to
acf5c0f
Compare
|
Review 7 · Fail · 3 critical Does the change do what the task asked? No. Gate: major and worse must be fixed. The main canvas, source tracing, persisted handoff, production 404 behavior, and ui-only template work in the exercised paths. Three browser-proven faults remain: open dialogs disable the picker, completing a send discards selections added during that send, and screenshots omit typed values in uncontrolled inputs. The repository was left unchanged. Required
|
|
Review 8 · Pass Does the change do what the task asked? Yes. Gate: major and worse must be fixed. F8, F9 and F10 are fixed: browser checks confirmed modal selection, preservation of later picks and edited notes during a pending send, and screenshots containing current form values. Focused tests and nearby runtime checks passed, with no remaining findings in this review round. The repository was left unchanged. No findings. |
9bdf7b9 to
ad6dc6e
Compare
|
Review 10 · Fail · 3 critical Does the change do what the task asked? No. Gate: major and worse must be fixed. The change does not meet the full task: the running app has no selection interface, open dialogs block selection, and clicking an SVG path saves a blank screenshot. The normal canvas handoff, source metadata, persistence across a server restart, and production 404 behavior worked locally. All 71 tests exercised passed, including the previously failing React type test. Required
|
|
Review 11 · Fail · 2 critical Does the change do what the task asked? No. Gate: major and worse must be fixed. F12 and F13 are fixed and worked in Chromium, but the change does not yet meet the supplied task. F11 remains against the original running-app selection requirement; the claimed later scope change was not confirmed. Pressing the advertised Escape shortcut after selecting dialog content also closes the dialog and silently loses its screenshot when sent. Required
|
|
Review 12 · Fail · 2 critical, 1 major Does the change do what the task asked? No. Gate: major and worse must be fixed. The design pages and ui-only starter work, including hot reload and production 404s. The change does not meet the supplied task because element selection and persistent agent handoff are absent. An unrelated unfinished draft can also break an otherwise valid design page. Required
|
|
Review 13 · Fail · 2 critical Does the change do what the task asked? No. Gate: major and worse must be fixed. The broken-draft loading bug is fixed, including live browser rendering and hot reload beside an unfinished page. The current task still explicitly requires multi-selection with notes and a persisted agent handoff; both remain absent despite their intentional removal, so the change does not meet all stated requirements. Required
|
adfa702 to
b5f6314
Compare
|
Review 14 · Fail · 1 critical, 2 major Does the change do what the task asked? No. Gate: major and worse must be fixed. The change does not meet the full task: the required element selection and persistent agent handoff are absent. Design page rendering, navigation and production 404s work; 83 targeted tests pass and both changed TypeScript packages typecheck. Browser testing also reproduced false readiness after a render error and a broken route for pages/index.tsx. Required
|
b5f6314 to
48d89da
Compare
|
Review 15 · Fail · 1 critical, 1 major Does the change do what the task asked? No. Gate: major and worse must be fixed. The required selection and persistent agent-handoff workflow is still missing. The render-error fix works for edits to the index page, but readiness remains incorrectly true when an imported component fails after a hot edit. F20 is fixed, and all 49 focused design and server tests pass. Required
|
0341ad5 to
2d7a963
Compare
|
Review 20 · Pass · 1 minor, 1 trivial Does the change do what the task asked? Yes. Gate: major and worse must be fixed. Taking the human's later scope decisions into account (selection handling moved to the builder's inspector, drafts served with a hydrator), the branch does what was asked: /design is dev-only and returns 404 otherwise, drafts render real appkit-ui blocks, errors are reported, the props schema is published, and the ui-only template is generated. All 67 design-plugin tests and the use-design-ready tests pass. One edge case is left: the dark-mode token sync follows the system color scheme and ignores a draft that forces its own theme. Not required (below the gate)
|
|
Review 21 · Fail · 1 major Does the change do what the task asked? Yes. Gate: major and worse must be fixed. This round's additions (browserless status fields, theme.css, shipped schema, chart data types, template vitest inline) are in place and the design and chart tests pass. One claim is overstated: Required
|
88f8350 to
407f007
Compare
The drafts folder was added to Vite's watcher. A changed .html file matches no module, so Vite sent a full reload, and in middleware mode (how the server plugin runs Vite) that reloads every open page on each write: a draft mid-stream restarted and the app reloaded too. Drafts are now watched with fs.watch, and only the appkit:draft-changed notice is sent. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
ECharts advances its entry animation on animation frames, which the browser
pauses in hidden or background frames, such as a builder's preview. The axes
and labels were drawn while the series stayed frozen part-drawn or empty
(a blank line, a donut without its ring, a bar chart without bars). Charts
now draw their final state at once; options={{ animation: true }} turns the
animation back on.
Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
…undle
The check for react-router 7 resolved it through Vite, which returns the
pre-bundled node_modules/.vite/deps/react-router.js. That folder's
package.json has no name, so the check failed, the page entry was built
without a router, and a page using <Link> crashed ("Cannot destructure
property 'basename'") and never painted. It now uses Node's resolution from
the design page, which finds the app's own copy.
Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
…, render once - A block alone in its element fills that element's height, so an agent's sized box sizes the chart (it rendered at the 160px minimum). Next to a heading it keeps its own height and stays inside the card. - A chart's title is a heading above the chart instead of ECharts' title, which was drawn over the axes and legend. The schema says to leave it out when the container has its own heading. - A block that has rendered is never mounted again, also when the hydrator runs twice, and a block re-parsed with the same JSON doesn't fade in again. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
This reverts commit 509a53f. With the entry animation off, the first click on a chart was lost on the playground's metric views page (only a second click selected the bar), failing its integration test. Frozen part-drawn charts only stay frozen while the browser keeps animation frames paused (a background or occluded window); they finish when frames resume. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
….json A block with data-src="mock#<key>" takes mock[<key>] from drafts/mock.json, served at /design/drafts/mock.json (also to the builder origins) and linked from /design/__status as `mock`. An array becomes the block's data (rows for a DataTable), an object is merged into its props; inline props win and the block may hold no JSON. The page fetches the file once; until it's there and parses, the blocks show their skeleton and the page asks again every second (errors after 30 s). A missing key fails just that block. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
…rrors
- data-src="mock#<key>" looks the key up in mock.json's "datasets" object
first, then at the top level: the drafts skill writes
{ mock, datasets: { <name>: rows } }, so every block failed to find its key.
- The fade-in is a CSS animation instead of a class set on an animation
frame. Frames don't run in a background tab or hidden frame, so blocks
(and "Couldn't render" boxes) stayed invisible there.
- /design/__status reports a draft's errors as null with checked: false
until a page has rendered its current version and handled every block,
instead of [] (which read as "no errors", e.g. right after a restart).
Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
The hydrator's reset, error and checked reports were independent fetch POSTs, so the status endpoint could get them out of order: a late reset wiped `checked` and the errors, and an early `checked` briefly showed errors: []. Each report now starts once the one before it has finished. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
For apps that skip /design (no data), the builder loads the app's / in a hidden frame and reveals it on appkit:app-ready. The app-ready script's last wait was two animation frames, which never run in a display:none frame, so the signal never came. On the app's pages it now waits for two frames or 100 ms, whichever comes first. /design keeps its two-frame wait. The draft-watcher test now writes again until the watcher is live: macOS's file events can miss writes made just after a watch starts. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
…ILDER_ORIGIN A scaffolded app calls design() with no options, so no builder origin was set and the plugin never added the app-ready script: a builder waiting for appkit:app-ready on / (apps that skip /design) waited forever. Without a builderOrigin option, design() now reads APPKIT_DESIGN_BUILDER_ORIGIN (one origin, or several separated by commas), which the builder's runtime sets. It is checked like the option; an explicit builderOrigin wins. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
…n it arrives The drafts can be written before drafts/mock.json. The hydrator gave up after 30 tries, took a missing key as final, and never fetched the file again, so draft charts and tables stayed empty. Now: - while mock.json is missing or doesn't parse, data-src blocks wait as skeletons and the page asks again every second, with no limit (after 30 s the skeleton says "Waiting for drafts/mock.json…"); - the dev server tells open drafts when mock.json is written (appkit:mock-changed), so they fetch it at once; - a new mock.json renders again, in place, each block whose data changed, and the status endpoint gets the page's errors again from the start; - a key a loaded mock.json lacks shows an error in that block, and the page keeps checking, so it renders once the key is added. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
…nd for the app, hidden or not
A builder keeps its preview hidden, and /design waited for two painted
frames, which a hidden frame never gets: `ready` never came and the agent
nudged the preview with resizes and reloads. Readiness is now based on
render and mount, never on paint or pixels, for any kind of app:
- every page's settle ends with two frames or 100 ms without them;
- each design page reports to /design/__status: `pages[]` gets `rendered`
and `errors` (its render error, uncaught errors, unhandled rejections,
Vite errors, with messages), null until a browser loaded that version;
- the app's own pages report too (the script is now always added in dev):
`app` = { entry, compiled (server-side, from index.html's entry module),
compileError, path, rendered (something mounted in #root), template,
errors };
- reports are sent one at a time, in order.
Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Reported errors were only cleared by a full page load (or an edit to the design page's own file), so an error fixed by a hot update stayed listed and the documented `errors.length === 0` check kept failing. - On vite:afterUpdate, design pages and the app's pages reset their report before settling again; what's still wrong reports again. - A design page's error boundary that caught an error is retried after Fast Refresh applies the edit (it re-renders only the edited modules), so a fix in an imported component renders the page again. - The app's reports are kept per path, so two tabs on different paths don't reset each other; `app` shows the path reported last. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
A draft's colors came from the theme stylesheet it links, so until that loaded the page painted with the browser's default white, also in dark mode. The first bytes of a streamed draft now carry the app's theme inline (light and dark tokens, color-scheme, the page background), so it is dark from its first paint. Block mounting was already incremental (measured in Chrome: each block rendered 15-35 ms after its JSON arrived, document still loading); the injected hydrator is an async module and holds nothing back. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
appkit design tsx-drafts writes a shared client/src/design/mock.ts and 3 appkit-ui pages at /design/<name>-a|b|c (KIT-37's writer: one cached system prompt, mock export list streamed first, tsc + up to 2 fix rounds, a page lands in pages/ only once it compiles). /design/__status reports each under tsx: writing, type-checking, rendering, ready or failed. appkit design lock-in keeps one as /design (or the home page with --home) and deletes the others. HTML drafts are unchanged. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
…es them Drop the appkit design tsx-drafts and lock-in commands and their prompt files: App Builder owns prompting, mock data, type-check and lock-in. /design/__status now reports per page compiled / compileError (built server-side) and a state (compile-error, rendering, ready, failed) from the plugin's own knowledge instead of a writer's status.json. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
The design plugin watches client/src/design/.staging/<name>.tsx (and .staging/mock.ts) as a builder appends a draft's source to it, closes the partial source at the last line that parses (open JSX, brackets, template literals; undeclared components stubbed, missing mock values stubbed) and hot-updates src/design/pages/<name>.tsx with it, so Fast Refresh swaps it in place. /design/__stream/<name> renders it and keeps the last good frame when a version throws. Once the finished file is written there it loads from disk and is remounted, ending identical to /design/<name>. apps/tsx-stream-spike replays writer streams recorded with KIT-37's writer (taxi, Tetris, onboarding form) through the staging files at their real timing, 3 drafts side by side, and measures them. Spike only (KIT-40). Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
…etons appkit-ui (react/beta) gets DesignPage, the shell every /design page renders through (streamed, finished, locked in): the app's theme with dark mode from the first paint (?theme= or the system setting), and an error boundary that keeps the last good frame on screen and holds readiness back (useDesignReady). The page entry and the stream host both use it instead of their own boundary and snapshot code. DraftPlaceholder (chart, table, card, generic skeleton) stands in for components a streamed draft uses before it defines them; mock values not written yet are a value that can't throw. Fixes from review: a deleted finished file no longer crashes the dev server (watcher handlers are caught), generic arrows (<K extends X>(...)) no longer read as JSX (this kept the form drafts from rendering), a finished file nothing imports yet doesn't reload every page, and the replay reset stops the writers of a replay still running. APPKIT_DESIGN_STREAM_MODE=boundary measures component-boundary updates; scripts/bound.ts gives the earliest paint any renderer could reach from each recording. The spike app pins the repo's React so the root test setup keeps one copy. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
The spike app inherited react-router 7 from KIT-37's app without using it. Having it in the workspace made the design plugin's router test find a react-router 7 for a fixture app without one, failing Unit Tests in CI. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
…moved The decision is TSX streaming only, so what only HTML drafts needed goes: - the hydrator (plugins/design/drafts.ts): data-appkit blocks and data-src="mock#key"; - /design/drafts/<name> and drafts/mock.json serving, the drafts/ watcher and its appkit:draft-changed / appkit:mock-changed events, the inline theme for streamed HTML (DesignPage applies the theme before first paint); - /design/drafts/theme.css, /design/drafts/__hydrator.js and /design/__data-appkit.schema.json, and drafts, blockSchema, theme, mock and hydrator in /design/__status; - appkit-ui's design/components.schema.json export and its generator (App Builder's TSX writer reads its own schema from its skill); - the spike app apps/tsx-stream-spike, and its lockfile changes; - the HTML drafts docs. "drafts" is no longer a reserved design page name. Kept: the plugin core, /design, /design/<name>, /design/__stream/<name>, the .staging watcher and closeOpen, DesignPage, DraftPlaceholder, useDesignReady, readiness and app reports in /design/__status, the chart fixes and the template design feature. The status tests that aren't about HTML drafts move to status.test.ts. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
The top-level compiled/compileError come from the index entry of pages, which already builds it, instead of a second compile of the same import graph per request. indexVersion, a one-use wrapper, is inlined. Same JSON. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
…ng facts
No code change. Multi-line comments are cut to one short line (JSDoc
contracts kept, tightened), rationale repeated in several places is kept
in one (chart default height, the builder-origin format), and stale
wording ("after first paint", "only with a builder origin") is fixed.
Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
The /design/__stream host no longer posts appkit:stream-frame messages, and the APPKIT_DESIGN_STREAM_MODE=boundary switch is gone, with its test. Both only served the KIT-40 spike's measurements (its replay app is already removed); nothing in App Builder reads or sets them. Streaming itself is unchanged. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
The chart data and height props' JSDoc changed; the generated pages now match. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
025a25f to
8e230d4
Compare
Adds a dev-only
design()plugin (beta) for building an app's UI as design pages before it's wired to data, and an emptyui-onlyapp template (server + design) for quick PoCs. This is the single design-plugin PR: it includes the TSX drafts work from #707 and #708 (KIT-38, KIT-40), which this replaces. HTML drafts are not part of it (the decision is TSX streaming only).What it does
/designand/design/<name>renderclient/src/design/index.tsxandclient/src/design/pages/<name>.tsxat full size, with the app's styles and hot reload. Other paths under/designreturn 404, and the plugin answers 404 in production.react-router7 (the template ships it), pages share a router with basename/design. Each page is imported on its own, so an unfinished page breaks only its own URL.TSX drafts, streamed while they're written.
client/src/design/.staging/<name>.tsx(and the shared mock's to.staging/mock.ts), then writes the finished, type-checked file topages/<name>.tsx./design/__stream/<name>shows the draft while it streams. The dev server keeps the latest renderable version of the staging file under the page's real module:closeOpencloses whatever is open at the cut (JSX, brackets, template literals), and components not written yet are stubbed.DraftPlaceholderskeleton.DesignPage(@databricks/appkit-ui/react/beta): every design page renders through it. It applies the app's theme before the first paint (dark included,?theme=override). Its error boundary keeps the last good frame on screen instead of a broken one.Readiness, for any kind of app, from a hidden preview.
GET /design/__statusreports:ready,compiled(server-side import-graph build, no browser) andwaitingFor;pages[]:compiled,rendered,errorsandstate;app:entry,compiled,path,rendered,templateanderrors.Errors cover render errors, uncaught errors, unhandled rejections and Vite errors, with their messages. They are
nulluntil a browser has loaded the page, and a hot update clears what it fixed. Nothing waits for a visible or painted frame (two frames, or 100 ms without them).Pages post
appkit:design-readyand the app's pagesappkit:app-readyto the configuredbuilderOrigin. That's a bare origin, never"*"; it defaults to theAPPKIT_DESIGN_BUILDER_ORIGINenvironment variable, so a scaffoldeddesign()needs no options.useDesignReady(false)holds readiness back for content the page can't detect on its own.Charts (appkit-ui) fill their container's height by default (at least 160px), or take an exact
height.Template: the
ui-onlyentry (featuredesign), a placeholderclient/src/design/index.tsx, and the.appkit/gitignore.Plugin hook: plugins can add Vite plugins to the dev server through an optional
vitePlugins()method.Selection is out of scope here (the human's decision): no element picker or
.appkit/design-selection.json. App Builder's own inspector selects elements through the dev server'sdata-source="file:line:col"attributes.How I checked it
closeOpenandrenderablePartial, the staging watcher,DesignPage, and chart sizing.display: noneiframes,/designpages and the app reportedrenderedand their errors..staging/<name>.tsxshowed up in the page as they were written.pnpm build,pnpm docs:build,pnpm -r typecheck,pnpm check, knip andpnpm test(324 files) pass.Not done
ui-onlywasn't generated withdatabricks apps init(needs the CLI and network); only the template files changed.Task: KIT-1 (app-kit/1)
This pull request and its description were written by Isaac.