Compare commits

...

33 Commits
s3 ... dev

Author SHA1 Message Date
miloschwartz
9fb677e952 allow editing self and owner user roles 2026-05-08 17:48:43 -07:00
Owen Schwartz
88d8414eb8 Merge pull request #3016 from fosrl/crowdin_dev
New Crowdin updates
2026-05-08 17:17:30 -07:00
Owen Schwartz
5f3fafb1b0 New translations en-us.json (Spanish)
[ci skip]
2026-05-08 17:16:31 -07:00
Owen Schwartz
de1338a8cd New translations en-us.json (Norwegian Bokmal)
[ci skip]
2026-05-08 17:16:29 -07:00
Owen Schwartz
0800aa2a61 New translations en-us.json (Chinese Simplified)
[ci skip]
2026-05-08 17:16:28 -07:00
Owen Schwartz
4959d66ac1 New translations en-us.json (Turkish)
[ci skip]
2026-05-08 17:16:26 -07:00
Owen Schwartz
9320df8be6 New translations en-us.json (Russian)
[ci skip]
2026-05-08 17:16:24 -07:00
Owen Schwartz
13ec6b6620 New translations en-us.json (Portuguese)
[ci skip]
2026-05-08 17:16:23 -07:00
Owen Schwartz
2ca3ef019c New translations en-us.json (Polish)
[ci skip]
2026-05-08 17:16:21 -07:00
Owen Schwartz
724e41a54f New translations en-us.json (Dutch)
[ci skip]
2026-05-08 17:16:19 -07:00
Owen Schwartz
ce5e62d216 New translations en-us.json (Korean)
[ci skip]
2026-05-08 17:16:17 -07:00
Owen Schwartz
874dc2b33e New translations en-us.json (Italian)
[ci skip]
2026-05-08 17:16:16 -07:00
Owen Schwartz
3b2622d590 New translations en-us.json (German)
[ci skip]
2026-05-08 17:16:14 -07:00
Owen Schwartz
c81d855741 New translations en-us.json (Czech)
[ci skip]
2026-05-08 17:16:12 -07:00
Owen Schwartz
3bce8d3596 New translations en-us.json (Bulgarian)
[ci skip]
2026-05-08 17:16:10 -07:00
Owen Schwartz
ee2a1e2bc3 New translations en-us.json (French)
[ci skip]
2026-05-08 17:16:09 -07:00
Owen Schwartz
a0f3ee74f9 New translations en-us.json (Spanish)
[ci skip]
2026-05-08 17:14:09 -07:00
Owen Schwartz
82a36fd632 New translations en-us.json (Norwegian Bokmal)
[ci skip]
2026-05-08 17:14:07 -07:00
Owen Schwartz
c5084137ab New translations en-us.json (Chinese Simplified)
[ci skip]
2026-05-08 17:14:06 -07:00
Owen Schwartz
65ec8da100 New translations en-us.json (Turkish)
[ci skip]
2026-05-08 17:14:04 -07:00
Owen Schwartz
e76e7581a5 New translations en-us.json (Russian)
[ci skip]
2026-05-08 17:14:02 -07:00
Owen Schwartz
a97a4b6ec1 New translations en-us.json (Portuguese)
[ci skip]
2026-05-08 17:14:00 -07:00
Owen Schwartz
e38bbde348 New translations en-us.json (Polish)
[ci skip]
2026-05-08 17:13:58 -07:00
Owen Schwartz
026260ddfb New translations en-us.json (Dutch)
[ci skip]
2026-05-08 17:13:57 -07:00
Owen Schwartz
97be5eb7d5 New translations en-us.json (Korean)
[ci skip]
2026-05-08 17:13:55 -07:00
Owen Schwartz
d7b96ba3f5 New translations en-us.json (Italian)
[ci skip]
2026-05-08 17:13:53 -07:00
Owen Schwartz
b42672530f New translations en-us.json (German)
[ci skip]
2026-05-08 17:13:51 -07:00
Owen Schwartz
b6b2dbd8ab New translations en-us.json (Czech)
[ci skip]
2026-05-08 17:13:50 -07:00
Owen Schwartz
975f3a01f5 New translations en-us.json (Bulgarian)
[ci skip]
2026-05-08 17:13:48 -07:00
Owen Schwartz
4de2dfff85 New translations en-us.json (French)
[ci skip]
2026-05-08 17:13:46 -07:00
Owen
27d230647f Merge branch 's3' into dev 2026-05-08 17:05:39 -07:00
Owen
114486608e Add client endpoint to network log 2026-05-08 17:04:58 -07:00
Owen Schwartz
451f3d24a8 New translations en-us.json (French)
[ci skip]
2026-05-06 17:13:33 -07:00
31 changed files with 609 additions and 144 deletions

View File

@@ -3062,7 +3062,7 @@
"streamingDatadogTitle": "Datadog",
"streamingDatadogDescription": "Пресочвайте събития директно към вашият акаунт в Datadog. Очаквайте скоро.",
"streamingTypePickerDescription": "Изберете вид на дестинацията, за да започнете.",
"streamingFailedToLoad": "Неуспешно зареждане на дестинации",
"streamingLastSyncError": "Възникна грешка при последната синхронизация",
"streamingUnexpectedError": "Възникна неочаквана грешка.",
"streamingFailedToUpdate": "Неуспешно актуализиране на дестинация",
"streamingDeletedSuccess": "Дестинацията беше изтрита успешно",
@@ -3079,7 +3079,34 @@
"S3DestEditTitle": "Редактиране на дестинацията",
"S3DestAddTitle": "Добавете S3 дестинация",
"S3DestEditDescription": "Актуализирайте конфигурацията за тази S3 дестинация за предаване на събития.",
"S3DestAddDescription": "Конфигурирайте нов крайна точка на S3, за да получавате събития на вашата организация.",
"S3DestAddDescription": "Конфигурирайте ново хранилище Amazon S3 (или съвместимо с S3), за да получавате събития на вашата организация.",
"s3DestTabSettings": "Настройки",
"s3DestTabFormat": "Формат",
"s3DestNameLabel": "Име",
"s3DestNamePlaceholder": "Моята S3 дестинация",
"s3DestAccessKeyIdLabel": "Идентификатор на достъп за AWS Key ID",
"s3DestSecretAccessKeyLabel": "Тайният ключ за достъп на AWS",
"s3DestSecretAccessKeyPlaceholder": "Вашият таен ключ за достъп за AWS",
"s3DestRegionLabel": "AWS Регион",
"s3DestBucketLabel": "Име на хранилище",
"s3DestPrefixLabel": "Префикс на ключ (по избор)",
"s3DestPrefixDescription": "По избор пътеводен префикс, добавен към всеки обектен ключ. Обектите се съхраняват в {prefix}/{logType}/{YYYY}/{MM}/{DD}/{filename}.",
"s3DestEndpointLabel": "Потребителски крайна точка (по избор)",
"s3DestEndpointDescription": "Заместете крайната точка на S3 за съвместимо с S3 хранилище като MinIO или Cloudflare R2. Оставете празно за стандартното AWS S3.",
"s3DestGzipLabel": "Gzip компресия",
"s3DestGzipDescription": "Компресирайте всеки качен обект с gzip. Намалява разходите за съхранение и размера на качването.",
"s3DestFormatTitle": "Формат на файл",
"s3DestFormatDescription": "Как събитията са сериализирани вътре във всеки качен обект.",
"s3DestFormatJsonArrayDescription": "Всеки обект е JSON масив от записи на събития. Съвместим с повечето аналитични инструменти.",
"s3DestFormatNdjsonDescription": "Всеки обект съдържа един JSON запис на ред (форматиран JSON с нов ред). Съвместим с Athena, BigQuery и Spark.",
"s3DestFormatCsvTitle": "CSV",
"s3DestFormatCsvDescription": "Всеки обект е RFC-4180 CSV файл с ред заглавие. Имената на колоните са извлечени от полетата на данните за събитията.",
"s3DestSaveChanges": "Запази промените",
"s3DestCreateDestination": "Създаване на дестинация",
"s3DestUpdatedSuccess": "Дестинацията е актуализирана успешно",
"s3DestCreatedSuccess": "Дестинацията е създадена успешно",
"s3DestUpdateFailed": "Неуспешно актуализиране на дестинацията",
"s3DestCreateFailed": "Неуспешно създаване на дестинация",
"datadogDestEditTitle": "Редактиране на дестинация",
"datadogDestAddTitle": "Добавяне на Datadog дестинация",
"datadogDestEditDescription": "Актуализирайте конфигурацията за тази Datadog дестинация за предаване на събития.",

View File

