feat(diffViewer): Improve diff viewer - Show untracked, deleted, modified outgoing changes - Improve modal style

This commit is contained in:
santiagosayshey
2024-08-24 17:53:41 +09:30
committed by Sam Chau
parent ab3c6183c5
commit 650cfa2dc7
4 changed files with 127 additions and 179 deletions

View File

@@ -69,36 +69,6 @@ def validate_git_token(repo_url, git_token):
except Exception as e:
return False
def parse_diff(diff_text):
diff_lines = diff_text.splitlines()
parsed_diff = []
local_version = []
incoming_version = []
in_local = False
in_incoming = False
for line in diff_lines:
if line.startswith('--- a/'):
in_local = True
in_incoming = False
elif line.startswith('+++ b/'):
in_incoming = True
in_local = False
elif line.startswith('@@'):
# Context lines that indicate a change
parsed_diff.append({'context': line, 'type': 'context'})
elif line.startswith('-'):
local_version.append(line[1:])
parsed_diff.append({'text': line[1:], 'type': 'local'})
elif line.startswith('+'):
incoming_version.append(line[1:])
parsed_diff.append({'text': line[1:], 'type': 'incoming'})
else:
parsed_diff.append({'text': line, 'type': 'unchanged'})
return parsed_diff, local_version, incoming_version
def get_outgoing_changes(repo):
status = repo.git.status('--porcelain', '-z').split('\0')
logger.debug(f"Raw porcelain status: {status}")
@@ -119,7 +89,19 @@ def get_outgoing_changes(repo):
full_path = os.path.join(repo.working_dir, file_path)
if os.path.isdir(full_path):
if x == 'D' or y == 'D':
# Handle deleted files
changes.append({
'name': 'Deleted File',
'id': '',
'type': determine_type(file_path),
'status': 'Deleted',
'file_path': file_path,
'staged': x != '?',
'modified': False,
'deleted': True
})
elif os.path.isdir(full_path):
logger.debug(f"Found directory: {file_path}, going through folder.")
for root, dirs, files in os.walk(full_path):
for file in files:
@@ -139,17 +121,14 @@ def get_outgoing_changes(repo):
'file_path': os.path.relpath(file_full_path, repo.working_dir),
'staged': x != '?' and x != ' ',
'modified': y == 'M',
'deleted': x == 'D' or y == 'D'
'deleted': False
})
else:
logger.debug(f"No data extracted from file: {file_full_path}")
else:
logger.debug(f"Found file: {full_path}, going through file.")
file_data = extract_data_from_yaml(full_path)
if file_data or x == 'D' or y == 'D': # Ensure that deleted files are handled
if not file_data:
logger.debug(f"No data found, using default file name as name")
file_data = {'name': os.path.basename(file_path).replace('.yml', ''), 'id': None}
if file_data:
logger.debug(f"File contents: {file_data}")
logger.debug(f"Found ID: {file_data.get('id')}")
logger.debug(f"Found Name: {file_data.get('name')}")
@@ -161,7 +140,19 @@ def get_outgoing_changes(repo):
'file_path': file_path,
'staged': x != '?' and x != ' ',
'modified': y == 'M',
'deleted': x == 'D' or y == 'D'
'deleted': False
})
else:
logger.debug(f"No data found, using default file name as name")
changes.append({
'name': os.path.basename(file_path).replace('.yml', ''),
'id': '',
'type': determine_type(file_path),
'status': interpret_git_status(x, y),
'file_path': file_path,
'staged': x != '?' and x != ' ',
'modified': y == 'M',
'deleted': False
})
logger.debug(f"Final changes: {json.dumps(changes, indent=2)}")
@@ -772,8 +763,23 @@ def get_diff():
try:
repo = git.Repo(settings_manager.repo_path)
branch = repo.active_branch.name
diff = repo.git.diff(f'HEAD...origin/{branch}', file_path)
return jsonify({'success': True, 'diff': diff}), 200
# Check if the file is untracked
untracked_files = repo.untracked_files
if file_path in untracked_files:
with open(os.path.join(repo.working_dir, file_path), 'r') as file:
content = file.read()
diff = "\n".join([f"+{line}" for line in content.splitlines()])
else:
# Check if the file is deleted
if not os.path.exists(os.path.join(repo.working_dir, file_path)):
diff = "-Deleted File"
else:
# Get the diff for modified files
diff = repo.git.diff(f'HEAD', file_path)
logger.debug(f"Diff for file {file_path}: {diff}")
return jsonify({'success': True, 'diff': diff if diff else ""}), 200
except Exception as e:
logger.error(f"Error getting diff for file {file_path}: {str(e)}", exc_info=True)
return jsonify({'success': False, 'error': f"Error getting diff for file: {str(e)}"}), 400
return jsonify({'success': False, 'error': f"Error getting diff for file: {str(e)}"}), 400

