Update Gitea-Sektion:

Branch-Auswahl
Dieser Commit ist enthalten in:
Claude Project Manager
2025-12-29 19:02:44 +00:00
Ursprung 8da6ad83f0
Commit 627beb1353
30 geänderte Dateien mit 3953 neuen und 56 gelöschten Zeilen

Datei anzeigen

@ -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;

Datei anzeigen

@ -606,9 +606,14 @@
<div class="status-grid">
<div class="status-item">
<span class="status-label">Branch</span>
<select id="branch-select" class="branch-select">
<!-- Branches dynamisch -->
</select>
<div class="branch-select-group">
<select id="branch-select" class="branch-select">
<!-- Branches dynamisch -->
</select>
<button id="btn-rename-branch" class="btn btn-small btn-icon" title="Branch umbenennen">
<svg viewBox="0 0 24 24" width="16" height="16"><path d="M17 3a2.85 2.85 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z" stroke="currentColor" stroke-width="2" fill="none"/></svg>
</button>
</div>
</div>
<div class="status-item">
<span class="status-label">Status</span>
@ -618,10 +623,6 @@
<span class="status-label">Änderungen</span>
<span id="git-changes-count" class="changes-count">0</span>
</div>
<div class="status-item">
<span class="status-label">Ahead / Behind</span>
<span id="git-ahead-behind">- / -</span>
</div>
</div>
</div>
@ -1163,6 +1164,70 @@
</div>
</div>
<!-- Git Branch Rename Modal -->
<div id="git-rename-branch-modal" class="modal modal-small hidden">
<div class="modal-header">
<h2>Branch umbenennen</h2>
<button class="modal-close" data-close-modal>&times;</button>
</div>
<div class="modal-body">
<form id="git-rename-branch-form">
<div class="form-group">
<label>Aktueller Branch</label>
<div id="rename-current-branch" class="form-static-value">master</div>
</div>
<div class="form-group">
<label for="rename-new-branch">Neuer Name *</label>
<input type="text" id="rename-new-branch" required
placeholder="z.B. main" pattern="[a-zA-Z0-9_\-]+"
title="Nur Buchstaben, Zahlen, Unterstriche und Bindestriche">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-close-modal>Abbrechen</button>
<button type="submit" form="git-rename-branch-form" class="btn btn-primary">Umbenennen</button>
</div>
</div>
<!-- Git Push Modal -->
<div id="git-push-modal" class="modal modal-small hidden">
<div class="modal-header">
<h2>Push zu Gitea</h2>
<button class="modal-close" data-close-modal>&times;</button>
</div>
<div class="modal-body">
<form id="git-push-form">
<div class="form-group">
<label>Lokaler Branch</label>
<div id="push-local-branch" class="form-static-value">wird ermittelt...</div>
<span class="form-hint">Der aktuelle lokale Branch wird automatisch erkannt</span>
</div>
<div class="form-group">
<label for="push-target-branch">Ziel-Branch auf Remote</label>
<select id="push-target-branch">
<option value="">Gleicher Name wie lokal</option>
<option value="main">main</option>
<option value="master">master</option>
<option value="develop">develop</option>
</select>
<span class="form-hint">Wählen Sie den Branch-Namen auf Gitea</span>
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="push-force">
Force Push (Remote überschreiben)
</label>
<span class="form-hint warning">Achtung: Überschreibt alle Änderungen auf dem Remote-Branch!</span>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-close-modal>Abbrechen</button>
<button type="submit" form="git-push-form" class="btn btn-primary">Push starten</button>
</div>
</div>
<!-- Create Repository Modal -->
<div id="create-repo-modal" class="modal modal-small hidden">
<div class="modal-header">

Datei anzeigen

@ -820,8 +820,12 @@ class ApiClient {
return this.post(`/git/set-remote/${projectId}`, { repoUrl });
}
async gitInitPush(projectId, branch = 'main') {
return this.post(`/git/init-push/${projectId}`, { branch });
async gitInitPush(projectId, targetBranch = null, force = false) {
return this.post(`/git/init-push/${projectId}`, { targetBranch, force });
}
async gitRenameBranch(projectId, oldName, newName) {
return this.post(`/git/rename-branch/${projectId}`, { oldName, newName });
}
}

Datei anzeigen

