diff --git a/static/index.html b/static/index.html index d733a09..40675d7 100644 --- a/static/index.html +++ b/static/index.html @@ -311,6 +311,9 @@ + + + @@ -562,6 +565,11 @@
+
+ + +
If set, only Azure AD members of this group can log in.
+
@@ -571,6 +579,171 @@
+ +
+
+
+
Windows DNS Integration
+
+
+
+
+ + +
+
Automatically create/delete DNS A-records when deploying customers.
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + +
+
+
+
+ + +
IP address that customer A-records will point to (usually your NPM server IP).
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
LDAP / Active Directory Authentication
+
+
+
+
+ + +
+
Allow Active Directory users to log in. Local admin accounts always work as fallback.
+
+
+ + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ +
+ + +
+
+
+
+ + +
+
+ + +
Use {username} as placeholder for the login name.
+
+
+ + +
If set, only members of this group can log in via LDAP.
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+ Version & Updates + +
+
+
Loading...
+
+
+
+
+
Git Repository Settings
+
+
+
+ + +
Used for version checks and one-click updates via Gitea API.
+
+
+ + +
+
+ +
+ + +
+
+
+
+
+ +
+
+
+
+
+
diff --git a/static/js/app.js b/static/js/app.js index d671a9e..2510f94 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -844,6 +844,31 @@ async function loadSettings() { document.getElementById('cfg-azure-tenant').value = cfg.azure_tenant_id || ''; document.getElementById('cfg-azure-client-id').value = cfg.azure_client_id || ''; document.getElementById('azure-secret-status').textContent = cfg.azure_client_secret_set ? t('settings.secretSet') : t('settings.noSecret'); + document.getElementById('cfg-azure-group-id').value = cfg.azure_allowed_group_id || ''; + + // DNS tab + document.getElementById('cfg-dns-enabled').checked = cfg.dns_enabled || false; + document.getElementById('cfg-dns-server').value = cfg.dns_server || ''; + document.getElementById('cfg-dns-zone').value = cfg.dns_zone || ''; + document.getElementById('cfg-dns-username').value = cfg.dns_username || ''; + document.getElementById('cfg-dns-record-ip').value = cfg.dns_record_ip || ''; + document.getElementById('dns-password-status').textContent = cfg.dns_password_set ? t('settings.passwordSet') : t('settings.noPasswordSet'); + + // LDAP tab + document.getElementById('cfg-ldap-enabled').checked = cfg.ldap_enabled || false; + document.getElementById('cfg-ldap-server').value = cfg.ldap_server || ''; + document.getElementById('cfg-ldap-port').value = cfg.ldap_port || 389; + document.getElementById('cfg-ldap-use-ssl').checked = cfg.ldap_use_ssl || false; + document.getElementById('cfg-ldap-bind-dn').value = cfg.ldap_bind_dn || ''; + document.getElementById('cfg-ldap-base-dn').value = cfg.ldap_base_dn || ''; + document.getElementById('cfg-ldap-user-filter').value = cfg.ldap_user_filter || '(sAMAccountName={username})'; + document.getElementById('cfg-ldap-group-dn').value = cfg.ldap_group_dn || ''; + document.getElementById('ldap-password-status').textContent = cfg.ldap_bind_password_set ? t('settings.passwordSet') : t('settings.noPasswordSet'); + + // Git/Update tab + document.getElementById('cfg-git-repo-url').value = cfg.git_repo_url || ''; + document.getElementById('cfg-git-branch').value = cfg.git_branch || 'main'; + document.getElementById('git-token-status').textContent = cfg.git_token_set ? t('settings.tokenSet') : t('settings.noToken'); } catch (err) { showSettingsAlert('danger', t('errors.failedToLoadSettings', { error: err.message })); } @@ -1069,6 +1094,182 @@ async function deleteLogo() { } } +// --------------------------------------------------------------------------- +// DNS Settings +// --------------------------------------------------------------------------- +document.getElementById('settings-dns-form').addEventListener('submit', async (e) => { + e.preventDefault(); + const payload = { + dns_enabled: document.getElementById('cfg-dns-enabled').checked, + dns_server: document.getElementById('cfg-dns-server').value, + dns_zone: document.getElementById('cfg-dns-zone').value, + dns_username: document.getElementById('cfg-dns-username').value, + dns_record_ip: document.getElementById('cfg-dns-record-ip').value, + }; + const pw = document.getElementById('cfg-dns-password').value; + if (pw) payload.dns_password = pw; + try { + await api('PUT', '/settings/system', payload); + showSettingsAlert('success', t('messages.dnsSettingsSaved')); + document.getElementById('cfg-dns-password').value = ''; + loadSettings(); + } catch (err) { + showSettingsAlert('danger', t('errors.failed', { error: err.message })); + } +}); + +async function testDnsConnection() { + const spinner = document.getElementById('dns-test-spinner'); + const resultEl = document.getElementById('dns-test-result'); + spinner.classList.remove('d-none'); + resultEl.classList.add('d-none'); + try { + const data = await api('GET', '/settings/test-dns'); + resultEl.className = `mt-3 alert alert-${data.ok ? 'success' : 'danger'}`; + resultEl.textContent = data.message; + resultEl.classList.remove('d-none'); + } catch (err) { + resultEl.className = 'mt-3 alert alert-danger'; + resultEl.textContent = err.message; + resultEl.classList.remove('d-none'); + } finally { + spinner.classList.add('d-none'); + } +} + +// --------------------------------------------------------------------------- +// LDAP Settings +// --------------------------------------------------------------------------- +document.getElementById('settings-ldap-form').addEventListener('submit', async (e) => { + e.preventDefault(); + const payload = { + ldap_enabled: document.getElementById('cfg-ldap-enabled').checked, + ldap_server: document.getElementById('cfg-ldap-server').value, + ldap_port: parseInt(document.getElementById('cfg-ldap-port').value) || 389, + ldap_use_ssl: document.getElementById('cfg-ldap-use-ssl').checked, + ldap_bind_dn: document.getElementById('cfg-ldap-bind-dn').value, + ldap_base_dn: document.getElementById('cfg-ldap-base-dn').value, + ldap_user_filter: document.getElementById('cfg-ldap-user-filter').value, + ldap_group_dn: document.getElementById('cfg-ldap-group-dn').value, + }; + const pw = document.getElementById('cfg-ldap-bind-password').value; + if (pw) payload.ldap_bind_password = pw; + try { + await api('PUT', '/settings/system', payload); + showSettingsAlert('success', t('messages.ldapSettingsSaved')); + document.getElementById('cfg-ldap-bind-password').value = ''; + loadSettings(); + } catch (err) { + showSettingsAlert('danger', t('errors.failed', { error: err.message })); + } +}); + +async function testLdapConnection() { + const spinner = document.getElementById('ldap-test-spinner'); + const resultEl = document.getElementById('ldap-test-result'); + spinner.classList.remove('d-none'); + resultEl.classList.add('d-none'); + try { + const data = await api('GET', '/settings/test-ldap'); + resultEl.className = `mt-3 alert alert-${data.ok ? 'success' : 'danger'}`; + resultEl.textContent = data.message; + resultEl.classList.remove('d-none'); + } catch (err) { + resultEl.className = 'mt-3 alert alert-danger'; + resultEl.textContent = err.message; + resultEl.classList.remove('d-none'); + } finally { + spinner.classList.add('d-none'); + } +} + +// --------------------------------------------------------------------------- +// Update / Version Management +// --------------------------------------------------------------------------- +document.getElementById('settings-git-form').addEventListener('submit', async (e) => { + e.preventDefault(); + const payload = { + git_repo_url: document.getElementById('cfg-git-repo-url').value, + git_branch: document.getElementById('cfg-git-branch').value || 'main', + }; + const token = document.getElementById('cfg-git-token').value; + if (token) payload.git_token = token; + try { + await api('PUT', '/settings/system', payload); + showSettingsAlert('success', t('messages.gitSettingsSaved')); + document.getElementById('cfg-git-token').value = ''; + loadSettings(); + } catch (err) { + showSettingsAlert('danger', t('errors.failed', { error: err.message })); + } +}); + +async function loadVersionInfo() { + const el = document.getElementById('version-info-content'); + if (!el) return; + el.innerHTML = `
${t('common.loading')}
`; + try { + const data = await api('GET', '/settings/version'); + const current = data.current || {}; + const latest = data.latest; + const needsUpdate = data.needs_update; + + let html = `
+
+
+
${t('settings.currentVersion')}
+
${esc(current.commit || 'unknown')}
+
${t('settings.branch')}: ${esc(current.branch || 'unknown')}
+
${esc(current.date || '')}
+
+
`; + + if (latest) { + const badge = needsUpdate + ? `${t('settings.updateAvailable')}` + : `${t('settings.upToDate')}`; + html += `
+
+
${t('settings.latestVersion')} ${badge}
+
${esc(latest.commit || 'unknown')}
+
${t('settings.branch')}: ${esc(latest.branch || 'unknown')}
+
${esc(latest.message || '')}
+
${esc(latest.date || '')}
+
+
`; + } else if (data.error) { + html += `
${esc(data.error)}
`; + } + html += '
'; + + if (needsUpdate) { + html += `
+ +
${t('settings.updateWarning')}
+
`; + } + el.innerHTML = html; + } catch (err) { + el.innerHTML = `
${esc(err.message)}
`; + } +} + +async function triggerUpdate() { + if (!confirm(t('settings.confirmUpdate'))) return; + const spinner = document.getElementById('update-spinner'); + if (spinner) spinner.classList.remove('d-none'); + try { + const data = await api('POST', '/settings/update'); + showSettingsAlert('success', data.message || t('messages.updateStarted')); + } catch (err) { + showSettingsAlert('danger', t('errors.failed', { error: err.message })); + if (spinner) spinner.classList.add('d-none'); + } +} + // --------------------------------------------------------------------------- // User Management // --------------------------------------------------------------------------- @@ -1181,6 +1382,7 @@ document.getElementById('settings-azure-form').addEventListener('submit', async azure_enabled: document.getElementById('cfg-azure-enabled').checked, azure_tenant_id: document.getElementById('cfg-azure-tenant').value || null, azure_client_id: document.getElementById('cfg-azure-client-id').value || null, + azure_allowed_group_id: document.getElementById('cfg-azure-group-id').value || null, }; const secret = document.getElementById('cfg-azure-client-secret').value; if (secret) payload.azure_client_secret = secret; diff --git a/static/lang/de.json b/static/lang/de.json index 034a881..383a0fc 100644 --- a/static/lang/de.json +++ b/static/lang/de.json @@ -90,5 +90,283 @@ "thImage": "Image", "lastCheck": "Letzte Prüfung: {time}", "openDashboard": "Dashboard öffnen" + }, + "settings": { + "title": "Systemeinstellungen", + "tabSystem": "Systemkonfiguration", + "tabNpm": "NPM Integration", + "tabImages": "Docker Images", + "tabBranding": "Branding", + "tabUsers": "Benutzer", + "tabAzure": "Azure AD", + "tabDns": "Windows DNS", + "tabLdap": "LDAP / AD", + "tabUpdate": "Updates", + "tabSecurity": "Sicherheit", + "baseDomain": "Basis-Domain", + "baseDomainPlaceholder": "ihredomain.com", + "baseDomainHint": "Kunden erhalten Subdomains: kunde.ihredomain.com", + "adminEmail": "Admin E-Mail", + "adminEmailPlaceholder": "admin@ihredomain.com", + "dataDir": "Datenverzeichnis", + "dataDirPlaceholder": "/opt/netbird-instances", + "dockerNetwork": "Docker-Netzwerk", + "dockerNetworkPlaceholder": "npm-network", + "relayBasePort": "Relay-Basisport", + "relayBasePortHint": "Erster UDP-Port für Relay. Bereich: Basis bis Basis+99", + "dashboardBasePort": "Dashboard-Basisport", + "dashboardBasePortHint": "Basisport für Kunden-Dashboards. Kunde N erhält Basis+N", + "saveSystemSettings": "Systemeinstellungen speichern", + "npmDescription": "NPM verwendet JWT-Authentifizierung. Geben Sie Ihre NPM-Zugangsdaten ein. Das System meldet sich automatisch an.", + "npmApiUrl": "NPM API URL", + "npmApiUrlPlaceholder": "http://nginx-proxy-manager:81/api", + "npmApiUrlHint": "http:// oder https:// - muss /api am Ende enthalten", + "npmLoginEmail": "NPM Login E-Mail", + "npmLoginEmailPlaceholder": "Leer lassen zum Beibehalten", + "npmLoginPassword": "NPM Login Passwort", + "npmLoginPasswordPlaceholder": "Leer lassen zum Beibehalten", + "credentialsSet": "Zugangsdaten gesetzt (leer lassen zum Beibehalten)", + "noCredentials": "Keine NPM-Zugangsdaten konfiguriert", + "saveNpmSettings": "NPM-Einstellungen speichern", + "testConnection": "Verbindung testen", + "sslModeTitle": "SSL-Zertifikat Modus", + "sslMode": "SSL-Modus", + "sslModeLetsencrypt": "Let's Encrypt (pro Kunde)", + "sslModeWildcard": "Wildcard-Zertifikat", + "sslModeHint": "Wählen Sie ob jeder Kunde ein eigenes Let's Encrypt Zertifikat oder ein geteiltes Wildcard-Zertifikat erhält.", + "wildcardCertificate": "Wildcard-Zertifikat", + "selectCertificate": "-- Zertifikat auswählen --", + "wildcardCertHint": "Wählen Sie das Wildcard-Zertifikat (z.B. *.example.com) das in NPM hochgeladen ist.", + "noWildcardCerts": "Keine Wildcard-Zertifikate in NPM gefunden.", + "certsLoaded": "{count} Wildcard-Zertifikat(e) gefunden.", + "expiresOn": "Läuft ab", + "managementImage": "Management Image", + "managementImagePlaceholder": "netbirdio/management:latest", + "signalImage": "Signal Image", + "signalImagePlaceholder": "netbirdio/signal:latest", + "relayImage": "Relay Image", + "relayImagePlaceholder": "netbirdio/relay:latest", + "dashboardImage": "Dashboard Image", + "dashboardImagePlaceholder": "netbirdio/dashboard:latest", + "saveImageSettings": "Image-Einstellungen speichern", + "brandingTitle": "Branding-Einstellungen", + "companyName": "Firmen- / Anwendungsname", + "companyNamePlaceholder": "NetBird MSP Appliance", + "companyNameHint": "Wird auf der Anmeldeseite und in der Navigationsleiste angezeigt", + "logoPreview": "Logo-Vorschau", + "defaultIcon": "Standardsymbol (kein Logo hochgeladen)", + "uploadLogo": "Logo hochladen (PNG, JPG, SVG, max. 500 KB)", + "uploadBtn": "Hochladen", + "removeLogo": "Logo entfernen", + "brandingSubtitle": "Untertitel", + "brandingSubtitlePlaceholder": "Multi-Tenant Management Plattform", + "brandingSubtitleHint": "Wird unter dem Titel auf der Anmeldeseite angezeigt", + "defaultLanguage": "Standardsprache", + "defaultLanguageHint": "Standardsprache für Benutzer ohne Präferenz", + "systemDefault": "Systemstandard", + "saveBranding": "Branding speichern", + "userManagement": "Benutzerverwaltung", + "newUser": "Neuer Benutzer", + "thId": "ID", + "thUsername": "Benutzername", + "thEmail": "E-Mail", + "thRole": "Rolle", + "thAuth": "Auth", + "thLanguage": "Sprache", + "thStatus": "Status", + "thActions": "Aktionen", + "azureTitle": "Azure AD / Entra ID Integration", + "enableAzureSso": "Azure AD SSO aktivieren", + "tenantId": "Tenant ID", + "clientId": "Client ID (Anwendungs-ID)", + "clientSecret": "Client Secret", + "clientSecretPlaceholder": "Leer lassen zum Beibehalten", + "secretSet": "Secret gesetzt (leer lassen zum Beibehalten)", + "noSecret": "Kein Client-Secret konfiguriert", + "saveAzureSettings": "Azure AD-Einstellungen speichern", + "azureGroupId": "Erlaubte Gruppen-Objekt-ID (optional)", + "azureGroupIdHint": "Falls gesetzt, können sich nur Azure AD-Mitglieder dieser Gruppe anmelden.", + "dnsTitle": "Windows DNS Integration", + "enableDns": "Windows DNS Integration aktivieren", + "dnsDescription": "Automatisch DNS A-Records erstellen/löschen beim Bereitstellen von Kunden.", + "dnsServer": "DNS-Serveradresse", + "dnsZone": "DNS-Zone", + "dnsUsername": "Benutzername (NTLM)", + "dnsPassword": "Passwort", + "dnsRecordIp": "A-Record Ziel-IP", + "dnsRecordIpHint": "IP-Adresse, auf die Kunden-A-Records zeigen (normalerweise die NPM-Server-IP).", + "saveDnsSettings": "DNS-Einstellungen speichern", + "ldapTitle": "LDAP / Active Directory Authentifizierung", + "enableLdap": "LDAP / AD Authentifizierung aktivieren", + "ldapDescription": "Active Directory Benutzern die Anmeldung erlauben. Lokale Admin-Konten funktionieren immer als Fallback.", + "ldapServer": "LDAP-Server", + "ldapPort": "Port", + "ldapUseSsl": "SSL/TLS verwenden (LDAPS)", + "ldapBindDn": "Bind DN (Dienstkonto)", + "ldapBindPassword": "Bind-Passwort", + "ldapBaseDn": "Basis-DN", + "ldapUserFilter": "Benutzerfilter", + "ldapUserFilterHint": "Verwenden Sie {username} als Platzhalter für den Anmeldenamen.", + "ldapGroupDn": "Gruppen-DN (optional, zur Einschränkung)", + "ldapGroupDnHint": "Falls gesetzt, können sich nur Mitglieder dieser Gruppe per LDAP anmelden.", + "saveLdapSettings": "LDAP-Einstellungen speichern", + "versionTitle": "Version & Updates", + "currentVersion": "Installierte Version", + "latestVersion": "Neueste verfügbare Version", + "branch": "Branch", + "updateAvailable": "Update verfügbar", + "upToDate": "Aktuell", + "triggerUpdate": "Update starten", + "updateWarning": "Die App ist während des Rebuilds ca. 60 Sekunden nicht verfügbar.", + "confirmUpdate": "Update jetzt starten? Die Datenbank wird zuerst gesichert. Die App startet neu (~60 Sekunden Ausfallzeit).", + "gitTitle": "Git-Repository Einstellungen", + "gitRepoUrl": "Repository URL", + "gitRepoUrlHint": "Wird für Versionsprüfungen und One-Click-Updates via Gitea API verwendet.", + "gitBranch": "Branch", + "gitToken": "Zugriffstoken (optional)", + "saveGitSettings": "Git-Einstellungen speichern", + "leaveEmptyToKeep": "Leer lassen zum Beibehalten", + "passwordSet": "Passwort gesetzt (leer lassen zum Beibehalten)", + "noPasswordSet": "Kein Passwort konfiguriert", + "tokenSet": "Token gesetzt (leer lassen zum Beibehalten)", + "noToken": "Kein Zugriffstoken konfiguriert", + "securityTitle": "Admin-Passwort ändern", + "currentPassword": "Aktuelles Passwort", + "newPassword": "Neues Passwort (min. 12 Zeichen)", + "confirmPassword": "Neues Passwort bestätigen", + "changePassword": "Passwort ändern" + }, + "mfa": { + "title": "Zwei-Faktor-Authentifizierung (MFA)", + "enableMfa": "MFA für alle lokalen Benutzer aktivieren", + "mfaDescription": "Bei Aktivierung müssen lokale Benutzer sich nach der Passworteingabe mit einer TOTP-Authentifikator-App verifizieren. Azure AD-Benutzer sind nicht betroffen.", + "saveMfaSettings": "MFA-Einstellungen speichern", + "yourTotpStatus": "Ihr TOTP-Status", + "totpActive": "Aktiv", + "totpNotSetUp": "Nicht eingerichtet", + "disableMyTotp": "Mein TOTP deaktivieren", + "enterCode": "Geben Sie Ihren 6-stelligen Authentifikator-Code ein", + "verify": "Bestätigen", + "backToLogin": "Zurück zur Anmeldung", + "scanQrCode": "Scannen Sie diesen QR-Code mit Ihrer Authentifikator-App", + "orEnterManually": "Oder geben Sie diesen Schlüssel manuell ein:", + "verifyAndActivate": "Bestätigen & Aktivieren", + "resetMfa": "MFA zurücksetzen", + "confirmResetMfa": "MFA für '{username}' zurücksetzen? Sie müssen bei der nächsten Anmeldung ihren Authentifikator neu einrichten.", + "mfaResetSuccess": "MFA für '{username}' zurückgesetzt.", + "mfaDisabled": "Ihr TOTP wurde deaktiviert.", + "mfaSaved": "MFA-Einstellungen gespeichert.", + "invalidCode": "Ungültiger Code. Bitte versuchen Sie es erneut.", + "codeExpired": "Verifizierung abgelaufen. Bitte melden Sie sich erneut an." + }, + "common": { + "loading": "Laden...", + "back": "Zurück", + "save": "Speichern", + "cancel": "Abbrechen", + "delete": "Löschen", + "edit": "Bearbeiten", + "view": "Ansehen", + "start": "Starten", + "stop": "Stoppen", + "restart": "Neustarten", + "disable": "Deaktivieren", + "enable": "Aktivieren", + "resetPassword": "Passwort zurücksetzen", + "open": "Öffnen", + "active": "Aktiv", + "disabled": "Deaktiviert" + }, + "errors": { + "networkError": "Netzwerkfehler — Server nicht erreichbar.", + "sessionExpired": "Sitzung abgelaufen.", + "requestFailed": "Anfrage fehlgeschlagen.", + "serverError": "Serverfehler (HTTP {status}).", + "unknownError": "Ein unbekannter Fehler ist aufgetreten.", + "uploadFailed": "Upload fehlgeschlagen.", + "deleteFailed": "Löschen fehlgeschlagen: {error}", + "failedToLoadSettings": "Einstellungen konnten nicht geladen werden: {error}", + "failed": "Fehlgeschlagen: {error}", + "logoUploadFailed": "Logo-Upload fehlgeschlagen: {error}", + "failedToRemoveLogo": "Logo konnte nicht entfernt werden: {error}", + "updateFailed": "Aktualisierung fehlgeschlagen: {error}", + "passwordResetFailed": "Passwort zurücksetzen fehlgeschlagen: {error}", + "selectFileFirst": "Bitte wählen Sie zuerst eine Datei aus.", + "passwordsDoNotMatch": "Passwörter stimmen nicht überein.", + "failedToLoadCredentials": "Zugangsdaten konnten nicht geladen werden: {error}", + "azureNotConfigured": "Azure AD ist nicht konfiguriert.", + "azureLoginFailed": "Azure AD Anmeldung fehlgeschlagen: {error}", + "actionFailed": "{action} fehlgeschlagen: {error}" + }, + "messages": { + "systemSettingsSaved": "Systemeinstellungen gespeichert.", + "npmSettingsSaved": "NPM-Einstellungen gespeichert.", + "imageSettingsSaved": "Image-Einstellungen gespeichert.", + "brandingNameSaved": "Branding-Einstellungen gespeichert.", + "logoUploaded": "Logo erfolgreich hochgeladen.", + "logoRemoved": "Logo entfernt.", + "azureSettingsSaved": "Azure AD-Einstellungen gespeichert.", + "dnsSettingsSaved": "DNS-Einstellungen gespeichert.", + "ldapSettingsSaved": "LDAP-Einstellungen gespeichert.", + "gitSettingsSaved": "Git-Einstellungen gespeichert.", + "updateStarted": "Update gestartet. Die App wird in Kürze neu starten.", + "passwordChanged": "Passwort erfolgreich geändert.", + "setupUrlCopied": "Setup-URL in Zwischenablage kopiert.", + "copiedToClipboard": "In Zwischenablage kopiert.", + "userCreated": "Benutzer '{username}' erstellt.", + "userDeleted": "Benutzer '{username}' gelöscht.", + "passwordResetFor": "Passwort zurückgesetzt für '{username}'.", + "newPasswordAlert": "Neues Passwort für '{username}':\n\n{password}\n\nBitte speichern Sie dieses Passwort jetzt. Es wird nicht erneut angezeigt.", + "confirmDeleteUser": "Benutzer '{username}' löschen? Dies kann nicht rückgängig gemacht werden.", + "confirmResetPassword": "Passwort für '{username}' zurücksetzen? Ein neues zufälliges Passwort wird generiert." + }, + "userModal": { + "title": "Neuer Benutzer", + "usernameLabel": "Benutzername *", + "passwordLabel": "Passwort * (min. 8 Zeichen)", + "emailLabel": "E-Mail", + "languageLabel": "Standardsprache", + "cancel": "Abbrechen", + "createUser": "Benutzer erstellen" + }, + "customerModal": { + "newCustomer": "Neuer Kunde", + "editCustomer": "Kunde bearbeiten", + "nameLabel": "Name *", + "companyLabel": "Firma", + "subdomainLabel": "Subdomain *", + "subdomainHint": "Kleinbuchstaben, alphanumerisch + Bindestriche", + "emailLabel": "E-Mail *", + "maxDevicesLabel": "Max. Geräte", + "notesLabel": "Notizen", + "cancel": "Abbrechen", + "saveAndDeploy": "Speichern & Bereitstellen", + "saveChanges": "Änderungen speichern" + }, + "deleteModal": { + "title": "Löschen bestätigen", + "confirmText": "Möchten Sie den Kunden wirklich löschen:", + "warning": "Alle Container, NPM-Einträge und Daten werden entfernt. Diese Aktion kann nicht rückgängig gemacht werden.", + "cancel": "Abbrechen", + "delete": "Löschen" + }, + "monitoring": { + "title": "System-Monitoring", + "refresh": "Aktualisieren", + "hostResources": "Host-Ressourcen", + "hostname": "Hostname", + "cpu": "CPU ({count} Kerne)", + "memory": "Arbeitsspeicher ({used}/{total} GB)", + "disk": "Festplatte ({used}/{total} GB)", + "allCustomerDeployments": "Alle Kunden-Deployments", + "thId": "ID", + "thName": "Name", + "thSubdomain": "Subdomain", + "thStatus": "Status", + "thDeployment": "Deployment", + "thDashboard": "Dashboard", + "thRelayPort": "Relay-Port", + "thContainers": "Container", + "noCustomers": "Keine Kunden." } } diff --git a/static/lang/en.json b/static/lang/en.json index 72b1965..0dd40f4 100644 --- a/static/lang/en.json +++ b/static/lang/en.json @@ -120,6 +120,9 @@ "tabBranding": "Branding", "tabUsers": "Users", "tabAzure": "Azure AD", + "tabDns": "Windows DNS", + "tabLdap": "LDAP / AD", + "tabUpdate": "Updates", "tabSecurity": "Security", "baseDomain": "Base Domain", "baseDomainPlaceholder": "yourdomain.com", @@ -202,6 +205,52 @@ "secretSet": "Secret is set (leave empty to keep current)", "noSecret": "No client secret configured", "saveAzureSettings": "Save Azure AD Settings", + "azureGroupId": "Allowed Group Object ID (optional)", + "azureGroupIdHint": "If set, only Azure AD members of this group can log in.", + "dnsTitle": "Windows DNS Integration", + "enableDns": "Enable Windows DNS Integration", + "dnsDescription": "Automatically create/delete DNS A-records when deploying customers.", + "dnsServer": "DNS Server Address", + "dnsZone": "DNS Zone", + "dnsUsername": "Username (NTLM)", + "dnsPassword": "Password", + "dnsRecordIp": "A-Record Target IP", + "dnsRecordIpHint": "IP address that customer A-records will point to (usually your NPM server IP).", + "saveDnsSettings": "Save DNS Settings", + "ldapTitle": "LDAP / Active Directory Authentication", + "enableLdap": "Enable LDAP / AD Authentication", + "ldapDescription": "Allow Active Directory users to log in. Local admin accounts always work as fallback.", + "ldapServer": "LDAP Server", + "ldapPort": "Port", + "ldapUseSsl": "Use SSL/TLS (LDAPS)", + "ldapBindDn": "Bind DN (Service Account)", + "ldapBindPassword": "Bind Password", + "ldapBaseDn": "Base DN", + "ldapUserFilter": "User Filter", + "ldapUserFilterHint": "Use {username} as placeholder for the login name.", + "ldapGroupDn": "Group Restriction DN (optional)", + "ldapGroupDnHint": "If set, only members of this group can log in via LDAP.", + "saveLdapSettings": "Save LDAP Settings", + "versionTitle": "Version & Updates", + "currentVersion": "Installed Version", + "latestVersion": "Latest Available", + "branch": "Branch", + "updateAvailable": "Update Available", + "upToDate": "Up to date", + "triggerUpdate": "Start Update", + "updateWarning": "The app will be unavailable for ~60 seconds during rebuild.", + "confirmUpdate": "Start the update now? The database will be backed up first. The app will restart (~60 seconds downtime).", + "gitTitle": "Git Repository Settings", + "gitRepoUrl": "Repository URL", + "gitRepoUrlHint": "Used for version checks and one-click updates via Gitea API.", + "gitBranch": "Branch", + "gitToken": "Access Token (optional)", + "saveGitSettings": "Save Git Settings", + "leaveEmptyToKeep": "Leave empty to keep current", + "passwordSet": "Password is set (leave empty to keep current)", + "noPasswordSet": "No password configured", + "tokenSet": "Token is set (leave empty to keep current)", + "noToken": "No access token configured", "securityTitle": "Change Admin Password", "currentPassword": "Current Password", "newPassword": "New Password (min 12 chars)", @@ -306,6 +355,10 @@ "logoUploaded": "Logo uploaded successfully.", "logoRemoved": "Logo removed.", "azureSettingsSaved": "Azure AD settings saved.", + "dnsSettingsSaved": "DNS settings saved.", + "ldapSettingsSaved": "LDAP settings saved.", + "gitSettingsSaved": "Git settings saved.", + "updateStarted": "Update started. The app will restart shortly.", "passwordChanged": "Password changed successfully.", "setupUrlCopied": "Setup URL copied to clipboard.", "copiedToClipboard": "Copied to clipboard.",