feat(graph): wire popover actions to real dialogs (Message, Open task/member)

- TeamGraphOverlay accepts onSendMessage, onOpenTaskDetail, onOpenMemberProfile
- TeamDetailView passes dialog openers to overlay:
  - Message → opens SendMessageDialog with recipient pre-filled
  - Open (task) → opens TaskDetailDialog with task found by ID
  - Open (member) → opens SendMessageDialog for that member
  - Double-click → same as Open
- Removed console.log stubs
This commit is contained in:
iliya 2026-03-28 12:56:43 +02:00
parent 789b74219e
commit 98a1155635
3 changed files with 58 additions and 41 deletions

View file

@ -1,28 +1,17 @@
# Contributing # Contributing
Thanks for contributing to Claude Agent Teams UI. Thanks for contributing to Claude Agent Teams UI!
## Project Philosophy & Scope ## Before You Start
claude-devtools exists to make the invisible parts of Claude Code visible — the token flows, context injections, tool executions, and session dynamics that are otherwise hidden behind the CLI. It is not a general-purpose dashboard or an IDE. For big features and major changes, please discuss them in our [Discord](https://discord.gg/RgBHMBsn) first so we can figure out the best approach together and avoid conflicts.
Our priorities: Small fixes, bug reports, and minor improvements are always welcome -- just open a PR.
1. **Parity with Claude Code** — When Claude Code ships new capabilities (agent teams, context tracking, new tool types), we adopt them quickly so users always have full visibility.
2. **Context engineering insight** — Features that help users understand *what* is consuming their context window, *how* tokens flow through a session, and *where* to optimize. If it doesn't help someone make better decisions about their Claude Code usage, it probably doesn't belong here.
3. **Stability over novelty** — A reliable, fast tool for professional workflows. We'd rather do fewer things well than many things poorly.
**What we generally do not accept:**
- Large custom features that don't directly serve context visibility or Claude Code parity.
- Speculative features that add maintenance burden without solving a concrete problem users face today.
- PRs that significantly expand scope without prior discussion in an Issue.
If you're considering a non-trivial contribution, **open an Issue first** to check alignment with the current roadmap. This saves everyone time and keeps the project focused.
## Prerequisites ## Prerequisites
- Node.js 20+ - Node.js 20+
- pnpm 10+ - pnpm 10+
- macOS or Windows - macOS, Windows, or Linux
## Setup ## Setup
```bash ```bash
@ -39,12 +28,16 @@ pnpm test
pnpm build pnpm build
``` ```
Or all at once:
```bash
pnpm check
```
## Pull Request Guidelines ## Pull Request Guidelines
- Keep changes focused and small — one purpose per PR. - Keep changes focused and small -- one purpose per PR.
- Add/adjust tests for behavior changes. - Add/adjust tests for behavior changes.
- Update docs when changing public behavior or setup. - Update docs when changing public behavior or setup.
- Use clear PR titles and include a short validation checklist. - Use clear PR titles and include a short validation checklist.
- **Large changes (new features, new dependencies, large data additions) must have a discussion in an Issue first.** Do not open a large PR without prior agreement on the approach.
- Avoid committing large hardcoded data blobs. If data can be fetched at runtime or generated at build time, prefer that approach. - Avoid committing large hardcoded data blobs. If data can be fetched at runtime or generated at build time, prefer that approach.
## AI-Assisted Contributions ## AI-Assisted Contributions
@ -52,15 +45,14 @@ pnpm build
AI coding tools are welcome, but **you are responsible for what you submit**: AI coding tools are welcome, but **you are responsible for what you submit**:
- **Review before submitting.** Read every line of AI-generated code and understand what it does. Do not submit raw, unreviewed AI output. - **Review before submitting.** Read every line of AI-generated code and understand what it does. Do not submit raw, unreviewed AI output.
- **Do not commit AI workflow artifacts.** Planning documents, session logs, step-by-step plans, or other outputs from AI tools (e.g. `docs/plans/`, `.speckit/`, etc.) do not belong in the repository. - **Do not commit AI workflow artifacts.** Planning documents, session logs, step-by-step plans, or other outputs from AI tools do not belong in the repository.
- **Test it yourself.** AI-generated code must be manually verified run the app, confirm the feature works, check edge cases. - **Test it yourself.** AI-generated code must be manually verified -- run the app, confirm the feature works, check edge cases.
- **Keep it intentional.** Every line in your PR should exist for a reason you can explain. If you can't explain why a piece of code is there, remove it. - **Keep it intentional.** Every line in your PR should exist for a reason you can explain. If you can't explain why a piece of code is there, remove it.
## What Does NOT Belong in the Repo ## What Does NOT Belong in the Repo
- Personal planning/workflow artifacts (AI session plans, task lists, etc.) - Personal planning/workflow artifacts (AI session plans, task lists, etc.)
- Large static data that could be fetched at runtime - Large static data that could be fetched at runtime
- Generated files that aren't part of the build output - Generated files that aren't part of the build output
- Experimental features without prior discussion
## Commit Style ## Commit Style
- Prefer conventional commits (`feat:`, `fix:`, `chore:`, `docs:`). - Prefer conventional commits (`feat:`, `fix:`, `chore:`, `docs:`).
@ -69,7 +61,7 @@ AI coding tools are welcome, but **you are responsible for what you submit**:
## Reporting Bugs ## Reporting Bugs
Please include: Please include:
- OS version - OS version
- app version / commit hash - App version / commit hash
- repro steps - Repro steps
- expected vs actual behavior - Expected vs actual behavior
- logs/screenshots when possible - Logs/screenshots when possible

View file

@ -2088,6 +2088,22 @@ export const TeamDetailView = ({ teamName }: TeamDetailViewProps): React.JSX.Ele
.getState() .getState()
.openTab({ type: 'graph', label: `${data.config.name} Graph`, teamName }); .openTab({ type: 'graph', label: `${data.config.name} Graph`, teamName });
}} }}
onSendMessage={(memberName) => {
setSendDialogRecipient(memberName);
setSendDialogDefaultText(undefined);
setSendDialogDefaultChip(undefined);
setSendDialogOpen(true);
}}
onOpenTaskDetail={(taskId) => {
const task = data.tasks.find((t) => t.id === taskId);
if (task) setSelectedTask(task);
}}
onOpenMemberProfile={(memberName) => {
setSendDialogRecipient(memberName);
setSendDialogDefaultText(undefined);
setSendDialogDefaultChip(undefined);
setSendDialogOpen(true);
}}
/> />
</Suspense> </Suspense>
)} )}

