merge: align dev branch with main
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { commitChanges } from "../../../api/git-repositories";
|
||||
import styles from "./CommitPanel.module.css";
|
||||
|
||||
interface CommitPanelProps {
|
||||
projectId: string;
|
||||
repoId: string;
|
||||
modified: string[];
|
||||
added: string[];
|
||||
deleted: string[];
|
||||
untracked: string[];
|
||||
onCommit: () => void;
|
||||
}
|
||||
|
||||
export const CommitPanel = ({
|
||||
projectId,
|
||||
repoId,
|
||||
modified,
|
||||
added,
|
||||
deleted,
|
||||
untracked,
|
||||
onCommit,
|
||||
}: CommitPanelProps) => {
|
||||
const [message, setMessage] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const allFiles = [...modified, ...added, ...deleted, ...untracked];
|
||||
const hasChanges = allFiles.length > 0;
|
||||
|
||||
const handleCommit = async () => {
|
||||
if (!message.trim()) {
|
||||
setError("Please enter a commit message");
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
await commitChanges(projectId, repoId, message);
|
||||
setMessage("");
|
||||
onCommit();
|
||||
} catch {
|
||||
setError("Commit failed. Please try again.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (!hasChanges) return null;
|
||||
|
||||
return (
|
||||
<div className={styles.commitPanel}>
|
||||
<h4>Changes</h4>
|
||||
|
||||
<div className={styles.fileList}>
|
||||
{modified.map((file) => (
|
||||
<div key={file} className={`${styles.fileItem} modified`}>
|
||||
<span className={styles.fileStatus}>M</span>
|
||||
<span>{file}</span>
|
||||
</div>
|
||||
))}
|
||||
{added.map((file) => (
|
||||
<div key={file} className={`${styles.fileItem} added`}>
|
||||
<span className={styles.fileStatus}>A</span>
|
||||
<span>{file}</span>
|
||||
</div>
|
||||
))}
|
||||
{deleted.map((file) => (
|
||||
<div key={file} className={`${styles.fileItem} deleted`}>
|
||||
<span className={styles.fileStatus}>D</span>
|
||||
<span>{file}</span>
|
||||
</div>
|
||||
))}
|
||||
{untracked.map((file) => (
|
||||
<div key={file} className={`${styles.fileItem} untracked`}>
|
||||
<span className={styles.fileStatus}>?</span>
|
||||
<span>{file}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className={styles.commitForm}>
|
||||
<textarea
|
||||
placeholder="Commit message"
|
||||
value={message}
|
||||
onChange={(e) => setMessage(e.target.value)}
|
||||
rows={2}
|
||||
className={styles.commitMessageInput}
|
||||
/>
|
||||
{error && <div className={styles.commitError}>{error}</div>}
|
||||
<button
|
||||
onClick={handleCommit}
|
||||
disabled={loading || !message.trim()}
|
||||
className={styles.commitButton}
|
||||
type="button"
|
||||
>
|
||||
{loading ? "Committing..." : "Commit"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user