Compare commits

...

27 commits

Author SHA1 Message Date
63930c3fa9
Update Pangolin to v1.9.4 2025-09-02 23:56:17 +02:00
Owen Schwartz
cd79e77576
Merge pull request #1397 from fosrl/dev
1.9.4
2025-09-01 17:47:01 -07:00
Owen Schwartz
1f1c20d637
Merge pull request #1396 from fosrl/crowdin_dev
New Crowdin updates
2025-09-01 17:46:22 -07:00
Owen Schwartz
e87b3b1b54 New translations en-us.json (Norwegian Bokmal) 2025-09-01 17:46:02 -07:00
Owen Schwartz
a6f7b65625 New translations en-us.json (Chinese Simplified) 2025-09-01 17:46:01 -07:00
Owen Schwartz
722fa47132 New translations en-us.json (Turkish) 2025-09-01 17:46:00 -07:00
Owen Schwartz
f83e290b4c New translations en-us.json (Russian) 2025-09-01 17:45:59 -07:00
Owen Schwartz
11b4047283 New translations en-us.json (Portuguese) 2025-09-01 17:45:57 -07:00
Owen Schwartz
69b2032a86 New translations en-us.json (Polish) 2025-09-01 17:45:56 -07:00
Owen Schwartz
636298569f New translations en-us.json (Dutch) 2025-09-01 17:45:55 -07:00
Owen Schwartz
ed8a282d35 New translations en-us.json (Korean) 2025-09-01 17:45:54 -07:00
Owen Schwartz
3bd5e850e0 New translations en-us.json (Italian) 2025-09-01 17:45:52 -07:00
Owen Schwartz
070f1f9159 New translations en-us.json (German) 2025-09-01 17:45:51 -07:00
Owen Schwartz
195644cca5 New translations en-us.json (Czech) 2025-09-01 17:45:50 -07:00
Owen Schwartz
8092c86ecd New translations en-us.json (Bulgarian) 2025-09-01 17:45:49 -07:00
Owen Schwartz
28f33702da New translations en-us.json (Spanish) 2025-09-01 17:45:48 -07:00
Owen Schwartz
570632b8be New translations en-us.json (French) 2025-09-01 17:45:46 -07:00
Owen
f2881e1b31
Merge branch 'Pallavikumarimdb-enhancement-#906/persist-amount-of-entries' into dev 2025-09-01 17:40:02 -07:00
Owen
dad35e37ef
Merge branch 'enhancement-#906/persist-amount-of-entries' of github.com:Pallavikumarimdb/pangolin into Pallavikumarimdb-enhancement-#906/persist-amount-of-entries 2025-09-01 17:39:16 -07:00
Owen
39afabd60e
Source maps as js 2025-09-01 14:03:32 -07:00
Owen
dc7e14a34b
Limit saas 2025-09-01 11:39:30 -07:00
Owen
1dca71a779
Try to include source maps 2025-09-01 11:29:49 -07:00
Pallavi
e9494efa8e quick fix 2025-09-01 23:06:39 +05:30
Owen Schwartz
8159a0f13d
Merge pull request #1394 from Pallavikumarimdb/Fix/hostname-field-reset-port-and-method
Fix/hostname field reset port and method
2025-09-01 10:21:31 -07:00
Pallavi
ee9101e738 Save Amount of Entries 2025-09-01 22:26:12 +05:30
Pallavi
b670e6e3dc update parser to handle h2c 2025-09-01 21:47:50 +05:30
Pallavi
5e5754fa62 preserve port and method on host change 2025-09-01 21:22:18 +05:30
35 changed files with 776 additions and 63 deletions

View file

@ -1059,6 +1059,7 @@
"actionGetSiteResource": "Get Site Resource",
"actionListSiteResources": "List Site Resources",
"actionUpdateSiteResource": "Update Site Resource",
"actionListInvitations": "List Invitations",
"noneSelected": "None selected",
"orgNotFound2": "No organizations found.",
"searchProgress": "Search...",
@ -1458,6 +1459,42 @@
"autoLoginError": "Auto Login Error",
"autoLoginErrorNoRedirectUrl": "No redirect URL received from the identity provider.",
"autoLoginErrorGeneratingUrl": "Failed to generate authentication URL.",
"managedSelfHosted": {
"title": "Managed Self-Hosted",
"description": "More reliable and low-maintenance self-hosted Pangolin server with extra bells and whistles",
"introTitle": "Managed Self-Hosted Pangolin",
"introDescription": "is a deployment option designed for people who want simplicity and extra reliability while still keeping their data private and self-hosted.",
"introDetail": "With this option, you still run your own Pangolin node — your tunnels, SSL termination, and traffic all stay on your server. The difference is that management and monitoring are handled through our cloud dashboard, which unlocks a number of benefits:",
"benefitSimplerOperations": {
"title": "Simpler operations",
"description": "No need to run your own mail server or set up complex alerting. You'll get health checks and downtime alerts out of the box."
},
"benefitAutomaticUpdates": {
"title": "Automatic updates",
"description": "The cloud dashboard evolves quickly, so you get new features and bug fixes without having to manually pull new containers every time."
},
"benefitLessMaintenance": {
"title": "Less maintenance",
"description": "No database migrations, backups, or extra infrastructure to manage. We handle that in the cloud."
},
"benefitCloudFailover": {
"title": "Cloud failover",
"description": "If your node goes down, your tunnels can temporarily fail over to our cloud points of presence until you bring it back online."
},
"benefitHighAvailability": {
"title": "High availability (PoPs)",
"description": "You can also attach multiple nodes to your account for redundancy and better performance."
},
"benefitFutureEnhancements": {
"title": "Future enhancements",
"description": "We're planning to add more analytics, alerting, and management tools to make your deployment even more robust."
},
"docsAlert": {
"text": "Learn more about the Managed Self-Hosted option in our",
"documentation": "documentation"
},
"convertButton": "Convert This Node to Managed Self-Hosted"
},
"internationaldomaindetected": "International Domain Detected",
"willbestoredas": "Will be stored as:"
}

View file

@ -1059,6 +1059,7 @@
"actionGetSiteResource": "Get Site Resource",
"actionListSiteResources": "List Site Resources",
"actionUpdateSiteResource": "Update Site Resource",
"actionListInvitations": "List Invitations",
"noneSelected": "None selected",
"orgNotFound2": "No organizations found.",
"searchProgress": "Search...",
@ -1458,6 +1459,42 @@
"autoLoginError": "Auto Login Error",
"autoLoginErrorNoRedirectUrl": "No redirect URL received from the identity provider.",
"autoLoginErrorGeneratingUrl": "Failed to generate authentication URL.",
"internationaldomaindetected": "Detekována mezinárodní doména",
"willbestoredas": "Bude uloženo jako:"
"managedSelfHosted": {
"title": "Managed Self-Hosted",
"description": "More reliable and low-maintenance self-hosted Pangolin server with extra bells and whistles",
"introTitle": "Managed Self-Hosted Pangolin",
"introDescription": "is a deployment option designed for people who want simplicity and extra reliability while still keeping their data private and self-hosted.",
"introDetail": "With this option, you still run your own Pangolin node — your tunnels, SSL termination, and traffic all stay on your server. The difference is that management and monitoring are handled through our cloud dashboard, which unlocks a number of benefits:",
"benefitSimplerOperations": {
"title": "Simpler operations",
"description": "No need to run your own mail server or set up complex alerting. You'll get health checks and downtime alerts out of the box."
},
"benefitAutomaticUpdates": {
"title": "Automatic updates",
"description": "The cloud dashboard evolves quickly, so you get new features and bug fixes without having to manually pull new containers every time."
},
"benefitLessMaintenance": {
"title": "Less maintenance",
"description": "No database migrations, backups, or extra infrastructure to manage. We handle that in the cloud."
},
"benefitCloudFailover": {
"title": "Cloud failover",
"description": "If your node goes down, your tunnels can temporarily fail over to our cloud points of presence until you bring it back online."
},
"benefitHighAvailability": {
"title": "High availability (PoPs)",
"description": "You can also attach multiple nodes to your account for redundancy and better performance."
},
"benefitFutureEnhancements": {
"title": "Future enhancements",
"description": "We're planning to add more analytics, alerting, and management tools to make your deployment even more robust."
},
"docsAlert": {
"text": "Learn more about the Managed Self-Hosted option in our",
"documentation": "documentation"
},
"convertButton": "Convert This Node to Managed Self-Hosted"
},
"internationaldomaindetected": "International Domain Detected",
"willbestoredas": "Will be stored as:"
}

