dashboard: mobile adaptation + restore web terminal + env-aware API URL#840
Conversation
… env Local dashboard dev calls a same-origin /api path; Vite proxies it to the selected backend, so the browser never makes a cross-origin (CORS-gated) request and no backend has to allow-list localhost. Replaces the prior VITE_BASE_API_URL=dev direct-call approach, which the browser blocked with CORS. - start-dashboard.mjs: API_TARGETS map (local/dev + prod placeholder), --api=<url> for any env, --yes-prod guard for prod - vite.config.mts: /api proxy target read from DASHBOARD_API_PROXY_TARGET - package.json: start:prod (replaces throwaway start:dev-proxy) - apps/CLAUDE.md: fix 'from repository root' -> apps/, document the proxy model
…om/boxlite-ai/boxlite into claude/loving-carson-e4a7cf
…n onboarding - BoxTable: remove the Region column from the desktop table and the Region entry from the compact mobile meta. The box table no longer surfaces region. - Remove the now-unused getRegionName plumbing from the box-table path (Boxes page, BoxTable, useBoxTable, columns, types) and the stale 'region' entry from persisted column visibility. useRegions/getRegionName stay in place for the other consumers (Runners, Org Settings, Box details). - onboarding-code-examples: use the fully-qualified image reference ghcr.io/boxlite-ai/boxlite-agent-base:20260605-p0-r3 across all four SDK snippets (JS/TS, Python, Go, Rust) instead of the short 'boxlite/base'.
- BoxTable: drop the stale min-w-[1360px] (sized for removed columns) to min-w-[1120px] so the table fills the viewport without horizontal scroll, and tighten row vertical padding (py-2 -> py-1, scoped to this table) so rows are ~41px instead of ~46px. - use-mobile: lower COMPACT_BREAKPOINT 1200 -> 1024 so the dashboard keeps the full table (not the compact card layout) down to 1024px.
Adopt exe.dev's calm/minimal/progressive-disclosure feel on the box list. List minimalism + progressive disclosure: - Default visible columns reduced to Name + Last Event + actions. Box ID, State, Resources, and Created At are hidden by default and toggleable via the View menu (TanStack columnVisibility + localStorage, bumped to a V2 key so the old forced 'id:true' default does not stick). - Status now leads the Name cell as a compact status dot (BoxState gains an iconOnly mode with a tooltip) instead of a dedicated State column. Centered-narrow layout: - New PageLayout 'content' size (~1040px); Boxes list switches off 'full' (1440px) onto it, so the list centers with side whitespace instead of filling the viewport. Table min-width lowered 1120 -> 680 for the trimmed row. Visual calm (global tokens): - Root font-size 15px -> 14px; --border lightened to a hairline; Card drops shadow-sm to rely on the border. Warm-cream brand palette kept. Verified in Chrome against the dev API: list centers, shows Name+dot / Last Event / actions, View menu toggles the four hidden columns back on.
…ass 2) Restructure the box detail page to exe.dev's calm, centered, progressive layout (approach B: observability moves into the column, not a full-bleed split). - BoxDetails: drop the full-bleed resizable Group/Panel split and the desktop/mobile duality. Detail now flows in one centered max-w-[1040px] scrolling column: metadata grid -> content tabs. Removes isDesktop / react-resizable-panels / ScrollArea usage. - BoxHeader: compress the two-line header (name over Box ID) into a single row (name + copy + inline mono Box ID + copy). - SDK 'Connect with the SDK' nudge demoted from a full-width banner owning the top to a compact inline card inside the column. - BoxInfoPanel: reflow the vertical sidebar sections into a 2-column metadata grid and surface fields that were in the Box model but never rendered — Image (full ghcr ref) and Region (getRegionName(target)), plus Labels. - BoxContentTabs: drop the now-redundant Overview tab (metadata is always shown above) and give the tab shell a bounded height (60vh) so the terminal and observability tabs render correctly inside the scrolling column. - Remove the now-dead InfoSection/InfoRow exports. Verified in Chrome: detail centers in ~1040px, header is one line, metadata grid shows Image + Region, terminal tab renders bounded.
Both the global top nav and the box-detail header spanned wider than the new centered ~1040px content column, so they didn't line up with it. - Sidebar (global top nav): constrain inner content max-w 1440 -> 1040 so the logo/tabs/search align with the page content column. - BoxHeader: center its content in a max-w-[1040px] inner wrapper (full-width border-b kept as the divider) so back/name align left and actions align right with the content below. Verified in Chrome: nav, box header, and detail content share one centered 1040px column on both the list and detail pages.
…inent - Org switcher/display moves out of the top nav into the right-side profile dropdown as an Organization section (org name -> settings, Copy organization ID). The 'Copy Organization ID' command-palette entry is preserved (re- registered in Sidebar). Removes the now-unused OrganizationPicker component. - Make the primary state action prominent: Start / Stop / Recover use the filled default button variant instead of muted outline, in both the box-table row (desktop + mobile) and the detail header, so the main action stands out from the secondary (terminal / SSH / overflow) buttons. Verified in Chrome: nav no longer shows the org pill; profile menu shows the Organization section; Start/Stop render as filled buttons in list and detail.
…ge row - BoxInfoPanel: remove the Auto-stop and Auto-delete metadata rows. The auto-stop/auto-delete feature is not supported (pipeline removed), so the dashboard should not surface it. (Note: box.autoStopInterval/autoDeleteInterval still exist on the api-client Box model — a backend/model remnant to purge separately.) - BoxDetails: remove the 'Connect with the SDK' nudge row from the detail page (misaligned and redundant — the guide is still reachable from the nav). Drop the now-orphaned onboardingCoreProgress/showOnboardingNudge and unused imports (getOnboardingCoreProgress, Code2, ListChecks, formatDuration).
- BoxTableHeader: remove the Refresh, View (column visibility), and Filter (state/last-event) controls. The toolbar is now just the box Search + the Create Box action. Removes the active-filter indicator row. - Drop the now-orphaned refresh plumbing end to end: onRefresh/isRefreshing from BoxTableHeaderProps and BoxTableProps, the passthrough in BoxTable, and handleRefresh + boxDataIsRefreshing + the refetch handle in Boxes.tsx. - Profile menu Organization section: keep just the org name (-> Settings) and drop the standalone 'Copy organization ID' item (still available via the command palette). Verified in Chrome: list toolbar shows only Search + Create Box; profile menu Organization shows only the org name.
…pler menus - Start/Stop/Recover: use the lighter 'secondary' button variant instead of the solid-black 'default' (still prominent vs the outline secondary buttons, but not heavy black). Applies to the box-table row (desktop + mobile) and detail header. - Typography consistency: drop the ad-hoc monospace from Box ID (header + detail) and Image so box detail reads in one consistent font. - Detail metadata grid: normal-case muted labels (no uppercase/letter-spacing), tighter row rhythm, baseline-aligned label/value pairs. - Profile menu: theme toggle on top (no 'Appearance' label); Organization is a single item (-> Settings) parallel to Docs/Discord (no section label, no org name); dropped the standalone org-name display. Verified in Chrome (light + dark): detail metadata uniform + compact; Start/Stop render as soft buttons; profile menu shows Organization/Docs/Discord parallel.
…boxes) Add BoxSearchCommands: while the command palette (nav search / ⌘K) is open, the typed query is debounced and run against listBoxesPaginated(idOrName); matching boxes are registered as a 'Boxes' result group, each selecting to the box detail. Mounted in Sidebar (inside the command-palette + api providers). This makes the global search find boxes by name/ID (industry-standard command palette entity search), complementing the in-list box filter. Verified in Chrome: typing a box name/ID in ⌘K shows it under 'Boxes' and navigates to the detail on select.
Billing is no longer a top-nav tab; it sits in the profile dropdown alongside Organization / Docs / Discord (-> /dashboard/billing). The top nav now carries just Boxes (plus Admin when permitted), keeping the bar minimal. Verified in Chrome: nav shows only Boxes; profile menu lists Organization, Billing, Docs, Discord.
…edup id, terminal start, status pill, metadata grid Top-designer walkthrough of the box detail + list. - Remove the unsupported Screen Recordings feature end-to-end (BoxHeader and BoxTableActions menus + the handler/prop chain through Boxes, BoxTable, columns, useBoxTable, types, BoxDetails; the port-33333 preview caller). - Dedup the Box ID: the header now shows just the name + one copy; the Box ID with its copy lives only in the metadata grid (was duplicated in both). - Terminal 'Box is not running' empty state now offers an inline 'Start box' button (gated by write permission) so users don't have to find the top-right Start (BoxTerminalTab uses useStartBoxMutation directly). - Status is now a colored pill (green running / muted stopped / red error / amber recoverable) via a new BoxState 'pill' variant — far more prominent. - Metadata grid redesigned into stacked label-over-value cells: Image spans the full row, the rest in a 3-col grid — left-aligned, no ragged right edge, consistent rhythm. Verified in Chrome (light+dark): screen recordings gone; single id copy; status pill; stopped box shows inline Start box in the terminal; metadata grid aligned.
…se, loading state - BoxTable row: the whole row is clickable again. The cell-level click handler only swallows the checkbox cell now; the actions cell lets clicks in the empty space around the (already self-stopping) buttons fall through to open the row. - BoxHeader: move the status pill next to the box name (left) instead of the crowded top-right action cluster, grouping identity + status. - BoxInfoPanel: uppercase the Region value (e.g. 'us' -> 'US'). - LoadingFallback: drop the duplicate centered spinner that overlapped the skeleton table, align width to the new 1040 content column, and show the 'taking longer' note (no competing spinner) only after 5s. One clean skeleton. Verified in Chrome: clicking near the row actions opens detail; status pill sits by the name; Region shows 'US'; reload shows a single clean skeleton.
…parse
Anchor the top of the box list with a title + one-line description ('Boxes' /
'Run code in isolated, on-demand environments.') and move Create Box up next to
it (title left, primary action right). Gives the page top matter — like a
breadcrumb/context region — instead of a thin table floating on a tall empty
viewport. The toolbar row is now just search.
…loading rows - Give the box table an iOS-like floating feel: weaker hairline border (border/40-50), softer/larger drop shadow, rounded-xl. Row + header dividers weakened to border/50-60 so separation reads from elevation, not heavy lines. Applied to both the desktop table card and the compact card. - Replace the in-table 'Loading...' text (which looked off in the framed table) with skeleton rows (5 desktop / 4 compact) so the loading state fills the card like real rows forming.
…mand palette) The in-list 'Search by name or Box ID' field is removed — box lookup is now served by the global command palette (⌘K), which searches boxes by name/ID. With the field and the (already-relocated) Create Box action gone, BoxTableHeader had nothing left to render, so it and its now-unused headerAction prop are deleted.
…low menu, surface SSH The row's '...' menu repeated actions that already have inline buttons. Now: - Remove Start/Stop/Recover and (desktop) Terminal from the overflow menu — they already exist as the inline primary button + terminal button. - Surface SSH as its own inline button (KeyRound) on desktop when the box is ssh-accessible, instead of burying 'Create SSH Access' in the menu. - Overflow menu is now just: View Details, Revoke SSH Access, Delete (plus, on compact/mobile where there are no inline terminal/ssh buttons, Terminal + Create SSH so mobile keeps access). Inline (desktop): primary state toggle · Terminal · SSH (when accessible) · more.
…der corners Establish a cohesive 'floating surface' visual system, centralized for easy rollback: - index.css: bump --radius 0.375rem -> 0.625rem (rounder cards/buttons/inputs proportionally) and add theme-aware --shadow-card / --shadow-card-hover (soft layered light shadow; deeper dark shadow so cards still lift off the bg). - tailwind.config: register shadow-card / shadow-card-hover utilities from those vars. - Card component: rounded-xl + hairline border (border/60) + shadow-card — this alone restyles the ~14 pages that use the shared Card (Billing, Settings, Wallet, Spending, Webhooks, Admin, …). - Apply the same shadow-card token to the surfaces that use ad-hoc containers: box table (replacing the earlier inline shadow), BoxInfoPanel, BoxContentTabs, and the API keys table. Verified in Chrome (dark): box list table floats with rounded-xl + soft shadow; buttons rounder but not pill-y. Other Card pages inherit via the central change.
Remove the border-b on the BoxHeader so there's no horizontal rule between the title row and the metadata/terminal content below it.
…ens a dialog anywhere (no redirect)
- Profile menu: give the theme toggle top padding (px-2 pb-2 -> px-2 py-2) so it
no longer hugs the dropdown's top edge.
- Theme switch flicker: drop the runWithoutAnimation hack that injected a global
'* { transition:none !important }' style and forced two synchronous reflows on
every element (which flashed the open dropdown). Just toggle the html class.
- Guide no longer jumps to the homepage. Add a single app-global OnboardingDialogHost
(rendered in Dashboard) that listens for ONBOARDING_OPEN_EVENT and opens the
guide as a dialog from any page; it preventDefaults the event so the Sidebar's
navigate(/dashboard/boxes?onboarding=1) fallback never fires. Removed the
per-page ONBOARDING_OPEN_EVENT listeners from Boxes/BoxDetails so the Guide
button no longer triggers their copies (first-visit auto-open + ?onboarding=1
stay page-local).
…vanced accordion) Surface CPU/Memory/Disk directly in the Create Box sheet instead of hiding them behind an 'Advanced options' accordion, so the sheet reads less empty. Image stays a dropdown; no live-summary card.
… cells The all-rounded floating restyle left hard hairlines and edge-hugging content that clashed with it: - top nav border-b: border-border -> border-border/50 - table header border-b: border-border/60 -> border-border/40 - first/last table cells: add pl-5 / pr-5 so content clears the card's rounded corners instead of sitting flush against them
… login) Previously the MSW mock only covered billing and even fetched /config from the real dev API, so the dashboard could not render its core surfaces offline. Make the local mock chain stand on its own: - fixtures.ts: typed Organization, member (owner), config and box fixtures - MockAuthProvider: swaps react-oidc-context's AuthProvider for a fixed authenticated session (no OIDC server, no login round-trip) - handlers.ts: serve a static config plus organizations, org members, paginated boxes, regions, and a 403 admin probe - ConfigProvider: use MockAuthProvider when VITE_ENABLE_MOCKING is set
…heet Few fields no longer warrant a full-height drawer; mirror the API-key dialog — centered modal, resources laid out in a single CPU/Memory/Disk row.
Replace the plain textarea + icon button with the tinted key card and a prominent labelled Copy button that confirms in place.
…ndlers Lets the box detail page and the onboarding key flow render offline.
… 16px Self-host Space Grotesk (SIL OFL) and apply it to titles and labels (cards, dialogs, sheets, the Label primitive, box name, detail meta labels — now bolder); body stays Inter and code stays monospace. Raise the root font-size from 14px to 16px so the whole UI scales up via rem.
… panel Drop the inner scroll region so the whole detail page scrolls. With observability tabs off, render a plain Terminal header instead of a single-tab selector, and remove the terminal's inner rounded frame so it fills the card edge to edge under the header.
…d section Now that Create Box is a centered dialog, the CPU/Memory/Disk fields tuck into an Advanced accordion (collapsed by default), stacked vertically.
… empty Drop the inline SSH button (its key icon clashed with API Keys and only showed on some rows); SSH now lives in the overflow menu on every layout, so rows are uniform. Skip the column header when the list is empty so the empty state isn't stranded under a half-width header.
…pulse Light tokens now form a clear ladder: a recessed page background with a brighter shared surface for cards and the top nav (nav switches from the background tone to the card tone) so chrome reads as one elevated layer. Also remove the onboarding Guide entry's pulse animation (and its dead keyframe / state / listener) so it's a plain button.
Rebuilds the dashboard UI to an ASCII/terminal design language (IBM Plex Mono, square corners, #00B0F0 accent, dark-default dual theme) while reusing all existing data hooks/mutations/providers unchanged. No server APIs added or modified; only existing endpoints are consumed. - Design system: index.css HSL token remap + brand token, IBM Plex Mono, square radii, theme key boxlite-theme; re-skins all shadcn ui primitives via token swap. - Top nav (Sidebar): logo/Sandboxes/Billing/Admin/Search/API Keys/Quickstart + standalone org switcher + profile menu; grayscale active state. - Sandboxes (Boxes): header + real-data stat cards (Total/Running via listBoxesPaginated.total, CPU-hours via analytics) + filter + redesigned table; New Box modal with stepper resource config (CPU<=8, Mem<=32, Disk<=50 default 10). - Box detail: breadcrumb + spec readout + real terminal panel + lifecycle/Remote SSH. - API Keys: redesigned table + create + one-time reveal modal. - Billing: 'on the way' empty state. - Login/register: dark-only, OIDC signinRedirect (no client auth API). - Quickstart: scenario picker (ASCII cards) -> per-scenario 3-step guided flow. - OrganizationSettings/EmailVerify/Admin reshelled in the new language. - Mock-only auth provider made stateful so the login page is reviewable under start:mock. Deliberate, design-driven feature reductions (underlying code retained): box-detail logs/metrics/traces/spending tabs and boxes-table bulk-select/column-sort are dropped from the new UI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Frontend-only follow-ups to the restyle. The only files outside apps/dashboard are the dependency manifests (apps/package.json, apps/yarn.lock) for the new icon set. No backend, generated clients, or data-contract changes; the single providers/ touch is an icon import-source swap (presentational, no logic). - Icons: replace lucide-react with a pixel/8-bit set (pixelarticons via @iconify) through a central shim (src/components/ui/icon.tsx) that re-exports every used name mapped to the angular glyph; 122 files re-pointed from 'lucide-react' to '@/components/ui/icon'. The logo is untouched. - Toasts (sonner): square corners, IBM Plex Mono, pixel status icons, bordered popover surface. - Org switcher: moved from a standalone nav control into the top-right profile menu (submenu with switch-org list + settings + copy id). Still org-scoped; not dropped. - API Keys page: aligned to the Sandboxes layout (big title, borderless hover-row table, simple footer). - Sandboxes: dot-matrix LED stat numbers, square status indicator (was a round dot), dashed filter input; page titles reduced 30->22px (Sandboxes + API Keys). - Quickstart 'coming soon' card uses a static halftone texture (added .halftone utilities). - Box terminal empty-state icon enlarged (was a tiny chip). Deps added: @iconify/react, @iconify-json/pixelarticons (offline, bundled). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Login/register tab selection now uses the same grayscale fill as the top nav active state (was a brand underline). SSO icons swapped to the 8-bit set: GitHub uses the pixel shim icon, Google uses a hand-drawn pixel 'G' (pixelarticons has no Google mark). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… UI polish Mobile / responsive: - Responsive Boxes list (card list <md), Create Box dialog, Sidebar, Box detail - Desktop L/R page padding unified to 40px across active pages Box detail: - Restore web terminal panel (responsive) + /terminal fullscreen route; SSH stays hidden - Spec readout: narrower column, tighter grouping, image hover tooltip; drop lifecycle Boxes list: - Stat cards: drop CPU-hours + index labels, add stopped count - Mock /box/paginated honors ?states= for real per-state counts Config / naming: - lib/environment.ts: resolve env by hostname, pin public REST API URL per env - Quickstart shows env-correct API URL - Rename user-facing Sandboxes -> Boxes Plus lint/type fixes in icon.tsx and mock fixtures.
|
Important Review skippedToo many files! This PR contains 163 files, which is 13 over the limit of 150. To get a review, narrow the scope: Upgrade to a paid plan to raise the limit. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (11)
📒 Files selected for processing (163)
You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0e55a9b75e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ] as const | ||
|
|
||
| const DEFAULTS = { cpu: 1, memory: 1, disk: 10 } | ||
| const LIMITS = { cpu: 8, memory: 32, disk: 50 } |
There was a problem hiding this comment.
Don't clamp valid box sizes in the dialog
For organizations whose quotas allow larger boxes, the new dialog silently clamps any typed Advanced Options values to 8 vCPU / 32 GiB memory / 50 GiB disk because every Stepper is capped by this LIMITS object; the replaced sheet only required positive integers, and the new comment says the backend accepts arbitrary cpu/memory/disk. This prevents users from creating otherwise-valid larger boxes from the dashboard.
Useful? React with 👍 / 👎.
| const totalBoxesQuery = useQuery({ | ||
| queryKey: ['boxesCount', orgId, 'all'], | ||
| queryFn: async () => (await boxApi.listBoxesPaginated(orgId, 1, 1)).data.total, |
There was a problem hiding this comment.
Invalidate fleet-count queries after box changes
These new stat-card queries use a separate ['boxesCount', orgId, ...] key, but all create/start/stop/delete handlers and websocket updates only invalidate getBoxesQueryKey(...). After creating, deleting, starting, or stopping a box, the table updates while the total/running/stopped cards keep the old cached counts until a remount/window-focus refetch happens, so the dashboard shows inconsistent fleet totals.
Useful? React with 👍 / 👎.
…ssets - LandingPage: unauthenticated visitors redirect straight to the OIDC hosted login (Auth0/Dex) via signinRedirect; drop the non-functional email/password/social facade that never authenticated. Authenticated -> /dashboard. - Delete 10 unreferenced assets (9 duplicate logos + react.svg); keep only the 4 logos used by Logo.tsx and the 4 SDK icons used by the Quickstart.
Addresses 3 confirmed findings from the review of the prior commits: - [P2] Logout no longer bounces back into login. LandingPage auto-redirects to the hosted login only for fresh visitors; a just-logged-out user (marked in sessionStorage before signoutRedirect in Logout + Sidebar) gets a manual sign-in screen instead, avoiding the SSO-cookie re-auth loop. - [P2] Create Box dialog caps at 540px again: sm:max-w-[540px] now overrides shadcn base sm:max-w-lg (512px). - [P2] Tablet header (768-1023px): mobile menu trigger md:hidden -> lg:hidden + add Quickstart to it, so Search/API Keys/Quickstart stay reachable.
# Conflicts: # apps/dashboard/src/components/BoxTable/columns.tsx # apps/dashboard/src/components/BoxTable/index.tsx # apps/dashboard/src/components/BoxTable/useBoxTable.ts # apps/dashboard/src/pages/Boxes.tsx # apps/scripts/start-dashboard.mjs
… top Profile dropdown reorder: name+email header, Theme (renamed from Appearance), then Organization / Docs / Discord as plain single-line items, Sign out last. Organization is now one item linking straight to org settings (drops the hover submenu with org switcher + copy-id; org-id copy stays in the command palette).
Continues the dashboard restyle from #829. Frontend-only (
apps/dashboard/*), 0 Rust / backend files.This session's work (tip commit
0e55a9b7)/terminalfullscreen route are back. SSH entry points stay hidden — SSH and the web Terminal are separate features and had been wrongly removed together./box/paginatednow honors?states=.lib/environment.tsresolves env by hostname (notconfig.environment— dev stage reports"production") and pins the public REST API URL per env. Temporary frontend shim with a fallback; long-term should be a/api/configfield.Targeting
mainwhile #829 (feat/dashboard-floating-restyle) is still open means this PR bundles #829's restyle commits too (62 commits via merge-base). For a clean 5-commit incremental, retarget the base tofeat/dashboard-floating-restyle.Verification