@@ -3062,7 +3062,7 @@
"streamingDatadogTitle": "Datadog",
"streamingDatadogDescription": "Přeposlat události přímo do vašeho účtu Datadog účtu. Brzy přijde.",
"streamingTypePickerDescription": "Vyberte cílový typ pro začátek.",
"streamingFailedToLoad": "Nepodařilo se načíst destinace",
"streamingLastSyncError": "Došlo k chybě při poslední synchronizaci",
"streamingUnexpectedError": "Došlo k neočekávané chybě.",
"streamingFailedToUpdate": "Nepodařilo se aktualizovat cíl",
"streamingDeletedSuccess": "Cíl byl úspěšně odstraněn",
@@ -3079,7 +3079,34 @@
"S3DestEditTitle": "Upravit cíl",
"S3DestAddTitle": "Přidat S3 cíl",
"S3DestEditDescription": "Aktualizujte konfiguraci tohoto S3 cíle pro streamování událostí.",
"S3DestAddDescription": "Konfigurujte nový S3 koncový bod pro přijímání událostí vaší organizace.",
"S3DestAddDescription": "Nakonfigurujte nový Amazon S3 (nebo S3-kompatibilní) bucket, aby přijímal události vaší organizace.",
"s3DestTabSettings": "Nastavení",
"s3DestTabFormat": "Formát",
"s3DestNameLabel": "Jméno",
"s3DestNamePlaceholder": "Moje cílové S3",
"s3DestAccessKeyIdLabel": "ID přístupového klíče AWS",
"s3DestSecretAccessKeyLabel": "Tajný přístupový klíč AWS",
"s3DestSecretAccessKeyPlaceholder": "Váš tajný přístupový klíč AWS",
"s3DestRegionLabel": "Oblast AWS",
"s3DestBucketLabel": "Název bucketu",
"s3DestPrefixLabel": "Předpona klíče (volitelné)",
"s3DestPrefixDescription": "Volitelná cesta předpony přidaná ke každému objektovému klíči. Objekty jsou uloženy na {prefix}/{logType}/{YYYY}/{MM}/{DD}/{filename}.",
"s3DestEndpointLabel": "Vlastní koncový bod (volitelné)",
"s3DestEndpointDescription": "Přepište koncový bod S3 pro S3-kompatibilní úložiště, jako je MinIO nebo Cloudflare R2. Nechte prázdné pro standardní AWS S3.",
"s3DestGzipLabel": "Komprese Gzip",
"s3DestGzipDescription": "Komprimujte každý nahraný objekt pomocí gzip. Snižuje náklady na uložení a velikost nahrávání.",
"s3DestFormatTitle": "Formát souboru",
"s3DestFormatDescription": "Jak jsou události serializovány v každém nahraném objektu.",
"s3DestFormatJsonArrayDescription": "Každý objekt je pole JSON záznamů událostí. Kompatibilní s většinou analytických nástrojů.",
"s3DestFormatNdjsonDescription": "Každý objekt obsahuje jeden JSON záznam na řádku (newline-delimited JSON). Kompatibilní s Athena, BigQuery a Spark.",
"s3DestFormatCsvTitle": "CSV",
"s3DestFormatCsvDescription": "Každý objekt je soubor CSV podle RFC-4180 s řádkem záhlaví. Názvy sloupců jsou odvozeny z polí dat událostí.",
"s3DestSaveChanges": "Uložit změny",
"s3DestCreateDestination": "Vytvořit destinaci",
"s3DestUpdatedSuccess": "Destinace úspěšně aktualizována",
"s3DestCreatedSuccess": "Destinace úspěšně vytvořena",
"s3DestUpdateFailed": "Aktualizace destinace se nezdařila",
"s3DestCreateFailed": "Vytvoření destinace se nezdařilo",
"datadogDestEditTitle": "Upravit cíl",
"datadogDestAddTitle": "Přidat Datadog cíl",
"datadogDestEditDescription": "Aktualizujte konfiguraci tohoto Datadog cíle pro streamování událostí.",

View File

@@ -3062,7 +3062,7 @@
"streamingDatadogTitle": "Datadog",
"streamingDatadogDescription": "Events direkt an Ihr Datadog Konto weiterleiten. Kommen Sie bald.",
"streamingTypePickerDescription": "Wählen Sie einen Zieltyp aus, um loszulegen.",
"streamingFailedToLoad": "Fehler beim Laden der Ziele",
"streamingLastSyncError": "Beim letzten Synchronisieren ist ein Fehler aufgetreten.",
"streamingUnexpectedError": "Ein unerwarteter Fehler ist aufgetreten.",
"streamingFailedToUpdate": "Fehler beim Aktualisieren des Ziels",
"streamingDeletedSuccess": "Ziel erfolgreich gelöscht",
@@ -3079,7 +3079,34 @@
"S3DestEditTitle": "Ziel bearbeiten",
"S3DestAddTitle": "S3-Ziel hinzufügen",
"S3DestEditDescription": "Konfiguration für dieses S3-Ereignis-Streamingziel aktualisieren.",
"S3DestAddDescription": "Neuen S3-Endpunkt konfigurieren, um die Ereignisse Ihrer Organisation zu erhalten.",
"S3DestAddDescription": "Konfigurieren Sie einen neuen Amazon S3 (oder S3-kompatiblen) Bucket, um die Ereignisse Ihrer Organisation zu empfangen.",
"s3DestTabSettings": "Einstellungen",
"s3DestTabFormat": "Format",
"s3DestNameLabel": "Name",
"s3DestNamePlaceholder": "Mein S3-Ziel",
"s3DestAccessKeyIdLabel": "AWS-Zugriffsschlüssel-ID",
"s3DestSecretAccessKeyLabel": "AWS-Geheimzugriffsschlüssel",
"s3DestSecretAccessKeyPlaceholder": "Ihr AWS-Geheimzugriffsschlüssel",
"s3DestRegionLabel": "AWS-Region",
"s3DestBucketLabel": "Bucket-Name",
"s3DestPrefixLabel": "Schlüssel-Präfix (optional)",
"s3DestPrefixDescription": "Optionales Pfadpräfix, das jedem Objektschlüssel vorangestellt wird. Objekte werden unter {prefix}/{logType}/{YYYY}/{MM}/{DD}/{filename} gespeichert.",
"s3DestEndpointLabel": "Benutzerdefinierter Endpunkt (optional)",
"s3DestEndpointDescription": "Überschreiben Sie den S3-Endpunkt für S3-kompatiblen Speicher wie MinIO oder Cloudflare R2. Lassen Sie das Feld leer für standardmäßiges AWS S3.",
"s3DestGzipLabel": "Gzip-Komprimierung",
"s3DestGzipDescription": "Jedes hochgeladene Objekt mit Gzip komprimieren. Reduziert die Speicherkosten und die Upload-Größe.",
"s3DestFormatTitle": "Dateiformat",
"s3DestFormatDescription": "Wie Ereignisse in jedem hochgeladenen Objekt serialisiert werden.",
"s3DestFormatJsonArrayDescription": "Jedes Objekt ist ein JSON-Array von Ereignisdaten. Kompatibel mit den meisten Analysetools.",
"s3DestFormatNdjsonDescription": "Jedes Objekt enthält einen JSON-Datensatz pro Zeile (newline-delimited JSON). Kompatibel mit Athena, BigQuery und Spark.",
"s3DestFormatCsvTitle": "CSV",
"s3DestFormatCsvDescription": "Jedes Objekt ist eine RFC-4180 CSV-Datei mit einer Kopfzeile. Spaltennamen werden aus den Ereignisdatenfeldern abgeleitet.",
"s3DestSaveChanges": "Änderungen speichern",
"s3DestCreateDestination": "Ziel erstellen",
"s3DestUpdatedSuccess": "Ziel erfolgreich aktualisiert",
"s3DestCreatedSuccess": "Ziel erfolgreich erstellt",
"s3DestUpdateFailed": "Fehler beim Aktualisieren des Ziels",
"s3DestCreateFailed": "Fehler beim Erstellen des Ziels",
"datadogDestEditTitle": "Ziel bearbeiten",
"datadogDestAddTitle": "Datadog-Ziel hinzufügen",
"datadogDestEditDescription": "Konfiguration für dieses Datadog-Ereignis-Streamingziel aktualisieren.",

View File

@@ -523,6 +523,12 @@
"userMessageOrgRemove": "Once removed, this user will no longer have access to the organization. You can always re-invite them later, but they will need to accept the invitation again.",
"userRemoveOrgConfirm": "Confirm Remove User",
"userRemoveOrg": "Remove User from Organization",
"userQuestionOrgRemoveSelf": "Are you sure you want to remove yourself from this organization?",
"userMessageOrgRemoveSelf": "You will lose access immediately. An administrator can invite you again later, but you will need to accept a new invitation.",
"userRemoveOrgConfirmSelf": "Confirm Remove Myself",
"userRemoveOrgSelf": "Remove yourself from the organization",
"userRemoveOrgSelfWarning": "You will lose access to this organization immediately.",
"userRemoveOrgConfirmPhraseSelf": "REMOVE MYSELF FROM ORG",
"users": "Users",
"accessRoleMember": "Member",
"accessRoleOwner": "Owner",
@@ -531,6 +537,11 @@
"emailInvalid": "Invalid email address",
"inviteValidityDuration": "Please select a duration",
"accessRoleSelectPlease": "Please select a role",
"removeOwnAdminRoleConfirmTitle": "Remove your administrator access?",
"removeOwnAdminRoleConfirmDescription": "You will no longer have administrator permissions in this organization after saving. Another administrator can restore access if needed.",
"removeOwnAdminRoleConfirmButton": "Remove My Administrator Access",
"removeOwnAdminRoleConfirmPhrase": "REMOVE MY ADMIN ACCESS",
"ownerMustRetainAdminRole": "The organization owner must keep at least one administrator role.",
"usernameRequired": "Username is required",
"idpSelectPlease": "Please select an identity provider",
"idpGenericOidc": "Generic OAuth2/OIDC provider.",

View File

@@ -3062,7 +3062,7 @@
"streamingDatadogTitle": "Datadog",
"streamingDatadogDescription": "Reenviar eventos directamente a tu cuenta de Datadog. Próximamente.",
"streamingTypePickerDescription": "Elija un tipo de destino para empezar.",
"streamingFailedToLoad": "Error al cargar destinos",
"streamingLastSyncError": "Ocurrió un error en la última sincronización.",
"streamingUnexpectedError": "Se ha producido un error inesperado.",
"streamingFailedToUpdate": "Error al actualizar destino",
"streamingDeletedSuccess": "Destino eliminado correctamente",
@@ -3079,7 +3079,34 @@
"S3DestEditTitle": "Editar destino",
"S3DestAddTitle": "Añadir destino S3",
"S3DestEditDescription": "Actualice la configuración para este destino de transmisión de eventos S3.",
"S3DestAddDescription": "Configure un nuevo punto final S3 para recibir los eventos de su organización.",
"S3DestAddDescription": "Configura un nuevo bucket de Amazon S3 (o compatible con S3) para recibir los eventos de tu organización.",
"s3DestTabSettings": "Ajustes",
"s3DestTabFormat": "Formato",
"s3DestNameLabel": "Nombre",
"s3DestNamePlaceholder": "Mi destino S3",
"s3DestAccessKeyIdLabel": "ID de clave de acceso de AWS",
"s3DestSecretAccessKeyLabel": "Clave de acceso secreta de AWS",
"s3DestSecretAccessKeyPlaceholder": "Tu clave de acceso secreta de AWS",
"s3DestRegionLabel": "Región de AWS",
"s3DestBucketLabel": "Nombre del bucket",
"s3DestPrefixLabel": "Prefijo clave (opcional)",
"s3DestPrefixDescription": "Prefijo de ruta opcional preanexado a cada clave de objeto. Los objetos se almacenan en {prefix}/{logType}/{YYYY}/{MM}/{DD}/{filename}.",
"s3DestEndpointLabel": "Punto final personalizado (opcional)",
"s3DestEndpointDescription": "Sobrescribe el punto final de S3 para almacenamiento compatible con S3 como MinIO o Cloudflare R2. Deja en blanco para el estándar AWS S3.",
"s3DestGzipLabel": "Compresión Gzip",
"s3DestGzipDescription": "Comprime cada objeto subido con gzip. Reduce costos de almacenamiento y tamaño de carga.",
"s3DestFormatTitle": "Formato de archivo",
"s3DestFormatDescription": "Cómo se serializan los eventos dentro de cada objeto cargado.",
"s3DestFormatJsonArrayDescription": "Cada objeto es un arreglo JSON de registros de eventos. Compatible con la mayoría de las herramientas de analítica.",
"s3DestFormatNdjsonDescription": "Cada objeto contiene un registro JSON por línea (JSON delimitado por nueva línea). Compatible con Athena, BigQuery y Spark.",
"s3DestFormatCsvTitle": "CSV",
"s3DestFormatCsvDescription": "Cada objeto es un archivo CSV conforme a RFC-4180 con una fila de encabezado. Los nombres de columna se derivan de los campos de datos del evento.",
"s3DestSaveChanges": "Guardar cambios",
"s3DestCreateDestination": "Crear destino",
"s3DestUpdatedSuccess": "Destino actualizado con éxito",
"s3DestCreatedSuccess": "Destino creado con éxito",
"s3DestUpdateFailed": "No se pudo actualizar el destino",
"s3DestCreateFailed": "No se pudo crear el destino",
"datadogDestEditTitle": "Editar destino",
"datadogDestAddTitle": "Añadir destino Datadog",
"datadogDestEditDescription": "Actualice la configuración para este destino de transmisión de eventos Datadog.",