View file

@ -1059,6 +1059,7 @@
"actionGetSiteResource": "Site-Ressource abrufen",
"actionListSiteResources": "Site-Ressourcen auflisten",
"actionUpdateSiteResource": "Site-Ressource aktualisieren",
"actionListInvitations": "Einladungen auflisten",
"noneSelected": "Keine ausgewählt",
"orgNotFound2": "Keine Organisationen gefunden.",
"searchProgress": "Suche...",
@ -1458,6 +1459,42 @@
"autoLoginError": "Fehler bei der automatischen Anmeldung",
"autoLoginErrorNoRedirectUrl": "Keine Weiterleitungs-URL vom Identitätsanbieter erhalten.",
"autoLoginErrorGeneratingUrl": "Fehler beim Generieren der Authentifizierungs-URL.",
"internationaldomaindetected": "Internationale Domäne erkannt",
"managedSelfHosted": {
"title": "Verwaltetes Selbsthosted",
"description": "Zuverlässiger und wartungsarmer Pangolin Server mit zusätzlichen Glocken und Pfeifen",
"introTitle": "Verwalteter selbstgehosteter Pangolin",
"introDescription": "ist eine Deployment-Option, die für Personen konzipiert wurde, die Einfachheit und zusätzliche Zuverlässigkeit wünschen, während sie ihre Daten privat und selbstgehostet halten.",
"introDetail": "Mit dieser Option haben Sie immer noch Ihren eigenen Pangolin-Knoten Ihre Tunnel, SSL-Terminierung und Traffic bleiben auf Ihrem Server. Der Unterschied besteht darin, dass Verwaltung und Überwachung über unser Cloud-Dashboard abgewickelt werden, das eine Reihe von Vorteilen freischaltet:",
"benefitSimplerOperations": {
"title": "Einfachere Operationen",
"description": "Sie brauchen keinen eigenen Mail-Server auszuführen oder komplexe Warnungen einzurichten. Sie erhalten Gesundheitschecks und Ausfallwarnungen aus dem Box."
},
"benefitAutomaticUpdates": {
"title": "Automatische Updates",
"description": "Das Cloud-Dashboard entwickelt sich schnell, so dass Sie neue Funktionen und Fehlerbehebungen erhalten, ohne jedes Mal neue Container manuell ziehen zu müssen."
},
"benefitLessMaintenance": {
"title": "Weniger Wartung",
"description": "Keine Datenbankmigrationen, Sicherungen oder zusätzliche Infrastruktur zum Verwalten. Wir kümmern uns um das in der Cloud."
},
"benefitCloudFailover": {
"title": "Cloud-Ausfall",
"description": "Wenn Ihr Knoten runtergeht, können Ihre Tunnel vorübergehend an unsere Cloud-Punkte scheitern, bis Sie ihn wieder online bringen."
},
"benefitHighAvailability": {
"title": "Hohe Verfügbarkeit (PoPs)",
"description": "Sie können auch mehrere Knoten an Ihr Konto anhängen, um Redundanz und bessere Leistung zu erzielen."
},
"benefitFutureEnhancements": {
"title": "Zukünftige Verbesserungen",
"description": "Wir planen weitere Analyse-, Alarm- und Management-Tools hinzuzufügen, um Ihren Einsatz noch robuster zu machen."
},
"docsAlert": {
"text": "Erfahren Sie mehr über die Managed Self-Hosted Option in unserer",
"documentation": "dokumentation"
},
"convertButton": "Diesen Knoten in Managed Self-Hosted umwandeln"
},
"internationaldomaindetected": "Internationale Domain erkannt",
"willbestoredas": "Wird gespeichert als:"
}

View file

@ -1059,6 +1059,7 @@
"actionGetSiteResource": "Obtener recurso del sitio",
"actionListSiteResources": "Listar recursos del sitio",
"actionUpdateSiteResource": "Actualizar recurso del sitio",
"actionListInvitations": "Listar invitaciones",
"noneSelected": "Ninguno seleccionado",
"orgNotFound2": "No se encontraron organizaciones.",
"searchProgress": "Buscar...",
@ -1458,6 +1459,42 @@
"autoLoginError": "Error de inicio de sesión automático",
"autoLoginErrorNoRedirectUrl": "No se recibió URL de redirección del proveedor de identidad.",
"autoLoginErrorGeneratingUrl": "Error al generar URL de autenticación.",
"internationaldomaindetected": "Dominio internacional detectado",
"willbestoredas": "Se almacenará como: "
"managedSelfHosted": {
"title": "Autogestionado",
"description": "Servidor Pangolin autoalojado más fiable y de bajo mantenimiento con campanas y silbidos extra",
"introTitle": "Pangolin autogestionado",
"introDescription": "es una opción de despliegue diseñada para personas que quieren simplicidad y fiabilidad extra mientras mantienen sus datos privados y autoalojados.",
"introDetail": "Con esta opción, todavía ejecuta su propio nodo Pangolin, sus túneles, terminación SSL y tráfico permanecen en su servidor. La diferencia es que la gestión y el control se gestionan a través de nuestro panel de control en la nube, que desbloquea una serie de ventajas:",
"benefitSimplerOperations": {
"title": "Operaciones simples",
"description": "No necesitas ejecutar tu propio servidor de correo o configurar alertas complejas. Recibirás cheques de salud y alertas de tiempo de inactividad."
},
"benefitAutomaticUpdates": {
"title": "Actualizaciones automáticas",
"description": "El tablero de la nube evolucionará rápidamente, por lo que obtendrá nuevas características y correcciones de errores sin tener que extraer manualmente nuevos contenedores cada vez."
},
"benefitLessMaintenance": {
"title": "Menos mantenimiento",
"description": "No hay migraciones de base de datos, copias de seguridad o infraestructura extra para administrar. Lo manejamos en la nube."
},
"benefitCloudFailover": {
"title": "Fallo en la nube",
"description": "Si tu nodo cae, tus túneles pueden fallar temporalmente a nuestros puntos de presencia en la nube hasta que lo vuelvas a conectar."
},
"benefitHighAvailability": {
"title": "Alta disponibilidad (PoPs)",
"description": "También puede adjuntar múltiples nodos a su cuenta para redundancia y mejor rendimiento."
},
"benefitFutureEnhancements": {
"title": "Mejoras futuras",
"description": "Estamos planeando añadir más herramientas analíticas, alertas y de administración para hacer su despliegue aún más robusto."
},
"docsAlert": {
"text": "Aprenda más acerca de la opción de autoalojamiento administrado en nuestra",
"documentation": "documentación"
},
"convertButton": "Convierte este nodo a autoalojado administrado"
},
"internationaldomaindetected": "Dominio Internacional detectado",
"willbestoredas": "Se almacenará como:"
}

View file

