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:
parent
789b74219e
commit
98a1155635
3 changed files with 58 additions and 41 deletions
42
.github/CONTRIBUTING.md
vendored
42
.github/CONTRIBUTING.md
vendored
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue