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 94f63a1..6692202 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. @@ -47,8 +66,9 @@ 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 | ### App Identity @@ -189,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 57b3cce..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 @@ -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/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") 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; }