View file

@ -15,32 +15,41 @@ export interface TeamGraphOverlayProps {
teamName: string; teamName: string;
onClose: () => void; onClose: () => void;
onPinAsTab?: () => void; onPinAsTab?: () => void;
onSendMessage?: (memberName: string) => void;
onOpenTaskDetail?: (taskId: string) => void;
onOpenMemberProfile?: (memberName: string) => void;
} }
export const TeamGraphOverlay = ({ export const TeamGraphOverlay = ({
teamName, teamName,
onClose, onClose,
onPinAsTab, onPinAsTab,
onSendMessage,
onOpenTaskDetail,
onOpenMemberProfile,
}: TeamGraphOverlayProps): React.JSX.Element => { }: TeamGraphOverlayProps): React.JSX.Element => {
const graphData = useTeamGraphAdapter(teamName); const graphData = useTeamGraphAdapter(teamName);
const events: GraphEventPort = { const events: GraphEventPort = {
onNodeClick: useCallback((_ref: GraphDomainRef) => { onNodeDoubleClick: useCallback(
// Popover shown by GraphView internally (ref: GraphDomainRef) => {
}, []), if (ref.kind === 'task') onOpenTaskDetail?.(ref.taskId);
onNodeDoubleClick: useCallback((ref: GraphDomainRef) => { else if (ref.kind === 'member') onOpenMemberProfile?.(ref.memberName);
// TODO: open TaskDetailDialog or MemberDetailDialog based on ref.kind },
console.log('Double-click:', ref); [onOpenTaskDetail, onOpenMemberProfile]
}, []), ),
onSendMessage: useCallback((_memberName: string, _teamName: string) => { onSendMessage: useCallback(
// TODO: open SendMessageDialog (memberName: string) => onSendMessage?.(memberName),
}, []), [onSendMessage]
onOpenTaskDetail: useCallback((_taskId: string, _teamName: string) => { ),
// TODO: open TaskDetailDialog onOpenTaskDetail: useCallback(
}, []), (taskId: string) => onOpenTaskDetail?.(taskId),
onBackgroundClick: useCallback(() => { [onOpenTaskDetail]
// Deselect handled by GraphView ),
}, []), onOpenMemberProfile: useCallback(
(memberName: string) => onOpenMemberProfile?.(memberName),
[onOpenMemberProfile]
),
}; };
return ( return (