Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/app/e2e/regression/device-controls.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,15 @@ for (const platforms of [["ios", "android"], ["ios"], ["android"]] as const) {
).toBeEnabled()
}

// Only a live JavaScript run names the project Metro serves; the failed iOS build loads nothing.
const metro = page.locator('[data-slot="device-metro"]')
await expect(metro).toHaveCount(expo ? 1 : 0)
if (expo) {
const android = page.getByRole("toolbar", { name: labels.android, exact: true }).locator("xpath=..")
await expect(android.locator('[data-slot="device-metro"]')).toContainText("Metro~/DeviceControls")
await expect(android.getByTitle(directory, { exact: true })).toBeVisible()
}

for (const platform of platforms) {
const label = labels[platform]
const pane = page.getByRole("toolbar", { name: label, exact: true })
Expand All @@ -138,6 +147,7 @@ for (const platforms of [["ios", "android"], ["ios"], ["android"]] as const) {
).toBeEnabled()
}
if (expo) await expect(controls.getByRole("button", { name: "Stop", exact: true })).toBeEnabled()
await expect(metro).toHaveCount(0)
expect(calls).toEqual([
...(expo ? [{ path: "/api/device-preview/bundler/start", directory }] : []),
...platforms.map((platform) => ({ path: "/api/device-preview/run", directory, platform })),
Expand Down
31 changes: 30 additions & 1 deletion packages/app/src/components/session/session-device-tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import { createStore } from "solid-js/store"
import { useLanguage } from "@/context/language"
import { usePlatform } from "@/context/platform"
import { useServerSDK } from "@/context/server-sdk"
import { useServerSync } from "@/context/server-sync"
import { devicePreviewUrl } from "@/utils/device-preview"
import { createDeviceState, deviceBuildBusy, devicePreviewIcon } from "./device-state"
import { createDeviceState, deviceBuildBusy, deviceFrameworkIcon, devicePreviewIcon } from "./device-state"

const ALL_PLATFORMS: DevicePreview.Platform[] = ["ios", "android"]
const LOG_TAIL = 40
Expand Down Expand Up @@ -127,6 +128,7 @@ function DevicePane(props: {
classList?: Record<string, boolean | undefined>
}) {
const serverSDK = useServerSDK()
const serverSync = useServerSync()
const platform = usePlatform()
const language = useLanguage()
let frame: HTMLIFrameElement | undefined
Expand Down Expand Up @@ -154,6 +156,18 @@ function DevicePane(props: {
return { text: url() ?? server()?.command ?? "", failed: false }
})

// Both apps load their JavaScript from one Metro, so a successful native build does not say
// which project's bundle is running. Name Metro's project beside every live JS run.
const metro = createMemo(() => {
const current = build()
const bundler = props.device.info()?.bundler
if (!current || !bundler || bundler.status === "exited") return
if (!deviceBuildBusy(current) && current.status !== "running") return
if (!deviceFrameworkIcon(current.framework ?? props.device.info()?.framework)) return
const home = serverSync().data.path.home
return { full: bundler.directory, short: home ? bundler.directory.replace(home, "~") : bundler.directory }
})

const reload = () => {
const next = url()
if (!frame || !next) return
Expand Down Expand Up @@ -250,6 +264,21 @@ function DevicePane(props: {
</Button>
</Show>
</div>
<Show when={metro()}>
{(value) => (
<div
data-slot="device-metro"
class="flex items-center gap-1.5 px-3 h-7 shrink-0 border-b border-border-weaker-base text-11-regular text-text-weak"
>
<AppIcon id="react" class="size-3.5 shrink-0" />
<span class="shrink-0">{language.t("session.device.bundler.label")}</span>
{/* Clip the start so the project folder stays visible; the LTR isolate keeps `~/` in front. */}
<span class="min-w-0 truncate-start text-text-base" title={value().full}>
<bdi dir="ltr">{value().short}</bdi>
</span>
</div>
)}
</Show>
<div class="relative flex-1 min-h-0">
<Switch>
<Match when={running()}>
Expand Down
Loading