95 lines
2.8 KiB
TypeScript
95 lines
2.8 KiB
TypeScript
/**
|
|
* DiffPreviewPanel
|
|
*
|
|
* Shows file edit proposals as side-by-side text diffs.
|
|
* Each edit has Accept/Reject buttons.
|
|
*/
|
|
|
|
import React from 'react';
|
|
import { FaCheck, FaTimes } from 'react-icons/fa';
|
|
import styles from './CodeEditor.module.css';
|
|
|
|
export interface FileEditProposal {
|
|
id: string;
|
|
fileId: string;
|
|
fileName: string;
|
|
oldContent: string | null;
|
|
newContent: string;
|
|
status: 'pending' | 'accepted' | 'rejected';
|
|
}
|
|
|
|
interface DiffPreviewPanelProps {
|
|
edits: FileEditProposal[];
|
|
onAccept: (editId: string) => void;
|
|
onReject: (editId: string) => void;
|
|
}
|
|
|
|
export const DiffPreviewPanel: React.FC<DiffPreviewPanelProps> = ({ edits, onAccept, onReject }) => {
|
|
const pendingEdits = edits.filter(e => e.status === 'pending');
|
|
const resolvedEdits = edits.filter(e => e.status !== 'pending');
|
|
|
|
return (
|
|
<div className={styles.diffPreview}>
|
|
<div className={styles.panelHeader}>
|
|
<h3>Changes ({pendingEdits.length} pending)</h3>
|
|
</div>
|
|
<div className={styles.diffItems}>
|
|
{edits.length === 0 ? (
|
|
<div className={styles.emptyState}>No changes proposed yet</div>
|
|
) : (
|
|
<>
|
|
{pendingEdits.map((edit) => (
|
|
<DiffCard key={edit.id} edit={edit} onAccept={onAccept} onReject={onReject} />
|
|
))}
|
|
{resolvedEdits.map((edit) => (
|
|
<DiffCard key={edit.id} edit={edit} onAccept={onAccept} onReject={onReject} />
|
|
))}
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const DiffCard: React.FC<{
|
|
edit: FileEditProposal;
|
|
onAccept: (id: string) => void;
|
|
onReject: (id: string) => void;
|
|
}> = ({ edit, onAccept, onReject }) => {
|
|
const isPending = edit.status === 'pending';
|
|
|
|
return (
|
|
<div className={`${styles.diffCard} ${styles[`diffCard_${edit.status}`]}`}>
|
|
<div className={styles.diffCardHeader}>
|
|
<span className={styles.diffFileName}>{edit.fileName}</span>
|
|
<span className={`${styles.diffStatus} ${styles[`diffStatus_${edit.status}`]}`}>
|
|
{edit.status}
|
|
</span>
|
|
</div>
|
|
|
|
<div className={styles.diffContent}>
|
|
{edit.oldContent && (
|
|
<div className={styles.diffOld}>
|
|
<div className={styles.diffLabel}>Old</div>
|
|
<pre>{edit.oldContent}</pre>
|
|
</div>
|
|
)}
|
|
<div className={styles.diffNew}>
|
|
<div className={styles.diffLabel}>New</div>
|
|
<pre>{edit.newContent}</pre>
|
|
</div>
|
|
</div>
|
|
|
|
{isPending && (
|
|
<div className={styles.diffActions}>
|
|
<button className={styles.acceptButton} onClick={() => onAccept(edit.id)}>
|
|
<FaCheck /> Accept
|
|
</button>
|
|
<button className={styles.rejectButton} onClick={() => onReject(edit.id)}>
|
|
<FaTimes /> Reject
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|