@ -72,6 +72,13 @@ class GiteaManager {
// Commit Modal
$('#git-commit-form')?.addEventListener('submit', (e) => this.handleCommit(e));
// Push Modal
$('#git-push-form')?.addEventListener('submit', (e) => this.executePush(e));
// Branch umbenennen
$('#btn-rename-branch')?.addEventListener('click', () => this.openRenameBranchModal());
$('#git-rename-branch-form')?.addEventListener('submit', (e) => this.executeRenameBranch(e));
}
subscribeToStore() {
@ -406,27 +413,76 @@ class GiteaManager {
}
}
async handlePush() {
handlePush() {
// Öffne das Push-Modal zur Branch-Auswahl
this.openPushModal();
}
openPushModal() {
const modal = $('#git-push-modal');
if (!modal) return;
// Aktuellen lokalen Branch anzeigen
const currentBranch = $('#branch-select')?.value || this.gitStatus?.branch || 'unbekannt';
$('#push-local-branch').textContent = currentBranch;
// Ziel-Branch zurücksetzen (Standard: gleicher Name wie lokal)
$('#push-target-branch').value = '';
modal.classList.remove('hidden');
modal.classList.add('visible');
$('#modal-overlay')?.classList.remove('hidden');
store.openModal('git-push-modal');
}
async executePush(e) {
e.preventDefault();
const projectId = store.get('currentProjectId');
if (!projectId) return;
// Modal schließen
const modal = $('#git-push-modal');
modal?.classList.add('hidden');
modal?.classList.remove('visible');
$('#modal-overlay')?.classList.add('hidden');
store.closeModal();
this.setOperationLoading('push', true);
try {
const branch = $('#branch-select')?.value || 'main';
let result = await api.gitPush(projectId, branch);
const targetBranch = $('#push-target-branch')?.value || null;
const forcePush = $('#push-force')?.checked || false;
const localBranch = $('#branch-select')?.value || this.gitStatus?.branch || 'master';
// Falls Push wegen fehlendem Upstream/Remote fehlschlägt, versuche init-push
if (!result.success && result.error &&
(result.error.includes('No configured push destination') ||
result.error.includes('no upstream') ||
result.error.includes('Kein Remote'))) {
this.showToast('Kein Upstream konfiguriert, führe initialen Push durch...', 'info');
result = await api.gitInitPush(projectId, branch);
let result;
// Wenn ein anderer Target-Branch ausgewählt wurde oder Force-Push, verwende init-push
if ((targetBranch && targetBranch !== localBranch) || forcePush) {
const forceText = forcePush ? ' (Force)' : '';
const branchText = targetBranch && targetBranch !== localBranch
? `Push von "${localBranch}" nach "${targetBranch}"${forceText}...`
: `Push nach "${localBranch}"${forceText}...`;
this.showToast(branchText, 'info');
result = await api.gitInitPush(projectId, targetBranch, forcePush);
} else {
// Normaler Push (gleicher Branch-Name)
result = await api.gitPush(projectId, localBranch);
// Falls Push wegen fehlendem Upstream/Remote fehlschlägt, versuche init-push
if (!result.success && result.error &&
(result.error.includes('No configured push destination') ||
result.error.includes('no upstream') ||
result.error.includes('Kein Remote'))) {
this.showToast('Kein Upstream konfiguriert, führe initialen Push durch...', 'info');
result = await api.gitInitPush(projectId, targetBranch, false);
}
}
if (result.success) {
this.showToast('Push erfolgreich', 'success');
const pushedBranch = result.branch || targetBranch || localBranch;
this.showToast(`Push erfolgreich nach Branch "${pushedBranch}"`, 'success');
await this.loadGitData();
} else {
this.showToast(result.error || 'Push fehlgeschlagen', 'error');
@ -438,6 +494,64 @@ class GiteaManager {
}
}
openRenameBranchModal() {
const modal = $('#git-rename-branch-modal');
if (!modal) return;
const currentBranch = $('#branch-select')?.value || this.gitStatus?.branch || 'master';
$('#rename-current-branch').textContent = currentBranch;
$('#rename-new-branch').value = '';
modal.classList.remove('hidden');
modal.classList.add('visible');
$('#modal-overlay')?.classList.remove('hidden');
store.openModal('git-rename-branch-modal');
// Focus auf das Eingabefeld
setTimeout(() => $('#rename-new-branch')?.focus(), 100);
}
async executeRenameBranch(e) {
e.preventDefault();
const projectId = store.get('currentProjectId');
if (!projectId) return;
const oldName = $('#rename-current-branch')?.textContent;
const newName = $('#rename-new-branch')?.value.trim();
if (!newName) {
this.showToast('Bitte geben Sie einen neuen Branch-Namen ein', 'error');
return;
}
if (oldName === newName) {
this.showToast('Der neue Name ist identisch mit dem aktuellen', 'error');
return;
}
// Modal schließen
const modal = $('#git-rename-branch-modal');
modal?.classList.add('hidden');
modal?.classList.remove('visible');
$('#modal-overlay')?.classList.add('hidden');
store.closeModal();
try {
const result = await api.gitRenameBranch(projectId, oldName, newName);
if (result.success) {
this.showToast(`Branch umbenannt: "${oldName}" → "${newName}"`, 'success');
await this.loadGitData();
} else {
this.showToast(result.error || 'Umbenennen fehlgeschlagen', 'error');
}
} catch (error) {
this.showToast(error.message || 'Umbenennen fehlgeschlagen', 'error');
}
}
openCommitModal() {
const modal = $('#git-commit-modal');
if (!modal) return;
@ -610,13 +724,11 @@ class GiteaManager {
renderStatus() {
const statusBadge = $('#git-status-indicator');
const changesCount = $('#git-changes-count');
const aheadBehind = $('#git-ahead-behind');
if (!this.gitStatus) {
statusBadge.textContent = 'Fehler';
statusBadge.className = 'status-badge error';
changesCount.textContent = '-';
aheadBehind.textContent = '- / -';
return;
}
@ -630,9 +742,6 @@ class GiteaManager {
} else if (this.gitStatus.hasChanges) {
statusBadge.textContent = 'Geändert';
statusBadge.className = 'status-badge dirty';
} else if (this.gitStatus.ahead > 0) {
statusBadge.textContent = 'Voraus';
statusBadge.className = 'status-badge ahead';
} else {
statusBadge.textContent = 'OK';
statusBadge.className = 'status-badge clean';
@ -641,11 +750,6 @@ class GiteaManager {
// Änderungen
const changes = this.gitStatus.changes || [];
changesCount.textContent = changes.length;
// Ahead/Behind
const ahead = this.gitStatus.ahead || 0;
const behind = this.gitStatus.behind || 0;
aheadBehind.textContent = `${ahead} / ${behind}`;
}
renderBranches() {

Datei anzeigen

@ -4,7 +4,7 @@
* Offline support and caching
*/
const CACHE_VERSION = '118';
const CACHE_VERSION = '123';
const CACHE_NAME = 'taskmate-v' + CACHE_VERSION;
const STATIC_CACHE_NAME = 'taskmate-static-v' + CACHE_VERSION;
const DYNAMIC_CACHE_NAME = 'taskmate-dynamic-v' + CACHE_VERSION;