Compare commits
1 Commits
alpha-1.9
...
alpha-1.10
| Author | SHA1 | Date | |
|---|---|---|---|
| b955e4f464 |
15
.gitignore
vendored
15
.gitignore
vendored
@@ -69,5 +69,20 @@ PROJECT_SUMMARY.md
|
||||
QUICKSTART.md
|
||||
VS_CODE_SETUP.md
|
||||
|
||||
# Gemini / Antigravity
|
||||
.gemini/
|
||||
|
||||
# Windows artifacts
|
||||
nul
|
||||
|
||||
# Debug / temp files (generated during development & testing)
|
||||
out.txt
|
||||
containers.txt
|
||||
helper.txt
|
||||
logs.txt
|
||||
port.txt
|
||||
env.txt
|
||||
network.txt
|
||||
update_helper.txt
|
||||
state.txt
|
||||
hostpath.txt
|
||||
|
||||
@@ -334,6 +334,19 @@ async def get_version(
|
||||
return result
|
||||
|
||||
|
||||
@router.get("/branches")
|
||||
async def get_branches(
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""Return a list of available branches from the configured git remote."""
|
||||
config = get_system_config(db)
|
||||
if not config or not config.git_repo_url:
|
||||
return []
|
||||
branches = await update_service.get_remote_branches(config)
|
||||
return branches
|
||||
|
||||
|
||||
@router.post("/update")
|
||||
async def trigger_update(
|
||||
current_user: User = Depends(get_current_user),
|
||||
|
||||
@@ -5,6 +5,7 @@ import logging
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import httpx
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
@@ -130,6 +131,42 @@ async def check_for_updates(config: Any) -> dict:
|
||||
}
|
||||
|
||||
|
||||
async def get_remote_branches(config: Any) -> list[str]:
|
||||
"""Query the Gitea API for available branches on the configured repository.
|
||||
|
||||
Returns a list of branch names (e.g., ['main', 'unstable', 'development']).
|
||||
If the repository URL is not configured or an error occurs, returns an empty list.
|
||||
"""
|
||||
if not config.git_repo_url:
|
||||
return []
|
||||
|
||||
repo_url = config.git_repo_url.rstrip("/")
|
||||
parts = repo_url.split("/")
|
||||
if len(parts) < 5:
|
||||
return []
|
||||
|
||||
base_url = "/".join(parts[:-2])
|
||||
owner = parts[-2]
|
||||
repo = parts[-1]
|
||||
branches_api = f"{base_url}/api/v1/repos/{owner}/{repo}/branches?limit=100"
|
||||
|
||||
headers = {}
|
||||
if config.git_token:
|
||||
headers["Authorization"] = f"token {config.git_token}"
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=10) as client:
|
||||
resp = await client.get(branches_api, headers=headers)
|
||||
if resp.status_code == 200:
|
||||
data = resp.json()
|
||||
if isinstance(data, list):
|
||||
return [branch.get("name") for branch in data if "name" in branch]
|
||||
except Exception as exc:
|
||||
logger.error("Error fetching branches: %s", exc)
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def backup_database(db_path: str) -> str:
|
||||
"""Create a timestamped backup of the SQLite database.
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
NAMES STATUS IMAGE
|
||||
netbird-msp-appliance Up 3 minutes (healthy) netbirdmsp-appliance-netbird-msp-appliance
|
||||
msp-updater Exited (0) 3 minutes ago netbirdmsp-appliance-netbird-msp-appliance:latest
|
||||
netbird-kunde1-caddy Up 2 hours caddy:2-alpine
|
||||
netbird-kunde1-signal Up 2 hours netbirdio/signal:latest
|
||||
netbird-kunde1-dashboard Up 2 hours netbirdio/dashboard:latest
|
||||
netbird-kunde1-relay Up 2 hours netbirdio/relay:latest
|
||||
netbird-kunde1-management Up 2 hours netbirdio/management:latest
|
||||
docker-socket-proxy Up 2 hours tecnativa/docker-socket-proxy:latest
|
||||
@@ -1 +0,0 @@
|
||||
Error response from daemon: No such container: msp-updater
|
||||
9
logs.txt
9
logs.txt
@@ -1,9 +0,0 @@
|
||||
INFO: Started server process [1]
|
||||
INFO: Waiting for application startup.
|
||||
2026-02-22 14:53:59,694 [INFO] app.main: Starting NetBird MSP Appliance...
|
||||
2026-02-22 14:53:59,744 [INFO] app.main: Database initialized.
|
||||
INFO: Application startup complete.
|
||||
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
|
||||
INFO: 127.0.0.1:45370 - "GET /api/health HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57724 - "GET /api/health HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56212 - "GET /api/health HTTP/1.1" 200 OK
|
||||
@@ -363,48 +363,54 @@
|
||||
<!-- Sidebar -->
|
||||
<div class="col-md-3 mb-4 mb-md-0 border-end pe-3">
|
||||
<ul class="nav nav-pills flex-column" id="settings-tabs">
|
||||
<li class="nav-item"><a class="nav-link active" data-bs-toggle="pill"
|
||||
href="#settings-system"><i class="bi bi-pc-display me-2"></i><span
|
||||
data-i18n="settings.tabSystem">System</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link" data-bs-toggle="pill" href="#settings-npm"><i
|
||||
class="bi bi-router me-2"></i><span data-i18n="settings.tabNpm">NPM
|
||||
Proxy</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link" data-bs-toggle="pill" href="#settings-images"><i
|
||||
class="bi bi-box me-2"></i><span
|
||||
data-i18n="settings.tabImages">Images</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link" data-bs-toggle="pill" href="#settings-branding"><i
|
||||
class="bi bi-palette me-2"></i><span
|
||||
data-i18n="settings.tabBranding">Branding</span></a></li>
|
||||
|
||||
<hr class="my-3 border-secondary opacity-25">
|
||||
|
||||
<div class="text-uppercase text-muted fw-bold mb-2 ps-3"
|
||||
style="font-size: 0.75rem; letter-spacing: 0.05em;"><i
|
||||
class="bi bi-shield-check me-1"></i>Auth & Users</div>
|
||||
<li class="nav-item"><a class="nav-link" data-bs-toggle="pill" href="#settings-users"
|
||||
onclick="loadUsers()"><i class="bi bi-people me-2"></i><span
|
||||
data-i18n="settings.tabUsers">Users</span></a></li>
|
||||
class="bi bi-shield-check me-1"></i><span
|
||||
data-i18n="settings.groupUsers">Benutzerverwaltung</span></div>
|
||||
<li class="nav-item"><a class="nav-link" data-bs-toggle="pill" href="#settings-azure"><i
|
||||
class="bi bi-microsoft me-2"></i><span data-i18n="settings.tabAzure">Azure
|
||||
AD</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link" data-bs-toggle="pill" href="#settings-users"
|
||||
onclick="loadUsers()"><i class="bi bi-people me-2"></i><span
|
||||
data-i18n="settings.tabUsers">Benutzer</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link" data-bs-toggle="pill" href="#settings-ldap"><i
|
||||
class="bi bi-diagram-3 me-2"></i><span data-i18n="settings.tabLdap">LDAP /
|
||||
AD</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link" data-bs-toggle="pill" href="#settings-security"><i
|
||||
class="bi bi-shield-lock me-2"></i><span
|
||||
data-i18n="settings.tabSecurity">Sicherheit</span></a></li>
|
||||
|
||||
<hr class="my-3 border-secondary opacity-25">
|
||||
|
||||
<div class="text-uppercase text-muted fw-bold mb-2 ps-3"
|
||||
style="font-size: 0.75rem; letter-spacing: 0.05em;"><i
|
||||
class="bi bi-gear-wide-connected me-1"></i>System</div>
|
||||
class="bi bi-gear-wide-connected me-1"></i><span
|
||||
data-i18n="settings.groupSystem">Systemkonfiguration</span></div>
|
||||
<li class="nav-item"><a class="nav-link" data-bs-toggle="pill" href="#settings-branding"><i
|
||||
class="bi bi-palette me-2"></i><span
|
||||
data-i18n="settings.tabBranding">Branding</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link" data-bs-toggle="pill" href="#settings-images"><i
|
||||
class="bi bi-box me-2"></i><span data-i18n="settings.tabImages">NetBird Docker
|
||||
Images</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link active" data-bs-toggle="pill"
|
||||
href="#settings-system"><i class="bi bi-pc-display me-2"></i><span
|
||||
data-i18n="settings.tabSystem">NetBird MSP System</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link" data-bs-toggle="pill" href="#settings-update"
|
||||
onclick="loadVersionInfo()"><i class="bi bi-cloud-arrow-down me-2"></i><span
|
||||
data-i18n="settings.tabUpdate">NetBird MSP Updates</span></a></li>
|
||||
|
||||
<hr class="my-3 border-secondary opacity-25">
|
||||
|
||||
<div class="text-uppercase text-muted fw-bold mb-2 ps-3"
|
||||
style="font-size: 0.75rem; letter-spacing: 0.05em;"><i
|
||||
class="bi bi-link-45deg me-1"></i><span
|
||||
data-i18n="settings.groupExternal">Umsysteme</span></div>
|
||||
<li class="nav-item"><a class="nav-link" data-bs-toggle="pill" href="#settings-npm"><i
|
||||
class="bi bi-router me-2"></i><span data-i18n="settings.tabNpm">NPM
|
||||
Proxy</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link" data-bs-toggle="pill" href="#settings-dns"><i
|
||||
class="bi bi-hdd-network me-2"></i><span data-i18n="settings.tabDns">Windows
|
||||
DNS</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link" data-bs-toggle="pill" href="#settings-update"
|
||||
onclick="loadVersionInfo()"><i class="bi bi-cloud-arrow-down me-2"></i><span
|
||||
data-i18n="settings.tabUpdate">Updates</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link" data-bs-toggle="pill" href="#settings-security"><i
|
||||
class="bi bi-shield-lock me-2"></i><span
|
||||
data-i18n="settings.tabSecurity">Security</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -1004,8 +1010,15 @@
|
||||
<div class="col-md-4">
|
||||
<label class="form-label"
|
||||
data-i18n="settings.gitBranch">Branch</label>
|
||||
<input type="text" class="form-control" id="cfg-git-branch"
|
||||
placeholder="main">
|
||||
<div class="input-group">
|
||||
<select class="form-select" id="cfg-git-branch">
|
||||
<option value="main">main</option>
|
||||
</select>
|
||||
<button class="btn btn-outline-secondary" type="button"
|
||||
onclick="loadGitBranches()" title="Aktualisieren">
|
||||
<i class="bi bi-arrow-clockwise"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<label class="form-label" data-i18n="settings.gitToken">Access Token
|
||||
|
||||
@@ -872,6 +872,9 @@ async function loadSettings() {
|
||||
} catch (err) {
|
||||
showSettingsAlert('danger', t('errors.failedToLoadSettings', { error: err.message }));
|
||||
}
|
||||
|
||||
// Automatically fetch branches once the base config is populated
|
||||
await loadGitBranches();
|
||||
}
|
||||
|
||||
function updateLogoPreview(logoPath) {
|
||||
@@ -1183,6 +1186,42 @@ async function testLdapConnection() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadGitBranches() {
|
||||
const branchSelect = document.getElementById('cfg-git-branch');
|
||||
const currentVal = branchSelect.value;
|
||||
|
||||
// Disable mapping while loading
|
||||
branchSelect.disabled = true;
|
||||
branchSelect.innerHTML = `<option value="${currentVal}">${currentVal} (Loading...)</option>`;
|
||||
|
||||
try {
|
||||
const branches = await api('GET', '/settings/branches');
|
||||
branchSelect.innerHTML = '';
|
||||
|
||||
// Always ensure the currently saved branch is an option
|
||||
if (currentVal && !branches.includes(currentVal)) {
|
||||
branches.unshift(currentVal);
|
||||
}
|
||||
|
||||
if (branches.length === 0) {
|
||||
branchSelect.innerHTML = `<option value="main">main</option>`;
|
||||
} else {
|
||||
branches.forEach(b => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = b;
|
||||
opt.textContent = b;
|
||||
if (b === currentVal) opt.selected = true;
|
||||
branchSelect.appendChild(opt);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
showSettingsAlert('warning', `Failed to load branches: ${err.message}`);
|
||||
branchSelect.innerHTML = `<option value="${currentVal}">${currentVal}</option>`;
|
||||
} finally {
|
||||
branchSelect.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Update / Version Management
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -93,16 +93,19 @@
|
||||
},
|
||||
"settings": {
|
||||
"title": "Systemeinstellungen",
|
||||
"tabSystem": "Systemkonfiguration",
|
||||
"tabNpm": "NPM Integration",
|
||||
"tabImages": "Docker Images",
|
||||
"tabSystem": "NetBird MSP System",
|
||||
"tabNpm": "NPM Proxy",
|
||||
"tabImages": "NetBird Docker Images",
|
||||
"tabBranding": "Branding",
|
||||
"tabUsers": "Benutzer",
|
||||
"tabAzure": "Azure AD",
|
||||
"tabDns": "Windows DNS",
|
||||
"tabLdap": "LDAP / AD",
|
||||
"tabUpdate": "Updates",
|
||||
"tabUpdate": "NetBird MSP Updates",
|
||||
"tabSecurity": "Sicherheit",
|
||||
"groupUsers": "Benutzerverwaltung",
|
||||
"groupSystem": "Systemkonfiguration",
|
||||
"groupExternal": "Umsysteme",
|
||||
"baseDomain": "Basis-Domain",
|
||||
"baseDomainPlaceholder": "ihredomain.com",
|
||||
"baseDomainHint": "Kunden erhalten Subdomains: kunde.ihredomain.com",
|
||||
|
||||
@@ -114,16 +114,19 @@
|
||||
},
|
||||
"settings": {
|
||||
"title": "System Settings",
|
||||
"tabSystem": "System Configuration",
|
||||
"tabNpm": "NPM Integration",
|
||||
"tabImages": "Docker Images",
|
||||
"tabSystem": "NetBird MSP System",
|
||||
"tabNpm": "NPM Proxy",
|
||||
"tabImages": "NetBird Docker Images",
|
||||
"tabBranding": "Branding",
|
||||
"tabUsers": "Users",
|
||||
"tabAzure": "Azure AD",
|
||||
"tabDns": "Windows DNS",
|
||||
"tabLdap": "LDAP / AD",
|
||||
"tabUpdate": "Updates",
|
||||
"tabUpdate": "NetBird MSP Updates",
|
||||
"tabSecurity": "Security",
|
||||
"groupUsers": "User Management",
|
||||
"groupSystem": "System Configuration",
|
||||
"groupExternal": "External Systems",
|
||||
"baseDomain": "Base Domain",
|
||||
"baseDomainPlaceholder": "yourdomain.com",
|
||||
"baseDomainHint": "Customers get subdomains: customer.yourdomain.com",
|
||||
@@ -370,4 +373,4 @@
|
||||
"confirmDeleteUser": "Delete user '{username}'? This cannot be undone.",
|
||||
"confirmResetPassword": "Reset password for '{username}'? A new random password will be generated."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
Container netbird-msp-appliance Recreate
|
||||
Container netbird-msp-appliance Recreated
|
||||
Container netbird-msp-appliance Starting
|
||||
Container netbird-msp-appliance Started
|
||||
Reference in New Issue
Block a user