@ -1059,6 +1059,7 @@
"actionGetSiteResource": "Obtenir une ressource de site",
"actionListSiteResources": "Lister les ressources de site",
"actionUpdateSiteResource": "Mettre à jour une ressource de site",
"actionListInvitations": "Lister les invitations",
"noneSelected": "Aucune sélection",
"orgNotFound2": "Aucune organisation trouvée.",
"searchProgress": "Rechercher...",
@ -1458,6 +1459,42 @@
"autoLoginError": "Erreur de connexion automatique",
"autoLoginErrorNoRedirectUrl": "Aucune URL de redirection reçue du fournisseur d'identité.",
"autoLoginErrorGeneratingUrl": "Échec de la génération de l'URL d'authentification.",
"managedSelfHosted": {
"title": "Gestion autonome",
"description": "Serveur Pangolin auto-hébergé avec des cloches et des sifflets supplémentaires",
"introTitle": "Pangolin auto-hébergé géré",
"introDescription": "est une option de déploiement conçue pour les personnes qui veulent de la simplicité et de la fiabilité tout en gardant leurs données privées et auto-hébergées.",
"introDetail": "Avec cette option, vous exécutez toujours votre propre nœud Pangolin — vos tunnels, la terminaison SSL et le trafic restent sur votre serveur. La différence est que la gestion et la surveillance sont gérées via notre tableau de bord du cloud, qui déverrouille un certain nombre d'avantages :",
"benefitSimplerOperations": {
"title": "Opérations plus simples",
"description": "Pas besoin de faire tourner votre propre serveur de messagerie ou de configurer des alertes complexes. Vous obtiendrez des contrôles de santé et des alertes de temps d'arrêt par la suite."
},
"benefitAutomaticUpdates": {
"title": "Mises à jour automatiques",
"description": "Le tableau de bord du cloud évolue rapidement, de sorte que vous obtenez de nouvelles fonctionnalités et des corrections de bugs sans avoir à extraire manuellement de nouveaux conteneurs à chaque fois."
},
"benefitLessMaintenance": {
"title": "Moins de maintenance",
"description": "Aucune migration de base de données, sauvegarde ou infrastructure supplémentaire à gérer. Nous gérons cela dans le cloud."
},
"benefitCloudFailover": {
"title": "Basculement du Cloud",
"description": "Si votre nœud descend, vos tunnels peuvent temporairement échouer jusqu'à ce que vous le rapatriez en ligne."
},
"benefitHighAvailability": {
"title": "Haute disponibilité (PoPs)",
"description": "Vous pouvez également attacher plusieurs nœuds à votre compte pour une redondance et de meilleures performances."
},
"benefitFutureEnhancements": {
"title": "Améliorations futures",
"description": "Nous prévoyons d'ajouter plus d'outils d'analyse, d'alerte et de gestion pour rendre votre déploiement encore plus robuste."
},
"docsAlert": {
"text": "En savoir plus sur l'option Auto-Hébergement géré dans notre",
"documentation": "documentation"
},
"convertButton": "Convertir ce noeud en auto-hébergé géré"
},
"internationaldomaindetected": "Domaine international détecté",
"willbestoredas": "Sera stocké comme:"
"willbestoredas": "Sera stocké comme :"
}

View file

@ -1059,6 +1059,7 @@
"actionGetSiteResource": "Ottieni Risorsa del Sito",
"actionListSiteResources": "Elenca Risorse del Sito",
"actionUpdateSiteResource": "Aggiorna Risorsa del Sito",
"actionListInvitations": "Elenco Inviti",
"noneSelected": "Nessuna selezione",
"orgNotFound2": "Nessuna organizzazione trovata.",
"searchProgress": "Ricerca...",
@ -1458,6 +1459,42 @@
"autoLoginError": "Errore di Accesso Automatico",
"autoLoginErrorNoRedirectUrl": "Nessun URL di reindirizzamento ricevuto dal provider di identità.",
"autoLoginErrorGeneratingUrl": "Impossibile generare l'URL di autenticazione.",
"internationaldomaindetected": "Rilevato dominio internazionale",
"willbestoredas": "Verrà archiviato come:"
"managedSelfHosted": {
"title": "Gestito Auto-Ospitato",
"description": "Server Pangolin self-hosted più affidabile e a bassa manutenzione con campanelli e fischietti extra",
"introTitle": "Managed Self-Hosted Pangolin",
"introDescription": "è un'opzione di distribuzione progettata per le persone che vogliono la semplicità e l'affidabilità extra mantenendo i loro dati privati e self-hosted.",
"introDetail": "Con questa opzione, esegui ancora il tuo nodo Pangolin — i tunnel, la terminazione SSL e il traffico rimangono tutti sul tuo server. La differenza è che la gestione e il monitoraggio sono gestiti attraverso il nostro cruscotto cloud, che sblocca una serie di vantaggi:",
"benefitSimplerOperations": {
"title": "Operazioni più semplici",
"description": "Non è necessario eseguire il proprio server di posta o impostare un avviso complesso. Otterrai controlli di salute e avvisi di inattività fuori dalla casella."
},
"benefitAutomaticUpdates": {
"title": "Aggiornamenti automatici",
"description": "Il cruscotto cloud si evolve rapidamente, in modo da ottenere nuove funzionalità e correzioni di bug senza dover tirare manualmente nuovi contenitori ogni volta."
},
"benefitLessMaintenance": {
"title": "Meno manutenzione",
"description": "Nessuna migrazione di database, backup o infrastruttura extra da gestire. Gestiamo questo problema nel cloud."
},
"benefitCloudFailover": {
"title": "failover del cloud",
"description": "Se il tuo nodo scende, i tuoi tunnel possono temporaneamente fallire nei nostri punti di presenza cloud fino a quando non lo riporti online."
},
"benefitHighAvailability": {
"title": "Alta disponibilità (PoPs)",
"description": "Puoi anche allegare più nodi al tuo account per ridondanza e prestazioni migliori."
},
"benefitFutureEnhancements": {
"title": "Miglioramenti futuri",
"description": "Stiamo pianificando di aggiungere più strumenti di analisi, allerta e gestione per rendere la tua distribuzione ancora più robusta."
},
"docsAlert": {
"text": "Scopri di più sull'opzione Managed Self-Hosted nella nostra",
"documentation": "documentazione"
},
"convertButton": "Converti questo nodo in auto-ospitato gestito"
},
"internationaldomaindetected": "Dominio Internazionale Rilevato",
"willbestoredas": "Verrà conservato come:"
}

View file

@ -1059,6 +1059,7 @@
"actionGetSiteResource": "사이트 리소스 가져오기",
"actionListSiteResources": "사이트 리소스 목록",
"actionUpdateSiteResource": "사이트 리소스 업데이트",
"actionListInvitations": "초대 목록",
"noneSelected": "선택된 항목 없음",
"orgNotFound2": "조직이 없습니다.",
"searchProgress": "검색...",
@ -1458,6 +1459,42 @@
"autoLoginError": "자동 로그인 오류",
"autoLoginErrorNoRedirectUrl": "ID 공급자로부터 리디렉션 URL을 받지 못했습니다.",
"autoLoginErrorGeneratingUrl": "인증 URL 생성 실패.",
"managedSelfHosted": {
"title": "관리 자체 호스팅",
"description": "더 신뢰할 수 있고 낮은 유지보수의 자체 호스팅 팡골린 서버, 추가 기능 포함",
"introTitle": "관리 자체 호스팅 팡골린",
"introDescription": "는 자신의 데이터를 프라이빗하고 자체 호스팅을 유지하면서 더 간단하고 추가적인 신뢰성을 원하는 사람들을 위한 배포 옵션입니다.",
"introDetail": "이 옵션을 사용하면 여전히 자신의 팡골린 노드를 운영하고 - 터널, SSL 종료 및 트래픽 모두 서버에 유지됩니다. 차이점은 관리 및 모니터링이 클라우드 대시보드를 통해 처리되어 여러 혜택을 제공합니다.",
"benefitSimplerOperations": {
"title": "더 간단한 운영",
"description": "자체 메일 서버를 운영하거나 복잡한 경고를 설정할 필요가 없습니다. 기본적으로 상태 점검 및 다운타임 경고를 받을 수 있습니다."
},
"benefitAutomaticUpdates": {
"title": "자동 업데이트",
"description": "클라우드 대시보드는 빠르게 발전하므로 새로운 기능과 버그 수정 사항을 수동으로 새로운 컨테이너를 가져오지 않고도 받을 수 있습니다."
},
"benefitLessMaintenance": {
"title": "유지보수 감소",
"description": "데이터베이스 마이그레이션, 백업 또는 추가 인프라를 관리할 필요가 없습니다. 저희가 클라우드에서 처리합니다."
},
"benefitCloudFailover": {
"title": "클라우드 장애 조치",
"description": "노드가 다운되면 터널이 클라우드의 프레즌스 포인트로 임시 전환되어 노드를 다시 온라인으로 가져올 때까지 유지됩니다."
},
"benefitHighAvailability": {
"title": "고가용성 (PoPs)",
"description": "계정에 여러 노드를 연결하여 이중성과 성능을 향상시킬 수 있습니다."
},
"benefitFutureEnhancements": {
"title": "향후 개선",
"description": "배포를 더욱 견고하게 만들기 위해 더 많은 분석, 경고, 및 관리 도구를 추가할 계획입니다."
},
"docsAlert": {
"text": "관리 자체 호스팅 옵션에 대해 더 알아보세요",
"documentation": "문서"
},
"convertButton": "이 노드를 관리 자체 호스팅으로 변환"
},
"internationaldomaindetected": "국제 도메인 감지됨",
"willbestoredas": "다음과 같이 저장됩니다."
"willbestoredas": "다음으로 저장됩니다:"
}

