ProdDash Viewer 1.0.0: a Mac app that only shows ProdDash, with a tab per installation

A new Apple-silicon app in viewer/macos (Swift, no dependencies, ~1 MB): one
window showing a ProdDash dashboard in WebKit, and nothing else. It runs no
server; it points at any ProdDash on the network.

- Connections (name + address) in Settings; the add/edit sheet asks
  /api/modules whether ProdDash answers as you type. No port means 24500.
- Two or more connections bring a slim tab bar of their names. In a window
  it floats over the dashboard and comes out while the pointer is on the
  title bar; it is not part of the title bar, because anything there makes
  WebKit push the page down. In full screen it is a titlebar accessory that
  comes down with the menu bar, and it flashes up after each switch.
  ⌃Tab / ⌃⇧Tab and ⌘1–9 switch from the keyboard.
- Full screen, reopening in full screen if it quit there; window size and
  the selected tab are kept too. The dashboard's own full-screen button
  works as well.
- Menus: View (Back, Forward, Reload Page, Enter Full Screen), Settings,
  Edit (copy/paste in the page's text fields), Window, Help (a guide that
  ships in the app).
- Every installation keeps its own live web view. One that can't be
  reached says why and retries at 2, 4, 8, then every 15 s; a redirect off
  the installation is reported, not handed to the browser. JS alert,
  confirm and prompt show as sheets; links to other sites open in the
  browser.
- General settings: open at login (SMAppService), keep the display awake
  while a dashboard is on screen (default on).

build.sh signs with the Developer ID when one is installed and makes a
notarised DMG with --notarize, as the launcher's does. It needs Xcode: with
only the command line tools the macOS 27 SDK can't expand SwiftUI's @State.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Waters Church
2026-10-25 13:05:14 -04:00
co-authored by Claude Opus 5.5
parent c043834d1e
commit 8d8c0ee0c3
18 changed files with 2229 additions and 2 deletions
+121
View File
@@ -0,0 +1,121 @@
# ProdDash Viewer for macOS
A Mac app whose only job is to show ProdDash. It opens one installation's
dashboard in its own window — or several, with a slim tab bar to switch
between them — and does nothing else: no address bar, no bookmarks, no
browser to wander off in. It is for the screens that just *show* a dashboard:
a booth display, a stage-manager's laptop, a second Mac watching the other
campus.
It runs no server. ProdDash itself is installed with the menu-bar app in
[launcher/macos](../../launcher/macos); the Viewer points at that, or at any
other ProdDash on the network.
Apple silicon, macOS 13 or newer. Native Swift (AppKit with a little SwiftUI,
WebKit for the page), no dependencies, about 1 MB.
## Build
```bash
./build.sh # build/ProdDash Viewer.app
./build.sh --dmg # …and build/ProdDash-Viewer-<version>-arm64.dmg
./build.sh --install # …and copy it to /Applications
./build.sh --run # …and open it
./build.sh --notarize # with --dmg: notarise and staple (Developer ID)
```
Needs Xcode, selected with `xcode-select` — with only the command line
tools, the macOS 27 SDK can't expand SwiftUI's `@State` macro and the
compile fails. Signing and notarising work exactly as
for ProdDash's own app — a Developer ID certificate when one is installed,
ad-hoc otherwise, and the same `proddash` notarytool profile; see
[launcher/macos/README.md](../../launcher/macos/README.md#signing). The
Viewer keeps its own version number (`VERSION` in `build.sh`), since it works
with any ProdDash rather than shipping with one.
The icon is `Resources/AppIcon.png`, drawn by `Resources/make-icon.swift` —
ProdDash's tile mark on a display, so the two apps tell apart in Finder.
Run `swift Resources/make-icon.swift Resources/AppIcon.png` to redraw it.
## Using it
**Settings…** (⌘,) → **Connections** → **+**: a name (what the tab says) and
the address you open ProdDash at in a browser, such as `10.3.11.152:24500`.
Without a port, ProdDash's 24500 is assumed; a path is kept, so an address
can open a particular page. The sheet asks the address whether ProdDash is
answering as you type, but saves either way — the installation may simply be
switched off right now. Double-click a connection to change it, drag to
reorder the tabs.
With two or more connections the tab bar appears. In a window it floats over
the top of the dashboard, comes out while the pointer is on the title bar and
tucks away after; in full screen it comes down with the menu bar, and shows
for a moment after each switch. ⌃Tab / ⌃⇧Tab and ⌘1…⌘9 switch from the
keyboard. A tab marked ⚠︎ is an installation that isn't answering.
The menus are short on purpose: **View** has Back (⌘[), Forward (⌘]), Reload
Page (⌘R) and Enter Full Screen; the rest is what every Mac app has. **Edit**
is there because without it Copy and Paste do nothing in the dashboard's and
the admin page's text fields. **Help** opens the guide that ships in the app.
**Settings → General**: **Open at login**, and **Keep the display awake**
(on by default) — while a dashboard is on screen, the display doesn't dim or
sleep. Minimised, hidden or covered, it lets go.
## How it behaves
- **Every dashboard stays live.** Each connection has its own web view, kept
running behind the one on screen, so switching is instant and nothing has
to reconnect.
- **The page never jumps.** In a window the tab bar is an overlay rather than
part of the title bar: anything in the title bar makes WebKit push the
whole page down to clear it, and a dashboard re-flowing every time the bar
came and went would be worse than no bar. In full screen it *is* a title
bar accessory — there the title bar lives in a window of its own, and the
page stays put.
- **It comes back by itself.** An installation that can't be reached shows
why (nothing answering, can't be found, no network — including macOS
withholding Local Network access) and is retried at 2, 4, 8 and then every
15 seconds. Once a dashboard has loaded, ProdDash's own service worker and
reconnect logic carry it through a server restart.
- **It comes back as it was left.** The window's size and place, the tab that
was showing, and full screen: quit in full screen and it reopens in full
screen — so a booth Mac set to log in and open the Viewer at login returns
to the dashboard on its own after a restart.
- **It stays on ProdDash.** Links to the installation's own pages open in
the window; links anywhere else (a Planning Center item, the release notes)
open in the default browser, as do downloads. The page's `alert`,
`confirm` and `prompt` — the admin page confirms before deleting a layout,
Band Lineup prompts for names — show as sheets titled with the
installation's name.
- **The dashboard's own full-screen button works**, in addition to the
window's: it fills the screen with the dashboard alone; Esc leaves.
- Closing the window quits the app, as with System Settings — there is only
ever the one window.
- Safari's **Develop** menu can inspect a dashboard running in the Viewer.
## Files
```
Sources/
main.swift NSApplication, nothing else
AppDelegate.swift lifecycle and the menus
ViewerWindowController.swift the window: pages, tab bar overlay/accessory,
full screen, keyboard switching, display awake
DashboardPage.swift one connection's web view, status view, retry,
navigation policy, JavaScript dialogs
TabBar.swift the tabs (SwiftUI), shared by overlay and accessory
Connections.swift Connection, address rules, the store, the probe
ViewerSettings.swift preferences and the login item
SettingsWindowController.swift Settings: Connections and General
HelpWindowController.swift Help → ProdDash Viewer Help
Resources/
Info.plist bundle id org.waterschurch.proddash.viewer
Help/index.html the guide shown by the Help menu
AppIcon.png, make-icon.swift the icon and what draws it
```
Preferences live in `~/Library/Preferences/org.waterschurch.proddash.viewer.plist`
(connections, the selected tab, full screen, keep awake); the web views'
storage — each dashboard's own per-browser settings — in WebKit's default
store for the app.