Observable Framework Integration Plan

Goal Description

Enable hosting and rendering of Observable Framework data apps on DataHub-next. Users will push their built Observable apps (static files) to a GitHub repo (or branch), and DataHub will ingest and serve them.

User Review Required

> Build Process: We assume the user creates a build beforehand (e.g., via GitHub Actions or locally) and commits the dist output to a branch (e.g., gh-pages or build). We will ingest the static files from that branch.

Iframe Rendering: Observable apps will be rendered inside an <iframe> pointing to the R2 storage URL. This ensures style isolation and correct relative path resolution for assets.

Proposed Changes

Data Model & Configuration

[MODIFY] schema.prisma

  • Add SiteType enum: DATAPACKAGE (default), OBSERVABLE.
  • Add type field to Site model.

Ingestion Logic

[MODIFY] inngest/functions.ts

  • In syncSite:
    • Check for observable type in config.json.
    • If siteConfig.type === 'observable', update the Site record's type in DB.
    • Ensure all supported assets (html, js, css) are uploaded.
    • Skip Markdown/Datapackage metadata computation for Observable apps.

Frontend Rendering

[NEW] components/ObservablePage.tsx

  • Server Component.
  • Props: site: SiteWithPublication, slug: string.
  • Implements the Iframe IFrame logic.

[NEW] components/DatasetPage.tsx

  • Server Component (async).
  • Props: site: SiteWithPublication, slug: string.
  • Encapsulates fetching of siteConfig, pageMetadata, pageContent, sitePermalinks.
  • Renders MDX component.

[MODIFY] app/[user]/[project]/...slug/page.tsx

  • Fetch site.
  • Check site.type.
  • Return <ObservablePage /> or <DatasetPage />.

UI Improvements

[NEW] components/site-renderers/observable-header.tsx

  • Component to display site metadata (title, description, author) and Like button.
  • Props: site: SiteWithPublication, config: SiteConfig | null.

[MODIFY] components/site-renderers/ObservablePage.tsx

  • Convert to async component.
  • Fetch siteConfig using api.site.getConfig.
  • Render <ObservableHeader /> with fetched config.

Verification Plan

Manual Verification

  1. Setup:
    • Use existing observable-demo site (seeded).
  2. Rendering:
    • Navigate to /[user]/[project] -> Should hit ObservablePage.
    • Navigate to a normal dataset page -> Should hit DatasetPage.