Skip to content

feat(android): land Databricks workspaces on the /omnigent mount - #4543

Merged
github-actions[bot] merged 1 commit into
omnigent-ai:mainfrom
fanzeyi:fanzeyi/android-databricks-redirect
Aug 10, 2026
Merged

feat(android): land Databricks workspaces on the /omnigent mount#4543
github-actions[bot] merged 1 commit into
omnigent-ai:mainfrom
fanzeyi:fanzeyi/android-databricks-redirect

Conversation

@fanzeyi

@fanzeyi fanzeyi commented Aug 10, 2026

Copy link
Copy Markdown
Member

Related issue

N/A — no tracking issue; requested directly.

Summary

  • A Databricks workspace serves its own landing page at the root and mounts the
    Omnigent SPA at /omnigent, so an Android user who connects to (or navigates
    back to) https://<workspace> sees Databricks, not the app. The shell now
    rewrites a bare workspace root to <origin>/omnigent, preserving ?o=<org>
    and any fragment; a URL that already carries a path is a deliberate deep link
    and is left alone.
  • Applied where the pinned server URL is read (ServerStore.currentServerUrl,
    expanded on read so the stored/offered entry stays what the user typed) and in
    all three WebViewClient callbacks that can observe the WebView reaching the
    root — no single one sees every case:
    shouldOverrideUrlLoading (link/redirect navigations; skipped for shell-issued
    and POST-driven loads), onPageStarted (every committed main-frame load,
    including the SSO chain's POST hand-back), and doUpdateVisitedHistory (in-page
    routing via pushState/replaceState/history, which loads nothing at all).
  • Host matching is by domain (*.databricks.com, *.azuredatabricks.net) with no
    probe request; *.databricksapps.com is excluded because Apps serve their own
    app at the root and have no workspace mount. Bounces are budgeted at one per
    app-page load, so a workspace whose /omnigent redirects back to the root
    leaves the user on the root instead of looping, and are posted to the main
    looper because a loadUrl issued while WebView is committing a navigation can
    be dropped.
  • Bumps versionName to 0.1.3. iOS/Electron still expand to /ml/omnigents
    behind a server: databricks probe; that divergence is deliberate (see the
    comment in web/electron/src/url.js) and untouched here.

Test Plan

  • ./gradlew :app:testDebugUnitTest for the touched classes — new
    OriginsWorkspaceUiUrlTest (expansion, query/fragment and port/case
    normalization, paths and non-workspace hosts left alone) plus new
    OmnigentWebViewClientTest cases for the redirect nav, the POST-style landing,
    in-page routing, the loop budget, and its re-arming.
  • web/android/bin/ktlint.sh and pre-commit run --files … clean on the touched
    files.
  • Manual, API 35 emulator against a real Databricks workspace: connected with a
    bare workspace URL and confirmed the shell loads /omnigent instead of the
    workspace landing page, and confirmed via a temporary debug trace (since
    removed) that in-page SPA navigations reach the new doUpdateVisitedHistory
    hook — the callback the earlier navigation-only hooks never saw.

Note: MainActivityTest > configuration change updates system bar icon polarity
fails on a clean checkout of main as well (verified with git stash); it is
unrelated to this change and left as is.

Demo

N/A — no new UI; the observable change is which URL the WebView lands on.

Type of change

  • Bug fix
  • Feature
  • UI / frontend change
  • Refactor / chore
  • Docs
  • Test / CI
  • Breaking change

Test coverage

  • Unit tests added / updated
  • Integration tests added / updated
  • E2E tests added / updated
  • Manual verification completed
  • Existing tests cover this change
  • Not applicable

Coverage notes

Robolectric unit tests cover the URL rule and each of the three navigation
callbacks, including the loop budget. Manual verification on an API 35 emulator
against a real workspace covered the connect-time expansion and that in-page
navigations reach the new hook; the redirect-loop path (a workspace without the
/omnigent mount) is covered by unit tests only, since it can't be reproduced
against a healthy workspace.

Changelog

The Android app now opens Databricks workspaces on their /omnigent app instead of the workspace landing page.

Signed-off-by: Zeyi (Rice) Fan zeyi.f@databricks.com

## Related issue

N/A — no tracking issue; requested directly.

## Summary

- A Databricks workspace serves its own landing page at the root and mounts the
  Omnigent SPA at `/omnigent`, so an Android user who connects to (or navigates
  back to) `https://<workspace>` sees Databricks, not the app. The shell now
  rewrites a **bare** workspace root to `<origin>/omnigent`, preserving `?o=<org>`
  and any fragment; a URL that already carries a path is a deliberate deep link
  and is left alone.
- Applied where the pinned server URL is read (`ServerStore.currentServerUrl`,
  expanded on read so the stored/offered entry stays what the user typed) and in
  all three `WebViewClient` callbacks that can observe the WebView reaching the
  root — no single one sees every case:
  `shouldOverrideUrlLoading` (link/redirect navigations; skipped for shell-issued
  and POST-driven loads), `onPageStarted` (every committed main-frame load,
  including the SSO chain's POST hand-back), and `doUpdateVisitedHistory` (in-page
  routing via `pushState`/`replaceState`/history, which loads nothing at all).
