Review comments should contain line of code (vibe-kanban) (#731)
* **Changes** - Capture the relevant code line in each draft/comment so it’s stored alongside metadata and rendered in the Markdown output, with backtick-safe formatting for inline/triple code blocks (`frontend/src/contexts/ReviewProvider.tsx:4-107`). - Pull the plain line text from the diff when a comment widget opens and stash it on the draft before saving (`frontend/src/components/DiffCard.tsx:140-155`). - Pass the captured line through when persisting a new review comment (`frontend/src/components/diff/CommentWidgetLine.tsx:28-34`). - Tests: `pnpm run check` Consider spot-checking the review markdown in the UI to confirm the new code line snippet displays as expected. * Line capture now trims trailing newline characters so inline code renders on a single line (`frontend/src/components/DiffCard.tsx:140-154`). `pnpm run check` still passes. Let me know if you spot any other formatting quirks. * Cleanup script changes for task attempt 93f0100f-256d-4177-839d-53cb700d2a3e * Pulled the diff-line lookup into a reusable helper so `DiffCard` now grabs and normalizes the raw line content before drafting comments; this keeps the widget payload lean and avoids scattering newline-trimming logic (`frontend/src/components/DiffCard.tsx:1-161`). Added a `stripLineEnding` utility so future callers have a single place to remove CR/LF sequences without touching other whitespace (`frontend/src/utils/string.ts:24-29`). Tests: `pnpm run check` (fails — TypeScript can’t resolve types for `markdown-to-jsx` in `frontend/src/components/ui/markdown-renderer.tsx`; worth checking that dependency’s types or a module declaration is in place before re-running).
This commit is contained in:
committed by
GitHub
parent
9951c0e44c
commit
bd96b7c18b
@@ -1,10 +1,11 @@
|
||||
import { Diff } from 'shared/types';
|
||||
import { DiffModeEnum, DiffView, SplitSide } from '@git-diff-view/react';
|
||||
import { generateDiffFile } from '@git-diff-view/file';
|
||||
import { generateDiffFile, type DiffFile } from '@git-diff-view/file';
|
||||
import { useMemo } from 'react';
|
||||
import { useUserSystem } from '@/components/config-provider';
|
||||
import { getHighLightLanguageFromPath } from '@/utils/extToLanguage';
|
||||
import { getActualTheme } from '@/utils/theme';
|
||||
import { stripLineEnding } from '@/utils/string';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
ChevronRight,
|
||||
@@ -45,6 +46,25 @@ function labelAndIcon(diff: Diff) {
|
||||
return { label: undefined as string | undefined, Icon: PencilLine };
|
||||
}
|
||||
|
||||
function readPlainLine(
|
||||
diffFile: DiffFile | null,
|
||||
lineNumber: number,
|
||||
side: SplitSide
|
||||
) {
|
||||
if (!diffFile) return undefined;
|
||||
try {
|
||||
const rawLine =
|
||||
side === SplitSide.old
|
||||
? diffFile.getOldPlainLine(lineNumber)
|
||||
: diffFile.getNewPlainLine(lineNumber);
|
||||
if (rawLine?.value === undefined) return undefined;
|
||||
return stripLineEnding(rawLine.value);
|
||||
} catch (error) {
|
||||
console.error('Failed to read line content for review comment', error);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export default function DiffCard({
|
||||
diff,
|
||||
expanded,
|
||||
@@ -131,11 +151,13 @@ export default function DiffCard({
|
||||
|
||||
const handleAddWidgetClick = (lineNumber: number, side: SplitSide) => {
|
||||
const widgetKey = `${filePath}-${side}-${lineNumber}`;
|
||||
const codeLine = readPlainLine(diffFile, lineNumber, side);
|
||||
const draft: ReviewDraft = {
|
||||
filePath,
|
||||
side,
|
||||
lineNumber,
|
||||
text: '',
|
||||
...(codeLine !== undefined ? { codeLine } : {}),
|
||||
};
|
||||
setDraft(widgetKey, draft);
|
||||
};
|
||||
|
||||
@@ -30,6 +30,7 @@ export function CommentWidgetLine({
|
||||
side: draft.side,
|
||||
lineNumber: draft.lineNumber,
|
||||
text: value.trim(),
|
||||
codeLine: draft.codeLine,
|
||||
});
|
||||
}
|
||||
setDraft(widgetKey, null);
|
||||
|
||||
@@ -7,6 +7,7 @@ export interface ReviewComment {
|
||||
lineNumber: number;
|
||||
side: SplitSide;
|
||||
text: string;
|
||||
codeLine?: string;
|
||||
}
|
||||
|
||||
export interface ReviewDraft {
|
||||
@@ -14,6 +15,7 @@ export interface ReviewDraft {
|
||||
side: SplitSide;
|
||||
lineNumber: number;
|
||||
text: string;
|
||||
codeLine?: string;
|
||||
}
|
||||
|
||||
interface ReviewContextType {
|
||||
@@ -83,11 +85,23 @@ export function ReviewProvider({ children }: { children: ReactNode }) {
|
||||
const commentsNum = comments.length;
|
||||
|
||||
const header = `## Review Comments (${commentsNum})\n\n`;
|
||||
const formatCodeLine = (line?: string) => {
|
||||
if (!line) return '';
|
||||
if (line.includes('`')) {
|
||||
return `\`\`\`\n${line}\n\`\`\``;
|
||||
}
|
||||
return `\`${line}\``;
|
||||
};
|
||||
|
||||
const commentsMd = comments
|
||||
.map(
|
||||
(comment) =>
|
||||
`**${comment.filePath}** (Line ${comment.lineNumber})\n\n> ${comment.text.trim()}\n`
|
||||
)
|
||||
.map((comment) => {
|
||||
const codeLine = formatCodeLine(comment.codeLine);
|
||||
const commentBody = comment.text.trim();
|
||||
if (codeLine) {
|
||||
return `**${comment.filePath}** (Line ${comment.lineNumber})\n${codeLine}\n\n> ${commentBody}\n`;
|
||||
}
|
||||
return `**${comment.filePath}** (Line ${comment.lineNumber})\n\n> ${commentBody}\n`;
|
||||
})
|
||||
.join('\n');
|
||||
|
||||
return header + commentsMd;
|
||||
|
||||
@@ -20,3 +20,11 @@ export const generateProjectNameFromPath = (path: string): string => {
|
||||
const dirName = path.split('/').filter(Boolean).pop() || '';
|
||||
return dirName.replace(/[-_]/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase());
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes a single trailing newline sequence from a string.
|
||||
* Handles CRLF/CR/LF endings while leaving other trailing whitespace intact.
|
||||
*/
|
||||
export const stripLineEnding = (value: string): string => {
|
||||
return value.replace(/(?:\r\n|\r|\n)$/, '');
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user