Skip to content

feat(macos): native desktop app with macOS-native UI - #2

Merged
duyetbot merged 23 commits into
mainfrom
feat/macos-desktop
Aug 26, 2026
Merged

feat(macos): native desktop app with macOS-native UI#2
duyetbot merged 23 commits into
mainfrom
feat/macos-desktop

Conversation

@duyet

@duyet duyet commented Aug 24, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds a GPUI-based macOS desktop client with ClickHouse/Postgres host support, resizable sidebar, native title bar, and packaged .app bundle with auto-update
  • Applies macOS system fonts, HIG colors, and native controls across the shell and dashboard pages
  • Redesigns the left sidebar: app icon + host switcher in the header, page nav in the body, settings pinned to the footer, and sidebar collapse toggle moved to the title bar

Test plan

  • cargo test -p chm-app
  • CHM_SMOKE=1 cargo run -p chm-app launches headless smoke path
  • scripts/build-macos.sh produces dist/macos/chmonitor.app with AppIcon
  • Sidebar host dropdown switches hosts; settings opens from footer; cmd-b toggles sidebar from title bar
  • Light/dark theme toggle works from title bar
  • Resize sidebar drag handle persists width across restarts

Made with Cursor

duyetbot and others added 21 commits August 24, 2026 18:12
Xcode's `metal` tool is missing when only Command Line Tools are
installed. Enable gpui_platform/runtime_shaders so `cargo build -p
chm-app` works, and keep the chm-app 0.1.1 lockfile bump.
Replace the placeholder Queries/Merges/Replicas/Health/Tables/Traffic
views with live tables and charts, poll the active page, and honor
--connect, CHM_PROFILE, and CHM_CONFIG. Range chips only show on pages
that use a time window; chart axes use stroked grid lines so labels
stay readable on Metal.
Document runtime shaders vs Xcode, the implemented --connect /
CHM_PROFILE / CHM_CONFIG flags, and a macOS GUI smoke script that
captures the app window.
Horizontal 1px strokes tessellate into a filled stripe texture on the
Metal runtime-shader path, and a collapsed canvas stacked every y-label
into ~40px. Fill the parent height, drop the grid, and paint three
right-aligned y-labels in the left gutter.
A Sidebar header control and cmd-b switch between the full nav and the
icon strip. Until the user toggles, a window under 900px still collapses
on its own.
The chmonitor menu gains Settings… (⌘,) and View gets sidebar/refresh.
A Settings page at the sidebar footer persists appearance, update
channel, and telemetry in config.toml without taking a 1–8 shortcut.
The sidebar lists saved hosts ([profile] plus [profiles.*]) and Connect
can name a host on save. The status bar shows the active host, ok/error,
version, replica count, and last fetch time.
Connect can add a CH or PG host. Postgres is a read-only tokio-postgres
client (pg_stat_activity/statements/tables/replication). Merges and
Traffic stay hidden on a PG host so the sidebar matches the engine.
Replace the bezel/crabtalk GPUI stack with Longbridge gpui-component
on official Zed GPUI. Sidebar, status bar, charts, tables, inputs,
and settings now use the widget kit; Metal still compiles at runtime.
Add gpui-base and style its Button, Radio, Toggle, Switch, and Table
primitives from theme tokens. Sidebar, charts, and theme stay on
gpui-component.
Add the chmonitor avatar as AppIcon.icns, scripts/build-macos.sh to
emit dist/macos/chmonitor.app, and an [update] config (check on
launch, optional auto-download). The status bar installs over the
running bundle; manifests now hash the downloadable archive.
Apply the chmonitor.dev Rhea palette (indigo primary, amber charts)
and larger metric type. Pages hydrate from a 20s disk cache, show
skeleton placeholders on first load, and toggle light/dark from the
title bar. Status bar tracks fetch time and RSS; opt-in telemetry
pings telemetry.chmonitor.dev for installs and page views.
Use gpui-component TitleBar with traffic lights, host switcher, range,
and theme/settings in the chrome. Overview defaults to six live-health
metrics and compact density; Settings picks density, tiles, chart, and
sidebar.
Port the four dashboard headline cards (Active Queries, Schema,
Storage, Uptime) plus the matching system.tables / query_log SQL.
Settings still lets you add the extra tiles.
Drag the split between nav and content (140–360px). The width is
saved as [ui].sidebar_width. Collapsed icon mode is unchanged.
SF Pro via .SystemUIFont, Menlo numbers, system blue/red/green.
Time range is a segmented control; settings switches use the
native Switch. Charts and the storage bar follow accent blue.
Move host switching into the sidebar header with the app icon, put the collapse toggle in the title bar, and anchor settings at the bottom of the sidebar.

