Files
box/docs/DOM-SETTINGS.md
T

283 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DOM Reference: Settings, Profile & Dock Rail
> **Box is the main surface.** All operator work goes through Box (box.muse-dev.online). The web UI, `box` CLI, and agents share the same API endpoints. No UI-only powers.
Inspected live via CDP on the opm browser (warp-opm netns, CDP 9440), 2026-10-04.
Re-verified 2026-10-04 across all three fleet nodes (muse 9410, pip 9420, opm 9440).
Structure only — no credential, token, or personal values are recorded here.
Related: `DOM-CHAT-PANEL.md` (chat panel), `DOM-MESSAGES.md` (messages),
`DOM-PAGE-STRUCTURE.md` (page states).
---
## 1. Dock rail
The left vertical nav rail. Container:
```html
<div data-testid="hatch-dock-rail" class="relative flex h-full">
```
### Rail items (top to bottom)
| # | Selector | Tag | `aria-label` | `data-pel-click` | Notes |
|---|----------|-----|--------------|------------------|-------|
| 1 | `[data-testid="hatch-nav-chat"]` | `<a href="/">` | `Chat` (unstable — see notifications doc) | `chat_tab_click` | The chat/message button from the user's screenshot. Navigates `/thread/new` → `https://muse.ai/`. See "chat activation" below. |
| 2 | `[data-testid="hatch-nav-search"]` | `<button>` | `Search` | `quick_search_nav_click` | Opens quick-search dialog `[data-testid="hatch-quick-search-frame"]` (heading "Search Muse"). |
| 3 | *(none)* | `<button>` | `Get the Muse app` | `mobile_app_upsell_click` | App download upsell. No `data-testid`. |
| 4 | `[data-testid="hatch-dock-more"]` | `<button>` | `Settings` | `settings_menu_open_click` | Opens the settings menu (radix menu). Bottom of rail (`div.mt-auto`). |
Mid-rail system items (verified 2026-10-04, all three nodes) — `DIV`s, not
buttons, between the search button and the app upsell:
| `data-testid` | `aria-label` |
|---|---|
| `hatch-nav-system-item-66656564` | `Feed` |
| `hatch-nav-system-item-6964656173` | `Ideas` |
| `hatch-nav-system-item-676f616c73` | `Goals` |
| `hatch-nav-system-item-6c696272617279` | `Library` |
(The hex suffixes decode to ascii: `feed`, `ideas`, `goals`, `library`.)
Parent chain of the settings button (4 levels):
```
div[data-testid="hatch-dock-rail"].relative.flex.h-full
> div.relative.z-10.flex
> div.mt-auto.flex.flex-col
> button#radix-_[data-testid="hatch-dock-more"].hatch-dock-reveal-item.group.relative
```
Key attributes on the button:
```html
<button type="button"
aria-label="Settings"
data-testid="hatch-dock-more"
aria-haspopup="menu"
aria-expanded="false" <!-- RELIABLE after 2026-10-04 re-verify: "true" when menu open -->
data-state="closed" <!-- unreliable: stays "closed" even when menu is open -->
data-pel-click="settings_menu_open_click">
```
> **Automation note (updated 2026-10-04):** `data-state` does NOT reflect the
> real open state (stays `"closed"`). `aria-expanded`, however, **does**:
> verified `"true"` on opm with the menu open (earlier claim that it stays
> `"false"` was wrong — possibly a timing artifact). Belt and braces: detect
> the open menu by counting `[role="menuitem"]` elements (`> 0` means open). Synthetic `.click()` does not open the radix menu;
> use real mouse events via CDP `Input.dispatchMouseEvent`
> (`mousePressed` + `mouseReleased` at the button center). The button toggles,
> so click only when `[role="menuitem"]` count is 0.
### Chat activation via `hatch-nav-chat`
Clicking `[data-testid="hatch-nav-chat"]` from the stripped `/thread/new` state
navigates to `https://muse.ai/` and the chat switcher appears (~1s). This is
the reliable "activate chat" primitive — see the `_ensure_chat_active()`
logic in `muse-chat-api.py` (priority: compose → switcher → nav-chat).
`aria-label` on this link is unstable (`"Chat"` vs `"Chat, N notification"`);
always match on the `data-testid`.
---
## 2. Settings menu (dock "more" menu)
Radix menu rendered in a popper. Items are **`DIV`s with `role="menuitem"`**
(verified 2026-10-04 — not buttons), no `data-testid`:
| Text | `data-pel-click` | Action (observed) |
|------|------------------|-------------------|
| Keyboard shortcuts | `keyboard_shortcuts_nav_click` | No dialog under automation (see §5) |
| Download apps | `mobile_app_upsell_menu_click` | — (not opened) |
| Report an issue | `bug_report_nav_click` | — (not opened) |
| Settings | `settings_nav_click` | Opens the Settings dialog (§3) |
Menu container selectors (either may match):
```javascript
document.querySelector('[role="menu"]')
document.querySelector('[data-radix-popper-content-wrapper]')
```
Find a menuitem reliably:
```javascript
[...document.querySelectorAll('[role="menuitem"]')]
.find(m => m.getAttribute('data-pel-click') === 'settings_nav_click')
```
---
## 3. Settings dialog
A radix dialog (`div[role="dialog]"`, id like `radix-_r_10g_`; the id suffix
is random per render — do not hardcode it).
```
div#radix-_<role=dialog>
```
- Heading is an **`H2`** with text `Settings` (not `h1`).
- Layout: left nav column + right content column.
### 3a. Left nav (section buttons)
Plain `<button>` elements, no `data-testid`s. In order:
```
General
Connectors
Wallet
Secure store
Permissions
Messaging channels
Devices
Data controls
Help & support
Legal info
Log out ← the sign-out control; no confirmation dialog observed at open
Close
```
### 3b. General section
Headings (all `h2`, in order): `General`, `Meta Account`, `Usage`, `Appearance`.
**Meta Account** — row labeled `Password, security, personal details`
(structure only; not opened).
**Usage** — plan and quota rows (structure only, values not recorded):
| Row | Notes |
|-----|-------|
| Plan name + weekly reset line | e.g. plan tier + "Weekly limit resets on <date>" |
| Usage bar(s) with percentage | at least two bars observed (weekly + additional) |
| `Upgrade` button | `data-pel-click="settings_general_upgrade_click"` |
| `Language` | control follows the usage block |
**Appearance** — theme + accent color:
| Control | Label source | Selection state |
|---------|--------------|-----------------|
| `<button aria-label="Light">` | `aria-label` (icon-only, no text) | `aria-pressed` |
| `<button aria-label="Dark">` | `aria-label` | `aria-pressed` |
| `<button aria-label="System">` | `aria-label` | `aria-pressed="true"` on opm (verified) |
| 9× `<input type="radio">` | **`aria-label`**, not innerText | `checked` |
Radio `aria-label`s in order: `Match my avatar` (checked on opm), `Default`,
`Blue`, `Purple`, `Pink`, `Orange`, `Green`, `Beige`, `Monochrome`.
All share one radio group (`name` is random per render, e.g. `_r_184_`).
### 3c. Profile / avatar
- Avatar image: `<img>` with empty `alt`, `src` present (value not recorded).
No `data-testid` on the img.
- `Edit avatar and name` button (`aria-label="Edit avatar and name"`,
`<button>`, no `data-testid`, id is a random `radix-_R_…` value).
> **Correction 2026-10-04:** the button is **not a descendant of
> `div[role="dialog"]`**. While the settings dialog is open it renders as a
> sibling overlay inside `[data-testid="hatch-status-panel-sliding-surface"]`
> (nearest testid ancestor at depth 10; button rect ≈ (622,141), 32×32 on a
> 780px-wide viewport). It appears only while the dialog is open and is gone
> after Escape. **Match it by `aria-label`, never by dialog containment.**
> The 3-level parent chain below is still accurate:
```
```
div.pointer-events-auto.absolute.z-20
> div.group-has-[[data-hatch-avatar-media-loading]]/status-avatar:hidden
> span.contents
> button[aria-label="Edit avatar and name"].inline-flex.shrink-0.cursor-pointer
```
### 3d. Other sections (not opened)
`Connectors`, `Wallet`, `Secure store`, `Permissions`, `Messaging channels`,
`Devices`, `Data controls`, `Help & support`, `Legal info` were not opened
during mapping (each is a left-nav `<button>`; clicking one swaps the right
content column). `Secure store` / `Wallet` likely contain credential-adjacent
UI — map with care, structure only, never values.
---
## 4. Account switching
**No multi-account switcher was observed** in the settings dialog or dock
rail. The only account control found is the `Log out` button in the settings
left nav. Each Muse account runs in its own isolated browser profile
(`muse`, `pip`, `646`, `opm` nodes), so in this fleet account switching
happens at the profile level, not inside the app UI.
---
## 5. Keyboard shortcuts modal
Menu item exists:
```javascript
[...document.querySelectorAll('[role="menuitem"]')]
.find(m => m.getAttribute('data-pel-click') === 'keyboard_shortcuts_nav_click')
```
Clicking it via automation (menuitem `.click()` after opening the dock menu
with real mouse events) produced **no `[role="dialog"]`** within 3s and no
URL change. Re-tested 2026-10-04 with **real mouse events**
(`Input.dispatchMouseEvent` press+release on the menuitem): still no dialog
within 3s; the menu simply closes. The menuitem carries no kbd hint in its
markup (icon SVG + text "Keyboard shortcuts" only).
**Status: selector documented, modal content not captured** — needs a headed/manual pass.
---
## 6. Quick reference: reliable selectors
```javascript
// Dock rail
'[data-testid="hatch-dock-rail"]'
'[data-testid="hatch-nav-chat"]' // chat button (stable; aria-label unstable)
'[data-testid="hatch-nav-search"]' // search
'[data-testid="hatch-dock-more"]' // settings menu trigger
// Settings menu (after real mouse click on hatch-dock-more)
'[role="menuitem"]' // count > 0 => menu open
'[data-pel-click="settings_nav_click"]'
'[data-pel-click="keyboard_shortcuts_nav_click"]'
'[data-pel-click="bug_report_nav_click"]'
'[data-pel-click="mobile_app_upsell_menu_click"]'
// Settings dialog
'div[role="dialog"]' // id is random per render
'button[aria-label="Edit avatar and name"]'
// Search dialog
'[data-testid="hatch-quick-search-frame"]'
```
## 7. Automation recipes
**Open the settings menu:**
```javascript
// 1. real mouse click at button center (synthetic .click() does NOT work)
const b = document.querySelector('[data-testid="hatch-dock-more"]');
const r = b.getBoundingClientRect();
// CDP: Input.dispatchMouseEvent mousePressed + mouseReleased at (r.x + r.width/2, r.y + r.height/2)
// 2. verify: document.querySelectorAll('[role="menuitem"]').length > 0
// (the button toggles — only click when count is 0)
```
**Open the Settings dialog:**
```javascript
[...document.querySelectorAll('[role="menuitem"]')]
.find(m => m.getAttribute('data-pel-click') === 'settings_nav_click')
.click();
// dialog appears in ~2s: document.querySelector('div[role="dialog"]')
// heading: [...document.querySelectorAll('h2')].find(h => h.innerText.trim() === 'Settings')
```
**Close any dialog:** `Escape` keydown (works for the settings dialog).