# 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 1. [Projektstruktur](#projektstruktur) 2. [Setup & Abhängigkeiten](#setup--abhängigkeiten) 3. [Entwicklung starten](#entwicklung-starten) 4. [Wichtige Module](#wichtige-module) 5. [Neue Features hinzufügen](#neue-features-hinzufügen) 6. [Build & Release](#build--release) 7. [Debugging & Testing](#debugging--testing) 8. [Code-Konventionen](#code-konventionen) 9. [Häufige Aufgaben](#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 ```bash # 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: ```bash # App neu starten npm start # Oder im laufenden Fenster: DevTools öffnen # Strg+Shift+I → Reload (Strg+R) ``` ### DevTools debuggen ```javascript // In main.js, beim Erstellen des Fensters: mainWindow.webContents.openDevTools(); // Oder per Shortcut im laufenden Fenster: // Strg+Shift+I ``` ### Logs anschauen ```bash # 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:** ```javascript // 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: ```javascript // 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. ```javascript // 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. ```javascript // 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 ```javascript /** * 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 ```javascript // 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 ```javascript // 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 ```bash # 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 einen `AbortController` an, `endCancellableUpload()` räumt auf (immer im `finally`). Der IPC-Kanal `cancel-upload` bricht alle laufenden Vorgänge ab. - Das `signal` wird durchgereicht an `simple-git` (`abort`), `execGit`/`runGitAsync` (`signal`), `runLimited` und `uploadItemsViaGiteaApi` (axios `signal`). - Ein Abbruch ist **kein Fehler**: Er läuft als `UPLOAD_CANCELLED` durch die Kette (`createUploadCancelledError`, `isUploadCancelledError`, `throwIfUploadCancelled` in `src/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, `signal` weiterreichen, im `catch` `isUploadCancelledError(e)` abfangen, im `finally` `endCancellableUpload()`. Im Renderer `showProgress(..., { cancellable: true })`. - Unter Windows beendet `spawn(signal)` nur `git.exe`; `execGit` beendet deshalb den ganzen Prozessbaum (`taskkill /T /F`) und kehrt sofort zurück. ### Pause, Sperre, Benachrichtigung, Release-Assistent - **Pause:** `src/features/pauseGate.js` (`createPauseGate`). In `main.js` gibt es genau ein `transferGate`. Kontrollpunkte rufen `await transferGate.wait(signal)` auf (in `runLimited`, vor dem Staging der Git-Wege, zwischen den Paketen von `uploadItemsViaGiteaApi` über `waitIfPaused`, vor jedem Batch-Clone). Ein Abbruch löst Wartende sofort aus. Neue langlaufende Schritte brauchen einen eigenen Kontrollpunkt. - **Zugangsdaten-Sperre:** `src/features/uploadBlocklist.js` nutzt die Dateinamen-Regeln aus `secretScan.js`. `removeBlockedInPlace()` und `blockedSecretReason()` in `main.js` sind in allen Upload-Handlern eingebaut, die Ergebnisse tragen `blockedFiles`. Neuer Upload-Weg: dort ebenfalls aufrufen. Einstellung `uploadBlockSecrets`. - **Benachrichtigung:** `src/features/transferNotice.js` baut den Text aus dem Verlaufseintrag, `maybeNotifyTransfer()` in `main.js` zeigt ihn nur, wenn das Hauptfenster nicht vorn ist (Einstellung `notifyTransfers`). - **Release-Assistent:** `src/features/releaseAssist.js` (Version aus Dateiname, Versionsvergleich, Tag-Prüfung, Release-Text mit Prüfsummen). IPC `inspect-release-file` und `prepare-release`, Oberfläche in `showCreateReleaseModal()`. Das Prüfsummen-Format in `buildReleaseBody` muss zu `extractChecksumFromReleaseBody` in `updater.js` passen. ### Startanimation Nach dem Vorbild des AeroMC-Launchers (`AeroMC-Launcher/src/startanimation.js`): 1. `createWindow()` berechnet Position und Größe (`centeredBounds`) und legt über `begin()` zuerst ein randloses, durchsichtiges Fenster mit `renderer/splash.html` an: das Logo dreht sich (CSS `rotateY`), darunter der Schriftzug. 2. Das Hauptfenster entsteht danach mit denselben Maßen, verborgen, und lädt. 3. `play()` wartet auf `did-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 mit `capturePage()` und lässt `aufbauen()` in `splash.js` das Bild von der Mitte aus aufziehen. 4. 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 mit `id` ergänzen, die Aktion in `trayTemplate()` in `main.js` verdrahten. - `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 in `upload-history.json` im userData-Ordner. `main.js` umhüllt dafür `ipcMain.handle` für die Kanäle in `UPLOAD_HISTORY_CHANNELS`, neue Upload-Kanäle dort eintragen. - Teilfehler: `buildPartialUploadError` hängt die fehlgeschlagenen Einträge an den Fehler (`failedItems`). Die Handler geben sie als `retryItems` zurück, der Renderer sendet sie über den Parameter `items` erneut (`retryFailedUploads`). - `.gitignore`-Vorlagen: `src/features/gitignoreTemplates.js`. ### Version erhöhen 1. Version in `package.json` updaten: `"version": "2.2.1"` 2. Changelog aktualisieren (optional) 3. Build ausführen 4. GitHub Release erstellen mit der .exe --- ## Debugging & Testing ### Unit Tests schreiben Jest ist konfiguriert. Test-Datei Vorlage: ```javascript // __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: ```bash npm test # Mit Coverage: npm test -- --coverage # Watch Mode: npm test -- --watch ``` ### Debugging im DevTools ```javascript // 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 ```javascript // 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 ```javascript // 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 ```javascript // 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 ```javascript // Kurze Inline-Kommentare über Code const delay = 1000; // Millisekunden /** * Längere Beschreibung vor Funktion * @param {string} repoName - Name des Repositories * @returns {Promise} Result mit { ok, data, error } */ async function loadRepository(repoName) { // Implementierung } ``` ### Fehlerbehandlung ```javascript // 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 1. **In `Settings.jsx` UI-Control hinzufügen** ```jsx setSetting('newOption', e.target.checked)} /> ``` 2. **In `renderer.js` speichern** ```javascript async function saveSettings(settings) { const result = await window.electronAPI.saveSettings(settings); // ... } ``` 3. **In `main.js` Handler** ```javascript ipcMain.handle('saveSettings', async (event, settings) => { // Validation und Speicherung return { ok: true }; }); ``` ### Neuer Button in der Toolbar 1. **In `index.html` Button hinzufügen** ```html ``` 2. **In `renderer.js` Event-Handler** ```javascript if ($('btnMyFeature')) { $('btnMyFeature').onclick = () => { myFeatureHandler(); }; } ``` ### Neue Kontextmenü-Option 1. **In `showRepoContextMenu()` Item hinzufügen** ```javascript items.push({ label: '🎯 Meine Aktion', click: () => myActionHandler(owner, repo) }); ``` 2. **Handler implementieren** ```javascript function myActionHandler(owner, repo) { // Logik... } ``` ### Neue API-Methode aufrufen 1. **In `src/git/apiHandler.js` ergänzen** 2. **In `main.js` IPC-Handler anlegen** 3. **In `renderer.js` aufrufen:** ```javascript const result = await window.electronAPI.myNewMethod({ param1, param2 }); ``` --- ## Troubleshooting für Entwickler ### App startet nicht ```bash # 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" ```bash # 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 - [Electron Dokumentation](https://www.electronjs.org/docs) - [Gitea API](https://docs.gitea.io/en-us/api-usage/) - [GitHub API v3](https://docs.github.com/en/rest) - [Jest Testing](https://jestjs.io/docs/getting-started) --- ## 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