Files
multica/packages/views/common
Naiyuan Qing 281779330e feat(chat): no-agent disabled state with onboarding fix and editor cleanup (#1919)
* fix(onboarding): refresh agent cache after import and agent creation

Two paths could leave the workspace agent-list query cache stale by the
time the dashboard rendered the welcome issue, causing the issue's
agent assignee to resolve to "Unknown Agent":

1. StarterContentPrompt.onImport invalidated pins/projects/issues but
   not agents, and didn't await any of them before navigating — so the
   issue-detail page could mount and read the cache before TanStack
   Query had marked the relevant queries stale.
2. OnboardingFlow.handleAgentCreated created the agent without
   invalidating the agent list, so the dashboard's first mount would
   read whatever was already cached from earlier in onboarding.

Both now invalidate workspaceKeys.agents, and the import flow awaits
all invalidations via Promise.all before pushing the navigation, so
the next page mount always refetches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(editor): drop editable prop, ContentEditor is editing-only

ContentEditor's `editable` prop had zero true callsites left in the
codebase — every read-only surface had migrated to ReadonlyContent
(react-markdown), and the prop only invited misuse: Tiptap's
`useEditor` reads `editable` at mount, so callers that toggled it
post-mount (like a chat input that needs to disable on no-agent)
silently got stuck in whichever mode the editor first created.

Changes:
- Remove `editable` prop and default; useEditor and createEditorExtensions
  no longer take it.
- Remove the `"readonly"` className branch and the readonly content sync
  useEffect (only the editing path remains).
- Remove the BubbleMenu and mouseDown editable guards.
- Drop LinkReadonly; rename LinkEditable to LinkExtension and use it
  unconditionally.
- Update the docstring to point readers at ReadonlyContent for display
  surfaces.

ReadonlyContent's `.readonly` CSS class stays in content-editor.css —
that file's selectors are still used by react-markdown's wrapper.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(chat): empty-state by session history, no-agent disabled state

Three independent improvements to the chat window's pre-conversation
states, sharing a new three-state availability primitive:

1. New `useWorkspaceAgentAvailability()` hook (`"loading" | "none" |
   "available"`) so callers don't have to reinvent the loading-vs-empty
   distinction. Treating loading as "no agent" — the easy mistake —
   caused the chat input to flash a fake disabled state for the few
   hundred ms after mount, even when the workspace had agents.
2. EmptyState now branches on session history, not agent presence:
   never-chatted users get a short pitch ("They know your workspace —
   issues, projects, skills"), returning users get the existing
   starter prompts. Missing-agent feedback moved to the banner above
   the input, keeping this surface focused on "what is chat for".
3. No-agent disabled state: when availability resolves to "none",
   ChatInput dims and stops responding to clicks/keys, with cursor
   `not-allowed` on hover. The disable lives at the wrapper level
   (`pointer-events-none` on the inner card, `cursor-not-allowed` on
   the outer one — splitting layers so hover bubbles to where the
   browser reads cursor) — we no longer reach into the editor's
   editable mode, which never switched cleanly post-mount anyway.
   A `<NoAgentBanner>` (sibling of OfflineBanner, mutually exclusive)
   states the prerequisite without linking out — no one should be
   pulled out of chat mid-thought to a settings page.

Also: default chat width 420 → 380, since the chat docks at the
bottom-right and 420 was crowding everything else.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(views): align PropRow labels using CSS subgrid

The fixed `w-16` (64px) label column on PropRow broke whenever a label
rendered wider than 64px (e.g. "Concurrency" in the agent inspector) —
the label would overflow into the gap and collide with the value.

Switch to subgrid: the parent declares `grid grid-cols-[auto_1fr]` and
each PropRow becomes `col-span-2 grid grid-cols-subgrid`. The `auto`
track sizes to the widest label across all rows in that parent, so
labels always fit and value columns stay aligned across rows without
picking a magic pixel width.

Updated parents:
- agent-detail-inspector Section wrapper
- issue-detail Properties group

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 11:32:35 +08:00
..