View file

@ -1059,6 +1059,7 @@
"actionGetSiteResource": "Hent Stedsressurs",
"actionListSiteResources": "List opp Stedsressurser",
"actionUpdateSiteResource": "Oppdater Stedsressurs",
"actionListInvitations": "Liste invitasjoner",
"noneSelected": "Ingen valgt",
"orgNotFound2": "Ingen organisasjoner funnet.",
"searchProgress": "Søker...",
@ -1457,5 +1458,43 @@
"autoLoginRedirecting": "Omdirigerer til innlogging...",
"autoLoginError": "Feil ved automatisk innlogging",
"autoLoginErrorNoRedirectUrl": "Ingen omdirigerings-URL mottatt fra identitetsleverandøren.",
"autoLoginErrorGeneratingUrl": "Kunne ikke generere autentiserings-URL."
"autoLoginErrorGeneratingUrl": "Kunne ikke generere autentiserings-URL.",
"managedSelfHosted": {
"title": "Administrert selv-hostet",
"description": "Sikre og lavvedlikeholdsservere, selvbetjente Pangolin med ekstra klokker, og understell",
"introTitle": "Administrert Self-Hosted Pangolin",
"introDescription": "er et alternativ for bruk utviklet for personer som ønsker enkel og ekstra pålitelighet mens de fortsatt holder sine data privat og selvdrevne.",
"introDetail": "Med dette valget kjører du fortsatt din egen Pangolin-node - tunneler, SSL-terminering og trafikken ligger på serveren din. Forskjellen er at behandling og overvåking håndteres gjennom vårt skydashbord, som låser opp en rekke fordeler:",
"benefitSimplerOperations": {
"title": "Enklere operasjoner",
"description": "Ingen grunn til å kjøre din egen e-postserver eller sette opp kompleks varsling. Du vil få helsesjekk og nedetid varsler ut av boksen."
},
"benefitAutomaticUpdates": {
"title": "Automatiske oppdateringer",
"description": "Cloud dashbordet utvikler seg raskt, så du får nye funksjoner og feilrettinger uten at du trenger å trekke nye beholdere manuelt hver gang."
},
"benefitLessMaintenance": {
"title": "Mindre vedlikehold",
"description": "Ingen databasestyrer, sikkerhetskopier eller ekstra infrastruktur for å forvalte. Vi håndterer det i skyen."
},
"benefitCloudFailover": {
"title": "Sky feilslått",
"description": "Hvis EK-gruppen din går ned, kan tunnlene midlertidig mislykkes i å nå våre sky-punkter til du tar den tilbake på nett."
},
"benefitHighAvailability": {
"title": "Høy tilgjengelighet (PoPs)",
"description": "Du kan også legge ved flere noder til kontoen din for redundans og bedre ytelse."
},
"benefitFutureEnhancements": {
"title": "Fremtidige forbedringer",
"description": "Vi planlegger å legge inn mer analyser, varsle og styringsverktøy for å gjøre din distribusjon enda mer robust."
},
"docsAlert": {
"text": "Lær mer om Managed Self-Hosted alternativet i vår",
"documentation": "dokumentasjon"
},
"convertButton": "Konverter denne noden til manuelt bruk"
},
"internationaldomaindetected": "Internasjonalt domene oppdaget",
"willbestoredas": "Vil bli lagret som:"
}

View file

@ -1059,6 +1059,7 @@
"actionGetSiteResource": "Bron van site ophalen",
"actionListSiteResources": "Bronnen van site weergeven",
"actionUpdateSiteResource": "Document bijwerken van site",
"actionListInvitations": "Toon uitnodigingen",
"noneSelected": "Niet geselecteerd",
"orgNotFound2": "Geen organisaties gevonden.",
"searchProgress": "Zoeken...",
@ -1458,6 +1459,42 @@
"autoLoginError": "Auto Login Fout",
"autoLoginErrorNoRedirectUrl": "Geen redirect URL ontvangen van de identity provider.",
"autoLoginErrorGeneratingUrl": "Genereren van authenticatie-URL mislukt.",
"managedSelfHosted": {
"title": "Beheerde Self-Hosted",
"description": "betrouwbaardere en slecht onderhouden Pangolin server met extra klokken en klokkenluiders",
"introTitle": "Beheerde zelfgehoste pangolin",
"introDescription": "is een implementatieoptie ontworpen voor mensen die eenvoud en extra betrouwbaarheid willen, terwijl hun gegevens privé en zelf georganiseerd blijven.",
"introDetail": "Met deze optie beheert u nog steeds uw eigen Pangolin node - uw tunnels, SSL-verbinding en verkeer alles op uw server. Het verschil is dat beheer en monitoring worden behandeld via onze cloud dashboard, wat een aantal voordelen oplevert:",
"benefitSimplerOperations": {
"title": "Simpler operaties",
"description": "Je hoeft geen eigen mailserver te draaien of complexe waarschuwingen in te stellen. Je krijgt gezondheidscontroles en downtime meldingen uit de box."
},
"benefitAutomaticUpdates": {
"title": "Automatische updates",
"description": "Het cloud dashboard evolueert snel, zodat u nieuwe functies en bug fixes krijgt zonder elke keer handmatig nieuwe containers te moeten trekken."
},
"benefitLessMaintenance": {
"title": "Minder onderhoud",
"description": "Geen database migratie, back-ups of extra infrastructuur om te beheren. Dat behandelen we in de cloud."
},
"benefitCloudFailover": {
"title": "Cloud fout",
"description": "Als uw node omlaag gaat, kunnen uw tunnels tijdelijk niet meer naar onze aanwezigheidspunten gaan totdat u hem weer online brengt."
},
"benefitHighAvailability": {
"title": "Hoge beschikbaarheid (PoPs)",
"description": "U kunt ook meerdere nodes koppelen aan uw account voor ontslag en betere prestaties."
},
"benefitFutureEnhancements": {
"title": "Toekomstige verbeteringen",
"description": "We zijn van plan om meer analytica, waarschuwing en beheerhulpmiddelen toe te voegen om uw implementatie nog steviger te maken."
},
"docsAlert": {
"text": "Meer informatie over de optie voor zelf-verzorging in onze",
"documentation": "documentatie"
},
"convertButton": "Converteer deze node naar Beheerde Zelf-Hosted"
},
"internationaldomaindetected": "Internationaal Domein Gedetecteerd",
"willbestoredas": "Wordt opgeslagen als:"
"willbestoredas": "Zal worden opgeslagen als:"
}

View file

