From c20f6a1b6807fe3ca7fe4ad9adc75488b2210ccd Mon Sep 17 00:00:00 2001 From: stroblme Date: Sun, 30 Aug 2026 18:48:52 +0200 Subject: [PATCH] Add a website widget, so a page nobody modelled as a message can hang on a wall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A tile that draws whatever an address serves: no binding, no flow, just an iframe. Only http(s) loads — a `javascript:` src would run in the app's own origin, and a dashboard is a document several people can edit. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01KocbsBHWme1kfCHVhrgBnw --- backend/fluksio/flow/dashboards.py | 5 ++- frontend/src/client/schemas.gen.ts | 2 +- frontend/src/client/types.gen.ts | 4 +- .../src/components/Dashboard/embed.check.ts | 39 ++++++++++++++++ frontend/src/components/Dashboard/panels.tsx | 18 +++++++- frontend/src/components/Dashboard/widgets.tsx | 45 ++++++++++++++++++- 6 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 frontend/src/components/Dashboard/embed.check.ts diff --git a/backend/fluksio/flow/dashboards.py b/backend/fluksio/flow/dashboards.py index 3bafb06..ee79451 100644 --- a/backend/fluksio/flow/dashboards.py +++ b/backend/fluksio/flow/dashboards.py @@ -65,6 +65,7 @@ WidgetType = Literal[ "clock", "media", "player", + "embed", # Input "button", "switch", @@ -113,8 +114,8 @@ WIDGET_DTYPES: dict[str, set[str]] = { # duration in one reading, because they are one thing and a player drawn # from five separate messages would redraw itself five times. "player": {"record"}, - # An icon maps weather strings, bool hints and numbers alike, and a clock - # binds nothing at all, so neither has a row to be held to. + # An icon maps weather strings, bool hints and numbers alike; a clock reads + # the wall and an embed a page of its own, so none has a row to be held to. } diff --git a/frontend/src/client/schemas.gen.ts b/frontend/src/client/schemas.gen.ts index 9505d17..19cbf96 100644 --- a/frontend/src/client/schemas.gen.ts +++ b/frontend/src/client/schemas.gen.ts @@ -3762,7 +3762,7 @@ export const WidgetDefSchema = { }, type: { type: 'string', - enum: ['stat', 'gauge', 'chart', 'markdown', 'agenda', 'notification', 'bar', 'icon', 'forecast', 'clock', 'media', 'player', 'button', 'switch', 'slider', 'input', 'dropdown', 'color'], + enum: ['stat', 'gauge', 'chart', 'markdown', 'agenda', 'notification', 'bar', 'icon', 'forecast', 'clock', 'media', 'player', 'embed', 'button', 'switch', 'slider', 'input', 'dropdown', 'color'], title: 'Type' }, title: { diff --git a/frontend/src/client/types.gen.ts b/frontend/src/client/types.gen.ts index 05a85cd..6e0035e 100644 --- a/frontend/src/client/types.gen.ts +++ b/frontend/src/client/types.gen.ts @@ -1297,7 +1297,7 @@ export type WebPushKey = { */ export type WidgetDef = { id: string; - type: 'stat' | 'gauge' | 'chart' | 'markdown' | 'agenda' | 'notification' | 'bar' | 'icon' | 'forecast' | 'clock' | 'media' | 'player' | 'button' | 'switch' | 'slider' | 'input' | 'dropdown' | 'color'; + type: 'stat' | 'gauge' | 'chart' | 'markdown' | 'agenda' | 'notification' | 'bar' | 'icon' | 'forecast' | 'clock' | 'media' | 'player' | 'embed' | 'button' | 'switch' | 'slider' | 'input' | 'dropdown' | 'color'; title?: string; layout?: { [key: string]: Placement; @@ -1307,7 +1307,7 @@ export type WidgetDef = { }; }; -export type type = 'stat' | 'gauge' | 'chart' | 'markdown' | 'agenda' | 'notification' | 'bar' | 'icon' | 'forecast' | 'clock' | 'media' | 'player' | 'button' | 'switch' | 'slider' | 'input' | 'dropdown' | 'color'; +export type type = 'stat' | 'gauge' | 'chart' | 'markdown' | 'agenda' | 'notification' | 'bar' | 'icon' | 'forecast' | 'clock' | 'media' | 'player' | 'embed' | 'button' | 'switch' | 'slider' | 'input' | 'dropdown' | 'color'; export type WorkerInfo = { name: string; diff --git a/frontend/src/components/Dashboard/embed.check.ts b/frontend/src/components/Dashboard/embed.check.ts new file mode 100644 index 0000000..9621cbb --- /dev/null +++ b/frontend/src/components/Dashboard/embed.check.ts @@ -0,0 +1,39 @@ +/** + * Which addresses an embed widget will load, checked. + * + * ponytail: a script rather than a suite, as with the other `.check.ts` files: + * + * cd frontend && bun run src/components/Dashboard/embed.check.ts + * + * The guard is the point. An `