543fee5d56
- Fix incorrect relative paths in feature components after directory restructure
- Components in features/{domain}/ were importing ./features/{domain}/X.module.css
instead of ./X.module.css
- Affected: AppShell, GitToolbar, FileEditor, CommitDialog, CommitPanel,
MergeDialog, SettingsTabLayout, InstanceList, TerminalComponent
Quality gates: tsc (pass), eslint (pass), build (pass)
Refs: repo-restructure Task 4.4
146 lines
3.9 KiB
TypeScript
146 lines
3.9 KiB
TypeScript
import styles from "./MergeDialog.module.css";
|
|
import { useState } from "react";
|
|
|
|
import { mergeBranches } from "../../../api/git-repositories";
|
|
import { Icon } from "../../ui/Icon";
|
|
|
|
interface MergeDialogProps {
|
|
projectId: string;
|
|
repoId: string;
|
|
branches: string[];
|
|
currentBranch: string;
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
onMerge: () => void;
|
|
}
|
|
|
|
export const MergeDialog = ({
|
|
projectId,
|
|
repoId,
|
|
branches,
|
|
currentBranch,
|
|
isOpen,
|
|
onClose,
|
|
onMerge,
|
|
}: MergeDialogProps) => {
|
|
const [sourceBranch, setSourceBranch] = useState("");
|
|
const [commitMessage, setCommitMessage] = useState("");
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [success, setSuccess] = useState(false);
|
|
|
|
if (!isOpen) return null;
|
|
|
|
const availableBranches = branches.filter((b) => b !== currentBranch);
|
|
|
|
const handleMerge = async () => {
|
|
if (!sourceBranch) {
|
|
setError("Please select a source branch");
|
|
return;
|
|
}
|
|
setLoading(true);
|
|
setError(null);
|
|
setSuccess(false);
|
|
try {
|
|
await mergeBranches(
|
|
projectId,
|
|
repoId,
|
|
sourceBranch,
|
|
currentBranch,
|
|
commitMessage || undefined
|
|
);
|
|
setSuccess(true);
|
|
setTimeout(() => {
|
|
onMerge();
|
|
onClose();
|
|
}, 1500);
|
|
} catch {
|
|
setError("Merge failed. There may be conflicts to resolve.");
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="modal-overlay" onClick={onClose}>
|
|
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
|
|
<h2>Merge Branch</h2>
|
|
|
|
<div className={styles.mergeForm}>
|
|
<div className={styles.formField}>
|
|
<label>Source Branch (merge from)</label>
|
|
<select
|
|
value={sourceBranch}
|
|
onChange={(e) => setSourceBranch(e.target.value)}
|
|
disabled={loading}
|
|
>
|
|
<option value="">Select branch...</option>
|
|
{availableBranches.map((branch) => (
|
|
<option key={branch} value={branch}>
|
|
{branch}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
|
|
<div className={styles.formField}>
|
|
<label>Target Branch (merge into)</label>
|
|
<input
|
|
type="text"
|
|
value={currentBranch}
|
|
disabled
|
|
className={styles.inputDisabled}
|
|
/>
|
|
</div>
|
|
|
|
<div className={styles.formField}>
|
|
<label>Commit Message (optional)</label>
|
|
<textarea
|
|
value={commitMessage}
|
|
onChange={(e) => setCommitMessage(e.target.value)}
|
|
placeholder={`Merge ${sourceBranch || "branch"} into ${currentBranch}`}
|
|
rows={3}
|
|
disabled={loading}
|
|
/>
|
|
</div>
|
|
|
|
{error && <div className="error-text">{error}</div>}
|
|
{success && (
|
|
<div className={styles.successText}>Merge successful!</div>
|
|
)}
|
|
|
|
<div className="modal-actions">
|
|
<button
|
|
className="secondary-button"
|
|
onClick={onClose}
|
|
disabled={loading}
|
|
type="button"
|
|
>
|
|
<Icon name="cancel" size="sm" />
|
|
Cancel
|
|
</button>
|
|
<button
|
|
className="primary-button"
|
|
onClick={handleMerge}
|
|
disabled={loading || !sourceBranch}
|
|
type="button"
|
|
>
|
|
{loading ? (
|
|
<>
|
|
<Icon name="loading" size="sm" />
|
|
Merging...
|
|
</>
|
|
) : (
|
|
<>
|
|
<Icon name="merge" size="sm" />
|
|
Merge
|
|
</>
|
|
)}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|