View File

@@ -1356,7 +1356,7 @@
"sidebarSites": "Nœuds",
"sidebarApprovals": "Demandes d'approbation",
"sidebarResources": "Ressource",
"sidebarProxyResources": "Publiques",
"sidebarProxyResources": "Publique",
"sidebarClientResources": "Privé",
"sidebarAccessControl": "Contrôle d'accès",
"sidebarLogsAndAnalytics": "Journaux & Analytiques",
@@ -2458,8 +2458,8 @@
"manageUserDevicesDescription": "Voir et gérer les appareils que les utilisateurs utilisent pour se connecter en privé aux ressources",
"downloadClientBannerTitle": "Télécharger le client Pangolin",
"downloadClientBannerDescription": "Téléchargez le client Pangolin pour votre système afin de vous connecter au réseau Pangolin et accéder aux ressources de manière privée.",
"manageMachineClients": "Gérer les machines",
"manageMachineClientsDescription": "Créer et gérer les clients que les serveurs et systèmes utilisent pour se connecter en privé aux ressources",
"manageMachineClients": "Gérer les clients de la machine",
"manageMachineClientsDescription": "Créer et gérer des clients que les serveurs et les systèmes utilisent pour se connecter en privé aux ressources",
"machineClientsBannerTitle": "Serveurs & Systèmes automatisés",
"machineClientsBannerDescription": "Les clients de machine sont conçus pour les serveurs et les systèmes automatisés qui ne sont pas associés à un utilisateur spécifique. Ils s'authentifient avec un identifiant et une clé secrète, et peuvent être exécutés avec Pangolin CLI, Olm CLI ou Olm en tant que conteneur.",
"machineClientsBannerPangolinCLI": "Pangolin CLI",
@@ -3062,7 +3062,7 @@
"streamingDatadogTitle": "Datadog",
"streamingDatadogDescription": "Transférer des événements directement sur votre compte Datadog. Prochainement.",
"streamingTypePickerDescription": "Choisissez un type de destination pour commencer.",
"streamingFailedToLoad": "Impossible de charger les destinations",
"streamingLastSyncError": "Une erreur s'est produite lors de la dernière synchronisation",
"streamingUnexpectedError": "Une erreur inattendue s'est produite.",
"streamingFailedToUpdate": "Impossible de mettre à jour la destination",
"streamingDeletedSuccess": "Destination supprimée avec succès",
@@ -3079,7 +3079,34 @@
"S3DestEditTitle": "Modifier la destination",
"S3DestAddTitle": "Ajouter une destination S3",
"S3DestEditDescription": "Mettre à jour la configuration de cette destination de diffusion d'événements S3.",
"S3DestAddDescription": "Configurer un nouveau point de terminaison S3 pour recevoir les événements de votre organisation.",
"S3DestAddDescription": "Configurez un nouveau bucket Amazon S3 (ou compatible S3) pour recevoir les événements de votre organisation.",
"s3DestTabSettings": "Réglages",
"s3DestTabFormat": "Format",
"s3DestNameLabel": "Nom",
"s3DestNamePlaceholder": "Ma destination S3",
"s3DestAccessKeyIdLabel": "ID de clé d'accès AWS",
"s3DestSecretAccessKeyLabel": "Clé d'accès secrète AWS",
"s3DestSecretAccessKeyPlaceholder": "Votre clé d'accès secrète AWS",
"s3DestRegionLabel": "Région AWS",
"s3DestBucketLabel": "Nom du bucket",
"s3DestPrefixLabel": "Préfixe clé (facultatif)",
"s3DestPrefixDescription": "Préfixe de chemin facultatif préfixé à chaque clé d'objet. Les objets sont stockés à {prefix}/{logType}/{YYYY}/{MM}/{DD}/{filename}.",
"s3DestEndpointLabel": "Point de terminaison personnalisé (facultatif)",
"s3DestEndpointDescription": "Modifiez le point de terminaison S3 pour un stockage compatible S3 tel que MinIO ou Cloudflare R2. Laissez vide pour l'AWS S3 standard.",
"s3DestGzipLabel": "Compression Gzip",
"s3DestGzipDescription": "Compressez chaque objet téléchargé avec gzip. Réduit les coûts de stockage et la taille de téléchargement.",
"s3DestFormatTitle": "Format de fichier",
"s3DestFormatDescription": "Comment les événements sont sérialisés dans chaque objet téléchargé.",
"s3DestFormatJsonArrayDescription": "Chaque objet est un tableau JSON des enregistrements d'événements. Compatible avec la plupart des outils d'analyse.",
"s3DestFormatNdjsonDescription": "Chaque objet contient un enregistrement JSON par ligne (JSON délimité par saut de ligne). Compatible avec Athena, BigQuery et Spark.",
"s3DestFormatCsvTitle": "CSV",
"s3DestFormatCsvDescription": "Chaque objet est un fichier CSV RFC-4180 avec une ligne d'en-tête. Les noms de colonne sont dérivés des champs de données de l'événement.",
"s3DestSaveChanges": "Enregistrer les modifications",
"s3DestCreateDestination": "Créer une destination",
"s3DestUpdatedSuccess": "Destination mise à jour avec succès",
"s3DestCreatedSuccess": "Destination créée avec succès",
"s3DestUpdateFailed": "Échec de la mise à jour de la destination",
"s3DestCreateFailed": "Échec de la création de la destination",
"datadogDestEditTitle": "Modifier la destination",
"datadogDestAddTitle": "Ajouter une destination Datadog",
"datadogDestEditDescription": "Mettre à jour la configuration de cette destination de diffusion d'événements Datadog.",
@@ -3154,7 +3181,6 @@
"healthCheckTabAdvanced": "Avancé",
"healthCheckStrategyNotAvailable": "Cette stratégie n'est pas disponible. Veuillez contacter le service commercial pour activer cette fonctionnalité.",
"uptime30d": "Disponibilité (30j)",
"uptimeNoData": "Aucune donnée",
"idpAddActionCreateNew": "Créer un nouveau fournisseur d'identité",
"idpAddActionImportFromOrg": "Importer d'une autre organisation",
"idpImportDialogTitle": "Importer le fournisseur d'identité",

View File

@@ -3062,7 +3062,7 @@
"streamingDatadogTitle": "Datadog",
"streamingDatadogDescription": "Inoltra gli eventi direttamente al tuo account Datadog. In arrivo.",
"streamingTypePickerDescription": "Scegli un tipo di destinazione per iniziare.",
"streamingFailedToLoad": "Impossibile caricare le destinazioni",
"streamingLastSyncError": "Si è verificato un errore durante l'ultima sincronizzazione",
"streamingUnexpectedError": "Si è verificato un errore imprevisto.",
"streamingFailedToUpdate": "Impossibile aggiornare la destinazione",
"streamingDeletedSuccess": "Destinazione eliminata con successo",
@@ -3079,7 +3079,34 @@
"S3DestEditTitle": "Modifica Destinazione",
"S3DestAddTitle": "Aggiungi Destinazione S3",
"S3DestEditDescription": "Aggiorna la configurazione per questa destinazione di streaming eventi S3.",
"S3DestAddDescription": "Configura un nuovo endpoint S3 per ricevere gli eventi della tua organizzazione.",
"S3DestAddDescription": "Configura un nuovo bucket Amazon S3 (o compatibile con S3) per ricevere gli eventi della tua organizzazione.",
"s3DestTabSettings": "Impostazioni",
"s3DestTabFormat": "Formato",
"s3DestNameLabel": "Nome",
"s3DestNamePlaceholder": "La mia destinazione S3",
"s3DestAccessKeyIdLabel": "ID Chiave Accesso AWS",
"s3DestSecretAccessKeyLabel": "Chiave Segreta Accesso AWS",
"s3DestSecretAccessKeyPlaceholder": "La tua chiave segreta di accesso AWS",
"s3DestRegionLabel": "Regione AWS",
"s3DestBucketLabel": "Nome Bucket",
"s3DestPrefixLabel": "Prefisso Chiave (facoltativo)",
"s3DestPrefixDescription": "Prefisso percorso facoltativo anteposto a ogni chiave oggetto. Gli oggetti vengono archiviati in {prefix}/{logType}/{YYYY}/{MM}/{DD}/{filename}.",
"s3DestEndpointLabel": "Endpoint personalizzato (facoltativo)",
"s3DestEndpointDescription": "Sostituisci l'endpoint S3 per lo storage compatibile con S3 come MinIO o Cloudflare R2. Lasciare vuoto per l'AWS S3 standard.",
"s3DestGzipLabel": "Compressione Gzip",
"s3DestGzipDescription": "Comprimi ogni oggetto caricato con gzip. Riduce i costi di archiviazione e la dimensione di caricamento.",
"s3DestFormatTitle": "Formato del File",
"s3DestFormatDescription": "Come gli eventi sono serializzati all'interno di ciascun oggetto caricato.",
"s3DestFormatJsonArrayDescription": "Ogni oggetto è un array JSON di record di eventi. Compatibile con la maggior parte degli strumenti analitici.",
"s3DestFormatNdjsonDescription": "Ogni oggetto contiene un record JSON per linea (JSON delimitato da newline). Compatibile con Athena, BigQuery e Spark.",
"s3DestFormatCsvTitle": "\"CSV\"",
"s3DestFormatCsvDescription": "Ogni oggetto è un file CSV RFC-4180 con una riga di intestazione. I nomi delle colonne sono derivati dai campi dei dati degli eventi.",
"s3DestSaveChanges": "Salva modifiche",
"s3DestCreateDestination": "Crea destinazione",
"s3DestUpdatedSuccess": "Destinazione aggiornata con successo",
"s3DestCreatedSuccess": "Destinazione creata con successo",
"s3DestUpdateFailed": "Aggiornamento della destinazione fallito",
"s3DestCreateFailed": "Creazione della destinazione fallita",
"datadogDestEditTitle": "Modifica Destinazione",
"datadogDestAddTitle": "Aggiungi Destinazione Datadog",
"datadogDestEditDescription": "Aggiorna la configurazione per questa destinazione di streaming eventi Datadog.",

