8000 feat: embedded web UI and JupyterLab (1.7.0) by dmux · Pull Request #4 · dmux/minilake · GitHub
[go: up one dir, main page]

Skip to content

feat: embedded web UI and JupyterLab (1.7.0) - #4

Merged
dmux merged 9 commits into
mainfrom
feature/athena-ui
Aug 19, 2026
Merged

dmux merged 9 commits into
mainfrom
feature/athena-ui

Conversation

@dmux
@dmux dmux commented Aug 19, 2026
Copy link
Copy Markdown
Owner

Gives minilake a face: an Athena-style SQL workspace served at /ui, and a real
JupyterLab running inside the image. Releases as 1.7.0 (see CHANGELOG.md).

Embedded JupyterLab

A real notebook server running as a child process of minilake, reverse-proxied at
/jupyter and framed by the UI at /ui/notebooks. On by default; MINILAKE_NOTEBOOK=0
disables it.

Serving it same-origin is load-bearing, not cosmetic. jupyter-server sends
Content-Security-Policy: frame-ancestors 'self', so a notebook server on its own port
cannot be framed by the UI at all — the browser blocks it. Proxying it under /jupyter
satisfies 'self' without weakening the policy, and keeps minilake's one-port,
one-origin property.

  • The proxy relays WebSockets, so kernels connect, execute and stream output.
    Without that the Lab UI loads and then hangs at "Connecting to kernel".
  • Jupyter binds 127.0.0.1 and is reachable only through the proxy, so it is exposed
    exactly as far as minilake is and no further.
  • No pyspark in the image. Notebooks reach real Spark through the Jobs API, in the
    same sibling containers a job already uses. The bundled quickstart carries the helper
    that stages a script, runs it and returns its output.
  • New optional extra minilake[notebook], bundled in the image. Image goes from
    1.52 GB to 1.82 GB — the Jupyter dependency tree, not Spark.

Web UI

The UI previously covered ~31 of ~109 routes, with six services having no surface at
all. This closes most of that gap:

  • Unity Catalog was read-only; now creates and drops catalogs, schemas, MANAGED
    tables and volumes. Drops cascade on the server and the confirmation says so.
  • Jobs gains create, edit and delete plus a per-task run detail view. The editor
    offers only the task types minilake actually executes (notebook_task,
    spark_python_task, sql_task.file) — the rest run SKIPPED, and a form offering
    them would promise work that never happens.
  • New pages: workspace browser over /Workspace, clusters, secrets, notebooks.
  • Identity in Settings; delete confirmation on warehouses, which was the one
    destructive action without it.

Also ships the Query History and Saved Queries APIs that back the corresponding
views.

Bug fix worth calling out

POST /_minilake/reset?full=true accepted full and ignored it — the UI's "Full
reset" and "Reset state" buttons did the same thing. A full reset now deletes the on-disk
data directories (per-catalog DuckDB databases, volume directories, warehouse files) that
no service reset() touches. Covered by two tests that assert the difference.

Verification

  • 264 tests pass via the Docker stack, including 4 new ones for the notebook proxy
    and 2 for the reset distinction.
  • The bundled quickstart was executed end to end with nbconvert --execute: Spark wrote
    a Delta table, minilake SQL read the same files, Spark read them back.
  • Inside the built image: kernel created, code executed over the proxied WebSocket, Lab
    assets streaming, /ui/notebooks serving.
  • UI lint, typecheck, vitest and static export all clean.

Deliberately out of scope

  • permissions and dbfs have no UI. Permissions are stored but never enforced
    (single-user allow-all), so a screen would imply access control that does not exist.
    DBFS shares its on-disk root with the Files API, which the Files page already browses.
  • Job editing covers a linear task chain, not arbitrary DAGs — those still need the
    SDK.
  • The separate --profile notebook container is left untouched. It offers something the
    builtin does not (a local SparkSession in the kernel), so it is not a duplicate —
    but it is worth deciding whether to keep it.

Note

--allow-root is passed to jupyter-server because the image runs as root, where it
otherwise refuses to start. The only symptom was a 503 from the proxy, with nothing
pointing at the cause; it is commented in the code.

dmux added 8 commits August 13, 2026 00:31
Adds the Athena-style SQL workspace at /ui and a real JupyterLab running
inside minilake, reverse-proxied at /jupyter and framed by the UI.

Serving Jupyter same-origin is load-bearing rather than cosmetic:
jupyter-server sends `Content-Security-Policy: frame-ancestors 'self'`,
so a notebook server on its own port cannot be framed by the UI. The
proxy relays WebSockets so kernels work, and binds Jupyter to loopback
so it is exposed exactly as far as minilake is. No pyspark ships in the
image — notebooks reach Spark through the Jobs API, in the same sibling
containers a job already uses.

Also widens UI coverage of the API (Unity Catalog mutations, job
create/edit/delete with per-task run detail, workspace browser, clusters,
secrets), adds the Query History and Saved Queries APIs, and makes
`POST /_minilake/reset?full=true` honour `full` — it was accepted and
ignored, so the UI's two reset buttons did the same thing.

See CHANGELOG.md for the full list.
The release adds functionality — the embedded web UI and JupyterLab, the
Query History and Saved Queries APIs, and the optional `notebook` extra —
so semver calls for a minor, not a patch.
@dmux dmux self-assigned this Aug 19, 2026
@dmux dmux added the enhancement New feature or request label Aug 19, 2026
The root .gitignore carried an unanchored `lib/` among the Python build
artifacts, which also matched `ui/src/lib/` — so the UI's entire API
client and helpers (22 files) were never committed.

Local builds passed because the files were on disk; CI built from a clean
checkout and failed with `Module not found: Can't resolve '@/lib/...'`
across every page.

Anchors the Python artifact patterns to the repo root, so `/lib/` no
longer reaches into subdirectories, and adds the missing files. `build/`,
`dist/` and `var/` had the same latent trap.
@dmux
dmux merged commit 3c8dbd7 into main Aug 19, 2026
3 checks passed
@dmux
dmux deleted the feature/athena-ui branch September 30, 2026 01:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0