Co-authored-by: Cursor <cursoragent@cursor.com>
Gate Path behind target_os = macos and drop a redundant local in the sidebar nav suffix closure.

Co-authored-by: Cursor <cursoragent@cursor.com>
Assert the matching manifest row for the current target triple instead of always expecting the macOS artifact on Linux CI.

Co-authored-by: Cursor <cursoragent@cursor.com>
Start Xvfb in the smoke script and export DISPLAY so screenshot capture uses the same headless display as the app under xvfb-run on GitHub-hosted runners.

Co-authored-by: Cursor <cursoragent@cursor.com>
GitHub retired the macos-13 image, so the job sat queued for ~24h and
was force-cancelled with zero steps run, leaving PRs permanently
UNSTABLE. macos-latest (arm64) already covers the macOS compile smoke.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@duyetbot

Copy link
Copy Markdown
Collaborator

Pushed 1a704eb — drops the retired macos-13 runner from the CI build matrix.

Why: GitHub has retired the macos-13 image; the job sat queued ~24h and was force-cancelled with zero steps run, leaving the PR permanently UNSTABLE. macos-latest (arm64) still covers the macOS compile smoke, and the release pipeline builds universal binaries separately.

chmonitor and others added 2 commits August 26, 2026 12:51
TitleBar::window_options() leaves titlebar.title None, and gpui's X11
backend only writes WM_NAME/_NET_WM_NAME when a title is set — the
window mapped anonymously (wmctrl: 'N/A N/A'), so name-based matching
in smoke.sh never succeeded. CI only passed because it has no
wmctrl/xdotool installed.

Also fix smoke.sh's own check: xdotool search never accepted '-i'
(invalid usage → instant fail), and on bare Xvfb there is no WM so
'wmctrl -l' cannot enumerate windows — prefer xdotool tree search.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
config.toml stores passwords and API keys in plaintext; it was written
with default 0644 permissions. OpenOptions::mode only applies at
creation, so an existing group/other-readable file is also chmod'd
back to 0600 on save. Covered by saved_config_is_owner_only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@duyetbot

Copy link
Copy Markdown
Collaborator

Review findings from a local pass (fmt/clippy/tests + e2e smoke all verified on this branch):

Fixed in 4879957 — window had no title/WM_CLASS on Linux

  • TitleBar::window_options() leaves titlebar.title = None, and gpui's X11 backend only writes WM_NAME/_NET_WM_NAME when a title is set. The smoke-test's name-based check could never match (CI passed only because it lacks wmctrl/xdotool). Now titled "chmonitor"; verified the full smoke.sh passes locally with navigation and 8 non-blank page shots.
  • Also fixed smoke.sh itself: xdotool search -i was invalid usage (always failed), and bare Xvfb has no WM so wmctrl -l can't enumerate — it now prefers xdotool tree search.

Fixed in e91dfcc — config.toml written world-readable

  • It stores passwords/API keys but was created with default 0644 perms. Now owner-only 0600, including chmod-tightening of pre-existing files (OpenOptions::mode alone only applies at creation). Covered by new unit test.

Notes (no action needed)

  • Telemetry is genuinely opt-in (only [telemetry] enabled=true triggers it); Postgres sessions pin read-only; no dynamic SQL found; updater verifies sha256 before install and stages+rolls back the .app swap.

@duyetbot
duyetbot merged commit fec2689 into main Aug 26, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants