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
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:
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.
Small fixes, bug reports, and minor improvements are always welcome -- just open a PR.
## Prerequisites
- Node.js 20+
- pnpm 10+
- macOS or Windows
- macOS, Windows, or Linux
## Setup
```bash
@ -39,12 +28,16 @@ pnpm test
pnpm build
```
Or all at once:
```bash
pnpm check
```
## 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.
- Update docs when changing public behavior or setup.
- 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.
## AI-Assisted Contributions
@ -52,15 +45,14 @@ pnpm build
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.
- **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.
- **Test it yourself.** AI-generated code must be manually verified run the app, confirm the feature works, check edge cases.
- **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.
- **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
- Personal planning/workflow artifacts (AI session plans, task lists, etc.)
- Large static data that could be fetched at runtime
- Generated files that aren't part of the build output
- Experimental features without prior discussion
## Commit Style
- 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
Please include:
- OS version
- app version / commit hash
- repro steps
- expected vs actual behavior
- logs/screenshots when possible
- App version / commit hash
- Repro steps
- Expected vs actual behavior
- Logs/screenshots when possible

View file

@ -2088,6 +2088,22 @@ export const TeamDetailView = ({ teamName }: TeamDetailViewProps): React.JSX.Ele
.getState()
.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>
)}

View file

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