Skip to content

Commit f6df0bd

Browse files
committed
Improve WEB UI
1 parent b58a035 commit f6df0bd

File tree

7 files changed

+404
-188
lines changed

7 files changed

+404
-188
lines changed

nextjs-frontend/src/app/api/comparison/analyze/route.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -371,24 +371,24 @@ function analyzeFileChanges(
371371
if (!targetFile) {
372372
changes.push({
373373
type: 'deleted',
374-
sourcePath: relativePath
374+
sourcePath: sourceFile.path // Use absolute path
375375
});
376376
} else {
377377
processedTargets.add(relativePath);
378-
378+
379379
if (sourceFile.hash === targetFile.hash) {
380380
changes.push({
381381
type: 'unchanged',
382-
sourcePath: relativePath,
383-
targetPath: relativePath,
382+
sourcePath: sourceFile.path, // Use absolute path
383+
targetPath: targetFile.path, // Use absolute path
384384
similarity: 1.0
385385
});
386386
} else {
387387
const similarity = calculateFileSimilarity(sourceFile, targetFile);
388388
changes.push({
389389
type: 'modified',
390-
sourcePath: relativePath,
391-
targetPath: relativePath,
390+
sourcePath: sourceFile.path, // Use absolute path
391+
targetPath: targetFile.path, // Use absolute path
392392
similarity,
393393
sizeChange: targetFile.size - sourceFile.size
394394
});
@@ -401,7 +401,7 @@ function analyzeFileChanges(
401401
if (!processedTargets.has(relativePath)) {
402402
changes.push({
403403
type: 'added',
404-
targetPath: relativePath
404+
targetPath: targetFile.path // Use absolute path
405405
});
406406
}
407407
}

nextjs-frontend/src/app/api/comparison/diff/route.ts

Lines changed: 110 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -50,23 +50,20 @@ export async function POST(request: NextRequest) {
5050
fs.readFile(targetAbsolutePath, 'utf-8')
5151
]);
5252

53-
const diff = generateUnifiedDiff(
54-
sourceContent,
55-
targetContent,
56-
sourceFilePath,
57-
targetFilePath,
58-
options
59-
);
60-
61-
const stats = calculateDiffStats(sourceContent, targetContent);
53+
const diffLines = generateDiffLines(sourceContent, targetContent);
54+
const stats = calculateDiffStats(diffLines);
6255

6356
return NextResponse.json({
64-
diff,
65-
stats,
66-
sourceSize: sourceStats.size,
67-
targetSize: targetStats.size,
68-
sourceModified: sourceStats.mtime.toISOString(),
69-
targetModified: targetStats.mtime.toISOString()
57+
sourcePath: sourceFilePath,
58+
targetPath: targetFilePath,
59+
sourceContent,
60+
targetContent,
61+
lines: diffLines,
62+
stats: {
63+
additions: stats.linesAdded,
64+
deletions: stats.linesDeleted,
65+
modifications: 0
66+
}
7067
});
7168

7269
} catch (error: any) {
@@ -126,11 +123,101 @@ function preprocessLines(lines: string[], options: DiffOptions): string[] {
126123
return processed;
127124
}
128125

126+
function generateDiffLines(sourceContent: string, targetContent: string): DiffLine[] {
127+
const sourceLines = sourceContent.split('\n');
128+
const targetLines = targetContent.split('\n');
129+
130+
const diffLines: DiffLine[] = [];
131+
let sourceIndex = 0;
132+
let targetIndex = 0;
133+
let lineNumber = 1;
134+
135+
// Simple diff algorithm - can be enhanced with proper LCS
136+
while (sourceIndex < sourceLines.length || targetIndex < targetLines.length) {
137+
const sourceLine = sourceLines[sourceIndex];
138+
const targetLine = targetLines[targetIndex];
139+
140+
if (sourceIndex >= sourceLines.length) {
141+
// Only target lines left (additions)
142+
diffLines.push({
143+
lineNumber: lineNumber++,
144+
content: targetLine,
145+
type: 'added',
146+
newLineNumber: targetIndex + 1,
147+
});
148+
targetIndex++;
149+
} else if (targetIndex >= targetLines.length) {
150+
// Only source lines left (deletions)
151+
diffLines.push({
152+
lineNumber: lineNumber++,
153+
content: sourceLine,
154+
type: 'removed',
155+
oldLineNumber: sourceIndex + 1,
156+
});
157+
sourceIndex++;
158+
} else if (sourceLine === targetLine) {
159+
// Lines are identical
160+
diffLines.push({
161+
lineNumber: lineNumber++,
162+
content: sourceLine,
163+
type: 'unchanged',
164+
oldLineNumber: sourceIndex + 1,
165+
newLineNumber: targetIndex + 1,
166+
});
167+
sourceIndex++;
168+
targetIndex++;
169+
} else {
170+
// Lines are different - check if it's a modification or add/remove
171+
const nextSourceMatch = targetLines.slice(targetIndex + 1).findIndex(line => line === sourceLine);
172+
const nextTargetMatch = sourceLines.slice(sourceIndex + 1).findIndex(line => line === targetLine);
173+
174+
if (nextSourceMatch === -1 && nextTargetMatch === -1) {
175+
// Likely a modification
176+
diffLines.push({
177+
lineNumber: lineNumber++,
178+
content: sourceLine,
179+
type: 'removed',
180+
oldLineNumber: sourceIndex + 1,
181+
});
182+
diffLines.push({
183+
lineNumber: lineNumber++,
184+
content: targetLine,
185+
type: 'added',
186+
newLineNumber: targetIndex + 1,
187+
});
188+
sourceIndex++;
189+
targetIndex++;
190+
} else if (nextSourceMatch !== -1 && (nextTargetMatch === -1 || nextSourceMatch < nextTargetMatch)) {
191+
// Source line appears later in target, so target lines are additions
192+
diffLines.push({
193+
lineNumber: lineNumber++,
194+
content: targetLine,
195+
type: 'added',
196+
newLineNumber: targetIndex + 1,
197+
});
198+
targetIndex++;
199+
} else {
200+
// Target line appears later in source, so source line is deletion
201+
diffLines.push({
202+
lineNumber: lineNumber++,
203+
content: sourceLine,
204+
type: 'removed',
205+
oldLineNumber: sourceIndex + 1,
206+
});
207+
sourceIndex++;
208+
}
209+
}
210+
}
211+
212+
return diffLines;
213+
}
214+
129215
interface DiffLine {
130-
type: 'context' | 'added' | 'deleted';
216+
lineNumber: number;
131217
content: string;
132-
sourceLineNumber?: number;
133-
targetLineNumber?: number;
218+
type: 'added' | 'removed' | 'unchanged' | 'modified';
219+
oldLineNumber?: number;
220+
newLineNumber?: number;
134221
}
135222

136223
function computeLCS(sourceLines: string[], targetLines: string[]): DiffLine[] {
@@ -343,21 +430,10 @@ function createHunk(lines: DiffLine[]): Hunk {
343430
};
344431
}
345432

346-
function calculateDiffStats(sourceContent: string, targetContent: string) {
347-
const sourceLines = sourceContent.split('\n');
348-
const targetLines = targetContent.split('\n');
349-
350-
const diff = computeLCS(sourceLines, targetLines);
351-
352-
const stats = {
353-
linesAdded: diff.filter(line => line.type === 'added').length,
354-
linesDeleted: diff.filter(line => line.type === 'deleted').length,
355-
linesChanged: 0,
356-
totalSourceLines: sourceLines.length,
357-
totalTargetLines: targetLines.length
433+
function calculateDiffStats(diffLines: DiffLine[]) {
434+
return {
435+
linesAdded: diffLines.filter(line => line.type === 'added').length,
436+
linesDeleted: diffLines.filter(line => line.type === 'removed').length,
437+
linesChanged: diffLines.filter(line => line.type === 'modified').length,
358438
};
359-
360-
stats.linesChanged = stats.linesAdded + stats.linesDeleted;
361-
362-
return stats;
363439
}

nextjs-frontend/src/app/api/comparison/file-content/route.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@ export async function POST(request: NextRequest) {
1414
);
1515
}
1616

17-
// Security check: ensure the path is absolute and doesn't contain traversal attempts
17+
// Security check: resolve to absolute path
1818
const absolutePath = path.resolve(filePath);
19-
if (!absolutePath.startsWith(process.cwd()) && !path.isAbsolute(filePath)) {
19+
20+
// Basic security check - ensure we're not accessing system files
21+
const normalizedPath = path.normalize(absolutePath);
22+
if (normalizedPath.includes('..') || normalizedPath.startsWith('/etc') || normalizedPath.startsWith('/proc')) {
2023
return NextResponse.json(
2124
{ error: 'Access denied: Invalid file path' },
2225
{ status: 403 }

nextjs-frontend/src/app/page.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import { useState } from 'react';
3+
import { useState, useEffect } from 'react';
44
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
55
import { Button } from '@/components/ui/Button';
66
import { Input } from '@/components/ui/Input';
@@ -60,6 +60,8 @@ export default function HomePage() {
6060
const handleReset = () => {
6161
setSourceDirectory('');
6262
setTargetDirectory('');
63+
localStorage.removeItem('smartdiff-source-directory');
64+
localStorage.removeItem('smartdiff-target-directory');
6365
setComparisonResult(null);
6466
setError(null);
6567
setActiveView('summary');

0 commit comments

Comments
 (0)