From c3592590b1e6f1158cc49fc1d61ec0602aba5b00 Mon Sep 17 00:00:00 2001 From: Andrei Kirkouski Date: Wed, 22 Apr 2026 10:44:54 +0200 Subject: [PATCH 1/2] facade: add fe_mode compat/managed for managed-layout.js entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New `fe_mode` requirement (default: `compat`) picks which Web Host entry file the facade loads: - `compat` — module.js, full Wippy chrome (unchanged behavior) - `managed` — managed-layout.js, declarative multi-panel host driven by hostConfig.layout (HostLayoutDeclaration) Both entries expose the same `window.initWippyApp(config)` symbol, so index.html does not branch on mode beyond the module file path. Unknown values of fe_mode normalize to `compat`. Requires Web Host >= 1.0.24. --- src/facade/README.md | 24 ++++++++++++++++++++++-- src/facade/_index.yaml | 13 +++++++++++++ src/facade/config_handler.lua | 13 +++++++++++++ src/facade/public/index.html | 11 ++++++++--- 4 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/facade/README.md b/src/facade/README.md index 94f63a1..c1968f5 100644 --- a/src/facade/README.md +++ b/src/facade/README.md @@ -7,10 +7,29 @@ Portable iframe facade for the Wippy frontend. Serves a thin HTML shell that loa 1. `index.html` is served as a static file via `http.static` 2. On load, it fetches `GET /api/public/facade/config` to get runtime configuration 3. Checks `localStorage` for an auth token, redirects to `login_path` if missing -4. Loads the Web Host bundle from CDN (`facade_url + '/module.js'`) -5. Calls `initWippyApp()` with the full AppConfig (wippy-context-2.0 format) +4. Loads the Web Host bundle from CDN — picks the module file based on `fe_mode`: + - `compat` (default) → `module.js` — full Wippy host chrome + - `managed` → `managed-layout.js` — declarative multi-panel host driven by `hostConfig.layout` +5. Calls `window.initWippyApp(config)` — both entries expose the same symbol; the mounted shell is the only difference 6. Shows `` / `` during initialization (vendored from Wippy Web Host CDN) +## Modes + +| Mode | Entry loaded | Mounted shell | Use case | +|---|---|---|---| +| `compat` _(default)_ | `module.js` | Full Wippy chrome (sidebar + chat + pages + right panel) | Backwards-compatible — existing facades keep working unchanged | +| `managed` | `managed-layout.js` | Declarative multi-panel layout — no default chrome, every panel declared via `hostConfig.layout` | IDE-style apps, dashboards, Adobe-style multi-pane tools | + +Both entries expose the same `window.initWippyApp(config, rootContainer?)` signature — the parent integration code does not change between modes. Set via the `fe_mode` requirement; unknown values normalize to `compat`. + +### When to switch to `managed` mode + +- You want a multi-panel app with separator-drag resizing +- You want to embed a custom panel configuration driven by config (not by the standard sidebar/chat layout) +- You want breakpoint-responsive layouts (desktop vs mobile) + +Leave `fe_mode` at `compat` unless you have a specific reason to opt in — the managed shell omits every piece of default Wippy chrome (no sidebar, no chat wrapper, no right panel) and expects the declaration to provide equivalents. + ## Vendored CDN files `public/@wippy-fe/` contains files copied from the Wippy Web Host CDN. These are loaded before the CDN URL is known (pre-config-fetch), so they must be vendored locally. @@ -49,6 +68,7 @@ These fields are NOT configurable via requirements — they are computed at runt |---|---|---| | `fe_facade_url` | `https://web-host.wippy.ai/webcomponents-1.0.23` | CDN base URL for the Web Host frontend bundle | | `fe_entry_path` | `/iframe.html` | Iframe HTML entry point path (appended to `fe_facade_url`) | +| `fe_mode` | `compat` | `compat` (default — loads `module.js`) or `managed` (loads `managed-layout.js` for declarative multi-panel apps). See [Modes](#modes) above | ### App Identity diff --git a/src/facade/_index.yaml b/src/facade/_index.yaml index 57b3cce..8ce3a4c 100644 --- a/src/facade/_index.yaml +++ b/src/facade/_index.yaml @@ -44,6 +44,19 @@ entries: path: .default default: /iframe.html + - name: fe_mode + kind: ns.requirement + meta: + description: | + Frontend bundle mode. `compat` (default) loads module.js and renders + the standard Wippy host (sidebar + chat + pages + right panel). + `managed` loads managed-layout.js and renders a declarative + multi-panel host defined by hostConfig.layout — no default chrome. + targets: + - entry: wippy.facade:fe_mode + path: .default + default: compat + # App identity - name: app_title kind: ns.requirement diff --git a/src/facade/config_handler.lua b/src/facade/config_handler.lua index b9973cd..edfde68 100644 --- a/src/facade/config_handler.lua +++ b/src/facade/config_handler.lua @@ -83,6 +83,17 @@ local function handler() local facade_url = get_req("fe_facade_url") local entry_path = get_req("fe_entry_path") + local fe_mode = get_req("fe_mode") + + -- Normalize mode: anything other than "managed" falls back to compat. + if fe_mode ~= "managed" then + fe_mode = "compat" + end + + -- Module filename loaded by index.html. `compat` keeps the historical + -- module.js (full Wippy host chrome); `managed` loads managed-layout.js + -- (declarative multi-panel host via hostConfig.layout). + local module_file = fe_mode == "managed" and "/managed-layout.js" or "/module.js" local iframe_origin: string? = "" if facade_url ~= "" then @@ -164,6 +175,8 @@ local function handler() iframe_origin = iframe_origin, iframe_url = iframe_url, login_path = get_req("login_path"), + mode = fe_mode, + module_file = module_file, env = { APP_API_URL = api_url, diff --git a/src/facade/public/index.html b/src/facade/public/index.html index eb09f9e..4c72793 100644 --- a/src/facade/public/index.html +++ b/src/facade/public/index.html @@ -80,11 +80,16 @@ console.warn('Failed to load import map:', e); } - // Now safe to load modules — import map is already in the DOM + // Now safe to load modules — import map is already in the DOM. + // `cfg.module_file` is "/module.js" (compat) or "/managed-layout.js" + // (managed). Both entries set the same `window.initWippyApp` symbol; + // the rendered shell is the only difference. Backend normalizes + // unknown modes to "compat", so the fallback below is purely defensive. + var moduleFile = cfg.module_file || '/module.js'; try { - await import(cfg.facade_url + '/module.js'); + await import(cfg.facade_url + moduleFile); } catch (importErr) { - showError('Failed to load frontend bundle', 'Could not load ' + cfg.facade_url + '/module.js — ' + importErr.message); + showError('Failed to load frontend bundle', 'Could not load ' + cfg.facade_url + moduleFile + ' — ' + importErr.message); throw importErr; } From 3901c9fc42fa03117921ed743935a2282f5b2f3c Mon Sep 17 00:00:00 2001 From: Andrei Kirkouski Date: Mon, 27 Apr 2026 12:10:28 +0200 Subject: [PATCH 2/2] Bump facade CDN to 1.0.25 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Skipped 1.0.24 — last reference here was 1.0.23. Updates the fe_facade_url default in _index.yaml plus the Makefile WEB_HOST_CDN, README example, and config_handler_test fixture. Re-ran `make sync` against the new URL — loading.js content is unchanged across 1.0.23 → 1.0.25 (the loading component didn't move this window), so no vendored-file delta to commit. Verified: wippy lint clean for src/facade and src/facade/test (0 issues, 2 entries each). Test runner blocked by a pre-existing Windows-symlink issue (src/facade/test/public stored as text "../public" because Git on Windows uses core.symlinks=false). Unrelated to this bump. --- src/facade/Makefile | 2 +- src/facade/README.md | 6 +++--- src/facade/_index.yaml | 2 +- src/facade/config_handler_test.lua | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/facade/Makefile b/src/facade/Makefile index 8280fac..b2fb2e1 100644 --- a/src/facade/Makefile +++ b/src/facade/Makefile @@ -6,7 +6,7 @@ # Run `make sync` after every Wippy Web Host version bump to pull fresh copies. # Web Host CDN base — update version when Wippy Web Host releases -WEB_HOST_CDN = https://web-host.wippy.ai/webcomponents-1.0.23 +WEB_HOST_CDN = https://web-host.wippy.ai/webcomponents-1.0.25 # Files to sync from CDN into public/@wippy-fe/ CDN_FILES = loading.js diff --git a/src/facade/README.md b/src/facade/README.md index c1968f5..6692202 100644 --- a/src/facade/README.md +++ b/src/facade/README.md @@ -66,7 +66,7 @@ These fields are NOT configurable via requirements — they are computed at runt | Requirement | Default | Description | |---|---|---| -| `fe_facade_url` | `https://web-host.wippy.ai/webcomponents-1.0.23` | CDN base URL for the Web Host frontend bundle | +| `fe_facade_url` | `https://web-host.wippy.ai/webcomponents-1.0.25` | CDN base URL for the Web Host frontend bundle | | `fe_entry_path` | `/iframe.html` | Iframe HTML entry point path (appended to `fe_facade_url`) | | `fe_mode` | `compat` | `compat` (default — loads `module.js`) or `managed` (loads `managed-layout.js` for declarative multi-panel apps). See [Modes](#modes) above | @@ -209,9 +209,9 @@ Only override what differs from defaults. ```json { - "facade_url": "https://web-host.wippy.ai/webcomponents-1.0.23", + "facade_url": "https://web-host.wippy.ai/webcomponents-1.0.25", "iframe_origin": "https://web-host.wippy.ai", - "iframe_url": "https://web-host.wippy.ai/webcomponents-1.0.23/iframe.html?waitForCustomConfig", + "iframe_url": "https://web-host.wippy.ai/webcomponents-1.0.25/iframe.html?waitForCustomConfig", "login_path": "/login.html", "env": { "APP_API_URL": "http://localhost:8085", diff --git a/src/facade/_index.yaml b/src/facade/_index.yaml index 8ce3a4c..8851c78 100644 --- a/src/facade/_index.yaml +++ b/src/facade/_index.yaml @@ -33,7 +33,7 @@ entries: targets: - entry: wippy.facade:fe_facade_url path: .default - default: https://web-host.wippy.ai/webcomponents-1.0.23 + default: https://web-host.wippy.ai/webcomponents-1.0.25 - name: fe_entry_path kind: ns.requirement diff --git a/src/facade/config_handler_test.lua b/src/facade/config_handler_test.lua index e719b6c..52ef495 100644 --- a/src/facade/config_handler_test.lua +++ b/src/facade/config_handler_test.lua @@ -112,7 +112,7 @@ local function define_tests() end) test.it("extracts iframe origin from facade URL", function() - local facade_url = "https://web-host.wippy.ai/webcomponents-1.0.23" + local facade_url = "https://web-host.wippy.ai/webcomponents-1.0.25" local origin = facade_url:match("^(https?://[^/]+)") test.eq(origin, "https://web-host.wippy.ai")