feat(composer): context chip previews with inline comment editing
Hovering (or tapping) a context chip opens a stacked preview of its pending items above the composer: numbered entries with a muted header band, the captured selection, and the user's comment, which can be edited in place (save/cancel) or removed before sending. The chips component now subscribes to the draft store itself; the per-kind count plumbing in ChatInput is gone.
This commit is contained in:
@@ -752,55 +752,8 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({
|
||||
[inlineDraftKey]
|
||||
)
|
||||
);
|
||||
const draftSourceKey = useInlineCommentDraftStore(
|
||||
React.useCallback(
|
||||
(state) => {
|
||||
const drafts = inlineDraftKey ? (state.drafts[inlineDraftKey] ?? []) : [];
|
||||
let previewAnnotation = 0;
|
||||
let review = 0;
|
||||
let terminal = 0;
|
||||
let prComment = 0;
|
||||
let prCheck = 0;
|
||||
let chatQuote = 0;
|
||||
for (const draft of drafts) {
|
||||
if (draft.source === 'preview-annotation') previewAnnotation += 1;
|
||||
else if (draft.source === 'terminal') terminal += 1;
|
||||
else if (draft.source === 'pr-comment') prComment += 1;
|
||||
else if (draft.source === 'pr-check') prCheck += 1;
|
||||
else if (draft.source === 'chat-quote') chatQuote += 1;
|
||||
else review += 1;
|
||||
}
|
||||
return `${previewAnnotation}:${review}:${terminal}:${prComment}:${prCheck}:${chatQuote}`;
|
||||
},
|
||||
[inlineDraftKey]
|
||||
)
|
||||
);
|
||||
const consumeDrafts = useInlineCommentDraftStore((state) => state.consumeDrafts);
|
||||
const removeInlineCommentDraft = useInlineCommentDraftStore((state) => state.removeDraft);
|
||||
const hasDrafts = draftCount > 0;
|
||||
const [previewAnnotationCount, reviewCount, terminalContextCount, prCommentCount, prCheckCount, chatQuoteCount] = draftSourceKey.split(':').map((entry) => Number(entry) || 0);
|
||||
const terminalContextDrafts = terminalContextCount > 0
|
||||
? (inlineDraftKey ? useInlineCommentDraftStore.getState().drafts[inlineDraftKey] ?? [] : []).filter((draft) => draft.source === 'terminal')
|
||||
: [];
|
||||
const removePreviewDrafts = React.useCallback((source: 'preview-annotation' | 'pr-comment' | 'pr-check' | 'chat-quote') => {
|
||||
if (!inlineDraftTarget) return;
|
||||
const drafts = useInlineCommentDraftStore.getState().getDrafts(inlineDraftTarget);
|
||||
for (const draft of drafts) {
|
||||
if (draft.source === source) {
|
||||
removeInlineCommentDraft(inlineDraftTarget, draft.id);
|
||||
}
|
||||
}
|
||||
}, [inlineDraftTarget, removeInlineCommentDraft]);
|
||||
// Review comments are the inline-comment drafts that aren't preview sources.
|
||||
const removeReviewDrafts = React.useCallback(() => {
|
||||
if (!inlineDraftTarget) return;
|
||||
const drafts = useInlineCommentDraftStore.getState().getDrafts(inlineDraftTarget);
|
||||
for (const draft of drafts) {
|
||||
if (draft.source !== 'preview-annotation' && draft.source !== 'terminal' && draft.source !== 'pr-comment' && draft.source !== 'pr-check' && draft.source !== 'chat-quote') {
|
||||
removeInlineCommentDraft(inlineDraftTarget, draft.id);
|
||||
}
|
||||
}
|
||||
}, [inlineDraftTarget, removeInlineCommentDraft]);
|
||||
|
||||
// User message history for up/down arrow navigation.
|
||||
// Keep this on a narrow hook instead of full session message records.
|
||||
@@ -2661,16 +2614,7 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({
|
||||
<AutoReviewBanner />
|
||||
{hasDrafts ? (
|
||||
<ComposerContextChips
|
||||
terminalDrafts={terminalContextDrafts}
|
||||
reviewCount={reviewCount}
|
||||
prCommentCount={prCommentCount}
|
||||
prCheckCount={prCheckCount}
|
||||
previewAnnotationCount={previewAnnotationCount}
|
||||
chatQuoteCount={chatQuoteCount}
|
||||
draftTarget={inlineDraftTarget}
|
||||
onRemoveDraft={removeInlineCommentDraft}
|
||||
onRemoveReviewDrafts={removeReviewDrafts}
|
||||
onRemovePreviewDrafts={removePreviewDrafts}
|
||||
colors={currentTheme.colors}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
Reference in New Issue
Block a user