View File

@@ -3062,7 +3062,7 @@
"streamingDatadogTitle": "데이터독",
"streamingDatadogDescription": "이벤트를 직접 Datadog 계정으로 전달합니다. 곧 제공됩니다.",
"streamingTypePickerDescription": "목표 유형을 선택하여 시작합니다.",
"streamingFailedToLoad": "대상 로드에 실패했습니다",
"streamingLastSyncError": "마지막 동기화에서 오류가 발생했습니다.",
"streamingUnexpectedError": "예기치 않은 오류가 발생했습니다.",
"streamingFailedToUpdate": "대상지를 업데이트하는 데 실패했습니다",
"streamingDeletedSuccess": "대상지가 성공적으로 삭제되었습니다",
@@ -3079,7 +3079,34 @@
"S3DestEditTitle": "대상지 수정",
"S3DestAddTitle": "S3 대상지 추가",
"S3DestEditDescription": "이 S3 이벤트 스트리밍 대상지의 구성을 업데이트하세요.",
"S3DestAddDescription": "조직의 이벤트를 받기 위한 새로운 S3 엔드포인트를 구성하세요.",
"S3DestAddDescription": "조직의 이벤트를 수신할 새로운 Amazon S3(또는 S3 호환) 버킷을 구성하세요.",
"s3DestTabSettings": "설정",
"s3DestTabFormat": "형식",
"s3DestNameLabel": "이름",
"s3DestNamePlaceholder": "내 S3 대상",
"s3DestAccessKeyIdLabel": "AWS 액세스 키 ID",
"s3DestSecretAccessKeyLabel": "AWS 비밀 액세스 키",
"s3DestSecretAccessKeyPlaceholder": "귀하의 AWS 비밀 액세스 키",
"s3DestRegionLabel": "AWS 지역",
"s3DestBucketLabel": "버킷 이름",
"s3DestPrefixLabel": "키 접두사(선택 사항)",
"s3DestPrefixDescription": "하나의 객체 키 앞에 붙이는 선택적 경로 접두사입니다. 객체는 {prefix}/{logType}/{YYYY}/{MM}/{DD}/{filename}에 저장됩니다.",
"s3DestEndpointLabel": "사용자 정의 엔드포인트(선택 사항)",
"s3DestEndpointDescription": "MinIO 또는 Cloudflare R2와 같은 S3 호환 저장소에 대한 S3 엔드포인트를 재정의합니다. 표준 AWS S3의 경우 비워 두십시오.",
"s3DestGzipLabel": "Gzip 압축",
"s3DestGzipDescription": "각 업로드된 객체를 gzip으로 압축합니다. 저장 비용과 업로드 크기를 줄입니다.",
"s3DestFormatTitle": "파일 형식",
"s3DestFormatDescription": "업로드된 각 객체 내에서 이벤트가 직렬화되는 방식입니다.",
"s3DestFormatJsonArrayDescription": "각 객체는 이벤트 기록의 JSON 배열입니다. 대부분의 분석 도구와 호환됩니다.",
"s3DestFormatNdjsonDescription": "각 객체는 한 줄당 하나의 JSON 레코드를 포함합니다(새 줄로 구분된 JSON). Athena, BigQuery, Spark와 호환됩니다.",
"s3DestFormatCsvTitle": "CSV",
"s3DestFormatCsvDescription": "각 객체는 헤더 행이 있는 RFC-4180 CSV 파일입니다. 열 이름은 이벤트 데이터 필드에서 파생됩니다.",
"s3DestSaveChanges": "변경 사항 저장",
"s3DestCreateDestination": "대상 생성",
"s3DestUpdatedSuccess": "대상이 성공적으로 업데이트되었습니다",
"s3DestCreatedSuccess": "대상이 성공적으로 생성되었습니다",
"s3DestUpdateFailed": "대상 업데이트에 실패했습니다",
"s3DestCreateFailed": "대상 생성에 실패했습니다",
"datadogDestEditTitle": "대상지 수정",
"datadogDestAddTitle": "Datadog 대상지 추가",
"datadogDestEditDescription": "이 Datadog 이벤트 스트리밍 대상지의 구성을 업데이트하세요.",

View File

@@ -3062,7 +3062,7 @@
"streamingDatadogTitle": "Datadog",
"streamingDatadogDescription": "Videresend arrangementer direkte til din Datadog-konto. Kommer snart.",
"streamingTypePickerDescription": "Velg en måltype for å komme i gang.",
"streamingFailedToLoad": "Kan ikke laste inn destinasjoner",
"streamingLastSyncError": "Det oppstod en feil under siste synkronisering",
"streamingUnexpectedError": "En uventet feil oppstod.",
"streamingFailedToUpdate": "Kunne ikke oppdatere destinasjon",
"streamingDeletedSuccess": "Målet ble slettet",
@@ -3079,7 +3079,34 @@
"S3DestEditTitle": "Rediger destinasjon",
"S3DestAddTitle": "Legg til S3 destinasjon",
"S3DestEditDescription": "Oppdatere konfigurasjonen for denne S3-hendelsesstrømmingsdestinasjonen.",
"S3DestAddDescription": "Konfigurer et nytt S3-endepunkt for å motta organisasjonens hendelser.",
"S3DestAddDescription": "Konfigurer en ny Amazon S3 (eller S3-kompatibel) bucket for å motta din organisasjons hendelser.",
"s3DestTabSettings": "Innstillinger",
"s3DestTabFormat": "Format",
"s3DestNameLabel": "Navn",
"s3DestNamePlaceholder": "Min S3-destinasjon",
"s3DestAccessKeyIdLabel": "AWS tilgangsnøkkel-ID",
"s3DestSecretAccessKeyLabel": "AWS hemmelige tilgangsnøkkel",
"s3DestSecretAccessKeyPlaceholder": "Din AWS secret access key",
"s3DestRegionLabel": "AWS-region",
"s3DestBucketLabel": "Bucket-navn",
"s3DestPrefixLabel": "Nøkkelprefiks (valgfritt)",
"s3DestPrefixDescription": "Valgfritt bane-prefiks lagt til hver objektnøkkel. Objekter er lagret på {prefix}/{logType}/{YYYY}/{MM}/{DD}/{filename}.",
"s3DestEndpointLabel": "Egendefinert endepunkt (valgfritt)",
"s3DestEndpointDescription": "Overstyr S3-endepunktet for S3-kompatibel lagring som MinIO eller Cloudflare R2. La stå tomt for standard AWS S3.",
"s3DestGzipLabel": "Gzip-komprimering",
"s3DestGzipDescription": "Komprimer hvert opplastede objekt med gzip. Reduserer lagringskostnader og opplastingsstørrelse.",
"s3DestFormatTitle": "Filformat",
"s3DestFormatDescription": "Hvordan hendelser er serialisert inni hvert opplastede objekt.",
"s3DestFormatJsonArrayDescription": "Hvert objekt er et JSON-array av hendelsesposter. Kompatibel med de fleste analyseverktøy.",
"s3DestFormatNdjsonDescription": "Hvert objekt inneholder en JSON-post per linje (nylinje-delt JSON). Kompatibel med Athena, BigQuery, og Spark.",
"s3DestFormatCsvTitle": "CSV",
"s3DestFormatCsvDescription": "Hvert objekt er en RFC-4180 CSV-fil med en overskriftsrad. Kolonnenavn er avledet fra hendelsesdatafeltene.",
"s3DestSaveChanges": "Lagre endringer",
"s3DestCreateDestination": "Opprett destinasjon",
"s3DestUpdatedSuccess": "Destinasjon oppdatert vellykket",
"s3DestCreatedSuccess": "Destinasjon opprettet vellykket",
"s3DestUpdateFailed": "Kunne ikke oppdatere destinasjon",
"s3DestCreateFailed": "Kunne ikke opprette destinasjon",
"datadogDestEditTitle": "Rediger destinasjon",
"datadogDestAddTitle": "Legg til Datadog destinasjon",
"datadogDestEditDescription": "Oppdatere konfigurasjonen for denne Datadog-hendelsesstrømmingsdestinasjonen.",
@@ -3174,7 +3201,7 @@
"publicIpEndpoint": "Endepunkt",
"lastTriggeredAt": "Siste utløste",
"reject": "Avvis",
"uptimeDaysAgo": "{count} days ago",
"uptimeDaysAgo": "{count} dager siden",
"uptimeToday": "I dag",
"uptimeNoDataAvailable": "Ingen data tilgjengelig",
"uptimeSuffix": "oppetid",

View File

