18 KiB
Entwicklerhandbuch — Git Manager Explorer Pro
Dieses Dokument richtet sich an Entwickler, die an Git Manager Explorer Pro beitragen oder das Projekt erweitern möchten.
Inhaltsverzeichnis
- Projektstruktur
- Setup & Abhängigkeiten
- Entwicklung starten
- Wichtige Module
- Neue Features hinzufügen
- Build & Release
- Debugging & Testing
- Code-Konventionen
- Häufige Aufgaben
Projektstruktur
git-manager-gui/
├── main.js # Electron Main Process — Fenster, Menü, IPC
├── preload.js # Preload Script — sichere Electron API für Renderer
├── renderer/ # Frontend (React/Vanilla JS)
│ ├── App.jsx # React-Komponente (optional, optional genutzt)
│ ├── Settings.jsx # Settings-Modal
│ ├── index.html # HTML Entry Point
│ ├── index.js # Renderer Init
│ ├── renderer.js # Hauptlogik: UI, Grid, Editor, API-Calls
│ ├── style.css # Styling
│ └── modules/ # Feature-Module
│ ├── editor.js # Editor-Funktion (Syntax Highlighting, etc.)
│ ├── gitea.js # Gitea API Wrapper
│ ├── github.js # GitHub API Wrapper
│ ├── progress.js # Progress-Bar & Ladeindikatoren
│ ├── state.js # State Management (Favoriten, Verlauf, etc.)
│ └── ui.js # UI Helpers (Dialoge, Toast, etc.)
├── src/ # Backend (Node.js Main Process)
│ ├── git/
│ │ ├── gitHandler.js # Git CLI Wrapper (Commits, Tags, etc.)
│ │ └── apiHandler.js # Gitea/GitHub API HTTP Client
│ ├── backup/
│ │ ├── BackupManager.js # Backup/Restore Logik
│ │ ├── BackupProvider.js # Provider Interface
│ │ └── LocalProvider.js # Lokale Datei-Provider
│ └── utils/
│ └── helpers.js # Allgemeine Hilfsfunktionen
├── __tests__/
│ └── gitHandler.test.js # Jest Unit Tests
├── updater.js # App-Update-Logik
├── package.json # Dependencies & Scripts
├── HANDBUCH.html # Benutzerhandbuch (HTML)
└── README.md # Projekt-Übersicht
Setup & Abhängigkeiten
Voraussetzungen
- Node.js 16+ (empfohlen: LTS)
- npm 7+
- Git (für Git-Operationen)
- Visual Studio Code (optional, empfohlen)
Installation
# Repository klonen
git clone https://github.com/dein-username/git-manager-gui.git
cd git-manager-gui
# Dependencies installieren
npm install
# App starten
npm start
Wichtige Dependencies
| Package | Verwendung |
|---|---|
electron |
Desktop-Framework |
sqlite3 |
Lokale Datenspeicherung (Favoriten, Verlauf) |
axios |
HTTP-Requests zu Gitea/GitHub APIs |
crypto |
Verschlüsselung von Credentials |
jest |
Testing Framework |
Entwicklung starten
Dev-Server / Hot Reload
Es gibt aktuell keinen automatischen Hot Reload. Nach Code-Änderungen:
# App neu starten
npm start
# Oder im laufenden Fenster: DevTools öffnen
# Strg+Shift+I → Reload (Strg+R)
DevTools debuggen
// In main.js, beim Erstellen des Fensters:
mainWindow.webContents.openDevTools();
// Oder per Shortcut im laufenden Fenster:
// Strg+Shift+I
Logs anschauen
# Logs der letzten Session anschauen:
# Windows: %APPDATA%\git-manager-gui\logs\
# oder direkt im app data folder
# Mit Winston logger (falls implementiert):
npm run logs
Wichtige Module
renderer/renderer.js — Hauptlogik
Das Herzstück der App. Enthält:
- Globale State-Variablen:
favorites,recentRepos,currentState,pinnedRepos - Grid-Rendering:
loadRepos(),loadGiteaRepos(),loadGithubRepos() - Kontext-Menü:
showRepoContextMenu() - Datei-Explorer:
loadRepoContents(),renderExplorer() - Editor:
openFileEditor(), mit Speichern & Syntax-Highlighting - Favoriten/Verlauf:
addToFavorites(),addToRecent()
Wichtige Funktionen:
// Repository-Liste laden
loadRepos() → loadGiteaRepos() oder loadGithubRepos()
// Repository öffnen (Datei-Explorer)
loadRepoContents(owner, repo, path)
// Datei bearbeiten
openFileEditor(owner, repo, path, content)
// Favoriten hinzufügen
async addToFavorites(owner, repo, cloneUrl, platform)
// Settings speichern
async saveSettings(settings)
src/git/gitHandler.js — Git-Operationen
Wrapper um Git CLI. Beispiele:
// Commits einsehen
const commits = await getCommitLog(repoPath, branch);
// Tags auflisten
const tags = await getTagList(repoPath);
// Branch wechseln
await checkoutBranch(repoPath, branchName);
// Lokales Repo klonen
await cloneRepository(cloneUrl, targetPath);
src/git/apiHandler.js — API-Calls
HTTP-Wrapper für Gitea/GitHub APIs.
// Gitea Repositories auflisten
const repos = await getGiteaRepos(url, token, username);
// GitHub Repositories
const repos = await getGithubRepos(token);
// Repository erstellen
await createGiteaRepo(url, token, { name, description, private });
// Datei speichern
await updateGiteaFile(url, token, owner, repo, path, content, message);
renderer/modules/state.js — State Management
Persistiert Favoriten, Verlauf und Settings.
// State laden/speichern
loadState() → returns { favorites, recent, pinnedRepos }
saveState(state) → speichert lokal
// Helpers
addFavorite(repo)
removeFavorite(repo)
addRecentRepo(repo)
clearRecent()
Neue Features hinzufügen
Beispiel: Neuer API-Endpoint integrieren
Schritt 1: API-Wrapper in src/git/apiHandler.js ergänzen
/**
* Gitea Webhook auflisten
*/
async function getGiteaWebhooks(url, token, owner, repo) {
const path = `/api/v1/repos/${owner}/${repo}/hooks`;
return axios.get(`${url}${path}`, {
headers: { 'Authorization': `token ${token}` }
}).then(r => r.data);
}
module.exports = { getGiteaWebhooks, /* ... other functions */ };
Schritt 2: IPC-Handler in main.js ergänzen
// In ipcMain.handle() Bereich:
ipcMain.handle('getGiteaWebhooks', async (event, { url, token, owner, repo }) => {
try {
const webhooks = await apiHandler.getGiteaWebhooks(url, token, owner, repo);
return { ok: true, webhooks };
} catch (err) {
return { ok: false, error: err.message };
}
});
Schritt 3: UI in renderer/renderer.js hinzufügen
// Button im Repo-Kontextmenü:
if (option === 'webhooks') {
const webhooks = await window.electronAPI.getGiteaWebhooks({
url: currentState.giteaUrl,
token: credentials.giteaToken,
owner,
repo
});
if (webhooks.ok) {
showWebhookList(webhooks.webhooks);
} else {
showError('Webhooks laden fehlgeschlagen: ' + webhooks.error);
}
}
Build & Release
Production Build
# Electron App als .exe packagen
npm run build
# Output: dist/git-manager-gui-Setup-2.x.x.exe
Abbrechbare Vorgänge
Uploads, Ordner-Downloads und Batch-Clones laufen über ein gemeinsames Abbruch-System:
main.js:beginCancellableUpload()legt einenAbortControlleran,endCancellableUpload()räumt auf (immer imfinally). Der IPC-Kanalcancel-uploadbricht alle laufenden Vorgänge ab.- Das
signalwird durchgereicht ansimple-git(abort),execGit/runGitAsync(signal),runLimitedunduploadItemsViaGiteaApi(axiossignal). - Ein Abbruch ist kein Fehler: Er läuft als
UPLOAD_CANCELLEDdurch die Kette (createUploadCancelledError,isUploadCancelledError,throwIfUploadCancelledinsrc/git/apiHandler.js), löst keinen API-Ausweichweg aus und kommt als{ ok: false, cancelled: true }im Renderer an. - Neuer abbrechbarer Handler:
beginCancellableUpload()am Anfang,signalweiterreichen, imcatchisUploadCancelledError(e)abfangen, imfinallyendCancellableUpload(). Im RenderershowProgress(..., { cancellable: true }). - Unter Windows beendet
spawn(signal)nurgit.exe;execGitbeendet deshalb den ganzen Prozessbaum (taskkill /T /F) und kehrt sofort zurück.
Pause, Sperre, Benachrichtigung, Release-Assistent
- Pause:
src/features/pauseGate.js(createPauseGate). Inmain.jsgibt es genau eintransferGate. Kontrollpunkte rufenawait transferGate.wait(signal)auf (inrunLimited, vor dem Staging der Git-Wege, zwischen den Paketen vonuploadItemsViaGiteaApiüberwaitIfPaused, vor jedem Batch-Clone). Ein Abbruch löst Wartende sofort aus. Neue langlaufende Schritte brauchen einen eigenen Kontrollpunkt. - Zugangsdaten-Sperre:
src/features/uploadBlocklist.jsnutzt die Dateinamen-Regeln aussecretScan.js.removeBlockedInPlace()undblockedSecretReason()inmain.jssind in allen Upload-Handlern eingebaut, die Ergebnisse tragenblockedFiles. Neuer Upload-Weg: dort ebenfalls aufrufen. EinstellunguploadBlockSecrets. - Benachrichtigung:
src/features/transferNotice.jsbaut den Text aus dem Verlaufseintrag,maybeNotifyTransfer()inmain.jszeigt ihn nur, wenn das Hauptfenster nicht vorn ist (EinstellungnotifyTransfers). - Release-Assistent:
src/features/releaseAssist.js(Version aus Dateiname, Versionsvergleich, Tag-Prüfung, Release-Text mit Prüfsummen). IPCinspect-release-fileundprepare-release, Oberfläche inshowCreateReleaseModal(). Das Prüfsummen-Format inbuildReleaseBodymuss zuextractChecksumFromReleaseBodyinupdater.jspassen.
Startanimation
Nach dem Vorbild des AeroMC-Launchers (AeroMC-Launcher/src/startanimation.js):
createWindow()berechnet Position und Größe (centeredBounds) und legt überbegin()zuerst ein randloses, durchsichtiges Fenster mitrenderer/splash.htmlan: das Logo dreht sich (CSSrotateY), darunter der Schriftzug.- Das Hauptfenster entsteht danach mit denselben Maßen, verborgen, und lädt.
play()wartet aufdid-finish-load(höchstens 12 s) und mindestens 1,6 s Drehzeit. Dann zeigt es das Hauptfenster unsichtbar (Deckkraft 0, Mausereignisse aus), wartet auf die gezeichnete Oberfläche (Repo-Liste oder höchstens 1,5 s), fotografiert es mitcapturePage()und lässtaufbauen()insplash.jsdas Bild von der Mitte aus aufziehen.- Am Ende übernimmt das echte Fenster an derselben Stelle. Fehler und Zeitüberschreitungen zeigen das Hauptfenster immer trotzdem.
Stolperstein: setIgnoreMouseEvents(true) am Startfenster darf erst nach dem Zeigen und leicht verzögert aufgerufen werden (IGNORE_MOUSE_DELAY_MS). Davor aufgerufen wird das durchsichtige Fenster unter Windows weiß. scripts/ui-smoke-splash.js prüft das über eine Bildschirmaufnahme (Farbe an einer leeren Stelle muss der des Desktops entsprechen) und darf deshalb die Hardware-Beschleunigung nicht abschalten.
Beim Start mit --hidden und bei abgeschalteter Einstellung showSplash gibt es die Animation nicht. scripts/ui-smoke-splash.js prüft sie mit einem Ersatz-Hauptfenster. Im Entwicklungsmodus (electron .) startet die App wegen der vielen node_modules-Dateien deutlich langsamer als das gepackte Programm; die Animation selbst wird dadurch nicht langsamer.
Oberflächen-Testlauf
npm run test:ui (scripts/ui-smoke.js) startet die App mit leerem eigenen APPDATA, steuert sie über den Debug-Port und prüft Toolbar-Layout bei drei Breiten, Fortschrittsbalken, Pause, Verlauf, Sperre, Release-Prüfung und Vorlagen. scripts/ui-smoke-tray.js prüft das Tray-Menüfenster in echtem Electron. Der Lauf berührt weder echte Zugangsdaten noch einen Server und dauert gut eine Minute.
Tray-Menü
Das Tray-Symbol öffnet kein natives Menü, sondern ein eigenes kleines Fenster, denn das native Electron-Menü zeichnet unter Windows keine Hover-Markierung:
src/features/trayMenu.js: Inhalt (buildTrayTemplate,serializeTemplate,runAction,trayTooltip), ohne Electron und damit testbar. Neuer Eintrag: dort mitidergänzen, die Aktion intrayTemplate()inmain.jsverdrahten.src/features/trayPopup.js: das Fenster (frameless, transparent, schließt bei Fokusverlust und Esc). Es wird 2 Sekunden nach dem Start vorgeladen, weil der erste Renderer-Start mehrere Sekunden dauert.renderer/tray-menu.html,renderer/tray-menu.js,tray-menu-preload.js: Darstellung (hell/dunkel nach Windows-Design, Pfeiltasten und Enter) und die vier IPC-Kanäle.- Das Fenster ist von der Zoom-Einstellung ausgenommen und wird beim Beenden zerstört, sonst hielte das versteckte Fenster die App am Leben.
Upload-Verlauf und Wiederholen
src/features/uploadHistory.js(buildEntry,filterEntries,createUploadHistory): speichert die letzten 100 Uploads inupload-history.jsonim userData-Ordner.main.jsumhüllt dafüripcMain.handlefür die Kanäle inUPLOAD_HISTORY_CHANNELS, neue Upload-Kanäle dort eintragen.- Teilfehler:
buildPartialUploadErrorhängt die fehlgeschlagenen Einträge an den Fehler (failedItems). Die Handler geben sie alsretryItemszurück, der Renderer sendet sie über den Parameteritemserneut (retryFailedUploads). .gitignore-Vorlagen:src/features/gitignoreTemplates.js.
Version erhöhen
- Version in
package.jsonupdaten:"version": "2.2.1" - Changelog aktualisieren (optional)
- Build ausführen
- GitHub Release erstellen mit der .exe
Debugging & Testing
Unit Tests schreiben
Jest ist konfiguriert. Test-Datei Vorlage:
// __tests__/myFeature.test.js
const { myFunction } = require('../src/git/gitHandler');
describe('Git Handler', () => {
it('should parse commit log', () => {
const result = myFunction(testData);
expect(result.length).toBe(3);
expect(result[0].sha).toMatch(/^[a-f0-9]{7}/);
});
});
Tests starten:
npm test
# Mit Coverage:
npm test -- --coverage
# Watch Mode:
npm test -- --watch
Debugging im DevTools
// Im renderer.js oder irgendwo im Renderer:
console.log('Debug Info:', data);
// Öffne DevTools: Strg+Shift+I
// Console Tab → alle Logs sichtbar
Main Process debuggen
// In main.js:
console.log('Main Process Log:', data);
// Logs erscheinen in der Terminal-Console
// wenn die App mit npm start gestartet wurde
Code-Konventionen
Variablen & Funktionen
// camelCase für Variablen und Funktionen
const repoName = "mein-projekt";
function loadRepositories() { }
// SCREAMING_SNAKE_CASE für Konstanten
const MAX_RETRIES = 5;
const DEFAULT_TIMEOUT = 3000;
// Präfixe für Boolean-Variablen
const isPrivate = true;
const hasCredentials = false;
const shouldRetry = true;
Async/Await
// Immer try-catch für async Funktionen
async function loadData() {
try {
const data = await fetchFromAPI();
return { ok: true, data };
} catch (error) {
console.error('Error:', error);
return { ok: false, error: error.message };
}
}
Kommentare
// Kurze Inline-Kommentare über Code
const delay = 1000; // Millisekunden
/**
* Längere Beschreibung vor Funktion
* @param {string} repoName - Name des Repositories
* @returns {Promise<Object>} Result mit { ok, data, error }
*/
async function loadRepository(repoName) {
// Implementierung
}
Fehlerbehandlung
// Immer aussagekräftige Fehlermeldungen
if (!token) {
return { ok: false, error: 'missing-token' };
}
// Oder sprechend für Benutzer:
if (!token) {
return { ok: false, error: 'Gitea Token nicht gespeichert. Bitte Settings öffnen.' };
}
Häufige Aufgaben
Neue Einstellung hinzufügen
-
In
Settings.jsxUI-Control hinzufügen<label>Neue Option</label> <input type="checkbox" onChange={(e) => setSetting('newOption', e.target.checked)} /> -
In
renderer.jsspeichernasync function saveSettings(settings) { const result = await window.electronAPI.saveSettings(settings); // ... } -
In
main.jsHandleripcMain.handle('saveSettings', async (event, settings) => { // Validation und Speicherung return { ok: true }; });
Neuer Button in der Toolbar
-
In
index.htmlButton hinzufügen<button id="btnMyFeature" title="Mein Feature">🎯 Feature</button> -
In
renderer.jsEvent-Handlerif ($('btnMyFeature')) { $('btnMyFeature').onclick = () => { myFeatureHandler(); }; }
Neue Kontextmenü-Option
-
In
showRepoContextMenu()Item hinzufügenitems.push({ label: '🎯 Meine Aktion', click: () => myActionHandler(owner, repo) }); -
Handler implementieren
function myActionHandler(owner, repo) { // Logik... }
Neue API-Methode aufrufen
- In
src/git/apiHandler.jsergänzen - In
main.jsIPC-Handler anlegen - In
renderer.jsaufrufen:const result = await window.electronAPI.myNewMethod({ param1, param2 });
Troubleshooting für Entwickler
App startet nicht
# Node/npm Version prüfen
node --version # sollte >= 16
npm --version # sollte >= 7
# Dependencies neu installieren
rm -r node_modules
npm install
npm start
Fehler: "Cannot find module"
# Dependencies aktualisieren
npm install
# Cache löschen
npm cache clean --force
Axios/API-Calls schlagen fehl
- URL/Token in Settings prüfen
- Gitea-Server online?
curl https://git.example.com/api/v1/user - Token noch gültig? Im Gitea-Interface regenerieren
- Firewall/VPN blockiert?
Datei-Upload funktioniert nicht
- Lokale Temp-Pfade prüfen (in
main.js) - Git-Auth konfiguriert?
- Ausreichend Festplatte?
Ressourcen
Lizenz & Beitragen
Dieses Projekt ist unter der MIT-Lizenz lizenziert.
Für Beiträge bitte einen Pull Request einreichen mit aussagekräftiger Beschreibung.
Letzte Aktualisierung: 13. Mai 2026 | Ersteller: M_Viper