diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 305b469..1434495 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,6 +1,123 @@ TASKMATE - CHANGELOG ==================== +================================================================================ +29.12.2025 - Gitea: Branch umbenennen + UI-Aufräumung +================================================================================ + +FEATURE: LOKALEN BRANCH UMBENENNEN +-------------------------------------------------------------------------------- +- Neuer Stift-Button neben dem Branch-Dropdown +- Modal zum Umbenennen des aktuellen Branches (z.B. "master" → "main") +- Backend-Endpoint: POST /api/git/rename-branch/:projectId + +UI-AUFRÄUMUNG +-------------------------------------------------------------------------------- +- "Ahead/Behind" Anzeige entfernt (war verwirrend) +- Branch-Bereich aufgeräumt mit Rename-Button + +ÄNDERUNGEN +-------------------------------------------------------------------------------- +- frontend/index.html: + * Branch-Select-Group mit Rename-Button + * Neues Rename-Branch-Modal + * Ahead/Behind entfernt +- frontend/css/gitea.css: + * .branch-select-group, .btn-small, .btn-icon Styles + * .status-badge.ahead und #git-ahead-behind entfernt +- frontend/js/gitea.js: + * openRenameBranchModal(), executeRenameBranch() hinzugefügt + * Ahead/Behind-Rendering entfernt +- frontend/js/api.js: gitRenameBranch() hinzugefügt +- backend/services/gitService.js: renameBranch() Funktion +- backend/routes/git.js: rename-branch Endpoint +- frontend/sw.js: Cache-Version auf 123 erhöht + +================================================================================ +29.12.2025 - Gitea: Force-Push Option +================================================================================ + +FEATURE: FORCE-PUSH UM REMOTE ZU ÜBERSCHREIBEN +-------------------------------------------------------------------------------- +- Problem: Push auf Remote-Branch mit unterschiedlicher Historie schlug fehl + (z.B. wenn Gitea eine README erstellt hat und man master→main pushen will) +- Lösung: Force-Push Option im Push-Modal hinzugefügt + +ÄNDERUNGEN +-------------------------------------------------------------------------------- +- frontend/index.html: Checkbox "Force Push (Remote überschreiben)" im Push-Modal +- frontend/css/gitea.css: .form-hint.warning Style für Warnung +- frontend/js/gitea.js: Force-Flag wird an API übergeben +- frontend/js/api.js: gitInitPush() akzeptiert force Parameter +- backend/services/gitService.js: pushWithUpstream() mit --force Flag +- backend/routes/git.js: init-push Endpoint akzeptiert force Parameter +- frontend/sw.js: Cache-Version auf 122 erhöht + +================================================================================ +29.12.2025 - Gitea: Bugfix Ziel-Branch Auswahl +================================================================================ + +BUGFIX: PUSH MIT ZIEL-BRANCH FUNKTIONIERTE NICHT +-------------------------------------------------------------------------------- +- Problem: Bei Auswahl eines anderen Ziel-Branches (z.B. "main" statt "master") + wurde trotzdem der reguläre Push verwendet, der die Auswahl ignorierte +- Ursache: executePush() versuchte immer zuerst den normalen Push, der den + bestehenden Upstream verwendet, nicht den ausgewählten Target-Branch + +LÖSUNG +-------------------------------------------------------------------------------- +- frontend/js/gitea.js: executePush() Logik korrigiert + * Wenn Ziel-Branch != lokaler Branch → verwendet immer init-push mit Mapping + * Nur bei gleichem Branch-Namen → normaler Push mit Fallback + * Zeigt Info-Toast mit "Push von X nach Y" +- frontend/sw.js: Cache-Version auf 121 erhöht + +================================================================================ +29.12.2025 - Gitea: Ziel-Branch Auswahl beim Push +================================================================================ + +FEATURE: ZIEL-BRANCH AUSWAHL BEIM PUSH +-------------------------------------------------------------------------------- +- Neues Push-Modal mit Branch-Auswahl vor dem Push +- Benutzer können jetzt wählen auf welchen Remote-Branch gepusht wird +- Z.B. lokaler Branch "master" kann als "main" auf Gitea gepusht werden +- Auswahl: "Gleicher Name wie lokal", "main", "master", "develop" + +ÄNDERUNGEN +-------------------------------------------------------------------------------- +- backend/services/gitService.js: pushWithUpstream() unterstützt jetzt targetBranch + * Branch-Mapping: `git push -u origin master:main` möglich + * Gibt sowohl localBranch als auch remoteBranch im Ergebnis zurück +- backend/routes/git.js: init-push Endpoint akzeptiert targetBranch Parameter +- frontend/js/api.js: gitInitPush() mit targetBranch Parameter +- frontend/js/gitea.js: + * Push-Button öffnet jetzt Modal statt direkt zu pushen + * Neue Methoden: openPushModal(), executePush() +- frontend/index.html: Neues Push-Modal mit Branch-Auswahl +- frontend/css/gitea.css: .form-static-value Style hinzugefügt +- frontend/sw.js: Cache-Version auf 120 erhöht + +================================================================================ +29.12.2025 - Gitea-Integration Bugfix: Branch-Mismatch +================================================================================ + +BUGFIX: DEFAULT-BRANCH MISMATCH ZWISCHEN GIT UND GITEA +-------------------------------------------------------------------------------- +- Problem: Dateien wurden nach "master" gepusht, aber Gitea zeigte "main" +- Benutzer sahen nur die auto-generierte README statt ihrer gepushten Dateien +- Ursache: Lokaler Branch "master" != Gitea Default-Branch "main" + +LÖSUNG +-------------------------------------------------------------------------------- +- backend/services/giteaService.js: NEU - updateRepository() Funktion + * Erlaubt das Ändern des Default-Branch über Gitea PATCH API + * Unterstützt auch Beschreibung und Private-Status Änderungen +- backend/services/gitService.js: pushWithUpstream() gibt jetzt Branch-Namen zurück +- backend/routes/git.js: init-push Endpoint aktualisiert Default-Branch automatisch + * Nach erfolgreichem Push wird Gitea's Default-Branch auf den gepushten Branch gesetzt + * Owner/Repo wird automatisch aus der Repository-URL extrahiert +- frontend/sw.js: Cache-Version auf 119 erhöht + ================================================================================ 28.12.2025 - Gitea-Integration ================================================================================ diff --git a/GITEA_INTEGRATION_STATUS.md b/GITEA_INTEGRATION_STATUS.md new file mode 100644 index 0000000..7ab1f6f --- /dev/null +++ b/GITEA_INTEGRATION_STATUS.md @@ -0,0 +1,179 @@ +# Gitea-Integration Status - TaskMate + +**Datum:** 29.12.2024 +**Status:** Vollständig implementiert - Bugfix angewendet + +--- + +## Übersicht + +Die Gitea-Integration für TaskMate ist vollständig implementiert. Der kritische Branch-Mismatch Bug wurde behoben - nach einem Push wird der Default-Branch in Gitea automatisch auf den gepushten Branch aktualisiert. + +--- + +## Was wurde bereits implementiert + +### Backend (vollständig) + +1. **`backend/server.js`** - Routes registriert: + ```javascript + const gitRoutes = require('./routes/git'); + const applicationsRoutes = require('./routes/applications'); + const giteaRoutes = require('./routes/gitea'); + + app.use('/api/git', authenticateToken, csrfProtection, gitRoutes); + app.use('/api/applications', authenticateToken, csrfProtection, applicationsRoutes); + app.use('/api/gitea', authenticateToken, csrfProtection, giteaRoutes); + ``` + +2. **`backend/routes/gitea.js`** - NEU erstellt mit Endpoints: + - `GET /test` - Verbindung testen + - `GET /repositories` - Alle Repos auflisten + - `POST /repositories` - Neues Repo erstellen + - `GET /repositories/:owner/:repo` - Repo-Details + - `GET /repositories/:owner/:repo/branches` - Branches + - `GET /repositories/:owner/:repo/commits` - Commits + +3. **`backend/routes/git.js`** - Erweitert mit: + - `POST /set-remote` - Remote setzen + - `POST /prepare-for-gitea` - Repository für Gitea vorbereiten + +4. **`backend/services/gitService.js`** - Erweitert mit: + - `setRemote()` - Remote-URL setzen + - `prepareForGitea()` - Repository für Gitea vorbereiten (remote + initial commit) + - `pushWithUpstream()` - Push mit automatischer Branch-Erkennung + +5. **`backend/services/giteaService.js`** - Vorhanden mit: + - `listRepositories()` - Organisation-Repositories auflisten + - `getRepository()` - Einzelnes Repo abrufen + - `createRepository()` - Neues Repo erstellen + - `updateRepository()` - Repo-Einstellungen aktualisieren (inkl. default_branch) + - `deleteRepository()` - Repo löschen + - `testConnection()` - Verbindung testen + - `getAuthenticatedCloneUrl()` - Clone-URL mit Token + +6. **`Dockerfile`** - Git-Unterstützung hinzugefügt: + ```dockerfile + RUN apk add --no-cache git + RUN git config --system --add safe.directory '*' + RUN git config --system user.email "taskmate@local" && \ + git config --system user.name "TaskMate" && \ + git config --system init.defaultBranch main + ``` + +### Frontend (vollständig) + +1. **`frontend/js/api.js`** - Erweitert mit allen Gitea/Git API-Methoden + +2. **`frontend/js/gitea.js`** - NEU erstellt: + - Kompletter GiteaManager mit allen Funktionen + - Konfigurationsansicht + - Status-Anzeige + - Git-Operationen (Fetch, Pull, Push, Commit) + - Commit-Historie + - Branch-Wechsel + +3. **`frontend/css/gitea.css`** - NEU erstellt: + - Alle Styles für Gitea-Tab + +4. **`frontend/index.html`** - Erweitert: + - Gitea-Tab in Navigation + - Gitea-View Container + - Commit-Modal + - Create-Repo-Modal + +5. **`frontend/js/app.js`** - Integriert: + - GiteaManager Import + - View-Switching für Gitea-Tab + +6. **`frontend/sw.js`** - Cache-Version erhöht + +--- + +## Der gelöste Bug: Branch-Mismatch + +### Problem (GELÖST) +- 146 Dateien wurden erfolgreich nach Gitea gepusht +- Die Dateien landeten im Branch `master` +- Gitea zeigte aber `main` als Standard-Branch an +- Benutzer sahen nur die auto-generierte README statt ihrer Dateien + +### Ursache +1. Gitea erstellt Repositories mit `default_branch: 'main'` (Zeile 179 in giteaService.js) +2. Der lokale Git-Branch heißt aber `master` +3. Die Dateien wurden nach `master` gepusht +4. Gitea zeigte `main` an (leer bis auf README) + +### Implementierte Lösung + +1. **`updateRepository()` Funktion** zu `backend/services/giteaService.js` hinzugefügt + - Ändert den Default-Branch über Gitea PATCH API + - Unterstützt auch Beschreibung und Private-Status + +2. **`pushWithUpstream()` Funktion** in `backend/services/gitService.js` erweitert + - Gibt jetzt den Branch-Namen im Ergebnis zurück + +3. **`init-push` Endpoint** in `backend/routes/git.js` erweitert + - Nach erfolgreichem Push wird automatisch der Default-Branch in Gitea aktualisiert + - Owner/Repo wird aus der Repository-URL extrahiert + +4. **Cache-Version** auf 119 erhöht in `frontend/sw.js` + +--- + +## Gelöste Probleme (zur Referenz) + +1. **"git: not found"** → Git in Dockerfile installiert +2. **"dubious ownership in repository"** → `safe.directory '*'` konfiguriert +3. **"No configured push destination"** → `setRemote()` und `prepareForGitea()` hinzugefügt +4. **"src refspec main does not match any"** → Branch-Erkennung in `pushWithUpstream()` implementiert + +--- + +## Wichtige Dateien + +| Datei | Status | +|-------|--------| +| `backend/server.js` | ✅ Fertig | +| `backend/routes/gitea.js` | ✅ Fertig | +| `backend/routes/git.js` | ✅ Fertig (inkl. auto Default-Branch Update) | +| `backend/services/gitService.js` | ✅ Fertig (inkl. Branch-Name Return) | +| `backend/services/giteaService.js` | ✅ Fertig (inkl. updateRepository) | +| `Dockerfile` | ✅ Fertig | +| `frontend/js/api.js` | ✅ Fertig | +| `frontend/js/gitea.js` | ✅ Fertig | +| `frontend/css/gitea.css` | ✅ Fertig | +| `frontend/index.html` | ✅ Fertig | +| `frontend/js/app.js` | ✅ Fertig | +| `frontend/sw.js` | ✅ Fertig (v119) | + +--- + +## Nächste Schritte + +1. ✅ `updateRepository()` zu `backend/services/giteaService.js` hinzugefügt +2. ✅ Funktion exportiert +3. ✅ Push-Flow erweitert, um Default-Branch nach Push zu aktualisieren +4. ✅ Docker-Container neu gebaut +5. ⏳ Testen: Projekt mit Gitea verknüpfen → Push → Dateien in Gitea sichtbar + +--- + +## Plan-Datei + +Der vollständige Implementierungsplan befindet sich in: +`C:\Users\hendr\.claude\plans\rosy-stargazing-scroll.md` + +--- + +## Befehle zum Testen + +```bash +# Container neu bauen +docker compose down +docker compose build --no-cache +docker compose up -d + +# Browser öffnen +start chrome --incognito http://localhost:3000 +``` diff --git a/backend/routes/git.js b/backend/routes/git.js index 3ddfd94..ba930a3 100644 --- a/backend/routes/git.js +++ b/backend/routes/git.js @@ -414,24 +414,58 @@ router.post('/set-remote/:projectId', (req, res) => { /** * POST /api/git/init-push/:projectId * Initialen Push mit Upstream-Tracking + * Body: { targetBranch?: string, force?: boolean } + * - targetBranch: Optional - Ziel-Branch auf Remote (z.B. "main" auch wenn lokal "master") + * - force: Optional - Force-Push um Remote zu überschreiben */ -router.post('/init-push/:projectId', (req, res) => { +router.post('/init-push/:projectId', async (req, res) => { try { const { projectId } = req.params; - const { branch } = req.body; + const { targetBranch, force } = req.body; const application = getApplicationForProject(projectId); if (!application) { return res.status(404).json({ error: 'Keine Anwendung für dieses Projekt konfiguriert' }); } - const currentBranch = branch || 'main'; - const result = gitService.pushWithUpstream(application.local_path, currentBranch); + // targetBranch kann null sein - dann wird der lokale Branch-Name verwendet + // force: boolean - überschreibt Remote-Branch bei Konflikten + const result = gitService.pushWithUpstream(application.local_path, targetBranch || null, 'origin', force === true); if (result.success) { // Sync-Zeitpunkt aktualisieren const db = getDb(); db.prepare('UPDATE applications SET last_sync = CURRENT_TIMESTAMP WHERE project_id = ?').run(projectId); + + // Default-Branch in Gitea aktualisieren wenn der gepushte Branch abweicht + if (application.gitea_repo_url && result.branch) { + try { + // Owner/Repo aus URL extrahieren (z.B. https://gitea.../AegisSight/TaskMate.git) + const urlMatch = application.gitea_repo_url.match(/\/([^\/]+)\/([^\/]+?)(?:\.git)?$/); + if (urlMatch) { + const owner = urlMatch[1]; + const repoName = urlMatch[2]; + const actualBranch = result.branch; + + // Default-Branch in Gitea setzen + const updateResult = await giteaService.updateRepository(owner, repoName, { + defaultBranch: actualBranch + }); + + if (updateResult.success) { + logger.info(`Default-Branch in Gitea auf '${actualBranch}' gesetzt für ${owner}/${repoName}`); + result.giteaUpdated = true; + result.defaultBranch = actualBranch; + } else { + logger.warn(`Konnte Default-Branch in Gitea nicht aktualisieren: ${updateResult.error}`); + result.giteaUpdated = false; + } + } + } catch (giteaError) { + logger.warn('Fehler beim Aktualisieren des Default-Branch in Gitea:', giteaError); + result.giteaUpdated = false; + } + } } res.json(result); @@ -441,4 +475,31 @@ router.post('/init-push/:projectId', (req, res) => { } }); +/** + * POST /api/git/rename-branch/:projectId + * Branch umbenennen + * Body: { oldName: string, newName: string } + */ +router.post('/rename-branch/:projectId', (req, res) => { + try { + const { projectId } = req.params; + const { oldName, newName } = req.body; + const application = getApplicationForProject(projectId); + + if (!application) { + return res.status(404).json({ error: 'Keine Anwendung für dieses Projekt konfiguriert' }); + } + + if (!oldName || !newName) { + return res.status(400).json({ error: 'oldName und newName sind erforderlich' }); + } + + const result = gitService.renameBranch(application.local_path, oldName, newName); + res.json(result); + } catch (error) { + logger.error('Fehler beim Umbenennen des Branches:', error); + res.status(500).json({ error: 'Serverfehler' }); + } +}); + module.exports = router; diff --git a/backend/services/gitService.js b/backend/services/gitService.js index f1f3410..e185f2f 100644 --- a/backend/services/gitService.js +++ b/backend/services/gitService.js @@ -443,7 +443,7 @@ function hasRemote(localPath, remoteName = 'origin') { /** * Initialen Push mit Upstream-Tracking */ -function pushWithUpstream(localPath, branch = null, remoteName = 'origin') { +function pushWithUpstream(localPath, targetBranch = null, remoteName = 'origin', force = false) { if (!isGitRepository(localPath)) { return { success: false, error: 'Kein Git-Repository' }; } @@ -477,11 +477,12 @@ function pushWithUpstream(localPath, branch = null, remoteName = 'origin') { } } - // Aktuellen Branch ermitteln NACH dem Commit + // Aktuellen (lokalen) Branch ermitteln NACH dem Commit + let localBranch = null; const branchResult = execGitCommand('git branch --show-current', localPath); if (branchResult.success && branchResult.output) { - branch = branchResult.output; - logger.info(`Aktueller Branch: ${branch}`); + localBranch = branchResult.output; + logger.info(`Lokaler Branch: ${localBranch}`); } else { // Fallback: Branch aus git branch auslesen const branchListResult = execGitCommand('git branch', localPath); @@ -491,29 +492,46 @@ function pushWithUpstream(localPath, branch = null, remoteName = 'origin') { const lines = branchListResult.output.split('\n'); for (const line of lines) { if (line.includes('*')) { - branch = line.replace('*', '').trim(); + localBranch = line.replace('*', '').trim(); break; } } } - if (!branch) { + if (!localBranch) { // Letzter Fallback: Versuche den Branch zu erstellen logger.info('Kein Branch gefunden, erstelle main'); execGitCommand('git checkout -b main', localPath); - branch = 'main'; + localBranch = 'main'; } } - logger.info(`Push auf Branch: ${branch}`); + // Wenn kein Ziel-Branch angegeben, verwende lokalen Branch-Namen + const remoteBranch = targetBranch || localBranch; + + logger.info(`Push: lokaler Branch '${localBranch}' → Remote Branch '${remoteBranch}'${force ? ' (FORCE)' : ''}`); // Push mit -u für Upstream-Tracking - const pushResult = execGitCommand(`git push -u ${remoteName} ${branch}`, localPath, { timeout: 120000 }); + // Format: git push -u origin localBranch:remoteBranch + const forceFlag = force ? ' --force' : ''; + let pushCommand; + if (localBranch === remoteBranch) { + pushCommand = `git push -u${forceFlag} ${remoteName} ${localBranch}`; + } else { + // Branch-Mapping: lokalen Branch auf anderen Remote-Branch pushen + pushCommand = `git push -u${forceFlag} ${remoteName} ${localBranch}:${remoteBranch}`; + } + + const pushResult = execGitCommand(pushCommand, localPath, { timeout: 120000 }); if (!pushResult.success) { logger.error(`Push fehlgeschlagen: ${pushResult.error}`); } + // Branch-Namen im Ergebnis inkludieren für Default-Branch Aktualisierung + pushResult.localBranch = localBranch; + pushResult.branch = remoteBranch; // Remote-Branch für Gitea Default-Branch + return pushResult; } @@ -561,6 +579,39 @@ function prepareForGitea(localPath, remoteUrl, options = {}) { return { success: true, message: 'Repository für Gitea vorbereitet' }; } +/** + * Branch umbenennen + */ +function renameBranch(localPath, oldName, newName) { + if (!isGitRepository(localPath)) { + return { success: false, error: 'Kein Git-Repository' }; + } + + // Validiere neuen Branch-Namen + if (!newName || !/^[a-zA-Z0-9_\-]+$/.test(newName)) { + return { success: false, error: 'Ungültiger Branch-Name. Nur Buchstaben, Zahlen, Unterstriche und Bindestriche erlaubt.' }; + } + + // Prüfe ob wir auf dem zu umbenennenden Branch sind + const branchResult = execGitCommand('git branch --show-current', localPath); + const currentBranch = branchResult.success ? branchResult.output : null; + + if (currentBranch !== oldName) { + return { success: false, error: `Bitte wechsle zuerst zum Branch "${oldName}" bevor du ihn umbenennst.` }; + } + + // Branch umbenennen + const renameResult = execGitCommand(`git branch -m ${oldName} ${newName}`, localPath); + + if (!renameResult.success) { + logger.error(`Branch umbenennen fehlgeschlagen: ${renameResult.error}`); + return renameResult; + } + + logger.info(`Branch umbenannt: ${oldName} → ${newName}`); + return { success: true, oldName, newName, message: `Branch "${oldName}" zu "${newName}" umbenannt` }; +} + module.exports = { windowsToContainerPath, containerToWindowsPath, @@ -581,5 +632,6 @@ module.exports = { setRemote, hasRemote, pushWithUpstream, - prepareForGitea + prepareForGitea, + renameBranch }; diff --git a/backend/services/giteaService.js b/backend/services/giteaService.js index 57de126..9b0d09c 100644 --- a/backend/services/giteaService.js +++ b/backend/services/giteaService.js @@ -284,12 +284,44 @@ function getSafeCloneUrl(cloneUrl) { return cloneUrl.replace(/https:\/\/[^@]+@/, 'https://'); } +/** + * Repository-Einstellungen aktualisieren (z.B. default_branch ändern) + */ +async function updateRepository(owner, repo, options = {}) { + try { + const updateData = {}; + if (options.defaultBranch) updateData.default_branch = options.defaultBranch; + if (options.description !== undefined) updateData.description = options.description; + if (options.private !== undefined) updateData.private = options.private; + + const repoData = await giteaFetch(`/repos/${owner}/${repo}`, { + method: 'PATCH', + body: JSON.stringify(updateData) + }); + + logger.info(`Repository ${owner}/${repo} aktualisiert (default_branch: ${repoData.default_branch})`); + return { + success: true, + repository: { + id: repoData.id, + name: repoData.name, + fullName: repoData.full_name, + defaultBranch: repoData.default_branch + } + }; + } catch (error) { + logger.error(`Fehler beim Aktualisieren des Repositories ${owner}/${repo}:`, error); + return { success: false, error: error.message }; + } +} + module.exports = { listRepositories, getRepository, getRepositoryBranches, getRepositoryCommits, createRepository, + updateRepository, deleteRepository, getCurrentUser, testConnection, diff --git a/backups/backup_2025-12-22T11-33-43-528Z.db-wal b/backups/backup_2025-12-22T11-33-43-528Z.db-wal deleted file mode 100644 index 15c3b34..0000000 Binary files a/backups/backup_2025-12-22T11-33-43-528Z.db-wal and /dev/null differ diff --git a/backups/backup_2025-12-22T11-44-05-900Z.db-wal b/backups/backup_2025-12-22T11-44-05-900Z.db-wal deleted file mode 100644 index 7921e9c..0000000 Binary files a/backups/backup_2025-12-22T11-44-05-900Z.db-wal and /dev/null differ diff --git a/backups/backup_2025-12-22T12-06-42-448Z.db-wal b/backups/backup_2025-12-22T12-06-42-448Z.db-wal deleted file mode 100644 index 4b1e6a6..0000000 Binary files a/backups/backup_2025-12-22T12-06-42-448Z.db-wal and /dev/null differ diff --git a/backups/backup_2025-12-22T12-18-33-252Z.db-wal b/backups/backup_2025-12-22T12-18-33-252Z.db-wal deleted file mode 100644 index 702a2da..0000000 Binary files a/backups/backup_2025-12-22T12-18-33-252Z.db-wal and /dev/null differ diff --git a/backups/backup_2025-12-22T12-33-43-793Z.db b/backups/backup_2025-12-22T12-33-43-793Z.db deleted file mode 100644 index 0fdc965..0000000 Binary files a/backups/backup_2025-12-22T12-33-43-793Z.db and /dev/null differ diff --git a/backups/backup_2025-12-22T12-33-43-793Z.db-wal b/backups/backup_2025-12-22T12-33-43-793Z.db-wal deleted file mode 100644 index fb317e3..0000000 Binary files a/backups/backup_2025-12-22T12-33-43-793Z.db-wal and /dev/null differ diff --git a/backups/backup_2025-12-22T11-33-43-528Z.db b/backups/backup_2025-12-29T18-03-28-634Z.db similarity index 77% rename from backups/backup_2025-12-22T11-33-43-528Z.db rename to backups/backup_2025-12-29T18-03-28-634Z.db index 0fdc965..b8c4b1f 100644 Binary files a/backups/backup_2025-12-22T11-33-43-528Z.db and b/backups/backup_2025-12-29T18-03-28-634Z.db differ diff --git a/backups/backup_2025-12-29T18-03-28-634Z.db-wal b/backups/backup_2025-12-29T18-03-28-634Z.db-wal new file mode 100644 index 0000000..e69de29 diff --git a/backups/backup_2025-12-22T12-06-42-448Z.db b/backups/backup_2025-12-29T18-30-58-187Z.db similarity index 77% rename from backups/backup_2025-12-22T12-06-42-448Z.db rename to backups/backup_2025-12-29T18-30-58-187Z.db index 0fdc965..7dd48cc 100644 Binary files a/backups/backup_2025-12-22T12-06-42-448Z.db and b/backups/backup_2025-12-29T18-30-58-187Z.db differ diff --git a/backups/backup_2025-12-29T18-30-58-187Z.db-wal b/backups/backup_2025-12-29T18-30-58-187Z.db-wal new file mode 100644 index 0000000..e69de29 diff --git a/backups/backup_2025-12-22T11-44-05-900Z.db b/backups/backup_2025-12-29T18-36-12-724Z.db similarity index 77% rename from backups/backup_2025-12-22T11-44-05-900Z.db rename to backups/backup_2025-12-29T18-36-12-724Z.db index 0fdc965..08ea730 100644 Binary files a/backups/backup_2025-12-22T11-44-05-900Z.db and b/backups/backup_2025-12-29T18-36-12-724Z.db differ diff --git a/backups/backup_2025-12-29T18-36-12-724Z.db-wal b/backups/backup_2025-12-29T18-36-12-724Z.db-wal new file mode 100644 index 0000000..e69de29 diff --git a/backups/backup_2025-12-22T12-18-33-252Z.db b/backups/backup_2025-12-29T18-46-49-826Z.db similarity index 77% rename from backups/backup_2025-12-22T12-18-33-252Z.db rename to backups/backup_2025-12-29T18-46-49-826Z.db index 0fdc965..08ea730 100644 Binary files a/backups/backup_2025-12-22T12-18-33-252Z.db and b/backups/backup_2025-12-29T18-46-49-826Z.db differ diff --git a/backups/backup_2025-12-29T18-46-49-826Z.db-wal b/backups/backup_2025-12-29T18-46-49-826Z.db-wal new file mode 100644 index 0000000..e69de29 diff --git a/backups/backup_2025-12-29T19-01-37-753Z.db b/backups/backup_2025-12-29T19-01-37-753Z.db new file mode 100644 index 0000000..08ea730 Binary files /dev/null and b/backups/backup_2025-12-29T19-01-37-753Z.db differ diff --git a/backups/backup_2025-12-29T19-01-37-753Z.db-wal b/backups/backup_2025-12-29T19-01-37-753Z.db-wal new file mode 100644 index 0000000..52406ee Binary files /dev/null and b/backups/backup_2025-12-29T19-01-37-753Z.db-wal differ diff --git a/data/taskmate.db b/data/taskmate.db index 7bef75d..08ea730 100644 Binary files a/data/taskmate.db and b/data/taskmate.db differ diff --git a/data/taskmate.db-shm b/data/taskmate.db-shm index 3f7f07e..dfaf176 100644 Binary files a/data/taskmate.db-shm and b/data/taskmate.db-shm differ diff --git a/data/taskmate.db-wal b/data/taskmate.db-wal index 9ef4444..0ea1e5f 100644 Binary files a/data/taskmate.db-wal and b/data/taskmate.db-wal differ diff --git a/frontend/css/gitea.css b/frontend/css/gitea.css index 6fa1edb..73cfdb4 100644 --- a/frontend/css/gitea.css +++ b/frontend/css/gitea.css @@ -225,6 +225,12 @@ letter-spacing: 0.05em; } +.branch-select-group { + display: flex; + align-items: center; + gap: var(--spacing-2); +} + .branch-select { padding: var(--spacing-2) var(--spacing-3); border-radius: var(--radius-md); @@ -233,6 +239,7 @@ color: var(--text-primary); font-size: var(--text-sm); cursor: pointer; + flex: 1; } .branch-select:focus { @@ -240,6 +247,24 @@ border-color: var(--primary); } +.btn-small { + padding: var(--spacing-1) var(--spacing-2); + font-size: var(--text-xs); +} + +.btn-icon { + display: inline-flex; + align-items: center; + justify-content: center; + padding: var(--spacing-1); + min-width: 28px; + min-height: 28px; +} + +.btn-icon svg { + flex-shrink: 0; +} + .status-badge { display: inline-flex; align-items: center; @@ -259,11 +284,6 @@ color: var(--warning); } -.status-badge.ahead { - background: rgba(59, 130, 246, 0.1); - color: var(--info); -} - .status-badge.error { background: rgba(239, 68, 68, 0.1); color: var(--error); @@ -275,12 +295,6 @@ color: var(--text-primary); } -#git-ahead-behind { - font-size: var(--text-sm); - color: var(--text-primary); - font-family: monospace; -} - /* ============================================================================= OPERATIONS PANEL ============================================================================= */ @@ -511,6 +525,20 @@ color: var(--error); } +.form-hint.warning { + color: var(--warning); +} + +.form-static-value { + padding: var(--spacing-2) var(--spacing-3); + background: var(--bg-tertiary); + border: 1px solid var(--border-color); + border-radius: var(--radius-md); + font-family: var(--font-mono); + font-size: var(--text-sm); + color: var(--text-secondary); +} + .checkbox-label { display: flex; align-items: center; diff --git a/frontend/index.html b/frontend/index.html index 1a88e97..431c872 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -606,9 +606,14 @@