@@ -3062,7 +3062,7 @@
"streamingDatadogTitle": "Datadog",
"streamingDatadogDescription": "Stuur gebeurtenissen rechtstreeks door naar je Datadog account. Binnenkort beschikbaar.",
"streamingTypePickerDescription": "Kies een bestemmingstype om te beginnen.",
"streamingFailedToLoad": "Laden van bestemmingen mislukt",
"streamingLastSyncError": "Er is een fout opgetreden bij de laatste synchronisatie",
"streamingUnexpectedError": "Er is een onverwachte fout opgetreden.",
"streamingFailedToUpdate": "Bijwerken bestemming mislukt",
"streamingDeletedSuccess": "Bestemming succesvol verwijderd",
@@ -3079,7 +3079,34 @@
"S3DestEditTitle": "Bestemming bewerken",
"S3DestAddTitle": "S3-bestemming toevoegen",
"S3DestEditDescription": "Werk de configuratie bij voor deze S3-gebeurtenisstreamingbestemming.",
"S3DestAddDescription": "Configureer een nieuw S3-eindpunt om de gebeurtenissen van uw organisatie te ontvangen.",
"S3DestAddDescription": "Configureer een nieuwe Amazon S3 (of S3-compatibele) bucket om de gebeurtenissen van uw organisatie te ontvangen.",
"s3DestTabSettings": "Instellingen",
"s3DestTabFormat": "Formaat",
"s3DestNameLabel": "Naam",
"s3DestNamePlaceholder": "Mijn S3-bestemming",
"s3DestAccessKeyIdLabel": "AWS-toegangssleutel-ID",
"s3DestSecretAccessKeyLabel": "AWS Geheime Toegangssleutel",
"s3DestSecretAccessKeyPlaceholder": "Uw AWS geheime toegangssleutel",
"s3DestRegionLabel": "AWS-regio",
"s3DestBucketLabel": "Bucketnaam",
"s3DestPrefixLabel": "Sleutelvoorvoegsel (optioneel)",
"s3DestPrefixDescription": "Optioneel padvoorvoegsel dat aan elke object sleutel wordt toegevoegd. Objecten worden opgeslagen op {prefix}/{logType}/{YYYY}/{MM}/{DD}/{filename}.",
"s3DestEndpointLabel": "Aangepast Eindpunt (optioneel)",
"s3DestEndpointDescription": "Overschrijf het S3-eindpunt voor S3-compatibele opslag zoals MinIO of Cloudflare R2. Laat leeg voor standaard AWS S3.",
"s3DestGzipLabel": "Gzip-compressie",
"s3DestGzipDescription": "Comprimeer elk geüpload object met gzip. Verlaagt opslagkosten en uploadgrootte.",
"s3DestFormatTitle": "Bestandsformaat",
"s3DestFormatDescription": "Hoe gebeurtenissen binnen elk geüpload object worden geserialiseerd.",
"s3DestFormatJsonArrayDescription": "Elk object is een JSON-array van gebeurtenisrecords. Compatibel met de meeste analysetools.",
"s3DestFormatNdjsonDescription": "Elk object bevat één JSON-record per regel (nieuwregel-gescheiden JSON). Compatibel met Athena, BigQuery en Spark.",
"s3DestFormatCsvTitle": "CSV",
"s3DestFormatCsvDescription": "Elk object is een RFC-4180 CSV-bestand met een kopregel. Kolomnamen zijn afgeleid van de gebeurtenis gegevensvelden.",
"s3DestSaveChanges": "Wijzigingen opslaan",
"s3DestCreateDestination": "Bestemming maken",
"s3DestUpdatedSuccess": "Bestemming succesvol bijgewerkt",
"s3DestCreatedSuccess": "Bestemming succesvol gecreëerd",
"s3DestUpdateFailed": "Bijwerken bestemming mislukt",
"s3DestCreateFailed": "Aanmaken bestemming mislukt",
"datadogDestEditTitle": "Bestemming bewerken",
"datadogDestAddTitle": "Datadog-bestemming toevoegen",
"datadogDestEditDescription": "Werk de configuratie bij voor deze Datadog-gebeurtenisstreamingbestemming.",

View File

@@ -3062,7 +3062,7 @@
"streamingDatadogTitle": "Datadog",
"streamingDatadogDescription": "Przekaż wydarzenia bezpośrednio do Twojego konta Datadog. Już wkrótce.",
"streamingTypePickerDescription": "Wybierz typ docelowy, aby rozpocząć.",
"streamingFailedToLoad": "Nie udało się załadować miejsc docelowych",
"streamingLastSyncError": "Wystąpił błąd podczas ostatniej synchronizacji",
"streamingUnexpectedError": "Wystąpił nieoczekiwany błąd.",
"streamingFailedToUpdate": "Nie udało się zaktualizować miejsca docelowego",
"streamingDeletedSuccess": "Cel usunięty pomyślnie",
@@ -3079,7 +3079,34 @@
"S3DestEditTitle": "Edytuj Miejsce Docelowe",
"S3DestAddTitle": "Dodaj Miejsce Docelowe S3",
"S3DestEditDescription": "Zaktualizuj konfigurację dla tego miejsca docelowego strumieniowego zdarzeń S3.",
"S3DestAddDescription": "Skonfiguruj nowy punkt końcowy S3, aby odbierać zdarzenia Twojej organizacji.",
"S3DestAddDescription": "Skonfiguruj nowy zasobnik Amazon S3 (lub zgodny z S3), aby otrzymywać zdarzenia twojej organizacji.",
"s3DestTabSettings": "Ustawienia",
"s3DestTabFormat": "Format",
"s3DestNameLabel": "Nazwa",
"s3DestNamePlaceholder": "Moje miejsce docelowe S3",
"s3DestAccessKeyIdLabel": "AWS Access Key ID",
"s3DestSecretAccessKeyLabel": "AWS Secret Access Key",
"s3DestSecretAccessKeyPlaceholder": "Twój AWS Secret Access Key",
"s3DestRegionLabel": "Region AWS",
"s3DestBucketLabel": "Nazwa kubła",
"s3DestPrefixLabel": "Prefiks klucza (opcjonalnie)",
"s3DestPrefixDescription": "Opcjonalny prefiks ścieżki dołączony do każdego klucza obiektu. Obiekty są przechowywane w {prefix}/{logType}/{YYYY}/{MM}/{DD}/{filename}.",
"s3DestEndpointLabel": "Niestandardowy punkt końcowy (opcjonalnie)",
"s3DestEndpointDescription": "Nadpisz punkt końcowy S3 dla zgodnego przechowywania danych, takiego jak MinIO lub Cloudflare R2. Pozostaw puste dla standardowego AWS S3.",
"s3DestGzipLabel": "Kompresja Gzip",
"s3DestGzipDescription": "Skompresuj każdy przesłany obiekt za pomocą gzip. Zmniejsza koszty przechowywania i rozmiar przesyłu.",
"s3DestFormatTitle": "Format pliku",
"s3DestFormatDescription": "Jak zdarzenia są serializowane w każdym przesłanym obiekcie.",
"s3DestFormatJsonArrayDescription": "Każdy obiekt to tablica JSON z rekordami zdarzeń. Zgodne z większością narzędzi analitycznych.",
"s3DestFormatNdjsonDescription": "Każdy obiekt zawiera jeden rekord JSON na linię (nowa linia-dzielone JSON). Zgodne z Athena, BigQuery i Spark.",
"s3DestFormatCsvTitle": "CSV",
"s3DestFormatCsvDescription": "Każdy obiekt to plik CSV zgodny z RFC-4180 z wierszem nagłówka. Nazwy kolumn pochodzą z pól danych zdarzeń.",
"s3DestSaveChanges": "Zapisz zmiany",
"s3DestCreateDestination": "Utwórz miejsce docelowe",
"s3DestUpdatedSuccess": "Miejsce docelowe zaktualizowane pomyślnie",
"s3DestCreatedSuccess": "Miejsce docelowe utworzone pomyślnie",
"s3DestUpdateFailed": "Nie udało się zaktualizować miejsca docelowego",
"s3DestCreateFailed": "Nie udało się utworzyć miejsca docelowego",
"datadogDestEditTitle": "Edytuj Miejsce Docelowe",
"datadogDestAddTitle": "Dodaj Miejsce Docelowe Datadog",
"datadogDestEditDescription": "Zaktualizuj konfigurację dla tego miejsca docelowego strumieniowego zdarzeń Datadog.",

View File

@@ -3062,7 +3062,7 @@
"streamingDatadogTitle": "Datadog",
"streamingDatadogDescription": "Encaminha eventos diretamente para a sua conta no Datadog. Em breve.",
"streamingTypePickerDescription": "Escolha um tipo de destino para começar.",
"streamingFailedToLoad": "Falha ao carregar destinos",
"streamingLastSyncError": "Ocorreu um erro na última sincronização",
"streamingUnexpectedError": "Ocorreu um erro inesperado.",
"streamingFailedToUpdate": "Falha ao atualizar destino",
"streamingDeletedSuccess": "Destino apagado com sucesso",
@@ -3079,7 +3079,34 @@
"S3DestEditTitle": "Editar Destino",
"S3DestAddTitle": "Adicionar Destino S3",
"S3DestEditDescription": "Atualize a configuração para este destino de streaming de eventos S3.",
"S3DestAddDescription": "Configure um novo endpoint S3 para receber os eventos da sua organização.",
"S3DestAddDescription": "Configure um novo bucket Amazon S3 (ou compatível com S3) para receber os eventos da sua organização.",
"s3DestTabSettings": "Configurações",
"s3DestTabFormat": "Formato",
"s3DestNameLabel": "Nome",
"s3DestNamePlaceholder": "Meu destino S3",
"s3DestAccessKeyIdLabel": "ID da Chave de Acesso AWS",
"s3DestSecretAccessKeyLabel": "Chave de Acesso Secreta AWS",
"s3DestSecretAccessKeyPlaceholder": "Sua chave de acesso secreta AWS",
"s3DestRegionLabel": "Região AWS",
"s3DestBucketLabel": "Nome do Bucket",
"s3DestPrefixLabel": "Prefixo da Chave (opcional)",
"s3DestPrefixDescription": "Prefixo de caminho opcional adicionado a cada chave de objeto. Os objetos são armazenados em {prefix}/{logType}/{YYYY}/{MM}/{DD}/{filename}.",
"s3DestEndpointLabel": "Endpoint Personalizado (opcional)",
"s3DestEndpointDescription": "Substitua o endpoint S3 por armazenamento compatível com S3, como MinIO ou Cloudflare R2. Deixe em branco para o padrão AWS S3.",
"s3DestGzipLabel": "Compressão Gzip",
"s3DestGzipDescription": "Comprime cada objeto carregado com gzip. Reduz custos de armazenamento e tamanho de upload.",
"s3DestFormatTitle": "Formato de Arquivo",
"s3DestFormatDescription": "Como os eventos são serializados dentro de cada objeto carregado.",
"s3DestFormatJsonArrayDescription": "Cada objeto é um array JSON de registros de eventos. Compatível com a maioria das ferramentas de análise.",
"s3DestFormatNdjsonDescription": "Cada objeto contém um registro JSON por linha (JSON delimitado por nova linha). Compatível com Athena, BigQuery e Spark.",
"s3DestFormatCsvTitle": "CSV",
"s3DestFormatCsvDescription": "Cada objeto é um arquivo CSV RFC-4180 com uma linha de cabeçalho. Nomes de colunas são derivados dos campos de dados do evento.",
"s3DestSaveChanges": "Salvar Alterações",
"s3DestCreateDestination": "Criar Destino",
"s3DestUpdatedSuccess": "Destino atualizado com sucesso",
"s3DestCreatedSuccess": "Destino criado com sucesso",
"s3DestUpdateFailed": "Falha ao atualizar destino",
"s3DestCreateFailed": "Falha ao criar destino",
"datadogDestEditTitle": "Editar Destino",
"datadogDestAddTitle": "Adicionar Destino Datadog",
"datadogDestEditDescription": "Atualize a configuração para este destino de streaming de eventos Datadog.",

