ui-nyla/src/pages/views/codeeditor/DiffPreviewPanel.tsx
2026-02-23 18:35:42 +01:00

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>
);
};