@ -1059,6 +1059,7 @@
"actionGetSiteResource": "Pobierz zasób strony",
"actionListSiteResources": "Lista zasobów strony",
"actionUpdateSiteResource": "Aktualizuj zasób strony",
"actionListInvitations": "Lista zaproszeń",
"noneSelected": "Nie wybrano",
"orgNotFound2": "Nie znaleziono organizacji.",
"searchProgress": "Szukaj...",
@ -1458,6 +1459,42 @@
"autoLoginError": "Błąd automatycznego logowania",
"autoLoginErrorNoRedirectUrl": "Nie otrzymano URL przekierowania od dostawcy tożsamości.",
"autoLoginErrorGeneratingUrl": "Nie udało się wygenerować URL uwierzytelniania.",
"internationaldomaindetected": "Wykryto domenę międzynarodową",
"willbestoredas": "Będzie przechowywane jako:"
"managedSelfHosted": {
"title": "Zarządzane Samodzielnie-Hostingowane",
"description": "Większa niezawodność i niska konserwacja serwera Pangolin z dodatkowymi dzwonkami i sygnałami",
"introTitle": "Zarządzany samowystarczalny Pangolin",
"introDescription": "jest opcją wdrażania zaprojektowaną dla osób, które chcą prostoty i dodatkowej niezawodności, przy jednoczesnym utrzymaniu swoich danych prywatnych i samodzielnych.",
"introDetail": "Z tą opcją nadal obsługujesz swój własny węzeł Pangolin — tunele, zakończenie SSL i ruch na Twoim serwerze. Różnica polega na tym, że zarządzanie i monitorowanie odbywa się za pomocą naszej tablicy rozdzielczej, która odblokowuje szereg korzyści:",
"benefitSimplerOperations": {
"title": "Uproszczone operacje",
"description": "Nie ma potrzeby uruchamiania własnego serwera pocztowego lub ustawiania skomplikowanych powiadomień. Będziesz mieć kontrolę zdrowia i powiadomienia o przestoju."
},
"benefitAutomaticUpdates": {
"title": "Automatyczne aktualizacje",
"description": "Panel chmury rozwija się szybko, więc otrzymujesz nowe funkcje i poprawki błędów bez konieczności ręcznego ciągnięcia nowych kontenerów za każdym razem."
},
"benefitLessMaintenance": {
"title": "Mniej konserwacji",
"description": "Brak migracji bazy danych, kopii zapasowych lub dodatkowej infrastruktury do zarządzania. Obsługujemy to w chmurze."
},
"benefitCloudFailover": {
"title": "Przegrywanie w chmurze",
"description": "Jeśli Twój węzeł zostanie wyłączony, tunele mogą tymczasowo zawieść do naszych punktów w chmurze, dopóki nie przyniesiesz go z powrotem do trybu online."
},
"benefitHighAvailability": {
"title": "Wysoka dostępność (PoPs)",
"description": "Możesz również dołączyć wiele węzłów do swojego konta w celu nadmiarowości i lepszej wydajności."
},
"benefitFutureEnhancements": {
"title": "Przyszłe ulepszenia",
"description": "Planujemy dodać więcej narzędzi analitycznych, ostrzegawczych i zarządzania, aby zwiększyć odporność wdrożenia."
},
"docsAlert": {
"text": "Dowiedz się więcej o opcji zarządzania samodzielnym hostingiem w naszym",
"documentation": "dokumentacja"
},
"convertButton": "Konwertuj ten węzeł do zarządzanego samodzielnie"
},
"internationaldomaindetected": "Wykryto międzynarodową domenę",
"willbestoredas": "Będą przechowywane jako:"
}

View file

@ -1059,6 +1059,7 @@
"actionGetSiteResource": "Obter Recurso do Site",
"actionListSiteResources": "Listar Recursos do Site",
"actionUpdateSiteResource": "Atualizar Recurso do Site",
"actionListInvitations": "Listar Convites",
"noneSelected": "Nenhum selecionado",
"orgNotFound2": "Nenhuma organização encontrada.",
"searchProgress": "Pesquisar...",
@ -1458,6 +1459,42 @@
"autoLoginError": "Erro de Login Automático",
"autoLoginErrorNoRedirectUrl": "Nenhum URL de redirecionamento recebido do provedor de identidade.",
"autoLoginErrorGeneratingUrl": "Falha ao gerar URL de autenticação.",
"internationaldomaindetected": "Domínio internacional detetado",
"managedSelfHosted": {
"title": "Gerenciado Auto-Hospedado",
"description": "Servidor Pangolin auto-hospedado mais confiável e com baixa manutenção com sinos extras e assobiamentos",
"introTitle": "Pangolin Auto-Hospedado Gerenciado",
"introDescription": "é uma opção de implantação projetada para pessoas que querem simplicidade e confiança adicional, mantendo os seus dados privados e auto-hospedados.",
"introDetail": "Com esta opção, você ainda roda seu próprio nó Pangolin — seus túneis, terminação SSL e tráfego todos permanecem no seu servidor. A diferença é que a gestão e a monitorização são geridos através do nosso painel de nuvem, que desbloqueia vários benefícios:",
"benefitSimplerOperations": {
"title": "Operações simples",
"description": "Não é necessário executar o seu próprio servidor de e-mail ou configurar um alerta complexo. Você receberá fora de caixa verificações de saúde e alertas de tempo de inatividade."
},
"benefitAutomaticUpdates": {
"title": "Atualizações automáticas",
"description": "O painel em nuvem evolui rapidamente, para que você obtenha novos recursos e correções de bugs sem ter de puxar manualmente novos contêineres toda vez."
},
"benefitLessMaintenance": {
"title": "Menos manutenção",
"description": "Sem migrações, backups ou infraestrutura extra para gerenciar. Lidamos com isso na nuvem."
},
"benefitCloudFailover": {
"title": "Falha na nuvem",
"description": "Se o seu nó descer, seus túneis podem falhar temporariamente nos nossos pontos de presença na nuvem até que você o traga online."
},
"benefitHighAvailability": {
"title": "Alta disponibilidade (Ppos)",
"description": "Você também pode anexar vários nós à sua conta para um melhor desempenho."
},
"benefitFutureEnhancements": {
"title": "Aprimoramentos futuros",
"description": "Estamos planejando adicionar mais análises, alertas e ferramentas de gerenciamento para tornar sua implantação ainda mais robusta."
},
"docsAlert": {
"text": "Saiba mais sobre a opção Hospedagem Auto-Gerenciada no nosso",
"documentation": "documentação"
},
"convertButton": "Converter este nó para Auto-Hospedado Gerenciado"
},
"internationaldomaindetected": "Domínio Internacional Detectado",
"willbestoredas": "Será armazenado como:"
}

View file

@ -1059,6 +1059,7 @@
"actionGetSiteResource": "Получить ресурс сайта",
"actionListSiteResources": "Список ресурсов сайта",
"actionUpdateSiteResource": "Обновить ресурс сайта",
"actionListInvitations": "Список приглашений",
"noneSelected": "Ничего не выбрано",
"orgNotFound2": "Организации не найдены.",
"searchProgress": "Поиск...",
@ -1458,6 +1459,42 @@
"autoLoginError": "Ошибка автоматического входа",
"autoLoginErrorNoRedirectUrl": "URL-адрес перенаправления не получен от провайдера удостоверения.",
"autoLoginErrorGeneratingUrl": "Не удалось сгенерировать URL-адрес аутентификации.",
"managedSelfHosted": {
"title": "Управляемый с самовывоза",
"description": "Более надежный и низко обслуживаемый сервер Pangolin с дополнительными колокольнями и свистками",
"introTitle": "Управляемый Само-Хост Панголина",
"introDescription": "- это вариант развертывания, предназначенный для людей, которые хотят простоты и надёжности, сохраняя при этом свои данные конфиденциальными и самостоятельными.",
"introDetail": "С помощью этой опции вы по-прежнему используете узел Pangolin — туннели, SSL, и весь остающийся на вашем сервере. Разница заключается в том, что управление и мониторинг осуществляются через нашу панель инструментов из облака, которая открывает ряд преимуществ:",
"benefitSimplerOperations": {
"title": "Более простые операции",
"description": "Не нужно запускать свой собственный почтовый сервер или настроить комплексное оповещение. Вы будете получать проверки состояния здоровья и оповещения о неисправностях из коробки."
},
"benefitAutomaticUpdates": {
"title": "Автоматическое обновление",
"description": "Панель управления в облаке развивается быстро, так что вы получаете новые функции и исправления ошибок, без необходимости каждый раз получать новые контейнеры."
},
"benefitLessMaintenance": {
"title": "Меньше обслуживания",
"description": "Нет миграции баз данных, резервных копий или дополнительной инфраструктуры для управления. Мы обрабатываем это в облаке."
},
"benefitCloudFailover": {
"title": "Облачное срабатывание",
"description": "Если ваш узел исчезнет, ваши туннели могут временно прерваться до наших облачных точек присутствия, пока вы не вернете его в сети."
},
"benefitHighAvailability": {
"title": "Высокая доступность (PoP)",
"description": "Вы также можете прикрепить несколько узлов к вашему аккаунту для избыточности и лучшей производительности."
},
"benefitFutureEnhancements": {
"title": "Будущие улучшения",
"description": "Мы планируем добавить дополнительные инструменты аналитики, оповещения и управления, чтобы сделать установку еще более надежной."
},
"docsAlert": {
"text": "Узнайте больше о опции Managed Self-Hosted в нашей",
"documentation": "документация"
},
"convertButton": "Конвертировать этот узел в управляемый себе-хост"
},
"internationaldomaindetected": "Обнаружен международный домен",
"willbestoredas": "Будет сохранен как:"
"willbestoredas": "Будет храниться как:"
}