View File

@@ -3062,7 +3062,7 @@
"streamingDatadogTitle": "Datadog",
"streamingDatadogDescription": "Перенаправлять события непосредственно на ваш аккаунт в Datadog. Скоро будет доступно.",
"streamingTypePickerDescription": "Выберите тип назначения, чтобы начать.",
"streamingFailedToLoad": "Не удалось загрузить места назначения",
"streamingLastSyncError": "Во время последней синхронизации произошла ошибка",
"streamingUnexpectedError": "Произошла непредвиденная ошибка.",
"streamingFailedToUpdate": "Не удалось обновить место назначения",
"streamingDeletedSuccess": "Адрес назначения успешно удален",
@@ -3079,7 +3079,34 @@
"S3DestEditTitle": "Редактировать пункт назначения",
"S3DestAddTitle": "Добавить S3 пункт назначения",
"S3DestEditDescription": "Обновите конфигурацию для этого S3 пункта назначения потоковых событий.",
"S3DestAddDescription": "Настройте новую S3 конечную точку для получения событий вашей организации.",
"S3DestAddDescription": "Настройте новый Amazon S3 (или совместимое S3) хранилище для получения событий вашей организации.",
"s3DestTabSettings": "Настройки",
"s3DestTabFormat": "Формат",
"s3DestNameLabel": "Имя",
"s3DestNamePlaceholder": "Моя S3 конечная точка",
"s3DestAccessKeyIdLabel": "Идентификатор ключа доступа AWS",
"s3DestSecretAccessKeyLabel": "Секретный ключ доступа AWS",
"s3DestSecretAccessKeyPlaceholder": "Ваш секретный ключ доступа AWS",
"s3DestRegionLabel": "Регион AWS",
"s3DestBucketLabel": "Имя хранилища",
"s3DestPrefixLabel": "Префикс ключа (по желанию)",
"s3DestPrefixDescription": "Необязательный префикс пути, добавляется к каждому ключу объекта. Объекты хранятся в {prefix}/{logType}/{YYYY}/{MM}/{DD}/{filename}.",
"s3DestEndpointLabel": "Пользовательская конечная точка (по желанию)",
"s3DestEndpointDescription": "Переопределите конечную точку S3 для совместимого хранилища, такого как MinIO или Cloudflare R2. Оставьте пустым для стандартного AWS S3.",
"s3DestGzipLabel": "Сжатие Gzip",
"s3DestGzipDescription": "Сжимайте каждый загруженный объект с помощью gzip. Уменьшает стоимость хранения и размер загрузки.",
"s3DestFormatTitle": "Формат файла",
"s3DestFormatDescription": "Как события сериализуются внутри каждого загруженного объекта.",
"s3DestFormatJsonArrayDescription": "Каждый объект — это JSON массив записей событий. Совместим с большинством аналитических инструментов.",
"s3DestFormatNdjsonDescription": "Каждый объект содержит одну запись JSON на строку (JSON, разделённый новой строкой). Совместим с Athena, BigQuery и Spark.",
"s3DestFormatCsvTitle": "CSV",
"s3DestFormatCsvDescription": "Каждый объект представляет собой CSV файл по стандарту RFC-4180 с заголовочной строкой. Имена столбцов выведены из полей данных событий.",
"s3DestSaveChanges": "Сохранить изменения",
"s3DestCreateDestination": "Создать конечную точку",
"s3DestUpdatedSuccess": "Конечная точка успешно обновлена",
"s3DestCreatedSuccess": "Конечная точка успешно создана",
"s3DestUpdateFailed": "Не удалось обновить конечную точку",
"s3DestCreateFailed": "Не удалось создать конечную точку",
"datadogDestEditTitle": "Редактировать пункт назначения",
"datadogDestAddTitle": "Добавить пункт назначения Datadog",
"datadogDestEditDescription": "Обновите конфигурацию для этого пункта назначения потоковых событий Datadog.",

View File

@@ -3062,7 +3062,7 @@
"streamingDatadogTitle": "Datadog",
"streamingDatadogDescription": "Olayları doğrudan Datadog hesabınıza iletin. Yakında gelicek.",
"streamingTypePickerDescription": "Başlamak için bir hedef türü seçin.",
"streamingFailedToLoad": "Hedefler yüklenemedi",
"streamingLastSyncError": "Son senkronizasyonda bir hata oluştu",
"streamingUnexpectedError": "Beklenmeyen bir hata oluştu.",
"streamingFailedToUpdate": "Hedef güncellenemedi",
"streamingDeletedSuccess": "Hedef başarıyla silindi",
@@ -3079,7 +3079,34 @@
"S3DestEditTitle": "Hedefi Düzenle",
"S3DestAddTitle": "S3 Hedefi Ekle",
"S3DestEditDescription": "Bu S3 olay akışı hedefi için yapılandırmayı güncelleyin.",
"S3DestAddDescription": "Kuruluşunuzun olaylarını almak için yeni bir S3 uç noktası yapılandırın.",
"S3DestAddDescription": "Kuruluşunuzun etkinliklerini almak için yeni bir Amazon S3 (veya S3-uyumlu) kovası yapılandırın.",
"s3DestTabSettings": "Ayarlar",
"s3DestTabFormat": "Biçim",
"s3DestNameLabel": "Ad",
"s3DestNamePlaceholder": "Benim S3 hedefim",
"s3DestAccessKeyIdLabel": "AWS Erişim Anahtar Kimliği",
"s3DestSecretAccessKeyLabel": "AWS Gizli Erişim Anahtarı",
"s3DestSecretAccessKeyPlaceholder": "AWS gizli erişim anahtarınız",
"s3DestRegionLabel": "AWS Bölgesi",
"s3DestBucketLabel": "Kova Adı",
"s3DestPrefixLabel": "Anahtar Ön Eki (isteğe bağlı)",
"s3DestPrefixDescription": "Her nesne anahtarının önüne eklenen isteğe bağlı yol öneki. Nesneler {prefix}/{logType}/{YYYY}/{MM}/{DD}/{filename} konumunda saklanır.",
"s3DestEndpointLabel": "Özel Uç Nokta (isteğe bağlı)",
"s3DestEndpointDescription": "MinIO veya Cloudflare R2 gibi S3-uyumlu depolama için S3 uç noktasını geçersiz kılın. Standart AWS S3 için boş bırakın.",
"s3DestGzipLabel": "Gzip sıkıştırması",
"s3DestGzipDescription": "Her yüklü nesneyi gzip ile sıkıştırın. Depolama maliyetlerini ve yükleme boyutunu azaltır.",
"s3DestFormatTitle": "Dosya Biçimi",
"s3DestFormatDescription": "Etkinliklerin her yüklendiği nesne içinde nasıl serileştirildiği.",
"s3DestFormatJsonArrayDescription": "Her nesne bir olay kayıtlarının JSON dizisidir. Çoğu analiz aracıyla uyumludur.",
"s3DestFormatNdjsonDescription": "Her nesne satır başına bir JSON kaydı içerir (yeni satır ile ayrılmış JSON). Athena, BigQuery ve Spark ile uyumludur.",
"s3DestFormatCsvTitle": "CSV",
"s3DestFormatCsvDescription": "Her nesne, bir başlık satırı ile birlikte RFC-4180 CSV dosyasıdır. Sütun isimleri olay verileri alanlarından türetilmiştir.",
"s3DestSaveChanges": "Değişiklikleri Kaydet",
"s3DestCreateDestination": "Hedef Oluştur",
"s3DestUpdatedSuccess": "Hedef başarıyla güncellendi",
"s3DestCreatedSuccess": "Hedef başarıyla oluşturuldu",
"s3DestUpdateFailed": "Hedef güncellenemedi",
"s3DestCreateFailed": "Hedef oluşturulamadı",
"datadogDestEditTitle": "Hedefi Düzenle",
"datadogDestAddTitle": "Datadog Hedefi Ekle",
"datadogDestEditDescription": "Bu Datadog olay akışı hedefi için yapılandırmayı güncelleyin.",

View File