- Host matching is by domain (`*.databricks.com`, `*.azuredatabricks.net`) with no
  probe request; `*.databricksapps.com` is excluded because Apps serve their own
  app at the root and have no workspace mount. Bounces are budgeted at one per
  app-page load, so a workspace whose `/omnigent` redirects back to the root
  leaves the user on the root instead of looping, and are posted to the main
  looper because a `loadUrl` issued while WebView is committing a navigation can
  be dropped.
- Bumps `versionName` to 0.1.3 and the local `versionCode` fallback to 9 (CI
  still passes `-PversionCode` explicitly). iOS/Electron still expand to
  `/ml/omnigents` behind a `server: databricks` probe; that divergence is deliberate (see the
  comment in `web/electron/src/url.js`) and untouched here.

## Test Plan

- `./gradlew :app:testDebugUnitTest` for the touched classes — new
  `OriginsWorkspaceUiUrlTest` (expansion, query/fragment and port/case
  normalization, paths and non-workspace hosts left alone) plus new
  `OmnigentWebViewClientTest` cases for the redirect nav, the POST-style landing,
  in-page routing, the loop budget, and its re-arming.
- `web/android/bin/ktlint.sh` and `pre-commit run --files …` clean on the touched
  files.
- Manual, API 35 emulator against a real Databricks workspace: connected with a
  bare workspace URL and confirmed the shell loads `/omnigent` instead of the
  workspace landing page, and confirmed via a temporary debug trace (since
  removed) that in-page SPA navigations reach the new `doUpdateVisitedHistory`
  hook — the callback the earlier navigation-only hooks never saw.

Note: `MainActivityTest > configuration change updates system bar icon polarity`
fails on a clean checkout of `main` as well (verified with `git stash`); it is
unrelated to this change and left as is.

## Demo

N/A — no new UI; the observable change is which URL the WebView lands on.

## Type of change

- [ ] Bug fix
- [x] Feature
- [ ] 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

Robolectric unit tests cover the URL rule and each of the three navigation
callbacks, including the loop budget. Manual verification on an API 35 emulator
against a real workspace covered the connect-time expansion and that in-page
navigations reach the new hook; the redirect-loop path (a workspace without the
`/omnigent` mount) is covered by unit tests only, since it can't be reproduced
against a healthy workspace.

## Changelog

The Android app now opens Databricks workspaces on their `/omnigent` app instead of the workspace landing page.

Signed-off-by: Zeyi (Rice) Fan <zeyi.f@databricks.com>
@fanzeyi
fanzeyi force-pushed the fanzeyi/android-databricks-redirect branch from 036bfd8 to 1c39ec7 Compare August 10, 2026 21:04
@github-actions github-actions Bot added the size/L Pull request size: L label Aug 10, 2026
@fanzeyi fanzeyi added skip-e2e-ui-test automerge Automatically Run Merge CI labels Aug 10, 2026
@github-actions
github-actions Bot enabled auto-merge (squash) August 10, 2026 21:17
@github-actions
github-actions Bot merged commit eae8136 into omnigent-ai:main Aug 10, 2026
50 of 53 checks passed
fanzeyi added a commit to fanzeyi/omnigent that referenced this pull request Aug 10, 2026
…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 server, 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: a schemeless host entered with
  "allow insecure HTTP" 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
  remote host now defaults to https (loopback still http, mirroring the desktop's
  `LOCAL_HOSTS`), and a server-driven http→https upgrade of the same host and port
  is adopted for those checks.
- Collapses the web view's pinning state onto one `PinnedServer` value. It was
  three fields for one concept — a URL, a cached origin string derived from it,
  and (as first written) a third field patching the cached origin when the
  server's scheme disagreed. The origin is now derived, the upgrade lives with
  the pin, and `matches` / `adoptSecureUpgrade` are unit-tested without a
  `WKWebView`. `loadSucceeded`'s URL argument is dropped: 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  (remote ⇒ 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` → 84 tests pass.
- New/updated unit tests: `PinnedServerTests` (origin derivation, matching, the
  http→https upgrade, and refusal of downgrades / foreign hosts / different
  ports, plus that adopting an upgrade leaves the pinned URL untouched);
  `WorkspaceChromeScriptTests` (CSS byte-identical to the desktop's
  `WORKSPACE_CHROME_HIDE_CSS`, install-once guard, CSS embedded as an escaped
  literal, plus a guard that fails if a URL/path gate is reintroduced in
  `didFinish`); `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 remote 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. Verified
  both before and after the `PinnedServer` refactor, with a stored `http://`
  server URL so the upgrade path is exercised. 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

`PinnedServer` (matching + the https upgrade), the mount-URL rewriting, scheme
defaulting and the injected script are all unit-tested. The navigation wiring is
not: `OmnigentWebView.Coordinator` needs a live `WKWebView` plus a SwiftUI context
to construct, so the callbacks were verified on the simulator against a real
workspace instead. A source-level test guards the one regression that is cheap to
reintroduce — gating the injection on the URL path.

## 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 added a commit to fanzeyi/omnigent that referenced this pull request Aug 11, 2026
…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 added a commit to fanzeyi/omnigent that referenced this pull request Aug 11, 2026
…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 added a commit that referenced this pull request Aug 11, 2026
…ace chrome (#4559)

## 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 #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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automerge Automatically Run Merge CI size/L Pull request size: L skip-e2e-ui-test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant