fix(ios): land Databricks workspaces on /omnigent and hide the workspace chrome - #4559
Merged
fanzeyi merged 1 commit intoAug 11, 2026
Merged
Conversation
fanzeyi
force-pushed
the
fanzeyi/ios-workspace-chrome-and-mount
branch
from
August 10, 2026 23:50
f87bd65 to
191da78
Compare
fanzeyi
force-pushed
the
fanzeyi/ios-workspace-chrome-and-mount
branch
from
August 11, 2026 00:06
191da78 to
02bd815
Compare
…ace chrome ## Related issue N/A — no tracking issue; requested directly. ## Summary - A workspace-hosted Omnigent on iOS was unusable in two ways: connecting with a bare workspace URL landed on the Databricks landing page instead of the app, and once on the app the workspace's top-nav bar was still painted over it — wasting vertical space and letting the user navigate into another workspace app with no way back. - Ports the desktop's chrome hide (`web/electron/src/workspace-chrome.js`) into a testable `WorkspaceChromeScript`, replacing the previous injection that was gated on `path.starts(with: "/ml/omnigents")` — a path gate skips auth-redirect landings and the `/omnigent` mount entirely. Keyed on the pinned origin, never on the path. - Mirrors the Android `/omnigent` bounce from omnigent-ai#4543 on iOS: domain-matched with no probe, `?o=<org>` and fragment preserved, one bounce per app-page load, wired into the three iOS equivalents of Android's callbacks — `decidePolicyFor` (link/redirect navs), `didCommit` (every committed load, incl. the login chain's POST hand-back) and KVO on `webView.url` (in-page `pushState`, which fires no navigation callback at all). - Root cause both of the above depended on: with `allowsInsecureHTTP` (debug only), a schemeless host was normalized to `http://`, so the app pinned `http://` while the server redirects to `https://`. Every pinned-origin comparison then failed silently — the chrome overlay, native bridge trust (`isTrustedBridgeMessage`, so the server switcher / Chat-Terminal bar / sidebar drag were dead), media-capture prompts, and load-success recording. A schemeless host now defaults to https unless it is loopback, mirroring the desktop's `LOCAL_HOSTS`, so the mismatch can't be created: release builds already reject `http://` outright and App Transport Security blocks it at the network layer. - Derives the pinned origin from the pinned URL instead of caching it in a second field, so the two can't drift, and re-arms the bare-root bounce budget when a new server is pinned. Drops `loadSucceeded`'s URL argument: its only consumer discarded it. ELI5: the app was told "the server is http://host", the server answered "actually I'm https://host", and every later "is this page still my server?" check compared the two strings, said no, and quietly skipped its work. ``` connect "dbc-x.cloud.databricks.com" │ ├─ before: http://dbc-x… → pinned http://dbc-x │ server 301 → https://… → page https://dbc-x │ pinned != page ─────────► chrome hide / bridge / recents SKIPPED │ └─ after: https://dbc-x… → pinned https://dbc-x (non-loopback ⇒ https) bare root ⇒ /omnigent → bounce once pinned == page ─────────► overlay covers the workspace bar ``` ## Test Plan - `cd web/ios && xcodebuild test -scheme Omnigent -destination 'platform=iOS Simulator,name=iPhone 17 Pro' -only-testing:OmnigentTests` → all tests pass. - New/updated unit tests: `WorkspaceChromeScriptTests` (CSS byte-identical to the desktop's `WORKSPACE_CHROME_HIDE_CSS`, the install-once guard, CSS embedded as an escaped literal); `WorkspaceMountURLTests` (bare roots on both workspace domains, query + fragment preserved, port and host-case, non-root paths left alone, `databricksapps.com` and a `databricks.com.evil.example` lookalike rejected, non-http schemes rejected); `ServerURLTests` (schemeless host → https even under the debug policy, loopback → http, explicit `http://` honoured). - Manual, iPhone 17 Pro simulator against a real Databricks workspace: a bare workspace URL lands on `/omnigent` and the workspace nav bar is gone. Confirmed during development with a temporary in-app probe (since removed) reporting `styleTag:true, position:"fixed", rect:{y:0,h:874}` — the embed root covers the viewport from y=0 — and independently by the maintainer on the same simulator. - `pre-commit run --files <touched files>` clean. ## Demo Before / after on the iPhone 17 Pro simulator against a workspace-hosted server: the Databricks top-nav bar (logo, workspace switcher, app switcher, avatar) is painted above the app before, and the app fills the viewport after. Screenshots attached below. ## Type of change - [ ] Bug fix - [ ] Feature - [x] UI / frontend change - [ ] Refactor / chore - [ ] Docs - [ ] Test / CI - [ ] Breaking change ## Test coverage - [x] Unit tests added / updated - [ ] Integration tests added / updated - [ ] E2E tests added / updated - [x] Manual verification completed - [ ] Existing tests cover this change - [ ] Not applicable ## Coverage notes The mount-URL rewriting, scheme defaulting and the injected script are unit-tested. The navigation wiring is not: `OmnigentWebView.Coordinator` needs a live `WKWebView` plus a SwiftUI context to construct, so the callbacks and the overlay were verified on the simulator against a real workspace instead. ## Changelog Connecting the iOS app to a Databricks workspace now opens Omnigent directly and hides the workspace navigation bar Signed-off-by: Zeyi (Rice) Fan <zeyi.f@databricks.com>
fanzeyi
force-pushed
the
fanzeyi/ios-workspace-chrome-and-mount
branch
from
August 11, 2026 00:14
02bd815 to
045910c
Compare
fanzeyi
enabled auto-merge (squash)
August 11, 2026 00:17
Contributor
|
🏷️ Doc impact: iOS/Electron shell changes to workspace-root bounce handling, chrome-hiding CSS refactor, and scheme defaults are internal client behavior with no change to documented setup, configuration, or user-facing surfaces. Auto-classified on merge. Set the label manually before merging to override. · run |
13 tasks
github-actions Bot
pushed a commit
that referenced
this pull request
Aug 11, 2026
…e viewport (#4568) ## Related issue N/A — reported directly after #4559. ## Summary - On a Databricks workspace-hosted server, the iOS app renders its top controls under the status bar / Dynamic Island: the sidebar toggle sits level with the clock and the chat header is flush at y=0. Self-hosted (OSS) servers are fine, and Android is fine. - All of the shell's iOS insets derive from `env(safe-area-inset-*)`, which is non-zero only when the document's meta viewport carries `viewport-fit=cover`. No document ships it, so the bridge script installs it at `.atDocumentStart`. - The workspace host then reassigns the whole `content` attribute once its app mounts (`useMobileViewport`, called for the Omnigent route), writing `width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no` — no `viewport-fit`. `env()` collapses to 0, so `--omnigent-safe-top` and `--omnigent-inset-top` become 0 and every rule padding for the notch pads by nothing. - Re-asserts the token with a `MutationObserver` on `document.head` instead of trusting the one-shot injection: the host rewrites again on its own re-renders, and it may replace the tag rather than edit it. The observer only writes when `viewport-fit=cover` is absent, so the shell's own write settles instead of looping. - Latent until now — the workspace nav bar used to occupy the top of the screen and pushed the app below the unsafe area. #4559 promotes the app to a full-viewport overlay to hide that bar, which is what exposes the missing inset. - Android is unaffected and untouched: it injects measured insets as `--omnigent-android-safe-area-*` (`MainActivity.kt`) and never depends on `env()`. Only iOS trusts the page's viewport metadata. ``` documentStart : … user-scalable=no, viewport-fit=cover ← shell installs it host mounts : … user-scalable=no ← token dropped env(safe-area-inset-top) = 0px → header y = 0 (under the island) observer : … user-scalable=no, viewport-fit=cover ← re-asserted env(safe-area-inset-top) = 62px → header y = 54 (clear) ``` ## Test Plan - `cd web/ios && xcodebuild test -scheme Omnigent -destination 'platform=iOS Simulator,name=iPhone 17 Pro' -only-testing:OmnigentTests` → all tests pass. - Manual, iPhone 17 Pro simulator against a real Databricks workspace, measuring from inside the page (temporary probe, since removed) at three points — page load, after the host's app mounts, and after further re-renders: - before this change, once the host mounted: `viewport-fit` gone, `env(safe-area-inset-top)` `0px`, `--omnigent-inset-top` `max(0px, 0px)`, `.chat-header` at `y=0`. - after: `viewport-fit=cover` present at all three points, `env(safe-area-inset-top)` `62px`, `--omnigent-inset-top` `max(62px, 0px)`, `.chat-header` at `y=54`, stable across re-renders. - to confirm the diagnosis before fixing, re-adding the token by hand at runtime moved the header from `y=0` to `y=54` on its own. - `pre-commit run --files web/ios/Omnigent/OmnigentWebView.swift` clean. ## Demo Workspace-hosted server on the iPhone 17 Pro simulator. Before: the sidebar toggle renders level with the status bar clock. After: it clears the status bar. Screenshots attached below. ## Type of change - [x] Bug fix - [ ] Feature - [x] UI / frontend change - [ ] Refactor / chore - [ ] Docs - [ ] Test / CI - [ ] Breaking change ## Test coverage - [ ] Unit tests added / updated - [ ] Integration tests added / updated - [ ] E2E tests added / updated - [x] Manual verification completed - [ ] Existing tests cover this change - [ ] Not applicable ## Coverage notes Not unit-tested: the fix is JavaScript embedded in a Swift string literal and injected into a live `WKWebView`, and the behaviour it guards against only happens when a third-party host page mutates the DOM after mount — there's no harness that reproduces that. Verified by measuring the computed inset and header position in the page against a real workspace, before and after, including after subsequent host re-renders. A follow-up worth doing: push measured safe-area insets from native as Android does, so iOS stops depending on page viewport metadata at all. ## Changelog Fixed iOS controls rendering under the status bar on Databricks workspace-hosted servers Signed-off-by: Zeyi (Rice) Fan <zeyi.f@databricks.com>
13 tasks
fanzeyi
added a commit
that referenced
this pull request
Aug 11, 2026
## Related issue N/A — release chore. ## Summary - Bumps `MARKETING_VERSION` from 0.1.1 to 0.1.2 for the `ai.omnigent.ios` target (Debug and Release) ahead of a TestFlight build, so testers can tell the build carrying the workspace fixes apart from earlier 0.1.1 uploads. - Covers two user-facing iOS fixes now on main: connecting to a Databricks workspace opens Omnigent directly and hides the workspace nav bar (#4559), and the top controls no longer render under the status bar on workspace-hosted servers (#4568). - Only the app target moves. The `.tests` / `.uitests` bundles stay at 0.1.0 — they are never shipped, and `web/ios/RELEASE.md` scopes manual bumps to the Omnigent target. - `CURRENT_PROJECT_VERSION` is deliberately untouched: the `beta` lane computes the build number as `latest_testflight_build_number + 1` and injects it via an xcodebuild override, so bumping it in git would only add churn. - Not part of the repo-wide version lockstep: `scripts/update_versions.py` covers the Python packages and the Electron desktop app, not the iOS project. ## Test Plan - `xcodebuild -project web/ios/Omnigent.xcodeproj -target Omnigent -showBuildSettings -configuration Release` reports `MARKETING_VERSION = 0.1.2` and `PRODUCT_BUNDLE_IDENTIFIER = ai.omnigent.ios`, confirming the resolved setting rather than just the edited text. - `python scripts/update_versions.py check` is unaffected (iOS is not one of the locked locations). - `pre-commit run --files web/ios/Omnigent.xcodeproj/project.pbxproj` clean. ## Demo N/A — version metadata only, no UI change. ## Type of change - [ ] Bug fix - [ ] Feature - [ ] UI / frontend change - [x] Refactor / chore - [ ] Docs - [ ] Test / CI - [ ] Breaking change ## Test coverage - [ ] Unit tests added / updated - [ ] Integration tests added / updated - [ ] E2E tests added / updated - [x] Manual verification completed - [ ] Existing tests cover this change - [x] Not applicable ## Coverage notes Build-setting metadata with no runtime behaviour, so there is nothing to unit test. Verified by reading back the resolved `MARKETING_VERSION` from `xcodebuild -showBuildSettings` for the Release configuration of the shipping target. ## Changelog N/A Signed-off-by: Zeyi (Rice) Fan <zeyi.f@databricks.com>
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.
Related issue
N/A — no tracking issue; requested directly.
Summary
bare workspace URL landed on the Databricks landing page instead of the app,
and once on the app the workspace's top-nav bar was still painted over it —
wasting vertical space and letting the user navigate into another workspace app
with no way back.
web/electron/src/workspace-chrome.js) into atestable
WorkspaceChromeScript, replacing the previous injection that wasgated on
path.starts(with: "/ml/omnigents")— a path gate skips auth-redirectlandings and the
/omnigentmount entirely. Keyed on the pinned origin, neveron the path.
/omnigentbounce from feat(android): land Databricks workspaces on the /omnigent mount #4543 on iOS: domain-matched with noprobe,
?o=<org>and fragment preserved, one bounce per app-page load, wiredinto the three iOS equivalents of Android's callbacks —
decidePolicyFor(link/redirect navs),
didCommit(every committed load, incl. the loginchain's POST hand-back) and KVO on
webView.url(in-pagepushState, whichfires no navigation callback at all).
allowsInsecureHTTP(debugonly), a schemeless host was normalized to
http://, so the app pinnedhttp://while the server redirects tohttps://. Every pinned-origincomparison then failed silently — the chrome overlay, native bridge trust
(
isTrustedBridgeMessage, so the server switcher / Chat-Terminal bar / sidebardrag were dead), media-capture prompts, and load-success recording. A schemeless
host now defaults to https unless it is loopback, mirroring the desktop's
LOCAL_HOSTS, so the mismatch can't be created: release builds already rejecthttp://outright and App Transport Security blocks it at the network layer.field, so the two can't drift, and re-arms the bare-root bounce budget when a
new server is pinned. Drops
loadSucceeded's URL argument: its only consumerdiscarded it.
ELI5: the app was told "the server is http://host", the server answered
"actually I'm https://host", and every later "is this page still my server?"
check compared the two strings, said no, and quietly skipped its work.
Test Plan
cd web/ios && xcodebuild test -scheme Omnigent -destination 'platform=iOS Simulator,name=iPhone 17 Pro' -only-testing:OmnigentTests→ all tests pass.WorkspaceChromeScriptTests(CSS byte-identical to thedesktop's
WORKSPACE_CHROME_HIDE_CSS, the install-once guard, CSS embedded asan escaped literal);
WorkspaceMountURLTests(bare roots on both workspacedomains, query + fragment preserved, port and host-case, non-root paths left
alone,
databricksapps.comand adatabricks.com.evil.examplelookalikerejected, non-http schemes rejected);
ServerURLTests(schemeless host → httpseven under the debug policy, loopback → http, explicit
http://honoured).workspace URL lands on
/omnigentand the workspace nav bar is gone. Confirmedduring development with a temporary in-app probe (since removed) reporting
styleTag:true, position:"fixed", rect:{y:0,h:874}— the embed root covers theviewport from y=0 — and independently by the maintainer on the same simulator.
pre-commit run --files <touched files>clean.Demo
Before:

After:
Type of change
Test coverage
Coverage notes
The mount-URL rewriting, scheme defaulting and the injected script are
unit-tested. The navigation wiring is not:
OmnigentWebView.Coordinatorneeds alive
WKWebViewplus a SwiftUI context to construct, so the callbacks and theoverlay were verified on the simulator against a real workspace instead.
Changelog
Connecting the iOS app to a Databricks workspace now opens Omnigent directly and
hides the workspace navigation bar
Signed-off-by: Zeyi (Rice) Fan zeyi.f@databricks.com