@@ -3062,7 +3062,7 @@
"streamingDatadogTitle": "Datadog",
"streamingDatadogDescription": "直接转发事件到您的Datadog 帐户。即将推出。",
"streamingTypePickerDescription": "选择要开始的目标类型。",
"streamingFailedToLoad": "加载目的地失败",
"streamingLastSyncError": "最后一次同步时发生错误",
"streamingUnexpectedError": "发生意外错误.",
"streamingFailedToUpdate": "更新目标失败",
"streamingDeletedSuccess": "目标删除成功",
@@ -3079,7 +3079,34 @@
"S3DestEditTitle": "编辑目的地",
"S3DestAddTitle": "添加 S3 目的地",
"S3DestEditDescription": "更新此 S3 事件流目的地的配置。",
"S3DestAddDescription": "配置新的 S3 终端以接收您的组织事件。",
"S3DestAddDescription": "配置一个新的 Amazon S3或兼容 S3 的)存储桶以接收您的组织事件。",
"s3DestTabSettings": "设置",
"s3DestTabFormat": "格式",
"s3DestNameLabel": "名称",
"s3DestNamePlaceholder": "我的 S3 目的地",
"s3DestAccessKeyIdLabel": "AWS 访问密钥 ID",
"s3DestSecretAccessKeyLabel": "AWS 秘密访问密钥",
"s3DestSecretAccessKeyPlaceholder": "您的 AWS 密钥",
"s3DestRegionLabel": "AWS 地区",
"s3DestBucketLabel": "存储桶名称",
"s3DestPrefixLabel": "密钥前缀(可选)",
"s3DestPrefixDescription": "每个对象密钥前加的可选路径前缀。对象存储在 {prefix}/{logType}/{YYYY}/{MM}/{DD}/{filename}。",
"s3DestEndpointLabel": "自定义端点(可选)",
"s3DestEndpointDescription": "替代 S3 端点用于 MinIO 或 Cloudflare R2 等兼容 S3 的存储。标准 AWS S3 留空。",
"s3DestGzipLabel": "Gzip 压缩",
"s3DestGzipDescription": "使用 gzip 压缩每个上传的对象。减少存储成本和上传大小。",
"s3DestFormatTitle": "文件格式",
"s3DestFormatDescription": "事件在每个上传对象内的序列化方式。",
"s3DestFormatJsonArrayDescription": "每个对象是事件记录的 JSON 数组。兼容大多数分析工具。",
"s3DestFormatNdjsonDescription": "每个对象每行包含一个 JSON 记录(换行分隔的 JSON。兼容 Athena、BigQuery 和 Spark。",
"s3DestFormatCsvTitle": "CSV",
"s3DestFormatCsvDescription": "每个对象是带有标题行的 RFC-4180 CSV 文件。列名来自事件数据字段。",
"s3DestSaveChanges": "保存更改",
"s3DestCreateDestination": "创建目的地",
"s3DestUpdatedSuccess": "目的地更新成功",
"s3DestCreatedSuccess": "目的地创建成功",
"s3DestUpdateFailed": "更新目的地失败",
"s3DestCreateFailed": "创建目的地失败",
"datadogDestEditTitle": "编辑目的地",
"datadogDestAddTitle": "添加 Datadog 目的地",
"datadogDestEditDescription": "更新此 Datadog 事件流目的地的配置。",

View File

@@ -332,6 +332,7 @@ export const connectionAuditLog = pgTable(
clientId: integer("clientId").references(() => clients.clientId, {
onDelete: "cascade"
}),
clientEndpoint: text("clientEndpoint"),
userId: text("userId").references(() => users.userId, {
onDelete: "cascade"
}),

View File

@@ -332,6 +332,7 @@ export const connectionAuditLog = sqliteTable(
clientId: integer("clientId").references(() => clients.clientId, {
onDelete: "cascade"
}),
clientEndpoint: text("clientEndpoint"),
userId: text("userId").references(() => users.userId, {
onDelete: "cascade"
}),

View File

@@ -46,6 +46,7 @@ export interface ConnectionLogRecord {
orgId: string;
siteId: number;
clientId: number | null;
clientEndpoint: string | null;
userId: string | null;
sourceAddr: string;
destAddr: string;

View File

@@ -124,15 +124,11 @@ function getWhere(data: Q) {
data.clientId
? eq(connectionAuditLog.clientId, data.clientId)
: undefined,
data.siteId
? eq(connectionAuditLog.siteId, data.siteId)
: undefined,
data.siteId ? eq(connectionAuditLog.siteId, data.siteId) : undefined,
data.siteResourceId
? eq(connectionAuditLog.siteResourceId, data.siteResourceId)
: undefined,
data.userId
? eq(connectionAuditLog.userId, data.userId)
: undefined
data.userId ? eq(connectionAuditLog.userId, data.userId) : undefined
);
}
@@ -144,6 +140,7 @@ export function queryConnection(data: Q) {
orgId: connectionAuditLog.orgId,
siteId: connectionAuditLog.siteId,
clientId: connectionAuditLog.clientId,
clientEndpoint: connectionAuditLog.clientEndpoint,
userId: connectionAuditLog.userId,
sourceAddr: connectionAuditLog.sourceAddr,
destAddr: connectionAuditLog.destAddr,
@@ -203,10 +200,7 @@ async function enrichWithDetails(
];
// Fetch resource details from main database
const resourceMap = new Map<
number,
{ name: string; niceId: string }
>();
const resourceMap = new Map<number, { name: string; niceId: string }>();
if (siteResourceIds.length > 0) {
const resourceDetails = await primaryDb
.select({
@@ -268,10 +262,7 @@ async function enrichWithDetails(
}
// Fetch user details from main database
const userMap = new Map<
string,
{ email: string | null }
>();
const userMap = new Map<string, { email: string | null }>();
if (userIds.length > 0) {
const userDetails = await primaryDb
.select({
@@ -290,29 +281,25 @@ async function enrichWithDetails(
return logs.map((log) => ({
...log,
resourceName: log.siteResourceId
? resourceMap.get(log.siteResourceId)?.name ?? null
? (resourceMap.get(log.siteResourceId)?.name ?? null)
: null,
resourceNiceId: log.siteResourceId
? resourceMap.get(log.siteResourceId)?.niceId ?? null
: null,
siteName: log.siteId
? siteMap.get(log.siteId)?.name ?? null
? (resourceMap.get(log.siteResourceId)?.niceId ?? null)
: null,
siteName: log.siteId ? (siteMap.get(log.siteId)?.name ?? null) : null,
siteNiceId: log.siteId
? siteMap.get(log.siteId)?.niceId ?? null
? (siteMap.get(log.siteId)?.niceId ?? null)
: null,
clientName: log.clientId
? clientMap.get(log.clientId)?.name ?? null
? (clientMap.get(log.clientId)?.name ?? null)
: null,
clientNiceId: log.clientId
? clientMap.get(log.clientId)?.niceId ?? null
? (clientMap.get(log.clientId)?.niceId ?? null)
: null,
clientType: log.clientId
? clientMap.get(log.clientId)?.type ?? null
? (clientMap.get(log.clientId)?.type ?? null)
: null,
userEmail: log.userId
? userMap.get(log.userId)?.email ?? null
: null
userEmail: log.userId ? (userMap.get(log.userId)?.email ?? null) : null
}));
}
@@ -521,4 +508,4 @@ export async function queryConnectionAuditLogs(
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
);
}
}
}

View File

@@ -11,7 +11,7 @@
* This file is not licensed under the AGPLv3.
*/
import { db } from "@server/db";
import { clientSitesAssociationsCache, db } from "@server/db";
import { MessageHandler } from "@server/routers/ws";
import { sites, Newt, clients, orgs } from "@server/db";
import { and, eq, inArray } from "drizzle-orm";
@@ -146,7 +146,11 @@ export const handleConnectionLogMessage: MessageHandler = async (context) => {
// each unique sourceAddr + the org's CIDR suffix and do a targeted IN query.
const ipToClient = new Map<
string,
{ clientId: number; userId: string | null }
{
clientId: number;
userId: string | null;
clientEndpoint: string | null;
}
>();
if (cidrSuffix) {
@@ -172,9 +176,21 @@ export const handleConnectionLogMessage: MessageHandler = async (context) => {
.select({
clientId: clients.clientId,
userId: clients.userId,
subnet: clients.subnet
subnet: clients.subnet,
clientEndpoint: clientSitesAssociationsCache.endpoint
})
.from(clients)
.leftJoin(
// this should be one to one
clientSitesAssociationsCache,
and(
eq(
clients.clientId,
clientSitesAssociationsCache.clientId
),
eq(clientSitesAssociationsCache.siteId, newt.siteId)
)
)
.where(
and(
eq(clients.orgId, orgId),
@@ -189,7 +205,8 @@ export const handleConnectionLogMessage: MessageHandler = async (context) => {
);
ipToClient.set(ip, {
clientId: c.clientId,
userId: c.userId
userId: c.userId,
clientEndpoint: c.clientEndpoint
});
}
}
@@ -234,6 +251,7 @@ export const handleConnectionLogMessage: MessageHandler = async (context) => {
orgId,
siteId: newt.siteId,
clientId: clientInfo?.clientId ?? null,
clientEndpoint: clientInfo?.clientEndpoint ?? null,
userId: clientInfo?.userId ?? null,
sourceAddr: session.sourceAddr,
destAddr: session.destAddr,

View File

@@ -98,15 +98,6 @@ export async function addUserRole(
);
}
if (existingUser[0].isOwner) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
"Cannot change the role of the owner of the organization"
)
);
}
const roleExists = await db
.select()
.from(roles)

View File

@@ -98,11 +98,11 @@ export async function removeUserRole(
);
}
if (existingUser.isOwner) {
if (existingUser.isOwner && role.isAdmin === true) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
"Cannot change the roles of the owner of the organization"
"Cannot remove the administrator role from the organization owner"
)
);
}

View File

@@ -87,17 +87,8 @@ export async function setUserOrgRoles(
);
}
if (existingUser.isOwner) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
"Cannot change the roles of the owner of the organization"
)
);
}
const orgRoles = await db
.select({ roleId: roles.roleId })
.select({ roleId: roles.roleId, isAdmin: roles.isAdmin })
.from(roles)
.where(
and(
@@ -115,6 +106,18 @@ export async function setUserOrgRoles(
);
}
if (existingUser.isOwner) {
const hasAdminRole = orgRoles.some((r) => r.isAdmin === true);
if (!hasAdminRole) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
"The organization owner must retain an administrator role"
)
);
}
}
let orgClientsToRebuild: Client[] = [];
await db.transaction(async (trx) => {
await trx

View File

@@ -100,6 +100,7 @@ export type QueryConnectionAuditLogResponse = {
orgId: string | null;
siteId: number | null;
clientId: number | null;
clientEndpoint: string | null;
userId: string | null;
sourceAddr: string;
destAddr: string;

View File

@@ -88,11 +88,11 @@ export async function addUserRoleLegacy(
);
}
if (existingUser.isOwner) {
if (existingUser.isOwner && role.isAdmin !== true) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
"Cannot change the role of the owner of the organization"
"The organization owner must retain an administrator role"
)
);
}

View File

@@ -47,10 +47,7 @@ export async function queryUser(orgId: string, userId: string) {
.from(userOrgRoles)
.leftJoin(roles, eq(userOrgRoles.roleId, roles.roleId))
.where(
and(
eq(userOrgRoles.userId, userId),
eq(userOrgRoles.orgId, orgId)
)
and(eq(userOrgRoles.userId, userId), eq(userOrgRoles.orgId, orgId))
);
const isAdmin = roleRows.some((r) => r.isAdmin);
@@ -61,7 +58,8 @@ export async function queryUser(orgId: string, userId: string) {
roleIds: roleRows.map((r) => r.roleId),
roles: roleRows.map((r) => ({
roleId: r.roleId,
name: r.roleName ?? ""
name: r.roleName ?? "",
isAdmin: r.isAdmin === true
}))
};
}

