215 lines
7.8 KiB
React
215 lines
7.8 KiB
React
import React, { useState, useEffect } from 'react';
|
|
import Settings from './Settings.jsx';
|
|
|
|
export default function App() {
|
|
const [folder, setFolder] = useState('');
|
|
const [repoName, setRepoName] = useState('');
|
|
const [platform, setPlatform] = useState('gitea');
|
|
const [status, setStatus] = useState('Bereit');
|
|
const [showSettings, setShowSettings] = useState(false);
|
|
const [branches, setBranches] = useState([]);
|
|
const [selectedBranch, setSelectedBranch] = useState('main');
|
|
const [logs, setLogs] = useState([]);
|
|
const [progress, setProgress] = useState(0);
|
|
|
|
async function selectFolder() {
|
|
const selected = await window.electronAPI.selectFolder();
|
|
if (!selected) return;
|
|
setFolder(selected);
|
|
const branchList = await window.electronAPI.getBranches({ folder: selected });
|
|
setBranches(branchList);
|
|
if (branchList.includes('main')) setSelectedBranch('main');
|
|
else if (branchList.includes('master')) setSelectedBranch('master');
|
|
else if (branchList.length > 0) setSelectedBranch(branchList[0]);
|
|
}
|
|
|
|
async function createRepoHandler() {
|
|
if (!repoName) return alert('Repo-Name erforderlich!');
|
|
setStatus('Repository wird erstellt…');
|
|
const result = await window.electronAPI.createRepo({ name: repoName, platform });
|
|
setStatus(result ? 'Repository erstellt!' : 'Fehler beim Erstellen des Repositories.');
|
|
}
|
|
|
|
async function pushProjectHandler() {
|
|
if (!folder) return alert('Bitte zuerst einen Projektordner auswählen!');
|
|
setStatus('Projekt wird gepusht…');
|
|
setProgress(0);
|
|
const result = await window.electronAPI.pushProject({
|
|
folder,
|
|
branch: selectedBranch,
|
|
onProgress: (p) => setProgress(p),
|
|
});
|
|
setStatus(result ? 'Projekt gepusht!' : 'Push fehlgeschlagen.');
|
|
if (result) {
|
|
const logList = await window.electronAPI.getCommitLogs({ folder });
|
|
setLogs(logList);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div id="app" style={{ display: 'flex', flexDirection: 'column', height: '100vh' }}>
|
|
|
|
{/* ── Toolbar ── */}
|
|
<div id="toolbar">
|
|
<div className="toolbar-row toolbar-row--top">
|
|
<div className="toolbar-brand">
|
|
<div className="toolbar-brand-mark">
|
|
<img src="./icon.png" alt="Git Manager Logo" className="toolbar-brand-logo" />
|
|
</div>
|
|
<div className="toolbar-brand-copy">
|
|
<span className="toolbar-kicker">Workspace Control</span>
|
|
<strong>Git Manager Explorer Pro</strong>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="toolbar-top-actions">
|
|
<div className="tool-group tool-group--quick-actions">
|
|
<button onClick={createRepoHandler} title="Neues Repository erstellen">🚀 New Repo</button>
|
|
<button onClick={pushProjectHandler} title="Projekt pushen">⬆️ Push</button>
|
|
</div>
|
|
|
|
<div className="tool-group tool-group--utility">
|
|
<button onClick={() => setShowSettings(true)} title="Einstellungen">⚙️ Settings</button>
|
|
</div>
|
|
|
|
<div className="toolbar-status-wrap">
|
|
<span className="status-dot" aria-hidden="true" />
|
|
<span className="status">{status}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="toolbar-row toolbar-row--bottom">
|
|
<div className="tool-group tool-group--workspace">
|
|
<button className="accent-btn" onClick={selectFolder} title="Lokalen Ordner öffnen">
|
|
📂 Open Local
|
|
</button>
|
|
</div>
|
|
|
|
<div className="tool-group tool-group--repo">
|
|
<div className="platform-switch" role="tablist" aria-label="Plattform auswählen">
|
|
{['gitea', 'github'].map(p => (
|
|
<button
|
|
key={p}
|
|
type="button"
|
|
className={`platform-option${platform === p ? ' active' : ''}`}
|
|
data-platform={p}
|
|
aria-pressed={platform === p}
|
|
onClick={() => setPlatform(p)}
|
|
>
|
|
{p === 'gitea' ? 'Gitea' : 'GitHub'}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{branches.length > 0 && (
|
|
<select
|
|
value={selectedBranch}
|
|
onChange={e => setSelectedBranch(e.target.value)}
|
|
title="Branch auswählen"
|
|
>
|
|
{branches.map(b => <option key={b} value={b}>{b}</option>)}
|
|
</select>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* ── Main ── */}
|
|
<main id="main">
|
|
|
|
{/* Fortschrittsbalken */}
|
|
{progress > 0 && progress < 100 && (
|
|
<div className="input-group" style={{ marginBottom: 20 }}>
|
|
<label>Fortschritt</label>
|
|
<progress value={progress} max="100" style={{ width: '100%', height: 8, borderRadius: 4 }} />
|
|
</div>
|
|
)}
|
|
|
|
{/* Repo erstellen / Ordner */}
|
|
<div className="card" style={{ marginBottom: 20 }}>
|
|
<h2>📁 Projekt & Repository</h2>
|
|
|
|
<div className="input-group">
|
|
<label>Lokaler Projektordner</label>
|
|
<div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
|
|
<input
|
|
type="text"
|
|
readOnly
|
|
value={folder}
|
|
placeholder="Noch kein Ordner ausgewählt…"
|
|
style={{ flex: 1 }}
|
|
/>
|
|
<button onClick={selectFolder} style={{ flex: '0 0 auto' }}>📂 Auswählen</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="input-group">
|
|
<label>Repository Name</label>
|
|
<input
|
|
type="text"
|
|
placeholder="mein-projekt"
|
|
value={repoName}
|
|
onChange={e => setRepoName(e.target.value)}
|
|
/>
|
|
</div>
|
|
|
|
<div style={{ display: 'flex', gap: 10, marginTop: 8 }}>
|
|
<button className="accent-btn" onClick={createRepoHandler}>🚀 Repo erstellen</button>
|
|
<button onClick={pushProjectHandler}>⬆️ Push / Aktualisieren</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Commit-Logs */}
|
|
{logs.length > 0 && (
|
|
<div className="card">
|
|
<h2>📊 Commit-Verlauf</h2>
|
|
<ul style={{ listStyle: 'none', padding: 0, margin: 0, display: 'flex', flexDirection: 'column', gap: 6 }}>
|
|
{logs.map((log, i) => (
|
|
<li
|
|
key={i}
|
|
style={{
|
|
padding: '8px 12px',
|
|
borderRadius: 8,
|
|
background: 'rgba(255,255,255,0.04)',
|
|
border: '1px solid rgba(140,173,255,0.08)',
|
|
fontSize: 13,
|
|
color: 'var(--text-secondary)',
|
|
fontFamily: 'monospace',
|
|
}}
|
|
>
|
|
{log}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
)}
|
|
|
|
{logs.length === 0 && !folder && (
|
|
<div style={{
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
paddingTop: 60,
|
|
gap: 16,
|
|
opacity: 0.55,
|
|
}}>
|
|
<div style={{ fontSize: 64, filter: 'drop-shadow(0 8px 16px rgba(88,213,255,0.2))' }}>📂</div>
|
|
<p style={{ color: 'var(--text-muted)', fontSize: 15, textAlign: 'center' }}>
|
|
Öffne einen lokalen Ordner oder lade Repos über die Toolbar.
|
|
</p>
|
|
</div>
|
|
)}
|
|
</main>
|
|
|
|
{/* ── Settings-Modal ── */}
|
|
{showSettings && (
|
|
<div id="settingsModal" className="modal" onClick={e => { if (e.target === e.currentTarget) setShowSettings(false); }}>
|
|
<Settings onClose={() => setShowSettings(false)} />
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|