View file

@ -1059,6 +1059,7 @@
"actionGetSiteResource": "Site Kaynağını Al",
"actionListSiteResources": "Site Kaynaklarını Listele",
"actionUpdateSiteResource": "Site Kaynağını Güncelle",
"actionListInvitations": "Davetiyeleri Listele",
"noneSelected": "Hiçbiri seçili değil",
"orgNotFound2": "Hiçbir organizasyon bulunamadı.",
"searchProgress": "Ara...",
@ -1458,6 +1459,42 @@
"autoLoginError": "Otomatik Giriş Hatası",
"autoLoginErrorNoRedirectUrl": "Kimlik sağlayıcıdan yönlendirme URL'si alınamadı.",
"autoLoginErrorGeneratingUrl": "Kimlik doğrulama URL'si oluşturulamadı.",
"internationaldomaindetected": "Uluslararası Etki Alanı Algılandı",
"willbestoredas": "Şu şekilde saklanacaktır:"
"managedSelfHosted": {
"title": "Yönetilen Self-Hosted",
"description": "Daha güvenilir ve düşük bakım gerektiren, ekstra özelliklere sahip kendi kendine barındırabileceğiniz Pangolin sunucusu",
"introTitle": "Yönetilen Kendi Kendine Barındırılan Pangolin",
"introDescription": "Bu, basitlik ve ekstra güvenilirlik arayan, ancak verilerini gizli tutmak ve kendi sunucularında barındırmak isteyen kişiler için tasarlanmış bir dağıtım seçeneğidir.",
"introDetail": "Bu seçenekle, kendi Pangolin düğümünüzü çalıştırmaya devam edersiniz — tünelleriniz, SSL bitişiniz ve trafiğiniz tamamen sunucunuzda kalır. Fark, yönetim ve izlemeyi bulut panomuz üzerinden gerçekleştiririz, bu da bir dizi avantaj sağlar:",
"benefitSimplerOperations": {
"title": "Daha basit işlemler",
"description": "Kendi e-posta sunucunuzu çalıştırmanıza veya karmaşık uyarılar kurmanıza gerek yok. Sağlık kontrolleri ve kesinti uyarılarını kutudan çıktığı gibi alırsınız."
},
"benefitAutomaticUpdates": {
"title": "Otomatik güncellemeler",
"description": "Bulut panosu hızla gelişir, böylece her seferinde yeni konteynerler manuel olarak çekmeden yeni özellikler ve hata düzeltmeleri alırsınız."
},
"benefitLessMaintenance": {
"title": "Daha az bakım",
"description": "Veritabanı geçişleri, yedeklemeler veya ekstra altyapı yönetimi yok. Biz bunu bulutta hallederiz."
},
"benefitCloudFailover": {
"title": "Bulut yedekleme",
"description": "Düğümünüz kapandığında, tünelleriniz geçici olarak bulut bağlantı noktalarımıza geçebilir, böylece tekrar çevrimiçi hale getirene kadar tünelleriniz kesintiye uğramaz."
},
"benefitHighAvailability": {
"title": "Yüksek kullanılabilirlik (Bağlantı Noktaları)",
"description": "Yedeklilik ve daha iyi performans için hesabınıza birden fazla düğüm bağlayabilirsiniz."
},
"benefitFutureEnhancements": {
"title": "Gelecek iyileştirmeler",
"description": "Dağıtımınızı daha sağlam hale getirmek amacıyla daha fazla analiz, uyarı ve yönetim aracı eklemeyi planlıyoruz."
},
"docsAlert": {
"text": "Yönetilen Kendi Kendine Barındırılan seçeneği hakkında daha fazla bilgi edinin",
"documentation": "dokümantasyon"
},
"convertButton": "Bu Düğümü Yönetilen Kendi Kendine Barındırma Dönüştürün"
},
"internationaldomaindetected": "Uluslararası Alan Adı Tespit Edildi",
"willbestoredas": "Şu şekilde depolanacak:"
}

View file

@ -1059,6 +1059,7 @@
"actionGetSiteResource": "获取站点资源",
"actionListSiteResources": "列出站点资源",
"actionUpdateSiteResource": "更新站点资源",
"actionListInvitations": "邀请列表",
"noneSelected": "未选择",
"orgNotFound2": "未找到组织。",
"searchProgress": "搜索中...",
@ -1458,6 +1459,42 @@
"autoLoginError": "自动登录错误",
"autoLoginErrorNoRedirectUrl": "未从身份提供商收到重定向URL。",
"autoLoginErrorGeneratingUrl": "生成身份验证URL失败。",
"internationaldomaindetected": "检测到国际域名",
"willbestoredas": "将存储为:"
"managedSelfHosted": {
"title": "托管自托管",
"description": "更可靠和低维护自我托管的 Pangolin 服务器,带有额外的铃声和告密器",
"introTitle": "托管自托管的潘戈林公司",
"introDescription": "这是一种部署选择,为那些希望简洁和额外可靠的人设计,同时仍然保持他们的数据的私密性和自我托管性。",
"introDetail": "通过此选项,您仍然运行您自己的 Pangolin 节点 — — 您的隧道、SSL 终止,并且流量在您的服务器上保持所有状态。 不同之处在于,管理和监测是通过我们的云层仪表板进行的,该仪表板开启了一些好处:",
"benefitSimplerOperations": {
"title": "简单的操作",
"description": "无需运行您自己的邮件服务器或设置复杂的警报。您将从方框中获得健康检查和下限提醒。"
},
"benefitAutomaticUpdates": {
"title": "自动更新",
"description": "云仪表盘快速演化,所以您可以获得新的功能和错误修复,而不必每次手动拉取新的容器。"
},
"benefitLessMaintenance": {
"title": "减少维护时间",
"description": "没有要管理的数据库迁移、备份或额外的基础设施。我们在云端处理这个问题。"
},
"benefitCloudFailover": {
"title": "云失败",
"description": "如果您的节点被关闭,您的隧道可能暂时无法连接到我们的云端,直到您将其重新连接上线。"
},
"benefitHighAvailability": {
"title": "高可用率(PoPs)",
"description": "您还可以将多个节点添加到您的帐户中以获取冗余和更好的性能。"
},
"benefitFutureEnhancements": {
"title": "将来的改进",
"description": "我们正在计划添加更多的分析、警报和管理工具,使你的部署更加有力。"
},
"docsAlert": {
"text": "在我们中更多地了解管理下的自托管选项",
"documentation": "文档"
},
"convertButton": "将此节点转换为管理自托管的"
},
"internationaldomaindetected": "检测到国际域",
"willbestoredas": "储存为:"
}

4
package-lock.json generated
View file