View File

@@ -1,5 +1,6 @@
"use client";
import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
import IdpTypeBadge from "@app/components/IdpTypeBadge";
import OrgRolesTagField from "@app/components/OrgRolesTagField";
import {
@@ -25,6 +26,7 @@ import { useEnvContext } from "@app/hooks/useEnvContext";
import { userOrgUserContext } from "@app/hooks/useOrgUserContext";
import { usePaidStatus } from "@app/hooks/usePaidStatus";
import { toast } from "@app/hooks/useToast";
import { useUserContext } from "@app/hooks/useUserContext";
import { createApiClient, formatAxiosError } from "@app/lib/api";
import { zodResolver } from "@hookform/resolvers/zod";
import { build } from "@server/build";
@@ -32,7 +34,7 @@ import { tierMatrix } from "@server/lib/billing/tierMatrix";
import { UserType } from "@server/types/UserTypes";
import { useTranslations } from "next-intl";
import { useParams } from "next/navigation";
import { useActionState, useEffect } from "react";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
@@ -42,13 +44,15 @@ const accessControlsFormSchema = z.object({
roles: z.array(
z.object({
id: z.string(),
text: z.string()
text: z.string(),
isAdmin: z.boolean().optional()
})
)
});
export default function AccessControlsPage() {
const { orgUser: user, updateOrgUser } = userOrgUserContext();
const { user: sessionUser } = useUserContext();
const { env } = useEnvContext();
const api = createApiClient({ env });
@@ -72,7 +76,8 @@ export default function AccessControlsPage() {
autoProvisioned: user.autoProvisioned || false,
roles: (user.roles ?? []).map((r) => ({
id: r.roleId.toString(),
text: r.name
text: r.name,
isAdmin: r.isAdmin === true
}))
}
});
@@ -84,7 +89,8 @@ export default function AccessControlsPage() {
"roles",
(user.roles ?? []).map((r) => ({
id: r.roleId.toString(),
text: r.name
text: r.name,
isAdmin: r.isAdmin === true
}))
);
form.setValue("autoProvisioned", user.autoProvisioned || false);
@@ -95,11 +101,11 @@ export default function AccessControlsPage() {
? t("singleRolePerUserPlanNotice")
: t("singleRolePerUserEditionNotice");
const [, action, isSubmitting] = useActionState(onSubmit, null);
async function onSubmit() {
const isValid = await form.trigger();
if (!isValid) return;
const [isSaving, setIsSaving] = useState(false);
const [confirmRemoveOwnAdminOpen, setConfirmRemoveOwnAdminOpen] =
useState(false);
async function executeSave() {
const values = form.getValues();
if (values.roles.length === 0) {
@@ -111,6 +117,7 @@ export default function AccessControlsPage() {
return;
}
setIsSaving(true);
try {
const roleIds = values.roles.map((r) => parseInt(r.id, 10));
const updateRoleRequest = supportsMultipleRolesPerUser
@@ -130,7 +137,8 @@ export default function AccessControlsPage() {
roleIds,
roles: values.roles.map((r) => ({
roleId: parseInt(r.id, 10),
name: r.text
name: r.text,
isAdmin: r.isAdmin === true
})),
autoProvisioned: values.autoProvisioned
});
@@ -149,11 +157,61 @@ export default function AccessControlsPage() {
t("accessRoleErrorAddDescription")
)
});
} finally {
setIsSaving(false);
}
}
async function handleAccessControlsSubmit(e: React.FormEvent) {
e.preventDefault();
const isValid = await form.trigger();
if (!isValid) return;
const values = form.getValues();
if (values.roles.length === 0) {
toast({
variant: "destructive",
title: t("accessRoleErrorAdd"),
description: t("accessRoleSelectPlease")
});
return;
}
const willHaveAdminRole = values.roles.some(
(r) => r.isAdmin === true
);
const isRemovingOwnAdmin =
sessionUser.userId === user.userId &&
user.isAdmin &&
!willHaveAdminRole;
if (isRemovingOwnAdmin) {
setConfirmRemoveOwnAdminOpen(true);
return;
}
await executeSave();
}
return (
<SettingsContainer>
<ConfirmDeleteDialog
open={confirmRemoveOwnAdminOpen}
setOpen={setConfirmRemoveOwnAdminOpen}
title={t("removeOwnAdminRoleConfirmTitle")}
dialog={
<div className="space-y-2">
<p>{t("removeOwnAdminRoleConfirmDescription")}</p>
</div>
}
buttonText={t("removeOwnAdminRoleConfirmButton")}
string={t("removeOwnAdminRoleConfirmPhrase")}
onConfirm={executeSave}
/>
<SettingsSection>
<SettingsSectionHeader>
<SettingsSectionTitle>
@@ -168,7 +226,7 @@ export default function AccessControlsPage() {
<SettingsSectionForm>
<Form {...form}>
<form
action={action}
onSubmit={(e) => void handleAccessControlsSubmit(e)}
className="space-y-4"
id="access-controls-form"
>
@@ -237,8 +295,8 @@ export default function AccessControlsPage() {
<SettingsSectionFooter>
<Button
type="submit"
loading={isSubmitting}
disabled={isSubmitting}
loading={isSaving}
disabled={isSaving}
form="access-controls-form"
>
{t("accessControlsSubmit")}

View File

@@ -645,6 +645,12 @@ export default function ConnectionLogsPage() {
</span>
)}
</div>*/}
<div>
<strong>Client Endpoint:</strong>{" "}
<span className="font-mono">
{row.clientEndpoint ?? "-"}
</span>
</div>
<div>
<strong>Site:</strong> {row.siteName ?? "-"}
{row.siteNiceId && (

View File

@@ -99,6 +99,14 @@ export default function UsersTable({
];
}, [searchParams.toString()]);
const isRemovingSelf = useMemo(() => {
if (!selectedUser || !user) return false;
return (
`${selectedUser.username}-${selectedUser.idpId}` ===
`${user.username}-${user.idpId}`
);
}, [selectedUser, user]);
function handleFilterChange(
column: string,
value: string | undefined | null
@@ -223,10 +231,7 @@ export default function UsersTable({
header: () => <span className="p-3"></span>,
cell: ({ row }) => {
const userRow = row.original;
const isCurrentUser =
`${userRow.username}-${userRow.idpId}` ===
`${user?.username}-${user?.idpId}`;
const isDisabled = userRow.isOwner || isCurrentUser;
const canRemoveFromOrg = !userRow.isOwner;
return (
<div className="flex items-center justify-end">
<div>
@@ -235,7 +240,6 @@ export default function UsersTable({
<Button
variant="ghost"
className="h-8 w-8 p-0"
disabled={isDisabled}
>
<span className="sr-only">
{t("openMenu")}
@@ -247,16 +251,12 @@ export default function UsersTable({
<Link
href={`/${org?.org.orgId}/settings/access/users/${userRow.id}`}
className="block w-full"
aria-disabled={isDisabled}
onClick={(e) =>
isDisabled && e.preventDefault()
}
>
<DropdownMenuItem disabled={isDisabled}>
<DropdownMenuItem>
{t("accessUserManage")}
</DropdownMenuItem>
</Link>
{!isDisabled && (
{canRemoveFromOrg && (
<DropdownMenuItem
onClick={() => {
setIsDeleteModalOpen(true);
@@ -271,25 +271,14 @@ export default function UsersTable({
</DropdownMenuContent>
</DropdownMenu>
</div>
{isDisabled ? (
<Button
variant={"outline"}
className="ml-2"
disabled
>
<Link
href={`/${org?.org.orgId}/settings/access/users/${userRow.id}`}
>
<Button variant={"outline"} className="ml-2">
{t("manage")}
<ArrowRight className="ml-2 w-4 h-4" />
</Button>
) : (
<Link
href={`/${org?.org.orgId}/settings/access/users/${userRow.id}`}
>
<Button variant={"outline"} className="ml-2">
{t("manage")}
<ArrowRight className="ml-2 w-4 h-4" />
</Button>
</Link>
)}
</Link>
</div>
);
}
@@ -359,22 +348,45 @@ export default function UsersTable({
}}
dialog={
<div className="space-y-2">
<p>{t("userQuestionOrgRemove")}</p>
<p>{t("userMessageOrgRemove")}</p>
<p>
{t(
isRemovingSelf
? "userQuestionOrgRemoveSelf"
: "userQuestionOrgRemove"
)}
</p>
<p>
{t(
isRemovingSelf
? "userMessageOrgRemoveSelf"
: "userMessageOrgRemove"
)}
</p>
</div>
}
buttonText={t("userRemoveOrgConfirm")}
buttonText={t(
isRemovingSelf
? "userRemoveOrgConfirmSelf"
: "userRemoveOrgConfirm"
)}
warningText={
isRemovingSelf ? t("userRemoveOrgSelfWarning") : undefined
}
onConfirm={async () => startTransition(removeUser)}
string={
selectedUser
? getUserDisplayName({
email: selectedUser.email,
name: selectedUser.name,
username: selectedUser.username
})
: ""
isRemovingSelf
? t("userRemoveOrgConfirmPhraseSelf")
: selectedUser
? getUserDisplayName({
email: selectedUser.email,
name: selectedUser.name,
username: selectedUser.username
})
: ""
}
title={t("userRemoveOrg")}
title={t(
isRemovingSelf ? "userRemoveOrgSelf" : "userRemoveOrg"
)}
/>
<ControlledDataTable

View File

@@ -11,7 +11,7 @@ import { cn } from "@app/lib/cn";
import { CheckIcon } from "lucide-react";
import { useTranslations } from "next-intl";
export type TagValue = { text: string; id: string };
export type TagValue = { text: string; id: string; isAdmin?: boolean };
export type MultiSelectTagsProps<T extends TagValue> = {
emptyPlaceholder?: string;

View File

@@ -6,7 +6,7 @@ import { useDebounce } from "use-debounce";
import { useTranslations } from "next-intl";
import { MultiSelectTagInput } from "./multi-select/multi-select-tag-input";
export type SelectedRole = { id: string; text: string };
export type SelectedRole = { id: string; text: string; isAdmin?: boolean };
export type RolesSelectorProps = {
orgId: string;