View File

@@ -1,87 +1,86 @@
import React from 'react';
import PropTypes from 'prop-types';
import Modal from '../ui/Modal';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';
import React from "react";
import PropTypes from "prop-types";
import Modal from "../ui/Modal";
const DiffModal = ({ isOpen, onClose, diffContent, type, name, commitMessage, title = "View Diff" }) => {
const formatDiffContent = (content) => {
return content
.split('\n')
.filter(line =>
!line.startsWith('diff --git') &&
!line.startsWith('index') &&
!line.startsWith('---') &&
!line.startsWith('+++') &&
!line.startsWith('@@')
)
.map((line, index) => {
let className = 'pl-2';
let lineBackground = '';
if (line.startsWith('+')) {
className += ' text-green-400'; // Green for additions
lineBackground = 'bg-green-900'; // Darker green background
} else if (line.startsWith('-')) {
className += ' text-red-400'; // Red for deletions
lineBackground = 'bg-red-900'; // Darker red background
} else if (line.startsWith('@@')) {
className += ' text-yellow-400'; // Yellow for diff hunk headers
lineBackground = 'bg-gray-700'; // Neutral background
} else {
lineBackground = 'bg-gray-800'; // Default background for unchanged lines
}
return (
<div
key={index}
className={`${lineBackground} ${className} py-1 flex`}
style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word' }} // Ensure long lines are wrapped properly
>
<span className="inline-block w-12 text-gray-600 select-none text-right pr-2">{index + 1}</span>
<span className="ml-2">{line}</span>
</div>
);
});
};
const DiffModal = ({
isOpen,
onClose,
diffContent,
type,
name,
commitMessage,
title = "View Diff",
}) => {
const formatDiffContent = (content) => {
if (!content) return [];
return content.split("\n").map((line, index) => {
let lineClass = "py-1 pl-4 border-l-2 ";
if (line.startsWith("+")) {
lineClass += "bg-green-900/30 text-green-400 border-green-500";
} else if (line.startsWith("-")) {
lineClass += "bg-red-900/30 text-red-400 border-red-500";
} else {
lineClass += "border-transparent";
}
return (
<div key={index} className={`flex ${lineClass}`}>
<span className="w-12 text-gray-500 select-none text-right pr-4 border-r border-gray-700">
{index + 1}
</span>
<code className="flex-1 pl-4 font-mono text-sm">{line}</code>
</div>
);
});
};
const formattedContent = formatDiffContent(diffContent);
return (
<Modal isOpen={isOpen} onClose={onClose} title={title} size="xl">
<div className="mb-4 p-4 bg-gray-700 rounded-lg shadow-md">
<div className="flex flex-col space-y-2">
<div>
<span className="font-bold text-gray-300">Type: </span>
<span className="text-gray-100">{type}</span>
<Modal isOpen={isOpen} onClose={onClose} title={title} size="4xl">
<div className="space-y-4">
<div className="bg-gray-100 dark:bg-gray-700 p-4 rounded-lg space-y-2 text-sm">
<div className="flex justify-between items-center">
<span className="font-medium text-gray-600 dark:text-gray-300">
Type:
</span>
<span className="bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 px-2 py-1 rounded">
{type}
</span>
</div>
<div>
<span className="font-bold text-gray-300">Name: </span>
<span className="text-gray-100">{name}</span>
<div className="flex justify-between items-center">
<span className="font-medium text-gray-600 dark:text-gray-300">
Name:
</span>
<span className="bg-gray-200 dark:bg-gray-600 text-gray-800 dark:text-gray-200 px-2 py-1 rounded">
{name === "Deleted File" ? "Deleted File" : name}
</span>
</div>
{commitMessage && (
<div>
<span className="font-bold text-gray-300">Commit Message: </span>
<span className="text-gray-100">{commitMessage}</span>
<div className="flex flex-col">
<span className="font-medium text-gray-600 dark:text-gray-300 mb-1">
Commit Message:
</span>
<p className="bg-gray-200 dark:bg-gray-600 text-gray-800 dark:text-gray-200 p-2 rounded">
{commitMessage}
</p>
</div>
)}
</div>
<div className="border border-gray-300 dark:border-gray-600 rounded-lg overflow-hidden">
<div className="bg-gray-50 dark:bg-gray-800 p-2 text-sm font-medium text-gray-600 dark:text-gray-300 border-b border-gray-300 dark:border-gray-600">
Diff Content
</div>
<div className="bg-white dark:bg-gray-900 p-4 max-h-[60vh] overflow-y-auto">
{formattedContent.length > 0 ? (
formattedContent
) : (
<div className="text-gray-500 dark:text-gray-400 italic">
No differences found or file is empty.
</div>
)}
</div>
</div>
</div>
<div
className="bg-gray-900 p-4 rounded-lg shadow-inner"
style={{ overflowX: 'auto' }} // Add horizontal scrolling
>
<div
className="text-sm text-gray-100 font-mono"
style={{
whiteSpace: 'pre-wrap', // Wrap lines
wordWrap: 'break-word', // Break long words
}}
>
{formatDiffContent(diffContent || "No differences found.")}
</div>
</div>
</Modal>
);
};
@@ -89,7 +88,7 @@ const DiffModal = ({ isOpen, onClose, diffContent, type, name, commitMessage, ti
DiffModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
diffContent: PropTypes.string.isRequired,
diffContent: PropTypes.string,
type: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
commitMessage: PropTypes.string,

View File

@@ -1,59 +0,0 @@
import React from 'react';
import Modal from '../ui/Modal';
const DiffViewer = ({ isOpen, onClose, diffContent = [] }) => {
// Ensure diffContent is an array before proceeding
if (!Array.isArray(diffContent)) {
diffContent = []; // Default to an empty array if diffContent is not an array
}
// Separate content for local and incoming
const localContent = diffContent.filter(line => line.type === 'local' || line.type === 'context' || line.type === 'unchanged');
const incomingContent = diffContent.filter(line => line.type === 'incoming' || line.type === 'context' || line.type === 'unchanged');
const renderDiffColumn = (content) => {
return content.map((line, index) => {
let lineClass = 'text-gray-200'; // Default line class for unchanged lines
if (line.type === 'local') {
lineClass = 'bg-red-400 text-black'; // Highlight local changes
} else if (line.type === 'incoming') {
lineClass = 'bg-yellow-400 text-black'; // Highlight incoming changes
} else if (line.type === 'context') {
lineClass = 'text-gray-400'; // Context lines
}
return (
<div key={index} className={`p-1 ${lineClass}`}>
{line.text}
</div>
);
});
};
return (
<Modal
isOpen={isOpen}
onClose={onClose}
title="Diff Viewer"
size="xl" // Making the modal larger
>
<div className="bg-gray-900 p-4 rounded-md overflow-auto text-xs flex space-x-4">
<div className="w-1/2">
<h3 className="text-gray-300 mb-2">Remote</h3>
<div className="bg-gray-800 p-2 rounded-md">
{renderDiffColumn(localContent)}
</div>
</div>
<div className="w-1/2">
<h3 className="text-gray-300 mb-2">Local</h3>
<div className="bg-gray-800 p-2 rounded-md">
{renderDiffColumn(incomingContent)}
</div>
</div>
</div>
</Modal>
);
};
export default DiffViewer;

View File

@@ -289,13 +289,15 @@ const SettingsPage = () => {
};
const handleViewDiff = async (change) => {
setLoadingDiff(true); // Start loading
setLoadingDiff(true);
try {
const response = await getDiff(change.file_path);
console.log("Diff response:", response); // Add this line to log the response
if (response.success) {
setDiffContent(response.diff); // Store the diff content
setCurrentChange(change); // Set the current change being viewed
setShowDiffModal(true); // Open the modal
console.log("Diff content:", response.diff); // Add this line to log the diff content
setDiffContent(response.diff);
setCurrentChange(change);
setShowDiffModal(true);
} else {
Alert.error(response.error);
}
@@ -303,7 +305,7 @@ const SettingsPage = () => {
Alert.error("An unexpected error occurred while fetching the diff.");
console.error("Error fetching diff:", error);
} finally {
setLoadingDiff(false); // Stop loading
setLoadingDiff(false);
setLoadingAction("");
}
};