@ -83,6 +83,7 @@
"react-icons": "^5.5.0",
"rebuild": "0.1.2",
"semver": "^7.7.2",
"source-map-support": "0.5.21",
"swagger-ui-express": "^5.0.1",
"tailwind-merge": "3.3.1",
"tw-animate-css": "^1.3.7",
@ -6192,7 +6193,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true,
"license": "MIT"
},
"node_modules/bytes": {
@ -15571,7 +15571,6 @@
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@ -15590,7 +15589,6 @@
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",

View file

@ -100,6 +100,7 @@
"react-icons": "^5.5.0",
"rebuild": "0.1.2",
"semver": "^7.7.2",
"source-map-support": "0.5.21",
"swagger-ui-express": "^5.0.1",
"tailwind-merge": "3.3.1",
"tw-animate-css": "^1.3.7",

View file

@ -1,5 +1,6 @@
#! /usr/bin/env node
import "./extendZod.ts";
import 'source-map-support/register.js'
import { runSetupFunctions } from "./setup";
import { createApiServer } from "./apiServer";

View file

@ -76,13 +76,16 @@ authenticated.post(
verifyUserHasAction(ActionsEnum.updateOrg),
org.updateOrg
);
authenticated.delete(
"/org/:orgId",
verifyOrgAccess,
verifyUserIsOrgOwner,
verifyUserHasAction(ActionsEnum.deleteOrg),
org.deleteOrg
);
if (build !== "saas") {
authenticated.delete(
"/org/:orgId",
verifyOrgAccess,
verifyUserIsOrgOwner,
verifyUserHasAction(ActionsEnum.deleteOrg),
org.deleteOrg
);
}
authenticated.put(
"/org/:orgId/site",

View file

@ -22,6 +22,7 @@ export function InvitationsDataTable<TData, TValue>({
<DataTable
columns={columns}
data={data}
persistPageSize="invitations-table"
title={t('invite')}
searchPlaceholder={t('inviteSearch')}
searchColumn="email"

View file

@ -24,6 +24,7 @@ export function RolesDataTable<TData, TValue>({
<DataTable
columns={columns}
data={data}
persistPageSize="roles-table"
title={t('roles')}
searchPlaceholder={t('accessRolesSearch')}
searchColumn="name"

View file

@ -24,6 +24,7 @@ export function UsersDataTable<TData, TValue>({
<DataTable
columns={columns}
data={data}
persistPageSize="users-table"
title={t('users')}
searchPlaceholder={t('accessUsersSearch')}
searchColumn="email"

View file

@ -22,6 +22,7 @@ export function OrgApiKeysDataTable<TData, TValue>({
<DataTable
columns={columns}
data={data}
persistPageSize="Org-apikeys-table"
title={t('apiKeys')}
searchPlaceholder={t('searchApiKeys')}
searchColumn="name"

View file

@ -20,6 +20,7 @@ export function ClientsDataTable<TData, TValue>({
<DataTable
columns={columns}
data={data}
persistPageSize="clients-table"
title="Clients"
searchPlaceholder="Search clients..."
searchColumn="name"

View file

@ -25,6 +25,7 @@ export function DomainsDataTable<TData, TValue>({
<DataTable
columns={columns}
data={data}
persistPageSize="domains-table"
title={t("domains")}
searchPlaceholder={t("domainsSearch")}
searchColumn="baseDomain"

View file

@ -99,6 +99,43 @@ type ResourcesTableProps = {
defaultView?: "proxy" | "internal";
};
const STORAGE_KEYS = {
PAGE_SIZE: 'datatable-page-size',
getTablePageSize: (tableId?: string) =>
tableId ? `datatable-${tableId}-page-size` : STORAGE_KEYS.PAGE_SIZE
};
const getStoredPageSize = (tableId?: string, defaultSize = 20): number => {
if (typeof window === 'undefined') return defaultSize;
try {
const key = STORAGE_KEYS.getTablePageSize(tableId);
const stored = localStorage.getItem(key);
if (stored) {
const parsed = parseInt(stored, 10);
if (parsed > 0 && parsed <= 1000) {
return parsed;
}
}
} catch (error) {
console.warn('Failed to read page size from localStorage:', error);
}
return defaultSize;
};
const setStoredPageSize = (pageSize: number, tableId?: string): void => {
if (typeof window === 'undefined') return;
try {
const key = STORAGE_KEYS.getTablePageSize(tableId);
localStorage.setItem(key, pageSize.toString());
} catch (error) {
console.warn('Failed to save page size to localStorage:', error);
}
};
export default function ResourcesTable({
resources,
internalResources,
@ -113,6 +150,13 @@ export default function ResourcesTable({
const api = createApiClient({ env });
const [proxyPageSize, setProxyPageSize] = useState<number>(() =>
getStoredPageSize('proxy-resources', 20)
);
const [internalPageSize, setInternalPageSize] = useState<number>(() =>
getStoredPageSize('internal-resources', 20)
);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [selectedResource, setSelectedResource] =
useState<ResourceRow | null>();
@ -559,7 +603,7 @@ export default function ResourcesTable({
onGlobalFilterChange: setProxyGlobalFilter,
initialState: {
pagination: {
pageSize: 20,
pageSize: proxyPageSize,
pageIndex: 0
}
},
@ -582,7 +626,7 @@ export default function ResourcesTable({
onGlobalFilterChange: setInternalGlobalFilter,
initialState: {
pagination: {
pageSize: 20,
pageSize: internalPageSize,
pageIndex: 0
}
},
@ -593,6 +637,16 @@ export default function ResourcesTable({
}
});
const handleProxyPageSizeChange = (newPageSize: number) => {
setProxyPageSize(newPageSize);
setStoredPageSize(newPageSize, 'proxy-resources');
};
const handleInternalPageSizeChange = (newPageSize: number) => {
setInternalPageSize(newPageSize);
setStoredPageSize(newPageSize, 'internal-resources');
};
return (
<>
{selectedResource && (
@ -761,7 +815,10 @@ export default function ResourcesTable({
</TableBody>
</Table>
<div className="mt-4">
<DataTablePagination table={proxyTable} />
<DataTablePagination
table={proxyTable}
onPageSizeChange={handleProxyPageSizeChange}
/>
</div>
</TabsContent>
<TabsContent value="internal">
@ -861,6 +918,7 @@ export default function ResourcesTable({
<div className="mt-4">
<DataTablePagination
table={internalTable}
onPageSizeChange={handleInternalPageSizeChange}
/>
</div>
</TabsContent>

View file

@ -649,24 +649,33 @@ export default function ReverseProxyTargets(props: {
defaultValue={row.original.ip}
className="min-w-[150px]"
onBlur={(e) => {
const parsed = parseHostTarget(e.target.value);
if (parsed) {
updateTarget(row.original.targetId, {
...row.original,
method: parsed.protocol,
ip: parsed.host,
port: parsed.port
});
const input = e.target.value.trim();
const hasProtocol = /^(https?|h2c):\/\//.test(input);
const hasPort = /:\d+(?:\/|$)/.test(input);
if (hasProtocol || hasPort) {
const parsed = parseHostTarget(input);
if (parsed) {
updateTarget(row.original.targetId, {
...row.original,
method: hasProtocol ? parsed.protocol : row.original.method,
ip: parsed.host,
port: hasPort ? parsed.port : row.original.port
});
} else {
updateTarget(row.original.targetId, {
...row.original,
ip: input
});
}
} else {
updateTarget(row.original.targetId, {
...row.original,
ip: e.target.value
ip: input
});
}
}}
/>
)
},
{
@ -961,11 +970,21 @@ export default function ReverseProxyTargets(props: {
id="ip"
{...field}
onBlur={(e) => {
const parsed = parseHostTarget(e.target.value);
if (parsed) {
addTargetForm.setValue("method", parsed.protocol);
addTargetForm.setValue("ip", parsed.host);
addTargetForm.setValue("port", parsed.port);
const input = e.target.value.trim();
const hasProtocol = /^(https?|h2c):\/\//.test(input);
const hasPort = /:\d+(?:\/|$)/.test(input);
if (hasProtocol || hasPort) {
const parsed = parseHostTarget(input);
if (parsed) {
if (hasProtocol || !addTargetForm.getValues("method")) {
addTargetForm.setValue("method", parsed.protocol);
}
addTargetForm.setValue("ip", parsed.host);
if (hasPort || !addTargetForm.getValues("port")) {
addTargetForm.setValue("port", parsed.port);
}
}
} else {
field.onBlur();
}

View file

@ -24,6 +24,7 @@ export function ShareLinksDataTable<TData, TValue>({
<DataTable
columns={columns}
data={data}
persistPageSize="shareLinks-table"
title={t('shareLinks')}
searchPlaceholder={t('shareSearch')}
searchColumn="name"

View file

@ -26,6 +26,7 @@ export function SitesDataTable<TData, TValue>({
<DataTable
columns={columns}
data={data}
persistPageSize="sites-table"
title={t('sites')}
searchPlaceholder={t('searchSitesProgress')}
searchColumn="name"

View file

@ -47,6 +47,7 @@ export function ApiKeysDataTable<TData, TValue>({
<DataTable
columns={columns}
data={data}
persistPageSize="apiKeys-table"
title={t('apiKeys')}
searchPlaceholder={t('searchApiKeys')}
searchColumn="name"

View file

@ -21,6 +21,7 @@ export function IdpDataTable<TData, TValue>({
<DataTable
columns={columns}
data={data}
persistPageSize="idp-table"
title={t('idp')}
searchPlaceholder={t('idpSearch')}
searchColumn="name"

View file

@ -22,6 +22,7 @@ export function PolicyDataTable<TData, TValue>({
<DataTable
columns={columns}
data={data}
persistPageSize="orgPolicies-table"
title={t('orgPolicies')}
searchPlaceholder={t('orgPoliciesSearch')}
searchColumn="orgId"

View file

@ -22,6 +22,7 @@ export function UsersDataTable<TData, TValue>({
<DataTable
columns={columns}
data={data}
persistPageSize="userServer-table"
title={t('userServer')}
searchPlaceholder={t('userSearch')}
searchColumn="email"

View file

@ -18,28 +18,38 @@ import { useTranslations } from "next-intl";
interface DataTablePaginationProps<TData> {
table: Table<TData>;
onPageSizeChange?: (pageSize: number) => void;
}
export function DataTablePagination<TData>({
table
table,
onPageSizeChange
}: DataTablePaginationProps<TData>) {
const t = useTranslations();
const handlePageSizeChange = (value: string) => {
const newPageSize = Number(value);
table.setPageSize(newPageSize);
// Call the callback if provided (for persistence)
if (onPageSizeChange) {
onPageSizeChange(newPageSize);
}
};
return (
<div className="flex items-center justify-between text-muted-foreground">
<div className="flex items-center space-x-2">
<Select
value={`${table.getState().pagination.pageSize}`}
onValueChange={(value) => {
table.setPageSize(Number(value));
}}
onValueChange={handlePageSizeChange}
>
<SelectTrigger className="h-8 w-[70px]">
<SelectValue
placeholder={table.getState().pagination.pageSize}
/>
</SelectTrigger>
<SelectContent side="top">
<SelectContent side="bottom">
{[10, 20, 30, 40, 50, 100].map((pageSize) => (
<SelectItem key={pageSize} value={`${pageSize}`}>
{pageSize}

View file

@ -20,7 +20,7 @@ import {
TableRow
} from "@/components/ui/table";
import { Button } from "@app/components/ui/button";
import { useState } from "react";
import { useEffect, useMemo, useState } from "react";
import { Input } from "@app/components/ui/input";
import { DataTablePagination } from "@app/components/DataTablePagination";
import { Plus, Search, RefreshCw } from "lucide-react";
@ -32,7 +32,42 @@ import {
} from "@app/components/ui/card";
import { Tabs, TabsList, TabsTrigger } from "@app/components/ui/tabs";
import { useTranslations } from "next-intl";
import { useMemo } from "react";
const STORAGE_KEYS = {
PAGE_SIZE: 'datatable-page-size',
getTablePageSize: (tableId?: string) =>
tableId ? `${tableId}-size` : STORAGE_KEYS.PAGE_SIZE
};
const getStoredPageSize = (tableId?: string, defaultSize = 20): number => {
if (typeof window === 'undefined') return defaultSize;
try {
const key = STORAGE_KEYS.getTablePageSize(tableId);
const stored = localStorage.getItem(key);
if (stored) {
const parsed = parseInt(stored, 10);
// Validate that it's a reasonable page size
if (parsed > 0 && parsed <= 1000) {
return parsed;
}
}
} catch (error) {
console.warn('Failed to read page size from localStorage:', error);
}
return defaultSize;
};
const setStoredPageSize = (pageSize: number, tableId?: string): void => {
if (typeof window === 'undefined') return;
try {
const key = STORAGE_KEYS.getTablePageSize(tableId);
localStorage.setItem(key, pageSize.toString());
} catch (error) {
console.warn('Failed to save page size to localStorage:', error);
}
};
type TabFilter = {
id: string;
@ -56,6 +91,8 @@ type DataTableProps<TData, TValue> = {
};
tabs?: TabFilter[];
defaultTab?: string;
persistPageSize?: boolean | string;
defaultPageSize?: number;
};
export function DataTable<TData, TValue>({
@ -70,8 +107,23 @@ export function DataTable<TData, TValue>({
searchColumn = "name",
defaultSort,
tabs,
defaultTab
defaultTab,
persistPageSize = false,
defaultPageSize = 20
}: DataTableProps<TData, TValue>) {
const t = useTranslations();
// Determine table identifier for storage
const tableId = typeof persistPageSize === 'string' ? persistPageSize : undefined;
// Initialize page size from storage or default
const [pageSize, setPageSize] = useState<number>(() => {
if (persistPageSize) {
return getStoredPageSize(tableId, defaultPageSize);
}
return defaultPageSize;
});
const [sorting, setSorting] = useState<SortingState>(
defaultSort ? [defaultSort] : []
);
@ -80,7 +132,6 @@ export function DataTable<TData, TValue>({
const [activeTab, setActiveTab] = useState<string>(
defaultTab || tabs?.[0]?.id || ""
);
const t = useTranslations();
// Apply tab filter to data
const filteredData = useMemo(() => {
@ -108,7 +159,7 @@ export function DataTable<TData, TValue>({
onGlobalFilterChange: setGlobalFilter,
initialState: {
pagination: {
pageSize: 20,
pageSize: pageSize,
pageIndex: 0
}
},
@ -119,12 +170,35 @@ export function DataTable<TData, TValue>({
}
});
useEffect(() => {
const currentPageSize = table.getState().pagination.pageSize;
if (currentPageSize !== pageSize) {
table.setPageSize(pageSize);
// Persist to localStorage if enabled
if (persistPageSize) {
setStoredPageSize(pageSize, tableId);
}
}
}, [pageSize, table, persistPageSize, tableId]);
const handleTabChange = (value: string) => {
setActiveTab(value);
// Reset to first page when changing tabs
table.setPageIndex(0);
};
// Enhanced pagination component that updates our local state
const handlePageSizeChange = (newPageSize: number) => {
setPageSize(newPageSize);
table.setPageSize(newPageSize);
// Persist immediately when changed
if (persistPageSize) {
setStoredPageSize(newPageSize, tableId);
}
};
return (
<div className="container mx-auto max-w-12xl">
<Card>
@ -235,7 +309,10 @@ export function DataTable<TData, TValue>({
</TableBody>
</Table>
<div className="mt-4">
<DataTablePagination table={table} />
<DataTablePagination
table={table}
onPageSizeChange={handlePageSizeChange}
/>
</div>
</CardContent>
</Card>

View file

@ -1,15 +1,29 @@
export function parseHostTarget(input: string) {
try {
const normalized = input.match(/^https?:\/\//) ? input : `http://${input}`;
const normalized = input.match(/^(https?|h2c):\/\//) ? input : `http://${input}`;
const url = new URL(normalized);
const protocol = url.protocol.replace(":", ""); // http | https
const protocol = url.protocol.replace(":", ""); // http | https | h2c
const host = url.hostname;
const port = url.port ? parseInt(url.port, 10) : protocol === "https" ? 443 : 80;
let defaultPort: number;
switch (protocol) {
case "https":
defaultPort = 443;
break;
case "h2c":
defaultPort = 80;
break;
default: // http
defaultPort = 80;
break;
}
const port = url.port ? parseInt(url.port, 10) : defaultPort;
return { protocol, host, port };
} catch {
return null;
}
}