Skip to content

feat(web): create, rename and delete graphs on phones (#277) - #288

Open
mvalancy wants to merge 3 commits into
devfrom
feat/phone-graph-management
Open

mvalancy wants to merge 3 commits into
devfrom
feat/phone-graph-management

Conversation

@mvalancy

Copy link
Copy Markdown
Member

On a phone you couldn't create, rename or delete a graph. The phone's top-bar graph selector (graph-selector-mobile) only switched between graphs:

  • it had no "Create New Graph";
  • its edit and delete buttons showed only on hover, and touch screens never send hover.

The journeys worked around this by creating their phone graph through the API (noted in #281).

Changes

  • Selector actions: the phone selector now asks Workspace, which owns the graph dialogs, to create, edit or delete. It does this with window events (lib/graphRequests.ts), the same way its "New work item" button already does. The phone top bar only renders on the workspace route, so a request always has a listener.
  • Touch screens (@media (hover: none)):
    • the edit and delete buttons always show;
    • they have larger tap targets;
    • they have accessible names such as "Edit Ideas" and "Delete Ideas".
  • Journeys: enterWorkspace creates the journey's graph through the visible selector on every device, so phone journeys use the real dialog. This replaces fix: relationship editor follows the saved relationship through type changes and flips (#262) #281's API workaround.
  • UI Fit gains graph-list and graph-create screens on every device.

Tests

  • graphRequests.test.ts: requests reach the workspace, stop once it unmounts, and an edit or delete with no graph is ignored.
  • GraphSelector.test.tsx: the phone selector's Edit, Delete and Create reach the workspace with the picked graph.
  • Unit tests pass 7/7. tsc is clean, and the lint counts match dev's.
  • I checked that Tailwind compiles the [@media(hover:none)] variants.
  • CI's UI Fit runs the new screens on iPhone, iPad and desktop. The relationship-edit journeys now create their phone graph through this path.

🤖 Generated with Claude Code

The phone's top-bar graph selector only switched graphs: it had no Create
New Graph, and its edit and delete buttons appeared only on hover, which
touch screens never send. A person on a phone could not make, rename or
delete a graph at all (journeys made theirs through the API).

- The phone selector now asks Workspace, which owns the graph dialogs, to
  create, edit or delete through window events (lib/graphRequests.ts),
  like its New work item button already does.
- On touch screens (hover: none) the edit and delete buttons always show,
  with larger tap targets and accessible names ("Edit Ideas").
- enterWorkspace creates the journey's graph through the selector on every
  device, so phone journeys use the real dialog instead of the API.
- UI Fit gains graph-list and graph-create screens on every device.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🧪 Comprehensive Test Suite

  • Unit suites (Node 22.18.0 & 24.x) — core, web, server, mcp-server: ✅ passed
  • Installer & deploy config: ✅ passed

Full-stack smoke gate runs in the CI workflow.

@mvalancy

Copy link
Copy Markdown
Member Author

Independent review (babf3f8)

vitest run src/lib/graphRequests.test.ts src/components/GraphSelector.test.tsx passes 7/7. No browsers were run, and UI Fit and the Smoke Gates were still pending when I checked.

Checked, no problem found

  • The bridge's [] deps are fine. openCreateGraph, openEditGraph and openDeleteGraph only call useState setters, whose identity React keeps stable, so the first render's closures never go stale.
  • No double handling. / and /workspace are separate routes, so only one Workspace is mounted at a time, and StrictMode's extra mount cleans up before it subscribes again. Layout renders the phone top bar only on those two routes, so no request is sent without a listener.
  • Desktop looks the same. Mouse devices match hover: hover, so the [@media(hover:none)] variants don't apply; the only desktop change is the new aria-label, which is an improvement. Using aria-disabled rather than disabled is the right choice, since it keeps the button focusable so the reason can be shown.

Findings

  1. must-fix: on phones the graph dialogs open underneath the top bar and bottom nav.
    • Cause: CreateGraphModal, UpdateGraphModal and DeleteGraphModal render inside Workspace, which sits in Layout's relative z-20 content wrapper. That wrapper is a stacking context, so their z-[9999] only counts inside it. The phone top bar (.mobile-project-header) and MobileBottomNav are both relative z-30 outside it, so they paint, and take taps, above the dialog.
    • What users see: on phones the panel is 100dvh tall with no padding. In portrait the dialog's header and Close button sit under the top bar, and its footer (Continue / Create Graph, and the Save and Delete buttons) under the bottom nav. In landscape the 52 px nav rail also covers the dialog's left edge.
    • History: test(mobile): automated mobile-UI audit system (layout / contrast / dialogs) in CI #86 hit this same trap with CreateWorkItemModal and fixed it with createPortal(document.body).
    • What will fail: expect UI Fit graph-create on iPhone to fail center-hit, and phone enterWorkspace clicks to fail with "intercepts pointer events". Rename and Delete have no UI Fit screen, and the create-graph check in tests/e2e/ui/z-order.spec.ts runs on desktop only.
    • Fix: portal all three dialogs to document.body, and add UI Fit screens for Rename and Delete.
  2. should-fix: tapping a greyed-out button on a system graph gives no visible reason (GraphSelector.tsx:169).
    • The lock tooltip appears on mouseenter, which a phone fires on tap, at left: rect.right + 8. On a phone the action buttons sit about 12 px from the right edge of the screen, so the whitespace-nowrap tooltip starts at the edge and is drawn off-screen.
    • The tooltip is also never cleared until something else is tapped.
    • Fix: flip or clamp the tooltip so it stays on screen, or show the reason on click as well. Exposing it through aria-describedby would also let screen-reader users hear why the button is unavailable; today they only hear "Edit Welcome, dimmed".
  3. nit: the action buttons on touch screens are 34×34 px (p-2.5 plus a 14 px icon). That meets the 24 px gate but shows up in the touch-comfort report; the other phone controls use min-h-[44px] min-w-[44px].
  4. nit: the comment at tests/lib/journeys/workspace.ts:10-11 still says phones "cannot create a graph, get it from the API". The gql import there is still used by line 101.

🤖 Generated with Claude Code

…on a tap

Review of #288:
- Create, Edit and Delete graph dialogs render in document.body. Inside the
  layout's z-20 content wrapper the phone top bar and bottom nav (z-30)
  drew over them and took their taps (the trap CreateWorkItemModal hit in
  #86).
- Edit and Delete graph dialogs get role=dialog, a name and a focus trap
  (useModalA11y), like Create.
- A locked button (another user's Welcome) explains itself on a tap too,
  fading after 2.5 s, on its left when the right edge is near, and to
  screen readers (aria-describedby).
- Touch action buttons are 44 x 44 px.
- UI Fit gains graph-edit and graph-delete screens on every device.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mvalancy

Copy link
Copy Markdown
Member Author

Thanks. All four findings are addressed in 42d7d0c:

  1. must-fix, dialogs under the phone bars: CreateGraphModal, UpdateGraphModal and DeleteGraphModal now render into document.body with createPortal, as CreateWorkItemModal does since test(mobile): automated mobile-UI audit system (layout / contrast / dialogs) in CI #86.
    • Edit and Delete also get useModalA11y: role="dialog", the names "Edit graph" and "Delete graph", focus on open and a focus trap.
    • UI Fit gains graph-edit and graph-delete screens next to graph-list and graph-create, on every device (24 checks).
  2. should-fix, locked reason off-screen and silent:
    • A tap on a locked button now shows the reason and fades it after 2.5 s.
    • The reason sits on the button's left when there isn't room on the right.
    • It's also exposed through aria-describedby.
    • Tests cover the tap, the left placement and the description.
  3. nit, small touch targets: touch buttons are 44×44 px (p-[15px] around the 14 px icon).
  4. nit, stale comment: the comment in workspace.ts is updated.

GraphSelector and graphRequests tests pass 9/9. tsc is clean, and the lint warnings on the changed files match dev's count (31, no errors).

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown

🧪 Comprehensive Test Suite

  • Unit suites (Node 22.18.0 & 24.x) — core, web, server, mcp-server: ❌ failure
  • Installer & deploy config: ✅ passed

Full-stack smoke gate runs in the CI workflow.

The Edit and Delete graph dialogs now use useModalA11y, and the unit tests
that render DeleteGraphModal (jsdom) have neither API. Without them the
dialog is still positioned on window resize and treated as not compact,
which also covers older browsers. Web unit tests: 692/692.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🧪 Comprehensive Test Suite

  • Unit suites (Node 22.18.0 & 24.x) — core, web, server, mcp-server: ✅ passed
  • Installer & deploy config: ✅ passed

Full-stack smoke gate runs in the CI workflow.

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.

1 participant