feat(ui): mount skychat/logs in WinBox via a CDK-portal bridge (no self-iframe) - #3720
Merged
Merged
Conversation
…lf-iframe) Steps 3 + 5 of the GUI embedding standardization (docs/design/gui-embedding-standardization.md): the wasm desktop's ☰ Chat and ☰ Logs WinBox windows iframed the SPA back into itself (/#/nodes/<pk>/chat?embed=1, .../logs?embed=1), loading a SECOND Angular runtime just to show one component. Replace that with an in-context mount of the real Angular component. - New NgBridgeService exposes window.SkywireNg.mountComponent(el, name, opts): it creates the component via a CDK DomPortalOutlet in the app's root injector (same services/theme/session), sets its inputs, and returns a dispose handle. AppComponent installs it at startup. Registry: skychat, logs. - SkychatComponent / LogsComponent gain an optional embeddedNodeKey input (+ embeddedPeer for chat). When set (portal mount, no NodeComponent parent route), they synthesize the node from the key — both only read node.localPk — instead of subscribing to NodeComponent.currentNode. Routed behaviour is unchanged. - browse.js chat/logs windows now prefer window.SkywireNg.mountComponent and fall back to the ?embed=1 iframe if the bridge is absent (non-Angular host). Peer retarget re-mounts skychat; the window disposes the component on close. One Angular runtime, shared context, no self-iframe. Validated live on a fresh hv serve --harness: the bridge mounts the real app-skychat, and clicking ☰ Logs opens a WinBox hosting app-logs (no iframe), 0 console errors. Rebuilt the embedded UI bundle.
0pcom
added a commit
that referenced
this pull request
Aug 5, 2026
…eb stays iframed (#3721) The skychat/logs ?embed=1 WinBox windows now mount the real Angular component via the window.SkywireNg CDK-portal bridge (#3720) — the earlier "deferred" finding was resolved once it was clear both components only read node.localPk and inject no routing deps. Also record the decision that skycoin-web stays iframed (separate upstream-owned app + wallet custody boundary), superseding the old migration-list line about converging it into the SPA.
This was referenced Aug 5, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Steps 3 + 5 of the GUI embedding standardization (
docs/design/gui-embedding-standardization.md): the wasm desktop's ☰ Chat and ☰ Logs WinBox windows iframed the SPA back into itself (/#/nodes/<pk>/chat?embed=1,.../logs?embed=1) — loading a second Angular runtime just to show one component. This replaces that with an in-context mount of the real Angular component.Completes the standardization series (#3715 SharedModule, #3716 bundle-mount host, #3717 VPN lazy).
How the route-coupling was solved
The doc flagged this as the hard part:
SkychatComponent/LogsComponentget their visor fromNodeComponent.currentNode(a static observable set by the parentNodeComponentroute), which a bare portal mount wouldn't have. The key finding: both components only readnode.localPk, and neither injectsActivatedRoute/Router/NodeComponent. So decoupling is clean.NgBridgeServiceexposeswindow.SkywireNg.mountComponent(el, name, opts): creates the component via a CDKDomPortalOutletin the app's root injector (same services/theme/session), sets its inputs before first CD, returns adispose()handle.AppComponentinstalls it at startup. Registry:skychat,logs.SkychatComponent/LogsComponentgain an optionalembeddedNodeKeyinput (+embeddedPeerfor chat). When set (portal mount), they synthesize the node from the key instead of subscribing toNodeComponent.currentNode. Routed behaviour is 100% unchanged (input unset → old path).browse.jschat/logs windows preferwindow.SkywireNg.mountComponentand fall back to the?embed=1iframe if the bridge is absent (keeps browse.js robust in any host). Peer retarget re-mounts skychat; the window disposes the component on close.Net: one Angular runtime, shared context, no self-iframe — while keeping the single 1500-line Angular skychat component (no dual-surface divergence).
Verification (live, over CDP on a persistent Brave tab)
Against a fresh
hv serve --tls --harness:ng lint/ng build/go build .— clean.window.SkywireNg.mountComponent(div, 'skychat', {nodeKey})rendered the realapp-skychat(full chat UI, 10.6 KB DOM) in the app's context — 0 console errors.app-logswith no iframe (hostsAppLogs: true, hostsIframe: false) — 0 console errors.