commit d6fde78f8d4f7c7448cfea9d8387f588581c046e Author: Jonas Juselius Date: Mon Jul 4 10:47:36 2022 +0200 feat: initial commit diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7c54f64 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,3 @@ +FROM busybox + +COPY keycloak-themes/oceanbox /theme diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..48ba7a9 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +build: + docker build -t docker.io/juselius/oceanbox-theme:1.0 . diff --git a/keycloak-themes/base/account/account.ftl b/keycloak-themes/base/account/account.ftl new file mode 100644 index 0000000..9254b96 --- /dev/null +++ b/keycloak-themes/base/account/account.ftl @@ -0,0 +1,70 @@ +<#import "template.ftl" as layout> +<@layout.mainLayout active='account' bodyClass='user'; section> + +
+
+

${msg("editAccountHtmlTitle")}

+
+
+ * ${msg("requiredFields")} +
+
+ +
+ + + + <#if !realm.registrationEmailAsUsername> +
+
+ <#if realm.editUsernameAllowed>* +
+ +
+ disabled="disabled" value="${(account.username!'')}"/> +
+
+ + +
+
+ * +
+ +
+ +
+
+ +
+
+ * +
+ +
+ +
+
+ +
+
+ * +
+ +
+ +
+
+ +
+
+
+ <#if url.referrerURI??>${kcSanitize(msg("backToApplication")?no_esc)} + + +
+
+
+
+ + diff --git a/keycloak-themes/base/account/applications.ftl b/keycloak-themes/base/account/applications.ftl new file mode 100644 index 0000000..a8edc38 --- /dev/null +++ b/keycloak-themes/base/account/applications.ftl @@ -0,0 +1,76 @@ +<#import "template.ftl" as layout> +<@layout.mainLayout active='applications' bodyClass='applications'; section> + +
+
+

${msg("applicationsHtmlTitle")}

+
+
+ +
+ + + + + + + + + + + + + + + + <#list applications.applications as application> + + + + + + + + + + + + + +
${msg("application")}${msg("availableRoles")}${msg("grantedPermissions")}${msg("additionalGrants")}${msg("action")}
+ <#if application.effectiveUrl?has_content> + <#if application.client.name?has_content>${advancedMsg(application.client.name)}<#else>${application.client.clientId} + <#if application.effectiveUrl?has_content> + + <#list application.realmRolesAvailable as role> + <#if role.description??>${advancedMsg(role.description)}<#else>${advancedMsg(role.name)} + <#if role_has_next>, + + <#list application.resourceRolesAvailable?keys as resource> + <#if application.realmRolesAvailable?has_content>, + <#list application.resourceRolesAvailable[resource] as clientRole> + <#if clientRole.roleDescription??>${advancedMsg(clientRole.roleDescription)}<#else>${advancedMsg(clientRole.roleName)} + ${msg("inResource")} <#if clientRole.clientName??>${advancedMsg(clientRole.clientName)}<#else>${clientRole.clientId} + <#if clientRole_has_next>, + + + + <#if application.client.consentRequired> + <#list application.clientScopesGranted as claim> + ${advancedMsg(claim)}<#if claim_has_next>, + + <#else> + ${msg("fullAccess")} + + + <#list application.additionalGrants as grant> + ${advancedMsg(grant)}<#if grant_has_next>, + + + <#if (application.client.consentRequired && application.clientScopesGranted?has_content) || application.additionalGrants?has_content> + + +
+
+ + \ No newline at end of file diff --git a/keycloak-themes/base/account/federatedIdentity.ftl b/keycloak-themes/base/account/federatedIdentity.ftl new file mode 100644 index 0000000..c2eb769 --- /dev/null +++ b/keycloak-themes/base/account/federatedIdentity.ftl @@ -0,0 +1,42 @@ +<#import "template.ftl" as layout> +<@layout.mainLayout active='social' bodyClass='social'; section> + +
+
+

${msg("federatedIdentitiesHtmlTitle")}

+
+
+ +
+ <#list federatedIdentity.identities as identity> +
+
+ +
+
+ +
+
+ <#if identity.connected> + <#if federatedIdentity.removeLinkPossible> +
+ + + + +
+ + <#else> +
+ + + + +
+ +
+
+ +
+ + diff --git a/keycloak-themes/base/account/log.ftl b/keycloak-themes/base/account/log.ftl new file mode 100644 index 0000000..29046cf --- /dev/null +++ b/keycloak-themes/base/account/log.ftl @@ -0,0 +1,35 @@ +<#import "template.ftl" as layout> +<@layout.mainLayout active='log' bodyClass='log'; section> + +
+
+

${msg("accountLogHtmlTitle")}

+
+
+ + + + + + + + + + + + + + <#list log.events as event> + + + + + + + + + + +
${msg("date")}${msg("event")}${msg("ip")}${msg("client")}${msg("details")}
${event.date?datetime}${event.event}${event.ipAddress}${event.client!}<#list event.details as detail>${detail.key} = ${detail.value} <#if detail_has_next>,
+ + \ No newline at end of file diff --git a/keycloak-themes/base/account/messages/messages_ca.properties b/keycloak-themes/base/account/messages/messages_ca.properties new file mode 100644 index 0000000..a1b8f91 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_ca.properties @@ -0,0 +1,147 @@ +doSave=Desa +doCancel=Cancel\u00B7la +doLogOutAllSessions=Desconnecta de totes les sessions +doRemove=Elimina +doAdd=Afegeix +doSignOut=Desconnectar + +editAccountHtmlTitle=Edita compte +federatedIdentitiesHtmlTitle=Identitats federades +accountLogHtmlTitle=Registre del compte +changePasswordHtmlTitle=Canvia contrasenya +sessionsHtmlTitle=Sessions +accountManagementTitle=Gesti\u00F3 de Compte Keycloak +authenticatorTitle=Autenticador +applicationsHtmlTitle=Aplicacions + +authenticatorCode=Codi d''un sol \u00FAs +email=Email +firstName=Nom +givenName=Nom de pila +fullName=Nom complet +lastName=Cognoms +familyName=Cognom +password=Contrasenya +passwordConfirm=Confirma la contrasenya +passwordNew=Nova contrasenya +username=Usuari +address=Adre\u00E7a +street=Carrer +locality=Ciutat o Municipi +region=Estat, Prov\u00EDncia, o Regi\u00F3 +postal_code=Postal code +country=Pa\u00EDs +emailVerified=Email verificat +gssDelegationCredential=GSS Delegation Credential + +role_admin=Administrador +role_realm-admin=Administrador del domini +role_create-realm=Crear domini +role_view-realm=Veure domini +role_view-users=Veure usuaris +role_view-applications=Veure aplicacions +role_view-clients=Veure clients +role_view-events=Veure events +role_view-identity-providers=Veure prove\u00EFdors d''identitat +role_manage-realm=Gestionar domini +role_manage-users=Gestinar usuaris +role_manage-applications=Gestionar aplicacions +role_manage-identity-providers=Gestionar prove\u00EFdors d''identitat +role_manage-clients=Gestionar clients +role_manage-events=Gestionar events +role_view-profile=Veure perfil +role_manage-account=Gestionar compte +role_read-token=Llegir token +role_offline-access=Acc\u00E9s sense connexi\u00F3 +client_account=Compte +client_security-admin-console=Consola d''Administraci\u00F3 de Seguretat +client_realm-management=Gesti\u00F3 de domini +client_broker=Broker + + +requiredFields=Camps obligatoris +allFieldsRequired=Tots els camps obligatoris + +backToApplication=« Torna a l''aplicaci\u00F3 +backTo=Torna a {0} + +date=Data +event=Event +ip=IP +client=Client +clients=Clients +details=Detalls +started=Iniciat +lastAccess=\u00DAltim acc\u00E9s +expires=Expira +applications=Aplicacions + +account=Compte +federatedIdentity=Identitat federada +authenticator=Autenticador +sessions=Sessions +log=Registre + +application=Aplicaci\u00F3 +availablePermissions=Permisos disponibles +grantedPermissions=Permisos concedits +grantedPersonalInfo=Informaci\u00F3 personal concedida +additionalGrants=Permisos addicionals +action=Acci\u00F3 +inResource=a +fullAccess=Acc\u00E9s total +offlineToken=Codi d''autoritzaci\u00F3 offline +revoke=Revocar perm\u00EDs + +configureAuthenticators=Autenticadors configurats +mobile=M\u00F2bil +totpStep1=Instal\u00B7la FreeOTP o Google Authenticator al teu tel\u00E8fon m\u00F2bil. Les dues aplicacions estan disponibles a Google Play i en l''App Store d''Apple. +totpStep2=Obre l''aplicaci\u00F3 i escaneja el codi o introdueix la clau. +totpStep3=Introdueix el codi \u00FAnic que et mostra l''aplicaci\u00F3 d''autenticaci\u00F3 i fes clic a Envia per finalitzar la configuraci\u00F3 + +missingUsernameMessage=Si us plau indica el teu usuari. +missingFirstNameMessage=Si us plau indica el nom. +invalidEmailMessage=Email no v\u00E0lid +missingLastNameMessage=Si us plau indica els teus cognoms. +missingEmailMessage=Si us plau indica l''email. +missingPasswordMessage=Si us plau indica la contrasenya. +notMatchPasswordMessage=Les contrasenyes no coincideixen. + +missingTotpMessage=Si us plau indica el teu codi d''autenticaci\u00F3 +invalidPasswordExistingMessage=La contrasenya actual no \u00E9s correcta. +invalidPasswordConfirmMessage=La confirmaci\u00F3 de contrasenya no coincideix. +invalidTotpMessage=El c\u00F3digo de autenticaci\u00F3n no es v\u00E1lido. + +usernameExistsMessage=L''usuari ja existeix +emailExistsMessage=L''email ja existeix + +readOnlyUserMessage=No pots actualitzar el teu usuari perqu\u00E8 el teu compte \u00E9s de nom\u00E9s lectura. +readOnlyPasswordMessage=No pots actualitzar la contrasenya perqu\u00E8 el teu compte \u00E9s de nom\u00E9s lectura. + +successTotpMessage=Aplicaci\u00F3 d''autenticaci\u00F3 m\u00F2bil configurada. +successTotpRemovedMessage=Aplicaci\u00F3 d''autenticaci\u00F3 m\u00F2bil eliminada. + +successGrantRevokedMessage=Perm\u00EDs revocat correctament + +accountUpdatedMessage=El teu compte s''ha actualitzat. +accountPasswordUpdatedMessage=La contrasenya s''ha actualitzat. + +missingIdentityProviderMessage=Prove\u00EFdor d''identitat no indicat. +invalidFederatedIdentityActionMessage=Acci\u00F3 no v\u00E0lida o no indicada. +identityProviderNotFoundMessage=No s''ha trobat un prove\u00EFdor d''identitat. +federatedIdentityLinkNotActiveMessage=Aquesta identitat ja no est\u00E0 activa +federatedIdentityRemovingLastProviderMessage=No pots eliminar l''\u00FAltima identitat federada perqu\u00E8 no tens fixada una contrasenya. +identityProviderRedirectErrorMessage=Error en la redirecci\u00F3 al prove\u00EFdor d''identitat +identityProviderRemovedMessage=Prove\u00EFdor d''identitat esborrat correctament. + +accountDisabledMessage=El compte est\u00E0 desactivada, contacteu amb l''administrador. + +accountTemporarilyDisabledMessage=El compte est\u00E0 temporalment desactivat, contacta amb l''administrador o intenta-ho de nou m\u00E9s tard. +invalidPasswordMinLengthMessage=Contrasenya incorrecta: longitud m\u00EDnima {0}. +invalidPasswordMinLowerCaseCharsMessage=Contrasenya incorrecta: ha de contenir almenys {0} lletres min\u00FAscules. +invalidPasswordMinDigitsMessage=Contrase\u00F1a incorrecta: debe contener al menos {0} caracteres num\u00E9ricos. +invalidPasswordMinUpperCaseCharsMessage=Contrasenya incorrecta: ha de contenir almenys {0} lletres maj\u00FAscules. +invalidPasswordMinSpecialCharsMessage=Contrasenya incorrecta: ha de contenir almenys {0} car\u00E0cters especials. +invalidPasswordNotUsernameMessage=Contrasenya incorrecta: no pot ser igual al nom d''usuari. +invalidPasswordRegexPatternMessage=Contrasenya incorrecta: no compleix l''expressi\u00F3 regular. +invalidPasswordHistoryMessage=Contrasenya incorrecta: no pot ser igual a cap de les \u00FAltimes {0} contrasenyes. \ No newline at end of file diff --git a/keycloak-themes/base/account/messages/messages_cs.properties b/keycloak-themes/base/account/messages/messages_cs.properties new file mode 100644 index 0000000..a683032 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_cs.properties @@ -0,0 +1,171 @@ +# encoding: utf-8 +doSave=Uložit +doCancel=Zrušit +doLogOutAllSessions=Odhlásit všechny relace +doRemove=Odstranit +doAdd=Přidat +doSignOut=Odhlásit se + +editAccountHtmlTitle=Upravit účet +federatedIdentitiesHtmlTitle=Propojené identity +accountLogHtmlTitle=Log účtu +changePasswordHtmlTitle=Změnit heslo +sessionsHtmlTitle=Relace +accountManagementTitle=Správa účtů Keycloak +authenticatorTitle=Autentizátor +applicationsHtmlTitle=Aplikace + +authenticatorCode=Jednorázový kód +email=E-mail +firstName=První křestní jméno +givenName=Křestní jména +fullName=Celé jméno +lastName=Příjmení +familyName=Rodinné jméno +password=Heslo +passwordConfirm=Nové heslo (znovu) +passwordNew=Nové heslo +username=Uživatelské jméno +address=Adresa +street=Ulice +locality=Město nebo lokalita +region=Kraj +postal_code=PSČ +country=Stát +emailVerified=E-mail ověřen +gssDelegationCredential=GSS delegované oprávnění + +role_admin=Správce +role_realm-admin=Správce realmu +role_create-realm=Vytvořit realm +role_view-realm=Zobrazit realm +role_view-users=Zobrazit uživatele +role_view-applications=Zobrazit aplikace +role_view-clients=Zobrazit klienty +role_view-events=Zobrazit události +role_view-identity-providers=Zobrazit poskytovatele identity +role_manage-realm=Spravovat realm +role_manage-users=Spravovat uživatele +role_manage-applications=Spravovat aplikace +role_manage-identity-providers=Spravovat poskytovatele identity +role_manage-clients=Spravovat klienty +role_manage-events=Spravovat události +role_view-profile=Zobrazit profil +role_manage-account=Spravovat účet +role_manage-account-links=Spravovat odkazy na účet +role_read-token=Číst token +role_offline-access=Přístup offline +role_uma_authorization=Získání oprávnění +client_account=Účet +client_security-admin-console=Administrátorská bezpečnostní konzole +client_admin-cli=Administrátorské CLI +client_realm-management=Správa realmů +client_broker=Broker + + +requiredFields=Požadovaná pole +allFieldsRequired=Všechna pole vyžadovaná + +backToApplication=« Zpět na aplikaci +backTo=Zpět na {0} + +date=Datum +event=Událost +ip=IP +client=Klient +clients=Klienti +details=Podrobnosti +started=Zahájeno +lastAccess=Poslední přístup +expires=Vyprší +applications=Aplikace + +account=Účet +federatedIdentity=Propojená identita +authenticator=Autentizátor +sessions=Relace +log=Log + +application=Aplikace +availablePermissions=Dostupná oprávnění +grantedPermissions=Udělené oprávnění +grantedPersonalInfo=Poskytnuté osobní informace +additionalGrants=Dodatečné oprávnění +action=Akce +inResource=v +fullAccess=Úplný přístup +offlineToken=Offline Token +revoke=Zrušit oprávnění + +configureAuthenticators=Konfigurované autentizátory +mobile=Mobilní +totpStep1=Nainstalujte jednu z následujících aplikací +totpStep2=Otevřete aplikaci a naskenujte čárový kód +totpStep3=Zadejte jednorázový kód poskytnutý aplikací a klepnutím na tlačítko Uložit dokončete nastavení. + +totpManualStep2=Otevřete aplikaci a zadejte klíč +totpManualStep3=Použijte následující hodnoty konfigurace, pokud aplikace umožňuje jejich nastavení +totpUnableToScan=Nelze skenovat? +totpScanBarcode=Skenovat čárový kód? + +totp.totp=Založeno na čase +totp.hotp=Založeno na čítači + +totpType=Typ +totpAlgorithm=Algoritmus +totpDigits=Číslice +totpInterval=Interval +totpCounter=Čítač + +missingUsernameMessage=Zadejte uživatelské jméno. +missingFirstNameMessage=Zadejte prosím křestní jméno. +invalidEmailMessage=Neplatná e-mailová adresa. +missingLastNameMessage=Zadejte prosím příjmení. +missingEmailMessage=Zadejte prosím e-mail. +missingPasswordMessage=Zadejte prosím heslo. +notMatchPasswordMessage=Hesla se neshodují. + +missingTotpMessage=Zadejte prosím kód autentizátoru. +invalidPasswordExistingMessage=Neplatné stávající heslo. +invalidPasswordConfirmMessage=Nová hesla se neshodují. +invalidTotpMessage=Neplatný kód autentizátoru. + +usernameExistsMessage=Uživatelské jméno již existuje. +emailExistsMessage=E-mail již existuje. + +readOnlyUserMessage=Nemůžete svůj účet aktualizovat, protože je pouze pro čtení. +readOnlyUsernameMessage=Nemůžete aktualizovat své uživatelské jméno, protože je pouze pro čtení. +readOnlyPasswordMessage=Nemůžete aktualizovat své heslo, protože váš účet je jen pro čtení. + +successTotpMessage=Ověření pomocí OTP úspěšně konfigurováno. +successTotpRemovedMessage=Ověření pomocí OTP úspěšně odstraněno. + +successGrantRevokedMessage=Oprávnění bylo úspěšně zrušeno. + +accountUpdatedMessage=Váš účet byl aktualizován. +accountPasswordUpdatedMessage=Vaše heslo bylo aktualizováno. + +missingIdentityProviderMessage=Chybějící poskytovatel identity. +invalidFederatedIdentityActionMessage=Neplatná nebo chybějící akce. +identityProviderNotFoundMessage=Poskytovatel identity nenalezen. +federatedIdentityLinkNotActiveMessage=Tato identita již není aktivní. +federatedIdentityRemovingLastProviderMessage=Nemůžete odstranit poslední propojenou identitu, protože nemáte heslo. +identityProviderRedirectErrorMessage=Nepodařilo se přesměrovat na poskytovatele identity. +identityProviderRemovedMessage=Poskytovatel identity byl úspěšně odstraněn. +identityProviderAlreadyLinkedMessage=Propojená identita vrácená uživatelem {0} je již propojena s jiným uživatelem. +staleCodeAccountMessage=Platnost vypršela. Zkuste to ještě jednou. +consentDenied=Souhlas byl zamítnut. + +accountDisabledMessage=Účet je zakázán, kontaktujte správce. + +accountTemporarilyDisabledMessage=Účet je dočasně zakázán, kontaktujte správce nebo zkuste to později. +invalidPasswordMinLengthMessage=Neplatné heslo: musí obsahovat minimálně {0} malých znaků. +invalidPasswordMinLowerCaseCharsMessage=Neplatné heslo: musí obsahovat minimálně {0} malé znaky. +invalidPasswordMinDigitsMessage=Neplatné heslo: musí obsahovat nejméně {0} číslic. +invalidPasswordMinUpperCaseCharsMessage=Neplatné heslo: musí obsahovat nejméně {0} velkých písmenen. +invalidPasswordMinSpecialCharsMessage=Neplatné heslo: musí obsahovat nejméně {0} speciálních znaků. +invalidPasswordNotUsernameMessage=Neplatné heslo: nesmí být totožné s uživatelským jménem. +invalidPasswordRegexPatternMessage=Neplatné heslo: neshoduje se zadaným regulárním výrazem. +invalidPasswordHistoryMessage=Neplatné heslo: Nesmí se opakovat žádné z posledních {0} hesel. +invalidPasswordBlacklistedMessage=Neplatné heslo: heslo je na černé listině. +invalidPasswordGenericMessage=Neplatné heslo: nové heslo neodpovídá pravidlům hesla. \ No newline at end of file diff --git a/keycloak-themes/base/account/messages/messages_da.properties b/keycloak-themes/base/account/messages/messages_da.properties new file mode 100644 index 0000000..2533abf --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_da.properties @@ -0,0 +1,339 @@ +# encoding: UTF-8 +doSave=Gem +doCancel=Annuller +doLogOutAllSessions=Log alle sessioner ud +doRemove=Fjern +doAdd=Tilføj +doSignOut=Log Ud +doLogIn=Log Ind +doLink=Link + +editAccountHtmlTitle=Ændre Konto +personalInfoHtmlTitle=Personlig information +federatedIdentitiesHtmlTitle=Forbundne identiter +accountLogHtmlTitle=Konto Log +changePasswordHtmlTitle=Skift Adgangskode +deviceActivityHtmlTitle=Enheds aktivitet +sessionsHtmlTitle=Sessioner +accountManagementTitle=Keycloak Account Management +authenticatorTitle=Authenticator +applicationsHtmlTitle=Applikationer +linkedAccountsHtmlTitle=Linkede konti + +accountManagementWelcomeMessage=Velkommen til Keycloak Account Management +personalInfoIntroMessage=Administrer dine informationer +accountSecurityTitle=Kontosikkerhed +accountSecurityIntroMessage=Kontroller din adgangskode og kontoadgang. +applicationsIntroMessage=Spor og administrer dine app tilladelser for at tilgå din konto +resourceIntroMessage=Del dine ressourcer med team medlemmer +passwordLastUpdateMessage=Din adgangskode blev opdateret +updatePasswordTitle=Opdater Adgangskode +updatePasswordMessageTitle=Sørg for at vælge en stærk adgangskode +updatePasswordMessage=En stærk adgangskode indeholder en blanding af tal, bogstaver og symboler. Det er svært at gætte, ligner ikke et rigtigt ord og bør kun bruges til denne konto. +personalSubTitle=Dine Personlige Informationer +personalSubMessage=Administrer disse grundinformationer; dit fornavn, efternavn og email adresse + +authenticatorCode=Engangskode +email=Email +firstName=Fornavn +givenName=Fornavn +fullName=Fulde navn +lastName=Efternavn +familyName=Efternavn +password=Adgangskode +currentPassword=Nuværende Adgangskode +passwordConfirm=Bekræft ny adgangskode +passwordNew=Ny adgangskode +username=Brugernavn +address=Adresse +street=Vejnavn +locality=By +region=Region +postal_code=Postnummer +country=Land +emailVerified=Email verificeret +gssDelegationCredential=GSS Delegation Credential + +profileScopeConsentText=Brugerprofil +emailScopeConsentText=Email adresse +addressScopeConsentText=Adresse +phoneScopeConsentText=Telefonnummer +offlineAccessScopeConsentText=Offline Adgang +samlRoleListScopeConsentText=Mine Roller + +role_admin=Admin +role_realm-admin=Rige Admin +role_create-realm=Opret rige +role_create-client=Opret klient +role_view-realm=Se rige +role_view-users=Se brugere +role_view-applications=Se applikationer +role_view-clients=Se klienter +role_view-events=Se hændelser +role_view-identity-providers=Se identitetsudbydere +role_manage-realm=Administrer rige +role_manage-users=Administrer brugere +role_manage-applications=Administrer applikationer +role_manage-identity-providers=Administrer identitetsudbydere +role_manage-clients=Administrer klienter +role_manage-events=Administrer hændelser +role_view-profile=Se profil +role_manage-account=Administrer konto +role_manage-account-links=Administrer konto links +role_read-token=Se token +role_offline-access=Offline adgang +client_account=Konto +client_security-admin-console=Sikkerheds Admin Konsol +client_admin-cli=Admin CLI +client_realm-management=Rige administration +client_broker=Broker + + +requiredFields=Påkrævede felter +allFieldsRequired=Alle felter er påkrævede + +backToApplication=« Tilbage til applikation +backTo=Tilbage til {0} + +date=Dato +event=Hændelse +ip=IP +client=Klient +clients=Klienter +details=Detaljer +started=Påbegyndt +lastAccess=Seneste Adgang +expires=Udløber +applications=Applikationer + +account=Konto +federatedIdentity=Federated Identity +authenticator=Authenticator +device-activity=Enheds aktivitet +sessions=Sessioner +log=Log + +application=Applikation +availableRoles=Tilgængelige Roller +grantedPermissions=Tildelte Rettigheder +grantedPersonalInfo=Tildelt Personlig Info +additionalGrants=Yderligere Tildelinger +action=Action +inResource=i +fullAccess=Fuld adgang +offlineToken=Offline Token +revoke=Tilbagekald tildeling + +configureAuthenticators=Konfigurerede Authenticators +mobile=Mobil +totpStep1=Installer en af følgende applikationer på din mobil +totpStep2=Åben applikationen og skan stregkoden +totpStep3=Indtast engangskoden fra applikationen og tryk Indsend for at gennemføre opsætningen + +totpManualStep2=Åben applikationen og indtast nøglen +totpManualStep3=Brug følgende konfigurations værdier hvis applikationen tillader det + +totpUnableToScan=Kan du ikke skanne? +totpScanBarcode=Skan stregkode? + +totp.totp=Tidsbaseret +totp.hotp=Tællerbaseret + +totpType=Type +totpAlgorithm=Algoritme +totpDigits=Tal +totpInterval=Interval +totpCounter=Tæller + +missingUsernameMessage=Angiv brugernavn +missingFirstNameMessage=Angiv fornavn. +invalidEmailMessage=Ugyldig email adresse. +missingLastNameMessage=Angiv efternavn +missingEmailMessage=Angiv email adresse. +missingPasswordMessage=Angiv adgangskode +notMatchPasswordMessage=Adgangskoderne er ikke ens +invalidUserMessage=Ugyldig bruger + +missingTotpMessage=Angiv autentificerings kode. +invalidPasswordExistingMessage=Ugyldig eksisterende adgangskode. +invalidPasswordConfirmMessage=Adgangskoderne er ikke ens +invalidTotpMessage=Ugyldig autentificerings kode. + +usernameExistsMessage=Brugernavnet eksisterer allerede. +emailExistsMessage=Email adressen eksisterer allerede. + +readOnlyUserMessage=Du kan ikke opdatere din konto da den er read-only. +readOnlyUsernameMessage=Du kan ikke opdatere dit brugernavn da det er read-only. +readOnlyPasswordMessage=Du kan ikke opdatere din adgangskode da den er read-only. + +successTotpMessage=Mobil authenticator konfigureret. +successTotpRemovedMessage=Mobil authenticator fjernet. + +successGrantRevokedMessage=Tildeling tilbagekaldt. + +accountUpdatedMessage=Din konto er blevet opdateret. +accountPasswordUpdatedMessage=Din adgangskode er blevet opdateret. + +missingIdentityProviderMessage=Identitetsudbyder ikke specificeret. +invalidFederatedIdentityActionMessage=Ugyldig eller manglende handling. +identityProviderNotFoundMessage=Den angivede identitetsudbyder kunne ikke findes. +federatedIdentityLinkNotActiveMessage=Denne identiet er ikke aktiv længere. +identityProviderRedirectErrorMessage=Kunne ikke redirecte til identitetsudbyder. +identityProviderRemovedMessage=Identitetsudbyder fjernet. +identityProviderAlreadyLinkedMessage=Forbundsidentitet returneret af {} er allerede forbundet til en anden bruger. +staleCodeAccountMessage=Siden er udløbet. Prøv igen. +consentDenied=Samtykke afslået. + +accountDisabledMessage=Kontoen er deaktiveret, kontakt en administrator. + +accountTemporarilyDisabledMessage=Kontoen er midlertidigt deaktiveret, kontakt en administrator eller prøv igen senere. +invalidPasswordMinLengthMessage=Ugyldig adgangskode: minimum længde {0}. +invalidPasswordMinLowerCaseCharsMessage=Ugyldig adgangskode: skal minimum indeholde {0} små bogstaver. +invalidPasswordMinDigitsMessage=Ugyldig adgangskode: skal minimum indeholde {0} tal. +invalidPasswordMinUpperCaseCharsMessage=Ugyldig adgangskode: skal minimum indeholde {0} store bogstaver. +invalidPasswordMinSpecialCharsMessage=Ugyldig adgangskode: skal minimum indeholde {0} specialtegn. +invalidPasswordNotUsernameMessage=Ugyldig adgangskode: må ikke være identisk med brugernavnet. +invalidPasswordRegexPatternMessage=Ugyldig adgangskode: Ikke i stand til at matche regex mønstre. +invalidPasswordHistoryMessage=Ugyldig adgangskode: må ikke være identisk med nogle af de seneste {0} adgangskoder. +invalidPasswordBlacklistedMessage=Ugyldig adgangskode: adgangskoden er sortlisted. +invalidPasswordGenericMessage=Ugyldig adgangskode: ny adgangskode matcher ikke vores adgangskode politikker. + +# Authorization +myResources=Mine Ressourcer +myResourcesSub=Mine ressourcer +doDeny=Afslå +doRevoke=Tilbagekald +doApprove=Godkend +doRemoveSharing=Fjern Deling +doRemoveRequest=Fjern Forespørgsel +peopleAccessResource=Folk med adgang til denne ressource +resourceManagedPolicies=Tilladelsen som giver adgang til denne ressource +resourceNoPermissionsGrantingAccess=Ingen tilladelser giver adgang til denne ressource +anyAction=Enhver handling +description=Beskrivelse +name=Navn +scopes=Scopes +resource=Ressource +user=Bruger +peopleSharingThisResource=Folk som deler denne ressource +shareWithOthers=Del med andre +needMyApproval=Mangler min godkendelse +requestsWaitingApproval=Din forespørgsel afventer godkendelse +icon=Ikon +requestor=Forespørger +owner=Ejer +resourcesSharedWithMe=Ressourcer delt med mig +permissionRequestion=Rettigsheds forespørgsel +permission=Tilladelse +shares=share(s) + +locale_ca=Catal\u00e0 +locale_de=Deutsch +locale_en=English +locale_es=Espa\u00f1ol +locale_fr=Fran\u00e7ais +locale_it=Italian +locale_ja=\u65e5\u672c\u8a9e +locale_nl=Nederlands +locale_no=Norsk +locale_lt=Lietuvi\u0173 +locale_pt-BR=Portugu\u00eas (Brasil) +locale_ru=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 +locale_sk=Sloven\u010dina +locale_sv=Svenska +locale_zh-CN=\u4e2d\u6587\u7b80\u4f53 + +# Applications +applicationName=Navn +applicationType=Applikationstype +applicationInUse=In-use app only +clearAllFilter=Ryd alle filtre +activeFilters=Aktive filtre +filterByName=Filtrer På Navn... +allApps=Alle applikationer +internalApps=Interne applikationer +thirdpartyApps=Tredje-parts applikationer +appResults=Resultater + +# Linked account +authorizedProvider=Autoriseret Udbyder +authorizedProviderMessage=Autoriserede udbydere forbundet med din konto + +identityProvider=Identitetsudbyder +identityProviderMessage=For at forbinde din konto med de identitetsudbydere du har konfigureret +socialLogin=Social Log ind +userDefined=Brugerdefineret +removeAccess=Fjern Adgang +removeAccessMessage=Du skal give adgang igen, hvis du vil bruge denne app konto. + +#Authenticator +authenticatorStatusMessage=To-faktor godkendelse er +authenticatorFinishSetUpTitle=Din to-faktor godkendelse +authenticatorFinishSetUpMessage=Hver gang du logger ind på din Keycloak konto, vil du blive bedt om at give din to-faktor godkendelses kode. +authenticatorSubTitle=Opsæt to-faktor godkendelse +authenticatorSubMessage=For at forbedre sikkerheden på din konto, aktiver mindst en af de tilgængelige to-faktor godkendelses metoder. +authenticatorMobileTitle=Mobile Authenticator +authenticatorMobileMessage=Brug Mobile Authenticator for at få godkendelses koder som to-faktor godkendelse. +authenticatorMobileFinishSetUpMessage=Authenticatoren er blevet bundet til din telefon. +authenticatorActionSetup=Opsæt +authenticatorSMSTitle=SMS Kode +authenticatorSMSMessage=Keycloak vil sende godkendelses koden til din telefon som to-faktor godkendelse. + +authenticatorSMSFinishSetUpMessage=Tekst beskeder er sendt til +authenticatorDefaultStatus=Standard +authenticatorChangePhone=Ændre Telefonnummer + +#Authenticator - Mobile Authenticator setup +authenticatorMobileSetupTitle=Mobile Authenticator Opsætning +smscodeIntroMessage=Indtast dit mobil nummer og en verifikationskode vil blive sendt til din telefon. +mobileSetupStep1=Installer en authenticator applikation på din telefon. De understøttede applikationer er listed her. +mobileSetupStep2=Åben applikationen og skan stregkoden. +mobileSetupStep3=Indtast engangskoden fra authenticator applikationen og tryk Gem for at færdiggøre opsætningen. +scanBarCode=Vil du skanne stregkoden? +enterBarCode=Indtast engangskoden +doCopy=Kopier +doFinish=Afslut + +#Authenticator - SMS Code setup +authenticatorSMSCodeSetupTitle=SMS Kode Opsætning +chooseYourCountry=Vælg dit land +enterYourPhoneNumber=Indtast dit telefonnummer +sendVerficationCode=Send Verifikationskode +enterYourVerficationCode=Indtast din verifikationskode + +#Authenticator - backup Code setup +authenticatorBackupCodesSetupTitle=Backup Kode Opsætning +realmName=Rige +doDownload=Download +doPrint=Print +doCopy=Kopier +generateNewBackupCodes=Generer Nye Backup Koder +backtoAuthenticatorPage=Tilbage til Authenticator siden + + +#Resources +resources=Ressourcer +myResources=Mine Ressourcer +sharedwithMe=Delt med mig +share=Del +resource=Ressource +application=Applikation +date=Dato +sharedwith=Delt med +owner=Ejer +accessPermissions=Adgangstilladelser +permissionRequests=Rettigheds forespørgsler +approve=Godkend +approveAll=Godkend alle +sharedwith=Delt med +people=Folk +perPage=per side +currentPage=Nuværende Side +sharetheResource=Del Ressourcen +user=Bruger +group=Gruppe +selectPermission=Vælg tilladelse +addPeople=Tilføj folk at dele ressourcen med +addTeam=Tilføj hold at dele ressourcen med +myPermissions=Mine Tilladelser +waitingforApproval=Afventer godkendelse diff --git a/keycloak-themes/base/account/messages/messages_de.properties b/keycloak-themes/base/account/messages/messages_de.properties new file mode 100644 index 0000000..12a81d1 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_de.properties @@ -0,0 +1,348 @@ +doSave=Speichern +doCancel=Abbrechen +doLogOutAllSessions=Alle Sitzungen abmelden +doRemove=Entfernen +doAdd=Hinzuf\u00FCgen +doSignOut=Abmelden +doLogIn=Anmelden +doLink=Verkn\u00FCpfen +noAccessMessage=Zugriff verweigert + + +editAccountHtmlTitle=Benutzerkonto bearbeiten +personalInfoHtmlTitle=Pers\u00F6nliche Informationen +federatedIdentitiesHtmlTitle=F\u00F6derierte Identit\u00E4ten +accountLogHtmlTitle=Benutzerkonto Log +changePasswordHtmlTitle=Passwort \u00C4ndern +deviceActivityHtmlTitle=Ger\u00E4teaktivit\u00E4t +sessionsHtmlTitle=Sitzungen +accountManagementTitle=Keycloak Benutzerkontoverwaltung +authenticatorTitle=Mehrfachauthentifizierung +applicationsHtmlTitle=Applikationen +linkedAccountsHtmlTitle=Verkn\u00FCpfte Konten + +accountManagementWelcomeMessage=Willkommen bei der Keycloak Kontoverwaltung +personalInfoIntroMessage=Grundlegende Informationen verwalten +accountSecurityTitle=Kontosicherheit +accountSecurityIntroMessage=Passwort und Kontozugriff verwalten +applicationsIntroMessage=App-Berechtigung f\u00FCr den Zugriff auf ihr Konto verwalten +resourceIntroMessage=Ressourcen mit Teammitgliedern teilen +passwordLastUpdateMessage=Ihr Passwort wurde aktualisiert am +updatePasswordTitle=Passwort aktualisieren +updatePasswordMessageTitle=W\u00C4hlen Sie ein sicheres Passwort +updatePasswordMessage=Ein sicheres Passwort besteht aus einer Kombination aus Zahlen, Buchstaben und Sonderzeichen. Es ist schwer zu erraten, hat keine \u00C4hnlichkeit mit einem echten Wort, und wird nur f\u00FCr dieses Konto verwendet. +personalSubTitle=Ihre pers\u00F6nlichen Informationen +personalSubMessage=Verwalten Sie folgende Informationen: Vorname, Nachname und E-Mail-Adresse + +authenticatorCode=One-time Code +email=E-Mail +firstName=Vorname +givenName=Vorname +fullName=Voller Name +lastName=Nachname +familyName=Nachname +password=Passwort +currentPassword=Aktuelles Passwort +passwordConfirm=Passwort best\u00E4tigen +passwordNew=Neues Passwort +username=Benutzername +address=Adresse +street=Stra\u00DFe +region=Staat, Provinz, Region +postal_code=PLZ +locality=Stadt oder Ortschaft +country=Land +emailVerified=E-Mail verifiziert +website=Website +phoneNumber=Telefonnummer +phoneNumberVerified=Telefonnummer verifiziert +gender=Geschlecht +birthday=Geburtsdatum +zoneinfo=Zeitzone +gssDelegationCredential=GSS delegierte Berechtigung + +profileScopeConsentText=Nutzerkonto +emailScopeConsentText=E-Mail Adresse +addressScopeConsentText=Adresse +phoneScopeConsentText=Telefonnummer +offlineAccessScopeConsentText=Offline Zugriff +samlRoleListScopeConsentText=Meine Rollen +rolesScopeConsentText=Nutzerrollen + +role_admin=Admin +role_realm-admin=Realm Admin +role_create-realm=Realm erstellen +role_view-realm=Realm ansehen +role_view-users=Benutzer ansehen +role_view-applications=Applikationen ansehen +role_view-clients=Clients ansehen +role_view-events=Events ansehen +role_view-identity-providers=Identity Provider ansehen +role_view-consent=Zustimmungen anzeigen +role_manage-realm=Realm verwalten +role_manage-users=Benutzer verwalten +role_manage-applications=Applikationen verwalten +role_manage-identity-providers=Identity Provider verwalten +role_manage-clients=Clients verwalten +role_manage-events=Events verwalten +role_view-profile=Profile ansehen +role_manage-account=Profile verwalten +role_manage-account-links=Profil-Links verwalten +role_manage-consent=Zustimmungen verwalten +role_read-token=Token lesen +role_offline-access=Offline-Zugriff +role_uma_authorization=Berechtigungen einholen +client_account=Clientkonto +client_account-console=Accountkonsole +client_security-admin-console=Security Adminkonsole +client_admin-cli=Admin CLI +client_realm-management=Realm-Management +client_broker=Broker + + +requiredFields=Erforderliche Felder +allFieldsRequired=Alle Felder sind erforderlich + +backToApplication=« Zur\u00FCck zur Applikation +backTo=Zur\u00FCck zu {0} + +date=Datum +event=Ereignis +ip=IP +client=Client +clients=Clients +details=Details +started=Startdatum +lastAccess=Letzter Zugriff +expires=Ablaufdatum +applications=Applikationen + +account=Benutzerkonto +federatedIdentity=F\u00F6derierte Identit\u00E4t +authenticator=Mehrfachauthentifizierung +device-activity=Ger\u00E4teaktivit\u00E4t +sessions=Sitzungen +log=Log + +application=Applikation +availablePermissions=verf\u00FCgbare Berechtigungen +grantedPermissions=gew\u00E4hrte Berechtigungen +grantedPersonalInfo=gew\u00E4hrte pers\u00F6nliche Informationen +additionalGrants=zus\u00E4tzliche Berechtigungen +action=Aktion +inResource=in +fullAccess=Vollzugriff +offlineToken=Offline-Token +revoke=Berechtigung widerrufen + +configureAuthenticators=Mehrfachauthentifizierung konfigurieren +mobile=Mobil +totpStep1=Installieren Sie eine der folgenden Applikationen auf Ihrem Smartphone: +totpStep2=\u00D6ffnen Sie die Applikation und scannen Sie den Barcode. +totpStep3=Geben Sie den von der Applikation generierten One-time Code ein und klicken Sie auf Speichern. +totpStep3DeviceName=Geben Sie einen Ger\u00E4tenamen an, um die Verwaltung Ihrer OTP-Ger\u00E4te zu erleichtern. + +totpManualStep2=\u00D6ffnen Sie die Applikation und geben Sie den folgenden Schl\u00FCssel ein. +totpManualStep3=Verwenden Sie die folgenden Konfigurationswerte, falls Sie diese f\u00FCr die Applikation anpassen k\u00F6nnen: +totpUnableToScan=Sie k\u00F6nnen den Barcode nicht scannen? +totpScanBarcode=Barcode scannen? + +totp.totp=zeitbasiert (time-based) +totp.hotp=z\u00E4hlerbasiert (counter-based) + +totpType=Typ +totpAlgorithm=Algorithmus +totpDigits=Ziffern +totpInterval=Intervall +totpCounter=Z\u00E4hler +totpDeviceName=Ger\u00E4tename + +irreversibleAction=Diese Aktion ist unwiderruflich +deletingImplies=Die L\u00F6schung Ihres Kontos bedeutet: +errasingData=L\u00F6schen aller Ihrer Daten +loggingOutImmediately=Sofortige Abmeldung +accountUnusable=Eine sp\u00E4tere Nutzung der Anwendung ist mit diesem Konto nicht mehr m\u00F6glich + +missingUsernameMessage=Bitte geben Sie einen Benutzernamen ein. +missingFirstNameMessage=Bitte geben Sie einen Vornamen ein. +invalidEmailMessage=Ung\u00FCltige E-Mail Adresse. +missingLastNameMessage=Bitte geben Sie einen Nachnamen ein. +missingEmailMessage=Bitte geben Sie eine E-Mail Adresse ein. +missingPasswordMessage=Bitte geben Sie ein Passwort ein. +notMatchPasswordMessage=Die Passw\u00F6rter sind nicht identisch. +invalidUserMessage=Ung\u00FCltiger Nutzer + +missingTotpMessage=Bitte geben Sie den One-time Code ein. +missingTotpDeviceNameMessage=Bitte geben Sie einen Ger\u00E4tenamen an. +invalidPasswordExistingMessage=Das aktuelle Passwort ist ung\u00FCltig. +invalidPasswordConfirmMessage=Die Passwortbest\u00E4tigung ist nicht identisch. +invalidTotpMessage=Ung\u00FCltiger One-time Code. + +usernameExistsMessage=Der Benutzername existiert bereits. +emailExistsMessage=Die E-Mail-Adresse existiert bereits. + +readOnlyUserMessage=Sie k\u00F6nnen Ihr Benutzerkonto nicht \u00E4ndern, da es schreibgesch\u00FCtzt ist. +readOnlyUsernameMessage=Sie k\u00F6nnen Ihren Benutzernamen nicht \u00E4ndern, da er schreibgesch\u00FCtzt ist. +readOnlyPasswordMessage=Sie k\u00F6nnen Ihr Passwort nicht \u00E4ndern, da es schreibgesch\u00FCtzt ist. + +successTotpMessage=Mehrfachauthentifizierung erfolgreich konfiguriert. +successTotpRemovedMessage=Mehrfachauthentifizierung erfolgreich entfernt. + +successGrantRevokedMessage=Berechtigung erfolgreich widerrufen. + +accountUpdatedMessage=Ihr Benutzerkonto wurde aktualisiert. +accountPasswordUpdatedMessage=Ihr Passwort wurde aktualisiert. + +missingIdentityProviderMessage=Identity Provider nicht angegeben. +invalidFederatedIdentityActionMessage=Ung\u00FCltige oder fehlende Aktion. +identityProviderNotFoundMessage=Angegebener Identity Provider nicht gefunden. +federatedIdentityLinkNotActiveMessage=Diese Identit\u00E4t ist nicht mehr aktiv. +federatedIdentityRemovingLastProviderMessage=Sie k\u00F6nnen den letzten Eintrag nicht entfernen, da Sie kein Passwort haben. +identityProviderRedirectErrorMessage=Fehler bei der Weiterleitung zum Identity Provider. +identityProviderRemovedMessage=Identity Provider erfolgreich entfernt. +identityProviderAlreadyLinkedMessage=Die f\u00F6derierte Identit\u00E4t von {0} ist bereits einem anderen Benutzer zugewiesen. +staleCodeAccountMessage=Diese Seite ist nicht mehr g\u00FCltig, bitte versuchen Sie es noch einmal. +consentDenied=Einverst\u00E4ndnis verweigert. + +accountDisabledMessage=Ihr Benutzerkonto ist gesperrt, bitte kontaktieren Sie den Admin. + +accountTemporarilyDisabledMessage=Ihr Benutzerkonto ist tempor\u00E4r gesperrt, bitte kontaktieren Sie den Admin oder versuchen Sie es sp\u00E4ter noch einmal. +invalidPasswordMinLengthMessage=Ung\u00FCltiges Passwort: Es muss mindestens {0} Zeichen lang sein. +invalidPasswordMinLowerCaseCharsMessage=Ung\u00FCltiges Passwort\: Es muss mindestens {0} Kleinbuchstaben beinhalten. +invalidPasswordMinDigitsMessage=Ung\u00FCltiges Passwort: Es muss mindestens {0} Zahl(en) beinhalten. +invalidPasswordMinUpperCaseCharsMessage=Ung\u00FCltiges Passwort: Es muss mindestens {0} Gro\u00DFbuchstaben beinhalten. +invalidPasswordMinSpecialCharsMessage=Ung\u00FCltiges Passwort: Es muss mindestens {0} Sonderzeichen beinhalten. +invalidPasswordNotUsernameMessage=Ung\u00FCltiges Passwort: Es darf nicht gleich sein wie der Benutzername. +invalidPasswordNotEmailMessage=Ung\u00FCltiges Passwort: darf nicht identisch mit der E-Mail-Adresse sein. +invalidPasswordRegexPatternMessage=Ung\u00FCltiges Passwort: Es entspricht nicht dem Regex-Muster. +invalidPasswordHistoryMessage=Ung\u00FCltiges Passwort: Es darf nicht einem der letzten {0} Passw\u00F6rter entsprechen. +invalidPasswordBlacklistedMessage=Ung\u00FCltiges Passwort: Das Passwort steht auf der Blocklist (schwarzen Liste). +invalidPasswordGenericMessge=Ung\u00FCltiges Passwort: Das neue Passwort verletzt die Passwort-Richtlinien. + +# Authorization +myResources=Meine Ressourcen +myResourcesSub=Meine Ressourcen +doDeny=Ablehnen +doRevoke=Widerrufen +doApprove=Genehmigen +doRemoveSharing=Freigabe entfernen +doRemoveRequest=Anfrage entfernen +peopleAccessResource=Personen mit Zugriff auf diese Ressource +resourceManagedPolicies=Berechtigungen, die Zugriff auf diese Ressource gew\u00E4hren +resourceNoPermissionsGrantingAccess=Keine Berechtigungen, die Zugriff auf diese Ressource gew\u00E4hren +anyAction=Jede Aktion +description=Beschreibung +name=Name +scopes=Geltungsbereiche +resource=Ressource +user=Nutzer +peopleSharingThisResource=Personen, die diese Ressource teilen +shareWithOthers=Mit anderen teilen +needMyApproval=Braucht meine Zustimmung +requestsWaitingApproval=Ihre Anfragen, die auf Genehmigung warten +icon=Icon +requestor=Antragstellender +owner=Besitzender +resourcesSharedWithMe=Mit mir geteilte Ressourcen +permissionRequestion=Genehmigungsanfrage +permission=Genehmigung +shares=teilt(en) +notBeingShared=Diese Ressource wird nicht freigegeben. +notHaveAnyResource=Sie haben keine Ressourcen +noResourcesSharedWithYou=Es werden keine Ressourcen mit Ihnen geteilt +havePermissionRequestsWaitingForApproval=Sie haben {0} Genehmigungsanfrage(n), die auf die Genehmigung warten. +clickHereForDetails=Klicken Sie hier f\u00FCr Details. +resourceIsNotBeingShared=Die Ressource wird nicht freigegeben + +# Applications +applicationName=Anwendungsname +applicationType=Anwendungstyp +applicationInUse=Nur verwendete Anwendungen +clearAllFilter=Alle Filter entfernen +activeFilters=Aktive Filter +filterByName=Nach Namen filtern ... +allApps=Alle Anwendungen +internalApps=Interne Anwendungen +thirdpartyApps=Anwendungen von Drittanbietern +appResults=Ergebnisse +clientNotFoundMessage=Client nicht gefunden. + +# Linked account +authorizedProvider=Autorisierter Provider +authorizedProviderMessage=Autorisierte Provider, die mit Ihrem Konto verkn\u00FCpft sind +identityProvider=Identit\u00E4tsprovider +identityProviderMessage=Verkn\u00FCpfen Sie Ihr Konto mit Identit\u00E4tsprovidern, die Sie konfiguriert haben +socialLogin=Social Login +userDefined=Benutzerdefiniert +removeAccess=Zugriff entfernen +removeAccessMessage=Sie m\u00FCssen den Zugriff erneut gew\u00E4hren, wenn Sie diese Anwendung verwenden m\u00F6chten. + +#Authenticator +authenticatorStatusMessage=Zwei-Faktor-Authentifizierung ist zurzeit +authenticatorFinishSetUpTitle=Ihre Zwei-Faktor-Authentifizierung +authenticatorFinishSetUpMessage=Jedes Mal, wenn Sie sich bei Ihrem Keycloak-Konto anmelden, werden Sie aufgefordert, einen Zwei-Faktor-Authentifizierungscode einzugeben. +authenticatorSubTitle=Zwei-Faktor-Authentifizierung einrichten +authenticatorSubMessage=Um die Sicherheit Ihres Kontos zu erh\u00F6hen, aktivieren Sie mindestens eine der verf\u00FCgbaren Zwei-Faktor-Authentifizierungsmethoden. +authenticatorMobileTitle=Handy-Authentifikator +authenticatorMobileMessage=Verwenden Sie Authenticator-Anwendungen auf Ihrem Telefon, um Verifizierungscodes als Zwei-Faktor-Authentifizierung zu erhalten. +authenticatorMobileFinishSetUpMessage=Die Authenticator-Anwendung wurde an Ihr Telefon gebunden. +authenticatorActionSetup=Einrichten +authenticatorSMSTitle=SMS-Code +authenticatorSMSMessage=Keycloak sendet den Verifizierungscode an Ihr Telefon als Zwei-Faktor-Authentifizierung. +authenticatorSMSFinishSetUpMessage=Textnachrichten werden gesendet an +authenticatorDefaultStatus=Standard +authenticatorChangePhone=Telefonnummer \u00E4ndern + +#Authenticator - Mobile Authenticator setup +authenticatorMobileSetupTitle=Handy-Authenticator-Setup +smscodeIntroMessage=Geben Sie Ihre Rufnummer ein und ein Verifizierungscode wird an Ihr Telefon gesendet. +mobileSetupStep1=Installieren Sie eine Authenticator-Anwendung auf Ihrem Telefon. Die hier aufgef\u00FChrten Anwendungen werden unterst\u00FCtzt. +mobileSetupStep2=\u00D6ffnen Sie die Anwendung und scannen Sie den Barcode: +mobileSetupStep3=Geben Sie den von der Anwendung bereitgestellten Einmalcode ein und klicken Sie auf Speichern, um die Einrichtung abzuschlie\u00DFen. +scanBarCode=Wollen Sie den Barcode scannen? +enterBarCode=Geben Sie den Einmalcode ein +doCopy=Kopieren +doFinish=Fertigstellen + +#Authenticator - SMS Code setup +authenticatorSMSCodeSetupTitle=SMS-Code-Einrichtung +chooseYourCountry=W\u00E4hlen Sie Ihr Land +enterYourPhoneNumber=Geben Sie Ihre Telefonnummer ein +sendVerficationCode=Verifizierungscode senden +enterYourVerficationCode=Geben Sie Ihren Verifizierungscode ein + +#Authenticator - backup Code setup +authenticatorBackupCodesSetupTitle=Backup-Codes einrichten +realmName=Realm +doDownload=Herunterladen +doPrint=Drucken +generateNewBackupCodes=Neue Backup-Codes generieren +backtoAuthenticatorPage=Zur\u00FCck zur Authenticator-Seite + + +#Resources +resources=Ressourcen +sharedwithMe=Mit mir geteilt +share=Teilen +sharedwith=Geteilt mit +accessPermissions=Zugriffsberechtigungen +permissionRequests=Berechtigungsanfragen +approve=Genehmigen +approveAll=Alle genehmigen +people=Personen +perPage=Pro Seite +currentPage=Aktuelle Seite +sharetheResource=Die Ressource teilen +group=Gruppe +selectPermission=Berechtigung ausw\u00E4hlen +addPeople=Personen hinzuf\u00FCgen, mit denen die Ressource geteilt werden soll +addTeam=Team hinzuf\u00FCgen, mit dem die Ressource geteilt werden soll +myPermissions=Meine Berechtigungen +waitingforApproval=Warten auf Genehmigung +anyPermission=Jede Berechtigung + +# Openshift messages +openshift.scope.user_info=Nutzerinformation +openshift.scope.user_check-access=Benutzerzugriffsinformationen +openshift.scope.user_full=Voller Zugriff +openshift.scope.list-projects=Projekte auflisten diff --git a/keycloak-themes/base/account/messages/messages_en.properties b/keycloak-themes/base/account/messages/messages_en.properties new file mode 100644 index 0000000..2c26091 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_en.properties @@ -0,0 +1,397 @@ +doSave=Save +doCancel=Cancel +doLogOutAllSessions=Log out all sessions +doRemove=Remove +doAdd=Add +doSignOut=Sign out +doLogIn=Log In +doLink=Link +noAccessMessage=Access not allowed + +personalInfoSidebarTitle=Personal info +accountSecuritySidebarTitle=Account security +signingInSidebarTitle=Signing in +deviceActivitySidebarTitle=Device activity +linkedAccountsSidebarTitle=Linked accounts + +editAccountHtmlTitle=Edit Account +personalInfoHtmlTitle=Personal Info +federatedIdentitiesHtmlTitle=Federated Identities +accountLogHtmlTitle=Account Log +changePasswordHtmlTitle=Change Password +deviceActivityHtmlTitle=Device Activity +sessionsHtmlTitle=Sessions +accountManagementTitle=Keycloak Account Management +authenticatorTitle=Authenticator +applicationsHtmlTitle=Applications +linkedAccountsHtmlTitle=Linked accounts + +accountManagementWelcomeMessage=Welcome to Keycloak Account Management +personalInfoIntroMessage=Manage your basic information +accountSecurityTitle=Account Security +accountSecurityIntroMessage=Control your password and account access +applicationsIntroMessage=Track and manage your app permission to access your account +resourceIntroMessage=Share your resources among team members +passwordLastUpdateMessage=Your password was updated at +updatePasswordTitle=Update Password +updatePasswordMessageTitle=Make sure you choose a strong password +updatePasswordMessage=A strong password contains a mix of numbers, letters, and symbols. It is hard to guess, does not resemble a real word, and is only used for this account. +personalSubTitle=Your Personal Info +personalSubMessage=Manage your basic information. + +authenticatorCode=One-time code +email=Email +firstName=First name +givenName=Given name +fullName=Full name +lastName=Last name +familyName=Family name +password=Password +currentPassword=Current Password +passwordConfirm=Confirmation +passwordNew=New Password +username=Username +address=Address +street=Street +locality=City or Locality +region=State, Province, or Region +postal_code=Zip or Postal code +country=Country +emailVerified=Email verified +website=Web page +phoneNumber=Phone number +phoneNumberVerified=Phone number verified +gender=Gender +birthday=Birthdate +zoneinfo=Time zone +gssDelegationCredential=GSS Delegation Credential + +profileScopeConsentText=User profile +emailScopeConsentText=Email address +addressScopeConsentText=Address +phoneScopeConsentText=Phone number +offlineAccessScopeConsentText=Offline Access +samlRoleListScopeConsentText=My Roles +rolesScopeConsentText=User roles + +role_admin=Admin +role_realm-admin=Realm Admin +role_create-realm=Create realm +role_view-realm=View realm +role_view-users=View users +role_view-applications=View applications +role_view-clients=View clients +role_view-events=View events +role_view-identity-providers=View identity providers +role_view-consent=View consents +role_manage-realm=Manage realm +role_manage-users=Manage users +role_manage-applications=Manage applications +role_manage-identity-providers=Manage identity providers +role_manage-clients=Manage clients +role_manage-events=Manage events +role_view-profile=View profile +role_manage-account=Manage account +role_manage-account-links=Manage account links +role_manage-consent=Manage consents +role_read-token=Read token +role_offline-access=Offline access +role_uma_authorization=Obtain permissions +client_account=Account +client_account-console=Account Console +client_security-admin-console=security admin console +client_admin-cli=Admin CLI +client_realm-management=Realm Management +client_broker=Broker + + +requiredFields=Required fields +allFieldsRequired=All fields required + +backToApplication=« Back to application +backTo=Back to {0} + +date=Date +event=Event +ip=IP +client=Client +clients=Clients +details=Details +started=Started +lastAccess=Last Access +expires=Expires +applications=Applications + +account=Account +federatedIdentity=Federated Identity +authenticator=Authenticator +device-activity=Device activity +sessions=Sessions +log=Log + +application=Application +availableRoles=Available Roles +grantedPermissions=Granted Permissions +grantedPersonalInfo=Granted Personal Info +additionalGrants=Additional Grants +action=Action +inResource=in +fullAccess=Full Access +offlineToken=Offline Token +revoke=Revoke Grant + +configureAuthenticators=Configured Authenticators +mobile=Mobile +totpStep1=Install one of the following applications on your mobile: +totpStep2=Open the application and scan the barcode: +totpStep3=Enter the one-time code provided by the application and click Save to finish the setup. +totpStep3DeviceName=Provide a Device Name to help you manage your OTP devices. + +totpManualStep2=Open the application and enter the key: +totpManualStep3=Use the following configuration values if the application allows setting them: +totpUnableToScan=Unable to scan? +totpScanBarcode=Scan barcode? + +totp.totp=Time-based +totp.hotp=Counter-based + +totpType=Type +totpAlgorithm=Algorithm +totpDigits=Digits +totpInterval=Interval +totpCounter=Counter +totpDeviceName=Device Name + +irreversibleAction=This action is irreversible +deletingImplies=Deleting your account implies: +errasingData=Erasing all your data +loggingOutImmediately=Logging you out immediately +accountUnusable=Any subsequent use of the application will not be possible with this account + +missingUsernameMessage=Please specify username. +missingFirstNameMessage=Please specify first name. +invalidEmailMessage=Invalid email address. +missingLastNameMessage=Please specify last name. +missingEmailMessage=Please specify email. +missingPasswordMessage=Please specify password. +notMatchPasswordMessage=Passwords don''t match. +invalidUserMessage=Invalid user +updateReadOnlyAttributesRejectedMessage=Update of read-only attribute rejected + +missingTotpMessage=Please specify authenticator code. +missingTotpDeviceNameMessage=Please specify device name. +invalidPasswordExistingMessage=Invalid existing password. +invalidPasswordConfirmMessage=Password confirmation doesn''t match. +invalidTotpMessage=Invalid authenticator code. + +usernameExistsMessage=Username already exists. +emailExistsMessage=Email already exists. + +readOnlyUserMessage=You can''t update your account as it is read-only. +readOnlyUsernameMessage=You can''t update your username as it is read-only. +readOnlyPasswordMessage=You can''t update your password as your account is read-only. + +successTotpMessage=Mobile authenticator configured. +successTotpRemovedMessage=Mobile authenticator removed. + +successGrantRevokedMessage=Grant revoked successfully. + +accountUpdatedMessage=Your account has been updated. +accountPasswordUpdatedMessage=Your password has been updated. + +missingIdentityProviderMessage=Identity provider not specified. +invalidFederatedIdentityActionMessage=Invalid or missing action. +identityProviderNotFoundMessage=Specified identity provider not found. +federatedIdentityLinkNotActiveMessage=This identity is not active anymore. +federatedIdentityRemovingLastProviderMessage=You can''t remove last federated identity as you don''t have a password. +identityProviderRedirectErrorMessage=Failed to redirect to identity provider. +identityProviderRemovedMessage=Identity provider removed successfully. +identityProviderAlreadyLinkedMessage=Federated identity returned by {0} is already linked to another user. +staleCodeAccountMessage=The page expired. Please try one more time. +consentDenied=Consent denied. + +accountDisabledMessage=Account is disabled, contact your administrator. + +accountTemporarilyDisabledMessage=Account is temporarily disabled, contact your administrator or try again later. +invalidPasswordMinLengthMessage=Invalid password: minimum length {0}. +invalidPasswordMaxLengthMessage=Invalid password: maximum length {0}. +invalidPasswordMinLowerCaseCharsMessage=Invalid password: must contain at least {0} lower case characters. +invalidPasswordMinDigitsMessage=Invalid password: must contain at least {0} numerical digits. +invalidPasswordMinUpperCaseCharsMessage=Invalid password: must contain at least {0} upper case characters. +invalidPasswordMinSpecialCharsMessage=Invalid password: must contain at least {0} special characters. +invalidPasswordNotUsernameMessage=Invalid password: must not be equal to the username. +invalidPasswordNotEmailMessage=Invalid password: must not be equal to the email. +invalidPasswordRegexPatternMessage=Invalid password: fails to match regex pattern(s). +invalidPasswordHistoryMessage=Invalid password: must not be equal to any of last {0} passwords. +invalidPasswordBlacklistedMessage=Invalid password: password is blacklisted. +invalidPasswordGenericMessage=Invalid password: new password doesn''t match password policies. + +# Authorization +myResources=My Resources +myResourcesSub=My resources +doDeny=Deny +doRevoke=Revoke +doApprove=Approve +doRemoveSharing=Remove Sharing +doRemoveRequest=Remove Request +peopleAccessResource=People with access to this resource +resourceManagedPolicies=Permissions granting access to this resource +resourceNoPermissionsGrantingAccess=No permissions granting access to this resource +anyAction=Any action +description=Description +name=Name +scopes=Scopes +resource=Resource +user=User +peopleSharingThisResource=People sharing this resource +shareWithOthers=Share with others +needMyApproval=Need my approval +requestsWaitingApproval=Your requests waiting approval +icon=Icon +requestor=Requestor +owner=Owner +resourcesSharedWithMe=Resources shared with me +permissionRequestion=Permission Requestion +permission=Permission +shares=share(s) +notBeingShared=This resource is not being shared. +notHaveAnyResource=You don't have any resources +noResourcesSharedWithYou=There are no resources shared with you +havePermissionRequestsWaitingForApproval=You have {0} permission request(s) waiting for approval. +clickHereForDetails=Click here for details. +resourceIsNotBeingShared=The resource is not being shared + +locale_ca=Catal\u00e0 +locale_cs=\u010Ce\u0161tina +locale_de=Deutsch +locale_en=English +locale_es=Espa\u00f1ol +locale_fr=Fran\u00e7ais +locale_hu=Magyar +locale_it=Italiano +locale_ja=\u65e5\u672c\u8a9e +locale_lt=Lietuvi\u0173 +locale_nl=Nederlands +locale_no=Norsk +locale_pl=Polski +locale_pt-BR=Portugu\u00eas (Brasil) +locale_ru=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 +locale_sk=Sloven\u010dina +locale_sv=Svenska +locale_tr=T\u00FCrk\u00E7e +locale_zh-CN=\u4e2d\u6587\u7b80\u4f53 +locale_fi=Suomi + +# Applications +applicationName=Name +applicationType=Application Type +applicationInUse=In-use app only +clearAllFilter=Clear all filters +activeFilters=Active filters +filterByName=Filter By Name ... +allApps=All applications +internalApps=Internal applications +thirdpartyApps=Third-Party applications +appResults=Results +clientNotFoundMessage=Client not found. + +# Linked account +authorizedProvider=Authorized Provider +authorizedProviderMessage=Authorized Providers linked with your account +identityProvider=Identity Provider +identityProviderMessage=To link your account with identity providers you have configured +socialLogin=Social Login +userDefined=User Defined +removeAccess=Remove Access +removeAccessMessage=You will need to grant access again, if you want to use this app account. + +#Authenticator +authenticatorStatusMessage=Two-factor authentication is currently +authenticatorFinishSetUpTitle=Your Two-Factor Authentication +authenticatorFinishSetUpMessage=Each time you sign in to your Keycloak account, you will be asked to provide a two-factor authentication code. +authenticatorSubTitle=Set Up Two-Factor Authentication +authenticatorSubMessage=To enhance the security of your account, enable at least one of the available two-factor authentication methods. +authenticatorMobileTitle=Mobile Authenticator +authenticatorMobileMessage=Use mobile Authenticator to get Verification codes as the two-factor authentication. +authenticatorMobileFinishSetUpMessage=The authenticator has been bound to your phone. +authenticatorActionSetup=Set up +authenticatorSMSTitle=SMS Code +authenticatorSMSMessage=Keycloak will send the Verification code to your phone as the two-factor authentication. +authenticatorSMSFinishSetUpMessage=Text messages are sent to +authenticatorDefaultStatus=Default +authenticatorChangePhone=Change Phone Number + +#Authenticator - Mobile Authenticator setup +authenticatorMobileSetupTitle=Mobile Authenticator Setup +smscodeIntroMessage=Enter your phone number and a verification code will be sent to your phone. +mobileSetupStep1=Install an authenticator application on your phone. The applications listed here are supported. +mobileSetupStep2=Open the application and scan the barcode: +mobileSetupStep3=Enter the one-time code provided by the application and click Save to finish the setup. +scanBarCode=Want to scan the barcode? +enterBarCode=Enter the one-time code +doCopy=Copy +doFinish=Finish + +#Authenticator - SMS Code setup +authenticatorSMSCodeSetupTitle=SMS Code Setup +chooseYourCountry=Choose your country +enterYourPhoneNumber=Enter your phone number +sendVerficationCode=Send Verification Code +enterYourVerficationCode=Enter your verification code + +#Authenticator - backup Code setup +authenticatorBackupCodesSetupTitle=Recovery Authentication Codes Setup +realmName=Realm +doDownload=Download +doPrint=Print +generateNewBackupCodes=Generate New Recovery Authentication Codes +backtoAuthenticatorPage=Back to Authenticator Page + + +#Resources +resources=Resources +sharedwithMe=Shared with Me +share=Share +sharedwith=Shared with +accessPermissions=Access Permissions +permissionRequests=Permission Requests +approve=Approve +approveAll=Approve all +people=people +perPage=per page +currentPage=Current Page +sharetheResource=Share the resource +group=Group +selectPermission=Select Permission +addPeople=Add people to share your resource with +addTeam=Add team to share your resource with +myPermissions=My Permissions +waitingforApproval=Waiting for approval +anyPermission=Any Permission + +# Openshift messages +openshift.scope.user_info=User information +openshift.scope.user_check-access=User access information +openshift.scope.user_full=Full Access +openshift.scope.list-projects=List projects + +error-invalid-value=Invalid value. +error-invalid-blank=Please specify value. +error-empty=Please specify value. +error-invalid-length=Attribute {0} must have a length between {1} and {2}. +error-invalid-length-too-short=Attribute {0} must have minimal length of {1}. +error-invalid-length-too-long=Attribute {0} must have maximal length of {2}. +error-invalid-email=Invalid email address. +error-invalid-number=Invalid number. +error-number-out-of-range=Attribute {0} must be a number between {1} and {2}. +error-number-out-of-range-too-small=Attribute {0} must have minimal value of {1}. +error-number-out-of-range-too-big=Attribute {0} must have maximal value of {2}. +error-pattern-no-match=Invalid value. +error-invalid-uri=Invalid URL. +error-invalid-uri-scheme=Invalid URL scheme. +error-invalid-uri-fragment=Invalid URL fragment. +error-user-attribute-required=Please specify attribute {0}. +error-invalid-date=Invalid date. +error-user-attribute-read-only=The field {0} is read only. +error-username-invalid-character=Username contains invalid character. +error-person-name-invalid-character=Name contains invalid character. diff --git a/keycloak-themes/base/account/messages/messages_es.properties b/keycloak-themes/base/account/messages/messages_es.properties new file mode 100644 index 0000000..fd36e59 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_es.properties @@ -0,0 +1,147 @@ +doSave=Guardar +doCancel=Cancelar +doLogOutAllSessions=Desconectar de todas las sesiones +doRemove=Eliminar +doAdd=A\u00F1adir +doSignOut=Desconectar + +editAccountHtmlTitle=Editar cuenta +federatedIdentitiesHtmlTitle=Identidades federadas +accountLogHtmlTitle=Registro de la cuenta +changePasswordHtmlTitle=Cambiar contrase\u00F1a +sessionsHtmlTitle=Sesiones +accountManagementTitle=Gesti\u00F3n de Cuenta Keycloak +authenticatorTitle=Autenticador +applicationsHtmlTitle=Aplicaciones + +authenticatorCode=C\u00F3digo de un solo uso +email=Email +firstName=Nombre +givenName=Nombre de pila +fullName=Nombre completo +lastName=Apellidos +familyName=Apellido +password=Contrase\u00F1a +passwordConfirm=Confirma la contrase\u00F1a +passwordNew=Nueva contrase\u00F1a +username=Usuario +address=Direcci\u00F3n +street=Calle +locality=Ciudad o Municipio +region=Estado, Provincia, o Regi\u00F3n +postal_code=C\u00F3digo Postal +country=Pa\u00EDs +emailVerified=Email verificado +gssDelegationCredential=GSS Delegation Credential + +role_admin=Administrador +role_realm-admin=Administrador del dominio +role_create-realm=Crear dominio +role_view-realm=Ver dominio +role_view-users=Ver usuarios +role_view-applications=Ver aplicaciones +role_view-clients=Ver clientes +role_view-events=Ver eventos +role_view-identity-providers=Ver proveedores de identidad +role_manage-realm=Gestionar dominio +role_manage-users=Gestionar usuarios +role_manage-applications=Gestionar aplicaciones +role_manage-identity-providers=Gestionar proveedores de identidad +role_manage-clients=Gestionar clientes +role_manage-events=Gestionar eventos +role_view-profile=Ver perfil +role_manage-account=Gestionar cuenta +role_read-token=Leer token +role_offline-access=Acceso sin conexi\u00F3n +client_account=Cuenta +client_security-admin-console=Consola de Administraci\u00F3n de Seguridad +client_realm-management=Gesti\u00F3n de dominio +client_broker=Broker + + +requiredFields=Campos obligatorios +allFieldsRequired=Todos los campos obligatorios + +backToApplication=« Volver a la aplicaci\u00F3n +backTo=Volver a {0} + +date=Fecha +event=Evento +ip=IP +client=Cliente +clients=Clientes +details=Detalles +started=Iniciado +lastAccess=\u00DAltimo acceso +expires=Expira +applications=Aplicaciones + +account=Cuenta +federatedIdentity=Identidad federada +authenticator=Autenticador +sessions=Sesiones +log=Regisro + +application=Aplicaci\u00F3n +availablePermissions=Permisos disponibles +grantedPermissions=Permisos concedidos +grantedPersonalInfo=Informaci\u00F3n personal concedida +additionalGrants=Permisos adicionales +action=Acci\u00F3n +inResource=en +fullAccess=Acceso total +offlineToken=C\u00F3digo de autorizaci\u00F3n offline +revoke=Revocar permiso + +configureAuthenticators=Autenticadores configurados +mobile=M\u00F3vil +totpStep1=Instala FreeOTP o Google Authenticator en tu tel\u00E9fono m\u00F3vil. Ambas aplicaciones est\u00E1n disponibles en Google Play y en la App Store de Apple. +totpStep2=Abre la aplicaci\u00F3n y escanea el c\u00F3digo o introduce la clave. +totpStep3=Introduce el c\u00F3digo \u00FAnico que te muestra la aplicaci\u00F3n de autenticaci\u00F3n y haz clic en Enviar para finalizar la configuraci\u00F3n + +missingUsernameMessage=Por favor indica tu usuario. +missingFirstNameMessage=Por favor indica el nombre. +invalidEmailMessage=Email no v\u00E1lido +missingLastNameMessage=Por favor indica tus apellidos. +missingEmailMessage=Por favor indica el email. +missingPasswordMessage=Por favor indica tu contrase\u00F1a. +notMatchPasswordMessage=Las contrase\u00F1as no coinciden. + +missingTotpMessage=Por favor indica tu c\u00F3digo de autenticaci\u00F3n +invalidPasswordExistingMessage=La contrase\u00F1a actual no es correcta. +invalidPasswordConfirmMessage=La confirmaci\u00F3n de contrase\u00F1a no coincide. +invalidTotpMessage=El c\u00F3digo de autenticaci\u00F3n no es v\u00E1lido. + +usernameExistsMessage=El usuario ya existe +emailExistsMessage=El email ya existe + +readOnlyUserMessage=No puedes actualizar tu usuario porque tu cuenta es de solo lectura. +readOnlyPasswordMessage=No puedes actualizar tu contrase\u00F1a porque tu cuenta es de solo lectura. + +successTotpMessage=Aplicaci\u00F3n de autenticaci\u00F3n m\u00F3vil configurada. +successTotpRemovedMessage=Aplicaci\u00F3n de autenticaci\u00F3n m\u00F3vil eliminada. + +successGrantRevokedMessage=Permiso revocado correctamente + +accountUpdatedMessage=Tu cuenta se ha actualizado. +accountPasswordUpdatedMessage=Tu contrase\u00F1a se ha actualizado. + +missingIdentityProviderMessage=Proveedor de identidad no indicado. +invalidFederatedIdentityActionMessage=Acci\u00F3n no v\u00E1lida o no indicada. +identityProviderNotFoundMessage=No se encontr\u00F3 un proveedor de identidad. +federatedIdentityLinkNotActiveMessage=Esta identidad ya no est\u00E1 activa +federatedIdentityRemovingLastProviderMessage=No puedes eliminar la \u00FAltima identidad federada porque no tienes fijada una contrase\u00F1a. +identityProviderRedirectErrorMessage=Error en la redirecci\u00F3n al proveedor de identidad +identityProviderRemovedMessage=Proveedor de identidad borrado correctamente. + +accountDisabledMessage=La cuenta est\u00E1 desactivada, contacta con el administrador. + +accountTemporarilyDisabledMessage=La cuenta est\u00E1 temporalmente desactivada, contacta con el administrador o int\u00E9ntalo de nuevo m\u00E1s tarde. +invalidPasswordMinLengthMessage=Contrase\u00F1a incorrecta: longitud m\u00EDnima {0}. +invalidPasswordMinLowerCaseCharsMessage=Contrase\u00F1a incorrecta: debe contener al menos {0} letras min\u00FAsculas. +invalidPasswordMinDigitsMessage=Contrase\u00F1a incorrecta: debe contener al menos {0} caracteres num\u00E9ricos. +invalidPasswordMinUpperCaseCharsMessage=Contrase\u00F1a incorrecta: debe contener al menos {0} letras may\u00FAsculas. +invalidPasswordMinSpecialCharsMessage=Contrase\u00F1a incorrecta: debe contener al menos {0} caracteres especiales. +invalidPasswordNotUsernameMessage=Contrase\u00F1a incorrecta: no puede ser igual al nombre de usuario. +invalidPasswordRegexPatternMessage=Contrase\u00F1a incorrecta: no cumple la expresi\u00F3n regular. +invalidPasswordHistoryMessage=Contrase\u00F1a incorrecta: no puede ser igual a ninguna de las \u00FAltimas {0} contrase\u00F1as. \ No newline at end of file diff --git a/keycloak-themes/base/account/messages/messages_fi.properties b/keycloak-themes/base/account/messages/messages_fi.properties new file mode 100644 index 0000000..3146b79 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_fi.properties @@ -0,0 +1,400 @@ +# encoding: UTF-8 +doSave=Tallenna +doCancel=Peruuta +doLogOutAllSessions=Kirjaudu ulos kaikista sessioista +doRemove=Poista +doAdd=Lisää +doSignOut=Kirjaudu ulos +doLogIn=Kirjaudu sisään +doLink=Yhdistä +noAccessMessage=Pääsy evätty + + +editAccountHtmlTitle=Muokkaa käyttäjää +personalInfoHtmlTitle=Henkilökohtaiset tiedot +federatedIdentitiesHtmlTitle=Yhteinen tunnistaminen +accountLogHtmlTitle=Käyttäjä loki +changePasswordHtmlTitle=Vaihda salasana +deviceActivityHtmlTitle=Device Activity +sessionsHtmlTitle=Istunnot +accountManagementTitle=Keycloak Käyttäjä Hallinta +authenticatorTitle=Kaksinkertainen kirjautuminen +applicationsHtmlTitle=Sovellukset +linkedAccountsHtmlTitle=Yhdistetyt tilit + +accountManagementWelcomeMessage=Tervetuloa Keycloak-tilin hallintaan +personalInfoIntroMessage=Hallinnoi perustietoja +accountSecurityTitle=Tilin turvallisuus +accountSecurityIntroMessage=Hallitse salasanaasi ja tilin pääsyasetuksia +applicationsIntroMessage=Seuraa ja hallitse sovelluksiasi, joilla on pääsy tilille +resourceIntroMessage=Jaa resurssejasi tiimin jäsenten kesken +passwordLastUpdateMessage=Salasanasi päivitettiin +updatePasswordTitle=Päivitä salasana +updatePasswordMessageTitle=Varmista, että valitsemasi salasana on vahva +updatePasswordMessage=Vahva salasana sisältää sekaisin numeroita, kirjaimia ja symboleja. Se on vaikea arvata, ei muistuta oikeita sanoja ja on käytössä vain tällä tilillä. +personalSubTitle=Henkilökohtaiset tiedot +personalSubMessage=Hallitse näitä perustietojasi: etunimi, sukunimi ja sähköposti + +authenticatorCode=Kertakäyttökoodi +email=Sähköposti +firstName=Etunimi +givenName=Sukunimi +fullName=Koko nimi +lastName=Sukunimi +familyName=Sukunimi +password=Salasana +currentPassword=Nykyinen salasana +passwordConfirm=Salasana uudelleen +passwordNew=Uusi salasana +username=Käyttäjänimi +address=Osoite +street=Katu +locality=Kaupunki +region=Osavaltio, Provinssi, tai Alue +postal_code=Postinumero +country=Maa +emailVerified=Sähköposti vahvistettu +website=Verkkosivu +phoneNumber=Puhelinnumero +phoneNumberVerified=Puhelinnumero varmennettu +gender=Sukupuoli +birthday=Syntymäpäivä +zoneinfo=Aikavyöhyke +gssDelegationCredential=GSS Delegation Credential + +profileScopeConsentText=Käyttäjän profiili +emailScopeConsentText=Sähköpostiosoite +addressScopeConsentText=Osoite +phoneScopeConsentText=Puhelinnumero +offlineAccessScopeConsentText=Offline-käyttö +samlRoleListScopeConsentText=Omat roolit +rolesScopeConsentText=Käyttäjäroolit + +role_admin=Admin +role_realm-admin=Realm Admin +role_create-realm=Luo realm +role_view-realm=Näytä realm +role_view-users=Näytä käyttäjät +role_view-applications=Näytä sovellukset +role_view-clients=Näytä asiakkaat +role_view-events=Näytä tapahtumat +role_view-identity-providers=Näytä henkilöllisyyden tarjoajat +role_view-consent=Näytä suostumukset +role_manage-realm=Hallinnoi realmia +role_manage-users=Hallinnoi käyttäjiä +role_manage-applications=Hallinnoi sovelluksia +role_manage-identity-providers=Hallinnoi henkilöllisyyden tarjoajia +role_manage-clients=Hallinnoi asiakkaita +role_manage-events=Hallinnoi tapahtumia +role_view-profile=Näytä profiili +role_manage-account=Hallitse tiliä +role_manage-account-links=Hallitse tilin linkkejä +role_manage-consent=Hallitse suostumuksia +role_read-token=Lue token +role_offline-access=Offline-pääsy +role_uma_authorization=Hanki käyttöoikeudet +client_account=Tili +client_account-console=Tilin konsoli +client_security-admin-console=Turvallisuus-hallintapaneeli +client_admin-cli=Admin CLI +client_realm-management=Realm Hallinta +client_broker=Broker + + +requiredFields=Vaaditut kentät +allFieldsRequired=Kaikki kentät vaaditaan + +backToApplication=« Takaisin sovellukseen +backTo=Takaisin {0} + +date=Päivämäärä +event=Event +ip=IP +client=Asiakas +clients=Asiakkaat +details=Yksityiskohdat +started=Luotu +lastAccess=Viimeksi käytetty +expires=Vanhenee +applications=Sovellukset + +account=Käyttäjätili +federatedIdentity=Yhteinen tunnistaminen +authenticator=Kaksinkertainen kirjautuminen +device-activity=Laiteaktiviteetti +sessions=Istunnot +log=Loki + +application=Sovellus +availableRoles=Saatavilla olevat roolit +availablePermissions=Saatavilla olevat oikeudet +grantedPermissions=Myönnetyt oikeudet +grantedPersonalInfo=Henkilökohtaiset tiedot +additionalGrants=Vaihtoehtoiset oikeudet +action=Toiminto +inResource=in +fullAccess=Täydet oikeudet +offlineToken=Offline Token +revoke=Kumoa oikeudet + +configureAuthenticators=Konfiguroitu kaksivaiheinen kirjautuminen +mobile=Mobiili +totpStep1=Asenna FreeOTP tai Google Authenticator ohjelma laiteellesi. Kummatkin sovellukset ovat saatavilla Google Play ja Apple App Store kaupoissa. +totpStep2=Avaa sovellus ja skannaa QR-koodi tai kirjoita avain. +totpStep3=Täytä saamasi kertaluontoinen koodisi allaolevaan kenttään ja paina Tallenna. +totpStep3DeviceName=Anna laitteelle nimi, jotta voit hallinnoida OTP-laitteitasi. + +totpManualStep2=Avaa sovellus ja syötä koodi +totpManualStep3=Käytä seuraavia asetuksia mikäli sovellus sallii niiden syötön +totpUnableToScan=Ongelmia skannuksessa? +totpScanBarcode=Skannaa viivakoodi? + +totp.totp=Aikapohjainen +totp.hotp=Laskuripohjainen + +totpType=Tyyppi +totpAlgorithm=Algoritmi +totpDigits=Numerot +totpInterval=Intervalli +totpCounter=Laskuri +totpDeviceName=Laitteen nimi + +irreversibleAction=Tätä toimintoa ei voi peruuttaa +deletingImplies=Tilin poisto tarkoittaa sitä, että: +errasingData=Kaikki tietosi poistetaan +loggingOutImmediately=Sinut kirjataan ulos välittömästi +accountUnusable=Tämän sovelluksen käyttö ei myöhemmin enää ole mahdollista tällä käyttäjätilillä + +missingUsernameMessage=Anna käyttäjätunnus. +missingFirstNameMessage=Anna etunimi. +invalidEmailMessage=Virheellinen sähköpostiosoite. +missingLastNameMessage=Anna sukunimi. +missingEmailMessage=Anna sähköpostiosoite. +missingPasswordMessage=Anna salasana. +notMatchPasswordMessage=Salasanat eivät täsmää. +invalidUserMessage=Väärä käyttäjä +updateReadOnlyAttributesRejectedMessage=Vain-luku-ominaisuuden päivittäminen hylätty + +missingTotpMessage=Ole hyvä ja määritä varmennuskoodi. +missingTotpDeviceNameMessage=Ole hyvä ja määritä laitteen nimi. +invalidPasswordExistingMessage=Vanha salasana on virheellinen. +invalidPasswordConfirmMessage=Salasanan vahivistus ei täsmää. +invalidTotpMessage=Väärä varmennuskoodi. + +usernameExistsMessage=Käyttäjänimi on varattu. +emailExistsMessage=Sähköpostiosoite on jo käytössä. + +readOnlyUserMessage=Et voi muokata käyttäjätiliäsi. +readOnlyUsernameMessage=Et voi päivittää käyttäjänimeäsi, koska se on "vain-luku"-tilassa. +readOnlyPasswordMessage=Et voi vaihtaa salasanaa. + +successTotpMessage=Mobiiliautentikointi konfiguroitu. +successTotpRemovedMessage=Mobiiliautentikointi poistettu. + +successGrantRevokedMessage=Lupa peruutettu onnistuneesti. + +accountUpdatedMessage=Käyttäjätiedot päivitetty. +accountPasswordUpdatedMessage=Salasana vaihdettu. + +missingIdentityProviderMessage=Henkilöllisyyden tarjoajaa ei määritetty. +invalidFederatedIdentityActionMessage=Väärä tai puuttuva toiminto. +identityProviderNotFoundMessage=Määritettyä henkilöllisyyden tarjoajaa ei löydy. +federatedIdentityLinkNotActiveMessage=Tämä henkilöllisyys ei ole enää aktiivinen. +federatedIdentityRemovingLastProviderMessage=Et voi poistaa viimeistä yhdistettyä henkilöllisyyttä, koska sinulla ei ole salasanaa. +identityProviderRedirectErrorMessage=Uudelleenohjaus henkilöllisyyden tarjoajaan epäonnistui. +identityProviderRemovedMessage=Henkilöllisyyden tarjoaja poistettu onnistuneesti. +identityProviderAlreadyLinkedMessage=Yhdistetty henkilöllisyys, minkä {0} palautti, on jo linkitetty toiseen käyttäjään. +staleCodeAccountMessage=Sivu vanhentui. Ole hyvä ja yritä vielä kerran. +consentDenied=Suostumus evätty. + +accountDisabledMessage=Tili on poistettu käytöstä, ota yhteyttä järjestelmänvalvojaan. + +accountTemporarilyDisabledMessage=Tili on väliaikaisesti poissa käytöstä, ota yhteyttä järjestelmänvalvojaan tai yritä myöhemmin uudelleen. +invalidPasswordMinLengthMessage=Virheellinen salasana: vähimmäispituus {0}. +invalidPasswordMaxLengthMessage=Virheellinen salasana: maksimipituus {0}. +invalidPasswordMinLowerCaseCharsMessage=Virheellinen salasana: salasanassa tulee olla vähintään {0} pientä kirjainta. +invalidPasswordMinDigitsMessage=Virheellinen salasana: salasanassa tulee olla vähintään {0} numeroa. +invalidPasswordMinUpperCaseCharsMessage=Virheellinen salasana: salasanassa tulee olla vähintään {0} isoa kirjainta. +invalidPasswordMinSpecialCharsMessage=Virheellinen salasana: salasanassa tulee olla vähintään {0} erikoismerkkiä. +invalidPasswordNotUsernameMessage=Virheellinen salasana: salasana ei saa olla sama kuin käyttäjätunnus. +invalidPasswordNotEmailMessage=Virheellinen salasana: ei voi olla sama kuin sähköposti. +invalidPasswordRegexPatternMessage=Virheellinen salasana: fails to match regex pattern(s). +invalidPasswordHistoryMessage=Virheellinen salasana: salasana ei saa olla sama kuin {0} edellistä salasanaasi. +invalidPasswordBlacklistedMessage=Väärä salasana, salasana on lisätty mustalle listalle. +invalidPasswordGenericMessage=Virheellinen salasana: uusi salasana ei täytä salasanavaatimuksia. + +# Authorization +myResources=Minun resurssini +myResourcesSub=Minun resurssini +doDeny=Kiellä +doRevoke=Peru +doApprove=Hyväksy +doRemoveSharing=Poista Jakaminen +doRemoveRequest=Poista Pyyntö +peopleAccessResource=Ihmiset, joilla on pääsy tähän resurssiin +resourceManagedPolicies=Luvat antavat pääsyn tähän resurssiin +resourceNoPermissionsGrantingAccess=Ei lupia, mitkä antavat pääsyn tähän resurssiin +anyAction=Mikä tahansa toiminto +description=Kuvaus +name=Nimi +scopes=Scopes +resource=Resurssi +user=Käyttäjä +peopleSharingThisResource=Ihmiset, jotka jakavat tämän resurssin +shareWithOthers=Jaa toisten kanssa +needMyApproval=Tarvitsee minulta luvan +requestsWaitingApproval=Pyyntösi odottaa hyväksymistä +icon=Ikoni +requestor=Pyynnön esittäjä +owner=Omistaja +resourcesSharedWithMe=Minun kanssani jaetut resurssit +permissionRequestion=Lupapyyntö +permission=Lupa +shares=jaettu +notBeingShared=Tätä resurssia ei ole jaettu. +notHaveAnyResource=Sinulla ei ole mitään resursseja +noResourcesSharedWithYou=Kanssasi ei ole jaettuna resursseja +havePermissionRequestsWaitingForApproval=Sinulla on {0} lupapyyntöä odottamassa hyväksyntää. +clickHereForDetails=Klikkaa tästä nähdäksesi yksityiskohdat. +resourceIsNotBeingShared=Resurssia ei ole jaettu +locale_ca=Català +locale_de=Deutsch +locale_en=English +locale_es=Español +locale_fr=Français +locale_hu=Magyar +locale_it=Italiano +locale_ja=日本語 +locale_lt=Lietuvių +locale_nl=Nederlands +locale_no=Norsk +locale_pl=Polski +locale_pt-BR=Português (Brasil) +locale_ru=Русский +locale_sk=Slovenčina +locale_sv=Svenska +locale_tr=Türkçe +locale_zh-CN=中文简体 +locale_fi=Suomi + +# Applications +applicationName=Nimi +applicationType=Ohjelman tyyppi +applicationInUse=Vain sovelluksen sisäinen käyttö +clearAllFilter=Poista kaikki suodattimet +activeFilters=Aktiiviset suodattimet +filterByName=Suodata nimen mukaan ... +allApps=Kaikki sovellukset +internalApps=Sisäiset sovellukset +thirdpartyApps=Kolmannen osapuolen sovellukset +appResults=Tulokset +clientNotFoundMessage=Asiakasta ei löytynyt. + +# Linked account +authorizedProvider=Valtuutettu palveluntarjoaja +authorizedProviderMessage=Tiliisi linkitetyt valtuutetut palveluntarjoajat +identityProvider=Henkilöllisyyden tarjoaja +identityProviderMessage=Linkittääksesi tilin asettamiesi henkilöllisyyden tarjoajien kanssa +socialLogin=Kirjaudu sosiaalisen median tunnuksilla +userDefined=Käyttäjän määrittämä +removeAccess=Poista käyttöoikeus +removeAccessMessage=Sinun täytyy myöntää käyttöoikeus uudelleen, jos haluat käyttää tätä sovellustiliä. + +#Authenticator +authenticatorStatusMessage=Kaksivaiheinen tunnistautuminen on tällä hetkellä +authenticatorFinishSetUpTitle=Sinun kaksivaiheinen tunnistautuminen +authenticatorFinishSetUpMessage=Joka kerta kun kirjaudut Keycloak-tilillesi, sinua pyydetään antamaan kaksivaiheisen tunnistautumisen koodi. +authenticatorSubTitle=Aseta kaksivaiheinen tunnistautuminen +authenticatorSubMessage=Parantaaksesi tilisi turvallisuutta, ota käyttöön vähintään yksi tarjolla olevista kaksivaiheisen tunnistautumisen tavoista. +authenticatorMobileTitle=Mobiili-tunnistautuminen +authenticatorMobileMessage=Käytä mobiili-todentajaa saadaksesi vahvistuskoodit kaksivaiheiseen tunnistautumiseen +authenticatorMobileFinishSetUpMessage=Tunnistautuminen on sidottu puhelimeesi. +authenticatorActionSetup=Aseta +authenticatorSMSTitle=SMS-koodi +authenticatorSMSMessage=Keycloak lähettää sinulle vahvistuskoodit kaksivaiheista tunnistautumista varten. +authenticatorSMSFinishSetUpMessage=Tekstiviestit lähetetään numeroon +authenticatorDefaultStatus=Oletus +authenticatorChangePhone=Vaihda puhelinnumero +authenticatorBackupCodesTitle=Varmuuskoodit +authenticatorBackupCodesMessage=Hanki 8-numeroiset varmuuskoodisi +authenticatorBackupCodesFinishSetUpMessage=12 varmuuskoodia luotiin tällä kertaa. Jokaisen niistä voi käyttää yhden kerran. + +#Authenticator - Mobile Authenticator setup +authenticatorMobileSetupTitle=Mobiili-todentajan asetukset +smscodeIntroMessage=Syötä puhelinnumerosi ja vahvistuskoodi lähetetään puhelimeesi. +mobileSetupStep1=Asenna todentaja-sovellus puhelimeesi. Listatut sovellukset ovat tuettuna. +mobileSetupStep2=Avaa sovellus ja skannaa viivakoodi: +mobileSetupStep3=Syötä saamasi kertaluontoinen koodi allaolevaan kenttään ja paina Tallenna viimeistelläksesi asetuksen. +scanBarCode=Haluatko skannata viivakoodin? +enterBarCode=Syötä kertaluontoinen koodisi +doCopy=Kopioi +doFinish=Valmis + +#Authenticator - SMS Code setup +authenticatorSMSCodeSetupTitle=SMS-koodin asetukset +chooseYourCountry=Valitse maa +enterYourPhoneNumber=Syötä puhelinnumerosi +sendVerficationCode=Lähetä vahvistuskoodi +enterYourVerficationCode=Syötä vahvistuskoodisi + +#Authenticator - backup Code setup +authenticatorBackupCodesSetupTitle=Varmuuskoodien asetukset +backupcodesIntroMessage=Jos menetät pääsyn puhelimeesi, voit silti kirjautua tilillesi käyttämällä varmuuskoodeja. Pidä ne turvassa ja saatavilla. +realmName=Realm +doDownload=Lataa +doPrint=Tulosta +doCopy=Copy +backupCodesTips-1=Jokaisen varmuuskoodin voi käyttää yhden kerran. +backupCodesTips-2=Nämä koodit on luotu +generateNewBackupCodes=Luo uudet varmuuskoodit +backupCodesTips-3=Kun luot uudet varmuuskoodit, nykyiset varmuuskoodit lakkaavat toimimasta. +backtoAuthenticatorPage=Takaisin Authenticator-sivulle + + +#Resources +resources=Resurssit +sharedwithMe=Jaettu kanssani +share=Jaa +sharedwith=Jaettu heidän kanssa +accessPermissions=Käyttöoikeudet +permissionRequests=Lupapyynnöt +approve=Hyväksy +approveAll=Hyväksy kaikki +people=ihmiset +perPage=per sivu +currentPage=Nykyinen sivu +sharetheResource=Jaa resurssi +group=Ryhmä +selectPermission=Valitse lupa +addPeople=Lisää henkilöitä, joille haluat jakaa resurssisi +addTeam=Lisää tiimi, jolle haluat jakaa resurssisi +myPermissions=Oikeuteni +waitingforApproval=Odottaa hyväksyntää +anyPermission=Mikä tahansa lupa + +# Openshift messages +openshift.scope.user_info=Käyttäjän tiedot +openshift.scope.user_check-access=Käyttäjän käyttöoikeustiedot +openshift.scope.user_full=Täysi käyttöoikeus +openshift.scope.list-projects=Listaa projektit + +error-invalid-value=Väärä arvo. +error-invalid-blank=Ole hyvä ja määritä arvo. +error-empty=Ole hyvä ja määritä arvo. +error-invalid-length=Ominaisuudella {0} täytyy olla pituus väliltä {1} ja {2}. +error-invalid-length-too-short=Ominaisuudella {0} täytyy olla minimipituus {1}. +error-invalid-length-too-long=Ominaisuudella {0} täytyy olla maksimipituus {2}. +error-invalid-email=Väärä sähköpostiosoite. +error-invalid-number=Väärä numero. +error-number-out-of-range=Ominaisuuden {0} täytyy olla numero väliltä {1} ja {2}. +error-number-out-of-range-too-small=Ominaisuudella {0} täytyy olla minimiarvona {1}. +error-number-out-of-range-too-big=Ominaisuudella {0} täytyy olla maksimiarvona {2}. +error-pattern-no-match=Väärä arvo. +error-invalid-uri=Väärä URL. +error-invalid-uri-scheme=Väärä URL:n malli. +error-invalid-uri-fragment=Väärä URL:n osa. +error-user-attribute-required=Ole hyvä ja määritä ominaisuus {0}. +error-invalid-date=Väärä päivämäärä. +error-user-attribute-read-only=Kenttä {0} on "vain luku"-tilassa. +error-username-invalid-character=Käyttäjänimi sisältää vääriä merkkejä. +error-person-name-invalid-character=Nimi sisältää vääriä merkkejä. \ No newline at end of file diff --git a/keycloak-themes/base/account/messages/messages_fr.properties b/keycloak-themes/base/account/messages/messages_fr.properties new file mode 100644 index 0000000..d0b7b1f --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_fr.properties @@ -0,0 +1,180 @@ +# TIPS to encode UTF-8 to ISO +# native2ascii -encoding ISO8859_1 srcFile > dstFile + +doSave=Sauvegarder +doCancel=Annuler +doLogOutAllSessions=D\u00e9connexion de toutes les sessions +doRemove=Supprimer +doAdd=Ajouter +doSignOut=D\u00e9connexion + +editAccountHtmlTitle=\u00c9dition du compte +federatedIdentitiesHtmlTitle=Identit\u00e9s f\u00e9d\u00e9r\u00e9es +accountLogHtmlTitle=Acc\u00e8s au compte +changePasswordHtmlTitle=Changer de mot de passe +sessionsHtmlTitle=Sessions +accountManagementTitle=Gestion du compte Keycloak +authenticatorTitle=Authentification +applicationsHtmlTitle=Applications + +authenticatorCode=Mot de passe unique +email=Courriel +firstName=Pr\u00e9nom +givenName=Pr\u00e9nom +fullName=Nom complet +lastName=Nom +familyName=Nom de famille +password=Mot de passe +passwordConfirm=Confirmation +passwordNew=Nouveau mot de passe +username=Compte +address=Adresse +street=Rue +locality=Ville ou Localit\u00e9 +region=\u00c9tat, Province ou R\u00e9gion +postal_code=Code Postal +country=Pays +emailVerified=Courriel v\u00e9rifi\u00e9 +gssDelegationCredential=Accr\u00e9ditation de d\u00e9l\u00e9gation GSS + +role_admin=Administrateur +role_realm-admin=Administrateur du domaine +role_create-realm=Cr\u00e9er un domaine +role_view-realm=Voir un domaine +role_view-users=Voir les utilisateurs +role_view-applications=Voir les applications +role_view-clients=Voir les clients +role_view-events=Voir les \u00e9v\u00e9nements +role_view-identity-providers=Voir les fournisseurs d''identit\u00e9s +role_manage-realm=G\u00e9rer le domaine +role_manage-users=G\u00e9rer les utilisateurs +role_manage-applications=G\u00e9rer les applications +role_manage-identity-providers=G\u00e9rer les fournisseurs d''identit\u00e9s +role_manage-clients=G\u00e9rer les clients +role_manage-events=G\u00e9rer les \u00e9v\u00e9nements +role_view-profile=Voir le profil +role_manage-account=G\u00e9rer le compte +role_read-token=Lire le jeton d''authentification +role_offline-access=Acc\u00e8s hors-ligne +client_account=Compte +client_security-admin-console=Console d''administration de la s\u00e9curit\u00e9 +client_admin-cli=Admin CLI +client_realm-management=Gestion du domaine +client_broker=Broker + + +requiredFields=Champs obligatoires +allFieldsRequired=Tous les champs sont obligatoires + +backToApplication=« Revenir \u00e0 l''application +backTo=Revenir \u00e0 {0} + +date=Date +event=Ev\u00e9nement +ip=IP +client=Client +clients=Clients +details=D\u00e9tails +started=D\u00e9but +lastAccess=Dernier acc\u00e8s +expires=Expiration +applications=Applications + +account=Compte +federatedIdentity=Identit\u00e9 f\u00e9d\u00e9r\u00e9e +authenticator=Authentification +sessions=Sessions +log=Connexion + +application=Application +availablePermissions=Permissions disponibles +grantedPermissions=Permissions accord\u00e9es +grantedPersonalInfo=Informations personnelles accord\u00e9es +additionalGrants=Droits additionnels +action=Action +inResource=dans +fullAccess=Acc\u00e8s complet +offlineToken=Jeton d''authentification hors-ligne +revoke=R\u00e9voquer un droit + +configureAuthenticators=Authentifications configur\u00e9es. +mobile=T\u00e9l\u00e9phone mobile +totpStep1=Installez une des applications suivantes sur votre mobile +totpStep2=Ouvrez l''application et scannez le code-barres ou entrez la clef. +totpStep3=Entrez le code \u00e0 usage unique fourni par l''application et cliquez sur Sauvegarder pour terminer. + +totpManualStep2=Ouvrez l''application et entrez la clef +totpManualStep3=Utilisez les valeurs de configuration suivante si l''application les autorise +totpUnableToScan=Impossible de scanner ? +totpScanBarcode=Scanner le code-barres ? + +totp.totp=Bas\u00e9 sur le temps +totp.hotp=Bas\u00e9 sur un compteur + +totpType=Type +totpAlgorithm=Algorithme +totpDigits=Chiffres +totpInterval=Intervalle +totpCounter=Compteur + +missingUsernameMessage=Veuillez entrer votre nom d''utilisateur. +missingFirstNameMessage=Veuillez entrer votre pr\u00e9nom. +invalidEmailMessage=Courriel invalide. +missingLastNameMessage=Veuillez entrer votre nom. +missingEmailMessage=Veuillez entrer votre courriel. +missingPasswordMessage=Veuillez entrer votre mot de passe. +notMatchPasswordMessage=Les mots de passe ne sont pas identiques + +missingTotpMessage=Veuillez entrer le code d''authentification. +invalidPasswordExistingMessage=Mot de passe existant invalide. +invalidPasswordConfirmMessage=Le mot de passe de confirmation ne correspond pas. +invalidTotpMessage=Le code d''authentification est invalide. + +usernameExistsMessage=Le nom d''utilisateur existe d\u00e9j\u00e0. +emailExistsMessage=Le courriel existe d\u00e9j\u00e0. + +readOnlyUserMessage=Vous ne pouvez pas mettre \u00e0 jour votre compte car il est en lecture seule. +readOnlyPasswordMessage=Vous ne pouvez pas mettre \u00e0 jour votre mot de passe car votre compte est en lecture seule. + +successTotpMessage=L''authentification via t\u00e9l\u00e9phone mobile est configur\u00e9e. +successTotpRemovedMessage=L''authentification via t\u00e9l\u00e9phone mobile est supprim\u00e9e. + +successGrantRevokedMessage=Droit r\u00e9voqu\u00e9 avec succ\u00e8s. + +accountUpdatedMessage=Votre compte a \u00e9t\u00e9 mis \u00e0 jour. +accountPasswordUpdatedMessage=Votre mot de passe a \u00e9t\u00e9 mis \u00e0 jour. + +missingIdentityProviderMessage=Le fournisseur d''identit\u00e9 n''est pas sp\u00e9cifi\u00e9. +invalidFederatedIdentityActionMessage=Action manquante ou invalide. +identityProviderNotFoundMessage=Le fournisseur d''identit\u00e9 sp\u00e9cifi\u00e9 n''est pas trouv\u00e9. +federatedIdentityLinkNotActiveMessage=Cette identit\u00e9 n''est plus active dor\u00e9navant. +federatedIdentityRemovingLastProviderMessage=Vous ne pouvez pas supprimer votre derni\u00e8re f\u00e9d\u00e9ration d''identit\u00e9 sans avoir de mot de passe sp\u00e9cifi\u00e9. +identityProviderRedirectErrorMessage=Erreur de redirection vers le fournisseur d''identit\u00e9. +identityProviderRemovedMessage=Le fournisseur d''identit\u00e9 a \u00e9t\u00e9 supprim\u00e9 correctement. +identityProviderAlreadyLinkedMessage=Le fournisseur d''identit\u00e9 retourn\u00e9 par {0} est d\u00e9j\u00e0 li\u00e9 \u00e0 un autre utilisateur. + +accountDisabledMessage=Ce compte est d\u00e9sactiv\u00e9, veuillez contacter votre administrateur. + +accountTemporarilyDisabledMessage=Ce compte est temporairement d\u00e9sactiv\u00e9, veuillez contacter votre administrateur ou r\u00e9essayez plus tard. +invalidPasswordMinLengthMessage=Mot de passe invalide: longueur minimale {0}. +invalidPasswordMinLowerCaseCharsMessage=Mot de passe invalide: doit contenir au moins {0} lettre(s) en minuscule. +invalidPasswordMinDigitsMessage=Mot de passe invalide: doit contenir au moins {0} chiffre(s). +invalidPasswordMinUpperCaseCharsMessage=Mot de passe invalide: doit contenir au moins {0} lettre(s) en majuscule. +invalidPasswordMinSpecialCharsMessage=Mot de passe invalide: doit contenir au moins {0} caract\u00e8re(s) sp\u00e9ciaux. +invalidPasswordNotUsernameMessage=Mot de passe invalide: ne doit pas \u00eatre identique au nom d''utilisateur. +invalidPasswordRegexPatternMessage=Mot de passe invalide: ne valide pas l''expression rationnelle. +invalidPasswordHistoryMessage=Mot de passe invalide: ne doit pas \u00eatre \u00e9gal aux {0} derniers mots de passe. + +applicationName=Nom de l''application +update=Mettre \u00e0 jour +status=Statut +authenticatorActionSetup=Configurer +device-activity=Activit\u00e9 des Appareils +accountSecurityTitle=S\u00e9curit\u00e9 du Compte +accountManagementWelcomeMessage=Bienvenue dans la Gestion de Compte Keycloak +personalInfoHtmlTitle=Informations Personnelles +personalInfoIntroMessage=G\u00e9rez vos informations de base +personalSubMessage=G\u00e9rez ces informations de base: votre pr\u00e9nom, nom de famille et email +accountSecurityIntroMessage=G\u00e9rez votre mot de passe et l''acc\u00e8s \u00e0 votre compte +applicationsIntroMessage=Auditez et g\u00e9rez les permissions d''acc\u00e8s des applications aux donn\u00e9es de votre compte +applicationType=Type d''application diff --git a/keycloak-themes/base/account/messages/messages_hu.properties b/keycloak-themes/base/account/messages/messages_hu.properties new file mode 100644 index 0000000..20e9a76 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_hu.properties @@ -0,0 +1,334 @@ +# encoding: utf-8 +doSave=Mentés +doCancel=Mégsem +doLogOutAllSessions=Minden munkamenet kiléptetése +doRemove=Törlés +doAdd=Hozzáadás +doSignOut=Kilépés +doLogIn=Belépés +doLink=Összekötés + +editAccountHtmlTitle=Fiók szerkesztése +personalInfoHtmlTitle=Személyes adatok +federatedIdentitiesHtmlTitle=Összekapcsolt személyazonosságok +accountLogHtmlTitle=Fiók napló +changePasswordHtmlTitle=Jelszó csere +deviceActivityHtmlTitle=Eszköz történet +sessionsHtmlTitle=Munkamenetek +accountManagementTitle=Keycloak Fiók Kezelő +authenticatorTitle=Hitelesítő +applicationsHtmlTitle=Alkalmazások +linkedAccountsHtmlTitle=Összekötött fiókok + +accountManagementWelcomeMessage=Üdvözöljük a Keycloak Fiók Kezelőben +personalInfoIntroMessage=Kezelje az alap személyes adatait +accountSecurityTitle=Fiók biztonság +accountSecurityIntroMessage=Szabályozza jelszó és fiók hozzáféréseit +applicationsIntroMessage=Kezelje alkalmazás jogosultságait, hogy hozzáférjen a fiókjához +resourceIntroMessage=Ossza meg az erőforrásait csapattagjai között +passwordLastUpdateMessage=A jelszava ekkor módosult +updatePasswordTitle=Módosítsa jelszavát +updatePasswordMessageTitle=Kérem válasszon erős jelszót +updatePasswordMessage=Egy erős jelszó számok, betűk és speciális karakterek keveréke, nehéz kitalálni, nem hasonlít valódi (szótári) szóra és csak ehhez a fiókhoz tartozik. +personalSubTitle=Személyes adatai +personalSubMessage=Kezelje alapvető személyes adatait: vezetéknév, keresztnév, email cím + +authenticatorCode=Egyszer használatos kód +email=Email cím +firstName=Keresztnév +givenName=Keresztnév +fullName=Teljes név +lastName=Vezetéknév +familyName=Vezetéknév +password=Jelszó +currentPassword=Jelenlegi jelszó +passwordConfirm=Megerősítés +passwordNew=Új jelszó +username=Felhasználó név +address=Cím +street=Közterület +locality=Település +region=Állam, Tartomány, Megye, Régió +postal_code=Irányítószám +country=Ország +emailVerified=Ellenőrzött email cím +gssDelegationCredential=GSS Delegation Credential + +profileScopeConsentText=Felhasználói fiók +emailScopeConsentText=Email cím +addressScopeConsentText=Cím +phoneScopeConsentText=Telefonszám +offlineAccessScopeConsentText=Offline hozzáférés +samlRoleListScopeConsentText=Szerepköreim +rolesScopeConsentText=Felhasználói szerepkörök + +role_admin=Adminisztrátor +role_realm-admin=Tartomány Adminisztrátor +role_create-realm=Tartomány létrehozása +role_view-realm=Tartományok megtekintése +role_view-users=Felhasználók megtekintése +role_view-applications=Alkalmazások megtekintése +role_view-clients=Kliensek megtekintése +role_view-events=Események megtekintése +role_view-identity-providers=Személyazonosság-kezelők megtekintése +role_view-consent=Jóváhagyó nyilatkozatok megtekintése +role_manage-realm=Tartományok kezelése +role_manage-users=Felhasználók kezelése +role_manage-applications=Alkalmazások kezelése +role_manage-identity-providers=Személyazonosság-kezelők karbantartása +role_manage-clients=Kliensek kezelése +role_manage-events=Események kezelése +role_view-profile=Fiók megtekintése +role_manage-account=Fiók kezelése +role_manage-account-links=Fiók összekötések kezelése +role_manage-consent=Jóváhagyó nyilatkozatok kezelése +role_read-token=Olvasási token +role_offline-access=Offline hozzáférés +role_uma_authorization=Hozzáférés jogosultságokhoz (UMA) +client_account=Fiók +client_account-console=Fiók kezelés +client_security-admin-console=Biztonsági, adminisztrátor fiók kezelés +client_admin-cli=Admin CLI +client_realm-management=Tartomány kezelés +client_broker=Ügynök + + +requiredFields=Kötelezően kitöltendő mezők +allFieldsRequired=Minden mező kitöltése kötelező + +backToApplication=« Vissza az alkalmazásba +backTo=Vissza a {0}-ba/be + +date=Dátum +event=Esemény +ip=IP cím +client=Kliens +clients=Kliensek +details=Részletek +started=Kezdete +lastAccess=Utolsó hozzáférés +expires=Lejárat +applications=Alkalmazások + +account=Fiók +federatedIdentity=Összekapcsolt személyazonosság +authenticator=Hitelesítő +device-activity=Eszköz történet +sessions=Munkamentek +log=Napló + +application=Alkalmazás +availableRoles=Elérhető szerepkörök +grantedPermissions=Engedélyezett jogosultságok +grantedPersonalInfo=Engedélyezett személyes adatok +additionalGrants=További engedélyek +action=Művelet +inResource=itt: +fullAccess=Teljes hozzáférés +offlineToken=Offline Token +revoke=Engedély visszavonása + +configureAuthenticators=Beállított Hitelesítők +mobile=Mobil eszköz +totpStep1=Kérem telepítse az itt felsorolt alkalmazások egyikét a mobil eszközére: +totpStep2=Indítsa el az alkalmazást a mobil eszközén és olvassa be ezt a (QR) kódot: +totpStep3=Adja meg az alkalmazás által generált egyszer használatos kódot majd kattintson a Mentés gombra a beállítás befejezéséhez. +totpStep3DeviceName=Adja meg a mobil eszköz nevét. Ez a későbbiekben segíthet az eszköz azonosításában. + +totpManualStep2=Indítsa el az alkalmazás és adja meg a következő kulcsot: +totpManualStep3=Használja a következő beállításokat, ha az alkalmazása támogatja ezeket: +totpUnableToScan=Nem tud (QR) kódot beolvasni? +totpScanBarcode=Inkább (QR) kódot olvasna be? + +totp.totp=Idő alapú +totp.hotp=Számláló alapú + +totpType=Típus +totpAlgorithm=Algoritmus +totpDigits=Számjegyek +totpInterval=Intervallum +totpCounter=Számláló +totpDeviceName=Eszköz neve + +missingUsernameMessage=Kérem adja meg a felhasználó nevét. +missingFirstNameMessage=Kérem adja meg a keresztnevet. +invalidEmailMessage=Érvénytelen email cím. +missingLastNameMessage=Kérem adja meg a vezetéknevet. +missingEmailMessage=Kérem adja meg az email címet. +missingPasswordMessage=Kérem adja meg a jelszót. +notMatchPasswordMessage=A jelszavak nem egyeznek meg. +invalidUserMessage=Érvénytelen felhasználó + +missingTotpMessage=Kérem adja meg a hitelesítő kódot. +missingTotpDeviceNameMessage=Kérem adja meg az eszköz nevét. +invalidPasswordExistingMessage=Érvénytelen jelenlegi jelszó. +invalidPasswordConfirmMessage=A jelszavak nem egyeznek meg. +invalidTotpMessage=Érvénytelen hitelesítő kód. + +usernameExistsMessage=Ez a felhasználó név már foglalt. +emailExistsMessage=Ez az email cím már foglalt. + +readOnlyUserMessage=A felhasználói fiókja csak olvasható, módosítás nem lehetséges. +readOnlyUsernameMessage=A felhasználó név nem módosítható. +readOnlyPasswordMessage=A felhasználói fiókja csak olvasható, így jelszó módosítás nem lehetséges. + +successTotpMessage=A mobil hitelesítőt beállítottuk. +successTotpRemovedMessage=A mobil hitelesítőt eltávolítottuk. + +successGrantRevokedMessage=Az engedélyt visszavontuk. + +accountUpdatedMessage=Felhasználói fiókját módosítottuk. +accountPasswordUpdatedMessage=Jelszavát módosítottuk. + +missingIdentityProviderMessage=Nincs megadva személyazonosság-kezelő. +invalidFederatedIdentityActionMessage=Érvénytelen, vagy nem létező művelet. +identityProviderNotFoundMessage=A megadott személyazonosság-kezelő nem található. +federatedIdentityLinkNotActiveMessage=Ez a személyazonosság összekötés már nem érvényes. +federatedIdentityRemovingLastProviderMessage=Az utolsó összekapcsolt személyazonosság nem törölhető, mert Ön nem rendelkezik érvényes jelszóval. +identityProviderRedirectErrorMessage=Nem sikerült az átirányítás a személyazonosság-kezelőre. +identityProviderRemovedMessage=A személyazonosság-kezelő összekötést töröltük. +identityProviderAlreadyLinkedMessage=Az összekapcsolt személyazonosság-kezelő által bizotsított személyazonosság már össze van kötve egy másik felhasználói fiókkal. +staleCodeAccountMessage=Az oldal érvényességi ideje lejárt. Kérem próbálja meg újra a kérést. +consentDenied=Jóváhagyó nyilatkozat elutasítva. + +accountDisabledMessage=Felhasználói fiókja inaktív, kérem vegye fel a kapcsolatot az alkalmazás adminisztrátorral. + +accountTemporarilyDisabledMessage=Felhasználói fiókja átmenetileg inaktív, kérem vegye fel a kapcsolatot az alkalmazás adminisztrátorral, vagy próbálkozzon később. +invalidPasswordMinLengthMessage=Érvénytelen jelszó: minimum hossz {0}. +invalidPasswordMinLowerCaseCharsMessage=Érvénytelen jelszó: legalább {0} darab kisbetűt kell tartalmaznia. +invalidPasswordMinDigitsMessage=Érvénytelen jelszó: legalább {0} darab számjegyet kell tartalmaznia. +invalidPasswordMinUpperCaseCharsMessage=Érvénytelen jelszó: legalább {0} darab nagybetűt kell tartalmaznia. +invalidPasswordMinSpecialCharsMessage=Érvénytelen jelszó: legalább {0} darab speciális karaktert (pl. #!$@ stb.) kell tartalmaznia. +invalidPasswordNotUsernameMessage=Érvénytelen jelszó: nem lehet azonos a felhasználó névvel. +invalidPasswordRegexPatternMessage=Érvénytelen jelszó: a jelszó nem illeszkedik a megadott reguláris kifejezés mintára. +invalidPasswordHistoryMessage=Érvénytelen jelszó: nem lehet azonos az utolsó {0} darab, korábban alkalmazott jelszóval. +invalidPasswordBlacklistedMessage=Érvénytelen jelszó: a jelszó tiltó listán szerepel. +invalidPasswordGenericMessage=Érvénytelen jelszó: az új jelszó nem felel meg a jelszó házirendnek. + +# Authorization +myResources=Erőforrásaim +myResourcesSub=Erőforrásaim +doDeny=Tiltás +doRevoke=Visszavonás +doApprove=Jóváhagyás +doRemoveSharing=Megosztás törlése +doRemoveRequest=Kérelem törlése +peopleAccessResource=Az erőforráshoz hozzáférő felhasználók +resourceManagedPolicies=Az erőforrás hozzáféréshez szükséges jogosultságok +resourceNoPermissionsGrantingAccess=Az erőforrás hozzáféréshez nem szükségesek jogosultságok +anyAction=Bármelyik művelet +description=Leírás +name=Név +scopes=Hatókör +resource=Erőforrás +user=Felhasználó +peopleSharingThisResource=Az erőforrást megosztó felhasználók +shareWithOthers=Megosztás más felhasználókkal +needMyApproval=A jóváhagyásom szükséges +requestsWaitingApproval=A kérése jóváhagyásra vár +icon=Ikon +requestor=Kérelmező +owner=Tulajdonos +resourcesSharedWithMe=Velem megosztott erőforrások +permissionRequestion=Jogosultság kérelem +permission=Jogosultság +shares=megosztás(ok) +notBeingShared=Az erőforrás nincs megosztva +notHaveAnyResource=Nincsen erőforrása +noResourcesSharedWithYou=Nincsenek Önnel megosztott erőforrásai +havePermissionRequestsWaitingForApproval=Önnek {0} darab várakozó, jóváhagyandó jogosultság kérése van. +clickHereForDetails=Kattintson ide a részletekért. +resourceIsNotBeingShared=Az erőforrás nincs megosztva + +# Applications +applicationName=Név +applicationType=Alkalmazás típus +#applicationInUse=In-use app only +clearAllFilter=Szűrő mezők törlése +activeFilters=Aktív szűrők +filterByName=Név alapú keresés +allApps=Minden alkalmazás +internalApps=Belső alkalmazások +thirdpartyApps=Harmadik féltől származó alkalmazások +appResults=Eredmény +clientNotFoundMessage=A kliens nem található. + +# Linked account +authorizedProvider=Meghatalmazott szolgáltató +authorizedProviderMessage=A felhasználói fiókjához kötött meghatalmazott szolgáltatók +identityProvider=Személyazonosság-kezelő +identityProviderMessage=Fiókja személyazonosság-kezelőkhöz kötéséhez eddig ezeket a beállításokat adta meg +#socialLogin=Social Login +userDefined=Felhasználó által meghatározott +removeAccess=Hozzáférés törlése +removeAccessMessage=Újra engedélyeznie kell a hozzáférést az alkalmazás ismételt használatához. + +#Authenticator +authenticatorStatusMessage=A kétszintű hitelesítés jelenleg +authenticatorFinishSetUpTitle=Kétszintű hitelesítés +authenticatorFinishSetUpMessage=Minden Keycloak fiók bejelentkezéskor kérni fogunk Öntől egy második szintű hitelesítő kódot. +authenticatorSubTitle=Állítsa be a második szintű hitelesítést +authenticatorSubMessage=Felhasználói fiókjának biztonsági szintjét növelheti, ha legalább egy második szintű hitelesítést is bekapcsol az elérhető eljárások közül. +authenticatorMobileTitle=Mobil eszköz alapú hitelesítés +authenticatorMobileMessage=Mobil eszközön generált ellenőrző kód, mint második szintű hitelesítés. +authenticatorMobileFinishSetUpMessage=A hitelesítés a mobil eszközéhez kötődik. +authenticatorActionSetup=Beállítás +authenticatorSMSTitle=SMS kód +authenticatorSMSMessage=A Keycloak SMS ellenőrző kódot küld a telefonjára (második szintű hitelesítő kód). +authenticatorSMSFinishSetUpMessage=A következő telefonszámokra SMS-t küldünk +authenticatorDefaultStatus=Alapértelmezett +authenticatorChangePhone=Módosítsa telefonszámát + +#Authenticator - Mobile Authenticator setup +authenticatorMobileSetupTitle=Mobil hitelesítő eszköz beállítása +smscodeIntroMessage=Adja meg a telefonszámát, melyre egy ellenőrző kódot küldünk. +mobileSetupStep1=Telepítsen egy hitelesítő alkalmazást mobil eszközére az itt felsorolt, támogatott, alkalmazások közül. +mobileSetupStep2=Indítsa el az alkalmazást és olvassa be a következő (QR) kódot: +mobileSetupStep3=Adja meg a mobil alkalmazás által generált egyszer használatos kódot, majd kattintson a Mentés gombra a beállításhoz. +scanBarCode=Inkább (QR) kódot olvasna be? +enterBarCode=Adja meg az egyszer használatos kódot +doCopy=Másolás +doFinish=Befejezés + +#Authenticator - SMS Code setup +authenticatorSMSCodeSetupTitle=SMS kód beállítása +chooseYourCountry=Válassza ki az országot +enterYourPhoneNumber=Adja meg a telefonszámát +sendVerficationCode=Ellenőrző kód küldése +enterYourVerficationCode=Adja meg az ellenőrző kódot + +#Authenticator - backup Code setup +authenticatorBackupCodesSetupTitle=Tartalék kódok beállítása +realmName=Tartomány +doDownload=Letöltés +doPrint=Nyomtatás +generateNewBackupCodes=Új tartalék kódok generálása +backtoAuthenticatorPage=Vissza a hitelesítő lapra + + +#Resources +resources=Erőforrások +sharedwithMe=Velem megosztott erőforrások +share=Megosztás +sharedwith=Megosztva +accessPermissions=Hozzáférési jogosultságok +permissionRequests=Jogosultság kérések +approve=Jóváhagyás +approveAll=Mindet jóváhagyja +people=felhasználó +perPage=oldalanként +currentPage=Aktuális oldal +sharetheResource=Erőforrás megosztása +group=Csoport +selectPermission=Jogosultság választás +addPeople=Adjon hozzá felhasználókat az erőforrás megosztáshoz +addTeam=Adjon meg csoportot az erőforrás megosztáshoz +myPermissions=Jogosultságaim +waitingforApproval=Jóváhagyásra vár +anyPermission=Bármilyen jogosultság + +# Openshift messages +openshift.scope.user_info=Felhasználó adatok +openshift.scope.user_check-access=Felhasználó hozzáférés adatok +openshift.scope.user_full=Teljes hozzáférés +openshift.scope.list-projects=Projektek listája diff --git a/keycloak-themes/base/account/messages/messages_it.properties b/keycloak-themes/base/account/messages/messages_it.properties new file mode 100644 index 0000000..81c91ba --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_it.properties @@ -0,0 +1,336 @@ +doSave=Salva +doCancel=Annulla +doLogOutAllSessions=Effettua il logout da tutte le sessioni +doRemove=Elimina +doAdd=Aggiungi +doSignOut=Esci +doLogIn=Log In +doLink=Link + + +editAccountHtmlTitle=Modifica Account +personalInfoHtmlTitle=Informazioni personali +federatedIdentitiesHtmlTitle=Identit\u00e0 federate +accountLogHtmlTitle=Log dell''account +changePasswordHtmlTitle=Cambia password +deviceActivityHtmlTitle=Attivit\u00e0 dei dispositivi +sessionsHtmlTitle=Sessioni +accountManagementTitle=Gestione degli account di Keycloak +authenticatorTitle=Autenticatore +applicationsHtmlTitle=Applicazioni +linkedAccountsHtmlTitle=Account collegati + +accountManagementWelcomeMessage=Benvenuto nella gestione degli account di Keycloak +personalInfoIntroMessage=Gestisci le tue informazioni di base +accountSecurityTitle=Sicurezza dell''account +accountSecurityIntroMessage=Controlla la tua password e gli accessi dell''account +applicationsIntroMessage=Traccia e gestisci i permessi delle applicazioni nell''accesso al tuo account +resourceIntroMessage=Condividi le tue risorse tra i membri del team +passwordLastUpdateMessage=La tua password \u00e8 stata aggiornata il +updatePasswordTitle=Aggiornamento password +updatePasswordMessageTitle=Assicurati di scegliere una password robusta +updatePasswordMessage=Una password robusta contiene un misto di numeri, lettere, e simboli. \u00c8 difficile da indovinare, non assomiglia a una parola reale, ed \u00e8 utilizzata solo per questo account. +personalSubTitle=Le tue informazioni personali +personalSubMessage=Gestisce queste informazioni di base: il tuo nome, cognome, e indirizzo email + +authenticatorCode=Codice monouso + +email=Email +firstName=Nome +givenName=Nome +fullName=Nome completo +lastName=Cognome +familyName=Cognome +password=Password +currentPassword=Password attuale +passwordConfirm=Conferma password +passwordNew=Nuova password +username=Username +address=Indirizzo +street=Via +locality=Citt\u00e0 o localit\u00e0 +region=Stato, Provincia, o Regione +postal_code=CAP +country=Paese +emailVerified=Email verificata +gssDelegationCredential=Credenziali delega GSS + +profileScopeConsentText=Profilo utente +emailScopeConsentText=Indirizzo email +addressScopeConsentText=Indirizzo +phoneScopeConsentText=Numero di telefono +offlineAccessScopeConsentText=Accesso offline +samlRoleListScopeConsentText=I miei ruoli +rolesScopeConsentText=Ruoli utente +role_admin=Admin +role_realm-admin=Realm admin +role_create-realm=Crea realm +role_view-realm=Visualizza realm +role_view-users=Visualizza utenti +role_view-applications=Visualizza applicazioni +role_view-clients=Visualizza client +role_view-events=Visualizza eventi +role_view-identity-providers=Visualizza identity provider +role_view-consent=Visualizza consensi +role_manage-realm=Gestisci realm +role_manage-users=Gestisci utenti +role_manage-applications=Gestisci applicazioni +role_manage-identity-providers=Gestisci identity provider +role_manage-clients=Gestisci client +role_manage-events=Gestisci eventi +role_view-profile=Visualizza profilo +role_manage-account=Gestisci account +role_manage-account-links=Gestisci i link dell''account +role_manage-consent=Gestisci consensi +role_read-token=Leggi token +role_offline-access=Accesso offline +role_uma_authorization=Ottieni permessi +client_account=Account +client_account-console=Console account +client_security-admin-console=Console di amministrazione di sicurezza +client_admin-cli=Admin CLI +client_realm-management=Gestione realm +client_broker=Broker + + +requiredFields=Campi obbligatori +allFieldsRequired=Tutti campi obbligatori + +backToApplication=« Torna all''applicazione +backTo=Torna a {0} + +date=Data +event=Evento +ip=IP +client=Client +clients=Client +details=Dettagli +started=Iniziato +lastAccess=Ultimo accesso +expires=Scade +applications=Applicazioni + +account=Account +federatedIdentity=Identit\u00e0 federate +authenticator=Autenticatore +device-activity=Attivit\u00e0 dei dispositivi +sessions=Sessioni +log=Log + +application=Applicazione +availablePermissions=Autorizzazioni disponibili +grantedPermissions=Autorizzazioni concesse +grantedPersonalInfo=Informazioni personali concesse +additionalGrants=Ulteriori concessioni +action=Azione +inResource=in +fullAccess=Accesso completo +offlineToken=Token offline +revoke=Revoca concessione + +configureAuthenticators=Autenticatori configurati +mobile=Dispositivo mobile +totpStep1=Installa una delle seguenti applicazioni sul tuo dispositivo mobile +totpStep2=Apri l''applicazione e scansiona il codice QR +totpStep3=Scrivi il codice monouso fornito dall''applicazione e clicca Salva per completare il setup. +totpStep3DeviceName=Fornisci il nome del dispositivo per aiutarti a gestire i dispositivi di autenticazione. + +totpManualStep2=Apri l''applicazione e scrivi la chiave +totpManualStep3=Usa le seguenti impostazioni se l''applicazione lo consente +totpUnableToScan=Non riesci a scansionare il codice QR? +totpScanBarcode=Vuoi scansionare il codice QR? + +totp.totp=Basato sull''ora +totp.hotp=Basato sul contatore + +totpType=Tipo +totpAlgorithm=Algoritmo +totpDigits=Cifre +totpInterval=Intervallo +totpCounter=Contatore +totpDeviceName=Nome dispositivo + +missingUsernameMessage=Inserisci lo username. +missingFirstNameMessage=Inserisci il nome. +invalidEmailMessage=Indirizzo email non valido. +missingLastNameMessage=Inserisci il cognome. +missingEmailMessage=Inserisci l''indirizzo email. +missingPasswordMessage=Inserisci la password. +notMatchPasswordMessage=Le password non coincidono. +invalidUserMessage=Utente non valido + +missingTotpMessage=Inserisci il codice di autenticazione. +missingTotpDeviceNameMessage=Inserisci il nome del dispositivo di autenticazione. +invalidPasswordExistingMessage=Password esistente non valida. +invalidPasswordConfirmMessage=La password di conferma non coincide. +invalidTotpMessage=Codice di autenticazione non valido. + +usernameExistsMessage=Username gi\u00e0 esistente. +emailExistsMessage=Email gi\u00e0 esistente. + +readOnlyUserMessage=Non puoi aggiornare il tuo account poich\u00E9 \u00e8 in modalit\u00e0 sola lettura. +readOnlyUsernameMessage=Non puoi aggiornare il tuo nome utente poich\u00E9 \u00e8 in modalit\u00e0 sola lettura. +readOnlyPasswordMessage=Non puoi aggiornare il tuo account poich\u00E9 \u00e8 in modalit\u00e0 sola lettura. + +successTotpMessage=Autenticatore mobile configurato. +successTotpRemovedMessage=Autenticatore mobile eliminato. + +successGrantRevokedMessage=Concessione revocata con successo. + +accountUpdatedMessage=Il tuo account \u00e8 stato aggiornato. +accountPasswordUpdatedMessage=La tua password \u00e8 stata aggiornata. + +missingIdentityProviderMessage=Identity provider non specificato. +invalidFederatedIdentityActionMessage=Azione non valida o mancante. +identityProviderNotFoundMessage=L''identity provider specificato non \u00e8 stato trovato. +federatedIdentityLinkNotActiveMessage=Questo identity non \u00e8 pi\u00f9 attivo. +federatedIdentityRemovingLastProviderMessage=Non puoi rimuovere l''ultima identit\u00e0 federata poich\u00E9 non hai pi\u00f9 la password. +identityProviderRedirectErrorMessage=Il reindirizzamento all''identity provider \u00e8 fallito. +identityProviderRemovedMessage=Identity provider eliminato correttamente. +identityProviderAlreadyLinkedMessage=L''identit\u00e0 federata restituita da {0} \u00e8 gi\u00e0 collegata ad un altro utente. +staleCodeAccountMessage=La pagina \u00e8 scaduta. Prova di nuovo. +consentDenied=Consenso negato. + +accountDisabledMessage=Account disabilitato, contatta l''amministratore. + +accountTemporarilyDisabledMessage=L''account \u00e8 temporaneamente disabilitato, contatta l''amministratore o riprova pi\u00f9 tardi. +invalidPasswordMinLengthMessage=Password non valida: lunghezza minima {0}. +invalidPasswordMinLowerCaseCharsMessage=Password non valida: deve contenere almeno {0} caratteri minuscoli. +invalidPasswordMinDigitsMessage=Password non valida: deve contenere almeno {0} numeri. +invalidPasswordMinUpperCaseCharsMessage=Password non valida: deve contenere almeno {0} caratteri maiuscoli. +invalidPasswordMinSpecialCharsMessage=Password non valida: deve contenere almeno {0} caratteri speciali. +invalidPasswordNotUsernameMessage=Password non valida: non deve essere uguale allo username. +invalidPasswordRegexPatternMessage=Password non valida: fallito il match con una o pi\u00f9 espressioni regolari. +invalidPasswordHistoryMessage=Password non valida: non deve essere uguale a una delle ultime {0} password. +invalidPasswordBlacklistedMessage=Password non valida: la password non \u00e8 consentita. +invalidPasswordGenericMessage=Password non valida: la nuova password non rispetta le indicazioni previste. + +# Authorization +myResources=Le mie risorse +myResourcesSub=Le mie risorse +doDeny=Nega +doRevoke=Revoca +doApprove=Approva +doRemoveSharing=Rimuovi condivisione +doRemoveRequest=Rimuovi richiesta +peopleAccessResource=Persone che hanno accesso a questa risorsa +resourceManagedPolicies=Permessi che danno accesso a questa risorsa +resourceNoPermissionsGrantingAccess=Nessun permesso d\u00E0 accesso a questa risorsa +anyAction=Qualsiasi azione +description=Descrizione +name=Nome +scopes=Ambito +resource=Risorsa +user=Utente +peopleSharingThisResource=Persone che condividono questa risorsa +shareWithOthers=Condividi con altri +needMyApproval=Richiede la mia approvazione +requestsWaitingApproval=La tua richiesta è in attesa di approvazione +icon=Icona +requestor=Richiedente +owner=Proprietario +resourcesSharedWithMe=Risorse condivise con me +permissionRequestion=Richiesta di permesso +permission=Permesso +shares=condivisioni +notBeingShared=Questa risorsa non \u00e8 in condivisione. +notHaveAnyResource=Non hai nessuna risorsa +noResourcesSharedWithYou=Non ci sono risorse condivise con te +havePermissionRequestsWaitingForApproval=Hai {0} richiesta(e) di permesso in attesa di approvazione. +clickHereForDetails=Clicca qui per i dettagli. +resourceIsNotBeingShared=La risorsa non \u00e8 in condivisione + +locale_it=Italiano + +# Applications +applicationName=Nome +applicationType=Tipo applicazione +applicationInUse=In-use app only +clearAllFilter=Azzera tutti i filtri +activeFilters=Filtri attivi +filterByName=Filtra per nome ... +allApps=Tutte le applicazioni +internalApps=Applicazioni interne +thirdpartyApps=Applicazioni di terze parti +appResults=Risultati +clientNotFoundMessage=Client non trovato. + +# Linked account +authorizedProvider=Provider autorizzato +authorizedProviderMessage=Provider autorizzati collegati al tuo account +identityProvider=Identity provider +identityProviderMessage=Collegare il tuo account con gli identity provider che hai configurato +socialLogin=Social Login +userDefined=Definito dall''utente +removeAccess=Rimuovi accesso +removeAccessMessage=Devi concedere di nuovo l''accesso, se vuoi utilizzare l''account di questa applicazione. + +#Authenticator +authenticatorStatusMessage=L''autenticazione a due fattori \u00e8 attualmente +authenticatorFinishSetUpTitle=La tua autenticazione a due fattori +authenticatorFinishSetUpMessage=Ogni volta che effettui l''accesso al tuo account Keycloak, ti verr\u00E0 richiesto di fornire il tuo codice di autenticazione a due fattori. +authenticatorSubTitle=Imposta l''autenticazione a due fattori +authenticatorSubMessage=Per incrementare la sicurezza del tuo account, attiva almeno uno dei metodi disponibili per l''autenticazione a due fattori. +authenticatorMobileTitle=Autenticatore mobile +authenticatorMobileMessage=Utilizza l''autenticatore mobile per ottenere i codici di verifica per l''autenticazione a due fattori. +authenticatorMobileFinishSetUpMessage=L''autenticatore \u00e8 stato collegato al tuo telefono. +authenticatorActionSetup=Set up +authenticatorSMSTitle=Codice SMS +authenticatorSMSMessage=Keycloak invier\u00E0 il codice di verifica al tuo telefono per l''autenticazione a due fattori. +authenticatorSMSFinishSetUpMessage=I messaggi di testo vengono inviati a +authenticatorDefaultStatus=Default +authenticatorChangePhone=Cambia numero di telefono + +#Authenticator - Mobile Authenticator setup +authenticatorMobileSetupTitle=Setup autenticatore mobile +smscodeIntroMessage=Inserisci il tuo numero di telefono e ti verr\u00E0 inviato un codice di verifica. +mobileSetupStep1=Installa un''applicazione di autenticazione sul tuo telefono. Sono supportate le applicazioni qui elencate. +mobileSetupStep2=Apri l''applicazione e scansiona il codice QR: +mobileSetupStep3=Inserisci il codice monouso fornito dall''applicazione e clicca Salva per completare il setup. +scanBarCode=Vuoi scansionare il codice QR? +enterBarCode=Inserisci il codice monouso +doCopy=Copia +doFinish=Termina + +#Authenticator - SMS Code setup +authenticatorSMSCodeSetupTitle=Setup codice SMS +chooseYourCountry=Scegli la tua nazione +enterYourPhoneNumber=Inserisci il tuo numero di telefono +sendVerficationCode=Invia il codice di verifica +enterYourVerficationCode=Inserisci il codice di verifica + +#Authenticator - backup Code setup +authenticatorBackupCodesSetupTitle=Setup backup codici +realmName=Realm +doDownload=Download +doPrint=Stampa +generateNewBackupCodes=Genera dei nuovi codici di backup +backtoAuthenticatorPage=Torna alla pagina dell''autenticatore + + +#Resources +resources=Risorse +sharedwithMe=Condiviso con me +share=Condiviso +sharedwith=Condiviso con +accessPermissions=Permessi di accesso +permissionRequests=Richieste di permesso +approve=Approva +approveAll=Approva tutti +people=persone +perPage=per pagina +currentPage=Pagina corrente +sharetheResource=Condividi la risorsa +group=Gruppo +selectPermission=Seleziona permessi +addPeople=Aggiungi persone con le quali condividere la tua risorsa +addTeam=Aggiungi gruppi con i quali condividere la tua risorsa +myPermissions=Miei permessi +waitingforApproval=Attesa dell''approvazione +anyPermission=Qualsiasi permesso + +# Openshift messages +openshift.scope.user_info=Informazioni utente +openshift.scope.user_check-access=Informazioni per l''accesso dell''utente +openshift.scope.user_full=Accesso completo +openshift.scope.list-projects=Elenca progetti diff --git a/keycloak-themes/base/account/messages/messages_ja.properties b/keycloak-themes/base/account/messages/messages_ja.properties new file mode 100644 index 0000000..ec07c92 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_ja.properties @@ -0,0 +1,335 @@ +# encoding: utf-8 +doSave=保存 +doCancel=キャンセル +doLogOutAllSessions=全セッションからログアウト +doRemove=削除 +doAdd=追加 +doSignOut=サインアウト +doLogIn=ログイン +doLink=リンク + + +editAccountHtmlTitle=アカウントの編集 +personalInfoHtmlTitle=個人情報 +federatedIdentitiesHtmlTitle=連携済みアイデンティティー +accountLogHtmlTitle=アカウントログ +changePasswordHtmlTitle=パスワード変更 +deviceActivityHtmlTitle=デバイス・アクティビティー +sessionsHtmlTitle=セッション +accountManagementTitle=Keycloakアカウント管理 +authenticatorTitle=オーセンティケーター +applicationsHtmlTitle=アプリケーション +linkedAccountsHtmlTitle=リンクされたアカウント + +accountManagementWelcomeMessage=Keycloakアカウント管理へようこそ +personalInfoIntroMessage=基本情報を管理する +accountSecurityTitle=アカウント・セキュリティー +accountSecurityIntroMessage=パスワードとアカウント・アクセスを制御する +applicationsIntroMessage=アカウントへアクセスするためにアプリのパーミッションを追跡して管理する +resourceIntroMessage=チームメンバー間でリソースを共有する +passwordLastUpdateMessage=パスワードは更新されました +updatePasswordTitle=パスワードの更新 +updatePasswordMessageTitle=強力なパスワードを選択してください +updatePasswordMessage=強力なパスワードは、数字、文字、記号を含みます。推測が難しく、実在する言葉に似ておらず、このアカウントだけで使用されています。 +personalSubTitle=個人情報 +personalSubMessage=この基本情報を管理してください:名、姓、メール + +authenticatorCode=ワンタイムコード +email=Eメール +firstName=名 +givenName=名 +fullName=氏名 +lastName=姓 +familyName=姓 +password=パスワード +currentPassword=現在のパスワード +passwordConfirm=新しいパスワード(確認) +passwordNew=新しいパスワード +username=ユーザー名 +address=住所 +street=番地 +locality=市区町村 +region=都道府県 +postal_code=郵便番号 +country=国 +emailVerified=確認済みEメール +gssDelegationCredential=GSS委譲クレデンシャル + +profileScopeConsentText=ユーザー・プロファイル +emailScopeConsentText=メールアドレス +addressScopeConsentText=アドレス +phoneScopeConsentText=電話番号 +offlineAccessScopeConsentText=オフライン・アクセス +samlRoleListScopeConsentText=ロール +rolesScopeConsentText=ユーザーロール + +role_admin=管理者 +role_realm-admin=レルム管理者 +role_create-realm=レルムの作成 +role_view-realm=レルムの参照 +role_view-users=ユーザーの参照 +role_view-applications=アプリケーションの参照 +role_view-clients=クライアントの参照 +role_view-events=イベントの参照 +role_view-identity-providers=アイデンティティー・プロバイダーの参照 +role_view-consent=同意の参照 +role_manage-realm=レルムの管理 +role_manage-users=ユーザーの管理 +role_manage-applications=アプリケーションの管理 +role_manage-identity-providers=アイデンティティー・プロバイダーの管理 +role_manage-clients=クライアントの管理 +role_manage-events=イベントの管理 +role_view-profile=プロファイルの参照 +role_manage-account=アカウントの管理 +role_manage-account-links=アカウントリンクの管理 +role_manage-consent=同意の管理 +role_read-token=トークンの参照 +role_offline-access=オフライン・アクセス +role_uma_authorization=パーミッションの取得 +client_account=アカウント +client_account-console=アカウント・コンソール +client_security-admin-console=セキュリティー管理コンソール +client_admin-cli=管理CLI +client_realm-management=レルム管理 +client_broker=ブローカー + + +requiredFields=必須 +allFieldsRequired=全ての入力項目が必須 + +backToApplication=« アプリケーションに戻る +backTo={0}に戻る + +date=日付 +event=イベント +ip=IP +client=クライアント +clients=クライアント +details=詳細 +started=開始 +lastAccess=最終アクセス +expires=有効期限 +applications=アプリケーション + +account=アカウント +federatedIdentity=連携済みアイデンティティー +authenticator=オーセンティケーター +device-activity=デバイス・アクティビティー +sessions=セッション +log=ログ + +application=アプリケーション +availableRoles=利用可能なロール +grantedPermissions=許可されたパーミッション +grantedPersonalInfo=許可された個人情報 +additionalGrants=追加の許可 +action=アクション +inResource=in +fullAccess=フルアクセス +offlineToken=オフライン・トークン +revoke=許可の取り消し + +configureAuthenticators=設定済みのオーセンティケーター +mobile=モバイル +totpStep1=モバイルに以下のアプリケーションのいずれかをインストールしてください。 +totpStep2=アプリケーションを開き、バーコードをスキャンしてください。 +totpStep3=アプリケーションで提供されたワンタイムコードを入力して保存をクリックし、セットアップを完了してください。 +totpStep3DeviceName=OTPデバイスの管理に役立つようなデバイス名を指定してください。 + +totpManualStep2=アプリケーションを開き、キーを入力してください。 +totpManualStep3=アプリケーションが設定できる場合は、次の設定値を使用してください。 +totpUnableToScan=スキャンできませんか? +totpScanBarcode=バーコードをスキャンしますか? + +totp.totp=時間ベース +totp.hotp=カウンターベース + +totpType=タイプ +totpAlgorithm=アルゴリズム +totpDigits=数字 +totpInterval=間隔 +totpCounter=カウンター +totpDeviceName=デバイス名 + +missingUsernameMessage=ユーザー名を入力してください。 +missingFirstNameMessage=名を入力してください。 +invalidEmailMessage=無効なメールアドレスです。 +missingLastNameMessage=姓を入力してください。 +missingEmailMessage=Eメールを入力してください。 +missingPasswordMessage=パスワードを入力してください。 +notMatchPasswordMessage=パスワードが一致していません。 +invalidUserMessage=無効なユーザーです。 + +missingTotpMessage=オーセンティケーター・コードを入力してください。 +missingTotpDeviceNameMessage=デバイス名を指定してください。 +invalidPasswordExistingMessage=既存のパスワードが不正です。 +invalidPasswordConfirmMessage=新しいパスワード(確認)と一致していません。 +invalidTotpMessage=無効なオーセンティケーター・コードです。 + +usernameExistsMessage=既に存在するユーザー名です。 +emailExistsMessage=既に存在するEメールです。 + +readOnlyUserMessage=読み取り専用のため、アカウントを更新することはできません。 +readOnlyUsernameMessage=読み取り専用のため、ユーザー名を更新することはできません。 +readOnlyPasswordMessage=読み取り専用のため、パスワードを更新することはできません。 + +successTotpMessage=モバイル・オーセンティケーターが設定されました。 +successTotpRemovedMessage=モバイル・オーセンティケーターが削除されました。 + +successGrantRevokedMessage=許可が正常に取り消しされました。 + +accountUpdatedMessage=アカウントが更新されました。 +accountPasswordUpdatedMessage=パスワードが更新されました。 + +missingIdentityProviderMessage=アイデンティティー・プロバイダーが指定されていません。 +invalidFederatedIdentityActionMessage=無効または存在しないアクションです。 +identityProviderNotFoundMessage=指定されたアイデンティティー・プロバイダーが見つかりません。 +federatedIdentityLinkNotActiveMessage=このアイデンティティーは有効ではありません。 +federatedIdentityRemovingLastProviderMessage=パスワードがないため、最後の連携済みアイデンティティーが削除できません。 +identityProviderRedirectErrorMessage=アイデンティティー・プロバイダーへのリダイレクトに失敗しました。 +identityProviderRemovedMessage=アイデンティティー・プロバイダーが正常に削除されました。 +identityProviderAlreadyLinkedMessage={0}から返された連携済みアイデンティティーは既に他のユーザーに関連付けされています。 +staleCodeAccountMessage=有効期限切れです。再度お試しください。 +consentDenied=同意が拒否されました。 + +accountDisabledMessage=アカウントが無効です。管理者に連絡してください。 + +accountTemporarilyDisabledMessage=アカウントが一時的に無効です。管理者に連絡するか、しばらく時間をおいてから再度お試しください。 +invalidPasswordMinLengthMessage=無効なパスワード: 最小{0}の長さが必要です。 +invalidPasswordMinLowerCaseCharsMessage=無効なパスワード: 少なくとも{0}文字の小文字を含む必要があります。 +invalidPasswordMinDigitsMessage=無効なパスワード: 少なくとも{0}文字の数字を含む必要があります。 +invalidPasswordMinUpperCaseCharsMessage=無効なパスワード:少なくとも{0}文字の大文字を含む必要があります。 +invalidPasswordMinSpecialCharsMessage=無効なパスワード: 少なくとも{0}文字の特殊文字を含む必要があります。 +invalidPasswordNotUsernameMessage=無効なパスワード: ユーザー名と同じパスワードは禁止されています。 +invalidPasswordRegexPatternMessage=無効なパスワード: 正規表現パターンと一致しません。 +invalidPasswordHistoryMessage=無効なパスワード: 最近の{0}パスワードのいずれかと同じパスワードは禁止されています。 +invalidPasswordBlacklistedMessage=無効なパスワード: パスワードがブラックリストに含まれています。 +invalidPasswordGenericMessage=無効なパスワード: 新しいパスワードはパスワード・ポリシーと一致しません。 + +# Authorization +myResources=マイリソース +myResourcesSub=マイリソース +doDeny=拒否 +doRevoke=取り消し +doApprove=承認 +doRemoveSharing=共有の削除 +doRemoveRequest=要求の削除 +peopleAccessResource=このリソースにアクセスできる人 +resourceManagedPolicies=このリソースへのアクセスを許可するパーミッション +resourceNoPermissionsGrantingAccess=このリソースへのアクセスを許可する権限はありません +anyAction=任意のアクション +description=説明 +name=名前 +scopes=スコープ +resource=リソース +user=ユーザー +peopleSharingThisResource=このリソースを共有している人 +shareWithOthers=他人と共有 +needMyApproval=承認が必要 +requestsWaitingApproval=承認待ちの要求 +icon=アイコン +requestor=要求者 +owner=オーナー +resourcesSharedWithMe=共有しているリソース +permissionRequestion=パーミッションの要求 +permission=パーミッション +shares=共有(複数) +notBeingShared=このリソースは共有されていません。 +notHaveAnyResource=リソースがありません。 +noResourcesSharedWithYou=共有しているリソースはありません +havePermissionRequestsWaitingForApproval=承認を待っている{0}個のパーミッションの要求があります。 +clickHereForDetails=詳細はこちらをクリックしてください。 +resourceIsNotBeingShared=リソースは共有されていません。 + +# Applications +applicationName=名前 +applicationType=アプリケーション・タイプ +applicationInUse=使用中のアプリケーションのみ +clearAllFilter=すべてのフィルターをクリア +activeFilters=アクティブなフィルター +filterByName=名前でフィルタリング... +allApps=すべてのアプリケーション +internalApps=内部アプリケーション +thirdpartyApps=サードパーティーのアプリケーション +appResults=結果 +clientNotFoundMessage=クライアントが見つかりません。 + +# Linked account +authorizedProvider=認可済みプロバイダー +authorizedProviderMessage=アカウントにリンクされた認可済みプロバイダー +identityProvider=アイデンティティー・プロバイダー +identityProviderMessage=アカウントと設定したアイデンティティー・プロバイダーをリンクするには +socialLogin=ソーシャル・ログイン +userDefined=ユーザー定義 +removeAccess=アクセス権の削除 +removeAccessMessage=このアプリ・アカウントを使用する場合は、アクセス権を再度付与する必要があります。 + +#Authenticator +authenticatorStatusMessage=2要素認証は現在 +authenticatorFinishSetUpTitle=あなたの2要素認証 +authenticatorFinishSetUpMessage=Keycloakアカウントにサインインするたびに、2要素認証コードを入力するように求められます。 +authenticatorSubTitle=2要素認証を設定する +authenticatorSubMessage=アカウントのセキュリティーを強化するには、利用可能な2要素認証の方式のうち少なくとも1つを有効にします。 +authenticatorMobileTitle=モバイル・オーセンティケーター +authenticatorMobileMessage=モバイル・オーセンティケーターを使用して、2要素認証として確認コードを取得します。 +authenticatorMobileFinishSetUpMessage=オーセンティケーターはあなたの携帯電話にバインドされています。 +authenticatorActionSetup=セットアップ +authenticatorSMSTitle=SMSコード +authenticatorSMSMessage=Keycloakは、2要素認証として確認コードを携帯電話に送信します。 +authenticatorSMSFinishSetUpMessage=テキスト・メッセージが次の電話番号宛に送信されます: +authenticatorDefaultStatus=デフォルト +authenticatorChangePhone=電話番号の変更 + +#Authenticator - Mobile Authenticator setup +authenticatorMobileSetupTitle=モバイル・オーセンティケーターのセットアップ +smscodeIntroMessage=電話番号を入力すると、確認コードがあなたの電話に送信されます。 +mobileSetupStep1=携帯電話にオーセンティケーター・アプリケーションをインストールします。ここにリストされているアプリケーションがサポートされています。 +mobileSetupStep2=アプリケーションを開き、バーコードをスキャンしてください。 +mobileSetupStep3=アプリケーションから提供されたワンタイムコードを入力し、保存をクリックしてセットアップを終了します。 +scanBarCode=バーコードをスキャンしますか? +enterBarCode=ワンタイムコードを入力してください +doCopy=コピー +doFinish=終了 + +#Authenticator - SMS Code setup +authenticatorSMSCodeSetupTitle=SMSコードのセットアップ +chooseYourCountry=国を選んでください +enterYourPhoneNumber=電話番号を入力してください +sendVerficationCode=確認コードの送信 +enterYourVerficationCode=確認コードを入力してください + +#Authenticator - backup Code setup +authenticatorBackupCodesSetupTitle=バックアップ・コードのセットアップ +realmName=レルム +doDownload=ダウンロード +doPrint=印刷 +generateNewBackupCodes=新しいバックアップ・コードを生成する +backtoAuthenticatorPage=オーセンティケーター・ページに戻る + + +#Resources +resources=リソース +sharedwithMe=私と共有 +share=共有 +sharedwith=共有 +accessPermissions=アクセス・パーミッション +permissionRequests=パーミッションの要求 +approve=承認 +approveAll=すべて承認 +people=人 +perPage=1ページあたり +currentPage=現在のページ +sharetheResource=リソースの共有 +group=グループ +selectPermission=パーミッションを選択 +addPeople=あなたのリソースを共有する人を追加 +addTeam=あなたのリソースを共有するチームを追加 +myPermissions=私のパーミッション +waitingforApproval=承認待ち +anyPermission=任意のパーミッション + +# Openshift messages +openshift.scope.user_info=ユーザー情報 +openshift.scope.user_check-access=ユーザーアクセス情報 +openshift.scope.user_full=フルアクセス +openshift.scope.list-projects=プロジェクトの一覧表示 \ No newline at end of file diff --git a/keycloak-themes/base/account/messages/messages_lt.properties b/keycloak-themes/base/account/messages/messages_lt.properties new file mode 100644 index 0000000..d6e4016 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_lt.properties @@ -0,0 +1,154 @@ +# encoding: utf-8 +doSave=Saugoti +doCancel=Atšaukti + +doLogOutAllSessions=Atjungti visas sesijas +doRemove=Šalinti +doAdd=Pridėti +doSignOut=Atsijungti + +editAccountHtmlTitle=Redaguoti paskyrą +federatedIdentitiesHtmlTitle=Susietos paskyros +accountLogHtmlTitle=Paskyros žurnalas +changePasswordHtmlTitle=Keisti slaptažodį +sessionsHtmlTitle=Prisijungimo sesijos +accountManagementTitle=Keycloak Naudotojų Administravimas +authenticatorTitle=Autentifikatorius +applicationsHtmlTitle=Programos + +authenticatorCode=Vienkartinis kodas +email=El. paštas +firstName=Vardas +givenName=Pavardė +fullName=Pilnas vardas +lastName=Pavardė +familyName=Pavardė +password=Slaptažodis +passwordConfirm=Pakartotas slaptažodis +passwordNew=Naujas slaptažodis +username=Naudotojo vardas +address=Adresas +street=Gatvė +locality=Miestas arba vietovė +region=Rajonas +postal_code=Pašto kodas +country=Šalis +emailVerified=El. pašto adresas patvirtintas +gssDelegationCredential=GSS prisijungimo duomenų delegavimas + +role_admin=Administratorius +role_realm-admin=Srities administravimas +role_create-realm=Kurti sritį +role_view-realm=Peržiūrėti sritį +role_view-users=Peržiūrėti naudotojus +role_view-applications=Peržiūrėti programas +role_view-clients=Peržiūrėti klientines programas +role_view-events=Peržiūrėti įvykių žurnalą +role_view-identity-providers=Peržiūrėti tapatybės teikėjus +role_manage-realm=Valdyti sritis +role_manage-users=Valdyti naudotojus +role_manage-applications=Valdyti programas +role_manage-identity-providers=Valdyti tapatybės teikėjus +role_manage-clients=Valdyti programas +role_manage-events=Valdyti įvykius +role_view-profile=Peržiūrėti paskyrą +role_manage-account=Valdyti paskyrą +role_read-token=Skaityti prieigos rakšą +role_offline-access=Darbas neprisijungus +role_uma_authorization=Įgauti UMA autorizavimo teises +client_account=Paskyra +client_security-admin-console=Saugumo administravimo konsolė +client_admin-cli=Administravimo CLI +client_realm-management=Srities valdymas +client_broker=Tarpininkas + + +requiredFields=Privalomi laukai +allFieldsRequired=Visi laukai yra privalomi + +backToApplication=« Grįžti į programą +backTo=Atgal į {0} + +date=Data +event=Įvykis +ip=IP +client=Klientas +clients=Klientai +details=Detaliau +started=Sukūrimo laikas +lastAccess=Vėliausia prieiga +expires=Galioja iki +applications=Programos + +account=Paskyra +federatedIdentity=Susieta tapatybė +authenticator=Autentifikatorius +sessions=Sesijos +log=Įvykiai + +application=Programa +availablePermissions=Galimos teisės +grantedPermissions=Įgalintos teisės +grantedPersonalInfo=Įgalinta asmeninė informacija +additionalGrants=Papildomi įgaliojimai +action=Veiksmas +inResource=yra +fullAccess=Pilna prieiga +offlineToken=Režimo neprisijungus raktas (token) +revoke=Atšaukti įgaliojimą + +configureAuthenticators=Sukonfigūruotas autentifikatorius +mobile=Mobilus +totpStep1=Įdiekite FreeOTP arba Google Authenticator savo įrenginyje. Programėlės prieinamos Google Play ir Apple App Store. +totpStep2=Atidarykite programėlę ir nuskenuokite barkodą arba įveskite kodą. +totpStep3=Įveskite programėlėje sugeneruotą vieną kartą galiojantį kodą ir paspauskite Saugoti norėdami prisijungti. + +missingUsernameMessage=Prašome įvesti naudotojo vardą. +missingFirstNameMessage=Prašome įvesti vardą. +invalidEmailMessage=Neteisingas el. pašto adresas. +missingLastNameMessage=Prašome įvesti pavardę. +missingEmailMessage=Prašome įvesti el. pašto adresą. +missingPasswordMessage=Prašome įvesti slaptažodį. +notMatchPasswordMessage=Slaptažodžiai nesutampa. + +missingTotpMessage=Prašome įvesti autentifikacijos kodą. +invalidPasswordExistingMessage=Neteisingas dabartinis slaptažodis. +invalidPasswordConfirmMessage=Pakartotas slaptažodis nesutampa. +invalidTotpMessage=Neteisingas autentifikacijos kodas. + +usernameExistsMessage=Toks naudotojas jau egzistuoja. +emailExistsMessage=El. pašto adresas jau egzistuoja. + +readOnlyUserMessage=Tik skaitymui sukonfigūruotos paskyros duomenų atnaujinti neleidžiama. +readOnlyPasswordMessage=Tik skaitymui sukonfigūruotos paskyros slaptažodžio atnaujinti neleidžiama. + +successTotpMessage=Mobilus autentifikatorius sukonfigūruotas. +successTotpRemovedMessage=Mobilus autentifikatorius pašalintas. + +successGrantRevokedMessage=Įgalinimas pašalintas sėkmingai. + +accountUpdatedMessage=Jūsų paskyros duomenys sėkmingai atnaujinti. +accountPasswordUpdatedMessage=Jūsų paskyros slaptažodis pakeistas. + +missingIdentityProviderMessage=Nenurodytas tapatybės teikėjas. +invalidFederatedIdentityActionMessage=Neteisingas arba nežinomas veiksmas. +identityProviderNotFoundMessage=Nurodytas tapatybės teikėjas nerastas. +federatedIdentityLinkNotActiveMessage=Nurodyta susieta tapatybė neaktyvi. +federatedIdentityRemovingLastProviderMessage=Jūs negalite pašalinti paskutinio tapatybės teikėjo sąsajos, nes Jūs neturite nusistatę paskyros slaptažodžio. +identityProviderRedirectErrorMessage=Klaida nukreipiant į tapatybės teikėjo puslapį. +identityProviderRemovedMessage=Tapatybės teikėjas sėkmingai pašalintas. +identityProviderAlreadyLinkedMessage=Susieta tapatybė iš {0} jau susieta su kita paskyra. +staleCodeAccountMessage=Puslapio galiojimas baigėsi. Bandykite dar kartą. +consentDenied=Prieiga draudžiama. + +accountDisabledMessage=Paskyros galiojimas sustabdytas, kreipkitės į administratorių. + +accountTemporarilyDisabledMessage=Paskyros galiojimas laikinai sustabdytas. Kreipkitės į administratorių arba pabandykite vėliau. +invalidPasswordMinLengthMessage=Per trumpas slaptažodis: mažiausias ilgis {0}. +invalidPasswordMinLowerCaseCharsMessage=Neteisingas slaptažodis: privaloma įvesti {0} mažąją raidę. +invalidPasswordMinDigitsMessage=Neteisingas slaptažodis: privaloma įvesti {0} skaitmenį. +invalidPasswordMinUpperCaseCharsMessage=Neteisingas slaptažodis: privaloma įvesti {0} didžiąją raidę. +invalidPasswordMinSpecialCharsMessage=Neteisingas slaptažodis: privaloma įvesti {0} specialų simbolį. +invalidPasswordNotUsernameMessage=Neteisingas slaptažodis: slaptažodis negali sutapti su naudotojo vardu. +invalidPasswordRegexPatternMessage=Neteisingas slaptažodis: slaptažodis netenkina regex taisyklės(ių). +invalidPasswordHistoryMessage=Neteisingas slaptažodis: slaptažodis negali sutapti su prieš tai buvusiais {0} slaptažodžiais. \ No newline at end of file diff --git a/keycloak-themes/base/account/messages/messages_lv.properties b/keycloak-themes/base/account/messages/messages_lv.properties new file mode 100644 index 0000000..7401ec6 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_lv.properties @@ -0,0 +1,197 @@ +# encoding: utf-8 +doSave=Saglabāt +doCancel=Atcelt +doLogOutAllSessions=Izlogoties no visām sesijām +doRemove=Noņemt +doAdd=Pievienot +doSignOut=Atslēgties +doLogIn=Pieslēgties +doLink=Savienot + + +editAccountHtmlTitle=Rediģēt kontu +personalInfoHtmlTitle=Personiskā informācija +federatedIdentitiesHtmlTitle=Federatīvās identitātes +accountLogHtmlTitle=Konta žurnāls +changePasswordHtmlTitle=Mainīt paroli +deviceActivityHtmlTitle=Ierīces aktivitāte +sessionsHtmlTitle=Sesijas +accountManagementTitle=Keycloak konta pārvaldība +authenticatorTitle=Autentifikators +applicationsHtmlTitle=Lietojumprogrammas +linkedAccountsHtmlTitle=Savienotie konti + +accountManagementWelcomeMessage=Laipni lūgti Keycloak konta pārvaldniekā +personalInfoIntroMessage=Pārvaldīt pamatinformāciju +accountSecurityTitle=Konta drošība +accountSecurityIntroMessage=Pārvaldi savu paroli un konta pieeju +applicationsIntroMessage=Uzraugi un pārvaldi lietojumprogrammas pieeju savam kontam +resourceIntroMessage= +passwordLastUpdateMessage=Tava parole tika atjaunota +updatePasswordTitle=Atjaunot paroli +updatePasswordMessageTitle=Izvēlies drošu parolu +updatePasswordMessage=Droša parole satur ciparus, burtus un simbolus. To ir grūti uzminēt, tā nesatur reālus vārdus un tiek izmantota tikai šim kontam. +personalSubTitle=Tava personīgā informācija +personalSubMessage=Pārvaldi savu pamatinformāciju: vārdu, uzvārdu un e-pastu + +authenticatorCode=Vienreizējā parole +email=E-pasts +firstName=Vārds +givenName=Vārds +fullName=Pilns vārds +lastName=Uzvārds +familyName=Uzvārds +password=Parole +currentPassword=Pašreizējā parole +passwordConfirm=Parole atkārtoti +passwordNew=Jauna parole +username=Lietotājvārds +address=Adrese +street=Iela +locality=Pilsēta +region=Novads vai reģions +postal_code=Pasta indegs +country=Valsts +emailVerified=E-pasts apstiprināts +gssDelegationCredential=GSS delegācijas atslēga + +profileScopeConsentText=Lietotāja profils +emailScopeConsentText=E-pasta adrese +addressScopeConsentText=Adrese +phoneScopeConsentText=Tālrunis +offlineAccessScopeConsentText=Bezsaustes piekļuve +samlRoleListScopeConsentText=Manas lomas +rolesScopeConsentText=Lietotāju lomas + +role_admin=Administrators +role_realm-admin=Realm administrators +role_create-realm=Izveidot realm +role_view-realm=Skatīt realm +role_view-users=Skatīt lietoājus +role_view-applications=Skatīt lietojumprogrammas +role_view-clients=Skatīt klientus +role_view-events=Skatīt notikumus +role_view-identity-providers=Skatīt identitātes sniedzējus +role_manage-realm=Pārvaldīt realm +role_manage-users=Pārvaldīt lietotājus +role_manage-applications=Pārvaldīt lietojumprogrammas +role_manage-identity-providers=Pārvaldīt identitātes sniedzējus +role_manage-clients=Pārvaldīt klientus +role_manage-events=Pārvaldīt notikumus +role_view-profile=Skatīt profilu +role_manage-account=Pārvaldīt kontu +role_manage-account-links=Pārvaldīt konta saites +role_read-token=Lasīt talonu (token) +role_offline-access=Bezsaistes piekļuve +role_uma_authorization=Iegūt atļaujas +client_account=Konts +client_security-admin-console=Drošības administrācijas konsole +client_admin-cli=Administrācijas CLI +client_realm-management=Realm pārvaldība +client_broker=Brokeris + + +requiredFields=Obligātie lauki +allFieldsRequired=Visi lauki ir obligāti + +backToApplication=« Atpakaļ uz lietojumprogrammu +backTo=Atpakaļ uz {0} + +date=Datums +event=Notikums +ip=IP +client=Klients +clients=Klienti +details=Detaļas +started=Uzsākta +lastAccess=Pēdējā piekļuve +expires=Beidzas +applications=Lietojumprogrammas + +account=Konts +federatedIdentity=Federatīvā identitāte +authenticator=Autentifikators +device-activity=Ierīces aktivitāte +sessions=Sesijas +log=Žurnāls + +application=Lietojumprogramma +availableRoles=Pieejamās lomas +grantedPermissions=Piešķirtās atļaujas +grantedPersonalInfo=Pieškirtā personālā informācija +additionalGrants=Papildus atļaujas +action=Darbība +inResource=iekš +fullAccess=Pilna piekļuve +offlineToken=Bezsaistes talons (token) +revoke=Atsaukt atļauju + +missingUsernameMessage=Lūdzu norādi lietotājvārdu. +missingFirstNameMessage=Lūdzu norādi vārdu. +invalidEmailMessage=Nekorekta e-pasta adrese. +missingLastNameMessage=Lūdzu norādi uzvārdu. +missingEmailMessage=Lūdzu norādi e-pastu. +missingPasswordMessage=Lūdzu norādi paroli. +notMatchPasswordMessage=Paroles nesakrīt. +invalidUserMessage=Nekorekts lietotājs + +usernameExistsMessage=Lietotājvārds jau eksistē. +emailExistsMessage=E-pasts jau eksistē. + +# Authorization +myResources=Mani resursi +myResourcesSub=Mani resursi +doDeny=Aizliegt +doRevoke=Atsaukt +doApprove=Apstiprināt +doRemoveSharing=Noņemt dalīšanos +doRemoveRequest=Noņemt pieprasījumu +peopleAccessResource=Cilvēki ar pieeju šim resursam +resourceManagedPolicies=Atļaujas šim resursam +resourceNoPermissionsGrantingAccess=Nav atļauju šim resursam +anyAction=Jebkura darbība +description=Apraksts +name=Nosaukums +scopes=Jomas (scopes) +resource=Resurss +user=Lietotājs +peopleSharingThisResource=Cilveki, kas dalās ar šo resursu +shareWithOthers=Dalīties ar citiem +needMyApproval=Nepieciešams mans apstiprinājums +requestsWaitingApproval=Tavi pieprasījumi, kas gaida apstiprinājumu +icon=Ikona +requestor=Pieprasītājs +owner=Īpašnieks +resourcesSharedWithMe=Resursi, kuri tiek dalīti ar mani +permissionRequestion=Atļaujas pieprasījums +permission=Atļauja +shares=share(s) + +locale_ca=Català +locale_de=Deutsch +locale_en=English +locale_es=Español +locale_fr=Français +locale_it=Italian +locale_ja=日本語 +locale_nl=Nederlands +locale_no=Norsk +locale_lt=Lietuvių +locale_lt=Latviešu +locale_pt-BR=Português (Brasil) +locale_ru=Русский +locale_sk=Slovenčina +locale_sv=Svenska +locale_zh-CN=中文简体 + +# Applications +applicaitonName=Nosaukums +applicationType=Lietojumprogrammas tips +applicationInUse=Tikai aktīvās lietojumprogrammas +clearAllFilter=Noņemt visus filtrus +activeFilters=Aktīvie filtri +filterByName=Filtrēt pēc nosaukuma ... +allApps=Visas lietojumprogrammas +internalApps=Iekšējās lietojumprogrammas +thirdpartyApps=Trešās puses lietojumprogrammas +appResults=Rezultāti diff --git a/keycloak-themes/base/account/messages/messages_nl.properties b/keycloak-themes/base/account/messages/messages_nl.properties new file mode 100644 index 0000000..80e5503 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_nl.properties @@ -0,0 +1,133 @@ +doSave=Opslaan +doCancel=Annuleer +doLogOutAllSessions=Alle sessies uitloggen +doRemove=Verwijder +doAdd=Voeg toe +doSignOut=Afmelden +editAccountHtmlTitle=Bewerk account +federatedIdentitiesHtmlTitle=Federated Identities +accountLogHtmlTitle=Account log +changePasswordHtmlTitle=Verander wachtwoord +sessionsHtmlTitle=Sessies +accountManagementTitle=Keycloak Accountbeheer +authenticatorTitle=Authenticator +applicationsHtmlTitle=Toepassingen +authenticatorCode=Eenmalige code +email=E-mailadres +firstName=Voornaam +givenName=Voornaam +fullName=Volledige naam +lastName=Achternaam +familyName=Achternaam +password=Wachtwoord +passwordConfirm=Bevestiging +passwordNew=Nieuw Wachtwoord +username=Gebruikersnaam +address=Adres +street=Straat +locality=Stad of plaats +region=Staat, provincie of regio +postal_code=Postcode +country=Land +emailVerified=E-mailadres geverifieerd +gssDelegationCredential=GSS gedelegeerde aanmeldgegevens +role_admin=Beheer +role_realm-admin=Realmbeheer +role_create-realm=Creëer realm +role_view-realm=Bekijk realm +role_view-users=Bekijk gebruikers +role_view-applications=Bekijk toepassingen +role_view-clients=Bekijk clients +role_view-events=Bekijk gebeurtenissen +role_view-identity-providers=Bekijk identity providers +role_manage-realm=Beheer realm +role_manage-users=Beheer gebruikers +role_manage-applications=Beheer toepassingen +role_manage-identity-providers=Beheer identity providers +role_manage-clients=Beheer clients +role_manage-events=Beheer gebeurtenissen +role_view-profile=Bekijk profiel +role_manage-account=Beheer account +role_manage-account-links=Beheer accountkoppelingen +role_read-token=Lees token +role_offline-access=Offline toegang +role_uma_authorization=Verkrijg UMA rechten +client_account=Account +client_security-admin-console=Console Veligheidsbeheer +client_admin-cli=Beheer CLI +client_realm-management=Realmbeheer +client_broker=Broker +requiredFields=Verplichte velden +allFieldsRequired=Alle velden verplicht +backToApplication=« Terug naar toepassing +backTo=Terug naar {0} +date=Datum +event=Gebeurtenis +ip=IP +client=Client +clients=Clients +details=Details +started=Gestart +lastAccess=Laatste toegang +expires=Vervalt +applications=Toepassingen +account=Account +federatedIdentity=Federated Identity +authenticator=Authenticator +sessions=Sessies +log=Log +application=Toepassing +availablePermissions=Beschikbare rechten +grantedPermissions=Gegunde rechten +grantedPersonalInfo=Gegunde Persoonsgegevens +additionalGrants=Verdere vergunningen +action=Actie +inResource=in +fullAccess=Volledige toegang +offlineToken=Offline Token +revoke=Vergunning intrekken +configureAuthenticators=Ingestelde authenticators +mobile=Mobiel nummer +totpStep1=Installeer een van de onderstaande applicaties op uw mobiele apparaat: +totpStep2=Open de toepassing en scan de QR-code of voer de sleutel in. +totpStep3=Voer de door de toepassing gegeven eenmalige code in en klik op Opslaan om de configuratie af te ronden. +missingUsernameMessage=Gebruikersnaam ontbreekt. +missingFirstNameMessage=Voornaam onbreekt. +invalidEmailMessage=Ongeldig e-mailadres. +missingLastNameMessage=Achternaam ontbreekt. +missingEmailMessage=E-mailadres ontbreekt. +missingPasswordMessage=Wachtwoord ontbreekt. +notMatchPasswordMessage=Wachtwoorden komen niet overeen. +missingTotpMessage=Authenticatiecode ontbreekt. +invalidPasswordExistingMessage=Ongeldig bestaand wachtwoord. +invalidPasswordConfirmMessage=Wachtwoordbevestiging komt niet overeen. +invalidTotpMessage=Ongeldige authenticatiecode. +emailExistsMessage=E-mailadres bestaat reeds. +readOnlyUserMessage=U kunt uw account niet bijwerken aangezien het account alleen-lezen is. +readOnlyPasswordMessage=U kunt uw wachtwoord niet wijzigen omdat uw account alleen-lezen is. +successTotpMessage=Mobiele authenticator geconfigureerd. +successTotpRemovedMessage=Mobiele authenticator verwijderd. +successGrantRevokedMessage=Vergunning succesvol ingetrokken +accountUpdatedMessage=Uw account is gewijzigd. +accountPasswordUpdatedMessage=Uw wachtwoord is gewijzigd. +missingIdentityProviderMessage=Geen identity provider aangegeven. +invalidFederatedIdentityActionMessage=Ongeldige of ontbrekende actie op federated identity. +identityProviderNotFoundMessage=Gespecificeerde identity provider niet gevonden. +federatedIdentityLinkNotActiveMessage=Deze federated identity is niet langer geldig. +federatedIdentityRemovingLastProviderMessage=U kunt de laatste federated identity provider niet verwijderen aangezien u dan niet langer zou kunnen inloggen. +identityProviderRedirectErrorMessage=Kon niet herverwijzen naar identity provider. +identityProviderRemovedMessage=Identity provider met succes verwijderd. +identityProviderAlreadyLinkedMessage=Door {0} teruggegeven federated identity is al gekoppeld aan een andere gebruiker. +staleCodeAccountMessage=De pagina is verlopen. Probeer het nogmaals. +consentDenied=Toestemming geweigerd +accountDisabledMessage=Account is gedeactiveerd. Contacteer de beheerder. +accountTemporarilyDisabledMessage=Account is tijdelijk deactiveerd, neem contact op met de beheerder of probeer het later opnieuw. +invalidPasswordMinLengthMessage=Ongeldig wachtwoord: de minimale lengte is {0} karakters. +invalidPasswordMinLowerCaseCharsMessage=Ongeldig wachtwoord: het moet minstens {0} kleine letters bevatten. +invalidPasswordMinDigitsMessage=Ongeldig wachtwoord: het moet minstens {0} getallen bevatten. +invalidPasswordMinUpperCaseCharsMessage=Ongeldig wachtwoord: het moet minstens {0} hoofdletters bevatten. +invalidPasswordMinSpecialCharsMessage=Ongeldig wachtwoord: het moet minstens {0} speciale karakters bevatten. +invalidPasswordNotUsernameMessage=Ongeldig wachtwoord: het mag niet overeenkomen met de gebruikersnaam. +invalidPasswordRegexPatternMessage=Ongeldig wachtwoord: het voldoet niet aan het door de beheerder ingestelde patroon. +invalidPasswordHistoryMessage=Ongeldig wachtwoord: het mag niet overeen komen met een van de laatste {0} wachtwoorden. +invalidPasswordGenericMessage=Ongeldig wachtwoord: het nieuwe wachtwoord voldoet niet aan het wachtwoordbeleid. diff --git a/keycloak-themes/base/account/messages/messages_no.properties b/keycloak-themes/base/account/messages/messages_no.properties new file mode 100644 index 0000000..49b7b58 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_no.properties @@ -0,0 +1,152 @@ +doSave=Lagre +doCancel=Avbryt +doLogOutAllSessions=Logg ut av alle sesjoner +doRemove=Fjern +doAdd=Legg til +doSignOut=Logg ut + +editAccountHtmlTitle=Rediger konto +federatedIdentitiesHtmlTitle=Federerte identiteter +accountLogHtmlTitle=Kontologg +changePasswordHtmlTitle=Endre passord +sessionsHtmlTitle=Sesjoner +accountManagementTitle=Keycloak kontoadministrasjon +authenticatorTitle=Autentikator +applicationsHtmlTitle=Applikasjoner + +authenticatorCode=Engangskode +email=E-post +firstName=Fornavn +givenName=Fornavn +fullName=Fullt navn +lastName=Etternavn +familyName=Etternavn +password=Passord +passwordConfirm=Bekreftelse +passwordNew=Nytt passord +username=Brukernavn +address=Adresse +street=Gate-/veinavn + husnummer +locality=By +region=Fylke +postal_code=Postnummer +country=Land +emailVerified=E-post bekreftet +gssDelegationCredential=GSS legitimasjonsdelegering + +role_admin=Administrator +role_realm-admin=Administrator for sikkerhetsdomene +role_create-realm=Opprette sikkerhetsdomene +role_view-realm=Se sikkerhetsdomene +role_view-users=Se brukere +role_view-applications=Se applikasjoner +role_view-clients=Se klienter +role_view-events=Se hendelser +role_view-identity-providers=Se identitetsleverand\u00F8rer +role_manage-realm=Administrere sikkerhetsdomene +role_manage-users=Administrere brukere +role_manage-applications=Administrere applikasjoner +role_manage-identity-providers=Administrere identitetsleverand\u00F8rer +role_manage-clients=Administrere klienter +role_manage-events=Administrere hendelser +role_view-profile=Se profil +role_manage-account=Administrere konto +role_read-token=Lese token +role_offline-access=Frakoblet tilgang +role_uma_authorization=Skaffe tillatelser +client_account=Konto +client_security-admin-console=Sikkerhetsadministrasjonskonsoll +client_admin-cli=Kommandolinje-grensesnitt for administrator +client_realm-management=Sikkerhetsdomene-administrasjon +client_broker=Broker + + +requiredFields=Obligatoriske felt +allFieldsRequired=Alle felt m\u00E5 fylles ut + +backToApplication=« Tilbake til applikasjonen +backTo=Tilbake til {0} + +date=Dato +event=Hendelse +ip=IP +client=Klient +clients=Klienter +details=Detaljer +started=Startet +lastAccess=Sist benyttet +expires=Utl\u00F8per +applications=Applikasjoner + +account=Konto +federatedIdentity=Federert identitet +authenticator=Autentikator +sessions=Sesjoner +log=Logg + +application=Applikasjon +availablePermissions=Tilgjengelige rettigheter +grantedPermissions=Innvilgede rettigheter +grantedPersonalInfo=Innvilget personlig informasjon +additionalGrants=Ekstra rettigheter +action=Handling +inResource=i +fullAccess=Full tilgang +offlineToken=Offline token +revoke=Opphev rettighet + +configureAuthenticators=Konfigurerte autentikatorer +mobile=Mobiltelefon +totpStep1=Installer ett av f\u00F8lgende programmer p\u00E5 mobilen din. +totpStep2=\u00C5pne applikasjonen og skann strekkoden eller skriv inn koden. +totpStep3=Skriv inn engangskoden gitt av applikasjonen og klikk Lagre for \u00E5 fullf\u00F8re. + +missingUsernameMessage=Vennligst oppgi brukernavn. +missingFirstNameMessage=Vennligst oppgi fornavn. +invalidEmailMessage=Ugyldig e-postadresse. +missingLastNameMessage=Vennligst oppgi etternavn. +missingEmailMessage=Vennligst oppgi e-postadresse. +missingPasswordMessage=Vennligst oppgi passord. +notMatchPasswordMessage=Passordene er ikke like. + +missingTotpMessage=Vennligst oppgi engangskode. +invalidPasswordExistingMessage=Ugyldig eksisterende passord. +invalidPasswordConfirmMessage=Passordene er ikke like. +invalidTotpMessage=Ugyldig engangskode. + +usernameExistsMessage=Brukernavnet finnes allerede. +emailExistsMessage=E-postadressen finnes allerede. + +readOnlyUserMessage=Du kan ikke oppdatere kontoen din ettersom den er skrivebeskyttet. +readOnlyPasswordMessage=Du kan ikke oppdatere passordet ditt ettersom kontoen din er skrivebeskyttet. + +successTotpMessage=Autentikator for mobiltelefon er konfigurert. +successTotpRemovedMessage=Autentikator for mobiltelefon er fjernet. + +successGrantRevokedMessage=Vellykket oppheving av rettighet. + +accountUpdatedMessage=Kontoen din har blitt oppdatert. +accountPasswordUpdatedMessage=Ditt passord har blitt oppdatert. + +missingIdentityProviderMessage=Identitetsleverand\u00F8r er ikke spesifisert. +invalidFederatedIdentityActionMessage=Ugyldig eller manglende handling. +identityProviderNotFoundMessage=Spesifisert identitetsleverand\u00F8r ikke funnet. +federatedIdentityLinkNotActiveMessage=Denne identiteten er ikke lenger aktiv. +federatedIdentityRemovingLastProviderMessage=Du kan ikke fjerne siste federerte identitet ettersom du ikke har et passord. +identityProviderRedirectErrorMessage=Redirect til identitetsleverand\u00F8r feilet. +identityProviderRemovedMessage=Fjerning av identitetsleverand\u00F8r var vellykket. +identityProviderAlreadyLinkedMessage=Federert identitet returnert av {0} er allerede koblet til en annen bruker. +staleCodeAccountMessage=Siden har utl\u00F8pt. Vennligst pr\u00F8v en gang til. +consentDenied=Samtykke avsl\u00E5tt. + +accountDisabledMessage=Konto er deaktivert, kontakt administrator. + +accountTemporarilyDisabledMessage=Konto er midlertidig deaktivert, kontakt administrator eller pr\u00F8v igjen senere. +invalidPasswordMinLengthMessage=Ugyldig passord: minimum lengde {0}. +invalidPasswordMinLowerCaseCharsMessage=Ugyldig passord: m\u00E5 inneholde minimum {0} sm\u00E5 bokstaver. +invalidPasswordMinDigitsMessage=Ugyldig passord: m\u00E5 inneholde minimum {0} sifre. +invalidPasswordMinUpperCaseCharsMessage=Ugyldig passord: m\u00E5 inneholde minimum {0} store bokstaver. +invalidPasswordMinSpecialCharsMessage=Ugyldig passord: m\u00E5 inneholde minimum {0} spesialtegn. +invalidPasswordNotUsernameMessage=Ugyldig passord: kan ikke v\u00E6re likt brukernavn. +invalidPasswordRegexPatternMessage=Ugyldig passord: tilfredsstiller ikke kravene for passord-m\u00F8nster. +invalidPasswordHistoryMessage=Ugyldig passord: kan ikke v\u00E6re likt noen av de {0} foreg\u00E5ende passordene. diff --git a/keycloak-themes/base/account/messages/messages_pl.properties b/keycloak-themes/base/account/messages/messages_pl.properties new file mode 100644 index 0000000..3d6d9b4 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_pl.properties @@ -0,0 +1,248 @@ +# encoding: UTF-8 +doSave=Zapisz +doCancel=Anuluj +doLogOutAllSessions=Wyloguj wszystkie sesje +doRemove=Usuń +doAdd=Dodaj +doSignOut=Wyloguj +doLogIn=Logowanie +doLink=Link + + +editAccountHtmlTitle=Edycja konta +personalInfoHtmlTitle=Dane osobiste +federatedIdentitiesHtmlTitle=Połączone tożsamości +accountLogHtmlTitle=Dziennik konta +changePasswordHtmlTitle=Zmień hasło +deviceActivityHtmlTitle=Aktywność urządzeń +sessionsHtmlTitle=Sesje +accountManagementTitle=Zarządzanie kontem +authenticatorTitle=Uwierzytelnienie dwuetapowe +applicationsHtmlTitle=Aplikacje +linkedAccountsHtmlTitle=Połączone konta + +accountManagementWelcomeMessage=Witamy w zarządzaniu kontem +personalInfoIntroMessage=Zarządzaj informacjami podstawowymi o sobie +accountSecurityTitle=Bezpieczeństwo Konta +accountSecurityIntroMessage=Kontroluj swoje hasło i dostęp +applicationsIntroMessage=Śledź i zarządzaj uprawnieniami aplikacji do twojego konta +resourceIntroMessage=Udostępnij swoje zasoby członkom zespołu +passwordLastUpdateMessage=Twoje hasło zostało zaktualizowane +updatePasswordTitle=Aktualizuj hasło +updatePasswordMessageTitle=Miej pewność, że wybrałeś silne hasło +updatePasswordMessage=Silne hasło zawiera mieszaninę cyfr, liter i symboli. Nie używaj zwykłych słów oraz haseł używanych na innych kontach. +personalSubTitle=Twoje dane osobiste +personalSubMessage=Zarządzaj informacjami podstawowymi: twoim imieniem, nazwiskiem oraz emailem + +authenticatorCode=Kod jednorazowy +email=Email +firstName=Imię +givenName=Imię +fullName=Pełna nazwa +lastName=Nazwisko +familyName=Nazwisko rodowe +password=Hasło +currentPassword=Aktualne hasło +passwordConfirm=Potwierdzenie +passwordNew=Nowe hasło +username=Nazwa użytkownika +address=Adres +street=Ulica +locality=Miejscowość +region=Stan, województwo, region +postal_code=Kod pocztowy +country=Kraj +emailVerified=Email zweryfikowany +website=Strona internetowa +phoneNumber=Nr telefonu +phoneNumberVerified=Nr telefonu zweryfikowany +gender=Płeć +birthday=Data urodzenia +zoneinfo=Strefa czasowa +gssDelegationCredential=Poświadczenia delegowane GSS + +profileScopeConsentText=Profil użytkownika +emailScopeConsentText=Adres email +addressScopeConsentText=Adres +phoneScopeConsentText=Telefon +offlineAccessScopeConsentText=Dostęp offline +samlRoleListScopeConsentText=Moje role +rolesScopeConsentText=Role użytkownika + +role_admin=Admin +role_realm-admin=Strefa Admin +role_create-realm=Utwórz strefę +role_view-realm=Przeglądaj strefy +role_view-users=Przeglądaj użytkowników +role_view-applications=Przeglądaj aplikacje +role_view-clients=Przeglądaj klientów +role_view-events=Przeglądaj zdarzenia +role_view-identity-providers=Przeglądaj dostawców tożsamości +role_view-consent=Przeglądaj zgody +role_manage-realm=Zarządzaj strefami +role_manage-users=Zarządzaj użytkownikami +role_manage-applications=Zarządzaj aplikacjami +role_manage-identity-providers=Zarządzaj dostawcami tożsamości +role_manage-clients=Zarządzaj klientami +role_manage-events=Zarządzaj zdarzeniami +role_view-profile=Przeglądaj profil +role_manage-account=Zarządzaj kontem +role_manage-account-links=Zarządzaj linkami konta +role_manage-consent=Zarządzaj zgodami +role_read-token=Odczytaj token +role_offline-access=Dostęp offline +role_uma_authorization=Uzyskaj uprawnienia +client_account=Konto +client_account-console=Konsola konta +client_security-admin-console=Konsola administratora bezpieczeństwa +client_admin-cli=Admin CLI +client_realm-management=Zarządzanie strefą +client_broker=Broker + + +requiredFields=Wymagane pola +allFieldsRequired=Wszystkie pola są wymagane + +backToApplication=« Powrót do aplikacji +backTo=Wróć do: {0} + +date=Data +event=Zdarzenie +ip=IP +client=Klient +clients=Aplikacje klienckie +details=Szczegóły +started=Rozpoczęta +lastAccess=Ostatni dostęp +expires=Data ważności +applications=Aplikacje + +account=Konto +federatedIdentity=Połączone tożsamości +authenticator=Uwierzytelnienie dwuetapowe +device-activity=Aktywność urządzenia +sessions=Sesje +log=Dziennik + +application=Aplikacja +availableRoles=Dostępne role +grantedPermissions=Przydzielone uprawnienia +grantedPersonalInfo=Przydzielone dane osobiste +additionalGrants=Dodatkowe przydziały +action=Akcje +inResource=w +fullAccess=Pełny dostęp +offlineToken=Token offline +revoke=Odbierz uprawnienia + +configureAuthenticators=Skonfigurowane autentykatory +mobile=Mobilne +totpStep1=Zainstaluj jedną z następujących aplikacji na telefonie komórkowym: +totpStep2=Otwórz aplikację i zeskanuj kod kreskowy: +totpStep3=Wprowadź jednorazowy kod podany przez aplikację i kliknij Zapisz aby zakończyć konfigurację. +totpStep3DeviceName=Podaj nazwę urządzenia aby lepiej zarządzać swoimi urządzeniami haseł jednorazowych. + +totpManualStep2=Otwórz aplikację i wprowadź klucz: +totpManualStep3=Użyj poniższych wartości konfiguracji, jeśli aplikacja pozwala na ich ustawienie: +totpUnableToScan=Nie można skanować? +totpScanBarcode=Zeskanować kod paskowy? + +totp.totp=Oparte o czas +totp.hotp=Oparte o licznik + +totpType=Typ +totpAlgorithm=Algorytm +totpDigits=Cyfry +totpInterval=Interwał +totpCounter=Licznik +totpDeviceName=Nazwa urządzenia + +missingUsernameMessage=Proszę podać nazwę użytkownika. +missingFirstNameMessage=Proszę podać imię. +invalidEmailMessage=Nieprawidłowy adres email. +missingLastNameMessage=Proszę podać nazwisko. +missingEmailMessage=Proszę podać e-mail. +missingPasswordMessage=Proszę podać hasło. +notMatchPasswordMessage=Hasła nie są zgodne. +invalidUserMessage=Nieprawidłowy użytkownik + +missingTotpMessage=Proszę podać kod uwierzytelniający. +missingTotpDeviceNameMessage=Proszę podać nazwę urządzenia. +invalidPasswordExistingMessage=Nieprawidłowe aktualne hasło. +invalidPasswordConfirmMessage=Potwierdzenie hasła nie jest zgodne. +invalidTotpMessage=Nieprawidłowy kod uwierzytelniający. + +usernameExistsMessage=Nazwa użytkownika już jest wykorzystana. +emailExistsMessage=Email już istnieje. + +readOnlyUserMessage=Zmiana nie jest możliwa, ponieważ edycja konta jest zablokowana. +readOnlyUsernameMessage=Zmiana nazwy użytkownika nie jest możliwa, ponieważ edycja konta jest zablokowana. +readOnlyPasswordMessage=Zmiana hasła nie jest możliwa, ponieważ edycja konta jest zablokowana. + +successTotpMessage=Mobilny autentykator skonfigurowany. +successTotpRemovedMessage=Mobilny autentykator usunięty. + +successGrantRevokedMessage=Cofnięto uprawnienia. + +accountUpdatedMessage=Twoje konto zostało zaktualizowane. +accountPasswordUpdatedMessage=Twoje hasło zostało zmienione. + +missingIdentityProviderMessage=Dostawca tożsamości nie został wybrany. +invalidFederatedIdentityActionMessage=Nieprawidłowa akcja. +identityProviderNotFoundMessage=Podany dostawca tożsamości nie istnieje. +federatedIdentityLinkNotActiveMessage=Podana tożsamość nie jest już aktywna. +federatedIdentityRemovingLastProviderMessage=Nie można usunąć ostatniej połączonej tożsamości, jeżeli nie ustawiłeś hasła. +identityProviderRedirectErrorMessage=Nieudane przekierowanie do zewnętrznego dostawcy tożsamości. +identityProviderRemovedMessage=Dostawca tożsamości został usunięty. +identityProviderAlreadyLinkedMessage=Połączona tożsamość {0} jest już przypisana do innego użytkownika. +staleCodeAccountMessage=Strona wygasła. Prosimy spróbować ponownie. +consentDenied=Zgoda wycofana. + +accountDisabledMessage=Konto jest zablokowane, skontaktuj się z administratorem. + +accountTemporarilyDisabledMessage=Konto jest tymczasowo zablokowane, skontaktuj się z administratorem lub spróbuj później. +invalidPasswordMinLengthMessage=Nieprawidłowe hasło: minimalna długość {0}. +invalidPasswordMinLowerCaseCharsMessage=Nieprawidłowe hasło: brak małych liter (co najmniej {0}). +invalidPasswordMinDigitsMessage=Nieprawidłowe hasło: brak cyfr (co najmniej {0}). +invalidPasswordMinUpperCaseCharsMessage=Nieprawidłowe hasło: brak dużych liter (co najmniej {0}). +invalidPasswordMinSpecialCharsMessage=Nieprawidłowe hasło: brak znaków specjalnych (co najmniej {0}). +invalidPasswordNotUsernameMessage=Nieprawidłowe hasło: nie może być zgodne z nazwą użytkownika. +invalidPasswordRegexPatternMessage=Nieprawidłowe hasło: nie spełnia przyjętych reguł. +invalidPasswordHistoryMessage=Nieprawidłowe hasło: jest identyczne jak jedno z ostatnich ({0}) haseł. +invalidPasswordBlacklistedMessage=Nieprawidłowe hasło: jest na liście haseł zabronionych. +invalidPasswordGenericMessage=Nieprawidłowe hasło: nowe hasło nie spełnia polityki haseł. + +# Authorization +myResources=Moje zasoby +myResourcesSub=Moje zasoby +doDeny=Zabroń +doRevoke=Cofnij +doApprove=Akceptuj +doRemoveSharing=Usuń udostępnianie +doRemoveRequest=Usuń żądanie +peopleAccessResource=Osoby z dostępem do tego zasobu +resourceManagedPolicies=Uprawnienia dające dostęp do tego zasobu +resourceNoPermissionsGrantingAccess=Brak uprawnień dających dostęp do tego zasobu +anyAction=Dowolna akcja +description=Opis +name=Nazwa +scopes=Zakres +resource=Zasób +user=Użytkownik +peopleSharingThisResource=Osoby współdzielące ten zasób +shareWithOthers=Udostępnij innym +needMyApproval=Wymagana moja akceptacja +requestsWaitingApproval=Twoje żądanie czeka na akceptację +icon=Ikona +requestor=Żądający +owner=Właściciel +resourcesSharedWithMe=Zasoby współdzielone ze mną +permissionRequestion=Żądania uprawnień +permission=Uprawnienia +shares=udostępnienia +notBeingShared=Ten zasób nie jest współdzielony. +notHaveAnyResource=Nie masz żadnych zasobów +noResourcesSharedWithYou=Brak zasobów udostępnionych dla Ciebie +havePermissionRequestsWaitingForApproval=Masz {0} żądań uprawnień oczekujących na akceptację. +clickHereForDetails=Więcej szczegółów... +resourceIsNotBeingShared=Zasób nie jest współdzielony diff --git a/keycloak-themes/base/account/messages/messages_pt_BR.properties b/keycloak-themes/base/account/messages/messages_pt_BR.properties new file mode 100644 index 0000000..462c817 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_pt_BR.properties @@ -0,0 +1,349 @@ +doSave=Salvar +doCancel=Cancelar +doLogOutAllSessions=Sair de todas as sess\u00F5es +doRemove=Remover +doAdd=Adicionar +doSignOut=Sair +doLogIn=Entrar +doLink=Vincular +noAccessMessage=Acesso n\u00e3o permitido + + +editAccountHtmlTitle=Editar Conta +personalInfoHtmlTitle=Informa\u00e7\u00f5es Pessoais +federatedIdentitiesHtmlTitle=Identidades Federadas +accountLogHtmlTitle=Hist\u00f3rico da conta +changePasswordHtmlTitle=Alterar senha +deviceActivityHtmlTitle=Atividade de Dispositivos +sessionsHtmlTitle=Sess\u00F5es +accountManagementTitle=Gerenciamento de Conta +authenticatorTitle=Autenticator +applicationsHtmlTitle=Aplicativos +linkedAccountsHtmlTitle=Contas Vinculadas + +accountManagementWelcomeMessage=Bem-vindo ao Gerenciamento de Conta +personalInfoIntroMessage=Gerenciar informa\u00e7\u00f5es b\u00e1sicas +accountSecurityTitle=Seguran\u00e7a da Conta +accountSecurityIntroMessage=Gerencie sua senha e acesso da conta +applicationsIntroMessage=Acompanhe e gerencie as permiss\u00f5es de app para acesso \u00e0 sua conta +resourceIntroMessage=Compartilhe seus recursos com membros de equipe +passwordLastUpdateMessage=Sua senha foi atualizada em +updatePasswordTitle=Atualizar Senha +updatePasswordMessageTitle=Certifique-se de que a nova senha \u00e9 segura +updatePasswordMessage=Uma senha segura cont\u00e9m uma combina\u00e7\u00e3o de n\u00famero, letras e caracteres especiais. Ela deve ser dif\u00edcil de adivinhar, n\u00e3o pode se assemelhar a uma palavra real e n\u00e3o \u00e9 utilizada em outros lugares. +personalSubTitle=Suas Informa\u00e7\u00f5es Pessoais +personalSubMessage=Gerencie as informa\u00e7\u00f5es b\u00e1sicas: seu primeiro nome, seu sobrenome e seu endere\u00e7o de e-mail + +authenticatorCode=C\u00F3digo autenticador +email=E-mail +firstName=Primeiro nome +givenName=Primeiro nome +fullName=Nome completo +lastName=Sobrenome +familyName=Sobrenome +password=Senha +currentPassword=Senha Atual +passwordConfirm=Confirma\u00E7\u00E3o +passwordNew=Nova senha +username=Nome de us\u00FAario +address=Endere\u00E7o +street=Logradouro +locality=Cidade ou Localidade +region=Estado +postal_code=CEP +country=Pa\u00EDs +emailVerified=E-mail verificado +website=P\u00e1gina da web +phoneNumber=N\u00famero de telefone +phoneNumberVerified=N\u00famero de telefone verificado +gender=G\u00eanero +birthday=Data de nascimento +zoneinfo=Zona hor\u00e1ria +gssDelegationCredential=Delega\u00E7\u00E3o de Credenciais GSS + +profileScopeConsentText=Perfil de usu\u00e1rio +emailScopeConsentText=Endere\u00e7o de e-mail +addressScopeConsentText=Endere\u00e7o +phoneScopeConsentText=N\u00famero de telefone +offlineAccessScopeConsentText=Acesso Offline +samlRoleListScopeConsentText=Meus Perfis de Acesso +rolesScopeConsentText=Perfis de acesso de usu\u00e1rio + +role_admin=Administrador +role_realm-admin=Administrador de dom\u00ednio +role_create-realm=Criar dom\u00ednio +role_view-realm=Visualizar dom\u00ednio +role_view-users=Visualizar usu\u00E1rios +role_view-applications=Visualizar aplicativos +role_view-clients=Visualizar clientes +role_view-events=Visualizar eventos +role_view-identity-providers=Visualizar provedores de identidade +role_view-consent=Visualizar consentimentos +role_manage-realm=Gerenciar dom\u00ednio +role_manage-users=Gerenciar usu\u00E1rios +role_manage-applications=Gerenciar aplicativos +role_manage-identity-providers=Gerenciar provedores de identidade +role_manage-clients=Gerenciar clientes +role_manage-events=Gerenciar eventos +role_view-profile=Visualizar perfil +role_manage-account=Gerenciar conta +role_manage-account-links=Gerenciar vincula\u00e7\u00f5es de conta +role_manage-consent=Gerenciar consentimentos +role_read-token=Ler token +role_offline-access=Acesso offline +role_uma_authorization=Obter permiss\u00F5es +client_account=Conta +client_account-console=Console de Conta +client_security-admin-console=Console de Administra\u00E7\u00E3o de Seguran\u00E7a +client_admin-cli=CLI de Administra\u00e7\u00e3o +client_realm-management=Gerenciamento de Dom\u00ednio +client_broker=Provedor de Identidade + + +requiredFields=Campos obrigat\u00F3rios +allFieldsRequired=Todos os campos s\u00E3o obrigat\u00F3rios + +backToApplication=« Voltar para aplica\u00E7\u00E3o +backTo=Voltar para {0} + +date=Data +event=Evento +ip=IP +client=Cliente +clients=Clientes +details=Detalhes +started=In\u00edcio em +lastAccess=\u00DAltimo acesso +expires=Expira em +applications=Aplicativos + +account=Conta +federatedIdentity=Identidade Federada +authenticator=Autenticador +device-activity=Atividade de Dispositivos +sessions=Sess\u00F5es +log=Hist\u00f3rico + +application=Aplicativo +availableRoles=Perfis de Acesso Dispon\u00EDveis +grantedPermissions=Permiss\u00F5es Concedidas +grantedPersonalInfo=Informa\u00E7\u00F5es Pessoais Concedidas +additionalGrants=Concess\u00F5es Adicionais +action=A\u00E7\u00E3o +inResource=em +fullAccess=Acesso Completo +offlineToken=Token Offline +revoke=Revogar Concess\u00e3o + +configureAuthenticators=Autenticadores Configurados +mobile=M\u00f3vel +totpStep1=Instale uma das seguintes aplica\u00e7\u00f5es no seu celular: +totpStep2=Abra a aplica\u00e7\u00e3o e escaneie o c\u00f3digo QR: +totpStep3=Insira o c\u00f3digo de uso \u00fanico exibido pela aplica\u00e7\u00e3o e clique em Salvar para finalizar a configura\u00e7\u00e3o. +totpStep3DeviceName=Forne\u00e7a um nome de dispositivo para ajud\u00e1-lo a gerenciar seus dipositivos de autentica\u00e7\u00e3o de dois fatores. + +totpManualStep2=Abra a aplica\u00e7\u00e3o e insira a chave: +totpManualStep3=Use as seguintes configura\u00e7\u00f5es se a aplica\u00e7\u00e3o permitir: +totpUnableToScan=N\u00e3o consegue escanear? +totpScanBarcode=Escanear c\u00f3digo QR? + +totp.totp=Baseada em tempo +totp.hotp=Baseada em contador + +totpType=Tipo +totpAlgorithm=Algoritmo +totpDigits=D\u00edgitos +totpInterval=Intervalo +totpCounter=Contador +totpDeviceName=Nome do Dispositivo + +irreversibleAction=Esta a\u00e7\u00e3o \u00e9 irrevers\u00edvel +deletingImplies=Apagar a sua conta implica em: +errasingData=Remover todos os dados +loggingOutImmediately=Finalizar a sess\u00e3o imediatamente +accountUnusable=Qualquer uso subsquente da aplica\u00e7\u00e3o n\u00e3o ser\u00e1 mais poss\u00edvel com esta conta + +missingUsernameMessage=Por favor, especifique o nome de usu\u00E1rio. +missingFirstNameMessage=Por favor, informe o primeiro nome. +invalidEmailMessage=E-mail inv\u00E1lido. +missingLastNameMessage=Por favor, informe o sobrenome. +missingEmailMessage=Por favor, informe o e-mail. +missingPasswordMessage=Por favor, informe a senha. +notMatchPasswordMessage=As senhas n\u00E3o coincidem. +invalidUserMessage=Usu\u00e1rio inv\u00e1lido +updateReadOnlyAttributesRejectedMessage=Atualiza\u00e7\u00e3o de atributo de apenas leitura n\u00e3o permitida + +missingTotpMessage=Por favor, informe o c\u00F3digo de uso \u00fanico. +missingTotpDeviceNameMessage=Por favor, informe o nome do dispositivo. +invalidPasswordExistingMessage=A senha atual \u00e9 inv\u00E1lida. +invalidPasswordConfirmMessage=A senha de confirma\u00E7\u00E3o n\u00E3o coincide. +invalidTotpMessage=C\u00F3digo de uso \u00fanico inv\u00E1lido. + +usernameExistsMessage=Este nome de usu\u00E1rio j\u00E1 existe. +emailExistsMessage=Este endere\u00e7o de e-mail j\u00E1 existe. + +readOnlyUserMessage=Voc\u00EA n\u00E3o pode atualizar sua conta, uma vez que \u00E9 apenas de leitura. +readOnlyUsernameMessage=Voc\u00ea^n\u00e3o pode atualizar o seu nome de usu\u00e1rio, uma vez que \u00e9 apenas de leitura. +readOnlyPasswordMessage=Voc\u00EA n\u00E3o pode atualizar sua senha, uma vez que sua conta \u00E9 apenas de leitura. + +successTotpMessage=Autenticador m\u00f3vel configurado. +successTotpRemovedMessage=Autenticador m\u00f3vel removido. + +successGrantRevokedMessage=Concess\u00e3o revogada com sucesso. + +accountUpdatedMessage=Sua conta foi atualizada. +accountPasswordUpdatedMessage=Sua senha foi atualizada. + +missingIdentityProviderMessage=Provedor de identidade n\u00E3o especificado. +invalidFederatedIdentityActionMessage=A\u00E7\u00E3o inv\u00E1lida ou ausente. +identityProviderNotFoundMessage=O provedor de identidade especificado n\u00E3o foi encontrado. +federatedIdentityLinkNotActiveMessage=Esta identidade n\u00E3o est\u00E1 mais em atividade. +federatedIdentityRemovingLastProviderMessage=Voc\u00EA n\u00E3o pode remover a \u00FAltima identidade federada, porque voc\u00EA n\u00E3o tem uma senha. +identityProviderRedirectErrorMessage=Falha ao redirecionar para o provedor de identidade. +identityProviderRemovedMessage=Provedor de identidade removido com sucesso. +identityProviderAlreadyLinkedMessage=Identidade federada retornada por {0} j\u00E1 est\u00E1 ligada a outro usu\u00E1rio. +staleCodeAccountMessage=A p\u00e1gina expirou. Por favor, tente novamente. +consentDenied=Consentimento negado. + +accountDisabledMessage=Conta desativada, por favor, contate um administrador. + +accountTemporarilyDisabledMessage=A conta est\u00E1 temporariamente indispon\u00EDvel, contate um administrador ou tente novamente mais tarde. +invalidPasswordMinLengthMessage=Senha inv\u00E1lida\: deve ter pelo menos {0} caracteres. +invalidPasswordMinLowerCaseCharsMessage=Senha inv\u00E1lida\: deve conter pelo menos {0} letra(s) min\u00FAscula(s). +invalidPasswordMinDigitsMessage=Senha inv\u00E1lida\: deve conter pelo menos {0} n\u00FAmero(s). +invalidPasswordMinUpperCaseCharsMessage=Senha inv\u00E1lida\: deve conter pelo menos {0} letra(s) mai\u00FAscula(s). +invalidPasswordMinSpecialCharsMessage=Senha inv\u00E1lida\: deve conter pelo menos {0} caractere(s) especial(is). +invalidPasswordNotUsernameMessage=Senha inv\u00E1lida\: n\u00E3o pode ser igual ao nome de usu\u00E1rio. +invalidPasswordNotEmailMessage=Senha inv\u00e1lida: n\u00e3o pode ser igual ao endere\u00e7o de e-mail. +invalidPasswordRegexPatternMessage=Senha inv\u00E1lida\: n\u00E3o corresponde ao(s) padr\u00E3o(\u00f5es) da express\u00E3o regular. +invalidPasswordHistoryMessage=Senha inv\u00E1lida\: n\u00E3o pode ser igual a qualquer uma da(s) \u00FAltima(s) {0} senha(s). +invalidPasswordBlacklistedMessage=Senha inv\u00e1lida: esta senha est\u00e1 na lista de exclus\u00e3o. +invalidPasswordGenericMessage=Senha inv\u00e1lida: a nova senha n\u00e3o cumpre as pol\u00edticas de senha. + +# Authorization +myResources=Meus Recursos +myResourcesSub=Meus recursos +doDeny=Negar +doRevoke=Revogar +doApprove=Permitir +doRemoveSharing=Remover Compartilhamento +doRemoveRequest=Remover Solicita\u00e7\u00e3o +peopleAccessResource=Pessoas com acesso a este recurso +resourceManagedPolicies=Permiss\u00f5es dando acesso a este recurso +resourceNoPermissionsGrantingAccess=Sem permiss\u00f5es dando acesso a este recurso +anyAction=Qualquer a\u00e7\u00e3o +description=Descri\u00e7\u00e3o +name=Nome +scopes=Escopo +resource=Recurso +user=Usu\u00e1rio +peopleSharingThisResource=Pessoas compartilhando este recurso +shareWithOthers=Compartilhar com outros +needMyApproval=Requer minha aprova\u00e7\u00e3o +requestsWaitingApproval=Solicita\u00e7\u00f5es suas aguardando aprova\u00e7\u00e3o +icon=\u00cdcone +requestor=Requerente +owner=Dono +resourcesSharedWithMe=Recursos compartilhados comigo +permissionRequestion=Solicita\u00e7\u00e3o de Permiss\u00e3o +permission=Permiss\u00e3o +shares=compartilha(m) +notBeingShared=Este recurso n\u00e3o est\u00e1 sendo compartilhado. +notHaveAnyResource=Voc\u00ea n\u00e3o possui recursos +noResourcesSharedWithYou=N\u00e3o h\u00e1 recursos compartilhados com voc\u00ea +havePermissionRequestsWaitingForApproval=Voc\u00ea tem {0} solicita\u00e7\u00e3o(\u00f5es) de permiss\u00e3o aguardando aprova\u00e7\u00e3o. +clickHereForDetails=Clique aqui para mais detalhes. +resourceIsNotBeingShared=O recurso n\u00e3o \u00e9 compartilhado + +# Applications +applicationName=Nome +applicationType=Tipo de aplica\u00e7\u00e3o +applicationInUse=Uso apenas em aplica\u00e7\u00e3o +clearAllFilter=Limpar todos os filtros +activeFilters=Filtros ativos +filterByName=Filtrar Por Nome ... +allApps=Todas as aplica\u00e7\u00f5es +internalApps=Aplica\u00e7\u00f5es internas +thirdpartyApps=Aplica\u00e7\u00f5es de terceiros +appResults=Resultados +clientNotFoundMessage=Cliente n\u00e3o encontrado. + +# Linked account +authorizedProvider=Provedor Autorizado +authorizedProviderMessage=Provedores Autorizados vinculados \u00e0 sua conta +identityProvider=Provedor de Identidade +identityProviderMessage=Para vincular a sua conta aos provedores de identidade configurados +socialLogin=Login Social +userDefined=Definido por Usu\u00e1rio +removeAccess=Remover Acesso +removeAccessMessage=Voc\u00ea dever\u00e1 conceder acesso novamente se quiser usar esta conta de app. + +#Authenticator +authenticatorStatusMessage=A autentica\u00e7\u00e3o de dois fatores est\u00e1 +authenticatorFinishSetUpTitle=Sua Autentica\u00e7\u00e3o de Dois Fatores +authenticatorFinishSetUpMessage=Sempre que entrar na sua conta, voc\u00ea dever\u00e1 fornecer um c\u00f3digo de autentica\u00e7\u00e3o de dois fatores. +authenticatorSubTitle=Configurar Autentica\u00e7\u00e3o de Dois Fatores +authenticatorSubMessage=Para aumentar a seguran\u00e7a da sua conta, habilite pelo menos um m\u00e9todo de autentica\u00e7\u00e3o de dois fatores dispon\u00edvel. +authenticatorMobileTitle=Autenticador M\u00f3vel +authenticatorMobileMessage=Use um autenticador m\u00f3vel para obter c\u00f3digos de verifica\u00e7\u00e3o para autentica\u00e7\u00e3o de dois fatores. +authenticatorMobileFinishSetUpMessage=O autenticador foi vinculado ao seu celular. +authenticatorActionSetup=Configurar +authenticatorSMSTitle=C\u00f3digo SMS +authenticatorSMSMessage=A aplica\u00e7\u00e3o ir\u00e1 enviar o c\u00f3digo de verifica\u00e7\u00e3o para o seu celular como autentica\u00e7\u00e3o de dois fatores. +authenticatorSMSFinishSetUpMessage=As mensagens de texto ser\u00e3o enviadas para +authenticatorDefaultStatus=Padr\u00e3o +authenticatorChangePhone=Mudar N\u00famero de Celular + +#Authenticator - Mobile Authenticator setup +authenticatorMobileSetupTitle=Configura\u00e7\u00e3o do Autenticador M\u00f3vel +smscodeIntroMessage=Insira seu n\u00famero de celular e o c\u00f3digo de verifica\u00e7\u00e3o ser\u00e1 enviado para o seu dispositivo. +mobileSetupStep1=Instale um app autenticador no seu celular. As seguintes aplica\u00e7\u00f5es s\u00e3o suportadas. +mobileSetupStep2=Abra a aplica\u00e7\u00e3o e escaneie o c\u00f3digo QR: +mobileSetupStep3=Insira o c\u00f3digo autenticador exibido pela aplica\u00e7\u00e3o e clique em Salvar para finalizar a configura\u00e7\u00e3o. +scanBarCode=Escanear c\u00f3digo QR? +enterBarCode=Insira o c\u00f3digo autenticador +doCopy=Copiar +doFinish=Finalizar + +#Authenticator - SMS Code setup +authenticatorSMSCodeSetupTitle=Configura\u00e7\u00e3o de C\u00f3digo SMS +chooseYourCountry=Selecione seu pa\u00eds +enterYourPhoneNumber=Insira seu n\u00famero de telefone +sendVerficationCode=Enviar C\u00f3digo de Verifica\u00e7\u00e3o +enterYourVerficationCode=Insira o seu c\u00f3digo de verifica\u00e7\u00e3o + +#Authenticator - backup Code setup +authenticatorBackupCodesSetupTitle=Configura\u00e7\u00e3o de C\u00f3digos de Emerg\u00eancia +realmName=Dom\u00ednio +doDownload=Baixar +doPrint=Imprimir +generateNewBackupCodes=Gerar Novos C\u00f3digos de Emerg\u00eancia +backtoAuthenticatorPage=Voltar \u00e0 P\u00e1gina de Autenticador + + +#Resources +resources=Recursos +sharedwithMe=Compartilhados Comigo +share=Compartilhar +sharedwith=Compartilhado com +accessPermissions=Permiss\u00f5es de Acesso +permissionRequests=Pedidos de Acesso +approve=Aprovar +approveAll=Aprovar todos +people=pessoas +perPage=por p\u00e1gina +currentPage=P\u00e1gina Atual +sharetheResource=Compartilhar recurso +group=Grupo +selectPermission=Selecionar Permiss\u00e3o +addPeople=Adicionar pessoas que compartilhem o recurso +addTeam=Adicionar equipe que compartilhe o recurso +myPermissions=Minhas Permiss\u00f5es +waitingforApproval=Aguardando aprova\u00e7\u00e3o +anyPermission=Qualquer Permiss\u00e3o + +# Openshift messages +openshift.scope.user_info=Informa\u00e7\u00f5es do usu\u00e1rio +openshift.scope.user_check-access=Informa\u00e7\u00f5es de acesso do usu\u00e1rio +openshift.scope.user_full=Acesso Completo +openshift.scope.list-projects=Listar projetos diff --git a/keycloak-themes/base/account/messages/messages_ru.properties b/keycloak-themes/base/account/messages/messages_ru.properties new file mode 100644 index 0000000..a9716b8 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_ru.properties @@ -0,0 +1,155 @@ +# encoding: utf-8 +doSave=Сохранить +doCancel=Отмена +doLogOutAllSessions=Выйти из всех сессий +doRemove=Удалить +doAdd=Добавить +doSignOut=Выход + +editAccountHtmlTitle=Изменение учетной записи +federatedIdentitiesHtmlTitle=Федеративные идентификаторы +accountLogHtmlTitle=Лог учетной записи +changePasswordHtmlTitle=Смена пароля +sessionsHtmlTitle=Сессии +accountManagementTitle=Управление учетной записью +authenticatorTitle=Аутентификатор +applicationsHtmlTitle=Приложения + +authenticatorCode=Одноразовый код +email=E-mail +firstName=Имя +givenName=Имя +fullName=Полное имя +lastName=Фамилия +familyName=Фамилия +password=Пароль +passwordConfirm=Подтверждение пароля +passwordNew=Новый пароль +username=Имя пользователя +address=Адрес +street=Улица +locality=Город +region=Регион +postal_code=Почтовый индекс +country=Страна +emailVerified=E-mail подтвержден +gssDelegationCredential=Делегирование учетных данных через GSS + +role_admin=Администратор +role_realm-admin=Администратор realm +role_create-realm=Создать realm +role_view-realm=Просмотр realm +role_view-users=Просмотр пользователей +role_view-applications=Просмотр приложений +role_view-clients=Просмотр клиентов +role_view-events=Просмотр событий +role_view-identity-providers=Просмотр провайдеров учетных записей +role_manage-realm=Управление realm +role_manage-users=Управление пользователями +role_manage-applications=Управление приложениями +role_manage-identity-providers=Управление провайдерами учетных записей +role_manage-clients=Управление клиентами +role_manage-events=Управление событиями +role_view-profile=Просмотр профиля +role_manage-account=Управление учетной записью +role_read-token=Чтение токена +role_offline-access=Доступ оффлайн +role_uma_authorization=Получение разрешений +client_account=Учетная запись +client_security-admin-console=Консоль администратора безопасности +client_admin-cli=Командный интерфейс администратора +client_realm-management=Управление Realm +client_broker=Брокер + + +requiredFields=Обязательные поля +allFieldsRequired=Все поля обязательны + +backToApplication=« Назад в приложение +backTo=Назад в {0} + +date=Дата +event=Событие +ip=IP +client=Клиент +clients=Клиенты +details=Детали +started=Начата +lastAccess=Последний доступ +expires=Истекает +applications=Приложения + +account=Учетная запись +federatedIdentity=Федеративный идентификатор +authenticator=Аутентификатор +sessions=Сессии +log=Журнал + +application=Приложение +availablePermissions=Доступные разрешения +grantedPermissions=Согласованные разрешения +grantedPersonalInfo=Согласованная персональная информация +additionalGrants=Дополнительные согласования +action=Действие +inResource=в +fullAccess=Полный доступ +offlineToken=Оффлайн токен +revoke=Отозвать согласование + +configureAuthenticators=Сконфигурированные аутентификаторы +mobile=Мобильное приложение +totpStep1=Установите FreeOTP или Google Authenticator. Оба приложения доступны на Google Play и в Apple App Store. +totpStep2=Откройте приложение и просканируйте баркод, либо введите ключ. +totpStep3=Введите одноразовый код, выданный приложением, и нажмите сохранить для завершения установки. + +missingUsernameMessage=Введите имя пользователя. +missingFirstNameMessage=Введите имя. +invalidEmailMessage=Введите корректный E-mail. +missingLastNameMessage=Введите фамилию. +missingEmailMessage=Введите E-mail. +missingPasswordMessage=Введите пароль. +notMatchPasswordMessage=Пароли не совпадают. + +missingTotpMessage=Введите код аутентификатора. +invalidPasswordExistingMessage=Существующий пароль неверный. +invalidPasswordConfirmMessage=Подтверждение пароля не совпадает. +invalidTotpMessage=Неверный код аутентификатора. + +usernameExistsMessage=Имя пользователя уже существует. +emailExistsMessage=E-mail уже существует. + +readOnlyUserMessage=Вы не можете обновить информацию вашей учетной записи, т.к. она доступна только для чтения. +readOnlyPasswordMessage=Вы не можете обновить пароль вашей учетной записи, т.к. он доступен только для чтения. + +successTotpMessage=Аутентификатор в мобильном приложении сконфигурирован. +successTotpRemovedMessage=Аутентификатор в мобильном приложении удален. + +successGrantRevokedMessage=Согласование отозвано успешно. + +accountUpdatedMessage=Ваша учетная запись обновлена. +accountPasswordUpdatedMessage=Ваш пароль обновлен. + +missingIdentityProviderMessage=Провайдер учетных записей не задан. +invalidFederatedIdentityActionMessage=Некорректное или недопустимое действие. +identityProviderNotFoundMessage=Заданный провайдер учетных записей не найден. +federatedIdentityLinkNotActiveMessage=Идентификатор больше не активен. +federatedIdentityRemovingLastProviderMessage=Вы не можете удалить последний федеративный идентификатор, т.к. Вы не имеете пароля. +identityProviderRedirectErrorMessage=Ошибка перенаправления в провайдер учетных записей. +identityProviderRemovedMessage=Провайдер учетных записей успешно удален. +identityProviderAlreadyLinkedMessage=Федеративный идентификатор, возвращенный {0} уже используется другим пользователем. +staleCodeAccountMessage=Страница устарела. Попробуйте еще раз. +consentDenied=В согласовании отказано. + +accountDisabledMessage=Учетная запись заблокирована, обратитесь к администратору. + +accountTemporarilyDisabledMessage=Учетная запись временно заблокирована, обратитесь к администратору или попробуйте позже. +invalidPasswordMinLengthMessage=Некорректный пароль: длина пароля должна быть не менее {0} символа(ов). +invalidPasswordMinLowerCaseCharsMessage=Некорректный пароль: пароль должен содержать не менее {0} символа(ов) в нижнем регистре. +invalidPasswordMinDigitsMessage=Некорректный пароль: пароль должен содержать не менее {0} цифр(ы). +invalidPasswordMinUpperCaseCharsMessage=Некорректный пароль: пароль должен содержать не менее {0} символа(ов) в верхнем регистре. +invalidPasswordMinSpecialCharsMessage=Некорректный пароль: пароль должен содержать не менее {0} спецсимвола(ов). +invalidPasswordNotUsernameMessage=Некорректный пароль: пароль не должен совпадать с именем пользователя. +invalidPasswordRegexPatternMessage=Некорректный пароль: пароль не удовлетворяет регулярному выражению. +invalidPasswordHistoryMessage=Некорректный пароль: пароль не должен совпадать с последним(и) {0} паролями. +invalidPasswordGenericMessage=Некорректный пароль: новый пароль не соответствует правилам пароля. + diff --git a/keycloak-themes/base/account/messages/messages_sk.properties b/keycloak-themes/base/account/messages/messages_sk.properties new file mode 100644 index 0000000..32cafc6 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_sk.properties @@ -0,0 +1,196 @@ +# encoding: utf-8 +doSave=Uložiť +doCancel=Zrušiť +doLogOutAllSessions=Odhlásenie všetkých relácií +doRemove=Odstrániť +doAdd=Pridať +doSignOut=Odhlásiť + +editAccountHtmlTitle=Upraviť účet +federatedIdentitiesHtmlTitle=Prepojená identita +accountLogHtmlTitle=Denník zmien užívateľských účtov +changePasswordHtmlTitle=Zmena hesla +sessionsHtmlTitle=Relácie +accountManagementTitle=Správa účtu Keycloak +authenticatorTitle=Autentifikátor +applicationsHtmlTitle=Aplikácie + +authenticatorCode=Jednorázový kód +email=E-mail +firstName=Meno +givenName=Meno pri narodení +fullName=Celé meno +lastName=Priezvisko +familyName=Rodné meno +password=Heslo +passwordConfirm=Potrvrdenie hesla +passwordNew=Nové heslo +username=Meno používateľa +address=Adresa +street=Ulica +locality=Mesto alebo lokalita +region=Kraj +postal_code=PSČ +country=Štát +emailVerified=E-mail overený +gssDelegationCredential=GSS delegované oprávnenie + +role_admin=Administrátor +role_realm-admin=Administrátor realmu +role_create-realm=Vytvoriť realm +role_view-realm=Zobraziť realm +role_view-users=Zobraziť používateľov +role_view-applications=Zobraziť aplikácie +role_view-clients=Zobraziť klientov +role_view-events=Zobraziť udalosti +role_view-identity-providers=Zobraziť klientov poskytovateľov identity +role_manage-realm=Spravovať realm +role_manage-users=Spravovať používateľov +role_manage-applications=Spravovať aplikácie +role_manage-identity-providers=Spravovať poskytovateľov identity +role_manage-clients=Spravovať klientov +role_manage-events=Spravovať udalosti +role_view-profile=Zobraziť profil +role_manage-account=Spravovať účet +role_manage-account-links=Spravovať odkazy na účet +role_read-token=Čítať token +role_offline-access=Offline prístup +role_uma_authorization=Autorizácia používateľom riadeného prístupu +client_account=Účet klienta +client_security-admin-console=Bezpečnostná administrátorská konzola +client_admin-cli=Spravovať CLI klienta +client_realm-management=Spravovať realmy klienta +client_broker=Broker + + +requiredFields=Povinné polia +allFieldsRequired=Všetky požadované polia + +backToApplication=« Späť na aplikáciu +backTo=Späť na {0} + +date=Dátum +event=Udalosť +ip=IP +client=Klient +clients=Klienti +details=Podrobnosti +started=Začíname +lastAccess=Posledný prístup +expires=Vyprší +applications=Aplikácie + +account=Účet +federatedIdentity=Prepojená identita +authenticator=Autentifikátor +sessions=Relácie +log=Denník + +application=Aplikácia +availablePermissions=Dostupné oprávnenia +grantedPermissions=Pridelené oprávnenia +grantedPersonalInfo=Poskytnuté osobné informácie +additionalGrants=Dodatočné oprávnenia +action=Akcia +inResource=v +fullAccess=Úplný prístup +offlineToken=Offline token +revoke=Zrušiť oprávnenie + +configureAuthenticators=Nakonfigurované autentifikátory +mobile=Mobilný +totpStep1=Nainštalujte vo svojom zariadení FreeOTP alebo Google Authenticator. Obidve aplikácie sú k dispozícii v Google Play a Apple App Store. +totpStep2=Otvorte aplikáciu a naskenujte čiarový kód alebo zadajte kľúč. +totpStep3=Zadajte jednorazový kód poskytnutý aplikáciou a kliknutím na tlačidlo Uložiť dokončíte nastavenie. + +totpManualStep2=Otvorte aplikáciu a zadajte kľúč +totpManualStep3=Použite nasledujúce hodnoty konfigurácie, ak aplikácia umožňuje ich nastavenie +totpUnableToScan=Nemožno skenovať? +totpScanBarcode=Skenovanie čiarového kódu? + +totp.totp=Založené na čase +totp.hotp=Založené na počítadle + +totpType=Typ +totpAlgorithm=Algoritmus +totpDigits=Číslica +totpInterval=Interval +totpCounter=Počítadlo + +missingUsernameMessage=Zadajte používateľské meno. +missingFirstNameMessage=Zadajte meno. +invalidEmailMessage=Neplatná e-mailová adresa. +missingLastNameMessage=Zadajte priezvisko. +missingEmailMessage=Zadajte e-mail. +missingPasswordMessage=Zadajte heslo, prosím. +notMatchPasswordMessage=Heslá sa nezhodujú. + +missingTotpMessage=Zadajte jednorazový kód, prosím +invalidPasswordExistingMessage=Neplatné existujúce heslo. +invalidPasswordConfirmMessage=Potvrdenie hesla sa nezhoduje. +invalidTotpMessage=Neplatný jednorazový kód. + +usernameExistsMessage=Užívateľské meno už existuje. +emailExistsMessage=E-mail už existuje. + +readOnlyUserMessage=Váš účet nemôžete aktualizovať, pretože je iba na čítanie. +readOnlyUsernameMessage=Nemôžete aktualizovať svoje používateľské meno, pretože je iba na čítanie. +readOnlyPasswordMessage=Heslo nemôžete aktualizovať, pretože váš účet je iba na čítanie. + +successTotpMessage=Konfigurácia mobilného autentifikátora. +successTotpRemovedMessage=Mobilný autentifikátor bol odstránený. + +successGrantRevokedMessage=Oprávnenie bolo úspešne zrušené. + +accountUpdatedMessage=Váš účet bol aktualizovaný. +accountPasswordUpdatedMessage=Vaše heslo bolo aktualizované. + +missingIdentityProviderMessage=Poskytovateľ identity nie je zadaný. +invalidFederatedIdentityActionMessage=Neplatná alebo chýbajúca akcia. +identityProviderNotFoundMessage=Zadaný poskytovateľ identity nenájdený. +federatedIdentityLinkNotActiveMessage=Identita už nie je aktívna. +federatedIdentityRemovingLastProviderMessage=Nemôžete odstrániť poslednú spojenú identitu, pretože nemáte heslo. +identityProviderRedirectErrorMessage=Nepodarilo sa presmerovať na poskytovateľa identity. +identityProviderRemovedMessage=Poskytovateľ identity bol úspešne odstránený. +identityProviderAlreadyLinkedMessage=Spojená identita vrátená {0} je už prepojená s iným používateľom. +staleCodeAccountMessage=Platnosť vypršala. Skúste ešte raz. +consentDenied=Súhlas bol zamietnutý. + +accountDisabledMessage=Účet je zakázaný, kontaktujte správcu. + +accountTemporarilyDisabledMessage=Účet je dočasne zakázaný, kontaktujte administrátora alebo skúste neskôr. +invalidPasswordMinLengthMessage=Neplatné heslo: minimálna dĺžka {0}. +invalidPasswordMinLowerCaseCharsMessage=Neplatné heslo: musí obsahovať minimálne {0} malé písmená. +invalidPasswordMinDigitsMessage=Neplatné heslo: musí obsahovať aspoň {0} číslic. +invalidPasswordMinUpperCaseCharsMessage=Neplatné heslo: musí obsahovať aspoň {0} veľké písmená. +invalidPasswordMinSpecialCharsMessage=Neplatné heslo: musí obsahovať aspoň {0} špeciálne znaky. +invalidPasswordNotUsernameMessage=Neplatné heslo: nesmie byť rovnaké ako používateľské meno. +invalidPasswordRegexPatternMessage=Neplatné heslo: nezodpovedá regulárnemu výrazu. +invalidPasswordHistoryMessage=Neplatné heslo: nesmie sa rovnať žiadnemu z posledných {0} hesiel. +invalidPasswordBlacklistedMessage=Neplatné heslo: heslo je na čiernej listine. +invalidPasswordGenericMessage=Neplatné heslo: nové heslo nezodpovedá pravidlám hesiel. + +# Authorization +myResources=Moje Zdroje +myResourcesSub=Moje zdroje +doDeny=Zakázať +doRevoke=Odvolať +doApprove=Schváliť +doRemoveSharing=Odstránenie zdieľania +doRemoveRequest=Odstrániť požiadavku +peopleAccessResource=Ľudia s prístupom k tomuto zdroju +name=Názov +scopes=Rozsahy +resource=Zdroj +user=Používateľ +peopleSharingThisResource=Ľudia zdieľajúci tento zdroj +shareWithOthers=Zdieľať s ostatnými +needMyApproval=Potrebuje môj súhlas +requestsWaitingApproval=Vaše požiadavky čakajú na schválenie +icon=Ikona +requestor=Žiadateľ +owner=Vlastník +resourcesSharedWithMe=Zdroje zdieľané so mnou +permissionRequestion=Žiadosti o povolenie +permission=Oprávnenie +shares=podiel (y) diff --git a/keycloak-themes/base/account/messages/messages_sv.properties b/keycloak-themes/base/account/messages/messages_sv.properties new file mode 100644 index 0000000..cc134cd --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_sv.properties @@ -0,0 +1,150 @@ +# encoding: utf-8 +doSave=Spara +doCancel=Avbryt +doLogOutAllSessions=Logga ut från samtliga sessioner +doRemove=Ta bort +doAdd=Lägg till +doSignOut=Logga ut + +editAccountHtmlTitle=Redigera konto +federatedIdentitiesHtmlTitle=Federerade identiteter +accountLogHtmlTitle=Kontologg +changePasswordHtmlTitle=Byt lösenord +sessionsHtmlTitle=Sessioner +accountManagementTitle=Kontohantering för Keycloak +authenticatorTitle=Autentiserare +applicationsHtmlTitle=Applikationer + +authenticatorCode=Engångskod +email=E-post +firstName=Förnamn +lastName=Efternamn +password=Lösenord +passwordConfirm=Bekräftelse +passwordNew=Nytt lösenord +username=Användarnamn +address=Adress +street=Gata +locality=Postort +region=Stat, Provins eller Region +postal_code=Postnummer +country=Land +emailVerified=E-post verifierad +gssDelegationCredential=GSS Delegation Credential + +role_admin=Administratör +role_realm-admin=Realm-administratör +role_create-realm=Skapa realm +role_view-realm=Visa realm +role_view-users=Visa användare +role_view-applications=Visa applikationer +role_view-clients=Visa klienter +role_view-events=Visa event +role_view-identity-providers=Visa identitetsleverantörer +role_manage-realm=Hantera realm +role_manage-users=Hantera användare +role_manage-applications=Hantera applikationer +role_manage-identity-providers=Hantera identitetsleverantörer +role_manage-clients=Hantera klienter +role_manage-events=Hantera event +role_view-profile=Visa profil +role_manage-account=Hantera konto +role_read-token=Läs element +role_offline-access=Åtkomst offline +role_uma_authorization=Erhåll tillstånd +client_account=Konto +client_security-admin-console=Säkerhetsadministratörskonsol +client_admin-cli=Administratörs-CLI +client_realm-management=Realmhantering + + +requiredFields=Obligatoriska fält +allFieldsRequired=Samtliga fält krävs + +backToApplication=« Tillbaka till applikationen +backTo=Tillbaka till {0} + +date=Datum +event=Event +ip=IP +client=Klient +clients=Klienter +details=Detaljer +started=Startade +lastAccess=Senast åtkomst +expires=Upphör +applications=Applikationer + +account=Konto +federatedIdentity=Federerad identitet +authenticator=Autentiserare +sessions=Sessioner +log=Logg + +application=Applikation +availablePermissions=Tillgängliga rättigheter +grantedPermissions=Beviljade rättigheter +grantedPersonalInfo=Medgiven personlig information +additionalGrants=Ytterligare medgivanden +action=Åtgärd +inResource=i +fullAccess=Fullständig åtkomst +offlineToken=Offline token +revoke=Upphäv rättighet + +configureAuthenticators=Konfigurerade autentiserare +mobile=Mobil +totpStep1=Installera FreeOTP eller Google Authenticator på din enhet. Båda applikationerna finns tillgängliga på Google Play och Apple App Store. +totpStep2=Öppna applikationen och skanna streckkoden eller skriv i nyckeln. +totpStep3=Fyll i engångskoden som tillhandahålls av applikationen och klicka på Spara för att avsluta inställningarna. + +missingUsernameMessage=Vänligen ange användarnamn. +missingFirstNameMessage=Vänligen ange förnamn. +invalidEmailMessage=Ogiltig e-postadress. +missingLastNameMessage=Vänligen ange efternamn. +missingEmailMessage=Vänligen ange e-post. +missingPasswordMessage=Vänligen ange lösenord. +notMatchPasswordMessage=Lösenorden matchar inte. + +missingTotpMessage=Vänligen ange autentiseringskoden. +invalidPasswordExistingMessage=Det nuvarande lösenordet är ogiltigt. +invalidPasswordConfirmMessage=Lösenordsbekräftelsen matchar inte. +invalidTotpMessage=Autentiseringskoden är ogiltig. + +usernameExistsMessage=Användarnamnet finns redan. +emailExistsMessage=E-posten finns redan. + +readOnlyUserMessage=Du kan inte uppdatera ditt konto eftersom det är skrivskyddat. +readOnlyPasswordMessage=Du kan inte uppdatera ditt lösenord eftersom ditt konto är skrivskyddat. + +successTotpMessage=Mobilautentiseraren är inställd. +successTotpRemovedMessage=Mobilautentiseraren är borttagen. + +successGrantRevokedMessage=Upphävandet av rättigheten lyckades. + +accountUpdatedMessage=Ditt konto har uppdaterats. +accountPasswordUpdatedMessage=Ditt lösenord har uppdaterats. + +missingIdentityProviderMessage=Identitetsleverantör är inte angiven. +invalidFederatedIdentityActionMessage=Åtgärden är ogiltig eller saknas. +identityProviderNotFoundMessage=Angiven identitetsleverantör hittas inte. +federatedIdentityLinkNotActiveMessage=Den här identiteten är inte längre aktiv. +federatedIdentityRemovingLastProviderMessage=Du kan inte ta bort senaste federerade identiteten eftersom du inte har ett lösenord. +identityProviderRedirectErrorMessage=Misslyckades med att omdirigera till identitetsleverantör. +identityProviderRemovedMessage=Borttagningen av identitetsleverantören lyckades. +identityProviderAlreadyLinkedMessage=Den federerade identiteten som returnerades av {0} är redan länkad till en annan användare. +staleCodeAccountMessage=Sidan har upphört att gälla. Vänligen försök igen. +consentDenied=Samtycket förnekades. + +accountDisabledMessage=Kontot är inaktiverat, kontakta administratör. + +accountTemporarilyDisabledMessage=Kontot är tillfälligt inaktiverat, kontakta administratör eller försök igen senare. +invalidPasswordMinLengthMessage=Ogiltigt lösenord. Minsta längd är {0}. +invalidPasswordMinLowerCaseCharsMessage=Ogiltigt lösenord: måste innehålla minst {0} små bokstäver. +invalidPasswordMinDigitsMessage=Ogiltigt lösenord: måste innehålla minst {0} siffror. +invalidPasswordMinUpperCaseCharsMessage=Ogiltigt lösenord: måste innehålla minst {0} stora bokstäver. +invalidPasswordMinSpecialCharsMessage=Ogiltigt lösenord: måste innehålla minst {0} specialtecken. +invalidPasswordNotUsernameMessage=Ogiltigt lösenord: Får inte vara samma som användarnamnet. +invalidPasswordRegexPatternMessage=Ogiltigt lösenord: matchar inte kravet för lösenordsmönster. +invalidPasswordHistoryMessage=Ogiltigt lösenord: Får inte vara samma som de senaste {0} lösenorden. +invalidPasswordGenericMessage=Ogiltigt lösenord: Det nya lösenordet stämmer inte med lösenordspolicyn. \ No newline at end of file diff --git a/keycloak-themes/base/account/messages/messages_tr.properties b/keycloak-themes/base/account/messages/messages_tr.properties new file mode 100644 index 0000000..5b19938 --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_tr.properties @@ -0,0 +1,315 @@ +doSave=Kaydet +doCancel=\u0130ptal +doLogOutAllSessions=T\u00FCm Oturumlar\u0131 Kapat +doRemove=Sil +doAdd=Ekle +doSignOut=\u00C7\u0131k\u0131\u015F +doLogIn=Oturum a\u00E7 +doLink=Ba\u011Flant\u0131 + + +editAccountHtmlTitle=Hesab\u0131m +personalInfoHtmlTitle=Ki\u015Fisel bilgi +federatedIdentitiesHtmlTitle=De\u011Fi\u015Ftirilen Kimlikler +accountLogHtmlTitle=Kullan\u0131c\u0131 Loglar\u0131 +changePasswordHtmlTitle=\u015Eifre De\u011Fi\u015Ftirme +deviceActivityHtmlTitle=Cihaz Etkinli\u011Fi +sessionsHtmlTitle=Oturum +accountManagementTitle=Keycloak Kullan\u0131c\u0131 Hesab\u0131 Y\u00F6netimi +authenticatorTitle=Kimlik Do\u011Frulama +applicationsHtmlTitle=Uygulama +linkedAccountsHtmlTitle=Ba\u011Flant\u0131l\u0131 Hesaplar + +accountManagementWelcomeMessage=Keycloak Hesap Y\u00F6netimine Ho\u015F Geldiniz +personalInfoIntroMessage=Temel bilgilerinizi y\u00F6netin +accountSecurityTitle=Hesap G\u00FCvenli\u011Fi +accountSecurityIntroMessage=\u015Eifrenizi ve hesap eri\u015Fiminizi kontrol edin +applicationsIntroMessage=Hesab\u0131n\u0131za eri\u015Fmek i\u00E7in uygulama izninizi takip edin ve y\u00F6netin +resourceIntroMessage=Kaynaklar\u0131n\u0131z\u0131 ekip \u00FCyeleri aras\u0131nda payla\u015F\u0131n +passwordLastUpdateMessage=\u015Eifreniz g\u00FCncellendi +updatePasswordTitle=\u015Eifre g\u00FCncelle +updatePasswordMessageTitle=G\u00FC\u00E7l\u00FC bir \u015Fifre se\u00E7ti\u011Finizden emin olun +updatePasswordMessage=G\u00FC\u00E7l\u00FC bir \u015Fifre, say\u0131lar, harfler ve sembollerin kar\u0131\u015F\u0131m\u0131ndan olu\u015Fmal\u0131d\u0131r. Tahmin etmesi zor ve ger\u00E7ek bir kelimeye benzemeyen \u015Fifre sadece bu hesap i\u00E7in kullan\u0131l\u0131r. +personalSubTitle=Ki\u015Fisel Bilgileriniz +personalSubMessage=Bu temel bilgileri y\u00F6netin: ad\u0131n\u0131z, soyad\u0131n\u0131z ve e-posta adresiniz + +authenticatorCode=Kimlik Do\u011Frulama Kodu +email=E-Mail +firstName=Ad +givenName=Ad +fullName=Ad Soyad +lastName=Soyad +familyName=Soyad +password=\u015Eifre +currentPassword=\u015Eimdiki \u015Eifre +passwordConfirm=\u015Eifre Do\u011Frulama +passwordNew=Yeni \u015Eifre +username=Kullan\u0131c\u0131 Ad\u0131 +address=Adres +street=Cadde +region=B\u00F6lge +postal_code=Posta Kodu +locality=\u015Eehir +country=\u00DClke +emailVerified=E-Mail Do\u011Fruland\u0131 +gssDelegationCredential=GSS Yetki Bilgisi + +profileScopeConsentText=Kullan\u0131c\u0131 profili +emailScopeConsentText=Email adresi +addressScopeConsentText=Adres +phoneScopeConsentText=Telefon numaras\u0131 +offlineAccessScopeConsentText=\u00C7evrimd\u0131\u015F\u0131 Eri\u015Fim +samlRoleListScopeConsentText=Rollerim +rolesScopeConsentText=Kullan\u0131c\u0131 rolleri + +role_admin=Admin +role_realm-admin=Realm Admin +role_create-realm=Realm Olu\u015Ftur +role_view-realm=Realm g\u00F6r\u00FCnt\u00FCle +role_view-users=Kullan\u0131c\u0131lar\u0131 g\u00F6r\u00FCnt\u00FCle +role_view-applications=Uygulamalar\u0131 g\u00F6r\u00FCnt\u00FCle +role_view-clients=\u0130stemci g\u00F6r\u00FCnt\u00FCle +role_view-events=Olay g\u00F6r\u00FCnt\u00FCle +role_view-identity-providers=Kimlik Sa\u011Flay\u0131c\u0131lar +role_manage-realm=Realm y\u00F6net +role_manage-users=Kullan\u0131c\u0131lar\u0131 y\u00F6net +role_manage-applications=Uygulamalar\u0131 y\u00F6net +role_manage-identity-providers=Kimlik Sa\u011Flay\u0131c\u0131lar\u0131 Y\u00F6net +role_manage-clients=\u0130stemci y\u00F6net +role_manage-events=Olay y\u00F6net +role_view-profile=Profilleri g\u00F6r\u00FCnt\u00FCle +role_manage-account=Profilleri Y\u00F6net +role_manage-account-links=Profil ba\u011Flant\u0131lar\u0131n\u0131 y\u00F6net +role_read-token=Token oku +role_offline-access=\u00C7evirimd\u0131\u015F\u0131 Yetki +role_uma_authorization=\u0130zinleri Al +client_account=M\u00FC\u015Fteri Hesab\u0131 +client_security-admin-console=G\u00FCvenlik Y\u00F6netici Konsolu +client_admin-cli=Admin CLI +client_realm-management=Realm-Management +client_broker=Broker + +requiredFields=Zorunlu Alanlar +allFieldsRequired=T\u00FCm Alanlar Zorunlu + +backToApplication=« Uygulamaya D\u00F6n +backTo=Geri D\u00F6n {0} + +date=G\u00FCn +event=Olay +ip=IP +client=\u0130stemci +clients=\u0130stemciler +details=Detaylar +started=Ba\u015Flang\u0131\u00E7 Tarihi +lastAccess=Son Eri\u015Fim Tarihi +expires=Son Kullanma Tarihi +applications=Uygulama + +account=Hesap +federatedIdentity=Federal Kimlik +authenticator=Kimlik Do\u011Frulama +device-activity=Cihaz Etkinli\u011Fi +sessions=Oturum +log=Log + +application=Uygulama +availablePermissions=Kullan\u0131labilir \u0130zinler +availableRoles=Kullan\u0131labilir Roller +grantedPermissions=Verilen \u0130zinler +grantedPersonalInfo=\u0130zin Verilen Ki\u015Fisel Bilgiler +additionalGrants=Ek \u0130zinler +action=Aksiyon +inResource=Kaynak +fullAccess=Tam Yetki +offlineToken=\u00C7evirimd\u0131\u015F\u0131-Token +revoke=\u0130zni \u0130ptal et + +configureAuthenticators=\u00C7oklu Kimlik Do\u011Frulama +mobile=Mobil +totpStep1=Ak\u0131ll\u0131 Telefonunuza a\u015Fa\u011F\u0131daki uygulamalardan birini y\u00FCkleyin: +totpStep2=Uygulamay\u0131 a\u00E7\u0131n ve barkodu okutun. +totpStep3=Uygulama taraf\u0131ndan olu\u015Fturulan tek seferlik kodu girin ve Kaydet''i t\u0131klay\u0131n. + +totpManualStep2=Uygulamay\u0131 a\u00E7\u0131n ve a\u015Fa\u011F\u0131daki anahtar\u0131 girin. +totpManualStep3=Bunlar\u0131 uygulama i\u00E7in \u00F6zelle\u015Ftirebilirseniz a\u015Fa\u011F\u0131daki yap\u0131land\u0131rma de\u011Ferlerini kullan\u0131n: +totpUnableToScan=Barkodu tarayam\u0131yor musunuz? +totpScanBarcode=Barkod Tara? + +totp.totp=Zaman bazl\u0131 (time-based) +totp.hotp=Saya\u00E7 tabanl\u0131 (counter-based) + +totpType=Tip +totpAlgorithm=Algoritma +totpDigits=Basamak +totpInterval=Aral\u0131k +totpCounter=Saya\u00E7 + +missingUsernameMessage=L\u00FCtfen bir kullan\u0131c\u0131 ad\u0131 giriniz. +missingFirstNameMessage=L\u00FCtfen bir ad girin. +invalidEmailMessage=Ge\u00E7ersiz e-posta adresi. +missingLastNameMessage=L\u00FCtfen bir soyad\u0131 giriniz. +missingEmailMessage=L\u00FCtfen bir e-mail adresi giriniz. +missingPasswordMessage=L\u00FCtfen bir \u015Fifre giriniz. +notMatchPasswordMessage=\u015Eifreler ayn\u0131 de\u011Fil. + +missingTotpMessage=L\u00FCtfen tek seferlik kodu girin. +invalidPasswordExistingMessage=Mevcut \u015Fifre ge\u00E7ersiz. +invalidPasswordConfirmMessage=\u015Eifre onay\u0131 ayn\u0131 de\u011Fil. +invalidTotpMessage=Ge\u00E7ersiz tek seferlik kod. + +usernameExistsMessage=Kullan\u0131c\u0131 ad\u0131 zaten mevcut. +emailExistsMessage=E-posta adresi zaten mevcut. + +readOnlyUserMessage=Yazma korumal\u0131 oldu\u011Fundan kullan\u0131c\u0131 hesab\u0131n\u0131z\u0131 de\u011Fi\u015Ftiremezsiniz. +readOnlyUsernameMessage=Yazma korumal\u0131 oldu\u011Fundan kullan\u0131c\u0131 ad\u0131n\u0131z\u0131 de\u011Fi\u015Ftiremezsiniz. +readOnlyPasswordMessage=Yazma korumal\u0131 oldu\u011Fundan \u015Fifrenizi de\u011Fi\u015Ftiremezsiniz. + +successTotpMessage=\u00C7oklu kimlik do\u011Frulamas\u0131 ba\u015Far\u0131yla yap\u0131land\u0131r\u0131ld\u0131. +successTotpRemovedMessage=\u00C7oklu kimlik do\u011Frulama ba\u015Far\u0131yla kald\u0131r\u0131ld\u0131. + +successGrantRevokedMessage=\u0130zin ba\u015Far\u0131yla iptal edildi. + +accountUpdatedMessage=Kullan\u0131c\u0131 hesab\u0131n\u0131z g\u00FCncellendi. +accountPasswordUpdatedMessage=\u015Eifreniz g\u00FCncellendi. + +missingIdentityProviderMessage=Kimlik Sa\u011Flay\u0131c\u0131s\u0131 belirtilmemi\u015F. +invalidFederatedIdentityActionMessage=Ge\u00E7ersiz veya eksik eylem. +identityProviderNotFoundMessage=Belirtilen Kimlik Sa\u011Flay\u0131c\u0131 bulunamad\u0131. +federatedIdentityLinkNotActiveMessage=Bu kimlik art\u0131k aktif de\u011Fil. +federatedIdentityRemovingLastProviderMessage=\u015Eifreniz olmad\u0131\u011F\u0131 i\u00E7in son giri\u015Fi kald\u0131ramazs\u0131n\u0131z. +identityProviderRedirectErrorMessage=Kimlik sa\u011Flay\u0131c\u0131ya iletilirken hata olu\u015Ftu. +identityProviderRemovedMessage=Kimlik Sa\u011Flay\u0131c\u0131s\u0131 ba\u015Far\u0131yla kald\u0131r\u0131ld\u0131. +identityProviderAlreadyLinkedMessage=De\u011Fi\u015Ftirilmi\u015F {0} kimli\u011Fi ba\u015Fka bir kullan\u0131c\u0131ya atanm\u0131\u015F. +staleCodeAccountMessage=Bu sayfa art\u0131k ge\u00E7erli de\u011Fil, l\u00FCtfen tekrar deneyin. +consentDenied=Onay reddedildi. + +accountDisabledMessage=Hesab\u0131n\u0131z kilitlendi, l\u00FCtfen y\u00F6neticiyle ileti\u015Fime ge\u00E7in. + +accountTemporarilyDisabledMessage=Hesab\u0131n\u0131z ge\u00E7ici olarak kilitlendi, l\u00FCtfen y\u00F6neticiyle ileti\u015Fime ge\u00E7in veya daha sonra tekrar deneyin. +invalidPasswordMinLengthMessage=Ge\u00E7ersiz \u015Eifre: En az {0} karakter uzunlu\u011Funda olmal\u0131. +invalidPasswordMinLowerCaseCharsMessage=Ge\u00E7ersiz \u015Eifre \: En az {0} k\u00FC\u00E7\u00FCk harf i\u00E7ermelidir. +invalidPasswordMinDigitsMessage=Ge\u00E7ersiz \u015Eifre: En az {0} say\u0131(lar) i\u00E7ermelidir. +invalidPasswordMinUpperCaseCharsMessage=Ge\u00E7ersiz \u015Eifre: En az {0} b\u00FCy\u00FCk harf i\u00E7ermelidir. +invalidPasswordMinSpecialCharsMessage=Ge\u00E7ersiz \u015Eifre: En az {0} \u00F6zel karakter i\u00E7ermelidir. +invalidPasswordNotUsernameMessage=Ge\u00E7ersiz \u015Eifre: Kullan\u0131c\u0131 ad\u0131yla ayn\u0131 olamaz. +invalidPasswordRegexPatternMessage=Ge\u00E7ersiz \u015Eifre: Regex Patternine uygun de\u011Fil. +invalidPasswordHistoryMessage=Ge\u00E7ersiz \u015Eifre: Son {0} \u015Fifreden biri olamaz. +invalidPasswordBlacklistedMessage=Ge\u00E7ersiz \u015Eifre: \u015Eifre bloklanm\u0131\u015F \u015Fifreler listesindedir (kara liste). +invalidPasswordGenericMessge=Ge\u00E7ersiz \u015Eifre: Yeni \u015Fifre, \u015Fifre kurallar\u0131n\u0131 ihlal ediyor. + + + +# Authorization +myResources=Kaynaklar\u0131m +myResourcesSub=Kaynaklar\u0131m +doDeny=Reddet +doRevoke=Geri al +doApprove=Onayla +doRemoveSharing=Payla\u015F\u0131m\u0131 Kald\u0131r +doRemoveRequest=\u0130ste\u011Fi Kald\u0131r +peopleAccessResource=Bu kayna\u011Fa eri\u015Fimi olan ki\u015Filer +resourceManagedPolicies=Bu kayna\u011Fa eri\u015Fim izni veren izinler +resourceNoPermissionsGrantingAccess=Bu kayna\u011Fa eri\u015Fim izni verilmeyen izin yok +anyAction=Herhangi bir eylem +description=A\u00E7\u0131klama +name=\u0130sim +scopes=Kapsam +resource=Kaynak +user=Kullan\u0131c\u0131 +peopleSharingThisResource=Bu kayna\u011F\u0131 payla\u015Fan kullan\u0131c\u0131lar +shareWithOthers=Ba\u015Fkalar\u0131yla payla\u015F +needMyApproval=Onay\u0131m gerekli +requestsWaitingApproval=Talepleriniz onay bekliyor +icon=Icon +requestor=Talep eden +owner=Sahip +resourcesSharedWithMe=Kaynaklar benimle payla\u015F\u0131ld\u0131 +permissionRequestion=\u0130zin Talepleri +permission=\u0130zin +shares=Payla\u015F\u0131m(lar) + +# Applications +applicationName=\u0130sim +applicationType=Uygulama Tipi +applicationInUse=Yaln\u0131zca uygulama i\u00E7i kullan\u0131m +clearAllFilter=T\u00FCm filtreleri temizle +activeFilters=Aktif filtreler +filterByName=\u0130sme G\u00F6re Filtrele ... +allApps=B\u00FCt\u00FCn uygulamalar +internalApps=\u0130\u00E7 uygulamalar +thirdpartyApps=\u00DC\u00E7\u00FCnc\u00FC parti uygulamalar +appResults=Sonu\u00E7lar + +# Linked account +authorizedProvider=Yetkili Tedarik\u00E7i +authorizedProviderMessage=Yetkili Sa\u011Flay\u0131c\u0131lar hesab\u0131n\u0131zla ba\u011Flant\u0131l\u0131 +identityProvider=Kimlik Sa\u011Flay\u0131c\u0131s\u0131 +identityProviderMessage=Hesab\u0131n\u0131z\u0131 yap\u0131land\u0131rd\u0131\u011F\u0131n\u0131z kimlik sa\u011Flay\u0131c\u0131lar\u0131yla ba\u011Flamak i\u00E7in +socialLogin=Sosyal Giri\u015F +userDefined=Kullan\u0131c\u0131 tan\u0131ml\u0131 +removeAccess=Eri\u015Fimi Kald\u0131r +removeAccessMessage=Bu uygulama hesab\u0131n\u0131 kullanmak istiyorsan\u0131z tekrar eri\u015Fim vermeniz gerekir. + +#Authenticator +authenticatorStatusMessage=\u0130ki fakt\u00F6rl\u00FC kimlik do\u011Frulama aktif +authenticatorFinishSetUpTitle=\u0130ki Fakt\u00F6rl\u00FC Do\u011Frulama +authenticatorFinishSetUpMessage=Keycloak hesab\u0131n\u0131zda her oturum a\u00E7t\u0131\u011F\u0131n\u0131zda, iki fakt\u00F6rl\u00FC bir do\u011Frulama kodu girmeniz istenecektir. +authenticatorSubTitle=\u0130ki Fakt\u00F6rl\u00FC Kimlik Do\u011Frulamay\u0131 Ayarlama +authenticatorSubMessage=Hesab\u0131n\u0131z\u0131n g\u00FCvenli\u011Fini art\u0131rmak i\u00E7in mevcut iki fakt\u00F6rl\u00FC kimlik do\u011Frulama y\u00F6ntemlerinden en az birini etkinle\u015Ftirin. +authenticatorMobileTitle=Mobil Kimlik Do\u011Frulay\u0131c\u0131 +authenticatorMobileMessage=Do\u011Frulama kodlar\u0131n\u0131 iki fakt\u00F6rl\u00FC kimlik do\u011Frulama olarak almak i\u00E7in mobil Do\u011Frulay\u0131c\u0131''y\u0131 kullan\u0131n. +authenticatorMobileFinishSetUpMessage=Do\u011Frulay\u0131c\u0131, telefonunuza ba\u011Fl\u0131. +authenticatorActionSetup=Kur +authenticatorSMSTitle=SMS Kodu +authenticatorSMSMessage=Keycloak, do\u011Frulama kodunu telefonunuza iki fakt\u00F6rl\u00FC kimlik do\u011Frulamas\u0131 olarak g\u00F6nderecektir. +authenticatorSMSFinishSetUpMessage=K\u0131sa mesajlar g\u00F6nderilir +authenticatorDefaultStatus=Varsay\u0131lan +authenticatorChangePhone=Telefon Numaras\u0131n\u0131 De\u011Fi\u015Ftir + +#Authenticator - Mobile Authenticator setup +authenticatorMobileSetupTitle=Mobil Kimlik Do\u011Frulama Kurulumu +smscodeIntroMessage=Telefon numaran\u0131z\u0131 girin ve telefonunuza bir do\u011Frulama kodu g\u00F6nderilecektir. +mobileSetupStep1=Telefonunuza bir kimlik do\u011Frulama uygulamas\u0131 y\u00FCkleyin. Burada listelenen uygulamalar desteklenmektedir. +mobileSetupStep2=Uygulamay\u0131 a\u00E7\u0131n ve barkodu taray\u0131n. +mobileSetupStep3=Uygulama taraf\u0131ndan sa\u011Flanan tek seferlik kodu girin ve kurulumu tamamlamak i\u00E7in Kaydet''e t\u0131klay\u0131n. +scanBarCode=Barkodu taramak ister misiniz? +enterBarCode=Tek seferlik kodu girin +doCopy=Kopyala +doFinish=Bitir + +#Authenticator - SMS Code setup +authenticatorSMSCodeSetupTitle=SMS Kodu Kurulumu +chooseYourCountry=\u00DClkenizi se\u00E7in +enterYourPhoneNumber=Telefon numaran\u0131z\u0131 girin +sendVerficationCode=Do\u011Frulama kodu G\u00F6nder +enterYourVerficationCode=Onaylama kodunu girin + +#Authenticator - backup Code setup +authenticatorBackupCodesSetupTitle=Yedekleme Kodlar\u0131 Kurulumu +realmName=Realm +doDownload=\u0130ndir +doPrint=Yazd\u0131r +generateNewBackupCodes=Yeni Yedekleme Kodlar\u0131 Olu\u015Ftur +backtoAuthenticatorPage=Kimlik Do\u011Frulay\u0131c\u0131 Sayfas\u0131na Geri D\u00F6n + +#Resources +resources=Kaynaklar +sharedwithMe=Benimle payla\u015Ft\u0131 +share=Payla\u015F\u0131m +sharedwith=\u0130le payla\u015Ft\u0131 +accessPermissions=Eri\u015Fim \u0130zinleri +permissionRequests=\u0130zin \u0130stekleri +approve=Onayla +approveAll=T\u00FCm\u00FCn\u00FC onayla +people=\u0130nsanlar +perPage=Sayfa ba\u015F\u0131na +currentPage=Ge\u00E7erli sayfa +sharetheResource=Kayna\u011F\u0131 payla\u015F +group=Grup +selectPermission=\u0130zin Se\u00E7 +addPeople=Kayna\u011F\u0131n\u0131z\u0131 payla\u015Fmak i\u00E7in kullan\u0131c\u0131 ekleyin +addTeam=Kayna\u011F\u0131n\u0131z\u0131 payla\u015Fmak i\u00E7in ekip ekleyin +myPermissions=\u0130zinlerim +waitingforApproval=Onay bekleniyor +anyPermission=Herhangi bir izin diff --git a/keycloak-themes/base/account/messages/messages_zh_CN.properties b/keycloak-themes/base/account/messages/messages_zh_CN.properties new file mode 100644 index 0000000..bbef84e --- /dev/null +++ b/keycloak-themes/base/account/messages/messages_zh_CN.properties @@ -0,0 +1,153 @@ +# encoding: utf-8 +doSave=保存 +doCancel=取消 +doLogOutAllSessions=登出所有会话 +doRemove=删除 +doAdd=添加 +doSignOut=登出 + +editAccountHtmlTitle=编辑账户 +federatedIdentitiesHtmlTitle=链接的身份 +accountLogHtmlTitle=账户日志 +changePasswordHtmlTitle=更改密码 +sessionsHtmlTitle=会话 +accountManagementTitle=Keycloak账户管理 +authenticatorTitle=认证者 +applicationsHtmlTitle=应用 + +authenticatorCode=一次性认证码 +email=电子邮件 +firstName=名 +givenName=姓 +fullName=全名 +lastName=姓 +familyName=姓 +password=密码 +passwordConfirm=确认 +passwordNew=新密码 +username=用户名 +address=地址 +street=街道 +locality=城市住所 +region=省,自治区,直辖市 +postal_code=邮政编码 +country=国家 +emailVerified=验证过的Email +gssDelegationCredential=GSS Delegation Credential + +role_admin=管理员 +role_realm-admin=域管理员 +role_create-realm=创建域 +role_view-realm=查看域 +role_view-users=查看用户 +role_view-applications=查看应用 +role_view-clients=查看客户 +role_view-events=查看事件 +role_view-identity-providers=查看身份提供者 +role_manage-realm=管理域 +role_manage-users=管理用户 +role_manage-applications=管理应用 +role_manage-identity-providers=管理身份提供者 +role_manage-clients=管理客户 +role_manage-events=管理事件 +role_view-profile=查看用户信息 +role_manage-account=管理账户 +role_read-token=读取 token +role_offline-access=离线访问 +role_uma_authorization=获取授权 +client_account=账户 +client_security-admin-console=安全管理终端 +client_admin-cli=管理命令行 +client_realm-management=域管理 +client_broker=代理 + + +requiredFields=必填项 +allFieldsRequired=所有项必填 + +backToApplication=« 回到应用 +backTo=回到 {0} + +date=日期 +event=事件 +ip=IP +client=客户端 +clients=客户端 +details=详情 +started=开始 +lastAccess=最后一次访问 +expires=过期时间 +applications=应用 + +account=账户 +federatedIdentity=关联身份 +authenticator=认证方 +sessions=会话 +log=日志 + +application=应用 +availablePermissions=可用权限 +grantedPermissions=授予权限 +grantedPersonalInfo=授权的个人信息 +additionalGrants=可授予的权限 +action=操作 +inResource=in +fullAccess=所有权限 +offlineToken=离线 token +revoke=收回授权 + +configureAuthenticators=配置的认证者 +mobile=手机 +totpStep1=在你的设备上安装 FreeOTP 或者 Google Authenticator.两个应用可以从 Google Play 和 Apple App Store下载。 +totpStep2=打开应用扫描二维码输入验证码 +totpStep3=输入应用提供的一次性验证码单击保存 + +missingUsernameMessage=请指定用户名 +missingFirstNameMessage=请指定名 +invalidEmailMessage=无效的电子邮箱地址 +missingLastNameMessage=请指定姓 +missingEmailMessage=请指定邮件地址 +missingPasswordMessage=请输入密码 +notMatchPasswordMessage=密码不匹配 + +missingTotpMessage=请指定认证者代码 +invalidPasswordExistingMessage=无效的旧密码 +invalidPasswordConfirmMessage=确认密码不相符 +invalidTotpMessage=无效的认证码 + +usernameExistsMessage=用户名已经存在 +emailExistsMessage=电子邮箱已经存在 + +readOnlyUserMessage=无法修改账户,因为它是只读的。 +readOnlyPasswordMessage=不可以更该账户因为它是只读的。 + +successTotpMessage=手机认证者配置完毕 +successTotpRemovedMessage=手机认证者已删除 + +successGrantRevokedMessage=授权成功回收 + +accountUpdatedMessage=您的账户已经更新 +accountPasswordUpdatedMessage=您的密码已经修改 + +missingIdentityProviderMessage=身份提供者未指定 +invalidFederatedIdentityActionMessage=无效或者缺少操作 +identityProviderNotFoundMessage=指定的身份提供者未找到 +federatedIdentityLinkNotActiveMessage=这个身份不再使用了。 +federatedIdentityRemovingLastProviderMessage=你不可以移除最后一个身份提供者因为你没有设置密码 +identityProviderRedirectErrorMessage=尝试重定向到身份提供商失败 +identityProviderRemovedMessage=身份提供商成功删除 +identityProviderAlreadyLinkedMessage=链接的身份 {0} 已经连接到已有用户。 +staleCodeAccountMessage=页面过期。请再试一次。 +consentDenied=不同意 + +accountDisabledMessage=账户已经关闭,请联系管理员 + +accountTemporarilyDisabledMessage=账户暂时关闭,请联系管理员或稍后再试。 +invalidPasswordMinLengthMessage=无效的密码:最短长度 {0}. +invalidPasswordMinLowerCaseCharsMessage=无效的密码: 至少包含 {0} 小写字母。 +invalidPasswordMinDigitsMessage=无效的密码: 至少包含 {0} 数字。 +invalidPasswordMinUpperCaseCharsMessage=无效的密码: 至少包含 {0} 大写字母 +invalidPasswordMinSpecialCharsMessage=无效的密码: 至少包含 {0} 个特殊字符 +invalidPasswordNotUsernameMessage=无效的密码: 不能与用户名相同 +invalidPasswordRegexPatternMessage=无效的密码: 无法与正则表达式匹配 +invalidPasswordHistoryMessage=无效的密码: 不能与之前的{0} 个旧密码相同 diff --git a/keycloak-themes/base/account/password.ftl b/keycloak-themes/base/account/password.ftl new file mode 100644 index 0000000..4a043f2 --- /dev/null +++ b/keycloak-themes/base/account/password.ftl @@ -0,0 +1,59 @@ +<#import "template.ftl" as layout> +<@layout.mainLayout active='password' bodyClass='password'; section> + +
+
+

${msg("changePasswordHtmlTitle")}

+
+
+ ${msg("allFieldsRequired")} +
+
+ +
+ + + <#if password.passwordSet> +
+
+ +
+ +
+ +
+
+ + + + +
+
+ +
+ +
+ +
+
+ +
+
+ +
+ +
+ +
+
+ +
+
+
+ +
+
+
+
+ + diff --git a/keycloak-themes/base/account/resource-detail.ftl b/keycloak-themes/base/account/resource-detail.ftl new file mode 100644 index 0000000..2c963d7 --- /dev/null +++ b/keycloak-themes/base/account/resource-detail.ftl @@ -0,0 +1,277 @@ +<#import "template.ftl" as layout> +<@layout.mainLayout active='authorization' bodyClass='authorization'; section> + + + + +
+
+

+ ${msg("myResources")} <#if authorization.resource.displayName??>${authorization.resource.displayName}<#else>${authorization.resource.name} +

+
+
+ + <#if authorization.resource.iconUri??> + +
+ + +
+
+

+ ${msg("peopleAccessResource")} +

+
+
+
+
+ + + + + + + + + + + <#if authorization.resource.shares?size != 0> + <#list authorization.resource.shares as permission> + + + + + + + + + + + + + <#else> + + + + + +
${msg("user")}${msg("permission")}${msg("date")}${msg("action")}
+ <#if permission.requester.email??>${permission.requester.email}<#else>${permission.requester.username} + + <#if permission.scopes?size != 0> + <#list permission.scopes as scope> + <#if scope.granted && scope.scope??> + + <#else> + ${msg("anyPermission")} + + + <#else> + Any action + + + ${permission.createdDate?datetime} + + ${msg("doRevoke")} +
${msg("resourceIsNotBeingShared")}
+ +
+
+
+
+

+ ${msg("resourceManagedPolicies")} +

+
+
+
+
+ + + + + + + + + + <#if authorization.resource.policies?size != 0> + <#list authorization.resource.policies as permission> + + + + + + + + + + + + <#else> + + + + + +
${msg("description")}${msg("permission")}${msg("action")}
+ <#if permission.description??> + ${permission.description} + + + <#if permission.scopes?size != 0> + <#list permission.scopes as scope> + + + <#else> + ${msg("anyAction")} + + + ${msg("doRevoke")} +
+ ${msg("resourceNoPermissionsGrantingAccess")} +
+ +
+
+
+
+

+ ${msg("shareWithOthers")} +

+
+
+
+
+
+ +
+ * +
+
+
+
+ +
+
+
+ <#list authorization.resource.scopes as scope> + + +
+ +
+
+
+
+
+
+ diff --git a/keycloak-themes/base/account/resources.ftl b/keycloak-themes/base/account/resources.ftl new file mode 100644 index 0000000..d86e8bc --- /dev/null +++ b/keycloak-themes/base/account/resources.ftl @@ -0,0 +1,403 @@ +<#import "template.ftl" as layout> +<@layout.mainLayout active='authorization' bodyClass='authorization'; section> + + +
+
+

+ ${msg("myResources")} +

+
+
+ + <#if authorization.resourcesWaitingApproval?size != 0> +
+
+

+ ${msg("needMyApproval")} +

+
+
+
+
+ + + + + + + + + + + <#list authorization.resourcesWaitingApproval as resource> + <#list resource.permissions as permission> + + + + + + + + + + + + + + +
${msg("resource")}${msg("requestor")}${msg("permissionRequestion")}${msg("action")}
+ <#if resource.displayName??>${resource.displayName}<#else>${resource.name} + + <#if permission.requester.email??>${permission.requester.email}<#else>${permission.requester.username} + + <#list permission.scopes as scope> + <#if scope.scope??> + + <#else> + ${msg("anyPermission")} + + + + ${msg("doApprove")} + ${msg("doDeny")} +
+
+
+ + +
+
+

+ ${msg("myResourcesSub")} +

+
+
+
+
+ + + + + + + + + + + <#if authorization.resources?size != 0> + <#list authorization.resources as resource> + + + + + + + <#else> + + + + + +
${msg("resource")}${msg("application")}${msg("peopleSharingThisResource")}
+ + <#if resource.displayName??>${resource.displayName}<#else>${resource.name} + + + <#if resource.resourceServer.baseUri??> + ${resource.resourceServer.name} + <#else> + ${resource.resourceServer.name} + + + <#if resource.shares?size != 0> + ${resource.shares?size} + <#else> + ${msg("notBeingShared")} + +
${msg("notHaveAnyResource")}
+
+
+ +
+
+

+ ${msg("resourcesSharedWithMe")} +

+
+
+
+
+
+ + + + + + + + + + + + + + <#if authorization.sharedResources?size != 0> + <#list authorization.sharedResources as resource> + + + + + + + + + + <#else> + + + + + +
disabled="true" + ${msg("resource")}${msg("owner")}${msg("application")}${msg("permission")}${msg("date")}
+ + + <#if resource.displayName??>${resource.displayName}<#else>${resource.name} + + ${resource.ownerName} + + <#if resource.resourceServer.baseUri??> + ${resource.resourceServer.name} + <#else> + ${resource.resourceServer.name} + + + <#if resource.permissions?size != 0> +
    + <#list resource.permissions as permission> + <#list permission.scopes as scope> + <#if scope.granted && scope.scope??> +
  • + <#if scope.scope.displayName??> + ${scope.scope.displayName} + <#else> + ${scope.scope.name} + +
  • + <#else> + ${msg("anyPermission")} + + + +
+ <#else> + Any action + +
+ ${resource.permissions[0].grantedDate?datetime} +
${msg("noResourcesSharedWithYou")}
+
+
+ <#if authorization.sharedResources?size != 0> + + +
+ + <#if authorization.resourcesWaitingOthersApproval?size != 0> +
+
+
+

+ ${msg("requestsWaitingApproval")} +

+
+
+
+
+ ${msg("havePermissionRequestsWaitingForApproval",authorization.resourcesWaitingOthersApproval?size)} + ${msg("clickHereForDetails")} +
+
+
+
+
+
+
+
+
+ +
+
+ + + \ No newline at end of file diff --git a/keycloak-themes/base/account/sessions.ftl b/keycloak-themes/base/account/sessions.ftl new file mode 100644 index 0000000..89dbf65 --- /dev/null +++ b/keycloak-themes/base/account/sessions.ftl @@ -0,0 +1,44 @@ +<#import "template.ftl" as layout> +<@layout.mainLayout active='sessions' bodyClass='sessions'; section> + +
+
+

${msg("sessionsHtmlTitle")}

+
+
+ + + + + + + + + + + + + + <#list sessions.sessions as session> + + + + + + + + + + +
${msg("ip")}${msg("started")}${msg("lastAccess")}${msg("expires")}${msg("clients")}
${session.ipAddress}${session.started?datetime}${session.lastAccess?datetime}${session.expires?datetime} + <#list session.clients as client> + ${client}
+ +
+ +
+ + +
+ + diff --git a/keycloak-themes/base/account/template.ftl b/keycloak-themes/base/account/template.ftl new file mode 100644 index 0000000..ec44204 --- /dev/null +++ b/keycloak-themes/base/account/template.ftl @@ -0,0 +1,88 @@ +<#macro mainLayout active bodyClass> + + + + + + + + ${msg("accountManagementTitle")} + + <#if properties.stylesCommon?has_content> + <#list properties.stylesCommon?split(' ') as style> + + + + <#if properties.styles?has_content> + <#list properties.styles?split(' ') as style> + + + + <#if properties.scripts?has_content> + <#list properties.scripts?split(' ') as script> + + + + + + + + +
+
+ +
+ +
+ <#if message?has_content> +
+ <#if message.type=='success' > + <#if message.type=='error' > + +
+ + + <#nested "content"> +
+
+ + + + \ No newline at end of file diff --git a/keycloak-themes/base/account/theme.properties b/keycloak-themes/base/account/theme.properties new file mode 100644 index 0000000..d8b7627 --- /dev/null +++ b/keycloak-themes/base/account/theme.properties @@ -0,0 +1 @@ +locales=ca,cs,da,de,en,es,fr,fi,hu,it,ja,lt,nl,no,pl,pt-BR,ru,sk,sv,tr,zh-CN diff --git a/keycloak-themes/base/account/totp.ftl b/keycloak-themes/base/account/totp.ftl new file mode 100644 index 0000000..987fe24 --- /dev/null +++ b/keycloak-themes/base/account/totp.ftl @@ -0,0 +1,141 @@ +<#import "template.ftl" as layout> +<@layout.mainLayout active='totp' bodyClass='totp'; section> + +
+
+

${msg("authenticatorTitle")}

+
+ <#if totp.otpCredentials?size == 0> +
+ * ${msg("requiredFields")} +
+ +
+ + <#if totp.enabled> + + + <#if totp.otpCredentials?size gt 1> + + + + <#else> + + + + + + + <#list totp.otpCredentials as credential> + + + <#if totp.otpCredentials?size gt 1> + + + + + + + +
${msg("configureAuthenticators")}
${msg("configureAuthenticators")}
${msg("mobile")}${credential.id}${credential.userLabel!} +
+ + + + +
+
+ <#else> + +
+ +
    +
  1. +

    ${msg("totpStep1")}

    + +
      + <#list totp.policy.supportedApplications as app> +
    • ${app}
    • + +
    +
  2. + + <#if mode?? && mode = "manual"> +
  3. +

    ${msg("totpManualStep2")}

    +

    ${totp.totpSecretEncoded}

    +

    ${msg("totpScanBarcode")}

    +
  4. +
  5. +

    ${msg("totpManualStep3")}

    +
      +
    • ${msg("totpType")}: ${msg("totp." + totp.policy.type)}
    • +
    • ${msg("totpAlgorithm")}: ${totp.policy.getAlgorithmKey()}
    • +
    • ${msg("totpDigits")}: ${totp.policy.digits}
    • + <#if totp.policy.type = "totp"> +
    • ${msg("totpInterval")}: ${totp.policy.period}
    • + <#elseif totp.policy.type = "hotp"> +
    • ${msg("totpCounter")}: ${totp.policy.initialCounter}
    • + +
    +
  6. + <#else> +
  7. +

    ${msg("totpStep2")}

    +

    Figure: Barcode

    +

    ${msg("totpUnableToScan")}

    +
  8. + +
  9. +

    ${msg("totpStep3")}

    +

    ${msg("totpStep3DeviceName")}

    +
  10. +
+ +
+ +
+ +
+
+ * +
+ +
+ + +
+ + +
+ +
+
+ <#if totp.otpCredentials?size gte 1>* +
+ +
+ +
+
+ +
+
+
+ + +
+
+
+
+ + + diff --git a/keycloak-themes/base/admin/index.ftl b/keycloak-themes/base/admin/index.ftl new file mode 100644 index 0000000..bbf1549 --- /dev/null +++ b/keycloak-themes/base/admin/index.ftl @@ -0,0 +1,99 @@ + + + + + + + + + + + + <#if properties.stylesCommon?has_content> + <#list properties.stylesCommon?split(' ') as style> + + + <#list properties.styles?split(' ') as style> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <#if properties.scripts?has_content> + <#list properties.scripts?split(' ') as script> + + + + + + + + +
+
+
+
+
+ +
+
+ + + + + + + {{notification.header}} {{notification.message}} +
+
+ +
Loading...
+ + + diff --git a/keycloak-themes/base/admin/messages/admin-messages_ca.properties b/keycloak-themes/base/admin/messages/admin-messages_ca.properties new file mode 100644 index 0000000..1e5b080 --- /dev/null +++ b/keycloak-themes/base/admin/messages/admin-messages_ca.properties @@ -0,0 +1,477 @@ +# Common messages +enabled=Habilitat +name=Nom +save=Desar +cancel=Cancel\u00B7la +onText=SI +offText=NO +client=Client +clients=Clients +clear=Neteja +selectOne=Selecciona un... + +true=S\u00ED +false=No + + +# Realm settings +realm-detail.enabled.tooltip=Els usuaris i clients nom\u00E9s poden accedir a un domini si est\u00E0 habilitat +registrationAllowed=Registre d''usuari +registrationAllowed.tooltip=Habilitar/deshabilitar la p\u00E0gina de registre. Un enlla\u00E7 per al registre es mostrar\u00E0 tamb\u00E9 a la p\u00E0gina d''inici de sessi\u00F3. +registrationEmailAsUsername=Email com a nom d''usuari +registrationEmailAsUsername.tooltip=Si est\u00E0 habilitat el nom d''usuari queda ocult del formulari de registre i l''email es fa servir com a nom d''usuari per als nous usuaris. +editUsernameAllowed=Edita el nom d''usuari +editUsernameAllowed.tooltip=Si est\u00E0 habilitat, el nom d''usuari \u00E9s editable, altrament \u00E9s de nom\u00E9s lectura. +resetPasswordAllowed=Oblit contrasenya +resetPasswordAllowed.tooltip=Mostra un enlla\u00E7 a la p\u00E0gina d''inici de sessi\u00F3 perqu\u00E8 l''usuari faci clic quan ha oblidat les seves credencials. +rememberMe=Mantenir connectat +rememberMe.tooltip=Mostra la casella de selecci\u00F3 en la p\u00E0gina d''inici de sessi\u00F3 per a permetre a l''usuari estar connectat entre reinicis del navegador fins que la sessi\u00F3 expiri. +verifyEmail=Verificar email +verifyEmail.tooltip=For\u00E7ar l''usuari a verificar la seva adre\u00E7a de correu electr\u00F2nic la primera vegada que inici\u00EF sessi\u00F3. +sslRequired=Sol\u00B7licitar SSL +sslRequired.option.all=totes les peticions +sslRequired.option.external=peticions externes +sslRequired.option.none=cap +sslRequired.tooltip=\u00C9s HTTP obligatori? ''cap'' significa que HTTPS no \u00E9s obligatori per cap direcic\u00F3n IP de client, ''peticions externes'' indica que localhost i les adreces IP privades poden accedir sense HTTPS, ''totes les peticions'' vol dir que HTTPS \u00E9s obligatori per a totes les adreces IP. +publicKey=Clau p\u00FAblica +gen-new-keys=Generar noves claus +certificate=Certificat +host=Host +smtp-host=Host SMTP +port=Port +smtp-port=Port SMTP (per defecte 25) +from=Des de +sender-email-addr=Email del emissor +enable-ssl=Habilitar SSL +enable-start-tls=Habilitar StartTLS +enable-auth=Habilitar autenticaci\u00F3 +username=Usuari +login-username=Usuari +password=Contrasenya +login-password=Contrasenya +login-theme=Tema d''inici de sessi\u00F3 +select-one=Selecciona un... +login-theme.tooltip=Selecciona el tema per a les p\u00E0gines d''inici de sessi\u00F3, OTP, permisos, registre i recordatori de contrasenya. +account-theme=Tema de compte +account-theme.tooltip=Selecciona el tema per a les p\u00E0gines de gesti\u00F3 del compte d''usuari. +admin-console-theme=Tema de consola d''administraci\u00F3 +select-theme-admin-console=Selecciona el tema per a la consola d''administraci\u00F3. +email-theme=Tema d''email +select-theme-email=Selecciona el tema per als correus electr\u00F2nics que s\u00F3n enviats pel servidor. +i18n-enabled=Internacionalitzaci\u00F3 activa +supported-locales=Idiomes suportats +supported-locales.placeholder=Indica l''idioma i prem Intro +default-locale=Idioma per defecte +#missing-locale=Missing locale. +#missing-file=Missing file. Please select a file to upload. +#localization-file.upload.success=The localization data has been loaded from file. +#localization-file.upload.error=The file can not be uploaded. Please verify the file. +#localization-show=Show realm specific localizations +#no-localizations-configured=No realm specific localizations configured +#add-localization-text=Add localization text +#locale.create.success=The Locale has been created. +#localization-text.create.success=The localization text has been created. +#localization-text.update.success=The localization text has been updated. +#localization-text.remove.success=The localization text has been deleted. +realm-cache-enabled=Cach\u00E9 de domini habilitada +realm-cache-enabled.tooltip=Activar/desactivar la cach\u00E9 per al domini, client i dades de rols. +user-cache-enabled=Cach\u00E9 d''usuari habilitada +user-cache-enabled.tooltip=Habilitar/deshabilitar la cach\u00E9 d''usuaris i d''assignacions d''usuaris a rols. +revoke-refresh-token=Revocar el token d''actualitzaci\u00F3 +revoke-refresh-token.tooltip=Si est\u00E0 activat els tokens d''actualitzaci\u00F3 nom\u00E9s poden usar-se una vegada. En un altre cas els tokens d''actualitzaci\u00F3 no es revoquen quan s''utilitzen i poden ser usat m\u00FAltiples vegades. +sso-session-idle=Sessions SSO inactives +seconds=Segons +minutes=Minuts +hours=Hores +days=Dies +sso-session-max=Temps m\u00E0xim sessi\u00F3 SSO +sso-session-idle.tooltip=Temps m\u00E0xim que una sessi\u00F3 pot estar inactiva abans que expiri. Els tokens i sessions de navegador s\u00F3n invalidades quan la sessi\u00F3 expira. +sso-session-max.tooltip=Temps m\u00E0xim abans que una sessi\u00F3 expiri. Els tokens i sessions de navegador s\u00F3n invalidats quan una sessi\u00F3 expira. +offline-session-idle=Inactivitat de sessi\u00F3 sense connexi\u00F3 +offline-session-idle.tooltip=Temps m\u00E0xim inactiu d''una sessi\u00F3 sense connexi\u00F3 abans que expiri. Necessites fer servi un token sense connexi\u00F3 per refrescar almenys una vegada dins d'aquest per\u00EDode, en un altre cas la sessi\u00F3 sense connexi\u00F3 expirar\u00E0. +access-token-lifespan=Durada del token d''acc\u00E9s +access-token-lifespan.tooltip=Temps m\u00E0xim abans que un token d''acc\u00E9s expiri. Es recomana que aquest valor sigui curt en relaci\u00F3 al temps m\u00E0xim de SSO +client-login-timeout=Temps m\u00E0xim d''autenticaci\u00F3 +client-login-timeout.tooltip=Temps m\u00E0xim que un client t\u00E9 per finalitzar el protocol d''obtenci\u00F3 del token d''acc\u00E9s. Hauria de ser normalment de l''ordre d''1 minut. +login-timeout=Temps m\u00E0xim de desconnexi\u00F3 +login-timeout.tooltip=Temps m\u00E0xim que un usuari t\u00E9 per completar l''inici de sessi\u00F3. Es recomana que sigui relativament alt. 30 minuts o m\u00E9s. +login-action-timeout=Temps m\u00E0xim d''acci\u00F3 en l''inici de sessi\u00F3 +login-action-timeout.tooltip=Temps m\u00E0xim que un usuari t\u00E9 per completar accions relacionades amb l''inici de sessi\u00F3, com l''actualitzaci\u00F3 de contrasenya o configuraci\u00F3 de OTP. \u00C9s recomanat que sigui relativament alt. 5 minuts o m\u00E9s. +headers=Cap\u00E7aleres +brute-force-detection=Detecci\u00F3 d''atacs per for\u00E7a bruta +x-frame-options=X-Frame-Options +click-label-for-info=Fes clic a l''enlla\u00E7 de l''etiqueta per obtenir m\u00E9s informaci\u00F3. El valor per defecte evita que les p\u00E0gines siguin incloses des d'iframes externs. +content-sec-policy=Content-Security-Policy +max-login-failures=Nombre m\u00E0xim d''errors d''inici de sessi\u00F3 +max-login-failures.tooltip=Indica quants errors es permeten abans que es dispari una espera. +wait-increment=Increment d''espera +wait-increment.tooltip=Quan s''ha arribat al llindar d''error, quant de temps ha d''estar un usuari bloquejat? +quick-login-check-millis=Temps en mil\u00B7lisegons entre inicis de sessi\u00F3 r\u00E0pids +quick-login-check-millis.tooltip=Si ocorren errors de forma concurrent i molt r\u00E0pida, bloquejar a l''usuari. +min-quick-login-wait=Temps m\u00EDnim entre errors de connexi\u00F3 r\u00E0pids +min-quick-login-wait.tooltip=Quant de temps s''ha d''esperar despr\u00E9s d''un error en un intent r\u00E0pid d''identificaci\u00F3 +max-wait=Espera m\u00E0xima +max-wait.tooltip=Temps m\u00E0xim que un usuari queda bloquejat. +failure-reset-time=Reinici del comptador d''errors +failure-reset-time.tooltip=Quan s''ha de reiniciar el comptador d''errors? +realm-tab-login=Inici de sessi\u00F3 +realm-tab-keys=Claus +realm-tab-email=Email +realm-tab-themes=Temes +#realm-tab-localization=Localization +realm-tab-cache=Cach\u00E9 +realm-tab-tokens=Tokens +realm-tab-security-defenses=Defenses de seguretat +realm-tab-general=General +add-realm=Afegir domini + +#Session settings +realm-sessions=Sessions de domini +revocation=Revocaci\u00F3 +logout-all=Desconnectar tot +active-sessions=Sessions actives +sessions=Sessions +not-before=No abans de +not-before.tooltip=Revocar qualsevol token em\u00E8s abans d''aquesta data. +set-to-now=Fixar a ara +push=Push +push.tooltip=Per a cada client que t\u00E9 un URL d''administraci\u00F3, notificar les noves pol\u00EDtiques de revocaci\u00F3. + +#Protocol Mapper +usermodel.prop.label=Propietat +usermodel.prop.tooltip=Nom del m\u00E8tode de propietat en la interf\u00EDcie UserModel. Per exemple, un valor de ''email'' faria refer\u00E8ncia al m\u00E8tode UserModel.getEmail(). +usermodel.attr.label=Atribut d''usuari +usermodel.attr.tooltip=Nom de l''atribut d''usuari emmagatzemat que \u00E9s el nom de l''atribut dins el map UserModel.attribute. +userSession.modelNote.label=Nota sessi\u00F3 usuari +userSession.modelNote.tooltip=Nom de la nota emmagatzemada en la sessi\u00F3 d''usuari dins del mapa UserSessionModel.note +multivalued.label=Valors m\u00FAltiples +multivalued.tooltip=Indica si l''atribut suporta m\u00FAltiples valors. Si est\u00E0 habilitat, la llista de tots els valors d''aquest atribut es fixar\u00E0 com a reclamaci\u00F3. Si est\u00E0 deshabilitat, nom\u00E9s el primer valor ser\u00E0 fixat com a reclamaci\u00F3. +selectRole.label=Selecciona rol +selectRole.tooltip=Introdueix el rol a la caixa de text de l''esquerra, o fes clic a aquest bot\u00F3 per navegar i buscar el rol que vols. +tokenClaimName.label=Nom de reclam del token +tokenClaimName.tooltip=Nom del reclam a inserir en el testimoni. Pot ser un nom complet com ''address.street''. En aquest cas, es crear\u00E0 un objecte JSON niat. +jsonType.label=Tipus JSON de reclamaci\u00F3 +jsonType.tooltip=El tipus de JSON que hauria de fer-se servir per omplir la petici\u00F3 de JSON en el token. long, int, boolean i String s\u00F3n valors v\u00E0lids +includeInIdToken.label=Afegir al token d''ID +includeInAccessToken.label=Afegir al token d''acc\u00E9s +includeInAccessToken.tooltip=S''hauria d'afegir la identitat reclamada al token d''acc\u00E9s? + + +# client details +clients.tooltip=Els clients s\u00F3n aplicacions de navegador de confian\u00E7a i serveis web d''un domini. Aquests clients poden sol\u00B7licitar un inici de sessi\u00F3. Tamb\u00E9 pots definir rols espec\u00EDfics de client. +search.placeholder=Cercar... +create=Crea +import=Importar +client-id=ID Client +base-url=URL Base +actions=Accions +not-defined=No definit +edit=Edita +delete=Esborra +no-results=Sense resultats +no-clients-available=No hi ha clients disponibles +add-client=Afegir Client +select-file=Selecciona arxiu +view-details=Veure detalls +clear-import=Neteja importaci\u00F3 +client-id.tooltip=Indica l''identificador (ID) referenciat en URIs i tokens. Per exemple ''my-client'' +client.name.tooltip=Indica el nom visible del client. Per exemple ''My Client''. Tamb\u00E9 suporta claus per valors localitzats. Per exemple: ${my_client} +client.enabled.tooltip=Els clients deshabilitats no poden iniciar una identificaci\u00F3 o obtenir codis d''acc\u00E9s. +consent-required=Consentiment necessari +consent-required.tooltip=Si est\u00E0 habilitat, els usuaris han de consentir l''acc\u00E9s del client. +direct-grants-only=Nom\u00E9s permisos directes +direct-grants-only.tooltip=Quan est\u00E0 habilitat, el client nom\u00E9s pot obtenir permisos de l''API REST. +client-protocol=Protocol del Client +client-protocol.tooltip=''OpenID connect'' permet als clients verificar la identitat de l''usuari final basat en l''autenticaci\u00F3 realitzada per un servidor d''autoritzaci\u00F3. ''SAML'' habilita l''autenticaci\u00F3 i autoritzaci\u00F3 d''escenaris basats en web incloent cross-domain i single sign-on (SSO) i utilitza tokens de seguretat que contenen afirmacions per passar informaci\u00F3. +access-type=Tipus d''acc\u00E9s +access-type.tooltip=Els clients ''Confidential'' necessiten un secret per iniciar el protocol d''identificaci\u00F3. Els clients ''Public'' no requereixen un secret. Els clients 'Bearer-only' s\u00F3n serveis web que mai inicien un login. +service-accounts-enabled=Comptes de servei habilitades +service-accounts-enabled.tooltip=Permetre autenticar aquest client contra Keycloak i rebre un token d''acc\u00E9s dedicat per a aquest client. +include-authnstatement=Incloure AuthnStatement +include-authnstatement.tooltip=Hauria d''incloure''s una declaraci\u00F3 especificant el m\u00E8tode i la marca de temps en la resposta d''inici de sessi\u00F3? +sign-documents=Signar documents +sign-documents.tooltip=Hauria el domini de signar els documents SAML? +sign-assertions=Signar assercions +sign-assertions.tooltip=Haurien de signar-se les assercions en documents SAML? Aquest ajust no \u00E9s necessari si el document ja s''est\u00E0 signant. +signature-algorithm=Algorisme de signatura +signature-algorithm.tooltip=L''algorisme de signatura usat per signar els documents. +canonicalization-method=M\u00E8tode de canonicalitzaci\u00F3 +canonicalization-method.tooltip=M\u00E8tode de canonicalitzaci\u00F3 per a les signatures XML +encrypt-assertions=Xifrar afirmacions +encrypt-assertions.tooltip=Haurien de xifrar-se les afirmacions SAML amb la clau p\u00FAblica del client fent servir AES? +client-signature-required=Signatura de Client requerida +client-signature-required.tooltip=Signar\u00E0 el client les seves peticions i respostes SAML? I haurien de ser validades? +force-post-binding=For\u00E7ar enlla\u00E7os POST +force-post-binding.tooltip=Fer servir sempre POST per a les respostes +front-channel-logout=Desconnexi\u00F3 en primer pla (Front Channel) +front-channel-logout.tooltip=Quan est\u00E0 activat, la desconnexi\u00F3 requereix una redirecci\u00F3 del navegador cap al client. Quan no est\u00E0 activat, el servidor realitza una invovaci\u00F3n de desconnexi\u00F3 en segon pla. +force-name-id-format=For\u00E7ar format NameID +force-name-id-format.tooltip=Ignorar la petici\u00F3 de subjecte NameID i fer servir la configurada a la consola d''administraci\u00F3. +name-id-format=Format de NameID +name-id-format.tooltip=El format de NameID que es far\u00E0 servir per al t\u00EDtol +root-url=URL arrel +root-url.tooltip=URL arrel afegida a les URL relatives +valid-redirect-uris=URIs de redirecci\u00F3 v\u00E0lides +valid-redirect-uris.tooltip=Patr\u00F3 d''URI v\u00E0lida per a la qual un navegador pot sol\u00B7licitar la redirecci\u00F3 despr\u00E9s d''un inici o tancament de sessi\u00F3 completat. Es permeten comodins simples p.ex. ''http://example.com/*''. Tamb\u00E9 es poden indicar rutes relatives p.ex. ''/my/relative/path/*''. Les rutes relatives generaran un URI de redirecci\u00F3 fent servir el host i port de la petici\u00F3. Per SAML, s''han de fixar patrons d''URI v\u00E0lids si vols confiar en l''URL del servei del consumidor indicada en la petici\u00F3 d''inici de sessi\u00F3. +base-url.tooltip=URL per defecte per utilitzar quan el servidor d''autoritzaci\u00F3 necessita redirigir o enviar de tornada al client. +admin-url=URL d''administraci\u00F3 +admin-url.tooltip=URL a la interf\u00EDcie d''administraci\u00F3 del client. Fixa aquest valor si el client suporta l''adaptador de REST. Aquesta API REST permet al servidor d''autenticaci\u00F3 enviar al client pol\u00EDtiques de revocaci\u00F3 i altres tasques administratives. Normalment es fixa a l''URL base del client. +master-saml-processing-url=URL principal de processament SAML +master-saml-processing-url.tooltip=Si est\u00E0 configurada, aquesta URL es fara servir per a cada enlla\u00E7 al prove\u00EFdor del servei del consumidor d''assercions i serveis de desconnexi\u00F3 \u00FAnics. Pot ser sobreescrit de forma individual per a cada enlla\u00E7 i servei en el punt final de configuraci\u00F3 fina de SAML. +idp-sso-url-ref=Nom de la URL d''un SSO iniciat per l''IDP +idp-sso-url-ref.tooltip=Nom del fragment de l''URL per referenciar al client quan vols un SSO iniciat per l''IDP. Deixant aix\u00F2 buit desactiva els SSO iniciats per l''IDP. L''URL referenciada des del navegador ser\u00E0: {server-root}/realms/{realm}/protocol/saml/clients/{client-url-name} +idp-sso-relay-state=Estat de retransmissi\u00F3 d''un SSO iniciat per l''IDP +idp-sso-relay-state.tooltip=Estat de retransmissi\u00F3 que vols enviar amb una petici\u00F3 SAML quan s''inicia un SSO iniciat per l''IDP +web-origins=Or\u00EDgens web +web-origins.tooltip=Or\u00EDgens CORS permesos. Per permetre tots els or\u00EDgens d''URIs de redirecci\u00F3 v\u00E0lides afegeix ''+''. Per permetre tots els or\u00EDgens afegeix ''*''. +fine-saml-endpoint-conf=Fine Grain SAML Endpoint Configuration +fine-saml-endpoint-conf.tooltip=Expandeix aquesta secci\u00F3 per configurar les URL exactes per Assertion Consumer i Single Logout Service. +assertion-consumer-post-binding-url=Assertion Consumer Service POST Binding URL +assertion-consumer-post-binding-url.tooltip=SAML POST Binding URL for the client''s assertion consumer service (login responses). You can leave this blank if you do not have a URL for this binding. +assertion-consumer-redirect-binding-url=Assertion Consumer Service Redirect Binding URL +assertion-consumer-redirect-binding-url.tooltip=Assertion Consumer Service Redirect Binding URL +logout-service-post-binding-url=URL d''enlla\u00E7 SAML POST per a la desconnexi\u00F3 +logout-service-post-binding-url.tooltip=URL d''enlla\u00E7 SAML POST per a la desconnexi\u00F3 \u00FAnica del client. Pots deixar-ho en blanc si est\u00E0s fent servir un enlla\u00E7 diferent. +logout-service-redir-binding-url=URL d''enlla\u00E7 SAML de redirecci\u00F3 per a la desconnexi\u00F3 +logout-service-redir-binding-url.tooltip=URL d''enlla\u00E7 SAML de redirecci\u00F3 per a la desconnexi\u00F3 \u00FAnica del client. Pots deixar-ho en blanc si est\u00E0s fent servir un enlla\u00E7 diferent. + +# client import +import-client=Importar Client +format-option=Format +select-format=Selecciona un format +import-file=Arxiu d''Importaci\u00F3 + +# client tabs +settings=Ajustos +credentials=Credencials +roles=Rols +mappers=Assignadors +mappers.tooltip=Els assignadors de protocols realitzen transformacions en tokens i documents. Poden fer coses com assignar dades d''usuari en peticions de protocol, o simplement transformar qualsevol petici\u00F3 entre el client i el servidor d''autenticaci\u00F3. +scope=\u00C0mbit +scope.tooltip=Les assignacions d''\u00E0mbit et permeten restringir que assignacions de rols d''usuari s''inclouen en el testimoni d''acc\u00E9s sol\u00B7licitat pel client. +sessions.tooltip=Veure sessions actives per a aquest client. Permet veure quins usuaris estan actius i quan es van identificar. +offline-access=Acc\u00E9s sense connexi\u00F3 +offline-access.tooltip=Veure sessions sense connexi\u00F3 per aquest client. Et permet veure que usuaris han sol\u00B7licitat tokens sense connexi\u00F3 i quan els van sol\u00B7licitar. Per revocar tots els tokens del client, accedeix a la pestanya de Revocaci\u00F3 i fixa el valor \"No abans de\" a \"now\". +clustering=Clustering +installation=Instal\u00B7laci\u00F3 +installation.tooltip=Eina d''ajuda per generar la configuraci\u00F3 de diversos formats d''adaptadors de client que pots descarregar o copiar i enganxar per configurar teus clients. +service-account-roles=Rols de compte de servei +service-account-roles.tooltip=Permetre autenticar assignacions de rol per el compte de servei dedicat a aquest client. + +# client credentials +client-authenticator=Client autenticador +client-authenticator.tooltip=Client autenticador usat per autenticar aquest client contra el servidor Keycloak +certificate.tooltip=Certificat de client per validar els JWT emesos per aquest client i signats amb la clau privada del client del teu magatzem de claus. +no-client-certificate-configured=No s''ha configurat el certificat de client +gen-new-keys-and-cert=Generar noves claus i certificat +import-certificate=Importar Certificat +gen-client-private-key=Generar clau privada de client +generate-private-key=Generar clau privada +archive-format=Format d''Arxiu +archive-format.tooltip=Format d''arxiu Java keystore o PKCS12 +key-alias=\u00C0lies de clau +key-alias.tooltip=\u00C0lies de l''arxiu de la teva clau privada i certificat. +key-password=Contrasenya de la clau +key-password.tooltip=Contrasenya per accedir a la clau privada continguda en l''arxiu +store-password=Contrasenya del magatzem +store-password.tooltip=Contrasenya per accedir a l''arxiu +generate-and-download=Generar i descarregar +client-certificate-import=Importaci\u00F3 de certificat de client +import-client-certificate=Importar Certificat de Client +jwt-import.key-alias.tooltip=\u00C0lies de l''arxiu del teu certificat. +secret=Secret +regenerate-secret=Regenerar secret +add-role=Afegir rol +role-name=Nom de rol +composite=Compost +description=Descripci\u00F3 +no-client-roles-available=No hi ha rols de client disponibles +scope-param-required=Par\u00E0metre d''\u00E0mbit obligatori +scope-param-required.tooltip=Aquest rol nom\u00E9s ser\u00E0 concedit si el par\u00E0metre d''\u00E0mbit amb el nom del rol \u00E9s usat durant la petici\u00F3 d''autoritzaci\u00F3/obtenci\u00F3 de token. +composite-roles=Rols compostos +composite-roles.tooltip=Quan aquest paper \u00E9s assignat/desassignat a un usuari qualsevol rol associat amb ell ser\u00E0 assignat/desassignat de forma impl\u00EDcita. +realm-roles=Rols de domini +available-roles=Rols Disponibles +add-selected=Afegeix seleccionat +associated-roles=Rols Associats +composite.associated-realm-roles.tooltip=Rols a nivell de domini associats amb aquest rol compost. +composite.available-realm-roles.tooltip=Rols a nivell de domini disponibles en aquest paper compost. +remove-selected=Esborrar seleccionats +client-roles=Rols de Client +select-client-to-view-roles=Selecciona el client per veure els seus rols +available-roles.tooltip=Rols d''aquest client que pots associar a aquest rol compost. +client.associated-roles.tooltip=Rols de client associats amb aquest rol compost. +add-builtin=Afegeix Builtin +category=Categoria +type=Tipus +no-mappers-available=No hi ha assignadors disponibles +add-builtin-protocol-mappers=Afegeix Builtin Protocol Mappers +add-builtin-protocol-mapper=Afegeix Builtin Protocol Mapper +scope-mappings=Assignacions d''\u00E0mbit +full-scope-allowed=Permet tots els \u00E0mbits +full-scope-allowed.tooltip=Permet deshabilitar totes les restriccions. +scope.available-roles.tooltip=Rols de domini que poden ser assignats a l''\u00E0mbit +assigned-roles=Rols Assignats +assigned-roles.tooltip=Rols a nivell de domini assignats a aquest \u00E0mbit. +effective-roles=Rols efectius +realm.effective-roles.tooltip=Rols de domini assignats que poden haver estat heretats d''un rol compost. +select-client-roles.tooltip=Selecciona el client per veure els seus rols +assign.available-roles.tooltip=Rols de clients disponibles per ser assignats. +client.assigned-roles.tooltip=Rols de client assignats +client.effective-roles.tooltip=Rols de client assignats que poden haver estat heretats des d''un rol compost. +basic-configuration=Configuraci\u00F3 b\u00E0sica +node-reregistration-timeout=Temps d''espera de re-registre de node +node-reregistration-timeout.tooltip=Indica el m\u00E0xim interval de temps perqu\u00E8 els nodes del cl\u00FAster registrats es tornin a registrar. Si el node del cl\u00FAster no envia una petici\u00F3 de re-registre a Keycloak dins d''aquest interval, ser\u00E0 desregistrat de Keycloak +registered-cluster-nodes=Registrar nodes de cl\u00FAster +register-node-manually=Registrar node manualment +test-cluster-availability=Provar disponibilitat del cl\u00FAster +last-registration=\u00DAltim registre +node-host=Host del node +no-registered-cluster-nodes=No hi ha nodes de cl\u00FAster registrats disponibles +cluster-nodes=Nodes de cl\u00FAster +add-node=Afegir Node +active-sessions.tooltip=Nombre total de sessions actives per a aquest client. +show-sessions=Mostrar sessions +show-sessions.tooltip=Advert\u00E8ncia, aquesta \u00E9s una operaci\u00F3 potencialment costosa depenent del nombre de sessions actives. +user=Usuari +from-ip=Des de IP +session-start=Inici de sessi\u00F3 +first-page=Primera p\u00E0gina +previous-page=P\u00E0gina Anterior +next-page=P\u00E0gina seg\u00FCent +client-revoke.not-before.tooltip=Revocar tots els tokens emesos abans d''aquesta data per a aquest client. +client-revoke.push.tooltip=Si l''URL d''administraci\u00F3 est\u00E0 configurada per a aquest client, envia aquesta pol\u00EDtica a aquest client. +select-a-format=Selecciona un format +download=Descarrega +offline-tokens=Tokens sense connexi\u00F3 +offline-tokens.tooltip=Nombre total de tokens sense connexi\u00F3 d''aquest client. +show-offline-tokens=Mostrar tokens sense connexi\u00F3 +show-offline-tokens.tooltip=Advert\u00E8ncia, aquesta \u00E9s una operaci\u00F3 potencialment costosa depenent del nombre de tokens sense connexi\u00F3. +token-issued=Token expedit +last-access=\u00DAltim Acc\u00E9s +last-refresh=\u00DAltima actualitzaci\u00F3 +key-export=Exportar clau +key-import=Importar clau +export-saml-key=Exporta clau SAML +import-saml-key=Importar clau SAML +realm-certificate-alias=\u00C0lies del certificat del domini +realm-certificate-alias.tooltip=El certificat del domini \u00E9s emmagatzemat en arxiu. Aquest \u00E9s l''\u00E0lies a aquest. +signing-key=Clau de firma +saml-signing-key=Clau de firma SAML. +private-key=Clau Privada +generate-new-keys=Generar noves claus +export=Exporta +encryption-key=Clau de xifrat +saml-encryption-key.tooltip=Clau de xifrat de SAML +service-accounts=Comptes de servei +service-account.available-roles.tooltip=Rols de domini que poden ser assignats al compte del servei. +service-account.assigned-roles.tooltip=Rols de domini assignats al compte del servei. +service-account-is-not-enabled-for=El compte del servei no est\u00E0 habilitada per {{client}} +create-protocol-mappers=Crea assignadors de protocol +create-protocol-mapper=Crea assignador de protocol +protocol=Protocol +protocol.tooltip=Protocol. +id=ID +mapper.name.tooltip=Nom de l''assignador. +mapper.consent-required.tooltip=Quan es concedeix acc\u00E9s temporal, \u00E9s necessari el consentiment de l''usuari per a proporcinar aquestes dades al client? +consent-text=Text del consentiment +consent-text.tooltip=Text per mostrar a la p\u00E0gina de consentiment. +mapper-type=Tipus d''assignador + +# realm identity providers +identity-providers=Prove\u00EFdors d''identitat +table-of-identity-providers=Taula de prove\u00EFdors d''identitat +add-provider.placeholder=Afegir prove\u00EFdor... +provider=Prove\u00EFdor +gui-order=Ordre en la interf\u00EDcie gr\u00E0fica (GUI) +redirect-uri=URI de redirecci\u00F3 +redirect-uri.tooltip=L''URI de redirecci\u00F3 usada per configurar el prove\u00EFdor d''identitat. +alias=\u00C0lies +identity-provider.alias.tooltip=L''\u00E0lies que identifica de forma \u00FAnica un prove\u00EFdor d''identitat, es far servir tamb\u00E9 per construir la URI de redirecci\u00F3. +identity-provider.enabled.tooltip=Habilita/deshabilita aquest prove\u00EFdor d''identitat. +authenticate-by-default=Autenticar per defecte +identity-provider.authenticate-by-default.tooltip=Indica si aquest prove\u00EFdor hauria de ser provat per defecte per autenticacaci\u00F3n fins i tot abans de mostrar la p\u00E0gina d''inici de sessi\u00F3. +store-tokens=Emmagatzemar tokens +identity-provider.store-tokens.tooltip=Habilitar/deshabilitar si els tokens han de ser emmagatzemats despr\u00E9s d''autenticar als usuaris. +stored-tokens-readable=Tokens emmagatzemats llegibles +identity-provider.stored-tokens-readable.tooltip=Habilitar/deshabilitar si els nous usuaris poden llegir els tokens emmagatzemats. Aix\u00F2 assigna el rol ''broker.read-token''. +update-profile-on-first-login=Actualitzar perfil al primer inici de sessi\u00F3 +on=Activat +on-missing-info=Si falta informaci\u00F3 +off=Desactivat +update-profile-on-first-login.tooltip=Defineix condicions sota les quals un usuari ha de actualitzar el seu perfil durant el primer inici de sessi\u00F3. +trust-email=Confiar en l''email +trust-email.tooltip=Si est\u00E0 habilitat, l''email rebut d''aquest prove\u00EFdor no es verificar\u00E0 encara que la verificaci\u00F3 estigui habilitada per al domini. +gui-order.tooltip=N\u00FAmero que defineix l''ordre del prove\u00EFdor en la interf\u00EDcie gr\u00E0fica (GUI) (ex. a la p\u00E0gina d''inici de sessi\u00F3) +openid-connect-config=Configuraci\u00F3 d''OpenID Connect +openid-connect-config.tooltip=Configuraci\u00F3 d''OIDC SP i IDP externs +authorization-url=URL d''autoritzaci\u00F3 +authorization-url.tooltip=La URL d''autoritzaci\u00F3. +token-url=Token URL +token-url.tooltip=L''URL del token. +logout-url=URL de desconnexi\u00F3 +identity-provider.logout-url.tooltip=Punt de tancament de sessi\u00F3 per utilitzar en la desconnexi\u00F3 d''usuaris des d''un prove\u00EFdor d''identitat (IDP) extern. +backchannel-logout=Backchannel Logout +backchannel-logout.tooltip=Does the external IDP support backchannel logout? +user-info-url=URL d''informaci\u00F3 d''usuari +user-info-url.tooltip=L''URL d''informaci\u00F3 d''usuari. Opcional. +identity-provider.client-id.tooltip=El client o identificador de client registrat en el prove\u00EFdor d''identitat. +client-secret=Secret de Client +show-secret=Mostrar secret +hide-secret=Amaga secret +client-secret.tooltip=El client o el secret de client registrat en el prove\u00EFdor d''identitat. +issuer=Emissor +issuer.tooltip=L''identificador de l''emissor per a l''emissor de la resposta. Si no s''indica, no es realitzar\u00E0 cap validaci\u00F3. +default-scopes=\u00C0mbits per defecte +identity-provider.default-scopes.tooltip=Els \u00E0mbits que s''enviaran quan es sol\u00B7liciti autoritzaci\u00F3. Pot ser una llista d''\u00E0mbits separats per espais. El valor per defecte \u00E9s ''openid''. +prompt=Prompt +unspecified.option=no especificat +none.option=cap +consent.option=consentiment +login.option=login +select-account.option=select_account +prompt.tooltip=Indica si el servidor d''autoritzaci\u00F3 sol\u00B7licita a l''usuari final per reautenticaci\u00F3n i consentiment. +validate-signatures=Validar signatures +identity-provider.validate-signatures.tooltip=Habilitar/deshabilitar la validaci\u00F3 de signatures de prove\u00EFdors d''identitat (IDP) externs +validating-public-key=Validant clau p\u00FAblica +identity-provider.validating-public-key.tooltip=La clau p\u00FAblica en format PEM que ha de fer-se servir per verificar les signatures de prove\u00EFdors d''identitat (IDP) externs. +import-external-idp-config=Importar configuraci\u00F3 externa d''IDP +import-external-idp-config.tooltip=Et permet carregar metadades d''un prove\u00EFdor d''identitat (IDP) extern d''un arxiu de coniguraci\u00F3n o descarregar des d''una URL. +import-from-url=Importar des d''URL +identity-provider.import-from-url.tooltip=Importa metadades des d''un descriptor d''un prove\u00EFdor d''identitat (IDP) remot. +import-from-file=Importa des d''arxiu +identity-provider.import-from-file.tooltip=Importa metadades des d''un descriptor d''un prove\u00EFdor d''identitat (IDP) descarregat. +saml-config=Configuraci\u00F3 SAML +identity-provider.saml-config.tooltip=Configuraci\u00F3 de prove\u00EFdor SAML i IDP extern +single-signon-service-url=URL de servei de connexi\u00F3 \u00FAnic (SSO) +saml.single-signon-service-url.tooltip=L''URL que s''ha de fer servir per enviar peticions d''autenticaci\u00F3 (SAML AuthnRequest). +single-logout-service-url=URL de servei de desconnexi\u00F3 \u00FAnic +saml.single-logout-service-url.tooltip=L''URL que ha de fer-se servir per enviar peticions de desconnexi\u00F3. +nameid-policy-format=Format de pol\u00EDtica NameID +nameid-policy-format.tooltip=Indica la refer\u00E8ncia a la URI corresponent a un format de NameID. El valor per defecte \u00E9s urn:oasis:names:tc:SAML:2.0:nameid-format:persistent. +http-post-binding-response=HTTP-POST enlla\u00E7 de resposta +http-post-binding-response.tooltip=Indica si es respon a les peticions fent servir HTTP-POST. Si no est\u00E0 activat, es far servir HTTP-REDIRECT. +http-post-binding-for-authn-request=HTTP-POST per AuthnRequest +http-post-binding-for-authn-request.tooltip=Indica si AuthnRequest ha de ser enviat usant HTTP-POST. Si no est\u00E0 activat es fa HTTP-REDIRECT. +want-authn-requests-signed=Signar AuthnRequests +want-authn-requests-signed.tooltip=Indica si el prove\u00EFdor d''identitat espera rebre signades les AuthnRequest. +force-authentication=For\u00E7ar autenticaci\u00F3 +identity-provider.force-authentication.tooltip=Indica si el prove\u00EFdor d''identitat ha d'autenticar en presentar directament les credencials en lloc de dependre d''un context de seguretat previ. +validate-signature=Validar signatura +saml.validate-signature.tooltip=Habilitar/deshabilitar la validaci\u00F3 de signatura en respostes SAML. +validating-x509-certificate=Validant certificat X509 +validating-x509-certificate.tooltip=El certificat en format PEM que ha de fer-se servir per comprovar les signatures. +saml.import-from-url.tooltip=Importar metadades des d''un descriptor d'entitat remot d''un IDP de SAML +social.client-id.tooltip=L''identificador del client registrat amb el prove\u00EFdor d''identitat. +social.client-secret.tooltip=El secret del client registrat amb el prove\u00EFdor d''identitat. +social.default-scopes.tooltip=\u00C0mbits que s''enviaran quan es sol\u00B7liciti autoritzaci\u00F3. Veure la documentaci\u00F3 per als possibles valors, separador i valor per defecte. +key=Clau +stackoverflow.key.tooltip=La clau obtinguda en el registre del client de Stack Overflow. + +realms=Dominis +realm=Domini + +identity-provider-mappers=Assignadors de prove\u00EFdors d''identitat (IDP) +create-identity-provider-mapper=Crea assignador de prove\u00EFdor d''identitat (IDP) +add-identity-provider-mapper=Afegeix assignador de prove\u00EFdor d''identitat +client.description.tooltip=Indica la descripci\u00F3 del client. Per exemple ''My Client for TimeSheets''. Tamb\u00E9 suporta claus per a valors localitzats. Per exemple: ${my_client_description} diff --git a/keycloak-themes/base/admin/messages/admin-messages_de.properties b/keycloak-themes/base/admin/messages/admin-messages_de.properties new file mode 100644 index 0000000..6d151ff --- /dev/null +++ b/keycloak-themes/base/admin/messages/admin-messages_de.properties @@ -0,0 +1,1627 @@ +consoleTitle=Keycloak Admin Konsole + +# Common messages +enabled=Aktiv +hidden=Versteckt +link-only-column=Nur Link +name=Name +displayName=Anzeigename +displayNameHtml=HTML-Anzeigename +save=Speichern +cancel=Abbrechen +onText=EIN +offText=AUS +client=Client +clients=Clients +clear=Zur\u00FCcksetzen +selectOne=Bitte w\u00E4hlen... + +true=Ja +false=Nein + +endpoints=Endpoints + +dateFormat=dd.MM.yyyy +timeFormat=HH:mm:ss + +# Realm settings +realm-detail.enabled.tooltip=Benutzer und Clients k\u00F6nnen das Realm nur verwenden, wenn es aktiviert ist +realm-detail.oidc-endpoints.tooltip=Zeigt die Konfiguration der OpenID Connect Endpunkte +realm-detail.userManagedAccess.tooltip=Wenn aktiviert, k\u00F6nnen Benutzer ihre Ressourcen und Berechtigungen \u00FCber die Account Management Console verwalten. +#userManagedAccess=User-Managed Access +registrationAllowed=Benutzerregistrierung +registrationAllowed.tooltip=Aktiviere/deaktiviere die Seite zur Benutzerregistrierung. Auf der Loginseite wird ein entsprechender Link angezeigt. +registrationEmailAsUsername=E-Mail-Adresse als Benutzername +registrationEmailAsUsername.tooltip=Wenn aktiviert, wird das Feld "Benutzername" auf der Registrierungsformular nicht angezeigt und als Benutzername wird stattdessen die E-Mail verwendet. +editUsernameAllowed=Benutzername editierbar +editUsernameAllowed.tooltip=Wenn aktiv, kann der Benutzername editiert werden. +resetPasswordAllowed=Passwort-Vergessen +resetPasswordAllowed.tooltip=Zeigt einen Link auf der Loginseite, auf den die Benutzer klicken k\u00F6nnen, wenn sie ihr Passwort vergessen haben. +rememberMe=Angemeldet bleiben +rememberMe.tooltip=Zeigt eine Auswahlbox auf der Loginseite, die es dem Benutzer erlaubt, zwischen Browser-Neustarts eingeloggt zu bleiben, bis die Session abl\u00E4uft. +loginWithEmailAllowed=Anmeldung mit E-Mail +loginWithEmailAllowed.tooltip=Erlaubt Benutzern, sich mit ihrer E-Mail-Adresse anzumelden. +#duplicateEmailsAllowed=Duplicate emails +#duplicateEmailsAllowed.tooltip=Allow multiple users to have the same email address. Changing this setting will also clear the users cache. It is recommended to manually update email constraints of existing users in the database after switching off support for duplicate email addresses. +verifyEmail=E-Mail verifizieren +verifyEmail.tooltip=Benutzer auffordern, ihre E-Mail-Adresse nach der ersten Anmeldung oder nach der \u00DCbermittlung von Adress\u00E4nderungen zu verifizieren. +#sslRequired=Require SSL +#sslRequired.option.all=all requests +#sslRequired.option.external=external requests +#sslRequired.option.none=none +sslRequired.tooltip=Ist HTTPS erforderlich? 'None' bedeutet, dass HTTPS f\u00FCr keine Client-IP-Adresse erforderlich ist. 'External requests' bedeutet, dass Localhost und private IP-Adressen ohne HTTPS zugreifen k\u00F6nnen. 'All requests' bedeutet, dass HTTPS f\u00FCr alle IP-Adressen erforderlich ist. +#publicKeys=Public keys +#publicKey=Public key +#privateKey=Private key +#gen-new-keys=Generate new keys +certificate=Zertifikat +host=Host +smtp-host=SMTP Host +port=Port +smtp-port=SMTP Port (Standardwert ist 25) +from=Von +#fromDisplayName=From Display Name +#fromDisplayName.tooltip=A user-friendly name for the 'From' address (optional). +#replyTo=Reply To +#replyToDisplayName=Reply To Display Name +#replyToDisplayName.tooltip=A user-friendly name for the 'Reply-To' address (optional). +#envelopeFrom=Envelope From +#envelopeFrom.tooltip=An email address used for bounces (optional). +sender-email-addr=E-Mail-Adresse des Absenders +#sender-email-addr-display=Display Name for Sender Email Address +#reply-to-email-addr=Reply To Email Address +#reply-to-email-addr-display=Display Name for Reply To Email Address +#sender-envelope-email-addr=Sender Envelope Email Address +enable-ssl=SSL aktivieren +#enable-start-tls=Enable StartTLS +#enable-auth=Enable Authentication +username=Benutzername +login-username=Login Benutzername +password=Passwort +login-password=Login Passwort +#login-theme=Login Theme +#login-theme.tooltip=Select theme for login, OTP, grant, registration, and forgot password pages. +#account-theme=Account Theme +#account-theme.tooltip=Select theme for user account management pages. +#admin-console-theme=Admin Console Theme +#select-theme-admin-console=Select theme for admin console. +#email-theme=Email Theme +#select-theme-email=Select theme for emails that are sent by the server. +i18n-enabled=Internationalisierung aktiv +supported-locales=Unterst\u00FCtzte Sprachen +#supported-locales.placeholder=Type a locale and enter +#default-locale=Default Locale +localization-upload-file=Hochladen einer JSON Datei mit Lokalisierungstexten +missing-locale=Locale fehlt. +missing-file=Datei fehlt. Bitte eine Datei f\u00FCr den Upload ausw\u00E4hlen. +localization-file.upload.success=Die Internationalisierungstexte wurden importiert. +localization-file.upload.error=Die Datei konnte nicht hochgeladen werden. Bitte \u00FCberpr\u00FCfen Sie die Datei. +localization-show=Realm-spezifische Lokalisierungstexte +no-localizations-configured=Es sind zur Zeit keine realm-spezifischen Lokalisierungstexte vorhanden. +add-localization-text=Lokalisierungstext hinzuf\u00FCgen +locale.create.success=Die Locale wurde ertellt. +localization-text.create.success=Der Lokalisierungstext wurde erstellt. +localization-text.update.success=Der Lokalisierungstext wurde aktualisiert. +localization-text.remove.success=Der Lokalisierungstext wurde gel\u00F6scht. +#realm-cache-clear=Realm Cache +#realm-cache-clear.tooltip=Clears all entries from the realm cache (this will clear entries for all realms) +#user-cache-clear=User Cache +#user-cache-clear.tooltip=Clears all entries from the user cache (this will clear entries for all realms) +#keys-cache-clear=Keys Cache +#keys-cache-clear.tooltip=Clears all entries from the cache of external public keys. These are keys of external clients or identity providers. (this will clear entries for all realms) +#revoke-refresh-token=Revoke Refresh Token +#revoke-refresh-token.tooltip=If enabled a refresh token can only be used up to 'Refresh Token Max Reuse' and is revoked when a different token is used. Otherwise refresh tokens are not revoked when used and can be used multiple times. +#refresh-token-max-reuse=Refresh Token Max Reuse +#refresh-token-max-reuse.tooltip=Maximum number of times a refresh token can be reused. When a different token is used, revocation is immediate. +#sso-session-idle=SSO Session Idle +seconds=Sekunden +minutes=Minuten +hours=Stunden +days=Tage +#sso-session-max=SSO Session Max +#sso-session-idle.tooltip=Time a session is allowed to be idle before it expires. Tokens and browser sessions are invalidated when a session is expired. +#sso-session-max.tooltip=Max time before a session is expired. Tokens and browser sessions are invalidated when a session is expired. +#offline-session-idle=Offline Session Idle +#offline-session-idle.tooltip=Time an offline session is allowed to be idle before it expires. You need to use offline token to refresh at least once within this period, otherwise offline session will expire. +#realm-detail.hostname=Hostname +#realm-detail.hostname.tooltip=Set the hostname for the realm. Use in combination with the fixed hostname provider to override the server hostname for a specific realm. + +## KEYCLOAK-7688 Offline Session Max for Offline Token +#offline-session-max-limited=Offline Session Max Limited +#offline-session-max-limited.tooltip=Enable Offline Session Max. +#offline-session-max=Offline Session Max +#offline-session-max.tooltip=Max time before an offline session is expired regardless of activity. + +#access-token-lifespan=Access Token Lifespan +#access-token-lifespan.tooltip=Max time before an access token is expired. This value is recommended to be short relative to the SSO timeout. +#access-token-lifespan-for-implicit-flow=Access Token Lifespan For Implicit Flow +#access-token-lifespan-for-implicit-flow.tooltip=Max time before an access token issued during OpenID Connect Implicit Flow is expired. This value is recommended to be shorter than SSO timeout. There is no possibility to refresh token during implicit flow, that's why there is separate timeout different to 'Access Token Lifespan'. +#action-token-generated-by-admin-lifespan=Default Admin-Initiated Action Lifespan +#action-token-generated-by-admin-lifespan.tooltip=Maximum time before an action permit sent to a user by admin is expired. This value is recommended to be long to allow admins send e-mails for users that are currently offline. The default timeout can be overridden right before issuing the token. +#action-token-generated-by-user-lifespan=User-Initiated Action Lifespan +#action-token-generated-by-user-lifespan.tooltip=Maximum time before an action permit sent by a user (e.g. forgot password e-mail) is expired. This value is recommended to be short because it is expected that the user would react to self-created action quickly. + +#action-token-generated-by-user.execute-actions=Execute Actions +#action-token-generated-by-user.idp-verify-account-via-email=IdP Account E-mail Verification +#action-token-generated-by-user.reset-credentials=Forgot Password +#action-token-generated-by-user.verify-email=E-mail Verification +#action-token-generated-by-user.tooltip=Override default settings of maximum time before an action permit sent by a user (e.g. forgot password e-mail) is expired for specific action. This value is recommended to be short because it is expected that the user would react to self-created action quickly. +#action-token-generated-by-user.reset=Reset +#action-token-generated-by-user.operation=Override User-Initiated Action Lifespan + +#client-login-timeout=Client login timeout +#client-login-timeout.tooltip=Max time a client has to finish the access token protocol. This should normally be 1 minute. +#login-timeout=Login timeout +#login-timeout.tooltip=Max time a user has to complete a login. This is recommended to be relatively long. 30 minutes or more. +#login-action-timeout=Login action timeout +#login-action-timeout.tooltip=Max time a user has to complete login related actions like update password or configure totp. This is recommended to be relatively long. 5 minutes or more. +#headers=Headers +#brute-force-detection=Brute Force Detection +#x-frame-options=X-Frame-Options +#x-frame-options-tooltip=Default value prevents pages from being included via non-origin iframes (click label for more information) +#content-sec-policy=Content-Security-Policy +#content-sec-policy-tooltip=Default value prevents pages from being included via non-origin iframes (click label for more information) +#content-type-options=X-Content-Type-Options +#content-type-options-tooltip=Default value prevents Internet Explorer and Google Chrome from MIME-sniffing a response away from the declared content-type (click label for more information) +#robots-tag=X-Robots-Tag +#robots-tag-tooltip=Prevent pages from appearing in search engines (click label for more information) +#x-xss-protection=X-XSS-Protection +#x-xss-protection-tooltip=This header configures the Cross-site scripting (XSS) filter in your browser. Using the default behavior, the browser will prevent rendering of the page when a XSS attack is detected (click label for more information) +#strict-transport-security=HTTP Strict Transport Security (HSTS) +#strict-transport-security-tooltip=The Strict-Transport-Security HTTP header tells browsers to always use HTTPS. Once a browser sees this header, it will only visit the site over HTTPS for the time specified (1 year) at max-age, including the subdomains. +#permanent-lockout=Permanent Lockout +#permanent-lockout.tooltip=Lock the user permanently when the user exceeds the maximum login failures. +#max-login-failures=Max Login Failures +#max-login-failures.tooltip=How many failures before wait is triggered. +#wait-increment=Wait Increment +#wait-increment.tooltip=When failure threshold has been met, how much time should the user be locked out? +#quick-login-check-millis=Quick Login Check Milli Seconds +#quick-login-check-millis.tooltip=If a failure happens concurrently too quickly, lock out the user. +#min-quick-login-wait=Minimum Quick Login Wait +#min-quick-login-wait.tooltip=How long to wait after a quick login failure. +#max-wait=Max Wait +#max-wait.tooltip=Max time a user will be locked out. +#failure-reset-time=Failure Reset Time +#failure-reset-time.tooltip=When will failure count be reset? +#realm-tab-login=Login +#realm-tab-keys=Keys +#realm-tab-email=Email +#realm-tab-themes=Themes +realm-tab-localization=Internationalisierung +#realm-tab-cache=Cache +#realm-tab-tokens=Tokens +#realm-tab-client-registration=Client Registration +#realm-tab-security-defenses=Security Defenses +#realm-tab-general=General +#add-realm=Add realm + +#Session settings +realm-sessions=Realm-Sessions +#revocation=Revocation +logout-all=Alle ausloggen +active-sessions=Aktive Sessions +offline-sessions=Offline-Sessions +sessions=Sessions +#not-before=Not Before +#not-before.tooltip=Revoke any tokens issued before this date. +#set-to-now=Set to now +#push=Push +#push.tooltip=For every client that has an admin URL, notify them of the new revocation policy. + +#Protocol Mapper +#usermodel.prop.label=Property +#usermodel.prop.tooltip=Name of the property method in the UserModel interface. For example, a value of 'email' would reference the UserModel.getEmail() method. +#usermodel.attr.label=User Attribute +#usermodel.attr.tooltip=Name of stored user attribute which is the name of an attribute within the UserModel.attribute map. +#userSession.modelNote.label=User Session Note +#userSession.modelNote.tooltip=Name of stored user session note within the UserSessionModel.note map. +#multivalued.label=Multivalued +#multivalued.tooltip=Indicates if attribute supports multiple values. If true, then the list of all values of this attribute will be set as claim. If false, then just first value will be set as claim +#selectRole.label=Select Role +#selectRole.tooltip=Enter role in the textbox to the left, or click this button to browse and select the role you want. +#tokenClaimName.label=Token Claim Name +#tokenClaimName.tooltip=Name of the claim to insert into the token. This can be a fully qualified name like 'address.street'. In this case, a nested json object will be created. To prevent nesting and use dot literally, escape the dot with backslash (\\.). +#jsonType.label=Claim JSON Type +#jsonType.tooltip=JSON type that should be used to populate the json claim in the token. long, int, boolean, and String are valid values. +#includeInIdToken.label=Add to ID token +#includeInIdToken.tooltip=Should the claim be added to the ID token? +#includeInAccessToken.label=Add to access token +#includeInAccessToken.tooltip=Should the claim be added to the access token? +#includeInUserInfo.label=Add to userinfo +#includeInUserInfo.tooltip=Should the claim be added to the userinfo? +#usermodel.clientRoleMapping.clientId.label=Client ID +#usermodel.clientRoleMapping.clientId.tooltip=Client ID for role mappings +#usermodel.clientRoleMapping.rolePrefix.label=Client Role prefix +#usermodel.clientRoleMapping.rolePrefix.tooltip=A prefix for each client role (optional). +#usermodel.realmRoleMapping.rolePrefix.label=Realm Role prefix +#usermodel.realmRoleMapping.rolePrefix.tooltip=A prefix for each Realm Role (optional). +#sectorIdentifierUri.label=Sector Identifier URI +#sectorIdentifierUri.tooltip=Providers that use pairwise sub values and support Dynamic Client Registration SHOULD use the sector_identifier_uri parameter. It provides a way for a group of websites under common administrative control to have consistent pairwise sub values independent of the individual domain names. It also provides a way for Clients to change redirect_uri domains without having to reregister all of their users. +#pairwiseSubAlgorithmSalt.label=Salt +#pairwiseSubAlgorithmSalt.tooltip=Salt used when calculating the pairwise subject identifier. If left blank, a salt will be generated. +#addressClaim.street.label=User Attribute Name for Street +#addressClaim.street.tooltip=Name of User Attribute, which will be used to map to 'street_address' subclaim inside 'address' token claim. Defaults to 'street' . +#addressClaim.locality.label=User Attribute Name for Locality +#addressClaim.locality.tooltip=Name of User Attribute, which will be used to map to 'locality' subclaim inside 'address' token claim. Defaults to 'locality' . +#addressClaim.region.label=User Attribute Name for Region +#addressClaim.region.tooltip=Name of User Attribute, which will be used to map to 'region' subclaim inside 'address' token claim. Defaults to 'region' . +#addressClaim.postal_code.label=User Attribute Name for Postal Code +#addressClaim.postal_code.tooltip=Name of User Attribute, which will be used to map to 'postal_code' subclaim inside 'address' token claim. Defaults to 'postal_code' . +#addressClaim.country.label=User Attribute Name for Country +#addressClaim.country.tooltip=Name of User Attribute, which will be used to map to 'country' subclaim inside 'address' token claim. Defaults to 'country' . +#addressClaim.formatted.label=User Attribute Name for Formatted Address +#addressClaim.formatted.tooltip=Name of User Attribute, which will be used to map to 'formatted' subclaim inside 'address' token claim. Defaults to 'formatted' . + +# client details +clients.tooltip=Clients sind vertrauensw\u00FCrdige Browseranwendungen und Webdienste in einem Realm. Diese Clients k\u00F6nnen eine Anmeldung anfordern. Man kann auch client-spezifische Rollen definieren. +search.placeholder=Suchen... +create=Erstellen +import=Importieren +client-id=Client-ID +base-url=Basis-URL +actions=Aktionen +not-defined=Nicht definiert +edit=Bearbeiten +delete=L\u00F6schen +no-results=Keine Resultate +no-clients-available=Keine Clients verf\u00FCgbar +add-client=Client hinzuf\u00FCgen +#select-file=Select file +#view-details=View details +#clear-import=Clear import +client-id.tooltip=Legt die Id fest, auf die in URI und Token verwiesen wird. Zum Beispiel 'my-client'. Bei SAML ist dies auch der erwartete Issuer-Wert von authn-Anfragen +client.name.tooltip=Legt den Anzeigenamen des Clients fest. Zum Beispiel 'My Client'. Unterst\u00FCtzt auch Keys f\u00FCr lokalisierte Werte. Zum Beispiel\: ${my_client} +#client.enabled.tooltip=Disabled clients cannot initiate a login or have obtain access tokens. +#consent-required=Consent Required +#consent-required.tooltip=If enabled users have to consent to client access. +#client.display-on-consent-screen=Display Client On Consent Screen +#client.display-on-consent-screen.tooltip=Applicable just if Consent Required is on. If this switch is off, then consent screen will contain just the consents corresponding to configured client scopes. If on, then there will be also one item on consent screen about this client itself +#client.consent-screen-text=Client Consent Screen Text +#client.consent-screen-text.tooltip=Applicable just if 'Display Client On Consent Screen' is on for this client. Contains the text, which will be on consent screen about permissions specific just for this client +#client-protocol=Client Protocol +#client-protocol.tooltip='OpenID connect' allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server.'SAML' enables web-based authentication and authorization scenarios including cross-domain single sign-on (SSO) and uses security tokens containing assertions to pass information. +#access-type=Access Type +#access-type.tooltip='Confidential' clients require a secret to initiate login protocol. 'Public' clients do not require a secret. 'Bearer-only' clients are web services that never initiate a login. +#standard-flow-enabled=Standard Flow Enabled +#standard-flow-enabled.tooltip=This enables standard OpenID Connect redirect based authentication with authorization code. In terms of OpenID Connect or OAuth2 specifications, this enables support of 'Authorization Code Flow' for this client. +#implicit-flow-enabled=Implicit Flow Enabled +#implicit-flow-enabled.tooltip=This enables support for OpenID Connect redirect based authentication without authorization code. In terms of OpenID Connect or OAuth2 specifications, this enables support of 'Implicit Flow' for this client. +#direct-access-grants-enabled=Direct Access Grants Enabled +#direct-access-grants-enabled.tooltip=This enables support for Direct Access Grants, which means that client has access to username/password of user and exchange it directly with Keycloak server for access token. In terms of OAuth2 specification, this enables support of 'Resource Owner Password Credentials Grant' for this client. +#service-accounts-enabled=Service Accounts Enabled +#service-accounts-enabled.tooltip=Allows you to authenticate this client to Keycloak and retrieve access token dedicated to this client. In terms of OAuth2 specification, this enables support of 'Client Credentials Grant' for this client. +#include-authnstatement=Include AuthnStatement +#include-authnstatement.tooltip=Should a statement specifying the method and timestamp be included in login responses? +#include-onetimeuse-condition=Include OneTimeUse Condition +#include-onetimeuse-condition.tooltip=Should a OneTimeUse Condition be included in login responses? +#sign-documents=Sign Documents +#sign-documents.tooltip=Should SAML documents be signed by the realm? +#sign-documents-redirect-enable-key-info-ext=Optimize REDIRECT signing key lookup +#sign-documents-redirect-enable-key-info-ext.tooltip=When signing SAML documents in REDIRECT binding for SP that is secured by Keycloak adapter, should the ID of the signing key be included in SAML protocol message in element? This optimizes validation of the signature as the validating party uses a single key instead of trying every known key for validation. +#sign-assertions=Sign Assertions +#sign-assertions.tooltip=Should assertions inside SAML documents be signed? This setting isn't needed if document is already being signed. +#signature-algorithm=Signature Algorithm +#signature-algorithm.tooltip=The signature algorithm to use to sign documents. +#canonicalization-method=Canonicalization Method +#canonicalization-method.tooltip=Canonicalization Method for XML signatures. +#encrypt-assertions=Encrypt Assertions +#encrypt-assertions.tooltip=Should SAML assertions be encrypted with client's public key using AES? +#client-signature-required=Client Signature Required +#client-signature-required.tooltip=Will the client sign their saml requests and responses? And should they be validated? +#force-post-binding=Force POST Binding +#force-post-binding.tooltip=Always use POST binding for responses. +#front-channel-logout=Front Channel Logout +#front-channel-logout.tooltip=When true, logout requires a browser redirect to client. When false, server performs a background invocation for logout. +#force-name-id-format=Force Name ID Format +#force-name-id-format.tooltip=Ignore requested NameID subject format and use admin console configured one. +#name-id-format=Name ID Format +#name-id-format.tooltip=The name ID format to use for the subject. +#root-url=Root URL +#root-url.tooltip=Root URL appended to relative URLs +#valid-redirect-uris=Valid Redirect URIs +valid-redirect-uris.tooltip=G\u00FCltiges URI-Muster, zu dem ein Browser nach einer erfolgreichen An- oder Abmeldung umleiten kann. Einfache Platzhalter sind zul\u00E4ssig, z. B. "http://example.com/*". Es kann auch ein relativer Pfad angegeben werden, z. B. /my/relative/path/*. Relative Pfade beziehen sich auf die Root URL des Clients, oder wenn keine angegeben ist, wird die Stamm-URL des Autorisierungsservers verwendet. F\u00FCr SAML muss man g\u00FCltige URI-Muster festlegen, wenn man sich auf die in die Anmeldeanforderung eingebettete URL des Verbraucherdienstes verl\u00E4sst. +#base-url.tooltip=Default URL to use when the auth server needs to redirect or link back to the client. +#admin-url=Admin URL +#admin-url.tooltip=URL to the admin interface of the client. Set this if the client supports the adapter REST API. This REST API allows the auth server to push revocation policies and other administrative tasks. Usually this is set to the base URL of the client. +#master-saml-processing-url=Master SAML Processing URL +#master-saml-processing-url.tooltip=If configured, this URL will be used for every binding to both the SP's Assertion Consumer and Single Logout Services. This can be individually overiden for each binding and service in the Fine Grain SAML Endpoint Configuration. +#idp-sso-url-ref=IDP Initiated SSO URL Name +#idp-sso-url-ref.tooltip=URL fragment name to reference client when you want to do IDP Initiated SSO. Leaving this empty will disable IDP Initiated SSO. The URL you will reference from your browser will be: {server-root}/realms/{realm}/protocol/saml/clients/{client-url-name} +#idp-sso-url-ref.urlhint=Target IDP initiated SSO URL: +#idp-sso-relay-state=IDP Initiated SSO Relay State +#idp-sso-relay-state.tooltip=Relay state you want to send with SAML request when you want to do IDP Initiated SSO. +web-origins=Web Origins +web-origins.tooltip=Erlaubte CORS Origins. Um alle Origins der Valid Redirect URIs zu erlauben, f\u00FCgen Sie ein '+' hinzu. Dabei wird der '*' Platzhalter nicht mit \u00FCbernommen. Um alle Origins zu erlauben, geben Sie explizit einen Eintrag mit '*' an. +#fine-oidc-endpoint-conf=Fine Grain OpenID Connect Configuration +#fine-oidc-endpoint-conf.tooltip=Expand this section to configure advanced settings of this client related to OpenID Connect protocol +#user-info-signed-response-alg=User Info Signed Response Algorithm +#user-info-signed-response-alg.tooltip=JWA algorithm used for signed User Info Endpoint response. If set to 'unsigned', then User Info Response won't be signed and will be returned in application/json format. +#request-object-signature-alg=Request Object Signature Algorithm +#request-object-signature-alg.tooltip=JWA algorithm, which client needs to use when sending OIDC request object specified by 'request' or 'request_uri' parameters. If set to 'any', then Request object can be signed by any algorithm (including 'none' ). +#request-object-required=Request Object Required +#request-object-required-alg.tooltip=Specifies if the client needs to provide a request object with their authorization requests, and what method they can use for this. If set to "not required", providing a request object is optional. In all other cases providing a request object is mandatory. If set to "request", the request object must be provided by value. If set to "request_uri", the request object must be provided by reference. If set to "request or request_uri", either method can be used. +#fine-saml-endpoint-conf=Fine Grain SAML Endpoint Configuration +#fine-saml-endpoint-conf.tooltip=Expand this section to configure exact URLs for Assertion Consumer and Single Logout Service. +#assertion-consumer-post-binding-url=Assertion Consumer Service POST Binding URL +#assertion-consumer-post-binding-url.tooltip=SAML POST Binding URL for the client's assertion consumer service (login responses). You can leave this blank if you do not have a URL for this binding. +#assertion-consumer-redirect-binding-url=Assertion Consumer Service Redirect Binding URL +#assertion-consumer-redirect-binding-url.tooltip=SAML Redirect Binding URL for the client's assertion consumer service (login responses). You can leave this blank if you do not have a URL for this binding. +#logout-service-post-binding-url=Logout Service POST Binding URL +#logout-service-post-binding-url.tooltip=SAML POST Binding URL for the client's single logout service. You can leave this blank if you are using a different binding +#logout-service-redir-binding-url=Logout Service Redirect Binding URL +#logout-service-redir-binding-url.tooltip=SAML Redirect Binding URL for the client's single logout service. You can leave this blank if you are using a different binding. +#saml-signature-keyName-transformer=SAML Signature Key Name +#saml-signature-keyName-transformer.tooltip=Signed SAML documents contain identification of signing key in KeyName element. For Keycloak / RH-SSO counterparty, use KEY_ID, for MS AD FS use CERT_SUBJECT, for others check and use NONE if no other option works. +#oidc-compatibility-modes=OpenID Connect Compatibility Modes +#oidc-compatibility-modes.tooltip=Expand this section to configure settings for backwards compatibility with older OpenID Connect / OAuth2 adapters. It is useful especially if your client uses older version of Keycloak / RH-SSO adapter. +#exclude-session-state-from-auth-response=Exclude Session State From Authentication Response +#exclude-session-state-from-auth-response.tooltip=If this is on, the parameter 'session_state' will not be included in OpenID Connect Authentication Response. It is useful if your client uses older OIDC / OAuth2 adapter, which does not support 'session_state' parameter. + +# client import +#import-client=Import Client +#format-option=Format Option +#select-format=Select a Format +#import-file=Import File + +# client tabs +settings=Einstellungen +credentials=Passw\u00F6rter +roles=Rollen +#mappers=Mappers +#mappers.tooltip=Protocol mappers perform transformation on tokens and documents. They can do things like map user data into protocol claims, or just transform any requests going between the client and auth server. +#scope=Scope +#scope.tooltip=Scope mappings allow you to restrict which user role mappings are included within the access token requested by the client. +#sessions.tooltip=View active sessions for this client. Allows you to see which users are active and when they logged in. +#offline-access=Offline Access +#offline-access.tooltip=View offline sessions for this client. Allows you to see which users retrieve offline token and when they retrieve it. To revoke all tokens for the client, go to Revocation tab and set not before value to now. +#clustering=Clustering +#installation=Installation +#installation.tooltip=Helper utility for generating various client adapter configuration formats which you can download or cut and paste to configure your clients. +#service-account-roles=Service Account Roles +#service-account-roles.tooltip=Allows you to authenticate role mappings for the service account dedicated to this client. + +# client credentials +#client-authenticator=Client Authenticator +#client-authenticator.tooltip=Client Authenticator used for authentication this client against Keycloak server +#certificate.tooltip=Client Certificate for validate JWT issued by client and signed by Client private key from your keystore. +#publicKey.tooltip=Public Key for validate JWT issued by client and signed by Client private key. +#no-client-certificate-configured=No client certificate configured +#gen-new-keys-and-cert=Generate new keys and certificate +#import-certificate=Import Certificate +#gen-client-private-key=Generate Client Private Key +#generate-private-key=Generate Private Key +#kid=Kid +#kid.tooltip=KID (Key ID) of the client public key from imported JWKS. +#use-jwks-url=Use JWKS URL +#use-jwks-url.tooltip=If the switch is on, then client public keys will be downloaded from given JWKS URL. This allows great flexibility because new keys will be always re-downloaded again when client generates new keypair. If the switch is off, then public key (or certificate) from the Keycloak DB is used, so when client keypair changes, you always need to import new key (or certificate) to the Keycloak DB as well. +#jwks-url=JWKS URL +#jwks-url.tooltip=URL where client keys in JWK format are stored. See JWK specification for more details. If you use Keycloak client adapter with "jwt" credential, then you can use URL of your app with '/k_jwks' suffix. For example 'http://www.myhost.com/myapp/k_jwks' . +#archive-format=Archive Format +#archive-format.tooltip=Java keystore or PKCS12 archive format. +#key-alias=Key Alias +#key-alias.tooltip=Archive alias for your private key and certificate. +#key-password=Key Password +#key-password.tooltip=Password to access the private key in the archive +#store-password=Store Password +#store-password.tooltip=Password to access the archive itself +#generate-and-download=Generate and Download +#client-certificate-import=Client Certificate Import +#import-client-certificate=Import Client Certificate +#jwt-import.key-alias.tooltip=Archive alias for your certificate. +#secret=Secret +#regenerate-secret=Regenerate Secret +#registrationAccessToken=Registration access token +#registrationAccessToken.regenerate=Regenerate registration access token +#registrationAccessToken.tooltip=The registration access token provides access for clients to the client registration service. +add-role=Rolle hinzuf\u00FCgen +role-name=Rollenname +#composite=Composite +description=Beschreibung +no-client-roles-available=Keine Client-Rollen verf\u00FCgbar +#composite-roles=Composite Roles +#composite-roles.tooltip=When this role is (un)assigned to a user any role associated with it will be (un)assigned implicitly. +realm-roles=Realm-Rollen +available-roles=Verf\u00FCgbare Rollen +add-selected=Ausgew\u00E4hlte hinzuf\u00FCgen +#associated-roles=Associated Roles +#composite.associated-realm-roles.tooltip=Realm level roles associated with this composite role. +#composite.available-realm-roles.tooltip=Realm level roles that you can associate to this composite role. +remove-selected=Ausgew\u00E4hlte entfernen +client-roles=Client-Rollen +select-client-to-view-roles=W\u00E4hlen Sie einen Client um die Rollen daf\u00FCr zu sehen +#available-roles.tooltip=Roles from this client that you can associate to this composite role. +#client.associated-roles.tooltip=Client roles associated with this composite role. +#add-builtin=Add Builtin +category=Kategorie +type=Typ +#no-mappers-available=No mappers available +#add-builtin-protocol-mappers=Add Builtin Protocol Mappers +#add-builtin-protocol-mapper=Add Builtin Protocol Mapper +#scope-mappings=Scope Mappings +#full-scope-allowed=Full Scope Allowed +#full-scope-allowed.tooltip=Allows you to disable all restrictions. +#scope.available-roles.tooltip=Realm level roles that can be assigned to scope. Contains effectively assigned roles which are not directly assigned. +assigned-roles=Zugewiesene Rollen +#assigned-roles.tooltip=Realm level roles assigned to scope. +effective-roles=Effektive Rollen +#realm.effective-roles.tooltip=Assigned realm level roles that may have been inherited from a composite role. +#select-client-roles.tooltip=Select client to view roles for client +#assign.available-roles.tooltip=Client roles available to be assigned. +#client.assigned-roles.tooltip=Assigned client roles. +#client.effective-roles.tooltip=Assigned client roles that may have been inherited from a composite role. +#basic-configuration=Basic configuration +#node-reregistration-timeout=Node Re-registration Timeout +#node-reregistration-timeout.tooltip=Interval to specify max time for registered clients cluster nodes to re-register. If cluster node won't send re-registration request to Keycloak within this time, it will be unregistered from Keycloak +#registered-cluster-nodes=Registered cluster nodes +#register-node-manually=Register node manually +#test-cluster-availability=Test cluster availability +#last-registration=Last registration +#node-host=Node host +#no-registered-cluster-nodes=No registered cluster nodes available +#cluster-nodes=Cluster Nodes +#add-node=Add Node +#active-sessions.tooltip=Total number of active user sessions for this client. +#show-sessions=Show Sessions +#show-sessions.tooltip=Warning, this is a potentially expensive operation depending on number of active sessions. +user=Benutzer +#from-ip=From IP +#session-start=Session Start +first-page=Erste Seite +previous-page=Vorherige Seite +next-page=N\u00E4chste Seite +#client-revoke.not-before.tooltip=Revoke any tokens issued before this date for this client. +#client-revoke.push.tooltip=If admin URL is configured for this client, push this policy to that client. +#select-a-format=Select a Format +#download=Download +#offline-tokens=Offline Tokens +#offline-tokens.tooltip=Total number of offline tokens for this client. +#show-offline-tokens=Show Offline Tokens +#show-offline-tokens.tooltip=Warning, this is a potentially expensive operation depending on number of offline tokens. +#token-issued=Token Issued +last-access=Letzter Zugriff +last-refresh=Letzte Aktualisierung +#key-export=Key Export +#key-import=Key Import +#export-saml-key=Export SAML Key +#import-saml-key=Import SAML Key +#realm-certificate-alias=Realm Certificate Alias +#realm-certificate-alias.tooltip=Realm certificate is stored in archive too. This is the alias to it. +#signing-key=Signing Key +#saml-signing-key=SAML Signing Key. +#private-key=Private Key +#generate-new-keys=Generate new keys +#export=Export +#encryption-key=Encryption Key +#saml-encryption-key.tooltip=SAML Encryption Key. +#service-accounts=Service Accounts +#service-account.available-roles.tooltip=Realm level roles that can be assigned to service account. Contains effectively assigned roles which are not directly assigned. +#service-account.assigned-roles.tooltip=Realm level roles assigned to service account. +#service-account-is-not-enabled-for=Service account is not enabled for {{client}} +#create-protocol-mappers=Create Protocol Mappers +#create-protocol-mapper=Create Protocol Mapper +#protocol=Protocol +#protocol.tooltip=Protocol... +#id=ID +#mapper.name.tooltip=Name of the mapper. +#mapper.consent-required.tooltip=When granting temporary access, must the user consent to providing this data to the client? +#consent-text=Consent Text +#consent-text.tooltip=Text to display on consent page. +#mapper-type=Mapper Type +#mapper-type.tooltip=Type of the mapper +# realm identity providers +#identity-providers=Identity Providers +#table-of-identity-providers=Table of identity providers +#add-provider.placeholder=Add provider... +#provider=Provider +#gui-order=GUI order +#first-broker-login-flow=First Login Flow +#post-broker-login-flow=Post Login Flow +sync-mode=Synchronisationsmodus +sync-mode.tooltip=Standardsyncmodus f\u00FCr alle Mapper. M\u00F6gliche Werte sind: 'Legacy' um das alte Verhalten beizubehalten, 'Importieren' um den Nutzer einmalig zu importieren, 'Erzwingen' um den Nutzer immer zu importieren. +sync-mode.inherit=Standard erben +sync-mode.legacy=Legacy +sync-mode.import=Importieren +sync-mode.force=Erzwingen +sync-mode-override=\u00DCberschriebene Synchronisation +sync-mode-override.tooltip=\u00DCberschreibt den normalen Synchronisationsmodus des IDP f\u00FCr diesen Mapper. Were sind 'Legacy' um das alte Verhalten beizubehalten, 'Importieren' um den Nutzer einmalig zu importieren, 'Erzwingen' um den Nutzer immer zu updaten. +#redirect-uri=Redirect URI +#redirect-uri.tooltip=The redirect uri to use when configuring the identity provider. +#alias=Alias +#display-name=Display Name +#identity-provider.alias.tooltip=The alias uniquely identifies an identity provider and it is also used to build the redirect uri. +#identity-provider.display-name.tooltip=Friendly name for Identity Providers. +#identity-provider.enabled.tooltip=Enable/disable this identity provider. +#authenticate-by-default=Authenticate by Default +#identity-provider.authenticate-by-default.tooltip=Indicates if this provider should be tried by default for authentication even before displaying login screen. +#store-tokens=Store Tokens +#identity-provider.store-tokens.tooltip=Enable/disable if tokens must be stored after authenticating users. +#stored-tokens-readable=Stored Tokens Readable +#identity-provider.stored-tokens-readable.tooltip=Enable/disable if new users can read any stored tokens. This assigns the broker.read-token role. +#disableUserInfo=Disable User Info +#identity-provider.disableUserInfo.tooltip=Disable usage of User Info service to obtain additional user information? Default is to use this OIDC service. +#userIp=Use userIp Param +#identity-provider.google-userIp.tooltip=Set 'userIp' query parameter when invoking on Google's User Info service. This will use the user's ip address. Useful if Google is throttling access to the User Info service. +#hostedDomain=Hosted Domain +#identity-provider.google-hostedDomain.tooltip=Set 'hd' query parameter when logging in with Google. Google will only list accounts for this domain. Keycloak validates that the returned identity token has a claim for this domain. When '*' is entered any hosted account can be used. +#sandbox=Target Sandbox +#identity-provider.paypal-sandbox.tooltip=Target PayPal's sandbox environment +#update-profile-on-first-login=Update Profile on First Login +#on=On +#on-missing-info=On missing info +#off=Off +#update-profile-on-first-login.tooltip=Define conditions under which a user has to update their profile during first-time login. +#trust-email=Trust Email +#trust-email.tooltip=If enabled then email provided by this provider is not verified even if verification is enabled for the realm. +#link-only=Account Linking Only +#link-only.tooltip=If true, users cannot log in through this provider. They can only link to this provider. This is useful if you don't want to allow login from the provider, but want to integrate with a provider +#hide-on-login-page=Hide on Login Page +#hide-on-login-page.tooltip=If hidden, then login with this provider is possible only if requested explicitly, e.g. using the 'kc_idp_hint' parameter. +#gui-order.tooltip=Number defining order of the provider in GUI (eg. on Login page). +#first-broker-login-flow.tooltip=Alias of authentication flow, which is triggered after first login with this identity provider. Term 'First Login' means that there is not yet existing Keycloak account linked with the authenticated identity provider account. +#post-broker-login-flow.tooltip=Alias of authentication flow, which is triggered after each login with this identity provider. Useful if you want additional verification of each user authenticated with this identity provider (for example OTP). Leave this empty if you don't want any additional authenticators to be triggered after login with this identity provider. Also note, that authenticator implementations must assume that user is already set in ClientSession as identity provider already set it. +#openid-connect-config=OpenID Connect Config +#openid-connect-config.tooltip=OIDC SP and external IDP configuration. +#authorization-url=Authorization URL +#authorization-url.tooltip=The Authorization Url. +#token-url=Token URL +#token-url.tooltip=The Token URL. +#loginHint=Pass login_hint +#loginHint.tooltip=Pass login_hint to identity provider. +logout-url=Logout-URL +#identity-provider.logout-url.tooltip=End session endpoint to use to logout user from external IDP. +#backchannel-logout=Backchannel Logout +#backchannel-logout.tooltip=Does the external IDP support backchannel logout? +#user-info-url=User Info URL +#user-info-url.tooltip=The User Info Url. This is optional. +#identity-provider.client-id.tooltip=The client or client identifier registered within the identity provider. +#client-secret=Client Secret +#show-secret=Show secret +#hide-secret=Hide secret +#client-secret.tooltip=The client or client secret registered within the identity provider. +#issuer=Issuer +#issuer.tooltip=The issuer identifier for the issuer of the response. If not provided, no validation will be performed. +#default-scopes=Default Scopes +#identity-provider.default-scopes.tooltip=The scopes to be sent when asking for authorization. It can be a space-separated list of scopes. Defaults to 'openid'. +#prompt=Prompt +#unspecified.option=unspecified +#none.option=none +#consent.option=consent +#login.option=login +#select-account.option=select_account +#prompt.tooltip=Specifies whether the Authorization Server prompts the End-User for reauthentication and consent. +#validate-signatures=Validate Signatures +#identity-provider.validate-signatures.tooltip=Enable/disable signature validation of external IDP signatures. +#identity-provider.use-jwks-url.tooltip=If the switch is on, then identity provider public keys will be downloaded from given JWKS URL. This allows great flexibility because new keys will be always re-downloaded again when identity provider generates new keypair. If the switch is off, then public key (or certificate) from the Keycloak DB is used, so when identity provider keypair changes, you always need to import new key to the Keycloak DB as well. +#identity-provider.jwks-url.tooltip=URL where identity provider keys in JWK format are stored. See JWK specification for more details. If you use external Keycloak identity provider, then you can use URL like 'http://broker-keycloak:8180/auth/realms/test/protocol/openid-connect/certs' assuming your brokered Keycloak is running on 'http://broker-keycloak:8180' and its realm is 'test' . +#validating-public-key=Validating Public Key +#identity-provider.validating-public-key.tooltip=The public key in PEM format that must be used to verify external IDP signatures. +#validating-public-key-id=Validating Public Key Id +#identity-provider.validating-public-key-id.tooltip=Explicit ID of the validating public key given above if the key ID. Leave blank if the key above should be used always, regardless of key ID specified by external IDP; set it if the key should only be used for verifying if key ID from external IDP matches. +#allowed-clock-skew=Allowed clock skew +#identity-provider.allowed-clock-skew.tooltip=Clock skew in seconds that is tolerated when validating identity provider tokens. Default value is zero. +#forwarded-query-parameters=Forwarded Query Parameters +#identity-provider.forwarded-query-parameters.tooltip=Non OpenID Connect/OAuth standard query parameters to be forwarded to external IDP from the initial application request to Authorization Endpoint. Multiple parameters can be entered, separated by comma (,). +#import-external-idp-config=Import External IDP Config +#import-external-idp-config.tooltip=Allows you to load external IDP metadata from a config file or to download it from a URL. +#import-from-url=Import from URL +#identity-provider.import-from-url.tooltip=Import metadata from a remote IDP discovery descriptor. +#import-from-file=Import from file +#identity-provider.import-from-file.tooltip=Import metadata from a downloaded IDP discovery descriptor. +#saml-config=SAML Config +#identity-provider.saml-config.tooltip=SAML SP and external IDP configuration. +#single-signon-service-url=Single Sign-On Service URL +#saml.single-signon-service-url.tooltip=The Url that must be used to send authentication requests (SAML AuthnRequest). +#single-logout-service-url=Single Logout Service URL +#saml.single-logout-service-url.tooltip=The Url that must be used to send logout requests. +#nameid-policy-format=NameID Policy Format +#nameid-policy-format.tooltip=Specifies the URI reference corresponding to a name identifier format. Defaults to urn:oasis:names:tc:SAML:2.0:nameid-format:persistent. +#http-post-binding-response=HTTP-POST Binding Response +#http-post-binding-response.tooltip=Indicates whether to respond to requests using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used. +#http-post-binding-for-authn-request=HTTP-POST Binding for AuthnRequest +#http-post-binding-for-authn-request.tooltip=Indicates whether the AuthnRequest must be sent using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used. +#http-post-binding-logout=HTTP-POST Binding Logout +#http-post-binding-logout.tooltip=Indicates whether to respond to requests using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used. +#want-authn-requests-signed=Want AuthnRequests Signed +#want-authn-requests-signed.tooltip=Indicates whether the identity provider expects a signed AuthnRequest. +#want-assertions-signed=Want Assertions Signed +#want-assertions-signed.tooltip=Indicates whether this service provider expects a signed Assertion. +#want-assertions-encrypted=Want Assertions Encrypted +#want-assertions-encrypted.tooltip=Indicates whether this service provider expects an encrypted Assertion. +#force-authentication=Force Authentication +#identity-provider.force-authentication.tooltip=Indicates whether the identity provider must authenticate the presenter directly rather than rely on a previous security context. +#validate-signature=Validate Signature +#saml.validate-signature.tooltip=Enable/disable signature validation of SAML responses. +#validating-x509-certificate=Validating X509 Certificates +#validating-x509-certificate.tooltip=The certificate in PEM format that must be used to check for signatures. Multiple certificates can be entered, separated by comma (,). +#saml.import-from-url.tooltip=Import metadata from a remote IDP SAML entity descriptor. +#social.client-id.tooltip=The client identifier registered with the identity provider. +#social.client-secret.tooltip=The client secret registered with the identity provider. +#social.default-scopes.tooltip=The scopes to be sent when asking for authorization. See documentation for possible values, separator and default value'. +key=Key +#stackoverflow.key.tooltip=The Key obtained from Stack Overflow client registration. +#openshift.base-url=Base Url +#openshift.base-url.tooltip=Base Url to OpenShift Online API +#openshift4.base-url=Base Url +#openshift4.base-url.tooltip=Base Url to OpenShift Online API +#gitlab-application-id=Application Id +#gitlab-application-secret=Application Secret +#gitlab.application-id.tooltip=Application Id for the application you created in your GitLab Applications account menu +#gitlab.application-secret.tooltip=Secret for the application that you created in your GitLab Applications account menu +#gitlab.default-scopes.tooltip=Scopes to ask for on login. Will always ask for openid. Additionally adds read_user if you do not specify anything. +#bitbucket-consumer-key=Consumer Key +#bitbucket-consumer-secret=Consumer Secret +#bitbucket.key.tooltip=Bitbucket OAuth Consumer Key +#bitbucket.secret.tooltip=Bitbucket OAuth Consumer Secret +#bitbucket.default-scopes.tooltip=Scopes to ask for on login. If you do not specify anything, scope defaults to 'email'. +# User federation +#sync-ldap-roles-to-keycloak=Sync LDAP Roles To Keycloak +#sync-keycloak-roles-to-ldap=Sync Keycloak Roles To LDAP +#sync-ldap-groups-to-keycloak=Sync LDAP Groups To Keycloak +#sync-keycloak-groups-to-ldap=Sync Keycloak Groups To LDAP +realms=Realms +#realm=Realm +#identity-provider-mappers=Identity Provider Mappers +#create-identity-provider-mapper=Create Identity Provider Mapper +#add-identity-provider-mapper=Add Identity Provider Mapper +#client.description.tooltip=Specifies description of the client. For example 'My Client for TimeSheets'. Supports keys for localized values as well. For example\: ${my_client_description} +#expires=Expires +#expiration=Expiration +#expiration.tooltip=Specifies how long the token should be valid +#count=Count +#count.tooltip=Specifies how many clients can be created using the token +#remainingCount=Remaining Count +#created=Created +#back=Back +#initial-access-tokens=Initial Access Tokens +#add-initial-access-tokens=Add Initial Access Token +#initial-access-token=Initial Access Token +#initial-access.copyPaste.tooltip=Copy/paste the initial access token before navigating away from this page as it's not possible to retrieve later +#continue=Continue +#initial-access-token.confirm.title=Copy Initial Access Token +#initial-access-token.confirm.text=Please copy and paste the initial access token before confirming as it can't be retrieved later +#no-initial-access-available=No Initial Access Tokens available +#client-reg-policies=Client Registration Policies +#client-reg-policy.name.tooltip=Display Name of the policy +#anonymous-policies=Anonymous Access Policies +#anonymous-policies.tooltip=Those Policies are used when Client Registration Service is invoked by unauthenticated request. This means request doesn't contain Initial Access Token nor Bearer Token. +#auth-policies=Authenticated Access Policies +#auth-policies.tooltip=Those Policies are used when Client Registration Service is invoked by authenticated request. This means request contains Initial Access Token or Bearer Token. +#policy-name=Policy Name +#no-client-reg-policies-configured=No Client Registration Policies +#trusted-hosts.label=Trusted Hosts +#trusted-hosts.tooltip=List of Hosts, which are trusted and are allowed to invoke Client Registration Service and/or be used as values of Client URIs. You can use hostnames or IP addresses. If you use star at the beginning (for example '*.example.com' ) then whole domain example.com will be trusted. +#host-sending-registration-request-must-match.label=Host Sending Client Registration Request Must Match +#host-sending-registration-request-must-match.tooltip=If on, then any request to Client Registration Service is allowed just if it was sent from some trusted host or domain. +#client-uris-must-match.label=Client URIs Must Match +#client-uris-must-match.tooltip=If on, then all Client URIs (Redirect URIs and others) are allowed just if they match some trusted host or domain. +#allowed-protocol-mappers.label=Allowed Protocol Mappers +#allowed-protocol-mappers.tooltip=Whitelist of allowed protocol mapper providers. If there is an attempt to register client, which contains some protocol mappers, which were not whitelisted, then registration request will be rejected. +#consent-required-for-all-mappers.label=Consent Required For Mappers +#consent-required-for-all-mappers.tooltip=If on, then all newly registered protocol mappers will automatically have consentRequired switch on. This means that user will need to approve consent screen. NOTE: Consent screen is shown just if client has consentRequired switch on. So it's usually good to use this switch together with consent-required policy. +#allowed-client-scopes.label=Allowed Client Scopes +#allowed-client-scopes.tooltip=Whitelist of the client scopes, which can be used on newly registered client. Attempt to register client with some client scope, which is not whitelisted, will be rejected. By default, the whitelist is either empty or contains just realm default client scopes (based on 'Allow Default Scopes' configuration property) +#allow-default-scopes.label=Allow Default Scopes +#allow-default-scopes.tooltip=If on, then newly registered clients will be allowed to have client scopes mentioned in realm default client scopes or realm optional client scopes +#max-clients.label=Max Clients Per Realm +#max-clients.tooltip=It won't be allowed to register new client if count of existing clients in realm is same or bigger than configured limit. + +#client-scopes=Client Scopes +#client-scopes.tooltip=Client scopes allow you to define common set of protocol mappers and roles, that are shared between multiple clients + +groups=Gruppen + +group.add-selected.tooltip=Realm-Rollen die zu der Gruppen hinzugef\u00FCgt werden k\u00F6nnen. +group.assigned-roles.tooltip=Realm-Rollen die zur Gruppe zugeordnet sind +#group.effective-roles.tooltip=All realm role mappings. Some roles here might be inherited from a mapped composite role. +#group.available-roles.tooltip=Assignable roles from this client. Contains effectively assigned roles which are not directly assigned. +#group.assigned-roles-client.tooltip=Role mappings for this client. +#group.effective-roles-client.tooltip=Role mappings for this client. Some roles here might be inherited from a mapped composite role. + +group.move.success=Gruppe verschoben. +group.remove.confirm.title=Gruppe l\u00F6schen +group.remove.confirm.message=Sind Sie sicher, dass Sie die Gruppe \u201E{{name}}\u201C l\u00F6schen m\u00F6chten? +group.remove.success=Die Gruppe wurde gel\u00F6scht. +group.fetch.fail=Fehler beim Laden: {{params}} +group.create.success=Gruppe erstellt. +group.edit.success=Die \u00C4nderungen wurde gespeichert. +group.roles.add.success=Rollenzuweisung hinzugef\u00FCgt. +group.roles.remove.success=Rollenzuweisung entfernt. +group.default.add.error=Bitte eine Gruppe ausw\u00E4hlen. +group.default.add.success=Standardgruppe hinzugef\u00FCgt. +group.default.remove.success=Standardgruppe entfernt. + +default-roles=Standardrollen +no-realm-roles-available=Keine Realm-Rollen verf\u00FCgbar + +users=Benutzer +user.add-selected.tooltip=Realm-Rollen, die dem Benutzer zugewiesen werden k\u00F6nnen. +user.assigned-roles.tooltip=Realm-Rollen, die dem Benutzer zugewiesen sind. +user.effective-roles.tooltip=Alle Realm-Rollen-Zuweisungen. Einige Rollen hier k\u00F6nnen von zusammengesetzten Rollen geerbt sein. +#user.available-roles.tooltip=Assignable roles from this client. Contains effectively assigned roles which are not directly assigned. +#user.assigned-roles-client.tooltip=Role mappings for this client. +#user.effective-roles-client.tooltip=Role mappings for this client. Some roles here might be inherited from a mapped composite role. + +user.roles.add.success=Rollenzuweisung hinzugef\u00FCgt. +user.roles.remove.success=Rollenzuweisung entfernt. +user.logout.all.success=Benutzer von allen Sitzungen abgemeldet. +user.logout.session.success=Benutzer von Sitzung abgemeldet. +user.fedid.link.remove.confirm.title=Verkn\u00FCpfung mit Identity Provider entfernen +user.fedid.link.remove.confirm.message=Sind Sie sicher, dass Sie die Verkn\u00FCpfung mit dem Identity Provider \u201E{{name}}\u201C entfernen m\u00F6chten? +user.fedid.link.remove.success=Verkn\u00FCpfung mit Identity Provider entfernt. +user.fedid.link.add.success=Verkn\u00FCpfung mit Identity Provider angelegt. +user.consent.revoke.success=Einwilligung widerrufen. +user.consent.revoke.error=Einwilligung konnte nicht widerrufen werden. +user.unlock.success=Alle vor\u00FCbergehend gesperrten Benutzer wurden entsperrt. +user.remove.confirm.title=Benutzer l\u00F6schen +user.remove.confirm.message=Sind Sie sicher, dass Sie den Benutzer \u201E{{name}}\u201C l\u00F6schen m\u00F6chten? +user.remove.success=Der Benutzer wurde gel\u00F6scht. +user.remove.error=Der Benutzer konnte nicht gel\u00F6scht werden. +user.create.success=Der Benutzer wurde angelegt. +user.edit.success=Die \u00C4nderungen wurden gespeichert. +user.credential.update.success=Die Zugangsdaten wurdern gespeichert. +user.credential.update.error=Beim Speichern der Zugangsdaten ist ein Fehler aufgetreten. +user.credential.remove.confirm.title=Zugangsdaten l\u00F6schen +user.credential.remove.confirm.message=Sind Sie sicher, dass Sie die Zugangsdaten l\u00F6schen m\u00F6chten? +user.credential.remove.success=Die Zugangsdaten wurden gel\u00F6scht. +user.credential.remove.error=Beim L\u00F6schen der Zugangsdaten ist ein Fehler aufgetreten. +user.credential.move-top.error=Beim Verschieben der Zugangsdaten ist ein Fehler aufgetreten. +user.credential.move-up.error=Beim Verschieben der Zugangsdaten ist ein Fehler aufgetreten. +user.credential.move-down.error=Beim Verschieben der Zugangsdaten ist ein Fehler aufgetreten. +user.credential.fetch.error=Beim Laden der Zugangsdaten ist ein Fehler aufgetreten. +#user.credential.storage.fetch.error=Error while loading user storage credentials. See console for more information. +user.password.error.not-matching=Die Passw\u00F6rter stimmen nicht \u00FCberein. +user.password.reset.confirm.title=Passwort zur\u00FCcksetzen +user.password.reset.confirm.message=Sind Sie sicher, dass Sie das Passwort f\u00FCr diesen Benutzer zur\u00FCcksetzen m\u00F6chten? +user.password.reset.success=Das Passwort wurde zur\u00FCckgesetzt. +user.password.set.confirm.title=Passwort setzen +user.password.set.confirm.message=Sind Sie sicher, dass Sie ein Passwort f\u00FCr diesen Benutzer setzen m\u00F6chten? +user.password.set.success=Das Passwort wurde gesetzt. +user.credential.disable.confirm.title=Zugangsdaten deaktivieren +user.credential.disable.confirm.message=Sind Sie sicher, dass Sie diese Zugangsdaten deaktivieren m\u00F6chten? +user.credential.disable.confirm.success=Zugangsdaten deaktiviert. +user.credential.disable.confirm.error=Fehler beim Deaktivieren der Zugangsdaten +user.actions-email.send.pending-changes.title=E-Mail kann nicht gesendet werden. +user.actions-email.send.pending-changes.message=Bitte speichern Sie Ihre \u00C4nderungen bevor Sie die E-Mail senden. +user.actions-email.send.confirm.title=E-Mail senden +user.actions-email.send.confirm.message=Sind Sie sicher, dass Sie die E-Mail an den Benutzer senden m\u00F6chten? +user.actions-email.send.confirm.success=E-Mail an Benutzer gesendet. +user.actions-email.send.confirm.error=Fehler beim Senden der E-Mail +#user.storage.remove.confirm.title=Delete User storage provider +#user.storage.remove.confirm.message=Are you sure you want to permanently delete the user storage provider {{name}}? +#user.storage.remove.success=The provider has been deleted. +#user.storage.create.success=The provider has been created. +#user.storage.edit.success=The provider has been updated. +#user.storage.sync.success=Sync of users finished successfully. {{status}} +#user.storage.sync.error=Error during sync of users +#user.storage.remove-users.success=Remove imported users finished successfully. +#user.storage.remove-users.error=Error during remove +#user.storage.unlink.success=Unlink of users finished successfully. +#user.storage.unlink.error=Error during unlink +user.groups.fetch.all.error=Fehler beim Laden alle Gruppen: {{params}} +user.groups.fetch.error=Fehler beim Laden: {{params}} +user.groups.join.error.no-group-selected=Bitte w\u00E4hlen Sie eine Gruppe aus! +user.groups.join.error.already-added=Benutzer geh\u00F6rt der Gruppe bereits an. +user.groups.join.success=Zur Gruppe hinzugef\u00FCgt. +user.groups.leave.error.no-group-selected=Bitte w\u00E4hlen Sie eine Gruppe aus! +user.groups.leave.success=Aus Gruppe entfernt. + +#default.available-roles.tooltip=Realm level roles that can be assigned. +#realm-default-roles=Realm Default Roles +#realm-default-roles.tooltip=Realm level roles assigned to new users. +#default.available-roles-client.tooltip=Roles from this client that are assignable as a default. +#client-default-roles=Client Default Roles +#client-default-roles.tooltip=Roles from this client assigned as a default role. +#composite.available-roles.tooltip=Realm level roles that you can associate to this composite role. +#composite.associated-roles.tooltip=Realm level roles associated with this composite role. +#composite.available-roles-client.tooltip=Roles from this client that you can associate to this composite role. +#composite.associated-roles-client.tooltip=Client roles associated with this composite role. +#partial-import=Partial Import +#partial-import.tooltip=Partial import allows you to import users, clients, and other resources from a previously exported json file. + +#file=File +#exported-json-file=Exported json file +#import-from-realm=Import from realm +#import-users=Import users +#import-groups=Import groups +#import-clients=Import clients +#import-identity-providers=Import identity providers +#import-realm-roles=Import realm roles +#import-client-roles=Import client roles +#if-resource-exists=If a resource exists +#fail=Fail +#skip=Skip +#overwrite=Overwrite +#if-resource-exists.tooltip=Specify what should be done if you try to import a resource that already exists. + +#partial-export=Partial Export +#partial-export.tooltip=Partial export allows you to export realm configuration, and other associated resources into a json file. +#export-groups-and-roles=Export groups and roles +#export-clients=Export clients + +action=Aktion +#role-selector=Role Selector +#realm-roles.tooltip=Realm roles that can be selected. + +#select-a-role=Select a role +#select-realm-role=Select realm role +#client-roles.tooltip=Client roles that can be selected. +#select-client-role=Select client role + +#client-saml-endpoint=Client SAML Endpoint +#add-client-scope=Add client scope + +#default-client-scopes=Default Client Scopes +#default-client-scopes.tooltip=Client Scopes, which will be added automatically to each created client +#default-client-scopes.default=Default Client Scopes +#default-client-scopes.default.tooltip=Allow to define client scopes, which will be added as default scopes to each created client +#default-client-scopes.default.available=Available Client Scopes +#default-client-scopes.default.available.tooltip=Client scopes, which are not yet assigned as realm default scopes or realm optional scopes +#default-client-scopes.default.assigned=Assigned Default Client Scopes +#default-client-scopes.default.assigned.tooltip=Client scopes, which will be added as default scopes to each created client +#default-client-scopes.optional=Optional Client Scopes +#default-client-scopes.optional.tooltip=Allow to define client scopes, which will be added as optional scopes to each created client +#default-client-scopes.optional.available=Available Client Scopes +#default-client-scopes.optional.available.tooltip=Client scopes, which are not yet assigned as realm default scopes or realm optional scopes +#default-client-scopes.optional.assigned=Assigned Optional Client Scopes +#default-client-scopes.optional.assigned.tooltip=Client scopes, which will be added as optional scopes to each created client + +#client-scopes.setup=Setup +#client-scopes.setup.tooltip=Allow to setup client scopes linked to this client +#client-scopes.default=Default Client Scopes +#client-scopes.default.tooltip=Default client scopes are always applied when issuing tokens for this client. Protocol mappers and role scope mappings are always applied regardless of value of used scope parameter in OIDC Authorization request +#client-scopes.default.available=Available Client Scopes +#client-scopes.default.available.tooltip=Client scopes, which are not yet assigned as default scopes or optional scopes +#client-scopes.default.assigned=Assigned Default Client Scopes +#client-scopes.default.assigned.tooltip=Client scopes, which will be used as default scopes when generating tokens for this client +#client-scopes.optional=Optional Client Scopes +#client-scopes.optional.tooltip=Optional client scopes are applied when issuing tokens for this client, however just in case when they are requested by scope parameter in OIDC Authorization request +#client-scopes.optional.available=Available Client Scopes +#client-scopes.optional.available.tooltip=Client scopes, which are not yet assigned as default scopes or optional scopes +#client-scopes.optional.assigned=Assigned Optional Client Scopes +#client-scopes.optional.assigned.tooltip=Client scopes, which may be used as optional scopes when generating tokens for this client + +#client-scopes.evaluate=Evaluate +#client-scopes.evaluate.tooltip=Allow to see all protocol mappers and role scope mappings, which will be used in the tokens issued to this client. Also allow to generate example access token based on provided scope parameter +#scope-parameter=Scope Parameter +#scope-parameter.tooltip=You can copy/paste this value of scope parameter and use it in initial OpenID Connect Authentication Request sent from this client adapter. Default client scopes and selected optional client scopes will be used when generating token issued for this client +#client-scopes.evaluate.scopes=Client Scopes +#client-scopes.evaluate.scopes.tooltip=Allow to select optional client scopes, which may be used when generating token issued for this client +#client-scopes.evaluate.scopes.available=Available Optional Client Scopes +#client-scopes.evaluate.scopes.available.tooltip=This contains Optional Client Scopes, which can be optionally used when issuing access token for this client +#client-scopes.evaluate.scopes.assigned=Selected Optional Client Scopes +#client-scopes.evaluate.scopes.assigned.tooltip=Selected Optional Client Scopes, which will be used when issuing access token for this client. You can see above what value of OAuth Scope Parameter need to be used when you want to have these optional client scopes applied when the initial OpenID Connect Authentication request will be sent from your client adapter +#client-scopes.evaluate.scopes.effective=Effective Client Scopes +#client-scopes.evaluate.scopes.effective.tooltip=Contains all default client scopes and selected optional scopes. All protocol mappers and role scope mappings of all those client scopes will be used when generating access token issued for your client +#client-scopes.evaluate.user.tooltip=Optionally select user, for whom the example access token will be generated. If you don't select any user, then example access token won't be generated during evaluation +#send-evaluation-request=Evaluate +#send-evaluation-request.tooltip=Click this to see all protocol mappers and role scope mappings, which will be used when issuing access token for this client. It will also optionally generate example access token in case that some user was selected + +#evaluated-protocol-mappers=Effective Protocol Mappers +#evaluated-protocol-mappers.tooltip=Allow you to see all effective protocol mappers, which will be used when issuing token for this client. Contains also protocol mappers of selected optional client scopes. For each protocol mapper, you can see from which client scope it is inherited from +#evaluated-roles=Effective Role Scope Mappings +#evaluated-roles.tooltip=Allow you to see all effective roles scope mappings, which will be used when issuing token for this client. Contains also role scope mappings of selected optional client scopes +#parent-client-scope=Parent Client Scope +#client-scopes.evaluate.not-granted-roles=Not Granted Roles +#client-scopes.evaluate.not-granted-roles.tooltip=Client doesn't have scope mappings for these roles. Those roles won't be in the access token issued to this client even if authenticated user is member of them +#client-scopes.evaluate.granted-realm-effective-roles=Granted Effective Realm Roles +#client-scopes.evaluate.granted-realm-effective-roles.tooltip=Client has scope mappings for these roles. Those roles will be in the access token issued to this client if authenticated user is member of them +#client-scopes.evaluate.granted-client-effective-roles=Granted Effective Client Roles +#generated-access-token=Generated Access Token +#generated-access-token.tooltip=See the example token, which will be generated and sent to the client when selected user is authenticated. You can see claims and roles, which the token will contain based on the effective protocol mappers and role scope mappings and also based on the claims/roles assigned to user himself + +manage=Verwalten +authentication=Authentifizierung +#user-federation=User Federation +#user-storage=User Storage +events=Ereignisse +realm-settings=Realm-Einstellungen +configure=Konfigurieren +select-realm=Realm ausw\u00E4hlen +add=Hinzuf\u00FCgen + +#client-storage=Client Storage +#no-client-storage-providers-configured=No client storage providers configured +#client-stores.tooltip=Keycloak can retrieve clients and their details from external stores. + +#client-scope.name.tooltip=Name of the client scope. Must be unique in the realm. Name shouldn't contain space characters as it's used as value of scope parameter +#client-scope.description.tooltip=Description of the client scope +#client-scope.protocol.tooltip=Which SSO protocol configuration is being supplied by this client scope +#client-scope.display-on-consent-screen=Display On Consent Screen +#client-scope.display-on-consent-screen.tooltip=If on, and this client scope is added to some client with consent required, then the text specified by 'Consent Screen Text' will be displayed on consent screen. If off, then this client scope won't be displayed on consent screen +#client-scope.consent-screen-text=Consent Screen Text +#client-scope.consent-screen-text.tooltip=Text, which will be shown on consent screen when this client scope is added to some client with consent required. Defaults to name of client scope if it's not filled + +#add-user-federation-provider=Add user federation provider +#add-user-storage-provider=Add user storage provider +#required-settings=Required Settings +#provider-id=Provider ID +#console-display-name=Console Display Name +#console-display-name.tooltip=Display name of provider when linked in admin console. +#priority=Priority +#priority.tooltip=Priority of provider when doing a user lookup. Lowest first. +#user-storage.enabled.tooltip=If provider is disabled it will not be considered for queries and imported users will be disabled and read-only until the provider is enabled again. +#sync-settings=Sync Settings +#periodic-full-sync=Periodic Full Sync +#periodic-full-sync.tooltip=Does periodic full synchronization of provider users to Keycloak should be enabled or not +#full-sync-period=Full Sync Period +#full-sync-period.tooltip=Period for full synchronization in seconds +#periodic-changed-users-sync=Periodic Changed Users Sync +#periodic-changed-users-sync.tooltip=Does periodic synchronization of changed or newly created provider users to Keycloak should be enabled or not +#changed-users-sync-period=Changed Users Sync Period +#changed-users-sync-period.tooltip=Period for synchronization of changed or newly created provider users in seconds +#synchronize-changed-users=Synchronize changed users +#synchronize-all-users=Synchronize all users +#remove-imported-users=Remove imported +unlink-users=Benutzer entsperren +#kerberos-realm=Kerberos Realm +#kerberos-realm.tooltip=Name of kerberos realm. For example FOO.ORG +#server-principal=Server Principal +#server-principal.tooltip=Full name of server principal for HTTP service including server and domain name. For example HTTP/host.foo.org@FOO.ORG +#keytab=KeyTab +#keytab.tooltip=Location of Kerberos KeyTab file containing the credentials of server principal. For example /etc/krb5.keytab +#debug=Debug +#debug.tooltip=Enable/disable debug logging to standard output for Krb5LoginModule. +#allow-password-authentication=Allow Password Authentication +#allow-password-authentication.tooltip=Enable/disable possibility of username/password authentication against Kerberos database +#edit-mode=Edit Mode +#edit-mode.tooltip=READ_ONLY means that password updates are not allowed and user always authenticates with Kerberos password. UNSYNCED means user can change his password in Keycloak database and this one will be used instead of Kerberos password then +#ldap.edit-mode.tooltip=READ_ONLY is a read-only LDAP store. WRITABLE means data will be synced back to LDAP on demand. UNSYNCED means user data will be imported, but not synced back to LDAP. +#update-profile-first-login=Update Profile First Login +#update-profile-first-login.tooltip=Update profile on first login +#sync-registrations=Sync Registrations +#ldap.sync-registrations.tooltip=Should newly created users be created within LDAP store? Priority effects which provider is chose to sync the new user. +#import-enabled=Import Users +#ldap.import-enabled.tooltip=If true, LDAP users will be imported into Keycloak DB and synced via the configured sync policies. +#vendor=Vendor +#ldap.vendor.tooltip=LDAP vendor (provider) +#username-ldap-attribute=Username LDAP attribute +#ldap-attribute-name-for-username=LDAP attribute name for username +#username-ldap-attribute.tooltip=Name of LDAP attribute, which is mapped as Keycloak username. For many LDAP server vendors it can be 'uid'. For Active directory it can be 'sAMAccountName' or 'cn'. The attribute should be filled for all LDAP user records you want to import from LDAP to Keycloak. +#rdn-ldap-attribute=RDN LDAP attribute +#ldap-attribute-name-for-user-rdn=LDAP attribute name for user RDN +#rdn-ldap-attribute.tooltip=Name of LDAP attribute, which is used as RDN (top attribute) of typical user DN. Usually it's the same as Username LDAP attribute, however it's not required. For example for Active directory it's common to use 'cn' as RDN attribute when username attribute might be 'sAMAccountName'. +#uuid-ldap-attribute=UUID LDAP attribute +#ldap-attribute-name-for-uuid=LDAP attribute name for UUID +#uuid-ldap-attribute.tooltip=Name of LDAP attribute, which is used as unique object identifier (UUID) for objects in LDAP. For many LDAP server vendors it's 'entryUUID' however some are different. For example for Active directory it should be 'objectGUID'. If your LDAP server really doesn't support the notion of UUID, you can use any other attribute, which is supposed to be unique among LDAP users in tree. For example 'uid' or 'entryDN'. +#user-object-classes=User Object Classes +#ldap-user-object-classes.placeholder=LDAP User Object Classes (div. by comma) +#ldap-connection-url=LDAP connection URL +#ldap-users-dn=LDAP Users DN +#ldap-bind-dn=LDAP Bind DN +#ldap-bind-credentials=LDAP Bind Credentials +#ldap-filter=LDAP Filter +#ldap.user-object-classes.tooltip=All values of LDAP objectClass attribute for users in LDAP divided by comma. For example: 'inetOrgPerson, organizationalPerson' . Newly created Keycloak users will be written to LDAP with all those object classes and existing LDAP user records are found just if they contain all those object classes. +#connection-url=Connection URL +#ldap.connection-url.tooltip=Connection URL to your LDAP server +#test-connection=Test connection +#users-dn=Users DN +#ldap.users-dn.tooltip=Full DN of LDAP tree where your users are. This DN is parent of LDAP users. It could be for example 'ou=users,dc=example,dc=com' assuming that your typical user will have DN like 'uid=john,ou=users,dc=example,dc=com' +#authentication-type=Authentication Type +#ldap.authentication-type.tooltip=LDAP Authentication type. Right now just 'none' (anonymous LDAP authentication) or 'simple' (Bind credential + Bind password authentication) mechanisms are available +#bind-dn=Bind DN +#ldap.bind-dn.tooltip=DN of LDAP admin, which will be used by Keycloak to access LDAP server +#bind-credential=Bind Credential +#ldap.bind-credential.tooltip=Password of LDAP admin +#test-authentication=Test authentication +#custom-user-ldap-filter=Custom User LDAP Filter +#ldap.custom-user-ldap-filter.tooltip=Additional LDAP Filter for filtering searched users. Leave this empty if you don't need additional filter. Make sure that it starts with '(' and ends with ')' +#search-scope=Search Scope +#ldap.search-scope.tooltip=For one level, we search for users just in DNs specified by User DNs. For subtree, we search in whole of their subtree. See LDAP documentation for more details +#use-truststore-spi=Use Truststore SPI +#ldap.use-truststore-spi.tooltip=Specifies whether LDAP connection will use the truststore SPI with the truststore configured in standalone.xml/domain.xml. 'Always' means that it will always use it. 'Never' means that it won't use it. 'Only for ldaps' means that it will use if your connection URL use ldaps. Note even if standalone.xml/domain.xml is not configured, the default Java cacerts or certificate specified by 'javax.net.ssl.trustStore' property will be used. +#validate-password-policy=Validate Password Policy +#connection-pooling=Connection Pooling +#connection-pooling-settings=Connection Pooling Settings +#connection-pooling-authentication=Connection Pooling Authentication +#connection-pooling-authentication-default=none simple +#connection-pooling-debug=Connection Pool Debug Level +#connection-pooling-debug-default=off +#connection-pooling-initsize=Connection Pool Initial Size +#connection-pooling-initsize-default=1 +#connection-pooling-maxsize=Connection Pool Maximum Size +#connection-pooling-maxsize-default=1000 +#connection-pooling-prefsize=Connection Pool Preferred Size +#connection-pooling-prefsize-default=5 +#connection-pooling-protocol=Connection Pool Protocol +#connection-pooling-protocol-default=plain ssl +#connection-pooling-timeout=Connection Pool Timeout +#connection-pooling-timeout-default=300000 +#ldap-connection-timeout=Connection Timeout +#ldap.connection-timeout.tooltip=LDAP Connection Timeout in milliseconds +#ldap-read-timeout=Read Timeout +#ldap.read-timeout.tooltip=LDAP Read Timeout in milliseconds. This timeout applies for LDAP read operations +#ldap.validate-password-policy.tooltip=Does Keycloak should validate the password with the realm password policy before updating it +#ldap.connection-pooling.tooltip=Does Keycloak should use connection pooling for accessing LDAP server +#ldap.connection-pooling.authentication.tooltip=A list of space-separated authentication types of connections that may be pooled. Valid types are "none", "simple", and "DIGEST-MD5". +#ldap.connection-pooling.debug.tooltip=A string that indicates the level of debug output to produce. Valid values are "fine" (trace connection creation and removal) and "all" (all debugging information). +#ldap.connection-pooling.initsize.tooltip=The string representation of an integer that represents the number of connections per connection identity to create when initially creating a connection for the identity. +#ldap.connection-pooling.maxsize.tooltip=The string representation of an integer that represents the maximum number of connections per connection identity that can be maintained concurrently. +#ldap.connection-pooling.prefsize.tooltip=The string representation of an integer that represents the preferred number of connections per connection identity that should be maintained concurrently. +#ldap.connection-pooling.protocol.tooltip=A list of space-separated protocol types of connections that may be pooled. Valid types are "plain" and "ssl". +#ldap.connection-pooling.timeout.tooltip=The string representation of an integer that represents the number of milliseconds that an idle connection may remain in the pool without being closed and removed from the pool. +#ldap.pagination.tooltip=Does the LDAP server support pagination. +#kerberos-integration=Kerberos Integration +#allow-kerberos-authentication=Allow Kerberos authentication +#ldap.allow-kerberos-authentication.tooltip=Enable/disable HTTP authentication of users with SPNEGO/Kerberos tokens. The data about authenticated users will be provisioned from this LDAP server +#use-kerberos-for-password-authentication=Use Kerberos For Password Authentication +#ldap.use-kerberos-for-password-authentication.tooltip=Use Kerberos login module for authenticate username/password against Kerberos server instead of authenticating against LDAP server with Directory Service API +#batch-size=Batch Size +#ldap.batch-size.tooltip=Count of LDAP users to be imported from LDAP to Keycloak within single transaction. +#ldap.periodic-full-sync.tooltip=Does periodic full synchronization of LDAP users to Keycloak should be enabled or not +#ldap.periodic-changed-users-sync.tooltip=Does periodic synchronization of changed or newly created LDAP users to Keycloak should be enabled or not +#ldap.changed-users-sync-period.tooltip=Period for synchronization of changed or newly created LDAP users in seconds +#user-federation-mappers=User Federation Mappers +#create-user-federation-mapper=Create user federation mapper +#add-user-federation-mapper=Add user federation mapper +#provider-name=Provider Name +#no-user-federation-providers-configured=No user federation providers configured +#no-user-storage-providers-configured=No user storage providers configured +#add-identity-provider=Add identity provider +#add-identity-provider-link=Add identity provider link +#identity-provider=Identity Provider +#identity-provider-user-id=Identity Provider User ID +#identity-provider-user-id.tooltip=Unique ID of the user on the Identity Provider side +#identity-provider-username=Identity Provider Username +#identity-provider-username.tooltip=Username on the Identity Provider side +#pagination=Pagination +#browser-flow=Browser Flow +#browser-flow.tooltip=Select the flow you want to use for browser authentication. +#registration-flow=Registration Flow +#registration-flow.tooltip=Select the flow you want to use for registration. +#direct-grant-flow=Direct Grant Flow +#direct-grant-flow.tooltip=Select the flow you want to use for direct grant authentication. +#reset-credentials=Reset Credentials +#reset-credentials.tooltip=Select the flow you want to use when the user has forgotten their credentials. +#client-authentication=Client Authentication +#client-authentication.tooltip=Select the flow you want to use for authentication of clients. +#docker-auth=Docker Authentication +#docker-auth.tooltip=Select the flow you want to use for authentication against a docker client. +new=Neu +copy=Kopieren +#add-execution=Add execution +#add-flow=Add flow +#auth-type=Auth Type +#requirement=Requirement +#config=Config +#no-executions-available=No executions available +#authentication-flows=Authentication Flows +#create-authenticator-config=Create authenticator config +#authenticator.alias.tooltip=Name of the configuration +#otp-type=OTP Type +#time-based=Time Based +#counter-based=Counter Based +#otp-type.tooltip=totp is Time-Based One Time Password. 'hotp' is a counter base one time password in which the server keeps a counter to hash against. +#otp-hash-algorithm=OTP Hash Algorithm +#otp-hash-algorithm.tooltip=What hashing algorithm should be used to generate the OTP. +#number-of-digits=Number of Digits +#otp.number-of-digits.tooltip=How many digits should the OTP have? +#look-ahead-window=Look Ahead Window +#otp.look-ahead-window.tooltip=How far ahead should the server look just in case the token generator and server are out of time sync or counter sync? +#initial-counter=Initial Counter +#otp.initial-counter.tooltip=What should the initial counter value be? +#otp-token-period=OTP Token Period +#otp-token-period.tooltip=How many seconds should an OTP token be valid? Defaults to 30 seconds. +#otp-supported-applications=Supported Applications +#otp-supported-applications.tooltip=Applications that are known to work with the current OTP policy +#table-of-password-policies=Table of Password Policies +#add-policy.placeholder=Add policy... +#policy-type=Policy Type +#policy-value=Policy Value +#admin-events=Admin Events +#admin-events.tooltip=Displays saved admin events for the realm. Events are related to admin account, for example a realm creation. To enable persisted events go to config. +#login-events=Login Events +#filter=Filter +#update=Update +#reset=Reset +#operation-types=Operation Types +#resource-types=Resource Types +#select-operations.placeholder=Select operations... +#select-resource-types.placeholder=Select resource types... +#resource-path=Resource Path +#resource-path.tooltip=Filter by resource path. Supports wildcard '*' (for example 'users/*'). +#date-(from)=Date (From) +#date-(to)=Date (To) +#authentication-details=Authentication Details +ip-address=IP-Adresse +time=Zeit +#operation-type=Operation Type +#resource-type=Resource Type +#auth=Auth +#representation=Representation +register=Registrieren +#required-action=Required Action +#default-action=Default Action +#auth.default-action.tooltip=If enabled, any new user will have this required action assigned to it. +#no-required-actions-configured=No required actions configured +#defaults-to-id=Defaults to id +#flows=Flows +#bindings=Bindings +#client-flow-bindings=Authentication Flow Overrides +#client-flow-bindings.tooltip=Override realm authentication flow bindings. +#required-actions=Required Actions +#password-policy=Password Policy +#otp-policy=OTP Policy +user-groups=Benutzergruppen +default-groups=Standardgruppen +groups.default-groups.tooltip=Liste von Gruppen, denen neue Benutzer automatisch beitreten. +cut=Ausschneiden +paste=Einf\u00FCgen +create-group=Gruppe erstellen +#create-authenticator-execution=Create Authenticator Execution +#create-form-action-execution=Create Form Action Execution +#create-top-level-form=Create Top Level Form +#flow.alias.tooltip=Specifies display name for the flow. +#top-level-flow-type=Top Level Flow Type +#flow.generic=generic +#flow.client=client +#top-level-flow-type.tooltip=What kind of top level flow is it? Type 'client' is used for authentication of clients (applications) when generic is for users and everything else +#create-execution-flow=Create Execution Flow +#flow-type=Flow Type +#flow.form.type=form +#flow.generic.type=generic +#flow-type.tooltip=What kind of form is it +#form-provider=Form Provider +#default-groups.tooltip=Newly created or registered users will automatically be added to these groups +select-a-type.placeholder=Typ ausw\u00E4hlen +available-groups=Verf\u00FCgbare Gruppen +#available-groups.tooltip=Select a group you want to add as a default. +value=Wert +#table-of-group-members=Table of group members +#table-of-role-members=Table of role members +last-name=Nachname +first-name=Vorname +email=Email +toggle-navigation=Navigation ein-/ausschalten +manage-account=Konto verwalten +sign-out=Abmelden +server-info=Server-Info +#resource-not-found=Resource not found... +#resource-not-found.instruction=We could not find the resource you are looking for. Please make sure the URL you entered is correct. +#go-to-the-home-page=Go to the home page » +#page-not-found=Page not found... +#page-not-found.instruction=We could not find the page you are looking for. Please make sure the URL you entered is correct. +#events.tooltip=Displays saved events for the realm. Events are related to user accounts, for example a user login. To enable persisted events go to config. +#select-event-types.placeholder=Select event types... +#events-config.tooltip=Displays configuration options to enable persistence of user and admin events. +select-an-action.placeholder=Aktion w\u00E4hlen... +#event-listeners.tooltip=Configure what listeners receive events for the realm. +#login.save-events.tooltip=If enabled login events are saved to the database which makes events available to the admin and account management consoles. +#clear-events.tooltip=Deletes all events in the database. +#events.expiration.tooltip=Sets the expiration for events. Expired events are periodically deleted from the database. +#admin-events-settings=Admin Events Settings +#save-events=Save Events +#admin.save-events.tooltip=If enabled admin events are saved to the database which makes events available to the admin console. +#saved-types.tooltip=Configure what event types are saved. +#include-representation=Include Representation +#include-representation.tooltip=Include JSON representation for create and update requests. +#clear-admin-events.tooltip=Deletes all admin events in the database. +#server-version=Server Version +#server-profile=Server Profile +#server-disabled=Server Disabled Features +#info=Info +#providers=Providers +#server-time=Server Time +#server-uptime=Server Uptime +#memory=Memory +#total-memory=Total Memory +#free-memory=Free Memory +#used-memory=Used Memory +#system=System +#current-working-directory=Current Working Directory +#java-version=Java Version +#java-vendor=Java Vendor +#java-runtime=Java Runtime +#java-vm=Java VM +#java-vm-version=Java VM Version +#java-home=Java Home +#user-name=User Name +#user-timezone=User Timezone +#user-locale=User Locale +#system-encoding=System Encoding +#operating-system=Operating System +#os-architecture=OS Architecture +#spi=SPI +granted-client-scopes=Gew\u00E4hrte Client-Scopes +additional-grants=Zus\u00E4tzliche Befugnisse +consent-created-date=Erstellt +consent-last-updated-date=Zuletzt aktualisiert +revoke=Widerrufen +new-password=Neues Passwort +password-confirmation=Passwort best\u00E4tigen +reset-password=Passwort zur\u00FCcksetzen +credentials.temporary.tooltip=Wenn eingeschaltet, ist der Benutzer beim n\u00E4chsten Login aufgefordert, dass Passwort zu \u00E4ndern. +#remove-totp=Remove OTP +#credentials.remove-totp.tooltip=Remove one time password generator for user. +reset-actions=Zur\u00FCcksetz-Aktionen +credentials.reset-actions.tooltip=Liste von Aktionen, die der Benutzer ausf\u00FChren soll, wenn er eine E-Mail zum Zur\u00FCcksetzen des Passworts erh\u00E4lt. 'Verify email' sendet bem Benutzer eine E-Mail um seine E-Mail-Adresse zu verifizieren. 'Update profile' verlangt vom Benutzer, dass er seine Profil-Informationen eingibt. 'Update password' verlangt vom Benutzer, dass er ein neues Passwort definiert. 'Configure OTP' verlangt vom Benutzer, dass er einen mobilen Passwort-Generator aufsetzt. +reset-actions-email=E-Mail zum Zur\u00FCcksetzen des Passworts senden +send-email=E-Mail senden +credentials.reset-actions-email.tooltip=Sendet eine E-Mail an den Benutzer mit einem eingebetteten Link. Wenn der Benutzer auf den Link klickt, kann er die Zur\u00FCcksetz-Aktion auszuf\u00FChren. Vorher muss sich der Benutzer nicht einloggen. Z.B. kann die Aktion 'update password' ausgew\u00E4hlt werden und dieser Button geklickt werden. Der Benutzer kann dann sein Passwort \u00E4ndern, ohne sich einzuloggen. +add-user=Benutzer hinzuf\u00FCgen +created-at=Erstellt am +user-enabled=Benutzer aktiv +user-enabled.tooltip=Ein deaktivierter Benutzer kann sich nicht einloggen +user-temporarily-locked=Benutzer tempor\u00E4r gesperrt +user-temporarily-locked.tooltip=Der Benutzer wurde vor\u00FCbergehend wegen zuvieler ung\u00FCltiger Loginversuche gesperrt. +unlock-user=Benutzer entsperren +#federation-link=Federation Link +email-verified=E-Mail verifiziert +email-verified.tooltip=Wurde die E-Mail des Benutzers verifiziert? +required-user-actions=Verlangte Benutzeraktionen +required-user-actions.tooltip=Verlangt eine Aktion wenn sich der Benutzer einloggt. 'E-Mail Verifizieren' sendet eine E-Mail an den Benutzer, um die G\u00FCltigkeit seiner E-Mailadresse zu pr\u00FCfen. 'Profil aktualisieren' verlangt, dass Benutzer ihre pers\u00F6nlichen Angaben eingeben. 'Passwort aktualisieren' zwingt Benutzer ein neues Passwort zu setzen. 'OTP konfigurieren' zwingt Benutzer einen mobilen Passwort-Generator einzurichten (i.e. Google Authenticator) +locale=Locale +#select-one.placeholder=Select one... +#impersonate=Impersonate +#impersonate-user=Impersonate user +#impersonate-user.tooltip=Login as this user. If user is in same realm as you, your current login session will be logged out before you are logged in as this user. +#identity-provider-alias=Identity Provider Alias +#provider-user-id=Provider User ID +#provider-username=Provider Username +#no-identity-provider-links-available=No identity provider links available +group-membership=Gruppen-Mitglied +leave=Verlassen +#group-membership.tooltip=Groups user is a member of. Select a listed group and click the Leave button to leave the group. +#membership.available-groups.tooltip=Groups a user can join. Select a group and click the join button. +#table-of-realm-users=Table of Realm Users +view-all-users=Zeige alle Benutzer +view-all-groups=Zeige alle Rollen +unlock-users=Benutzer entsperren +no-users-available=Keine Benutzer verf\u00FCgbar +#users.instruction=Please enter a search, or click on view all users +consents=Einwilligungen +started=Gestartet +logout-all-sessions=Alle Sessions ausloggen +logout=Ausloggen +new-name=Neuer Name +ok=Ok +attributes=Attribute +role-mappings=Rollenzuweisungen +members=Mitglieder +details=Details +#identity-provider-links=Identity Provider Links +#register-required-action=Register required action +gender=Geschlecht +address=Adresse +phone=Telefon +#profile-url=Profile URL +#picture-url=Picture URL +#website=Website +#import-keys-and-cert=Import keys and cert +#import-keys-and-cert.tooltip=Upload the client's key pair and cert. +#upload-keys=Upload Keys +#download-keys-and-cert=Download keys and cert +#no-value-assigned.placeholder=No value assigned +remove=Entfernen +#no-group-members=No group members +#no-role-members=No role members +temporary=Tempor\u00E4r +join=Beitreten +#event-type=Event Type +#events-config=Events Config +#event-listeners=Event Listeners +#login-events-settings=Login Events Settings +#clear-events=Clear events +#saved-types=Saved Types +#clear-admin-events=Clear admin events +#clear-changes=Clear changes +#error=Error +# Authz +# Authz Common +#authz-authorization=Authorization +#authz-owner=Owner +#authz-uri=URI +#authz-uris=URIS +#authz-scopes=Scopes +#authz-resource=Resource +#authz-resource-type=Resource Type +#authz-resources=Resources +#authz-scope=Scope +#authz-authz-scopes=Authorization Scopes +#authz-policies=Policies +#authz-policy=Policy +#authz-permissions=Permissions +#authz-users=Users in Role +#authz-evaluate=Evaluate +#authz-icon-uri=Icon URI +#authz-icon-uri.tooltip=An URI pointing to an icon. +#authz-select-scope=Select a scope +#authz-select-resource=Select a resource +#authz-associated-policies=Associated Policies +#authz-any-resource=Any resource +#authz-any-scope=Any scope +#authz-any-role=Any role +#authz-policy-evaluation=Policy Evaluation +#authz-select-client=Select a client +#authz-select-user=Select a user +#authz-entitlements=Entitlements +#authz-no-resources=No resources +#authz-result=Result +#authz-authorization-services-enabled=Authorization Enabled +#authz-authorization-services-enabled.tooltip=Enable/Disable fine-grained authorization support for a client +#authz-required=Required +#authz-show-details=Show Details +#authz-hide-details=Hide Details +#authz-associated-permissions=Associated Permissions +#authz-no-permission-associated=No permissions associated +# Authz Settings +#authz-import-config.tooltip=Import a JSON file containing authorization settings for this resource server. +#authz-policy-enforcement-mode=Policy Enforcement Mode +#authz-policy-enforcement-mode.tooltip=The policy enforcement mode dictates how policies are enforced when evaluating authorization requests. 'Enforcing' means requests are denied by default even when there is no policy associated with a given resource. 'Permissive' means requests are allowed even when there is no policy associated with a given resource. 'Disabled' completely disables the evaluation of policies and allows access to any resource. +#authz-policy-enforcement-mode-enforcing=Enforcing +#authz-policy-enforcement-mode-permissive=Permissive +#authz-policy-enforcement-mode-disabled=Disabled +#authz-remote-resource-management=Remote Resource Management +#authz-remote-resource-management.tooltip=Should resources be managed remotely by the resource server? If false, resources can be managed only from this admin console. +#authz-export-settings=Export Settings +#authz-export-settings.tooltip=Export and download all authorization settings for this resource server. +# Authz Resource List +#authz-no-resources-available=No resources available. +#authz-no-scopes-assigned=No scopes assigned. +#authz-no-type-defined=No type defined. +#authz-no-uri-defined=No URI defined. +#authz-no-permission-assigned=No permission assigned. +#authz-no-policy-assigned=No policy assigned. +#authz-create-permission=Create Permission +# Authz Resource Detail +#authz-add-resource=Add Resource +#authz-resource-name.tooltip=A unique name for this resource. The name can be used to uniquely identify a resource, useful when querying for a specific resource. +#authz-resource-owner.tooltip=The owner of this resource. +#authz-resource-type.tooltip=The type of this resource. It can be used to group different resource instances with the same type. +#authz-resource-uri.tooltip=Set of URIs which are protected by resource. +#authz-resource-scopes.tooltip=The scopes associated with this resource. +#authz-resource-attributes=Resource Attributes +#authz-resource-attributes.tooltip=The attributes associated wth the resource. +#authz-resource-user-managed-access-enabled=User-Managed Access Enabled +#authz-resource-user-managed-access-enabled.tooltip=If enabled this access to this resource can be managed by the resource owner. + +# Authz Scope List +#authz-add-scope=Add Scope +#authz-no-scopes-available=No scopes available. +# Authz Scope Detail +#authz-scope-name.tooltip=A unique name for this scope. The name can be used to uniquely identify a scope, useful when querying for a specific scope. +# Authz Policy List +#authz-all-types=All types +#authz-create-policy=Create Policy +#authz-no-policies-available=No policies available. +# Authz Policy Detail +#authz-policy-name.tooltip=The name of this policy. +#authz-policy-description.tooltip=A description for this policy. +#authz-policy-logic=Logic +#authz-policy-logic-positive=Positive +#authz-policy-logic-negative=Negative +#authz-policy-logic.tooltip=The logic dictates how the policy decision should be made. If 'Positive', the resulting effect (permit or deny) obtained during the evaluation of this policy will be used to perform a decision. If 'Negative', the resulting effect will be negated, in other words, a permit becomes a deny and vice-versa. +#authz-policy-apply-policy=Apply Policy +#authz-policy-apply-policy.tooltip=Specifies all the policies that must be applied to the scopes defined by this policy or permission. +#authz-policy-decision-strategy=Decision Strategy +#authz-policy-decision-strategy.tooltip=The decision strategy dictates how the policies associated with a given permission are evaluated and how a final decision is obtained. 'Affirmative' means that at least one policy must evaluate to a positive decision in order for the final decision to be also positive. 'Unanimous' means that all policies must evaluate to a positive decision in order for the final decision to be also positive. 'Consensus' means that the number of positive decisions must be greater than the number of negative decisions. If the number of positive and negative is the same, the final decision will be negative. +#authz-policy-decision-strategy-affirmative=Affirmative +#authz-policy-decision-strategy-unanimous=Unanimous +#authz-policy-decision-strategy-consensus=Consensus +#authz-select-a-policy=Select existing policy +#authz-no-policies-assigned=No policies assigned. +# Authz Role Policy Detail +#authz-add-role-policy=Add Role Policy +#authz-no-roles-assigned=No roles assigned. +#authz-policy-role-realm-roles.tooltip=Specifies the *realm* roles allowed by this policy. +#authz-policy-role-clients.tooltip=Selects a client in order to filter the client roles that can be applied to this policy. +#authz-policy-role-client-roles.tooltip=Specifies the client roles allowed by this policy. +# Authz User Policy Detail +#authz-add-user-policy=Add User Policy +#authz-no-users-assigned=No users assigned. +#authz-policy-user-users.tooltip=Specifies which user(s) are allowed by this policy. +# Authz Client Policy Detail +#authz-add-client-policy=Add Client Policy +#authz-no-clients-assigned=No clients assigned. +#authz-policy-client-clients.tooltip=Specifies which client(s) are allowed by this policy. +# Authz Time Policy Detail +#authz-add-time-policy=Add Time Policy +#authz-policy-time-not-before.tooltip=Defines the time before which the policy MUST NOT be granted. Only granted if current date/time is after or equal to this value. +#authz-policy-time-not-on-after=Not On or After +#authz-policy-time-not-on-after.tooltip=Defines the time after which the policy MUST NOT be granted. Only granted if current date/time is before or equal to this value. +#authz-policy-time-day-month=Day of Month +#authz-policy-time-day-month.tooltip=Defines the day of month which the policy MUST be granted. You can also provide a range by filling the second field. In this case, permission is granted only if current day of month is between or equal to the two values you provided. +#authz-policy-time-month=Month +#authz-policy-time-month.tooltip=Defines the month which the policy MUST be granted. You can also provide a range by filling the second field. In this case, permission is granted only if current month is between or equal to the two values you provided. +#authz-policy-time-year=Year +#authz-policy-time-year.tooltip=Defines the year which the policy MUST be granted. You can also provide a range by filling the second field. In this case, permission is granted only if current year is between or equal to the two values you provided. +#authz-policy-time-hour=Hour +#authz-policy-time-hour.tooltip=Defines the hour which the policy MUST be granted. You can also provide a range by filling the second field. In this case, permission is granted only if current hour is between or equal to the two values you provided. +#authz-policy-time-minute=Minute +#authz-policy-time-minute.tooltip=Defines the minute which the policy MUST be granted. You can also provide a range by filling the second field. In this case, permission is granted only if current minute is between or equal to the two values you provided. +# Authz Drools Policy Detail +#authz-add-drools-policy=Add Rules Policy +#authz-policy-drools-maven-artifact-resolve=Resolve +#authz-policy-drools-maven-artifact=Policy Maven Artifact +#authz-policy-drools-maven-artifact.tooltip=A Maven GAV pointing to an artifact from where the rules would be loaded from. Once you have provided the GAV, you can click *Resolve* to load both *Module* and *Session* fields. +#authz-policy-drools-module=Module +#authz-policy-drools-module.tooltip=The module used by this policy. You must provide a module in order to select a specific session from where rules will be loaded from. +#authz-policy-drools-session=Session +#authz-policy-drools-session.tooltip=The session used by this policy. The session provides all the rules to evaluate when processing the policy. +#authz-policy-drools-update-period=Update Period +#authz-policy-drools-update-period.tooltip=Specifies an interval for scanning for artifact updates. +# Authz JS Policy Detail +#authz-add-js-policy=Add JavaScript Policy +#authz-policy-js-code=Code +#authz-policy-js-code.tooltip=The JavaScript code providing the conditions for this policy. +# Authz Aggregated Policy Detail +#authz-aggregated=Aggregated +#authz-add-aggregated-policy=Add Aggregated Policy +# Authz Group Policy Detail +#authz-add-group-policy=Add Group Policy +#authz-no-groups-assigned=No groups assigned. +#authz-policy-group-claim=Groups Claim +#authz-policy-group-claim.tooltip=If defined, the policy will fetch user's groups from the given claim within an access token or ID token representing the identity asking permissions. If not defined, user's groups are obtained from your realm configuration. +#authz-policy-group-groups.tooltip=Specifies the groups allowed by this policy. + +# Authz Permission List +#authz-no-permissions-available=No permissions available. + +# Authz Permission Detail +#authz-permission-name.tooltip=The name of this permission. +#authz-permission-description.tooltip=A description for this permission. + +# Authz Resource Permission Detail +#authz-add-resource-permission=Add Resource Permission +#authz-permission-resource-apply-to-resource-type=Apply to Resource Type +#authz-permission-resource-apply-to-resource-type.tooltip=Specifies if this permission would be applied to all resources with a given type. In this case, this permission will be evaluated for all instances of a given resource type. +#authz-permission-resource-resource.tooltip=Specifies that this permission must be applied to a specific resource instance. +#authz-permission-resource-type.tooltip=Specifies that this permission must be applied to all resources instances of a given type. + +# Authz Scope Permission Detail +#authz-add-scope-permission=Add Scope Permission +#authz-permission-scope-resource.tooltip=Restrict the scopes to those associated with the selected resource. If not selected all scopes would be available. +#authz-permission-scope-scope.tooltip=Specifies that this permission must be applied to one or more scopes. + +# Authz Evaluation +#authz-evaluation-identity-information=Identity Information +#authz-evaluation-identity-information.tooltip=The available options to configure the identity information that will be used when evaluating policies. +#authz-evaluation-client.tooltip=Select the client making this authorization request. If not provided, authorization requests would be done based on the client you are in. +#authz-evaluation-user.tooltip=Select a user whose identity is going to be used to query permissions from the server. +#authz-evaluation-role.tooltip=Select the roles you want to associate with the selected user. +#authz-evaluation-new=New Evaluation +#authz-evaluation-re-evaluate=Re-Evaluate +#authz-evaluation-previous=Previous Evaluation +#authz-evaluation-contextual-info=Contextual Information +#authz-evaluation-contextual-info.tooltip=The available options to configure any contextual information that will be used when evaluating policies. +#authz-evaluation-contextual-attributes=Contextual Attributes +#authz-evaluation-contextual-attributes.tooltip=Any attribute provided by a running environment or execution context. +#authz-evaluation-permissions.tooltip=The available options to configure the permissions to which policies will be applied. +#authz-evaluation-evaluate=Evaluate +#authz-evaluation-any-resource-with-scopes=Any resource with scope(s) +#authz-evaluation-no-result=Could not obtain any result for the given authorization request. Check if the provided resource(s) or scope(s) are associated with any policy. +#authz-evaluation-no-policies-resource=No policies were found for this resource. +#authz-evaluation-result.tooltip=The overall result for this permission request. +#authz-evaluation-scopes.tooltip=The list of allowed scopes. +#authz-evaluation-policies.tooltip=Details about which policies were evaluated and their decisions. +#authz-evaluation-authorization-data=Response +#authz-evaluation-authorization-data.tooltip=Represents a token carrying authorization data as a result of the processing of an authorization request. This representation is basically what Keycloak issues to clients asking for permissions. Check the 'authorization' claim for the permissions that were granted based on the current authorization request. +#authz-show-authorization-data=Show Authorization Data + +keys=Keys +status=Status +#keystore=Keystore +#keystores=Keystores +#add-keystore=Add Keystore +#add-keystore.placeholder=Add keystore... +#view=View +active=Aktiv +#passive=Passive +#disabled=Disabled +#algorithms=Algorithms +#providerHelpText=Provider description + +Sunday=Sonntag +Monday=Montag +Tuesday=Dienstag +Wednesday=Mittwoch +Thursday=Donnerstag +Friday=Freitag +Saturday=Samstag + +#user-storage-cache-policy=Cache Settings +#userStorage.cachePolicy=Cache Policy +#userStorage.cachePolicy.option.DEFAULT=DEFAULT +#userStorage.cachePolicy.option.EVICT_WEEKLY=EVICT_WEEKLY +#userStorage.cachePolicy.option.EVICT_DAILY=EVICT_DAILY +#userStorage.cachePolicy.option.MAX_LIFESPAN=MAX_LIFESPAN +#userStorage.cachePolicy.option.NO_CACHE=NO_CACHE +#userStorage.cachePolicy.tooltip=Cache Policy for this storage provider. 'DEFAULT' is whatever the default settings are for the global cache. 'EVICT_DAILY' is a time of day every day that the cache will be invalidated. 'EVICT_WEEKLY' is a day of the week and time the cache will be invalidated. 'MAX-LIFESPAN' is the time in milliseconds that will be the lifespan of a cache entry. +#userStorage.cachePolicy.evictionDay=Eviction Day +#userStorage.cachePolicy.evictionDay.tooltip=Day of the week the entry will become invalid on +#userStorage.cachePolicy.evictionHour=Eviction Hour +#userStorage.cachePolicy.evictionHour.tooltip=Hour of day the entry will become invalid on. +#userStorage.cachePolicy.evictionMinute=Eviction Minute +#userStorage.cachePolicy.evictionMinute.tooltip=Minute of day the entry will become invalid on. +#userStorage.cachePolicy.maxLifespan=Max Lifespan +#userStorage.cachePolicy.maxLifespan.tooltip=Max lifespan of cache entry in milliseconds. +#user-origin-link=Storage Origin +#user-origin.tooltip=UserStorageProvider the user was loaded from +#user-link.tooltip=UserStorageProvider this locally stored user was imported from. +#client-origin-link=Storage Origin +#client-origin.tooltip=Provider the client was loaded from + +#client-storage-cache-policy=Cache Settings +#clientStorage.cachePolicy=Cache Policy +#clientStorage.cachePolicy.option.DEFAULT=DEFAULT +#clientStorage.cachePolicy.option.EVICT_WEEKLY=EVICT_WEEKLY +#clientStorage.cachePolicy.option.EVICT_DAILY=EVICT_DAILY +#clientStorage.cachePolicy.option.MAX_LIFESPAN=MAX_LIFESPAN +#clientStorage.cachePolicy.option.NO_CACHE=NO_CACHE +#clientStorage.cachePolicy.tooltip=Cache Policy for this storage provider. 'DEFAULT' is whatever the default settings are for the global cache. 'EVICT_DAILY' is a time of day every day that the cache will be invalidated. 'EVICT_WEEKLY' is a day of the week and time the cache will be invalidated. 'MAX-LIFESPAN' is the time in milliseconds that will be the lifespan of a cache entry. +#clientStorage.cachePolicy.evictionDay=Eviction Day +#clientStorage.cachePolicy.evictionDay.tooltip=Day of the week the entry will become invalid on +#clientStorage.cachePolicy.evictionHour=Eviction Hour +#clientStorage.cachePolicy.evictionHour.tooltip=Hour of day the entry will become invalid on. +#clientStorage.cachePolicy.evictionMinute=Eviction Minute +#clientStorage.cachePolicy.evictionMinute.tooltip=Minute of day the entry will become invalid on. +#clientStorage.cachePolicy.maxLifespan=Max Lifespan +#clientStorage.cachePolicy.maxLifespan.tooltip=Max lifespan of cache entry in milliseconds. + +#client-storage-list-no-entries=Keycloak can federate external client databases. Out of the box we have support for Openshift OAuth clients and service accounts. To get started select a provider from the dropdown below: + + +disable=Deaktivieren +disableable-credential-types=Deaktivierbare Typen +credentials.disableable.tooltip=Liste von Zugangstypen, die deaktiviert werden k\u00F6nnen. +disable-credential-types=Zugangstypen deaktivieren +credentials.disable.tooltip=Dr\u00FCcken Sie den Button, um die ausgew\u00E4hlten Zugangstypen zu sperren. +credential-types=Zugangstypen +manage-user-password=Zugang verwalten +disable-credentials=Zugang deaktivieren +credential-reset-actions=Zugang zur\u00FCcksetzen +credential-reset-actions-timeout=L\u00E4uft ab in +credential-reset-actions-timeout.tooltip=Maximale Zeit in der die Aktion zugelassen ist. +#ldap-mappers=LDAP Mappers +#create-ldap-mapper=Create LDAP mapper +#map-role-mgmt-scope-description=Policies that decide if an admin can map this role to a user or group +#manage-authz-users-scope-description=Policies that decide if an admin can manage all users in the realm +#view-authz-users-scope-description=Policies that decide if an admin can view all users in realm +permissions-enabled-role=Berechtigungen aktiv +permissions-enabled-role.tooltip=Legt fest, ob feingranulare Berechtigungen f\u00FCr diese Rolle aktiv sein sollen. Wird diese Option deaktiviert, werden alle aktuell aufgesetzten Berechtigungen gel\u00F6scht. +manage-permissions-role.tooltip=Feingranulare Berechtigungen f\u00FCr Rollen. Zum Beispiel k\u00F6nnen Berechtigungen eingerichtet werden, die festlegen, wer berechtigt, ist eine Rolle zuzuweisen. +lookup=Suche +manage-permissions-users.tooltip=Feingranulare Berechtigungen f\u00FCr alle Benutzer in diesem Realm. Es k\u00F6nnen verschiedene Einstellungen definiert werden, wer in diesem Realm berechtigt ist, Benutzer zu verwalten. +permissions-enabled-users=Berechtigungen aktiv +permissions-enabled-users.tooltip=Legt fest, ob feingranulare Berechtigungen f\u00FCr Benutzer aktiv sein sollen. Wird diese Option deaktiviert, werden alle aktuell aufgesetzten Berechtigungen gel\u00F6scht. +#manage-permissions-client.tooltip=Fine grain permissions for admins that want to manage this client or apply roles defined by this client. +#manage-permissions-group.tooltip=Fine grain permissions for admins that want to manage this group or the members of this group. +#manage-authz-group-scope-description=Policies that decide if an admin can manage this group +#view-authz-group-scope-description=Policies that decide if an admin can view this group +#view-members-authz-group-scope-description=Policies that decide if an admin can view the members of this group +#token-exchange-authz-client-scope-description=Policies that decide which clients are allowed exchange tokens for a token that is targeted to this client. +#token-exchange-authz-idp-scope-description=Policies that decide which clients are allowed exchange tokens for an external token minted by this identity provider. +#manage-authz-client-scope-description=Policies that decide if an admin can manage this client +#configure-authz-client-scope-description=Reduced management permissions for admin. Cannot set scope, template, or protocol mappers. +#view-authz-client-scope-description=Policies that decide if an admin can view this client +#map-roles-authz-client-scope-description=Policies that decide if an admin can map roles defined by this client +#map-roles-client-scope-authz-client-scope-description=Policies that decide if an admin can apply roles defined by this client to the client scope of another client +#map-roles-composite-authz-client-scope-description=Policies that decide if an admin can apply roles defined by this client as a composite to another role +#map-role-authz-role-scope-description=Policies that decide if an admin can map this role to a user or group +#map-role-client-scope-authz-role-scope-description=Policies that decide if an admin can apply this role to the client scope of a client +#map-role-composite-authz-role-scope-description=Policies that decide if an admin can apply this role as a composite to another role +#manage-group-membership-authz-users-scope-description=Policies that decide if an admin can manage group membership for all users in the realm. This is used in conjunction with specific group policy +#impersonate-authz-users-scope-description=Policies that decide if admin can impersonate other users +#map-roles-authz-users-scope-description=Policies that decide if admin can map roles for all users +#user-impersonated-authz-users-scope-description=Policies that decide which users can be impersonated. These policies are applied to the user being impersonated. +#manage-membership-authz-group-scope-description=Policies that decide if an admin can add or remove users from this group +#manage-members-authz-group-scope-description=Policies that decide if an admin can manage the members of this group + +# KEYCLOAK-6771 Certificate Bound Token +# https://tools.ietf.org/html/draft-ietf-oauth-mtls-08#section-3 +#advanced-client-settings=Advanced Settings +#advanced-client-settings.tooltip=Expand this section to configure advanced settings of this client +#tls-client-certificate-bound-access-tokens=OAuth 2.0 Mutual TLS Certificate Bound Access Tokens Enabled +#tls-client-certificate-bound-access-tokens.tooltip=This enables support for OAuth 2.0 Mutual TLS Certificate Bound Access Tokens, which means that keycloak bind an access token and a refresh token with a X.509 certificate of a token requesting client exchanged in mutual TLS between keycloak's Token Endpoint and this client. These tokens can be treated as Holder-of-Key tokens instead of bearer tokens. +#subjectdn=Subject DN +#subjectdn-tooltip=A regular expression for validating Subject DN in the Client Certificate. Use "(.*?)(?:$)" to match all kind of expressions. + +notifications.info.header=Information! +notifications.success.header=Erfolg! +notifications.error.header=Fehler! +notifications.warn.header=Warnung! + +dialogs.delete.title={{type}} l\u00F6schen +dialogs.delete.message=Sind Sie sicher, dass Sie {{type}} {{name}} l\u00F6schen m\u00F6chten? +dialogs.delete.confirm=L\u00F6schen +dialogs.cancel=Abbrechen +dialogs.ok=OK diff --git a/keycloak-themes/base/admin/messages/admin-messages_en.properties b/keycloak-themes/base/admin/messages/admin-messages_en.properties new file mode 100644 index 0000000..a2b7086 --- /dev/null +++ b/keycloak-themes/base/admin/messages/admin-messages_en.properties @@ -0,0 +1,2024 @@ +consoleTitle=Keycloak Admin Console + +# Common messages +enabled=Enabled +hidden=Hidden +link-only-column=Link only +name=Name +displayName=Display name +displayNameHtml=HTML Display name +save=Save +cancel=Cancel +next=Next +onText=ON +offText=OFF +client=Client +clients=Clients +clear=Clear +selectOne=Select One... + +true=True +false=False + +endpoints=Endpoints + +# Angular date filter format strings: https://docs.angularjs.org/api/ng/filter/date +dateFormat=shortDate +timeFormat=mediumTime + +# Realm settings +realm-detail.enabled.tooltip=Users and clients can only access a realm if it's enabled +realm-detail.protocol-endpoints.tooltip=Shows the configuration of the protocol endpoints +realm-detail.protocol-endpoints.oidc=OpenID Endpoint Configuration +realm-detail.protocol-endpoints.saml=SAML 2.0 Identity Provider Metadata +realm-detail.userManagedAccess.tooltip=If enabled, users are allowed to manage their resources and permissions using the Account Management Console. +userProfileEnabled=User Profile Enabled +userProfileEnabled.tooltip=If enabled, allows managing user profiles. +userManagedAccess=User-Managed Access +registrationAllowed=User registration +registrationAllowed.tooltip=Enable/disable the registration page. A link for registration will show on login page too. +registrationEmailAsUsername=Email as username +registrationEmailAsUsername.tooltip=If enabled then username field is hidden from registration form and email is used as username for new user. +editUsernameAllowed=Edit username +editUsernameAllowed.tooltip=If enabled, the username field is editable, readonly otherwise. +resetPasswordAllowed=Forgot password +resetPasswordAllowed.tooltip=Show a link on login page for user to click on when they have forgotten their credentials. +rememberMe=Remember Me +rememberMe.tooltip=Show checkbox on login page to allow user to remain logged in between browser restarts until session expires. +loginWithEmailAllowed=Login with email +loginWithEmailAllowed.tooltip=Allow users to log in with their email address. +duplicateEmailsAllowed=Duplicate emails +duplicateEmailsAllowed.tooltip=Allow multiple users to have the same email address. Changing this setting will also clear the user's cache. It is recommended to manually update email constraints of existing users in the database after switching off support for duplicate email addresses. +verifyEmail=Verify email +verifyEmail.tooltip=Require users to verify their email address after initial login or after address changes are submitted. +sslRequired=Require SSL +sslRequired.option.all=all requests +sslRequired.option.external=external requests +sslRequired.option.none=none +sslRequired.tooltip=Is HTTPS required? 'None' means HTTPS is not required for any client IP address. 'External requests' means localhost and private IP addresses can access without HTTPS. 'All requests' means HTTPS is required for all IP addresses. +publicKeys=Public keys +publicKey=Public key +privateKey=Private key +gen-new-keys=Generate new keys +certificate=Certificate +host=Host +smtp-host=SMTP Host +port=Port +smtp-port=SMTP Port (defaults to 25) +smtp-password.tooltip=SMTP password. This field is able to obtain its value from vault, use ${vault.ID} format. +from=From +fromDisplayName=From Display Name +fromDisplayName.tooltip=A user-friendly name for the 'From' address (optional). +replyTo=Reply To +replyToDisplayName=Reply To Display Name +replyToDisplayName.tooltip=A user-friendly name for the 'Reply-To' address (optional). +envelopeFrom=Envelope From +envelopeFrom.tooltip=An email address used for bounces (optional). +sender-email-addr=Sender Email Address +sender-email-addr-display=Display Name for Sender Email Address +reply-to-email-addr=Reply To Email Address +reply-to-email-addr-display=Display Name for Reply To Email Address +sender-envelope-email-addr=Sender Envelope Email Address +enable-ssl=Enable SSL +enable-start-tls=Enable StartTLS +enable-auth=Enable Authentication +username=Username +login-username=Login Username +password=Password +login-password=Login Password +login-theme=Login Theme +login-theme.tooltip=Select theme for login, OTP, grant, registration, and forgot password pages. +account-theme=Account Theme +account-theme.tooltip=Select theme for user account management pages. +admin-console-theme=Admin Console Theme +select-theme-admin-console=Select theme for admin console. +email-theme=Email Theme +select-theme-email=Select theme for emails that are sent by the server. +i18n-enabled=Internationalization Enabled +supported-locales=Supported Locales +supported-locales.placeholder=Type a locale and enter +default-locale=Default Locale +localization-upload-file=Upload localization JSON file +missing-locale=Missing locale. +missing-file=Missing file. Please select a file to upload. +localization-file.upload.success=The localization data has been loaded from file. +localization-file.upload.error=The file can not be uploaded. Please verify the file. +localization-show=Show realm specific localizations +no-localizations-configured=No realm specific localizations configured +add-localization-text=Add localization text +localization-text.create.success=The localization text has been created. +localization-text.update.success=The localization text has been updated. +localization-text.remove.success=The localization text has been deleted. +realm-cache-clear=Realm Cache +realm-cache-clear.tooltip=Clears all entries from the realm cache (this will clear entries for all realms) +user-cache-clear=User Cache +user-cache-clear.tooltip=Clears all entries from the user cache (this will clear entries for all realms) +keys-cache-clear=Keys Cache +keys-cache-clear.tooltip=Clears all entries from the cache of external public keys. These are keys of external clients or identity providers. (this will clear entries for all realms) +default-signature-algorithm=Default Signature Algorithm +default-signature-algorithm.tooltip=Default algorithm used to sign tokens for the realm +revoke-refresh-token=Revoke Refresh Token +revoke-refresh-token.tooltip=If enabled a refresh token can only be used up to 'Refresh Token Max Reuse' and is revoked when a different token is used. Otherwise refresh tokens are not revoked when used and can be used multiple times. +refresh-token-max-reuse=Refresh Token Max Reuse +refresh-token-max-reuse.tooltip=Maximum number of times a refresh token can be reused. When a different token is used, revocation is immediate. +sso-session-idle=SSO Session Idle +seconds=Seconds +minutes=Minutes +hours=Hours +days=Days +sso-session-max=SSO Session Max +sso-session-idle.tooltip=Time a session is allowed to be idle before it expires. Tokens and browser sessions are invalidated when a session is expired. +sso-session-max.tooltip=Max time before a session is expired. Tokens and browser sessions are invalidated when a session is expired. +sso-session-idle-remember-me=SSO Session Idle Remember Me +sso-session-idle-remember-me.tooltip=Time a remember me session is allowed to be idle before it expires. Tokens and browser sessions are invalidated when a session is expired. If not set it uses the standard SSO Session Idle value. +sso-session-max-remember-me=SSO Session Max Remember Me +sso-session-max-remember-me.tooltip=Max time before a session is expired when the user has set the remember me option. Tokens and browser sessions are invalidated when a session is expired. If not set, it uses the standard SSO Session Max value. +offline-session-idle=Offline Session Idle +offline-session-idle.tooltip=Time an offline session is allowed to be idle before it expires. You need to use offline token to refresh at least once within this period; otherwise offline session will expire. +realm-detail.hostname=Hostname +realm-detail.hostname.tooltip=Set the hostname for the realm. Use in combination with the fixed hostname provider to override the server hostname for a specific realm. +realm-detail.frontendUrl=Frontend URL +realm-detail.frontendUrl.tooltip=Set the frontend URL for the realm. Use in combination with the default hostname provider to override the base URL for frontend requests for a specific realm. + +## KEYCLOAK-7688 Offline Session Max for Offline Token +offline-session-max-limited=Offline Session Max Limited +offline-session-max-limited.tooltip=Enable Offline Session Max. +offline-session-max=Offline Session Max +offline-session-max.tooltip=Max time before an offline session is expired regardless of activity. +client-session-idle=Client Session Idle +client-session-idle.tooltip=Time a client session is allowed to be idle before it expires. Tokens are invalidated when a client session is expired. If not set it uses the standard SSO Session Idle value. +client-session-max=Client Session Max +client-session-max.tooltip=Max time before a client session is expired. Tokens are invalidated when a client session is expired. If not set, it uses the standard SSO Session Max value. +client-offline-session-idle=Client Offline Session Idle +client-offline-session-idle.tooltip=Time a client offline session is allowed to be idle before it expires. Offline tokens are invalidated when a client offline session is expired. If not set it uses the Offline Session Idle value. +client-offline-session-max=Client Offline Session Max +client-offline-session-max.tooltip=Max time before a client offline session is expired. Offline tokens are invalidated when a client offline session is expired. If not set, it uses the Offline Session Max value. +access-token-lifespan=Access Token Lifespan +access-token-lifespan.tooltip=Max time before an access token is expired. This value is recommended to be short relative to the SSO timeout. +access-token-lifespan-for-implicit-flow=Access Token Lifespan For Implicit Flow +access-token-lifespan-for-implicit-flow.tooltip=Max time before an access token issued during OpenID Connect Implicit Flow is expired. This value is recommended to be shorter than SSO timeout. There is no possibility to refresh token during implicit flow, that's why there is a separate timeout different to 'Access Token Lifespan'. +action-token-generated-by-admin-lifespan=Default Admin-Initiated Action Lifespan +action-token-generated-by-admin-lifespan.tooltip=Maximum time before an action permit sent to a user by administrator is expired. This value is recommended to be long to allow administrators send e-mails for users that are currently offline. The default timeout can be overridden immediately before issuing the token. +action-token-generated-by-user-lifespan=User-Initiated Action Lifespan +action-token-generated-by-user-lifespan.tooltip=Maximum time before an action permit sent by a user (such as a forgot password e-mail) is expired. This value is recommended to be short because it is expected that the user would react to self-created action quickly. +saml-assertion-lifespan=Assertion Lifespan +saml-assertion-lifespan.tooltip=Lifespan set in the SAML assertion conditions. After that time the assertion will be invalid. The "SessionNotOnOrAfter" attribute is not modified and continue using the "SSO Session Max" time defined at realm level. + +action-token-generated-by-user.execute-actions=Execute Actions +action-token-generated-by-user.idp-verify-account-via-email=IdP Account E-mail Verification +action-token-generated-by-user.reset-credentials=Forgot Password +action-token-generated-by-user.verify-email=E-mail Verification +action-token-generated-by-user.tooltip=Override default settings of maximum time before an action permit sent by a user (such as a forgot password e-mail) is expired for specific action. This value is recommended to be short because it is expected that the user would react to self-created action quickly. +action-token-generated-by-user.reset=Reset +action-token-generated-by-user.operation=Override User-Initiated Action Lifespan + +client-login-timeout=Client login timeout +client-login-timeout.tooltip=Max time a client has to finish the access token protocol. This should normally be 1 minute. +login-timeout=Login timeout +login-timeout.tooltip=Max time a user has to complete a login. This is recommended to be relatively long, such as 30 minutes or more. +login-action-timeout=Login action timeout +login-action-timeout.tooltip=Max time a user has to complete login related actions like update password or configure totp. This is recommended to be relatively long, such as 5 minutes or more. + +oauth2-device-code-lifespan=OAuth 2.0 Device Code Lifespan +oauth2-device-code-lifespan.tooltip=Max time before the device code and user code are expired. This value needs to be a long enough lifetime to be usable (allowing the user to retrieve their secondary device, navigate to the verification URI, login, etc.), but should be sufficiently short to limit the usability of a code obtained for phishing. +oauth2-device-polling-interval=OAuth 2.0 Device Polling Interval +oauth2-device-polling-interval.tooltip=The minimum amount of time in seconds that the client should wait between polling requests to the token endpoint. + +headers=Headers +brute-force-detection=Brute Force Detection +x-frame-options=X-Frame-Options +x-frame-options-tooltip=Default value prevents pages from being included by non-origin iframes (click label for more information) +content-sec-policy=Content-Security-Policy +content-sec-policy-tooltip=Default value prevents pages from being included by non-origin iframes (click label for more information) +content-sec-policy-report-only=Content-Security-Policy-Report-Only +content-sec-policy-report-only-tooltip=For testing Content Security Policies +content-type-options=X-Content-Type-Options +content-type-options-tooltip=Default value prevents Internet Explorer and Google Chrome from MIME-sniffing a response away from the declared content-type (click label for more information) +robots-tag=X-Robots-Tag +robots-tag-tooltip=Prevent pages from appearing in search engines (click label for more information) +x-xss-protection=X-XSS-Protection +x-xss-protection-tooltip=This header configures the Cross-site scripting (XSS) filter in your browser. Using the default behavior, the browser will prevent rendering of the page when a XSS attack is detected (click label for more information) +strict-transport-security=HTTP Strict Transport Security (HSTS) +strict-transport-security-tooltip=The Strict-Transport-Security HTTP header tells browsers to always use HTTPS. Once a browser sees this header, it will only visit the site over HTTPS for the time specified (1 year) at max-age, including the subdomains. +permanent-lockout=Permanent Lockout +permanent-lockout.tooltip=Lock the user permanently when the user exceeds the maximum login failures. +max-login-failures=Max Login Failures +max-login-failures.tooltip=How many failures before wait is triggered. +wait-increment=Wait Increment +wait-increment.tooltip=When failure threshold has been met, how much time should the user be locked out? +quick-login-check-millis=Quick Login Check Milli Seconds +quick-login-check-millis.tooltip=If a failure happens concurrently too quickly, lock out the user. +min-quick-login-wait=Minimum Quick Login Wait +min-quick-login-wait.tooltip=How long to wait after a quick login failure. +max-wait=Max Wait +max-wait.tooltip=Max time a user will be locked out. +failure-reset-time=Failure Reset Time +failure-reset-time.tooltip=When will failure count be reset? +realm-tab-login=Login +realm-tab-keys=Keys +realm-tab-email=Email +realm-tab-themes=Themes +realm-tab-localization=Localization +realm-tab-cache=Cache +realm-tab-tokens=Tokens +realm-tab-client-registration=Client Registration +realm-tab-security-defenses=Security Defenses +realm-tab-user-profile=User Profile +realm-tab-general=General +add-realm=Add realm + +#Session settings +realm-sessions=Realm Sessions +revocation=Revocation +logout-all=Logout all +active-sessions=Active Sessions +offline-sessions=Offline Sessions +sessions=Sessions +not-before=Not Before +not-before.tooltip=Revoke any tokens issued before this date. +set-to-now=Set to now +push=Push +push.tooltip=For every client that has an admin URL, notify them of the new revocation policy. + +#Protocol Mapper +usermodel.prop.label=Property +usermodel.prop.tooltip=Name of the property method in the UserModel interface. For example, a value of 'email' would reference the UserModel.getEmail() method. +usermodel.attr.label=User Attribute +usermodel.attr.tooltip=Name of stored user attribute which is the name of an attribute within the UserModel.attribute map. +userSession.modelNote.label=User Session Note +userSession.modelNote.tooltip=Name of stored user session note within the UserSessionModel.note map. +multivalued.label=Multivalued +multivalued.tooltip=Indicates if attribute supports multiple values. If true, the list of all values of this attribute will be set as claim. If false, just first value will be set as claim +aggregate.attrs.label=Aggregate attribute values +aggregate.attrs.tooltip=Indicates if attribute values should be aggregated with the group attributes. If using OpenID Connect mapper the multivalued option needs to be enabled too in order to get all the values. Duplicated values are discarded and the order of values is not guaranteed with this option. +selectRole.label=Select Role +selectRole.tooltip=Enter role in the textbox to the left, or click this button to browse and select the role you want. +selectGroup.label=Select Group +selectGroup.tooltip=Enter group in the textbox to the left, or click this button to browse and select the group you want. +tokenClaimName.label=Token Claim Name +tokenClaimName.tooltip=Name of the claim to insert into the token. This can be a fully qualified name like 'address.street'. In this case, a nested json object will be created. To prevent nesting and use dot literally, escape the dot with backslash (\\.). +jsonType.label=Claim JSON Type +jsonType.tooltip=JSON type that should be used to populate the json claim in the token. long, int, boolean, String and JSON are valid values. +includeInIdToken.label=Add to ID token +includeInIdToken.tooltip=Should the claim be added to the ID token? +includeInAccessToken.label=Add to access token +includeInAccessToken.tooltip=Should the claim be added to the access token? +includeInAccessTokenResponse.label=Add to access token response +includeInAccessTokenResponse.tooltip=Should the claim be added to the access token response? Should only be used for informative and non-sensitive data +includeInUserInfo.label=Add to userinfo +includeInUserInfo.tooltip=Should the claim be added to the userinfo? +usermodel.clientRoleMapping.clientId.label=Client ID +usermodel.clientRoleMapping.clientId.tooltip=Client ID for role mappings. Just client roles of this client will be added to the token. If this is unset, client roles of all clients will be added to the token. +usermodel.clientRoleMapping.rolePrefix.label=Client Role prefix +usermodel.clientRoleMapping.rolePrefix.tooltip=A prefix for each client role (optional). +usermodel.clientRoleMapping.tokenClaimName.tooltip=Name of the claim to insert into the token. This can be a fully qualified name like 'address.street'. In this case, a nested json object will be created. To prevent nesting and use dot literally, escape the dot with backslash (\\.). The special token ${client_id} can be used and this will be replaced by the actual client ID. Example usage is 'resource_access.${client_id}.roles'. This is useful especially when you are adding roles from all the clients (Hence 'Client ID' switch is unset) and you want client roles of each client stored separately. +usermodel.realmRoleMapping.rolePrefix.label=Realm Role prefix +usermodel.realmRoleMapping.rolePrefix.tooltip=A prefix for each Realm Role (optional). +sectorIdentifierUri.label=Sector Identifier URI +sectorIdentifierUri.tooltip=Providers that use pairwise sub values and support Dynamic Client Registration SHOULD use the sector_identifier_uri parameter. It provides a way for a group of websites under common administrative control to have consistent pairwise sub values independent of the individual domain names. It also provides a way for Clients to change redirect_uri domains without having to reregister all their users. +pairwiseSubAlgorithmSalt.label=Salt +pairwiseSubAlgorithmSalt.tooltip=Salt used when calculating the pairwise subject identifier. If left blank, a salt will be generated. +addressClaim.street.label=User Attribute Name for Street +addressClaim.street.tooltip=Name of User Attribute, which will be used to map to 'street_address' subclaim inside 'address' token claim. Defaults to 'street' . +addressClaim.locality.label=User Attribute Name for Locality +addressClaim.locality.tooltip=Name of User Attribute, which will be used to map to 'locality' subclaim inside 'address' token claim. Defaults to 'locality' . +addressClaim.region.label=User Attribute Name for Region +addressClaim.region.tooltip=Name of User Attribute, which will be used to map to 'region' subclaim inside 'address' token claim. Defaults to 'region' . +addressClaim.postal_code.label=User Attribute Name for Postal Code +addressClaim.postal_code.tooltip=Name of User Attribute, which will be used to map to 'postal_code' subclaim inside 'address' token claim. Defaults to 'postal_code' . +addressClaim.country.label=User Attribute Name for Country +addressClaim.country.tooltip=Name of User Attribute, which will be used to map to 'country' subclaim inside 'address' token claim. Defaults to 'country' . +addressClaim.formatted.label=User Attribute Name for Formatted Address +addressClaim.formatted.tooltip=Name of User Attribute, which will be used to map to 'formatted' subclaim inside 'address' token claim. Defaults to 'formatted' . +included.client.audience.label=Included Client Audience +included.client.audience.tooltip=The Client ID of the specified audience client will be included in audience (aud) field of the token. If there are existing audiences in the token, the specified value is just added to them. It won't override existing audiences. +included.custom.audience.label=Included Custom Audience +included.custom.audience.tooltip=This is used just if 'Included Client Audience' is not filled. The specified value will be included in audience (aud) field of the token. If there are existing audiences in the token, the specified value is just added to them. It won't override existing audiences. + +# client details +clients.tooltip=Clients are trusted browser apps and web services in a realm. These clients can request a login. You can also define client specific roles. +search.placeholder=Search... +search.loading=Searching... +create=Create +import=Import +client-id=Client ID +base-url=Base URL +actions=Actions +not-defined=Not defined +edit=Edit +delete=Delete +no-results=No results +no-clients-available=No clients available +add-client=Add Client +select-file=Select file +view-details=View details +clear-import=Clear import +client-id.tooltip=Specifies ID referenced in URI and tokens. For example 'my-client'. For SAML this is also the expected issuer value from authn requests +client.name.tooltip=Specifies display name of the client. For example 'My Client'. Supports keys for localized values as well. For example\: ${my_client} +client.enabled.tooltip=Disabled clients cannot initiate a login or have obtain access tokens. +alwaysDisplayInConsole=Always Display in Console +alwaysDisplayInConsole.tooltip=Always list this client in the Account Console, even if the user does not have an active session. +consent-required=Consent Required +consent-required.tooltip=If enabled, users have to consent to client access. +client.display-on-consent-screen=Display Client On Consent Screen +client.display-on-consent-screen.tooltip=Applicable just if Consent Required is on. If this switch is off, consent screen will contain just the consents corresponding to configured client scopes. If on, there will be also one item on consent screen about this client itself +client.consent-screen-text=Client Consent Screen Text +client.consent-screen-text.tooltip=Applicable just if 'Display Client On Consent Screen' is on for this client. Contains the text, which will be on consent screen about permissions specific just for this client +client-protocol=Client Protocol +client-protocol.tooltip='OpenID connect' allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server.'SAML' enables web-based authentication and authorization scenarios including cross-domain single sign-on (SSO) and uses security tokens containing assertions to pass information. +access-type=Access Type +access-type.tooltip='Confidential' clients require a secret to initiate login protocol. 'Public' clients do not require a secret. 'Bearer-only' clients are web services that never initiate a login. +standard-flow-enabled=Standard Flow Enabled +standard-flow-enabled.tooltip=This enables standard OpenID Connect redirect based authentication with authorization code. In terms of OpenID Connect or OAuth2 specifications, this enables support of 'Authorization Code Flow' for this client. +implicit-flow-enabled=Implicit Flow Enabled +implicit-flow-enabled.tooltip=This enables support for OpenID Connect redirect based authentication without authorization code. In terms of OpenID Connect or OAuth2 specifications, this enables support of 'Implicit Flow' for this client. +direct-access-grants-enabled=Direct Access Grants Enabled +direct-access-grants-enabled.tooltip=This enables support for Direct Access Grants, which means that client has access to username/password of user and exchange it directly with Keycloak server for access token. In terms of OAuth2 specification, this enables support of 'Resource Owner Password Credentials Grant' for this client. +service-accounts-enabled=Service Accounts Enabled +service-accounts-enabled.tooltip=Allows you to authenticate this client to Keycloak and retrieve access token dedicated to this client. In terms of OAuth2 specification, this enables support of 'Client Credentials Grant' for this client. +oauth2-device-authorization-grant-enabled=OAuth 2.0 Device Authorization Grant Enabled +oauth2-device-authorization-grant-enabled.tooltip=This enables support for OAuth 2.0 Device Authorization Grant, which means that client is an application on device that has limited input capabilities or lack a suitable browser. +oidc-ciba-grant-enabled=OIDC CIBA Grant Enabled +oidc-ciba-grant-enabled.tooltip=This enables support for OIDC CIBA Grant, which means that the user is authenticated via some external authentication device instead of the user's browser. +include-authnstatement=Include AuthnStatement +include-authnstatement.tooltip=Should a statement specifying the method and timestamp be included in login responses? +include-onetimeuse-condition=Include OneTimeUse Condition +include-onetimeuse-condition.tooltip=Should a OneTimeUse Condition be included in login responses? +artifact-binding = Force Artifact Binding +artifact-binding.tooltip = Should response messages be returned to the client through the SAML ARTIFACT binding system? +sign-documents=Sign Documents +sign-documents.tooltip=Should SAML documents be signed by the realm? +sign-documents-redirect-enable-key-info-ext=Optimize REDIRECT signing key lookup +sign-documents-redirect-enable-key-info-ext.tooltip=When signing SAML documents in REDIRECT binding for SP that is secured by Keycloak adapter, should the ID of the signing key be included in SAML protocol message in element? This optimizes validation of the signature as the validating party uses a single key instead of trying every known key for validation. +sign-assertions=Sign Assertions +sign-assertions.tooltip=Should assertions inside SAML documents be signed? This setting is not needed if document is already being signed. +signature-algorithm=Signature Algorithm +signature-algorithm.tooltip=The signature algorithm to use to sign documents. +canonicalization-method=Canonicalization Method +canonicalization-method.tooltip=Canonicalization Method for XML signatures. +encrypt-assertions=Encrypt Assertions +encrypt-assertions.tooltip=Should SAML assertions be encrypted with client's public key using AES? +client-signature-required=Client Signature Required +client-signature-required.tooltip=Will the client sign their saml requests and responses? And should they be validated? +force-post-binding=Force POST Binding +force-post-binding.tooltip=Always use POST binding for responses. +front-channel-logout=Front Channel Logout +front-channel-logout.tooltip=When true, logout requires a browser redirect to client. When false, server performs a background invocation for logout. +front-channel-logout-url=Front-Channel Logout URL +front-channel-logout-url.tooltip=URL that will cause the client to log itself out when a logout request is sent to this realm (via end_session_endpoint). If not provided, it defaults to the base url. +front-channel-logout-session-required=Front-Channel Logout Session Required +front-channel-logout-session-required.tooltip=Specifying whether a sid (session ID) and iss (Issuer) claims are included in the Logout Token when the Front-Channel Logout URL is used. + +force-name-id-format=Force Name ID Format +force-name-id-format.tooltip=Ignore requested NameID subject format and use admin console configured one. +allow-ecp-flow=Allow ECP Flow +allow-ecp-flow.tooltip=This client is allowed to use ECP flow for authenticating users. +name-id-format=Name ID Format +name-id-format.tooltip=The name ID format to use for the subject. +mapper.nameid.format.tooltip=Name ID Format using Mapper +root-url=Root URL +root-url.tooltip=Root URL appended to relative URLs +valid-redirect-uris=Valid Redirect URIs +valid-redirect-uris.tooltip=Valid URI pattern a browser can redirect to after a successful login or logout. Simple wildcards are allowed such as 'http://example.com/*'. Relative path can be specified too such as /my/relative/path/*. Relative paths are relative to the client root URL, or if none is specified the auth server root URL is used. For SAML, you must set valid URI patterns if you are relying on the consumer service URL embedded with the login request. +base-url.tooltip=Default URL to use when the auth server needs to redirect or link back to the client. +admin-url=Admin URL +admin-url.tooltip=URL to the admin interface of the client. Set this if the client supports the adapter REST API. This REST API allows the auth server to push revocation policies and other administrative tasks. Usually this is set to the base URL of the client. +master-saml-processing-url=Master SAML Processing URL +master-saml-processing-url.tooltip=If configured, this URL will be used for every binding to both the SP's Assertion Consumer and Single Logout Services. This can be individually overridden for each binding and service in the Fine Grain SAML Endpoint Configuration. +idp-sso-url-ref=IDP Initiated SSO URL Name +idp-sso-url-ref.tooltip=URL fragment name to reference client when you want to do IDP Initiated SSO. Leaving this empty will disable IDP Initiated SSO. The URL you will reference from your browser will be: {server-root}/realms/{realm}/protocol/saml/clients/{client-url-name} +idp-sso-url-ref.urlhint=Target IDP initiated SSO URL: +idp-sso-relay-state=IDP Initiated SSO Relay State +idp-sso-relay-state.tooltip=Relay state you want to send with SAML request when you want to do IDP Initiated SSO. +web-origins=Web Origins +web-origins.tooltip=Allowed CORS origins. To permit all origins of Valid Redirect URIs, add '+'. This does not include the '*' wildcard though. To permit all origins, explicitly add '*'. +backchannel-logout-url=Backchannel Logout URL +backchannel-logout-url.tooltip=URL that will cause the client to log itself out when a logout request is sent to this realm (via end_session_endpoint). If omitted, no logout request will be sent to the client is this case. +backchannel-logout-session-required=Backchannel Logout Session Required +backchannel-logout-session-required.tooltip=Specifying whether a sid (session ID) Claim is included in the Logout Token when the Backchannel Logout URL is used. +backchannel-logout-revoke-offline-sessions=Backchannel Logout Revoke Offline Sessions +backchannel-logout-revoke-offline-sessions.tooltip=Specifying whether a "revoke_offline_access" event is included in the Logout Token when the Backchannel Logout URL is used. Keycloak will revoke offline sessions when receiving a Logout Token with this event. +fine-oidc-endpoint-conf=Fine Grain OpenID Connect Configuration +fine-oidc-endpoint-conf.tooltip=Expand this section to configure advanced settings of this client related to OpenID Connect protocol +access-token-signed-response-alg=Access Token Signature Algorithm +access-token-signed-response-alg.tooltip=JWA algorithm used for signing access tokens. +id-token-signed-response-alg=ID Token Signature Algorithm +id-token-signed-response-alg.tooltip=JWA algorithm used for signing ID tokens. +id-token-encrypted-response-alg=ID Token Encryption Key Management Algorithm +id-token-encrypted-response-alg.tooltip=JWA Algorithm used for key management in encrypting ID tokens. This option is needed if you want encrypted ID tokens. If left empty, ID Tokens are just signed, but not encrypted. +id-token-encrypted-response-enc=ID Token Encryption Content Encryption Algorithm +id-token-encrypted-response-enc.tooltip=JWA Algorithm used for content encryption in encrypting ID tokens. This option is needed just if you want encrypted ID tokens. If left empty, ID Tokens are just signed, but not encrypted. +user-info-signed-response-alg=User Info Signed Response Algorithm +user-info-signed-response-alg.tooltip=JWA algorithm used for signed User Info Endpoint response. If set to 'unsigned', User Info Response won't be signed and will be returned in application/json format. +user-info-encrypted-response-alg=User Info Response Encryption Key Management Algorithm +user-info-encrypted-response-alg.tooltip=JWA Algorithm used for key management in encrypting User Info Endpoint responses. This option is needed if you want encrypted User Info Endpoint responses. If left empty, User Info Endpoint responses are not encrypted. +user-info-encrypted-response-enc=User Info Response Encryption Content Encryption Algorithm +user-info-encrypted-response-enc.tooltip=JWA Algorithm used for content encryption in encrypting User Info Endpoint responses. If User Info response encryption key management algorithm is specified, the default for this value is A128CBC-HS256. +request-object-signature-alg=Request Object Signature Algorithm +request-object-signature-alg.tooltip=JWA algorithm, which client needs to use when sending OIDC request object specified by 'request' or 'request_uri' parameters. If set to 'any', Request object can be signed by any algorithm (including 'none' ). +request-object-required=Request Object Required +request-object-required.tooltip=Specifies if the client needs to provide a request object with their authorization requests, and what method they can use for this. If set to "not required", providing a request object is optional. In all other cases, providing a request object is mandatory. If set to "request", the request object must be provided by value. If set to "request_uri", the request object must be provided by reference. If set to "request or request_uri", either method can be used. +request-object-encryption-alg=Request Object Encryption Algorithm +request-object-encryption-alg.tooltip=JWE algorithm, which client needs to use when sending OIDC request object specified by 'request' or 'request_uri' parameters. If set to 'any', encryption is optional and any algorithm is allowed. +request-object-encryption-enc=Request Object Content Encryption Algorithm +request-object-encryption-enc.tooltip=JWE algorithm, which client needs to use when encrypting the content of the OIDC request object specified by 'request' or 'request_uri' parameters. If set to 'any', any algorithm is allowed. +ciba-backchannel-token-delivery-mode=CIBA Backchannel Token Delivery Mode +ciba-backchannel-token-delivery-mode.tooltip= CIBA mode, which will be used by this client. If not set, defaults to realm attribute set at the CIBA Policy (defaults to 'poll') +ciba-backchannel-client-notification-endpoint=CIBA Backchannel Client Notification Endpoint +ciba-backchannel-client-notification-endpoint.tooltip=Client Notification Endpoint URL used by the CIBA Ping mode. +ciba-backchannel-auth-request-signing-alg=CIBA Backchannel Authentication Request Signature Algorithm +ciba-backchannel-auth-request-signing-alg.tooltip=JWA algorithm, which client needs to use when sending CIBA backchannel authentication request specified by 'request' or 'request_uri' parameters. Only asymmetric algorithms are allowed according CIBA specification. If set to 'any', any algorithm is allowed. +request-uris=Valid Request URIs +request-uris.tooltip=List of valid URIs, which can be used as values of 'request_uri' parameter during OpenID Connect authentication request. There is support for the same capabilities like for Valid Redirect URIs. For example wildcards or relative paths. +fine-saml-endpoint-conf=Fine Grain SAML Endpoint Configuration +fine-saml-endpoint-conf.tooltip=Expand this section to configure exact URLs for Assertion Consumer and Single Logout Service. +assertion-consumer-post-binding-url=Assertion Consumer Service POST Binding URL +assertion-consumer-post-binding-url.tooltip=SAML POST Binding URL for the client's assertion consumer service (login responses). You can leave this blank if you do not have a URL for this binding. +assertion-consumer-redirect-binding-url=Assertion Consumer Service Redirect Binding URL +assertion-consumer-redirect-binding-url.tooltip=SAML Redirect Binding URL for the client's assertion consumer service (login responses). You can leave this blank if you do not have a URL for this binding. +logout-service-post-binding-url=Logout Service POST Binding URL +logout-service-post-binding-url.tooltip=SAML POST Binding URL for the client's single logout service. You can leave this blank if you are using a different binding +logout-service-redir-binding-url=Logout Service Redirect Binding URL +logout-service-redir-binding-url.tooltip=SAML Redirect Binding URL for the client's single logout service. You can leave this blank if you are using a different binding. +logout-service-artifact-binding-url=Logout Service ARTIFACT Binding URL +logout-service-artifact-binding-url.tooltip=SAML ARTIFACT Binding URL for the client's single logout service. You can leave this blank if you are using a different binding. +artifact-binding-url= Artifact Binding URL +artifact-binding-url.tooltip=URL to send the HTTP ARTIFACT messages to. You can leave this blank if you are using a different binding. This value should be set when forcing ARTIFACT binding together with IdP initiated login. +artifact-resolution-service-url= Artifact Resolution Service +artifact-resolution-service-url.tooltip= SAML Artifact resolution service for the client. This is the endpoint to which Keycloak will send a SOAP ArtifactResolve message. You can leave this blank if you do not have a URL for this binding. +saml-signature-keyName-transformer=SAML Signature Key Name +saml-signature-keyName-transformer.tooltip=Signed SAML documents contain identification of signing key in KeyName element. For Keycloak / RH-SSO counterparty, use KEY_ID, for MS AD FS use CERT_SUBJECT, for others check and use NONE if no other option works. +oidc-compatibility-modes=OpenID Connect Compatibility Modes +oidc-compatibility-modes.tooltip=Expand this section to configure settings for backwards compatibility with older OpenID Connect / OAuth2 adapters. It is useful especially if your client uses older version of Keycloak / RH-SSO adapter. +exclude-session-state-from-auth-response=Exclude Session State From Authentication Response +exclude-session-state-from-auth-response.tooltip=If this is on, the parameter 'session_state' will not be included in OpenID Connect Authentication Response. It is useful if your client uses older OIDC / OAuth2 adapter, which does not support 'session_state' parameter. +use-refresh-tokens=Use Refresh Tokens +use-refresh-tokens.tooltip=If this is on, a refresh_token will be created and added to the token response. If this is off then no refresh_token will be generated. +use-refresh-token-for-client-credentials-grant=Use Refresh Tokens For Client Credentials Grant +use-refresh-token-for-client-credentials-grant.tooltip=If this is on, a refresh_token will be created and added to the token response if the client_credentials grant is used. The OAuth 2.0 RFC6749 Section 4.4.3 states that a refresh_token should not be generated when client_credentials grant is used. If this is off then no refresh_token will be generated and the associated user session will be removed. +use-lower-case-bearer-in-token-responses=Use lower-case bearer type in token responses +use-lower-case-bearer-in-token-responses.tooltip=If this is on, token responses will be set the with the type "bearer" in lower-case. By default, the server sets the type as "Bearer" as defined by RFC6750. +authorization-signed-response-alg=Authorization Response Signature Algorithm +authorization-signed-response-alg.tooltip=JWA algorithm used for signing authorization response tokens when the response mode is jwt. +authorization-encrypted-response-alg=Authorization Response Encryption Key Management Algorithm +authorization-encrypted-response-alg.tooltip=JWA Algorithm used for key management in encrypting the authorization response when the response mode is jwt. This option is needed if you want encrypted authorization response. If left empty, the authorization response is just signed, but not encrypted. +authorization-encrypted-response-enc=Authorization Response Encryption Content Encryption Algorithm +authorization-encrypted-response-enc.tooltip=JWA Algorithm used for content encryption in encrypting the authorization response when the response mode is jwt. This option is needed if you want encrypted authorization response. If left empty, the authorization response is just signed, but not encrypted. +logo-uri=Logo URL +logo-uri.tooltip=URL that references a logo for the Client application +policy-uri=Policy URL +policy-uri.tooltip=URL that the Relying Party Client provides to the End-User to read about the how the profile data will be used +tos-uri=Terms of service URL +tos-uri.tooltip=URL that the Relying Party Client provides to the End-User to read about the Relying Party's terms of service + + +# client import +import-client=Import Client +format-option=Format Option +select-format=Select a Format +import-file=Import File + +# client tabs +settings=Settings +credentials=Credentials +roles=Roles +mappers=Mappers +mappers.tooltip=Protocol mappers perform transformation on tokens and documents. They can do things like map user data into protocol claims, or just transform any requests going between the client and auth server. +scope=Scope +scope.tooltip=Scope mappings allow you to restrict which user role mappings are included within the access token requested by the client. +sessions.tooltip=View active sessions for this client. Allows you to see which users are active and when they logged in. +offline-access=Offline Access +offline-access.tooltip=View offline sessions for this client. Allows you to see which users retrieve offline token and when they retrieve it. To revoke all tokens for the client, go to the Revocation tab and set Not Before to Now. +clustering=Clustering +installation=Installation +installation.tooltip=Helper utility for generating various client adapter configuration formats which you can download or cut and paste to configure your clients. +service-account-roles=Service Account Roles +service-account-roles.tooltip=Allows you to authenticate role mappings for the service account dedicated to this client. + +# client credentials +client-authenticator=Client Authenticator +client-authenticator.tooltip=Client Authenticator used for authentication of this client against Keycloak server +certificate.tooltip=Client Certificate for validate JWT issued by client and signed by Client private key from your keystore. +publicKey.tooltip=Public Key for validate JWT issued by client and signed by Client private key. +no-client-certificate-configured=No client certificate configured +need-to-configure-keys=Configure JWKS URL or Signing key in the Keys tab +gen-new-keys-and-cert=Generate new keys and certificate +import-certificate=Import Certificate +gen-client-private-key=Generate Client Private Key +generate-private-key=Generate Private Key +kid=Kid +kid.tooltip=KID (Key ID) of the client public key from imported JWKS. +token-endpoint-auth-signing-alg=Signature Algorithm +token-endpoint-auth-signing-alg.tooltip=JWA algorithm, which the client needs to use when signing a JWT for authentication. If left blank, the client is allowed to use any algorithm. +use-jwks-url=Use JWKS URL +use-jwks-url.tooltip=If the switch is on, client public keys will be downloaded from given JWKS URL. This allows great flexibility because new keys will be always re-downloaded again when client generates new keypair. If the switch is off, public key (or certificate) from the Keycloak DB is used, so when client keypair changes, you always need to import new key (or certificate) to the Keycloak DB as well. This switch is mutually exclusive with the switch "Use JWKS". +jwks-url=JWKS URL +jwks-url.tooltip=URL where client keys in JWK format are stored. See JWK specification for more details. If you use Keycloak client adapter with "jwt" credential, you can use URL of your app with '/k_jwks' suffix. For example 'http://www.myhost.com/myapp/k_jwks' . +use-jwks-string=Use JWKS +use-jwks-string.tooltip=If the switch is on, client public keys will be configurable in JWKS. This switch is mutually exclusive with the switch "Use JWKS URL". +jwks-string=JWKS +jwks-string.tooltip=Client keys in JWK format. See JWK specification for more details. +pkce-enabled=Use PKCE +pkce-enabled.tooltip=Use PKCE (Proof of Key-code exchange) for IdP Brokering +pkce-method=PKCE Method +pkce-method.tooltip=PKCE Method to use +pkce.plain.option=Plain +pkce.s256.option=S256 +archive-format=Archive Format +archive-format.tooltip=Java keystore or PKCS12 archive format. +key-alias=Key Alias +key-alias.tooltip=Archive alias for your private key and certificate. +key-password=Key Password +key-password.tooltip=Password to access the private key in the archive +store-password=Store Password +store-password.tooltip=Password to access the archive itself +generate-and-download=Generate and Download +client-certificate-import=Client Certificate Import +import-client-certificate=Import Client Certificate +jwt-import.key-alias.tooltip=Archive alias for your certificate. +secret=Secret +regenerate-secret=Regenerate Secret +secret-rotation=Secret Rotation +secret-rotation-enabled.tooltip=This enables client secret rotation. +rotate.secret=Rotate Secret +secret-rotated=Secret Rotated +invalidate-secret=Invalidate Secret +secret-expires-on=Secret expires on +registrationAccessToken=Registration access token +registrationAccessToken.regenerate=Regenerate registration access token +registrationAccessToken.tooltip=The registration access token provides access for clients to the client registration service. +add-role=Add Role +role-name=Role Name +composite=Composite +description=Description +no-client-roles-available=No client roles available +composite-roles=Composite Roles +composite-roles.tooltip=When this role is (un)assigned to a user any role associated with it will be (un)assigned implicitly. +realm-roles=Realm Roles +available-roles=Available Roles +add-selected=Add selected +associated-roles=Associated Roles +composite.associated-realm-roles.tooltip=Realm level roles associated with this composite role. +composite.available-realm-roles.tooltip=Realm level roles that you can associate to this composite role. +remove-selected=Remove selected +client-roles=Client Roles +select-client-to-view-roles=Select client to view roles for client +available-roles.tooltip=Roles from this client that you can associate to this composite role. +client.associated-roles.tooltip=Client roles associated with this composite role. +add-builtin=Add Builtin +category=Category +type=Type +priority-order=Priority Order +no-mappers-available=No mappers available +add-builtin-protocol-mappers=Add Builtin Protocol Mappers +add-builtin-protocol-mapper=Add Builtin Protocol Mapper +scope-mappings=Scope Mappings +full-scope-allowed=Full Scope Allowed +full-scope-allowed.tooltip=Allows you to disable all restrictions. +scope.available-roles.tooltip=Realm level roles that can be assigned to scope. Contains effectively assigned roles which are not directly assigned. +assigned-roles=Assigned Roles +assigned-roles.tooltip=Realm level roles assigned to scope. +effective-roles=Effective Roles +realm.effective-roles.tooltip=Assigned realm level roles that may have been inherited from a composite role. +select-client-roles.tooltip=Select client to view roles for client +assign.available-roles.tooltip=Client roles available to be assigned. Contains effectively assigned roles which are not directly assigned. +client.assigned-roles.tooltip=Assigned client roles. +client.effective-roles.tooltip=Assigned client roles that may have been inherited from a composite role. +basic-configuration=Basic configuration +node-reregistration-timeout=Node Re-registration Timeout +node-reregistration-timeout.tooltip=Interval to specify max time for registered clients cluster nodes to re-register. If cluster node will not send re-registration request to Keycloak within this time, it will be unregistered from Keycloak +registered-cluster-nodes=Registered cluster nodes +register-node-manually=Register node manually +test-cluster-availability=Test cluster availability +last-registration=Last registration +node-host=Node host +no-registered-cluster-nodes=No registered cluster nodes available +cluster-nodes=Cluster Nodes +add-node=Add Node +active-sessions.tooltip=Total number of active user sessions for this client. +show-sessions=Show Sessions +show-sessions.tooltip=Warning, this is a potentially expensive operation depending on the number of active sessions. +user=User +from-ip=From IP +session-start=Session Start +first-page=First Page +previous-page=Previous Page +next-page=Next Page +client-revoke.not-before.tooltip=Revoke any tokens issued before this date for this client. +client-revoke.push.tooltip=If the admin URL is configured for this client, push this policy to that client. +select-a-format=Select a Format +download=Download +offline-tokens=Offline Tokens +offline-tokens.tooltip=Total number of offline tokens for this client. +show-offline-tokens=Show Offline Tokens +show-offline-tokens.tooltip=Warning, this is a potentially expensive operation depending on the number of offline tokens. +token-issued=Token Issued +last-access=Last Access +last-refresh=Last Refresh +key-export=Key Export +key-import=Key Import +export-saml-key=Export SAML Key +import-saml-key=Import SAML Key +realm-certificate-alias=Realm Certificate Alias +realm-certificate-alias.tooltip=Realm certificate is stored in archive too. This is the alias to it. +signing-key=Signing Key +saml-signing-key=SAML Signing Key. +private-key=Private Key +generate-new-keys=Generate new keys +export=Export +encryption-key=Encryption Key +saml-encryption-key.tooltip=SAML Encryption Key. +service-accounts=Service Accounts +service-account.available-roles.tooltip=Realm level roles that can be assigned to service account. Contains effectively assigned roles which are not directly assigned. +service-account=Service Account +service-account.roles=Service Account Roles +service-account.user=Service Account User +service-account.user.tooltip=Username of the Service Account. To manage details and group mappings click on the username. +service-account.assigned-roles.tooltip=Realm level roles assigned to service account. +service-account-is-not-enabled-for=Service account is not enabled for {{client}} +create-protocol-mappers=Create Protocol Mappers +create-protocol-mapper=Create Protocol Mapper +protocol=Protocol +protocol.tooltip=Protocol... +id=ID +mapper.name.tooltip=Name of the mapper. +mapper.consent-required.tooltip=When granting temporary access, must the user consent to providing this data to the client? +consent-text=Consent Text +consent-text.tooltip=Text to display on consent page. +mapper-type=Mapper Type +mapper-type.tooltip=Type of the mapper +user-label=User Label +data=Data +show-data=Show data... +position=Position +# realm identity providers +identity-providers=Identity Providers +table-of-identity-providers=Table of identity providers +add-provider.placeholder=Add provider... +provider=Provider +gui-order=GUI order +first-broker-login-flow=First Login Flow +post-broker-login-flow=Post Login Flow +sync-mode=Sync Mode +sync-mode.tooltip=Default sync mode for all mappers. The sync mode determines when user data will be synced using the mappers. Possible values are: 'legacy' to keep the behaviour before this option was introduced, 'import' to only import the user once during first login of the user with this identity provider, 'force' to always update the user during every login with this identity provider. +sync-mode.inherit=inherit +sync-mode.legacy=legacy +sync-mode.import=import +sync-mode.force=force +sync-mode-override=Sync Mode Override +sync-mode-override.tooltip=Overrides the default sync mode of the IDP for this mapper. Values are: 'legacy' to keep the behaviour before this option was introduced, 'import' to only import the user once during first login of the user with this identity provider, 'force' to always update the user during every login with this identity provider and 'inherit' to use the sync mode defined in the identity provider for this mapper. +redirect-uri=Redirect URI +redirect-uri.tooltip=The redirect uri to use when configuring the identity provider. +alias=Alias +display-name=Display Name +identity-provider.alias.tooltip=The alias uniquely identifies an identity provider and it is also used to build the redirect uri. +identity-provider.api-url=API URL +identity-provider.api-url.tooltip=Override the default API URL for this identity provider. +identity-provider.base-url=Base URL +identity-provider.base-url.tooltip=Override the default Base URL for this identity provider. +identity-provider.display-name.tooltip=Friendly name for Identity Providers. +identity-provider.enabled.tooltip=Enable/disable this identity provider. +authenticate-by-default=Authenticate by Default +identity-provider.authenticate-by-default.tooltip=Indicates if this provider should be tried by default for authentication even before displaying login screen. +store-tokens=Store Tokens +identity-provider.store-tokens.tooltip=Enable/disable if tokens must be stored after authenticating users. +stored-tokens-readable=Stored Tokens Readable +identity-provider.stored-tokens-readable.tooltip=Enable/disable if new users can read any stored tokens. This assigns the broker.read-token role. +disableUserInfo=Disable User Info +identity-provider.disableUserInfo.tooltip=Disable usage of User Info service to obtain additional user information? Default is to use this OIDC service. +userIp=Use userIp Param +identity-provider.google-userIp.tooltip=Set 'userIp' query parameter when invoking on Google's User Info service. This will use the user's ip address. Useful if Google is throttling access to the User Info service. +offlineAccess=Request refresh token +identity-provider.google-offlineAccess.tooltip=Set 'access_type' query parameter to 'offline' when redirecting to google authorization endpoint, to get a refresh token back. Useful if planning to use Token Exchange to retrieve Google token to access Google APIs when the user is not at the browser. +hostedDomain=Hosted Domain +identity-provider.google-hostedDomain.tooltip=Set 'hd' query parameter when logging in with Google. Google will list accounts only for this domain. Keycloak validates that the returned identity token has a claim for this domain. When '*' is entered, any hosted account can be used. +identity-provider.facebook-fetchedFields.label=Additional user's profile fields +identity-provider.facebook-fetchedFields.tooltip=Provide additional fields which would be fetched using the profile request. This will be appended to the default set of 'id,name,email,first_name,last_name'. +sandbox=Target Sandbox +identity-provider.paypal-sandbox.tooltip=Target PayPal's sandbox environment +update-profile-on-first-login=Update Profile on First Login +on=On +on-missing-info=On missing info +off=Off +update-profile-on-first-login.tooltip=Define conditions under which a user has to update their profile during first-time login. +trust-email=Trust Email +trust-email.tooltip=If enabled, email provided by this provider is not verified even if verification is enabled for the realm. +link-only=Account Linking Only +link-only.tooltip=If true, users cannot log in through this provider. They can only link to this provider. This is useful if you don't want to allow login from the provider, but want to integrate with a provider +hide-on-login-page=Hide on Login Page +hide-on-login-page.tooltip=If hidden, login with this provider is possible only if requested explicitly, for example using the 'kc_idp_hint' parameter. +gui-order.tooltip=Number defining order of the provider in GUI (for example, on Login page). +first-broker-login-flow.tooltip=Alias of authentication flow, which is triggered after first login with this identity provider. Term 'First Login' means that no Keycloak account is currently linked to the authenticated identity provider account. +post-broker-login-flow.tooltip=Alias of authentication flow, which is triggered after each login with this identity provider. Useful if you want additional verification of each user authenticated with this identity provider (for example OTP). Leave this empty if you need no any additional authenticators to be triggered after login with this identity provider. Also note that authenticator implementations must assume that user is already set in ClientSession as identity provider already set it. +openid-connect-config=OpenID Connect Config +openid-connect-config.tooltip=OIDC SP and external IDP configuration. +authorization-url=Authorization URL +authorization-url.tooltip=The Authorization Url. +token-url=Token URL +token-url.tooltip=The Token URL. +loginHint=Pass login_hint +loginHint.tooltip=Pass login_hint to identity provider. +uiLocales=Pass current locale +uiLocales.tooltip=Pass the current locale to the identity provider as a ui_locales parameter. +logout-url=Logout URL +identity-provider.logout-url.tooltip=End session endpoint to use to logout user from external IDP. +backchannel-logout=Backchannel Logout +backchannel-logout.tooltip=Does the external IDP support backchannel logout? +user-info-url=User Info URL +user-info-url.tooltip=The User Info Url. This is optional. +client-auth=Client Authentication +client-auth.tooltip=The client authentication method (cfr. https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication). In case of JWT signed with private key, the realm private key is used. +client-auth.client_secret_post=Client secret sent as post +client-auth.client_secret_basic=Client secret sent as basic auth +client-auth.client_secret_jwt=Client secret as jwt +client-auth.private_key_jwt=JWT signed with private key +identity-provider.client-id.tooltip=The client or client identifier registered within the identity provider. +client-secret=Client Secret +client-assertion-signing-algorithm=Client Assertion Signature Algorithm +client-assertion-signing-algorithm.tooltip=Signature algorithm to create JWT assertion as client authentication. In the case of JWT signed with private key or Client secret as jwt, it is required. If no algorithm is specified, the following algorithm is adapted. RS256 is adapted in the case of JWT signed with private key. HS256 is adapted in the case of Client secret as jwt. +show-secret=Show secret +hide-secret=Hide secret +client-secret.tooltip=The client or client secret registered within the identity provider. This field is able to obtain its value from vault, use ${vault.ID} format. +issuer=Issuer +issuer.tooltip=The issuer identifier for the issuer of the response. If not provided, no validation will be performed. +default-scopes=Default Scopes +identity-provider.default-scopes.tooltip=The scopes to be sent when asking for authorization. It can be a space-separated list of scopes. Defaults to 'openid'. +prompt=Prompt +unspecified.option=unspecified +none.option=none +consent.option=consent +login.option=login +select-account.option=select_account +prompt.tooltip=Specifies whether the Authorization Server prompts the End-User for reauthentication and consent. +accepts-prompt-none-forward-from-client=Accepts prompt=none forward from client +accepts-prompt-none-forward-from-client.tooltip=This is just used together with Identity Provider Authenticator or when kc_idp_hint points to this identity provider. In case that client sends a request with prompt=none and user is not yet authenticated, the error will not be directly returned to client, but the request with prompt=none will be forwarded to this identity provider. +validate-signatures=Validate Signatures +identity-provider.validate-signatures.tooltip=Enable/disable signature validation of external IDP signatures. +identity-provider.use-jwks-url.tooltip=If the switch is on, identity provider public keys will be downloaded from given JWKS URL. This allows great flexibility because new keys will be always re-downloaded again when identity provider generates new keypair. If the switch is off, public key (or certificate) from the Keycloak DB is used, so when the identity provider keypair changes, you always need to import the new key to the Keycloak DB as well. +identity-provider.jwks-url.tooltip=URL where identity provider keys in JWK format are stored. See JWK specification for more details. If you use external Keycloak identity provider, you can use URL like 'http://broker-keycloak:8180/auth/realms/test/protocol/openid-connect/certs' assuming your brokered Keycloak is running on 'http://broker-keycloak:8180' and its realm is 'test' . +validating-public-key=Validating Public Key +identity-provider.validating-public-key.tooltip=The public key in PEM format that must be used to verify external IDP signatures. +validating-public-key-id=Validating Public Key Id +identity-provider.validating-public-key-id.tooltip=Explicit ID of the validating public key given above if the key ID. Leave blank if the key above should be used always, regardless of key ID specified by external IDP; set it if the key should only be used for verifying if the key ID from external IDP matches. +allowed-clock-skew=Allowed clock skew +identity-provider.allowed-clock-skew.tooltip=Clock skew in seconds that is tolerated when validating identity provider tokens. Default value is zero. +forwarded-query-parameters=Forwarded Query Parameters +identity-provider.forwarded-query-parameters.tooltip=Non OpenID Connect/OAuth standard query parameters to be forwarded to external IDP from the initial application request to Authorization Endpoint. Multiple parameters can be entered, separated by comma (,). +import-external-idp-config=Import External IDP Config +import-external-idp-config.tooltip=Allows you to load external IDP metadata from a config file or to download it from a URL. +import-from-url=Import from URL +identity-provider.import-from-url.tooltip=Import metadata from a remote IDP discovery descriptor. +import-from-file=Import from file +identity-provider.import-from-file.tooltip=Import metadata from a downloaded IDP discovery descriptor. +identity-provider.saml.entity-id=Service Provider Entity ID +identity-provider.saml.entity-id.tooltip=The Entity ID that will be used to uniquely identify this SAML Service Provider +identity-provider.saml.protocol-endpoints.saml=SAML 2.0 Service Provider Metadata +identity-provider.saml.protocol-endpoints.saml.tooltip=Shows the configuration of the Service Provider endpoint +identity-provider.saml.attribute-consuming-service-index=Attribute Consuming Service Index +identity-provider.saml.attribute-consuming-service-index.tooltip=Index of the Attribute Consuming Service profile to request during authentication +identity-provider.saml.attribute-consuming-service-name=Attribute Consuming Service Name +identity-provider.saml.attribute-consuming-service-name.tooltip=Name of the Attribute Consuming Service profile to advertise in the SP metadata. Default value equal to the realm display name when configured, otherwise equal to the realm name. +saml-config=SAML Config +identity-provider.saml-config.tooltip=SAML SP and external IDP configuration. +single-signon-service-url=Single Sign-On Service URL +saml.single-signon-service-url.tooltip=The Url that must be used to send authentication requests (SAML AuthnRequest). +single-logout-service-url=Single Logout Service URL +saml.single-logout-service-url.tooltip=The Url that must be used to send logout requests. +nameid-policy-format=NameID Policy Format +nameid-policy-format.tooltip=Specifies the URI reference corresponding to a name identifier format. Defaults to urn:oasis:names:tc:SAML:2.0:nameid-format:persistent. +saml.principal-type=Principal Type +saml.principal-type.tooltip=Way to identify and track external users from the assertion. Default is using Subject NameID, alternatively you can set up identifying attribute. +saml.principal-attribute=Principal Attribute +saml.principal-attribute.tooltip=Name or Friendly Name of the attribute used to identify external users. +saml.allow-create=Allow create +saml.allow-create.tooltip=Allow the external identity provider to create a new identifier to represent the principal +http-post-binding-response=HTTP-POST Binding Response +http-post-binding-response.tooltip=Indicates whether to respond to requests using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used. +http-post-binding-for-authn-request=HTTP-POST Binding for AuthnRequest +http-post-binding-for-authn-request.tooltip=Indicates whether the AuthnRequest must be sent using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used. +http-post-binding-logout=HTTP-POST Binding Logout +http-post-binding-logout.tooltip=Indicates whether to respond to requests using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used. +want-authn-requests-signed=Want AuthnRequests Signed +want-authn-requests-signed.tooltip=Indicates whether the identity provider expects a signed AuthnRequest. +want-assertions-signed=Want Assertions Signed +want-assertions-signed.tooltip=Indicates whether this service provider expects a signed Assertion. +want-assertions-encrypted=Want Assertions Encrypted +want-assertions-encrypted.tooltip=Indicates whether this service provider expects an encrypted Assertion. +force-authentication=Force Authentication +identity-provider.force-authentication.tooltip=Indicates whether the identity provider must authenticate the presenter directly rather than rely on a previous security context. +validate-signature=Validate Signature +saml.validate-signature.tooltip=Enable/disable signature validation of SAML responses. +validating-x509-certificate=Validating X509 Certificates +validating-x509-certificate.tooltip=The certificate in PEM format that must be used to check for signatures. Multiple certificates can be entered, separated by comma (,). +saml.loginHint=Pass subject +saml.loginHint.tooltip=During login phase, forward an optional login_hint query parameter to SAML AuthnRequest's Subject. +saml.import-from-url.tooltip=Import metadata from a remote IDP SAML entity descriptor. +identity-provider.saml.sign-sp-metadata=Sign Service Provider Metadata +identity-provider.saml.sign-sp-metadata.tooltip=Enable/disable signature of the provider SAML metadata +identity-provider.saml.requested-authncontext=Requested AuthnContext Constraints +identity-provider.saml.requested-authncontext.tooltip=Allows the SP to specify the authentication context requirements of authentication statements returned. +identity-provider.saml.authncontext-comparison-type=Comparison +identity-provider.saml.authncontext-comparison-type.tooltip=Specifies the comparison method used to evaluate the requested context classes or statements. The default is "Exact". +identity-provider.saml.authncontext-comparison-type.exact=Exact +identity-provider.saml.authncontext-comparison-type.minimum=Minimum +identity-provider.saml.authncontext-comparison-type.maximum=Maximum +identity-provider.saml.authncontext-comparison-type.better=Better +identity-provider.saml.authncontext-class-ref=AuthnContext ClassRefs +identity-provider.saml.authncontext-class-ref.tooltip=Ordered list of requested AuthnContext ClassRefs. +identity-provider.saml.authncontext-decl-ref=AuthnContext DeclRefs +identity-provider.saml.authncontext-decl-ref.tooltip=Ordered list of requested AuthnContext DeclRefs. +social.client-id.tooltip=The client identifier registered with the identity provider. +social.client-secret.tooltip=The client secret registered with the identity provider. This field is able to obtain its value from vault, use ${vault.ID} format. +social.default-scopes.tooltip=The scopes to be sent when asking for authorization. See the documentation for possible values, separator and default value'. +key=Key +stackoverflow.key.tooltip=The Key obtained from Stack Overflow client registration. +openshift.base-url=Base Url +openshift.base-url.tooltip=Base Url to OpenShift Online API +openshift4.base-url=Base Url +openshift4.base-url.tooltip=Base Url to OpenShift Online API +gitlab-application-id=Application Id +gitlab-application-secret=Application Secret +gitlab.application-id.tooltip=Application Id for the application you created in your GitLab Applications account menu +gitlab.application-secret.tooltip=Secret for the application that you created in your GitLab Applications account menu +gitlab.default-scopes.tooltip=Scopes to ask for on login. Will always ask for openid. Additionally adds read_user if you do not specify anything. +bitbucket-consumer-key=Consumer Key +bitbucket-consumer-secret=Consumer Secret +bitbucket.key.tooltip=Bitbucket OAuth Consumer Key +bitbucket.secret.tooltip=Bitbucket OAuth Consumer Secret +bitbucket.default-scopes.tooltip=Scopes to ask for on login. If you do not specify anything, scope defaults to 'email'. +# User federation +sync-ldap-roles-to-keycloak=Sync LDAP Roles To Keycloak +sync-keycloak-roles-to-ldap=Sync Keycloak Roles To LDAP +sync-ldap-groups-to-keycloak=Sync LDAP Groups To Keycloak +sync-keycloak-groups-to-ldap=Sync Keycloak Groups To LDAP +realms=Realms +realm=Realm +identity-provider-mappers=Identity Provider Mappers +create-identity-provider-mapper=Create Identity Provider Mapper +add-identity-provider-mapper=Add Identity Provider Mapper +client.description.tooltip=Specifies description of the client. For example 'My Client for TimeSheets'. Supports keys for localized values as well. For example\: ${my_client_description} +expires=Expires +expiration=Expiration +expiration.tooltip=Specifies how long the token should be valid +count=Count +count.tooltip=Specifies how many clients can be created using the token +remainingCount=Remaining Count +created=Created +back=Back +initial-access-tokens=Initial Access Tokens +add-initial-access-tokens=Add Initial Access Token +initial-access-token=Initial Access Token +initial-access.copyPaste.tooltip=Copy/paste the initial access token before navigating away from this page as it is not possible to retrieve later +continue=Continue +initial-access-token.confirm.title=Copy Initial Access Token +initial-access-token.confirm.text=Please copy and paste the initial access token before confirming as it cannot be retrieved later +no-initial-access-available=No Initial Access Tokens available +client-reg-policies=Client Registration Policies +client-reg-policy.name.tooltip=Display Name of the policy +anonymous-policies=Anonymous Access Policies +anonymous-policies.tooltip=Those Policies are used when the Client Registration Service is invoked by unauthenticated request. This means that the request does not contain Initial Access Token nor Bearer Token. +auth-policies=Authenticated Access Policies +auth-policies.tooltip=Those Policies are used when Client Registration Service is invoked by authenticated request. This means that the request contains Initial Access Token or Bearer Token. +policy-name=Policy Name +no-client-reg-policies-configured=No Client Registration Policies +trusted-hosts.label=Trusted Hosts +trusted-hosts.tooltip=List of Hosts, which are trusted and are allowed to invoke Client Registration Service and/or be used as values of Client URIs. You can use hostnames or IP addresses. If you use star at the beginning (for example '*.example.com' ) then whole domain example.com will be trusted. +host-sending-registration-request-must-match.label=Host Sending Client Registration Request Must Match +host-sending-registration-request-must-match.tooltip=If on, any request to Client Registration Service is allowed just if it was sent from some trusted host or domain. +client-uris-must-match.label=Client URIs Must Match +client-uris-must-match.tooltip=If on, all Client URIs (Redirect URIs and others) are allowed just if they match some trusted host or domain. +consent-required-for-all-mappers.label=Consent Required For Mappers +consent-required-for-all-mappers.tooltip=If on, all newly registered protocol mappers will automatically have consentRequired switch on. This means that user will need to approve consent screen. NOTE: Consent screen is shown just if client has consentRequired switch on. So it is usually good to use this switch together with consent-required policy. +allowed-client-scopes.label=Allowed Client Scopes +allowed-client-scopes.tooltip=Whitelist of the client scopes, which can be used on a newly registered client. Attempt to register client with some client scope, which is not whitelisted, will be rejected. By default, the whitelist is either empty or contains just realm default client scopes (based on 'Allow Default Scopes' configuration property) +allow-default-scopes.label=Allow Default Scopes +allow-default-scopes.tooltip=If on, newly registered clients will be allowed to have client scopes mentioned in realm default client scopes or realm optional client scopes + +# Client Registration Policies providers +allowed-protocol-mappers.label=Allowed Protocol Mappers +allowed-protocol-mappers.tooltip=Whitelist of allowed protocol mapper providers. If there is an attempt to register client, which contains some protocol mappers, which were not whitelisted, registration request will be rejected. + +allowed-client-templates.label=Allowed Client Templates +client-disabled.label=Client Disabled +scope.label=Scope +consent-required.label=Consent Required + +max-clients.label=Max Clients Per Realm +max-clients.tooltip=It will not be allowed to register a new client if count of existing clients in realm is same or bigger than the configured limit. + +client-scopes=Client Scopes +client-scopes.tooltip=Client scopes allow you to define a common set of protocol mappers and roles, which are shared between multiple clients + +# Client Policies +realm-tab-client-policies=Client Policies +client-policies-profiles=Profiles +client-policies-profiles.tooltip=Client Profile allows to setup set of executors, which are enforced for various actions done with the client. Actions can be admin actions like creating or updating client, or user actions like authentication to the client. +client-policies-policies=Policies +client-policies-policies.tooltip=Client Policy allows to bind client profiles with various conditions to specify when exactly is enforced behaviour specified by executors of the particular client profile. +client-profiles-form-view=Form View +client-profiles-json-editor=JSON Editor +global=Global +executors=Executors +client-profile-name.tooltip=Name of the client profile. Must be unique within the realm +client-profile-executors.tooltip=Executors, which will be applied for this client profile +no-executors-available=No Executors Available +push-profile-to-json=Push Profile to JSON +executor-type=Executor Type +create-executor=Create Executor +client-policy-name.tooltip=Name of the client policy. Must be unique within the realm. +client-policy-enabled.tooltip=Specifies if client policy is enabled. Disabled policies are not considered at all during evaluation of client requests. +conditions=Conditions +client-policy-conditions.tooltip=Conditions, which will be evaluated to determine if client policy should be applied during particular action or not. +no-conditions-available=No Conditions Available +condition-type=Condition Type +create-condition=Create Condition +client-profiles=Client Profiles +client-policies=Client Policies +client-profiles.tooltip=Client Profiles applied on this policy +add-profile.placeholder=Add client profile ... +no-client-profiles-configured=No client profiles configured +create-client-profile=Create Client Profile +create-client-policy=Create Client Policy + +client-scopes-condition.label=Expected Scopes +client-scopes-condition.tooltip=The list of expected client scopes. Condition evaluates to true if specified client request matches some of the client scopes. It depends also whether it should be default or optional client scope based on the 'Scope Type' configured. +client-accesstype.label=Client Access Type +client-accesstype.tooltip=Access Type of the client, for which the condition will be applied. +client-roles.label=Client Roles +client-roles-condition.tooltip=Client roles, which will be checked during this condition evaluation. Condition evaluates to true if client has at least one client role with the name as the client roles specified in the configuration. +client-updater-source-groups.label=Groups +client-updater-source-groups.tooltip=Name of groups to check. Condition evaluates to true if the entity, who creates/updates client is member of some of the specified groups. Configured groups are specified by their simple name, which must match to the name of the Keycloak group. No support for group hierarchy is used here. +client-updater-trusted-hosts.label=Trusted hosts +client-updater-trusted-hosts.tooltip=List of Hosts, which are trusted. In case that client registration/update request comes from the host/domain specified in this configuration, condition evaluates to true. You can use hostnames or IP addresses. If you use star at the beginning (for example '*.example.com' ) then whole domain example.com will be trusted. +client-updater-source-roles.label=Updating entity role +client-updater-source-roles.tooltip=The condition is checked during client registration/update requests and it evaluates to true if the entity (usually user), who is creating/updating client is member of the specified role. For reference the realm role, you can use the realm role name like 'my_realm_role' . For reference client role, you can use the client_id.role_name for example 'my_client.my_client_role' will refer to client role 'my_client_role' of client 'my_client'. + +groups=Groups + +group.add-selected.tooltip=Realm roles that can be assigned to the group. Contains effectively assigned roles which are not directly assigned. +group.assigned-roles.tooltip=Realm roles mapped to the group +group.effective-roles.tooltip=All realm role mappings. Some roles here might be inherited from a mapped composite role. +group.available-roles.tooltip=Assignable roles from this client. Contains effectively assigned roles which are not directly assigned. +group.assigned-roles-client.tooltip=Role mappings for this client. +group.effective-roles-client.tooltip=Role mappings for this client. Some roles here might be inherited from a mapped composite role. + +group.move.success=Group moved. +group.remove.confirm.title=Delete Group +group.remove.confirm.message=Are you sure you want to permanently delete the group {{name}}? +group.remove.success=The group has been deleted. +group.fetch.fail=Unable to fetch {{params}} +group.create.success=Group Created. +group.edit.success=Your changes have been saved to the group. +group.roles.add.success=Role mappings updated. +group.roles.remove.success=Role mappings updated. +group.default.add.error=Please select a group to add +group.default.add.success=Added default group +group.default.remove.success=Removed default group + +default-roles=Default Roles +no-realm-roles-available=No realm roles available + +users=Users +user.add-selected.tooltip=Realm roles that can be assigned to the user. Contains effectively assigned roles which are not directly assigned. +user.assigned-roles.tooltip=Realm roles mapped to the user +user.effective-roles.tooltip=All realm role mappings. Some roles here might be inherited from a mapped composite role. +user.available-roles.tooltip=Assignable roles from this client. Contains effectively assigned roles which are not directly assigned. +user.assigned-roles-client.tooltip=Role mappings for this client. +user.effective-roles-client.tooltip=Role mappings for this client. Some roles here might be inherited from a mapped composite role. + +user.roles.add.success=Role mappings updated. +user.roles.remove.success=Role mappings updated. +user.logout.all.success=Logged out user in all clients +user.logout.session.success=Logged out session +user.fedid.link.remove.confirm.title=Delete Identity Provider Link +user.fedid.link.remove.confirm.message=Are you sure you want to permanently delete the Identity Provider Link {{name}}? +user.fedid.link.remove.success=The provider link has been deleted. +user.fedid.link.add.success=Provider link has been created. +user.consent.revoke.success=Grant revoked successfully +user.consent.revoke.error=Grant couldn't be revoked +user.remove.confirm.title=Delete User +user.remove.confirm.message=Are you sure you want to permanently delete the user {{name}}? +user.unlock.success=Any temporarily locked users are now unlocked. +user.remove.success=The user has been deleted. +user.remove.error=User couldn't be deleted +user.create.success=The user has been created. +user.edit.success=Your changes have been saved to the user. +user.credential.update.success=Credentials saved! +user.credential.update.error=Error while updating the credential. See console for more information. +user.credential.remove.confirm.title=Delete credentials +user.credential.remove.confirm.message=Are you sure you want to delete these users credentials? +user.credential.remove.success=Credentials deleted! +user.credential.remove.error=Error while deleting the credential. See console for more information. +user.credential.move-top.error=Error while moving the credential to top. See console for more information. +user.credential.move-up.error=Error while moving the credential up. See console for more information. +user.credential.move-down.error=Error while moving the credential down. See console for more information. +user.credential.fetch.error=Error while loading user credentials. See console for more information. +user.credential.storage.fetch.error=Error while loading user storage credentials. See console for more information. +user.password.error.not-matching=Password and confirmation does not match. +user.password.reset.confirm.title=Reset password +user.password.reset.confirm.message=Are you sure you want to reset the password for the user? +user.password.reset.success=The password has been reset. +user.password.set.confirm.title=Set password +user.password.set.confirm.message=Are you sure you want to set a password for the user? +user.password.set.success=The password has been set. +user.credential.disable.confirm.title=Disable credentials +user.credential.disable.confirm.message=Are you sure you want to disable these users credentials? +user.credential.disable.confirm.success=Credentials disabled +user.credential.disable.confirm.error=Failed to disable credentials +user.actions-email.send.pending-changes.title=Cannot send email +user.actions-email.send.pending-changes.message=You must save your current changes before you can send an email +user.actions-email.send.confirm.title=Send Email +user.actions-email.send.confirm.message=Are you sure you want to send email to user? +user.actions-email.send.confirm.success=Email sent to user +user.actions-email.send.confirm.error=Failed to send email to user +user.storage.remove.confirm.title=Delete User storage provider +user.storage.remove.confirm.message=Are you sure you want to permanently delete the user storage provider {{name}}? +user.storage.remove.success=The provider has been deleted. +user.storage.create.success=The provider has been created. +user.storage.edit.success=The provider has been updated. +user.storage.sync.success=Sync of users finished successfully. {{status}} +user.storage.sync.error=Error during sync of users +user.storage.remove-users.success=Remove imported users finished successfully. +user.storage.remove-users.error=Error during remove +user.storage.unlink.success=Unlink of users finished successfully. +user.storage.unlink.error=Error during unlink +user.groups.fetch.all.error=Unable to fetch all group memberships {{params}} +user.groups.fetch.error=Unable to fetch {{params}} +user.groups.join.error.no-group-selected=Please select a group to add +user.groups.join.error.already-added=Group already added +user.groups.join.success=Added group membership +user.groups.leave.error.no-group-selected=Please select a group to remove +user.groups.leave.success=Removed group membership + +default.available-roles.tooltip=Realm level roles that can be assigned. +realm-default-roles=Realm Default Roles +realm-default-roles.tooltip=Realm level roles assigned to new users. +default.available-roles-client.tooltip=Roles from this client that are assignable as a default. +client-default-roles=Client Default Roles +client-default-roles.tooltip=Roles from this client assigned as a default role. +composite.available-roles.tooltip=Realm level roles that you can associate to this composite role. +composite.associated-roles.tooltip=Realm level roles associated with this composite role. +composite.available-roles-client.tooltip=Roles from this client that you can associate to this composite role. +composite.associated-roles-client.tooltip=Client roles associated with this composite role. +partial-import=Partial Import +partial-import.tooltip=Partial import allows you to import users, clients, and other resources from a previously exported json file. + +file=File +exported-json-file=Exported json file +import-from-realm=Import from realm +import-users=Import users +import-groups=Import groups +import-clients=Import clients +import-identity-providers=Import identity providers +import-realm-roles=Import realm roles +import-client-roles=Import client roles +if-resource-exists=If a resource exists +fail=Fail +skip=Skip +overwrite=Overwrite +if-resource-exists.tooltip=Specify what should be done if you try to import a resource that already exists. + +partial-export=Partial Export +partial-export.tooltip=Partial export allows you to export realm configuration, and other associated resources into a json file. +export-groups-and-roles=Export groups and roles +export-clients=Export clients + +action=Action +role-selector=Role Selector +group-selector=Group Selector +realm-roles.tooltip=Realm roles that can be selected. + +select-a-role=Select a role +select-realm-role=Select realm role +select-group=Select group +client-roles.tooltip=Client roles that can be selected. +select-client-role=Select client role + +client-saml-endpoint=Client SAML Endpoint +add-client-scope=Add client scope + +default-client-scopes=Default Client Scopes +default-client-scopes.tooltip=Client Scopes, which will be added automatically to each created client +default-client-scopes.default=Default Client Scopes +default-client-scopes.default.tooltip=Allow to define client scopes, which will be added as default scopes to each created client +default-client-scopes.default.available=Available Client Scopes +default-client-scopes.default.available.tooltip=Client scopes, which are not yet assigned as realm default scopes or realm optional scopes +default-client-scopes.default.assigned=Assigned Default Client Scopes +default-client-scopes.default.assigned.tooltip=Client scopes, which will be added as default scopes to each created client +default-client-scopes.optional=Optional Client Scopes +default-client-scopes.optional.tooltip=Allow to define client scopes, which will be added as optional scopes to each created client +default-client-scopes.optional.available=Available Client Scopes +default-client-scopes.optional.available.tooltip=Client scopes, which are not yet assigned as realm default scopes or realm optional scopes +default-client-scopes.optional.assigned=Assigned Optional Client Scopes +default-client-scopes.optional.assigned.tooltip=Client scopes, which will be added as optional scopes to each created client + +client-scopes.setup=Setup +client-scopes.setup.tooltip=Allow to setup client scopes linked to this client +client-scopes.default=Default Client Scopes +client-scopes.default.tooltip=Default client scopes are always applied when issuing tokens for this client. Protocol mappers and role scope mappings are always applied regardless of value of used scope parameter in OIDC Authorization request +client-scopes.default.available=Available Client Scopes +client-scopes.default.available.tooltip=Client scopes, which are not yet assigned as default scopes or optional scopes +client-scopes.default.assigned=Assigned Default Client Scopes +client-scopes.default.assigned.tooltip=Client scopes, which will be used as default scopes when generating tokens for this client +client-scopes.optional=Optional Client Scopes +client-scopes.optional.tooltip=Optional client scopes are applied when issuing tokens for this client, however just in case when they are requested by scope parameter in OIDC Authorization request +client-scopes.optional.available=Available Client Scopes +client-scopes.optional.available.tooltip=Client scopes, which are not yet assigned as default scopes or optional scopes +client-scopes.optional.assigned=Assigned Optional Client Scopes +client-scopes.optional.assigned.tooltip=Client scopes, which may be used as optional scopes when generating tokens for this client + +client-scopes.evaluate=Evaluate +client-scopes.evaluate.tooltip=Allow to see all protocol mappers and role scope mapping that will be used in the tokens issued to this client. Also allow to generate example access token based on provided scope parameter +scope-parameter=Scope Parameter +scope-parameter.tooltip=You can copy/paste this value of scope parameter and use it in initial OpenID Connect Authentication Request sent from this client adapter. Default client scopes and selected optional client scopes will be used when generating token issued for this client +client-scopes.evaluate.scopes=Client Scopes +client-scopes.evaluate.scopes.tooltip=Allow to select optional client scopes, which may be used when generating token issued for this client +client-scopes.evaluate.scopes.available=Available Optional Client Scopes +client-scopes.evaluate.scopes.available.tooltip=This contains Optional Client Scopes, which can be optionally used when issuing access token for this client +client-scopes.evaluate.scopes.assigned=Selected Optional Client Scopes +client-scopes.evaluate.scopes.assigned.tooltip=Selected Optional Client Scopes, which will be used when issuing access token for this client. You can see above what value of OAuth Scope Parameter needs to be used when you want to have these optional client scopes applied when the initial OpenID Connect Authentication request will be sent from your client adapter +client-scopes.evaluate.scopes.effective=Effective Client Scopes +client-scopes.evaluate.scopes.effective.tooltip=Contains all default client scopes and selected optional scopes. All protocol mappers and role scope mappings of all those client scopes will be used when generating access token issued for your client +client-scopes.evaluate.user.tooltip=Optionally select user, for whom the example access token will be generated. If you do not select a user, example access token will not be generated during evaluation +send-evaluation-request=Evaluate +send-evaluation-request.tooltip=Click this to see all protocol mappers and role scope mappings that will be used when issuing an access token for this client. It will also optionally generate example access token in case that some user was selected + +evaluated-protocol-mappers=Effective Protocol Mappers +evaluated-protocol-mappers.tooltip=Shows all effective protocol mappers that will be used when issuing token for this client. Also contains protocol mappers of selected optional client scopes. For each protocol mapper, you can see from which client scope it is inherited from +evaluated-roles=Effective Role Scope Mappings +evaluated-roles.tooltip=Shows all effective roles scope mappings that will be used when issuing token for this client. Also contains role scope mappings of selected optional client scopes +parent-client-scope=Parent Client Scope +client-scopes.evaluate.not-granted-roles=Not Granted Roles +client-scopes.evaluate.not-granted-roles.tooltip=Client does not have scope mappings for these roles. Those roles will not be in the access token issued to this client even if the authenticated user is a member of them +client-scopes.evaluate.granted-realm-effective-roles=Granted Effective Realm Roles +client-scopes.evaluate.granted-realm-effective-roles.tooltip=Client has scope mappings for these roles. Those roles will be in the access token issued to this client if the authenticated user is a member of them +client-scopes.evaluate.granted-client-effective-roles=Granted Effective Client Roles +generated-access-token=Generated Access Token +generated-access-token.tooltip=See the example access token, which will be generated and sent to the client when selected user is authenticated. You can see claims and roles that the token will contain based on the effective protocol mappers and role scope mappings and also based on the claims/roles assigned to user himself +generated-id-token=Generated ID Token +generated-id-token.tooltip=See the example ID Token, which will be generated and sent to the client when selected user is authenticated. You can see claims and roles that the token will contain based on the effective protocol mappers and role scope mappings and also based on the claims/roles assigned to user himself +generated-user-info=Generated User Info +generated-user-info.tooltip=See the example User Info, which will be provided by the User Info Endpoint + +manage=Manage +authentication=Authentication +user-federation=User Federation +user-storage=User Storage +events=Events +realm-settings=Realm Settings +configure=Configure +select-realm=Select realm +add=Add + +client-storage=Client Storage +no-client-storage-providers-configured=No client storage providers configured +client-stores.tooltip=Keycloak can retrieve clients and their details from external stores. + +client-scope.name.tooltip=Name of the client scope. Must be unique in the realm. Name should not contain space characters as it is used as value of scope parameter +client-scope.description.tooltip=Description of the client scope +client-scope.protocol.tooltip=Which SSO protocol configuration is being supplied by this client scope +client-scope.display-on-consent-screen=Display On Consent Screen +client-scope.display-on-consent-screen.tooltip=If on, and this client scope is added to some client with consent required, the text specified by 'Consent Screen Text' will be displayed on consent screen. If off, this client scope will not be displayed on the consent screen +client-scope.consent-screen-text=Consent Screen Text +client-scope.consent-screen-text.tooltip=Text that will be shown on the consent screen when this client scope is added to some client with consent required. Defaults to name of client scope if it is not filled +client-scope.gui-order=GUI order +client-scope.gui-order.tooltip=Specify order of the provider in GUI (such as in Consent page) as integer +client-scope.include-in-token-scope=Include In Token Scope +client-scope.include-in-token-scope.tooltip=If on, the name of this client scope will be added to the access token property 'scope' as well as to the Token Introspection Endpoint response. If off, this client scope will be omitted from the token and from the Token Introspection Endpoint response. +client-scope.is-dynamic-scope=Dynamic Scope +client-scope.is-dynamic-scope.tooltip=If on, this scope will be considered a Dynamic Scope, which will be comprised of a static and a variable portion. +client-scope.dynamic-scope-regexp=Dynamic Scope Format +client-scope.dynamic-scope-regexp.tooltip=This is the regular expression that the system will use to extract the scope name and variable. + +add-user-federation-provider=Add user federation provider +add-user-storage-provider=Add user storage provider +required-settings=Required Settings +provider-id=Provider ID +console-display-name=Console Display Name +console-display-name.tooltip=Display name of provider when linked in admin console. +priority=Priority +priority.tooltip=Priority of provider when doing a user lookup. Lowest first. +user-storage.enabled.tooltip=If provider is disabled, it will not be considered for queries and imported users will be disabled and read-only until the provider is enabled again. +sync-settings=Sync Settings +periodic-full-sync=Periodic Full Sync +periodic-full-sync.tooltip=Does periodic full synchronization of provider users to Keycloak should be enabled or not +full-sync-period=Full Sync Period +full-sync-period.tooltip=Period for full synchronization in seconds +periodic-changed-users-sync=Periodic Changed Users Sync +periodic-changed-users-sync.tooltip=Does periodic synchronization of changed or newly created provider users to Keycloak should be enabled or not +changed-users-sync-period=Changed Users Sync Period +changed-users-sync-period.tooltip=Period for synchronization of changed or newly created provider users in seconds +synchronize-changed-users=Synchronize changed users +synchronize-all-users=Synchronize all users +remove-imported-users=Remove imported +unlink-users=Unlink users +kerberos-realm=Kerberos Realm +kerberos-realm.tooltip=Name of kerberos realm. For example FOO.ORG +server-principal=Server Principal +server-principal.tooltip=Full name of server principal for HTTP service including server and domain name. For example 'HTTP/host.foo.org@FOO.ORG'. Use '*' to accept any service principal in the KeyTab file. +keytab=KeyTab +keytab.tooltip=Location of Kerberos KeyTab file containing the credentials of server principal. For example /etc/krb5.keytab +debug=Debug +debug.tooltip=Enable/disable debug logging to standard output for Krb5LoginModule. +allow-password-authentication=Allow Password Authentication +allow-password-authentication.tooltip=Enable/disable possibility of username/password authentication against Kerberos database +edit-mode=Edit Mode +edit-mode.tooltip=READ_ONLY means that password updates are not allowed and user always authenticates with Kerberos password. UNSYNCED means that the user can change the password in the Keycloak database and this one will be used instead of the Kerberos password +ldap.edit-mode.tooltip=READ_ONLY is a read-only LDAP store. WRITABLE means data will be synced back to LDAP on demand. UNSYNCED means user data will be imported, but not synced back to LDAP. +update-profile-first-login=Update Profile First Login +update-profile-first-login.tooltip=Update profile on first login +sync-registrations=Sync Registrations +ldap.sync-registrations.tooltip=Should newly created users be created within LDAP store? Priority effects which provider is chosen to sync the new user. This setting is effectively appplied only with WRITABLE edit mode. +import-enabled=Import Users +ldap.import-enabled.tooltip=If true, LDAP users will be imported into Keycloak DB and synced by the configured sync policies. +vendor=Vendor +ldap.vendor.tooltip=LDAP vendor (provider) +enable-usePasswordModifyExtendedOp=Enable the LDAPv3 Password Modify Extended Operation +ldap.usePasswordModifyExtendedOp.tooltip=Use the LDAPv3 Password Modify Extended Operation (RFC-3062). The password modify extended operation usually requires that LDAP user already has password in the LDAP server. So when this is used with 'Sync Registrations', it can be good to add also 'Hardcoded LDAP attribute mapper' with randomly generated initial password. +username-ldap-attribute=Username LDAP attribute +ldap-attribute-name-for-username=LDAP attribute name for username +username-ldap-attribute.tooltip=Name of LDAP attribute, which is mapped as Keycloak username. For many LDAP server vendors it can be 'uid'. For Active directory it can be 'sAMAccountName' or 'cn'. The attribute should be filled for all LDAP user records you want to import from LDAP to Keycloak. +rdn-ldap-attribute=RDN LDAP attribute +ldap-attribute-name-for-user-rdn=LDAP attribute name for user RDN +rdn-ldap-attribute.tooltip=Name of LDAP attribute, which is used as RDN (top attribute) of typical user DN. Usually it's the same as Username LDAP attribute, however it is not required. For example for Active directory, it is common to use 'cn' as RDN attribute when username attribute might be 'sAMAccountName'. +uuid-ldap-attribute=UUID LDAP attribute +ldap-attribute-name-for-uuid=LDAP attribute name for UUID +uuid-ldap-attribute.tooltip=Name of LDAP attribute, which is used as unique object identifier (UUID) for objects in LDAP. For many LDAP server vendors, it is 'entryUUID'; however some are different. For example for Active directory it should be 'objectGUID'. If your LDAP server does not support the notion of UUID, you can use any other attribute that is supposed to be unique among LDAP users in tree. For example 'uid' or 'entryDN'. +user-object-classes=User Object Classes +ldap-user-object-classes.placeholder=LDAP User Object Classes (div. by comma) +ldap-connection-url=LDAP connection URL +ldap-users-dn=LDAP Users DN +ldap-bind-dn=LDAP Bind DN +ldap-bind-credentials=LDAP Bind Credentials +ldap-filter=LDAP Filter +ldap.user-object-classes.tooltip=All values of LDAP objectClass attribute for users in LDAP divided by comma. For example: 'inetOrgPerson, organizationalPerson' . Newly created Keycloak users will be written to LDAP with all those object classes and existing LDAP user records are found just if they contain all those object classes. +connection-url=Connection URL +ldap.connection-url.tooltip=Connection URL to your LDAP server +test-connection=Test connection +users-dn=Users DN +ldap.users-dn.tooltip=Full DN of LDAP tree where your users are. This DN is the parent of LDAP users. It could be for example 'ou=users,dc=example,dc=com' assuming that your typical user will have DN like 'uid=john,ou=users,dc=example,dc=com' +authentication-type=Bind Type +ldap.authentication-type.tooltip=Type of the Authentication method used during LDAP Bind operation. It is used in most of the requests sent to the LDAP server. Currently only 'none' (anonymous LDAP authentication) or 'simple' (Bind credential + Bind password authentication) mechanisms are available +bind-dn=Bind DN +ldap.bind-dn.tooltip=DN of LDAP admin, which will be used by Keycloak to access LDAP server +bind-credential=Bind Credential +ldap.bind-credential.tooltip=Password of LDAP admin. This field is able to obtain its value from vault, use ${vault.ID} format. +test-authentication=Test authentication +custom-user-ldap-filter=Custom User LDAP Filter +ldap.custom-user-ldap-filter.tooltip=Additional LDAP Filter for filtering searched users. Leave this empty if you don't need additional filter. Make sure that it starts with '(' and ends with ')' +search-scope=Search Scope +ldap.search-scope.tooltip=For one level, the search applies only for users in the DNs specified by User DNs. For subtree, the search applies to the whole subtree. See LDAP documentation for more details +use-truststore-spi=Use Truststore SPI +ldap.use-truststore-spi.tooltip=Specifies whether LDAP connection will use the truststore SPI with the truststore configured in standalone.xml/domain.xml. 'Always' means that it will always use it. 'Never' means that it will not use it. 'Only for ldaps' means that it will use if your connection URL use ldaps. Note even if standalone.xml/domain.xml is not configured, the default Java cacerts or certificate specified by 'javax.net.ssl.trustStore' property will be used. +validate-password-policy=Validate Password Policy +connection-pooling=Connection Pooling +connection-pooling-settings=Connection Pooling Settings +connection-pooling-authentication=Connection Pooling Authentication +connection-pooling-authentication-default=none simple +connection-pooling-debug=Connection Pool Debug Level +connection-pooling-debug-default=off +connection-pooling-initsize=Connection Pool Initial Size +connection-pooling-initsize-default=1 +connection-pooling-maxsize=Connection Pool Maximum Size +connection-pooling-maxsize-default=1000 +connection-pooling-prefsize=Connection Pool Preferred Size +connection-pooling-prefsize-default=5 +connection-pooling-protocol=Connection Pool Protocol +connection-pooling-protocol-default=plain ssl +connection-pooling-timeout=Connection Pool Timeout +connection-pooling-timeout-default=300000 +ldap-connection-timeout=Connection Timeout +ldap.connection-timeout.tooltip=LDAP Connection Timeout in milliseconds +ldap-read-timeout=Read Timeout +ldap.read-timeout.tooltip=LDAP Read Timeout in milliseconds. This timeout applies for LDAP read operations +ldap.validate-password-policy.tooltip=Determines if Keycloak should validate the password with the realm password policy before updating the LDAP mapped user. When this is false, Keycloak password policy would not be applied, which means that password will be updated on LDAP server unless LDAP server itself has some password policy rules. This setting is possible only with WRITABLE edit mode. +ldap.connection-pooling.tooltip=Determines if Keycloak should use connection pooling for accessing LDAP server +ldap.connection-pooling.authentication.tooltip=A list of space-separated authentication types of connections that may be pooled. Valid types are "none", "simple", and "DIGEST-MD5". +ldap.connection-pooling.debug.tooltip=A string that indicates the level of debug output to produce. Valid values are "fine" (trace connection creation and removal) and "all" (all debugging information). +ldap.connection-pooling.initsize.tooltip=The string representation of an integer that represents the number of connections per connection identity to create when initially creating a connection for the identity. +ldap.connection-pooling.maxsize.tooltip=The string representation of an integer that represents the maximum number of connections per connection identity that can be maintained concurrently. +ldap.connection-pooling.prefsize.tooltip=The string representation of an integer that represents the preferred number of connections per connection identity that should be maintained concurrently. +ldap.connection-pooling.protocol.tooltip=A list of space-separated protocol types of connections that may be pooled. Valid types are "plain" and "ssl". +ldap.connection-pooling.timeout.tooltip=The string representation of an integer that represents the number of milliseconds that an idle connection may remain in the pool without being closed and removed from the pool. +ldap.pagination.tooltip=Does the LDAP server support pagination. +ldap.startTls.tooltip=Encrypts the connection to LDAP using STARTTLS, which will disable connection pooling. +kerberos-integration=Kerberos Integration +allow-kerberos-authentication=Allow Kerberos authentication +ldap.allow-kerberos-authentication.tooltip=Enable/disable HTTP authentication of users with SPNEGO/Kerberos tokens. The data about authenticated users will be provisioned from this LDAP server +use-kerberos-for-password-authentication=Use Kerberos For Password Authentication +ldap.use-kerberos-for-password-authentication.tooltip=Use Kerberos login module for authenticate username/password against Kerberos server instead of authenticating against LDAP server with Directory Service API +batch-size=Batch Size +ldap.batch-size.tooltip=Count of LDAP users to be imported from LDAP to Keycloak within a single transaction. +ldap.periodic-full-sync.tooltip=Does periodic full synchronization of LDAP users to Keycloak should be enabled or not +ldap.periodic-changed-users-sync.tooltip=Does periodic synchronization of changed or newly created LDAP users to Keycloak should be enabled or not +ldap.changed-users-sync-period.tooltip=Period for synchronization of changed or newly created LDAP users in seconds +user-federation-mappers=User Federation Mappers +create-user-federation-mapper=Create user federation mapper +add-user-federation-mapper=Add user federation mapper +provider-name=Provider Name +no-user-federation-providers-configured=No user federation providers configured +no-user-storage-providers-configured=No user storage providers configured +add-identity-provider=Add identity provider +add-identity-provider-link=Add identity provider link +identity-provider=Identity Provider +identity-provider-user-id=Identity Provider User ID +identity-provider-user-id.tooltip=Unique ID of the user on the Identity Provider side +identity-provider-username=Identity Provider Username +identity-provider-username.tooltip=Username on the Identity Provider side +pagination=Pagination +browser-flow=Browser Flow +browser-flow.tooltip=Select the flow you want to use for browser authentication. +registration-flow=Registration Flow +registration-flow.tooltip=Select the flow you want to use for registration. +direct-grant-flow=Direct Grant Flow +direct-grant-flow.tooltip=Select the flow you want to use for direct grant authentication. +reset-credentials=Reset Credentials +reset-credentials.tooltip=Select the flow you want to use when the user has forgotten their credentials. +client-authentication=Client Authentication +client-authentication.tooltip=Select the flow you want to use for authentication of clients. +docker-auth=Docker Authentication +docker-auth.tooltip=Select the flow you want to use for authentication against a docker client. +new=New +copy=Copy +add-execution=Add execution +add-flow=Add flow +auth-type=Auth Type +requirement=Requirement +config=Config +no-executions-available=No executions available +authentication-flows=Authentication Flows +create-authenticator-config=Create authenticator config +authenticator.alias.tooltip=Name of the configuration +otp-type=OTP Type +time-based=Time Based +counter-based=Counter Based +otp-type.tooltip=totp is Time-Based One Time Password. 'hotp' is a counter base one time password in which the server keeps a counter to hash against. +otp-hash-algorithm=OTP Hash Algorithm +otp-hash-algorithm.tooltip=What hashing algorithm should be used to generate the OTP. +number-of-digits=Number of Digits +otp.number-of-digits.tooltip=How many digits should the OTP have? +look-ahead-window=Look Ahead Window +otp.look-ahead-window.tooltip=How far ahead should the server look just in case the token generator and server are out of counter sync? +look-around-window=Look Around Window +otp.look-around-window.tooltip=How far should the server look around just in case the token generator and server are out of time sync? +initial-counter=Initial Counter +otp.initial-counter.tooltip=What should the initial counter value be? +otp-token-period=OTP Token Period +otp-token-period.tooltip=How many seconds should an OTP token be valid? Defaults to 30 seconds. +otp-supported-applications=Supported Applications +otp-supported-applications.tooltip=Applications that are known to work with the current OTP policy +loa-level=Level of Authentication +loa-level.tooltip=Sets the Level of Authentication to the specified value. +loa-max-age=Max Age +loa-max-age.tooltip=Maximum age in seconds for which this level is considered valid after successful authentication. For example if this is set to 300 and user authenticated with this level and then tries to authenticate again in less than 300 second, then this level will be automatically considered as authenticated without need of user to re-authenticate. If it is set to 0, then the authenticated level is valid just for this authentication and next authentication will always need to re-authenticate. Default value is 10 hours, which is same as default SSO session timeout and it means that level is valid until end of SSO session and user doesn't need to re-authenticate. +loa-condition-level=Level of Authentication (LoA) +loa-condition-level.tooltip=The number value, usually 1 or bigger, which specifies level of authentication. Condition evaluates to true if user does not yet have this authentication level and this level is requested. This level of authentication will be set to the session after the subflow, where this condition is configured, is successfully finished. +table-of-password-policies=Table of Password Policies +add-policy.placeholder=Add policy... +policy-type=Policy Type +policy-value=Policy Value +webauthn-policy=WebAuthn Policy +webauthn-policy.tooltip=Policy for WebAuthn authentication. This one will be used by 'WebAuthn Register' required action and 'WebAuthn Authenticator' authenticator. Typical usage is, when WebAuthn will be used for the two-factor authentication. +webauthn-policy-passwordless=WebAuthn Passwordless Policy +webauthn-policy-passwordless.tooltip=Policy for passwordless WebAuthn authentication. This one will be used by 'Webauthn Register Passwordless' required action and 'WebAuthn Passwordless Authenticator' authenticator. Typical usage is, when WebAuthn will be used as first-factor authentication. Having both 'WebAuthn Policy' and 'WebAuthn Passwordless Policy' allows to use WebAuthn as both first factor and second factor authenticator in the same realm. +webauthn-rp-entity-name=Relying Party Entity Name +webauthn-rp-entity-name.tooltip=Human-readable server name as WebAuthn Relying Party +webauthn-signature-algorithms=Signature Algorithms +webauthn-signature-algorithms.tooltip=What signature algorithms should be used for Authentication Assertion. +webauthn-rp-id=Relying Party ID +webauthn-rp-id.tooltip=This is ID as WebAuthn Relying Party. It must be origin's effective domain. +webauthn-attestation-conveyance-preference=Attestation Conveyance Preference +webauthn-attestation-conveyance-preference.tooltip=Communicates to an authenticator the preference of how to generate an attestation statement. +webauthn-authenticator-attachment=Authenticator Attachment +webauthn-authenticator-attachment.tooltip=Communicates to an authenticator an acceptable attachment pattern. +webauthn-require-resident-key=Require Resident Key +webauthn-require-resident-key.tooltip=It tells an authenticator create a public key credential as Resident Key or not. +webauthn-user-verification-requirement=User Verification Requirement +webauthn-user-verification-requirement.tooltip=Communicates to an authenticator to confirm actually verifying a user. +webauthn-create-timeout=Timeout +webauthn-create-timeout.tooltip=Timeout value for creating user's public key credential in seconds. if set to 0, this timeout option is not adapted. +webauthn-avoid-same-authenticator-register=Avoid Same Authenticator Registration +webauthn-avoid-same-authenticator-register.tooltip=avoid registering the authenticator that has already been registered. +webauthn-acceptable-aaguids=Acceptable AAGUIDs +webauthn-acceptable-aaguids.tooltip=The list of AAGUID of which an authenticator can be registered. +manage-webauthn-authenticator=Manage WebAuthn Authenticator +public-key-credential-id=Public Key Credential ID +public-key-credential-aaguid=Public Key Credential AAGUID +public-key-credential-label=Public Key Credential Label +ciba-policy=CIBA Policy +ciba-backchannel-tokendelivery-mode=Backchannel Token Delivery Mode +ciba-backchannel-tokendelivery-mode.tooltip=Specifies how the CD(Consumption Device) gets the authentication result and related tokens. This mode will be used by default for the CIBA clients, which do not have other mode explicitly set. The default mode is 'poll'. +ciba-expires-in=Expires In +ciba-expires-in.tooltip=The expiration time of the "auth_req_id" in seconds since the authentication request was received. +ciba-interval=Interval +ciba-interval.tooltip=The minimum amount of time in seconds that the CD(Consumption Device) must wait between polling requests to the token endpoint. +ciba-auth-requested-user-hint=Authentication Requested User Hint +ciba-auth-requested-user-hint.tooltip=The way of identifying the end-user for whom authentication is being requested. +admin-events=Admin Events +admin-events.tooltip=Displays saved admin events for the realm. Events are related to admin account, for example a realm creation. To enable persisted events go to config. +login-events=Login Events +filter=Filter +update=Update +reset=Reset +operation-types=Operation Types +resource-types=Resource Types +select-operations.placeholder=Select operations... +select-resource-types.placeholder=Select resource types... +resource-path=Resource Path +resource-path.tooltip=Filter by resource path. Supports wildcard '*' (for example 'users/*'). +date-(from)=Date (From) +date-(to)=Date (To) +authentication-details=Authentication Details +ip-address=IP Address +time=Time +operation-type=Operation Type +resource-type=Resource Type +auth=Auth +representation=Representation +register=Register +required-action=Required Action +default-action=Default Action +auth.default-action.tooltip=If enabled, any new user will have this required action assigned to it. +no-required-actions-configured=No required actions configured +defaults-to-id=Defaults to id +flows=Flows +bindings=Bindings +client-flow-bindings=Authentication Flow Overrides +client-flow-bindings.tooltip=Override realm authentication flow bindings. +required-actions=Required Actions +password-policy=Password Policy +otp-policy=OTP Policy +user-groups=User Groups +default-groups=Default Groups +groups.default-groups.tooltip=Set of groups that new users will automatically join. +cut=Cut +paste=Paste +create-group=Create group +create-authenticator-execution=Create Authenticator Execution +edit-flow=Edit Flow +create-form-action-execution=Create Form Action Execution +create-top-level-form=Create Top Level Form +flow.alias.tooltip=Specifies display name for the flow. +top-level-flow-type=Top Level Flow Type +flow.generic=generic +flow.client=client +top-level-flow-type.tooltip=What kind of top level flow is it? Type 'client' is used for authentication of clients (applications) when generic is for users and everything else +create-execution-flow=Create Execution Flow +flow-type=Flow Type +flow.form.type=form +flow.generic.type=generic +flow-type.tooltip=What kind of form is it +form-provider=Form Provider +default-groups.tooltip=Newly created or registered users will automatically be added to these groups +select-a-type.placeholder=select a type +available-groups=Available Groups +available-groups.tooltip=Select a group you want to add as a default. +value=Value +table-of-group-members=Table of group members +table-of-role-members=Table of role members +last-name=Last Name +first-name=First Name +email=Email +toggle-navigation=Toggle navigation +manage-account=Manage account +sign-out=Sign Out +server-info=Server Info +resource-not-found=Resource not found... +resource-not-found.instruction=We could not find the resource you are looking for. Please make sure the URL you entered is correct. +go-to-the-home-page=Go to the home page » +page-not-found=Page not found... +page-not-found.instruction=We could not find the page you are looking for. Please make sure the URL you entered is correct. +events.tooltip=Displays saved events for the realm. Events are related to user accounts, for example a user login. To enable persisted events go to config. +select-event-types.placeholder=Select event types... +events-config.tooltip=Displays configuration options to enable persistence of user and admin events. +select-an-action.placeholder=Select an action... +event-listeners.tooltip=Configure what listeners receive events for the realm. +login.save-events.tooltip=If enabled, login events are saved to the database, which makes events available to the admin and account management consoles. +clear-events.tooltip=Deletes all events in the database. +events.expiration.tooltip=Sets the expiration for events. Expired events are periodically deleted from the database. +admin-events-settings=Admin Events Settings +save-events=Save Events +admin.save-events.tooltip=If enabled, admin events are saved to the database, which makes events available to the admin console. +saved-types.tooltip=Configure what event types are saved. +include-representation=Include Representation +include-representation.tooltip=Include JSON representation for create and update requests. +clear-admin-events.tooltip=Deletes all admin events in the database. +server-version=Server Version +server-profile=Server Profile +server-disabled=Disabled Features +server-disabled.tooltip=Features that are not currently enabled. Some features are not enabled by default. This applies to all preview and experimental features. +server-preview=Preview Features +server-preview.tooltip=Preview features are not supported in production use and may be significantly changed or removed in the future. +server-experimental=Experimental Features +server-experimental.tooltip=Experimental features, which may not be fully functional. Never use experimental features in production. +info=Info +providers=Providers +server-time=Server Time +server-uptime=Server Uptime +profile=Profile +memory=Memory +total-memory=Total Memory +free-memory=Free Memory +used-memory=Used Memory +system=System +current-working-directory=Current Working Directory +java-version=Java Version +java-vendor=Java Vendor +java-runtime=Java Runtime +java-vm=Java VM +java-vm-version=Java VM Version +java-home=Java Home +user-name=User Name +user-timezone=User Timezone +user-locale=User Locale +system-encoding=System Encoding +operating-system=Operating System +os-architecture=OS Architecture +spi=SPI +granted-client-scopes=Granted Client Scopes +additional-grants=Additional Grants +consent-created-date=Created +consent-last-updated-date=Last updated +revoke=Revoke +new-password=New Password +password-confirmation=Password Confirmation +reset-password=Reset Password +set-password=Set Password +credentials.temporary.tooltip=If enabled, the user must change the password on next login +remove-totp=Remove OTP +credentials.remove-totp.tooltip=Remove one time password generator for user. +reset-actions=Reset Actions +credentials.reset-actions.tooltip=Set of actions to execute when sending the user a Reset Actions Email. 'Verify email' sends an email to the user to verify their email address. 'Update profile' requires user to enter in new personal information. 'Update password' requires user to enter in a new password. 'Configure OTP' requires setup of a mobile password generator. +reset-actions-email=Reset Actions Email +send-email=Send email +credentials.reset-actions-email.tooltip=Sends an email to user with an embedded link. Clicking the link enables the user to execute the reset actions without first logging in. For example, set the action to update password, click this button, and the user can change the password without logging in. +add-user=Add user +created-at=Created At +user-enabled=User Enabled +user-enabled.tooltip=A disabled user cannot login. +user-temporarily-locked=User Temporarily Locked +user-temporarily-locked.tooltip=The user may be locked due to multiple failed attempts to log in. +unlock-user=Unlock user +federation-link=Federation Link +email-verified=Email Verified +email-verified.tooltip=Has the user's email been verified? +groups-joining=Groups +groups-joining.tooltip=Groups the user will be joining. To add a group, search for any existing one and select it. +groups-joining-select.placeholder=Select existing group +groups-joining-no-selected=No group selected +groups-joining-path=Path +required-user-actions=Required User Actions +required-user-actions.tooltip=Require an action when the user logs in. 'Verify email' sends an email to the user to verify their email address. 'Update profile' requires user to enter in new personal information. 'Update password' requires user to enter in a new password. 'Configure OTP' requires setup of a mobile password generator. +locale=Locale +select-one.placeholder=Select one... +impersonate=Impersonate +impersonate-user=Impersonate user +impersonate-user.tooltip=Login as this user. If user is in same realm as you, your current login session will be logged out before you are logged in as this user. +identity-provider-alias=Identity Provider Alias +provider-user-id=Provider User ID +provider-username=Provider Username +no-identity-provider-links-available=No identity provider links available +group-membership=Group Membership +leave=Leave +group-membership.tooltip=Groups where the user has membership. To leave a group, select it and click Leave. +membership.available-groups.tooltip=Groups a user can join. Select a group and click Join. +table-of-realm-users=Table of Realm Users +view-all-users=View all users +view-all-groups=View all groups +view-all-roles=View all roles +unlock-users=Unlock users +no-users-available=No users available +users.instruction=Please enter a search, or click on view all users +clients.instruction=Please enter a search +consents=Consents +started=Started +logout-all-sessions=Log out all sessions +logout=Logout +new-name=New Name +new-description=New Description +ok=Ok +attributes=Attributes +role-mappings=Role Mappings +members=Members +details=Details +identity-provider-links=Identity Provider Links +register-required-action=Register required action +gender=Gender +address=Address +phone=Phone +profile-url=Profile URL +picture-url=Picture URL +website=Website +import-keys-and-cert=Import keys and cert +import-keys-and-cert.tooltip=Upload the client's key pair and cert. +upload-keys=Upload Keys +download-keys-and-cert=Download keys and cert +no-value-assigned.placeholder=No value assigned +remove=Remove +no-group-members=No group members +no-role-members=No role members +temporary=Temporary +join=Join +event-type=Event Type +events-config=Events Config +event-listeners=Event Listeners +login-events-settings=Login Events Settings +clear-events=Clear events +saved-types=Saved Types +clear-admin-events=Clear admin events +clear-changes=Clear changes +error=Error +# Authz +# Authz Common +authz-authorization=Authorization +authz-owner=Owner +authz-uri=URI +authz-uris=URIS +authz-scopes=Scopes +authz-resource=Resource +authz-resource-type=Resource Type +authz-resources=Resources +authz-scope=Scope +authz-authz-scopes=Authorization Scopes +authz-policies=Policies +authz-policy=Policy +authz-permissions=Permissions +authz-users=Users in Role +authz-evaluate=Evaluate +authz-icon-uri=Icon URI +authz-icon-uri.tooltip=An URI pointing to an icon. +authz-select-scope=Select a scope +authz-select-resource=Select a resource +authz-associated-policies=Associated Policies +authz-any-resource=Any resource +authz-any-scope=Any scope +authz-any-role=Any role +authz-policy-evaluation=Policy Evaluation +authz-select-user=Select a user +authz-select-client=Select a client +authz-entitlements=Entitlements +authz-no-resources=No resources +authz-result=Result +authz-authorization-services-enabled=Authorization Enabled +authz-authorization-services-enabled.tooltip=Enable/Disable fine-grained authorization support for a client +authz-required=Required +authz-show-details=Show Details +authz-hide-details=Hide Details +authz-associated-permissions=Associated Permissions +authz-no-permission-associated=No permissions associated +# Authz Settings +authz-import-config.tooltip=Import a JSON file containing authorization settings for this resource server. +authz-policy-enforcement-mode=Policy Enforcement Mode +authz-policy-enforcement-mode.tooltip=The policy enforcement mode dictates how policies are enforced when evaluating authorization requests. 'Enforcing' means requests are denied by default even when there is no policy associated with a given resource. 'Permissive' means requests are allowed even when there is no policy associated with a given resource. 'Disabled' completely disables the evaluation of policies and allows access to any resource. +authz-policy-enforcement-mode-enforcing=Enforcing +authz-policy-enforcement-mode-permissive=Permissive +authz-policy-enforcement-mode-disabled=Disabled +authz-remote-resource-management=Remote Resource Management +authz-remote-resource-management.tooltip=Should resources be managed remotely by the resource server? If false, resources can be managed only from this admin console. +authz-export-settings=Export Settings +authz-export-settings.tooltip=Export and download all authorization settings for this resource server. +authz-server-decision-strategy.tooltip=The decision strategy dictates how permissions are evaluated and how a final decision is obtained. 'Affirmative' means that at least one permission must evaluate to a positive decision in order to grant access to a resource and its scopes. 'Unanimous' means that all permissions must evaluate to a positive decision in order for the final decision to be also positive. +# Authz Resource List +authz-no-resources-available=No resources available. +authz-no-scopes-assigned=No scopes assigned. +authz-no-type-defined=No type defined. +authz-no-uri-defined=No URI defined. +authz-no-permission-assigned=No permission assigned. +authz-no-policy-assigned=No policy assigned. +authz-create-permission=Create Permission +# Authz Resource Detail +authz-add-resource=Add Resource +authz-resource-name.tooltip=A unique name for this resource. The name can be used to uniquely identify a resource, useful when querying for a specific resource. +authz-resource-owner.tooltip=The owner of this resource. +authz-resource-type.tooltip=The type of this resource. It can be used to group different resource instances with the same type. +authz-resource-uri.tooltip=Set of URIs which are protected by resource. +authz-resource-scopes.tooltip=The scopes associated with this resource. +authz-resource-attributes=Resource Attributes +authz-resource-attributes.tooltip=The attributes associated wth the resource. +authz-resource-user-managed-access-enabled=User-Managed Access Enabled +authz-resource-user-managed-access-enabled.tooltip=If enabled, the access to this resource can be managed by the resource owner. + +# Authz Scope List +authz-add-scope=Add Scope +authz-no-scopes-available=No scopes available. +# Authz Scope Detail +authz-scope-name.tooltip=A unique name for this scope. The name can be used to uniquely identify a scope, useful when querying for a specific scope. +# Authz Policy List +authz-all-types=All types +authz-create-policy=Create Policy +authz-no-policies-available=No policies available. +# Authz Policy Detail +authz-policy-name.tooltip=The name of this policy. +authz-policy-description.tooltip=A description for this policy. +authz-policy-logic=Logic +authz-policy-logic-positive=Positive +authz-policy-logic-negative=Negative +authz-policy-logic.tooltip=The logic dictates how the policy decision should be made. If 'Positive', the resulting effect (permit or deny) obtained during the evaluation of this policy will be used to perform a decision. If 'Negative', the resulting effect will be negated, in other words, a permit becomes a deny and vice-versa. +authz-policy-apply-policy=Apply Policy +authz-policy-apply-policy.tooltip=Specifies all the policies that must be applied to the scopes defined by this policy or permission. +authz-policy-decision-strategy=Decision Strategy +authz-policy-decision-strategy.tooltip=The decision strategy dictates how the policies associated with a given permission are evaluated and how a final decision is obtained. 'Affirmative' means that at least one policy must evaluate to a positive decision in order for the final decision to be also positive. 'Unanimous' means that all policies must evaluate to a positive decision in order for the final decision to be also positive. 'Consensus' means that the number of positive decisions must be greater than the number of negative decisions. If the number of positive and negative is the same, the final decision will be negative. +authz-policy-decision-strategy-affirmative=Affirmative +authz-policy-decision-strategy-unanimous=Unanimous +authz-policy-decision-strategy-consensus=Consensus +authz-select-a-policy=Select existing policy +authz-no-policies-assigned=No policies assigned. +# Authz Role Policy Detail +authz-add-role-policy=Add Role Policy +authz-no-roles-assigned=No roles assigned. +authz-policy-role-realm-roles.tooltip=Specifies the *realm* roles allowed by this policy. +authz-policy-role-clients.tooltip=Selects a client in order to filter the client roles that can be applied to this policy. +authz-policy-role-client-roles.tooltip=Specifies the client roles allowed by this policy. +# Authz User Policy Detail +authz-add-user-policy=Add User Policy +authz-no-users-assigned=No users assigned. +authz-policy-user-users.tooltip=Specifies which user(s) are allowed by this policy. +# Authz Client Policy Detail +authz-add-client-policy=Add Client Policy +authz-no-clients-assigned=No clients assigned. +authz-policy-client-clients.tooltip=Specifies which client(s) are allowed by this policy. +# Authz Time Policy Detail +authz-add-time-policy=Add Time Policy +authz-policy-time-not-before.tooltip=Defines the time before which the policy MUST NOT be granted. Only granted if current date/time is after or equal to this value. +authz-policy-time-not-on-after=Not On or After +authz-policy-time-not-on-after.tooltip=Defines the time after which the policy MUST NOT be granted. Only granted if current date/time is before or equal to this value. +authz-policy-time-day-month=Day of Month +authz-policy-time-day-month.tooltip=Defines the day of month when the policy MUST be granted. You can also provide a range by filling the second field. In this case, permission is granted only if current day of month is between or equal to the two values you provided. +authz-policy-time-month=Month +authz-policy-time-month.tooltip=Defines the month which the policy MUST be granted. You can also provide a range by filling the second field. In this case, permission is granted only if current month is between or equal to the two values you provided. +authz-policy-time-year=Year +authz-policy-time-year.tooltip=Defines the year when the policy MUST be granted. You can also provide a range by filling the second field. In this case, permission is granted only if current year is between or equal to the two values you provided. +authz-policy-time-hour=Hour +authz-policy-time-hour.tooltip=Defines the hour when the policy MUST be granted. You can also provide a range by filling the second field. In this case, permission is granted only if current hour is between or equal to the two values you provided. +authz-policy-time-minute=Minute +authz-policy-time-minute.tooltip=Defines the minute when the policy MUST be granted. You can also provide a range by filling the second field. In this case, permission is granted only if current minute is between or equal to the two values you provided. +# Authz JS Policy Detail +authz-add-js-policy=Add JavaScript Policy +authz-policy-js-code=Code +authz-policy-js-code.tooltip=The JavaScript code providing the conditions for this policy. +# Authz Aggregated Policy Detail +authz-aggregated=Aggregated +authz-add-aggregated-policy=Add Aggregated Policy +# Authz Group Policy Detail +authz-add-group-policy=Add Group Policy +authz-no-groups-assigned=No groups assigned. +authz-policy-group-claim=Groups Claim +authz-policy-group-claim.tooltip=If defined, the policy will fetch user's groups from the given claim within an access token or ID token representing the identity asking permissions. If not defined, user's groups are obtained from your realm configuration. +authz-policy-group-groups.tooltip=Specifies the groups allowed by this policy. +# Authz Client Scope Policy Detail +authz-add-client-scope-policy=Add Client Scope Policy +authz-no-client-scopes-assigned=No client scopes assigned. +authz-policy-client-scope-client-scopes.tooltip=Specifies which client scope(s) are allowed by this policy. +select-a-client-scope=Select a client scope +# Authz Regex Policy Detail +authz-add-regex-policy=Add Regex Policy +regex=Regex +authz-policy-target-claim=Target Claim +authz-policy-target-claim.tooltip=Specifies the target claim which the policy will fetch. +authz-policy-regex-pattern=Regex Pattern +authz-policy-regex-pattern.tooltip=Specifies the regex pattern. + +# Authz Permission List +authz-no-permissions-available=No permissions available. + +# Authz Permission Detail +authz-permission-name.tooltip=The name of this permission. +authz-permission-description.tooltip=A description for this permission. + +# Authz Resource Permission Detail +authz-add-resource-permission=Add Resource Permission +authz-permission-resource-apply-to-resource-type=Apply to Resource Type +authz-permission-resource-apply-to-resource-type.tooltip=Specifies if this permission should be applied to all resources with a given type. In this case, this permission will be evaluated for all instances of a given resource type. +authz-permission-resource-resource.tooltip=Specifies that this permission must be applied to a specific resource instance. +authz-permission-resource-type.tooltip=Specifies that this permission must be applied to all resources instances of a given type. + +# Authz Scope Permission Detail +authz-add-scope-permission=Add Scope Permission +authz-permission-scope-resource.tooltip=Restrict the scopes to those associated with the selected resource. If not selected all scopes would be available. +authz-permission-scope-scope.tooltip=Specifies that this permission must be applied to one or more scopes. + +# Authz Evaluation +authz-evaluation-identity-information=Identity Information +authz-evaluation-identity-information.tooltip=The available options to configure the identity information that will be used when evaluating policies. +authz-evaluation-client.tooltip=Select the client making this authorization request. If not provided, authorization requests would be done based on the client you are in. +authz-evaluation-user.tooltip=Select a user whose identity is going to be used to query permissions from the server. +authz-evaluation-role.tooltip=Select the roles you want to associate with the selected user. +authz-evaluation-new=New Evaluation +authz-evaluation-re-evaluate=Re-Evaluate +authz-evaluation-previous=Previous Evaluation +authz-evaluation-contextual-info=Contextual Information +authz-evaluation-contextual-info.tooltip=The available options to configure any contextual information that will be used when evaluating policies. +authz-evaluation-contextual-attributes=Contextual Attributes +authz-evaluation-contextual-attributes.tooltip=Any attribute provided by a running environment or execution context. +authz-evaluation-permissions.tooltip=The available options to configure the permissions to which policies will be applied. +authz-evaluation-evaluate=Evaluate +authz-evaluation-any-resource-with-scopes=Any resource with scope(s) +authz-evaluation-no-result=Could not obtain any result for the given authorization request. Check if the provided resource(s) or scope(s) are associated with any policy. +authz-evaluation-no-policies-resource=No policies were found for this resource. +authz-evaluation-result.tooltip=The overall result for this permission request. +authz-evaluation-scopes.tooltip=The list of allowed scopes. +authz-evaluation-policies.tooltip=Details about which policies were evaluated and their decisions. +authz-evaluation-authorization-data=Response +authz-evaluation-authorization-data.tooltip=Represents a token carrying authorization data as a result of the processing of an authorization request. This representation is basically what Keycloak issues to clients asking for permissions. Check the 'authorization' claim for the permissions that were granted based on the current authorization request. +authz-show-authorization-data=Show Authorization Data + +keys=Keys +status=Status +keystore=Keystore +keystores=Keystores +add-keystore=Add Keystore +add-keystore.placeholder=Add keystore... +view=View +active=Active +passive=Passive +disabled=Disabled +algorithm=Algorithm +providerHelpText=Provider description + +Sunday=Sunday +Monday=Monday +Tuesday=Tuesday +Wednesday=Wednesday +Thursday=Thursday +Friday=Friday +Saturday=Saturday + +user-storage-cache-policy=Cache Settings +userStorage.cachePolicy=Cache Policy +userStorage.cachePolicy.option.DEFAULT=DEFAULT +userStorage.cachePolicy.option.EVICT_WEEKLY=EVICT_WEEKLY +userStorage.cachePolicy.option.EVICT_DAILY=EVICT_DAILY +userStorage.cachePolicy.option.MAX_LIFESPAN=MAX_LIFESPAN +userStorage.cachePolicy.option.NO_CACHE=NO_CACHE +userStorage.cachePolicy.tooltip=Cache Policy for this storage provider. 'DEFAULT' is whatever the default settings are for the global cache. 'EVICT_DAILY' is a time of day every day that the cache will be invalidated. 'EVICT_WEEKLY' is a day of the week and time the cache will be invalidated. 'MAX-LIFESPAN' is the time in milliseconds that will be the lifespan of a cache entry. +userStorage.cachePolicy.evictionDay=Eviction Day +userStorage.cachePolicy.evictionDay.tooltip=Day of the week the entry will become invalid on +userStorage.cachePolicy.evictionHour=Eviction Hour +userStorage.cachePolicy.evictionHour.tooltip=Hour of day the entry will become invalid on. +userStorage.cachePolicy.evictionMinute=Eviction Minute +userStorage.cachePolicy.evictionMinute.tooltip=Minute of day the entry will become invalid on. +userStorage.cachePolicy.maxLifespan=Max Lifespan +userStorage.cachePolicy.maxLifespan.tooltip=Max lifespan of cache entry in milliseconds. +user-origin-link=Storage Origin +user-origin.tooltip=UserStorageProvider the user was loaded from +user-link.tooltip=UserStorageProvider this locally stored user was imported from. +client-origin-link=Storage Origin +client-origin.tooltip=Provider the client was loaded from + +client-storage-cache-policy=Cache Settings +clientStorage.cachePolicy=Cache Policy +clientStorage.cachePolicy.option.DEFAULT=DEFAULT +clientStorage.cachePolicy.option.EVICT_WEEKLY=EVICT_WEEKLY +clientStorage.cachePolicy.option.EVICT_DAILY=EVICT_DAILY +clientStorage.cachePolicy.option.MAX_LIFESPAN=MAX_LIFESPAN +clientStorage.cachePolicy.option.NO_CACHE=NO_CACHE +clientStorage.cachePolicy.tooltip=Cache Policy for this storage provider. 'DEFAULT' is whatever the default settings are for the global cache. 'EVICT_DAILY' is a time of day every day that the cache will be invalidated. 'EVICT_WEEKLY' is a day of the week and time the cache will be invalidated. 'MAX-LIFESPAN' is the time in milliseconds that will be the lifespan of a cache entry. +clientStorage.cachePolicy.evictionDay=Eviction Day +clientStorage.cachePolicy.evictionDay.tooltip=Day of the week the entry will become invalid on +clientStorage.cachePolicy.evictionHour=Eviction Hour +clientStorage.cachePolicy.evictionHour.tooltip=Hour of day the entry will become invalid on. +clientStorage.cachePolicy.evictionMinute=Eviction Minute +clientStorage.cachePolicy.evictionMinute.tooltip=Minute of day the entry will become invalid on. +clientStorage.cachePolicy.maxLifespan=Max Lifespan +clientStorage.cachePolicy.maxLifespan.tooltip=Max lifespan of cache entry in milliseconds. + +client-storage-list-no-entries=Keycloak can federate external client databases. By default, we support Openshift OAuth clients and service accounts. To get started, select a provider from the dropdown below: + + +disable=Disable +disableable-credential-types=Disableable Types +credentials.disableable.tooltip=List of credential types that you can disable +disable-credential-types=Disable Credential Types +credentials.disable.tooltip=Click button to disable selected credential types +credential-types=Credential Types +manage-user-password=Manage Password +supported-user-storage-credential-types=Supported User Storage Credential Types +supported-user-storage-credential-types.tooltip=Credential types, which are provided by User Storage Provider and which are configured for this user. Validation and eventually update of the credentials of those types can be delegated to the User Storage Provider based on the configuration and implementation of the particular provider. +provided-by=Provided By +manage-credentials=Manage Credentials +manage-credentials.tooltip=Credentials, which are not provided by the user storage. They are saved in the local database. +disable-credentials=Disable Credentials +credential-reset-actions=Credential Reset +credential-reset-actions-timeout=Expires In +credential-reset-actions-timeout.tooltip=Maximum time before the action permit expires. +ldap-mappers=LDAP Mappers +create-ldap-mapper=Create LDAP mapper +map-role-mgmt-scope-description=Policies that decide if an administrator can map this role to a user or group +manage-authz-users-scope-description=Policies that decide if an administrator can manage all users in the realm +view-authz-users-scope-description=Policies that decide if an administrator can view all users in realm +permissions-enabled-role=Permissions Enabled +permissions-enabled-role.tooltip=Determines if fine grained permissions are enabled for managing this role. Disabling will delete all current permissions that have been set up. +manage-permissions-role.tooltip=Fine grained permissions for managing roles. For example, you can define different policies for who is allowed to map a role. +lookup=Lookup +manage-permissions-users.tooltip=Fine grained permissions for managing all users in realm. You can define different policies for who is allowed to manage users in the realm. +permissions-enabled-users=Permissions Enabled +permissions-enabled-users.tooltip=Determines if fined grain permissions are enabled for managing users. Disabling will delete all current permissions that have been set up. +manage-permissions-client.tooltip=Fine grained permissions for administrators that want to manage this client or apply roles defined by this client. +manage-permissions-group.tooltip=Fine grained permissions for administrators that want to manage this group or the members of this group. +manage-authz-group-scope-description=Policies that decide if an administrator can manage this group +view-authz-group-scope-description=Policies that decide if an administrator can view this group +view-members-authz-group-scope-description=Policies that decide if an administrator can view the members of this group +token-exchange-authz-client-scope-description=Policies that decide which clients are allowed exchange tokens for a token that is targeted to this client. +token-exchange-authz-idp-scope-description=Policies that decide which clients are allowed exchange tokens for an external token minted by this identity provider. +manage-authz-client-scope-description=Policies that decide if an administrator can manage this client +configure-authz-client-scope-description=Reduced management permissions for administrator. Cannot set scope, template, or protocol mappers. +view-authz-client-scope-description=Policies that decide if an administrator can view this client +map-roles-authz-client-scope-description=Policies that decide if an administrator can map roles defined by this client +map-roles-client-scope-authz-client-scope-description=Policies that decide if an administrator can apply roles defined by this client to the client scope of another client +map-roles-composite-authz-client-scope-description=Policies that decide if an administrator can apply roles defined by this client as a composite to another role +map-role-authz-role-scope-description=Policies that decide if an administrator can map this role to a user or group +map-role-client-scope-authz-role-scope-description=Policies that decide if an administrator can apply this role to the client scope of a client +map-role-composite-authz-role-scope-description=Policies that decide if an administrator can apply this role as a composite to another role +manage-group-membership-authz-users-scope-description=Policies that decide if an administrator can manage group membership for all users in the realm. This is used in conjunction with specific group policy +impersonate-authz-users-scope-description=Policies that decide if administrator can impersonate other users +map-roles-authz-users-scope-description=Policies that decide if administrator can map roles for all users +user-impersonated-authz-users-scope-description=Policies that decide which users can be impersonated. These policies are applied to the user being impersonated. +manage-membership-authz-group-scope-description=Policies that decide if an administrator can add or remove users from this group +manage-members-authz-group-scope-description=Policies that decide if an administrator can manage the members of this group + +# KEYCLOAK-6771 Certificate Bound Token +# https://tools.ietf.org/html/draft-ietf-oauth-mtls-08#section-3 +advanced-client-settings=Advanced Settings +advanced-client-settings.tooltip=Expand this section to configure advanced settings of this client +tls-client-certificate-bound-access-tokens=OAuth 2.0 Mutual TLS Certificate Bound Access Tokens Enabled +tls-client-certificate-bound-access-tokens.tooltip=This enables support for OAuth 2.0 Mutual TLS Certificate Bound Access Tokens, which means that keycloak bind an access token and a refresh token with a X.509 certificate of a token requesting client exchanged in mutual TLS between keycloak's Token Endpoint and this client. These tokens can be treated as Holder-of-Key tokens instead of bearer tokens. + +# PAR request parameters. +require-pushed-authorization-requests=Pushed Authorization Request Required +require-pushed-authorization-requests.tooltip=Boolean parameter indicating whether the authorization server accepts authorization request data only via the pushed authorization request method. +request-uri-lifespan=Lifetime of the Request URI for Pushed Authorization Request +request-uri-lifespan.tooltip=Number that represents the lifetime of the request URI in minutes or hours, the default value is 1 minute. + +subjectdn=Subject DN +subjectdn-tooltip=The expected Subject DN, which should match DN from client certificate. In case that 'Allow Regex Pattern Comparison' allowed, this can contain regular expression for validating Subject DN in the Client Certificate. Use "(.*?)(?:$)" to match all kind of expressions. +allow-regex-pattern-comparison=Allow Regex Pattern Comparison +allow-regex-pattern-comparison.tooltip=If OFF, then the Subject DN from given client certificate must exactly match the given DN from the 'Subject DN' property as described in the RFC8705 specification. The Subject DN can be in the RFC2553 or RFC1779 format. If ON, then the Subject DN from given client certificate should match regex specified by 'Subject DN' property. + +pkce-code-challenge-method=Proof Key for Code Exchange Code Challenge Method +pkce-code-challenge-method.tooltip=Choose which code challenge method for PKCE is used. If not specified, keycloak does not applies PKCE to a client unless the client sends an authorization request with appropriate code challenge and code exchange method. + +use-idtoken-as-detached-signature=Use ID Token as a Detached Signature +use-idtoken-as-detached-signature.tooltip=This makes ID token returned from Authorization Endpoint in OIDC Hybrid flow use as a detached signature defined in FAPI 1.0 Advanced Security Profile. Therefore, this ID token does not include an authenticated user's information. + +acr-loa-map=ACR to LoA Mapping +acr-loa-map.tooltip=Define which ACR (Authentication Context Class Reference) value is mapped to which LoA (Level of Authentication). The ACR can be any value, whereas the LoA must be numeric. The LoA typically refers to the numbers configured as levels in the conditions in the authentication flow. The ACR refers to the value used in the OIDC/SAML authorization request and returned to client in the tokens. +acr-loa-map-client.tooltip=Define which ACR (Authentication Context Class Reference) value is mapped to which LoA (Level of Authentication). The ACR can be any value, whereas the LoA must be numeric. This is recommended to be configured at the realm level where it is shared for all the clients. If you configure at the client level, the client mapping will take precedence over the mapping from the realm level. +default-acr-values=Default ACR Values +default-acr-values.tooltip=Default values to be used as voluntary ACR in case that there is no explicit ACR requested by 'claims' or 'acr_values' parameter in the OIDC request. + +key-not-allowed-here=Key '{{character}}' is not allowed here. + +# KEYCLOAK-10927 Implement LDAPv3 Password Modify Extended Operation +advanced-ldap-settings=Advanced Settings +ldap-query-supported-extensions=Query Supported Extensions +ldap-query-supported-extensions.tooltip=This will query LDAP server for supported extensions, controls and features. Some advanced settings of the LDAP provider will be then automatically configured based on the capabilities/extensions/features supported by LDAP server. For example if LDAPv3 Password Modify extension is supported by LDAP server, corresponding switch will be enabled for LDAP provider. + +notifications.info.header=Info! +notifications.success.header=Success! +notifications.error.header=Error! +notifications.warn.header=Warning! + +dialogs.delete.title=Delete {{type}} +dialogs.delete.message=Are you sure you want to permanently delete the {{type}} {{name}}? +dialogs.delete.confirm=Delete +dialogs.cancel=Cancel +dialogs.ok=Ok +use=Use + +user.profile.attribute=Attribute +user.profile.attribute.name=Name +user.profile.attribute.name.tooltip=The name of the attribute. +user.profile.attribute.displayName=Display name +user.profile.attribute.displayName.tooltip=Display name for the attribute. Supports keys for localized values as well. For example\: ${profile.attribute.phoneNumber}. +user.profile.attribute.selector.scopes=Enabled when scope +user.profile.attribute.selector.scopes.tooltip=Set the attribute as enabled only when a set of one or more scopes are requested by clients. This constraint only applies to flows where clients are able to ask for scopes (e.g.: during login or registration). +user.profile.attribute.required=Required +user.profile.attribute.required.tooltip=Set the attribute as required. If enabled, the attribute must be set by users and administrators. Otherwise, the attribute is optional. +user.profile.attribute.required.roles=Required for roles +user.profile.attribute.required.roles.tooltip=Set the attribute as required for specific types of users. If set to 'user', the attribute is required for users. If set to 'admin' the attribute is required only for administrators. +user.profile.attribute.required.scopes=Required for scopes +user.profile.attribute.required.scopes.tooltip=Set the attribute as required only when a set of one or more scopes are requested by clients. This constraint only applies to flows where clients are able to ask for scopes (e.g.: during login or registration). +user.profile.attribute.permission=Permission +user.profile.attribute.canUserView=Can user view? +user.profile.attribute.canUserView.tooltip=If enabled, users can view the attribute. Otherwise, users don't have access to the attribute. +user.profile.attribute.canUserEdit=Can user edit? +user.profile.attribute.canUserEdit.tooltip=If enabled, users can view and edit the attribute. Otherwise, users don't have access to write to the attribute. +user.profile.attribute.canAdminView=Can admin view? +user.profile.attribute.canAdminView.tooltip=If enabled, administrators can view the attribute. Otherwise, administrators don't have access to the attribute. +user.profile.attribute.canAdminEdit=Can admin edit? +user.profile.attribute.canAdminEdit.tooltip=If enabled, administrators can view and edit the attribute. Otherwise, administrators don't have access to write to the attribute. +user.profile.attribute.validation=Validation +user.profile.attribute.validation.add.validator=Add Validator +user.profile.attribute.validation.add.validator.tooltip=Select a validator to enforce specific constraints to the attribute value. +user.profile.attribute.validation.no.validators=No validators. +user.profile.attribute.annotation=Annotation +user.profile.attribute.group=Attribute Group +attribute-groups=Attribute Groups +user.profile.attributegroup.displayHeader=Display header +user.profile.attributegroup.displayHeader.tooltip=A user-friendly name for the group that should be used when rendering a group of attributes in user-facing forms. Supports keys for localized values as well. For example\: ${profile.attribute.group.address}. +user.profile.attributegroup.displayDescription=Display description +user.profile.attributegroup.displayDescription.tooltip=A text that should be used as a tooltip when rendering user-facing forms. +user.profile.attributegroup=Attribute Group +user.profile.attributegroup.name=Name +user.profile.attributegroup.name.tooltip=A unique name for the group. This name will be used to reference the group when binding an attribute to a group. +user.profile.attributegroup.annotation=Annotation diff --git a/keycloak-themes/base/admin/messages/admin-messages_es.properties b/keycloak-themes/base/admin/messages/admin-messages_es.properties new file mode 100644 index 0000000..3f67a03 --- /dev/null +++ b/keycloak-themes/base/admin/messages/admin-messages_es.properties @@ -0,0 +1,479 @@ +# Common messages +enabled=Habilitado +name=Nombre +save=Guardar +cancel=Cancelar +onText=SI +offText=NO +client=Cliente +clients=Clientes +clear=Limpiar +selectOne=Selecciona uno... + +true=S\u00ED +false=No + + +# Realm settings +realm-detail.enabled.tooltip=Los usuarios y clientes solo pueden acceder a un dominio si est\u00E1 habilitado +registrationAllowed=Registro de usuario +registrationAllowed.tooltip=Habilitar/deshabilitar la p\u00E1gina de registro. Un enlace para el registro se mostrar\u00E1 tambi\u00E9n en la p\u00E1gina de inicio de sesi\u00F3n. +registrationEmailAsUsername=Email como nombre de usuario +registrationEmailAsUsername.tooltip=Si est\u00E1 habilitado el nombre de usuario queda oculto del formulario de registro y el email se usa como nombre de usuario para los nuevos usuarios. +editUsernameAllowed=Editar nombre de usuario +editUsernameAllowed.tooltip=Si est\u00E1 habilitado, el nombre de usuario es editable, en otro caso es de solo lectura. +resetPasswordAllowed=Olvido contrase\u00F1a +resetPasswordAllowed.tooltip=Muestra un enlace en la p\u00E1gina de inicio de sesi\u00F3n para que el usuario haga clic cuando ha olvidado sus credenciales. +rememberMe=Seguir conectado +rememberMe.tooltip=Muestra la casilla de selecci\u00F3n en la p\u00E1gina de inicio de sesi\u00F3n para permitir al usuario permanecer conectado entre reinicios del navegador hasta que la sesi\u00F3n expire. +verifyEmail=Verificar email +verifyEmail.tooltip=Forzar al usuario a verificar su direcci\u00F3n de email la primera vez que inicie sesi\u00F3n. +sslRequired=Solicitar SSL +sslRequired.option.all=todas las peticiones +sslRequired.option.external=peticiones externas +sslRequired.option.none=ninguna +sslRequired.tooltip=\u00BFEs HTTP obligatorio? ''ninguna'' significa que HTTPS no es obligatorio para ninguna direcic\u00F3n IP de cliente, ''peticiones externas'' indica que localhost y las direcciones IP privadas pueden acceder sin HTTPS, ''todas las peticiones'' significa que HTTPS es obligatorio para todas las direcciones IP. +publicKey=Clave p\u00FAblica +gen-new-keys=Generar nuevas claves +certificate=Certificado +host=Host +smtp-host=Host SMTP +port=Puerto +smtp-port=Puerto SMTP (por defecto 25) +from=De +sender-email-addr=Email del emisor +enable-ssl=Habilitar SSL +enable-start-tls=Habilitar StartTLS +enable-auth=Habilitar autenticaci\u00F3n +username=Usuario +login-username=Usuario +password=Contrase\u00F1a +login-password=Contrase\u00F1a +login-theme=Tema de inicio de sesi\u00F3n +select-one=Selecciona uno... +login-theme.tooltip=Selecciona el tema para las p\u00E1ginas de inicio de sesi\u00F3n, OTP, permisos, registro y recordatorio de contrase\u00F1a. +account-theme=Tema de cuenta +account-theme.tooltip=Selecciona el tema para las p\u00E1ginas de gesti\u00F3n de la cuenta de usuario. +admin-console-theme=Tema de consola de administraci\u00F3n +select-theme-admin-console=Selecciona el tema para la consola de administraci\u00F3n. +email-theme=Tema de email +select-theme-email=Selecciona el tema para los emails que son enviados por el servidor. +i18n-enabled=Internacionalizaci\u00F3n activa +supported-locales=Idiomas soportados +supported-locales.placeholder=Indica el idioma y pulsa Intro +default-locale=Idioma por defecto +#localization-upload-file=Upload localization JSON file +#missing-locale=Missing locale. +#missing-file=Missing file. Please select a file to upload. +#localization-file.upload.success=The localization data has been loaded from file. +#localization-file.upload.error=The file can not be uploaded. Please verify the file. +#localization-show=Show realm specific localizations +#no-localizations-configured=No realm specific localizations configured +#add-localization-text=Add localization text +#locale.create.success=The Locale has been created. +#localization-text.create.success=The localization text has been created. +#localization-text.update.success=The localization text has been updated. +#localization-text.remove.success=The localization text has been deleted. +realm-cache-enabled=Cach\u00E9 de dominio habilitada +realm-cache-enabled.tooltip=Activar/desactivar la cach\u00E9 para el dominio, cliente y datos de roles. +user-cache-enabled=Cach\u00E9 de usuario habilitada +user-cache-enabled.tooltip=Habilitar/deshabilitar la cach\u00E9 de usuarios y de asignaciones de usuarios a roles. +revoke-refresh-token=Revocar el token de actualizaci\u00F3n +revoke-refresh-token.tooltip=Si est\u00E1 activado los tokens de actualizaci\u00F3n solo pueden usarse una vez. En otro caso los tokens de actualizaci\u00F3n no se revocan cuando se utilizan y pueden ser usado m\u00FAltiples veces. +sso-session-idle=Sesiones SSO inactivas +seconds=Segundos +minutes=Minutos +hours=Horas +days=D\u00EDas +sso-session-max=Tiempo m\u00E1ximo sesi\u00F3n SSO +sso-session-idle.tooltip=Tiempo m\u00E1ximo que una sesi\u00F3n puede estar inactiva antes de que expire. Los tokens y sesiones de navegador son invalidadas cuando la sesi\u00F3n expira. +sso-session-max.tooltip=Tiempo m\u00E1ximo antes de que una sesi\u00F3n expire. Los tokens y sesiones de navegador son invalidados cuando una sesi\u00F3n expira. +offline-session-idle=Inactividad de sesi\u00F3n sin conexi\u00F3n +offline-session-idle.tooltip=Tiempo m\u00E1ximo inactivo de una sesi\u00F3n sin conexi\u00F3n antes de que expire. Necesitas usar un token sin conexi\u00F3n para refrescar al menos una vez dentro de este periodo, en otro caso la sesi\u00F3n sin conexi\u00F3n expirar\u00E1. +access-token-lifespan=Duraci\u00F3n del token de acceso +access-token-lifespan.tooltip=Tiempo m\u00E1ximo antes de que un token de acceso expire. Se recomienda que este valor sea corto en relaci\u00F3n al tiempo m\u00E1ximo de SSO +client-login-timeout=Tiempo m\u00E1ximo de autenticaci\u00F3n +client-login-timeout.tooltip=Tiempo m\u00E1ximo que un cliente tiene para finalizar el protocolo de obtenci\u00F3n del token de acceso. Deber\u00EDa ser normalmente del orden de 1 minuto. +login-timeout=Tiempo m\u00E1ximo de desconexi\u00F3n +login-timeout.tooltip=Tiempo m\u00E1ximo que un usuario tiene para completar el inicio de sesi\u00F3n. Se recomienda que sea relativamente alto. 30 minutos o m\u00E1s. +login-action-timeout=Tiempo m\u00E1ximo de acci\u00F3n en el inicio de sesi\u00F3n +login-action-timeout.tooltip=Tiempo m\u00E1ximo que un usuario tiene para completar acciones relacionadas con el inicio de sesi\u00F3n, como la actualizaci\u00F3n de contrase\u00F1a o configuraci\u00F3n de OTP. Es recomendado que sea relativamente alto. 5 minutos o m\u00E1s. +headers=Cabeceras +brute-force-detection=Detecci\u00F3n de ataques por fuerza bruta +x-frame-options=X-Frame-Options +click-label-for-info=Haz clic en el enlace de la etiqueta para obtener m\u00E1s informaci\u00F3n. El valor por defecto evita que las p\u00E1ginas sean incluidas desde iframes externos. +content-sec-policy=Content-Security-Policy +max-login-failures=N\u00FAmero m\u00E1ximo de fallos de inicio de sesi\u00F3n +max-login-failures.tooltip=Indica cuantos fallos se permiten antes de que se dispare una espera. +wait-increment=Incremento de espera +wait-increment.tooltip=Cuando se ha alcanzado el umbral de fallo, \u00BFcuanto tiempo debe estar un usuario bloqueado? +quick-login-check-millis=Tiempo en milisegundos entre inicios de sesi\u00F3n r\u00E1pidos +quick-login-check-millis.tooltip=Si ocurren errores de forma concurrente y muy r\u00E1pida, bloquear al usuario. +min-quick-login-wait=Tiempo m\u00EDnimo entre fallos de conexi\u00F3n r\u00E1pidos +min-quick-login-wait.tooltip=Cuanto tiempo se debe esperar tras un fallo en un intento r\u00E1pido de identificaci\u00F3n +max-wait=Espera m\u00E1xima +max-wait.tooltip=Tiempo m\u00E1ximo que un usuario quedar\u00E1 bloqueado. +failure-reset-time=Reinicio del contador de errores +failure-reset-time.tooltip=\u00BFCuando se debe reiniciar el contador de errores? +realm-tab-login=Inicio de sesi\u00F3n +realm-tab-keys=Claves +realm-tab-email=Email +realm-tab-themes=Temas +#realm-tab-localization=Localization +realm-tab-cache=Cach\u00E9 +realm-tab-tokens=Tokens +realm-tab-security-defenses=Defensas de seguridad +realm-tab-general=General +add-realm=A\u00F1adir dominio + +#Session settings +realm-sessions=Sesiones de dominio +revocation=Revocaci\u00F3n +logout-all=Desconectar todo +active-sessions=Sesiones activas +sessions=Sesiones +not-before=No antes de +not-before.tooltip=Revocar cualquier token emitido antes de esta fecha. +set-to-now=Fijar a ahora +push=Push +push.tooltip=Para cada cliente que tiene una URL de administraci\u00F3n, notificarlos las nuevas pol\u00EDticas de revocaci\u00F3n. + +#Protocol Mapper +usermodel.prop.label=Propiedad +usermodel.prop.tooltip=Nombre del m\u00E9todo de propiedad en la interfaz UserModel. Por ejemplo, un valor de ''email'' referenciar\u00EDa al m\u00E9todo UserModel.getEmail(). +usermodel.attr.label=Atributo de usuario +usermodel.attr.tooltip=Nombre del atributo de usuario almacenado que es el nombre del atributo dentro del map UserModel.attribute. +userSession.modelNote.label=Nota sesi\u00F3n usuario +userSession.modelNote.tooltip=Nombre de la nota almacenada en la sesi\u00F3n de usuario dentro del mapa UserSessionModel.note +multivalued.label=Valores m\u00FAltiples +multivalued.tooltip=Indica si el atributo soporta m\u00FAltiples valores. Si est\u00E1 habilitado, la lista de todos los valores de este atributo se fijar\u00E1 como reclamaci\u00F3n. Si est\u00E1 deshabilitado, solo el primer valor ser\u00E1 fijado como reclamaci\u00F3n. +selectRole.label=Selecciona rol +selectRole.tooltip=Introduce el rol en la caja de texto de la izquierda, o haz clic en este bot\u00F3n para navegar y buscar el rol que quieres. +tokenClaimName.label=Nombre de reclamo del token +tokenClaimName.tooltip=Nombre del reclamo a insertar en el token. Puede ser un nombre completo como ''address.street''. En este caso, se crear\u00E1 un objeto JSON anidado. +jsonType.label=Tipo JSON de reclamaci\u00F3n +jsonType.tooltip=El tipo de JSON que deber\u00EDa ser usado para rellenar la petici\u00F3n de JSON en el token. long, int, boolean y String son valores v\u00E1lidos +includeInIdToken.label=A\u00F1adir al token de ID +includeInAccessToken.label=A\u00F1adir al token de acceso +includeInAccessToken.tooltip=\u00BFDeber\u00EDa a\u00F1adirse la identidad reclamada al token de acceso? + + +# client details +clients.tooltip=Los clientes son aplicaciones de navegador de confianza y servicios web de un dominio. Estos clientes pueden solicitar un inicio de sesi\u00F3n. Tambi\u00E9n puedes definir roles espec\u00EDficos de cliente. +search.placeholder=Buscar... +create=Crear +import=Importar +client-id=ID Cliente +base-url=URL Base +actions=Acciones +not-defined=No definido +edit=Editar +delete=Borrar +no-results=Sin resultados +no-clients-available=No hay clientes disponibles +add-client=A\u00F1adir Cliente +select-file=Selecciona archivo +view-details=Ver detalles +clear-import=Limpiar importaci\u00F3n +client-id.tooltip=Indica el identificador (ID) referenciado en URIs y tokens. Por ejemplo ''my-client'' +client.name.tooltip=Indica el nombre visible del cliente. Por ejemplo ''My Client''. Tambi\u00E9n soporta claves para valores localizados. Por ejemplo: ${my_client} +client.enabled.tooltip=Los clientes deshabilitados no pueden iniciar una identificaci\u00F3n u obtener c\u00F3digos de acceso. +consent-required=Consentimiento necesario +consent-required.tooltip=Si est\u00E1 habilitado, los usuarios tienen que consentir el acceso del cliente. +direct-grants-only=Solo permisos directos +direct-grants-only.tooltip=Cuando est\u00E1 habilitado, el cliente solo puede obtener permisos de la API REST. +client-protocol=Protocolo del Cliente +client-protocol.tooltip=''OpenID connect'' permite a los clientes verificar la identidad del usuario final basado en la autenticaci\u00F3n realizada por un servidor de autorizaci\u00F3n. ''SAML'' habilita la autenticaci\u00F3n y autorizaci\u00F3n de escenarios basados en web incluyendo cross-domain y single sign-on (SSO) y utiliza tokens de seguridad que contienen afirmaciones para pasar informaci\u00F3n. +access-type=Tipo de acceso +access-type.tooltip=Los clientes ''Confidential'' necesitan un secreto para iniciar el protocolo de identificaci\u00F3n. Los clientes ''Public'' no requieren un secreto. Los clientes ''Bearer-only'' son servicios web que nunca inician un login. +service-accounts-enabled=Cuentas de servicio habilitadas +service-accounts-enabled.tooltip=Permitir autenticar este cliente contra Keycloak y recibir un token de acceso dedicado para este cliente. +include-authnstatement=Incluir AuthnStatement +include-authnstatement.tooltip=\u00BFDeber\u00EDa incluirse una declaraci\u00F3n especificando el m\u00E9todo y la marca de tiempo en la respuesta de inicio de sesi\u00F3n? +sign-documents=Firmar documentos +sign-documents.tooltip=\u00BFDeber\u00EDa el dominio firmar los documentos SAML? +sign-assertions=Firmar aserciones +sign-assertions.tooltip=\u00BFDeber\u00EDan firmarse las aserciones en documentos SAML? Este ajuste no es necesario si el documento ya est\u00E1 siendo firmado. +signature-algorithm=Algoritmo de firma +signature-algorithm.tooltip=El algoritmo de firma usado para firmar los documentos. +canonicalization-method=M\u00E9todo de canonicalizaci\u00F3n +canonicalization-method.tooltip=M\u00E9todo de canonicalizaci\u00F3n para las firmas XML +encrypt-assertions=Cifrar afirmaciones +encrypt-assertions.tooltip=\u00BFDeber\u00EDan cifrarse las afirmaciones SAML con la clave p\u00FAblica del cliente usando AES? +client-signature-required=Firma de Cliente requerida +client-signature-required.tooltip=\u00BFFirmar\u00E1 el cliente sus peticiones y respuestas SAML? \u00BFY deber\u00EDan ser validadas? +force-post-binding=Forzar enlaces POST +force-post-binding.tooltip=Usar siempre POST para las respuestas +front-channel-logout=Desonexi\u00F3n en primer plano (Front Channel) +front-channel-logout.tooltip=Cuando est\u00E1 activado, la desconexi\u00F3n require una redirecci\u00F3n del navegador hacia el cliente. Cuando no est\u00E1 activado, el servidor realiza una invovaci\u00F3n de desconexi\u00F3n en segundo plano. +force-name-id-format=Forzar formato NameID +force-name-id-format.tooltip=Ignorar la petici\u00F3n de sujeto NameID y usar la configurada en la consola de administraci\u00F3n. +name-id-format=Formato de NameID +name-id-format.tooltip=El formato de NameID que se usar\u00E1 para el t\u00EDtulo +root-url=URL ra\u00EDz +root-url.tooltip=URL ra\u00EDz a\u00F1adida a las URLs relativas +valid-redirect-uris=URIs de redirecci\u00F3n v\u00E1lidas +valid-redirect-uris.tooltip=Patr\u00F3n de URI v\u00E1lida para la cual un navegador puede solicitar la redirecci\u00F3n tras un inicio o cierre de sesi\u00F3n completado. Se permiten comodines simples p.ej. ''http://example.com/*''. Tambi\u00E9n se pueden indicar rutas relativas p.ej. ''/my/relative/path/*''. Las rutas relativas generar\u00E1n una URI de redirecci\u00F3n usando el host y puerto de la petici\u00F3n. Para SAML, se deben fijar patrones de URI v\u00E1lidos si quieres confiar en la URL del servicio del consumidor indicada en la petici\u00F3n de inicio de sesi\u00F3n. +base-url.tooltip=URL por defecto para usar cuando el servidor de autorizaci\u00F3n necesita redirigir o enviar de vuelta al cliente. +admin-url=URL de administraci\u00F3n +admin-url.tooltip=URL a la interfaz de administraci\u00F3n del cliente. Fija este valor si el cliente soporta el adaptador de REST. Esta API REST permite al servidor de autenticaci\u00F3n enviar al cliente pol\u00EDticas de revocaci\u00F3n y otras tareas administrativas. Normalment se fija a la URL base del cliente. +master-saml-processing-url=URL principal de procesamiento SAML +master-saml-processing-url.tooltip=Si est\u00E1 configurada, esta URL se usar\u00E1 para cada enlace al proveedor del servicio del consumidor de aserciones y servicios de desconexi\u00F3n \u00FAnicos. Puede ser sobreescrito de forma individual para cada enlace y servicio en el punto final de configuraci\u00F3n fina de SAML. +idp-sso-url-ref=Nombre de la URL de un SSO iniciado por el IDP +idp-sso-url-ref.tooltip=Nombre del fragmento de la URL para referenciar al cliente cuando quieres un SSO iniciado por el IDP. Dejando esto vac\u00EDo deshabilita los SSO iniciados por el IDP. La URL referenciada desde el navegador ser\u00E1: {server-root}/realms/{realm}/protocol/saml/clients/{client-url-name} +idp-sso-relay-state=Estado de retransmisi\u00F3n de un SSO iniciado por el IDP +idp-sso-relay-state.tooltip=Estado de retransmisi\u00F3n que quieres enviar con una petici\u00F3n SAML cuando se inicia un SSO iniciado por el IDP +web-origins=Or\u00EDgenes web +web-origins.tooltip=Or\u00EDgenes CORS permitidos. Para permitir todos los or\u00EDgenes de URIs de redirecci\u00F3n v\u00E1lidas a\u00F1ade ''+''. Para permitir todos los or\u00EDgenes a\u00F1ade ''*''. +fine-saml-endpoint-conf=Fine Grain SAML Endpoint Configuration +fine-saml-endpoint-conf.tooltip=Expande esta secci\u00F3n para configurar las URL exactas para Assertion Consumer y Single Logout Service. +assertion-consumer-post-binding-url=Assertion Consumer Service POST Binding URL +assertion-consumer-post-binding-url.tooltip=SAML POST Binding URL for the client''s assertion consumer service (login responses). You can leave this blank if you do not have a URL for this binding. +assertion-consumer-redirect-binding-url=Assertion Consumer Service Redirect Binding URL +assertion-consumer-redirect-binding-url.tooltip=Assertion Consumer Service Redirect Binding URL +logout-service-post-binding-url=URL de enlace SAML POST para la desconexi\u00F3n +logout-service-post-binding-url.tooltip=URL de enlace SAML POST para la desconexi\u00F3n \u00FAnica del cliente. Puedes dejar esto en blanco si est\u00E1s usando un enlace distinto. +logout-service-redir-binding-url=URL de enlace SAML de redirecci\u00F3n para la desconexi\u00F3n +logout-service-redir-binding-url.tooltip=URL de enlace SAML de redirecci\u00F3n para la desconexi\u00F3n \u00FAnica del cliente. Puedes dejar esto en blanco si est\u00E1s usando un enlace distinto. + +# client import +import-client=Importar Cliente +format-option=Formato +select-format=Selecciona un formato +import-file=Archivo de Importaci\u00F3n + +# client tabs +settings=Ajustes +credentials=Credenciales +roles=Roles +mappers=Asignadores +mappers.tooltip=Los asignadores de protocolos realizan transformaciones en tokens y documentos. Pueden hacer cosas como asignar datos de usuario en peticiones de protocolo, o simplemente transformar cualquier petici\u00F3n entre el cliente y el servidor de autenticaci\u00F3n. +scope=\u00C1mbito +scope.tooltip=Las asignaciones de \u00E1mbito te permiten restringir que asignaciones de roles de usuario se incluyen en el token de acceso solicitado por el cliente. +sessions.tooltip=Ver sesiones activas para este cliente. Permite ver qu\u00E9 usuarios est\u00E1n activos y cuando se identificaron. +offline-access=Acceso sin conexi\u00F3n +offline-access.tooltip=Ver sesiones sin conexi\u00F3n para este cliente. Te permite ver que usuarios han solicitado tokens sin conexi\u00F3n y cuando los solicitaron. Para revocar todos los tokens del cliente, accede a la pesta\u00F1a de Revocaci\u00F3n y fija el valor \"No antes de\" a \"now\". +clustering=Clustering +installation=Instalaci\u00F3n +installation.tooltip=Herramienta de ayuda para generar la configuraci\u00F3n de varios formatos de adaptadores de cliente que puedes descargar o copiar y pegar para configurar tus clientes. +service-account-roles=Roles de cuenta de servicio +service-account-roles.tooltip=Permitir autenticar asignaciones de rol para la cuenta de servicio dedicada a este cliente. + +# client credentials +client-authenticator=Cliente autenticador +client-authenticator.tooltip=Cliente autenticador usado para autenticar este cliente contra el servidor Keycloak +certificate.tooltip=Certificado de cliente para validar los JWT emitidos por este cliente y firmados con la clave privada del cliente de tu almac\u00E9n de claves. +no-client-certificate-configured=No se ha configurado el certificado de cliente +gen-new-keys-and-cert=Generar nuevas claves y certificado +import-certificate=Importar Certificado +gen-client-private-key=Generar clave privada de cliente +generate-private-key=Generar clave privada +archive-format=Formato de Archivo +archive-format.tooltip=Formato de archivo Java keystore o PKCS12 +key-alias=Alias de clave +key-alias.tooltip=Alias del archivo de tu clave privada y certificado. +key-password=Contrase\u00F1a de la clave +key-password.tooltip=Contrase\u00F1a para acceder a la clave privada contenida en el archivo +store-password=Contrase\u00F1a del almac\u00E9n +store-password.tooltip=Contrase\u00F1a para acceder al archivo +generate-and-download=Generar y descargar +client-certificate-import=Importaci\u00F3n de certificado de cliente +import-client-certificate=Importar Certificado de Cliente +jwt-import.key-alias.tooltip=Alias del archivo de tu certificado. +secret=Secreto +regenerate-secret=Regenerar secreto +add-role=A\u00F1adir rol +role-name=Nombre de rol +composite=Compuesto +description=Descripci\u00F3n +no-client-roles-available=No hay roles de cliente disponibles +scope-param-required=Par\u00E1metro de \u00E1mbito obligatorio +scope-param-required.tooltip=Este rol solo ser\u00E1 concedido si el par\u00E1metro de \u00E1mbito con el nombre del rol es usado durante la petici\u00F3n de autorizaci\u00F3n/obtenci\u00F3n de token. +composite-roles=Roles compuestos +composite-roles.tooltip=Cuando este rol es asignado/desasignado a un usuario cualquier rol asociado con \u00E9l ser\u00E1 asignado/desasignado de forma impl\u00EDcita. +realm-roles=Roles de dominio +available-roles=Roles Disponibles +add-selected=A\u00F1adir seleccionado +associated-roles=Roles Asociados +composite.associated-realm-roles.tooltip=Roles a nivel de dominio asociados con este rol compuesto. +composite.available-realm-roles.tooltip=Roles a nivel de dominio disponibles en este rol compuesto. +remove-selected=Borrar seleccionados +client-roles=Roles de Cliente +select-client-to-view-roles=Selecciona el cliente para ver sus roles +available-roles.tooltip=Roles de este cliente que puedes asociar a este rol compuesto. +client.associated-roles.tooltip=Roles de cliente asociados con este rol compuesto. +add-builtin=A\u00F1adir Builtin +category=Categor\u00EDa +type=Tipo +no-mappers-available=No hay asignadores disponibles +add-builtin-protocol-mappers=A\u00F1adir Builtin Protocol Mappers +add-builtin-protocol-mapper=A\u00F1adir Builtin Protocol Mapper +scope-mappings=Asignaciones de \u00E1mbito +full-scope-allowed=Permitir todos los \u00E1mbitos +full-scope-allowed.tooltip=Permite deshabilitar todas las restricciones. +scope.available-roles.tooltip=Roles de dominio que pueden ser asignados al \u00E1mbito +assigned-roles=Roles Asignados +assigned-roles.tooltip=Roles a nivel de dominio asignados a este \u00E1mbito. +effective-roles=Roles Efectivos +realm.effective-roles.tooltip=Roles de dominio asignados que pueden haber sido heredados de un rol compuesto. +select-client-roles.tooltip=Selecciona el cliente para ver sus roles +assign.available-roles.tooltip=Roles de clientes disponibles para ser asignados. +client.assigned-roles.tooltip=Roles de cliente asignados +client.effective-roles.tooltip=Roles de cliente asignados que pueden haber sido heredados desde un rol compuesto. +basic-configuration=Configuraci\u00F3n b\u00E1sica +node-reregistration-timeout=Tiempo de espera de re-registro de nodo +node-reregistration-timeout.tooltip=Indica el m\u00E1ximo intervalo de tiempo para que los nodos del cluster registrados se vuelvan a registrar. Si el nodo del cluster no env\u00EDa una petici\u00F3n de re-registro a Keycloak dentro de este intervalo, ser\u00E1 desregistrado de Keycloak +registered-cluster-nodes=Registrar nodos de cluster +register-node-manually=Registrar nodo manualmente +test-cluster-availability=Probar disponibilidad del cluster +last-registration=\u00DAltimo registro +node-host=Host del nodo +no-registered-cluster-nodes=No hay nodos de cluster registrados disponibles +cluster-nodes=Nodos de cl\u00FAster +add-node=A\u00F1adir Nodo +active-sessions.tooltip=N\u00FAmero total de sesiones activas para este cliente. +show-sessions=Mostrar sesiones +show-sessions.tooltip=Advertencia, esta es una operaci\u00F3n potencialmente costosa dependiendo del n\u00FAmero de sesiones activas. +user=Usuario +from-ip=Desde IP +session-start=Inicio de sesi\u00F3n +first-page=Primera p\u00E1gina +previous-page=P\u00E1gina Anterior +next-page=P\u00E1gina siguiente +client-revoke.not-before.tooltip=Revocar todos los tokens emitidos antes de esta fecha para este cliente. +client-revoke.push.tooltip=Si la URL de administraci\u00F3n est\u00E1 configurada para este cliente, env\u00EDa esta pol\u00EDtica a este cliente. +select-a-format=Selecciona un formato +download=Descargar +offline-tokens=Tokens sin conexi\u00F3n +offline-tokens.tooltip=N\u00FAmero total de tokens sin conexi\u00F3n de este cliente. +show-offline-tokens=Mostrar tokens sin conexi\u00F3n +show-offline-tokens.tooltip=Advertencia, esta es una operaci\u00F3n potencialmente costosa dependiendo del n\u00FAmero de tokens sin conexi\u00F3n. +token-issued=Token expedido +last-access=\u00DAltimo Acceso +last-refresh=\u00DAltima actualizaci\u00F3n +key-export=Exportar clave +key-import=Importar clave +export-saml-key=Exportar clave SAML +import-saml-key=Importar clave SAML +realm-certificate-alias=Alias del certificado del dominio +realm-certificate-alias.tooltip=El certificado del dominio es almacenado en archivo. Este es el alias al mismo. +signing-key=Clave de firma +saml-signing-key=Clave de firma SAML. +private-key=Clave Privada +generate-new-keys=Generar nuevas claves +export=Exportar +encryption-key=Clave de cifrado +saml-encryption-key.tooltip=Clave de cifrado de SAML +service-accounts=Cuentas de servicio +service-account.available-roles.tooltip=Roles de dominio que pueden ser asignados a la cuenta del servicio. +service-account.assigned-roles.tooltip=Roles de dominio asignados a la cuenta del servicio. +service-account-is-not-enabled-for=La cuenta del servicio no est\u00E1 habilitada para {{client}} +create-protocol-mappers=Crear asignadores de protocolo +create-protocol-mapper=Crear asignador de protocolo +protocol=Protocolo +protocol.tooltip=Protocolo. +id=ID +mapper.name.tooltip=Nombre del asignador. +mapper.consent-required.tooltip=Cuando se concede acceso temporal, \u00BFes necesario el consentimiento del usuario para proporcionar estos datos al cliente? +consent-text=Texto del consentimiento +consent-text.tooltip=Texto para mostrar en la p\u00E1gina de consentimiento. +mapper-type=Tipo de asignador + +# realm identity providers +identity-providers=Proveedores de identidad +table-of-identity-providers=Tabla de proveedores de identidad +add-provider.placeholder=A\u00F1adir proveedor... +provider=Proveedor +gui-order=Orden en la interfaz gr\u00E1fica (GUI) +redirect-uri=URI de redirecci\u00F3n +redirect-uri.tooltip=La URI de redirecci\u00F3n usada para configurar el proveedor de identidad. +alias=Alias +identity-provider.alias.tooltip=El alias que identifica de forma \u00FAnica un proveedor de identidad, se usa tambi\u00E9n para construir la URI de redirecci\u00F3n. +identity-provider.enabled.tooltip=Habilita/deshabilita este proveedor de identidad. +authenticate-by-default=Autenticar por defecto +identity-provider.authenticate-by-default.tooltip=Indica si este proveedor deber\u00EDa ser probado por defecto para autenticacaci\u00F3n incluso antes de mostrar la p\u00E1gina de inicio de sesi\u00F3n. +store-tokens=Almacenar tokens +identity-provider.store-tokens.tooltip=Habilitar/deshabilitar si los tokens deben ser almacenados despu\u00E9s de autenticar a los usuarios. +stored-tokens-readable=Tokens almacenados legibles +identity-provider.stored-tokens-readable.tooltip=Habilitar/deshabilitar si los nuevos usuarios pueden leer los tokens almacenados. Esto asigna el rol ''broker.read-token''. +update-profile-on-first-login=Actualizar perfil en el primer inicio de sesi\u00F3n +on=Activado +on-missing-info=Si falta informaci\u00F3n +off=Desactivado +update-profile-on-first-login.tooltip=Define condiciones bajo las cuales un usuario tiene que actualizar su perfil durante el primer inicio de sesi\u00F3n. +trust-email=Confiar en el email +trust-email.tooltip=Si est\u00E1 habilitado, el email recibido de este proveedor no se verificar\u00E1 aunque la verificaci\u00F3n est\u00E9 habilitada para el dominio. +gui-order.tooltip=N\u00FAmero que define el orden del proveedor en la interfaz gr\u00E1fica (GUI) (ej. en la p\u00E1gina de inicio de sesi\u00F3n) +openid-connect-config=Configuraci\u00F3n de OpenID Connect +openid-connect-config.tooltip=Configuraci\u00F3n de OIDC SP e IDP externos +authorization-url=URL de autorizaci\u00F3n +authorization-url.tooltip=La URL de autorizaci\u00F3n. +token-url=Token URL +token-url.tooltip=La URL del token. +logout-url=URL de desconexi\u00F3n +identity-provider.logout-url.tooltip=Punto de cierre de sesi\u00F3n para usar en la desconexi\u00F3n de usuarios desde un proveedor de identidad (IDP) externo. +backchannel-logout=Backchannel Logout +backchannel-logout.tooltip=Does the external IDP support backchannel logout? +user-info-url=URL de informaci\u00F3n de usuario +user-info-url.tooltip=La URL de informaci\u00F3n de usuario. Opcional. +identity-provider.client-id.tooltip=El cliente o identificador de cliente registrado en el proveedor de identidad. +client-secret=Secreto de Cliente +show-secret=Mostrar secreto +hide-secret=Ocultar secreto +client-secret.tooltip=El cliente o el secreto de cliente registrado en el proveedor de identidad. +issuer=Emisor +issuer.tooltip=El identificador del emisor para el emisor de la respuesta. Si no se indica, no se realizar\u00E1 ninguna validaci\u00F3n. +default-scopes=\u00C1mbitos por defecto +identity-provider.default-scopes.tooltip=Los \u00E1mbitos que se enviar\u00E1n cuando se solicite autorizaci\u00F3n. Puede ser una lista de \u00E1mbitos separados por espacios. El valor por defecto es ''openid''. +prompt=Prompt +unspecified.option=no especificado +none.option=ninguno +consent.option=consentimiento +login.option=login +select-account.option=select_account +prompt.tooltip=Indica si el servidor de autorizaci\u00F3n solicita al usuario final para reautenticaci\u00F3n y consentimiento. +validate-signatures=Validar firmas +identity-provider.validate-signatures.tooltip=Habilitar/deshabilitar la validaci\u00F3n de firmas de proveedores de identidad (IDP) externos +validating-public-key=Validando clave p\u00FAblica +identity-provider.validating-public-key.tooltip=La clave p\u00FAblica en formato PEM que debe usarse para verificar las firmas de proveedores de identidad (IDP) externos. +import-external-idp-config=Importar configuraci\u00F3n externa de IDP +import-external-idp-config.tooltip=Te permite cargar metadatos de un proveedor de identidad (IDP) externo de un archivo de coniguraci\u00F3n o descargarlo desde una URL. +import-from-url=Importar desde URL +identity-provider.import-from-url.tooltip=Importar metadatos desde un descriptor de un proveedor de identidad (IDP) remoto. +import-from-file=Importar desde archivo +identity-provider.import-from-file.tooltip=Importar metadatos desde un descriptor de un proveedor de identidad (IDP) descargado. +saml-config=Configuraci\u00F3n SAML +identity-provider.saml-config.tooltip=Configuraci\u00F3n de proveedor SAML e IDP externo +single-signon-service-url=URL de servicio de conexi\u00F3n \u00FAnico (SSO) +saml.single-signon-service-url.tooltip=La URL que debe ser usada para enviar peticiones de autenticaci\u00F3n (SAML AuthnRequest). +single-logout-service-url=URL de servicio de desconexi\u00F3n \u00FAnico +saml.single-logout-service-url.tooltip=La URL que debe usarse para enviar peticiones de desconexi\u00F3n. +nameid-policy-format=Formato de pol\u00EDtica NameID +nameid-policy-format.tooltip=Indica la referencia a la URI correspondiente a un formato de NameID. El valor por defecto es urn:oasis:names:tc:SAML:2.0:nameid-format:persistent. +http-post-binding-response=HTTP-POST enlace de respuesta +http-post-binding-response.tooltip=Indica si se responde a las peticiones usando HTTP-POST. Si no est\u00E1 activado, se usa HTTP-REDIRECT. +http-post-binding-for-authn-request=HTTP-POST para AuthnRequest +http-post-binding-for-authn-request.tooltip=Indica si AuthnRequest debe ser enviada usando HTTP-POST. Si no est\u00E1 activado se hace HTTP-REDIRECT. +want-authn-requests-signed=Firmar AuthnRequests +want-authn-requests-signed.tooltip=Indica si el proveedor de identidad espera recibir firmadas las AuthnRequest. +force-authentication=Forzar autenticaci\u00F3n +identity-provider.force-authentication.tooltip=Indica si el proveedor de identidad debe autenticar al presentar directamente las credenciales en lugar de depender de un contexto de seguridad previo. +validate-signature=Validar firma +saml.validate-signature.tooltip=Habilitar/deshabilitar la validaci\u00F3n de firma en respuestas SAML. +validating-x509-certificate=Validando certificado X509 +validating-x509-certificate.tooltip=El certificado en formato PEM que debe usarse para comprobar las firmas. +saml.import-from-url.tooltip=Importar metadatos desde un descriptor de entidad remoto de un IDP de SAML +social.client-id.tooltip=El identificador del cliente registrado con el proveedor de identidad. +social.client-secret.tooltip=El secreto del cliente registrado con el proveedor de identidad. +social.default-scopes.tooltip=\u00C1mbitos que se enviar\u00E1n cuando se solicite autorizaci\u00F3n. Ver la documentaci\u00F3n para los posibles valores, separador y valor por defecto. +key=Clave +stackoverflow.key.tooltip=La clave obtenida en el registro del cliente de Stack Overflow. + +realms=Dominios +realm=Dominio + +identity-provider-mappers=Asignadores de proveedores de identidad (IDP) +create-identity-provider-mapper=Crear asignador de proveedor de identidad (IDP) +add-identity-provider-mapper=A\u00F1adir asignador de proveedor de identidad +client.description.tooltip=Indica la descripci\u00F3n del cliente. Por ejemplo ''My Client for TimeSheets''. Tambi\u00E9n soporta claves para valores localizados. Por ejemplo: ${my_client_description} +content-type-options= diff --git a/keycloak-themes/base/admin/messages/admin-messages_fi.properties b/keycloak-themes/base/admin/messages/admin-messages_fi.properties new file mode 100644 index 0000000..6eb3265 --- /dev/null +++ b/keycloak-themes/base/admin/messages/admin-messages_fi.properties @@ -0,0 +1 @@ +# encoding: UTF-8 \ No newline at end of file diff --git a/keycloak-themes/base/admin/messages/admin-messages_fr.properties b/keycloak-themes/base/admin/messages/admin-messages_fr.properties new file mode 100644 index 0000000..c627e93 --- /dev/null +++ b/keycloak-themes/base/admin/messages/admin-messages_fr.properties @@ -0,0 +1,155 @@ +consoleTitle=Keycloak Admin Console + +# Common messages +enabled=Actif +name=Nom +displayName=Display name +displayNameHtml=HTML Display name +save=Sauver +cancel=Annuler +onText=Oui +offText=Non +client=Client +clients=Clients +clear=Effacer +selectOne=Select One... + +manage=G\u00e9rer +authentication=Authentification +user-federation=Regroupement Utilisateur +user-storage=Stockage Utilisateur +events=\u00c9v\u00e8nements +realm-settings=Configurations du domaine +configure=Configurer +select-realm=Choisir un domaine +add=Ajouter + +true=Vrai +false=Faux + +endpoints=Endpoints + +# Realm settings +realm-detail.enabled.tooltip=Les utilisateurs et les clients peuvent acc\u00e9der au domaine si celui-ci est actif +realm-detail.oidc-endpoints.tooltip=Affiche les configurations de l''endpoint OpenID Connect +registrationAllowed=Enregistrement d''utilisateur +registrationAllowed.tooltip=Activer/d\u00e9sactiver la page d''enregistrement. Un lien pour l''enregistrement sera visible sur la page de connexion. +registrationEmailAsUsername=Courriel comme nom d''utilisateur +registrationEmailAsUsername.tooltip=Si actif, le champ du nom de l''utilisateur est cach\u00e9 pendant l''enregistrement ; le courriel est utilis\u00e9 comme nom d''utilisateur. +editUsernameAllowed=\u00c9ditez le nom de l''utilisateur +editUsernameAllowed.tooltip=Si actif, le champ du nom de l''utilisateur est modifiable. +resetPasswordAllowed=Mot de passe oubli\u00e9 +resetPasswordAllowed.tooltip=Affiche un lien sur la page de connexion pour les utilisateurs ayant oubli\u00e9 leurs accr\u00e9ditations. +rememberMe=Se souvenir de moi +rememberMe.tooltip=Affiche une case \u00e0 cocher sur la page de connexion pour permettre aux utilisateurs de rester connect\u00e9s entre deux red\u00e9marrages de leur navigateur, jusqu''\u00e0 expiration de la session. +verifyEmail=V\u00e9rification du courriel +verifyEmail.tooltip=Force l''utilisateur \u00e0 v\u00e9rifier son courriel lors de la premi\u00e8re connexion. +loginWithEmailAllowed=Authentification avec courriel +loginWithEmailAllowed.tooltip=Autorise l''utilisateur \u00e0 s''authentifier avec son adresse de courriel. +duplicateEmailsAllowed=Doublon courriel +duplicateEmailsAllowed.tooltip=Autorise plusieurs utilisateurs \u00e0 avoir la m\u00eame adresse de courriel. Changer cette configuration va vider le cache. Il est recommand\u00e9 de mettre \u00e0 jour manuellement les contraintes sur le courriel dans la base de donn\u00e9es apr\u00e8s la d\u00e9sactivation du support des doublons. +sslRequired=SSL requis +sslRequired.option.all=toutes les requ\u00eates +sslRequired.option.external=les requ\u00eates externes +sslRequired.option.none=aucun +sslRequired.tooltip=Niveau d''exigence HTTPS \: ''aucun'' signifie que le HTTPS n''est requis pour aucune adresse IP cliente. ''les requ\u00eates externes'' signifie que localhost et les adresses IP priv\u00e9es peuvent acc\u00e9der sans HTTPS. ''toutes les requ\u00eates'' signifie que le protocole HTTPS est obligatoire pour toutes les adresses IP. +publicKey=Clef publique +gen-new-keys=Cr\u00e9ation de nouvelle clef +certificate=Certificat +host=H\u00f4te +smtp-host=H\u00f4te SMTP +port=Port +smtp-port=Port SMTP (25 par d\u00e9faut) +from=De +sender-email-addr=Courriel de l''exp\u00e9diteur +enable-ssl=Activer SSL/TLS +enable-start-tls=Activer StartTLS +enable-auth=Activer l''authentification +username=Nom de l''utilisateur +login-username=Connexion de l''utilisateur +password=Mot de passe +login-password=Mot de passe +login-theme=Th\u00e8me de connexion +select-one=S\u00e9lectionnez-en un... +login-theme.tooltip=S\u00e9lectionnez le th\u00e8me pour les pages de connexion, de mot de passe \u00e0 usage unique bas\u00e9 sur le temps, des droits, de l''enregistrement, et du mot passe oubli\u00e9. +account-theme=Th\u00e8me du compte +account-theme.tooltip=S\u00e9lectionnez le th\u00e8me pour la gestion des comptes. +admin-console-theme=Th\u00e8me de la console d''administration +select-theme-admin-console=S\u00e9lectionnez le th\u00e8me de la console d''administration. +email-theme=Th\u00e8me pour le courriel +select-theme-email=S\u00e9lectionnez le th\u00e8me pour les courriels envoy\u00e9es par le serveur. +i18n-enabled=Internationalisation activ\u00e9e +supported-locales=Locales support\u00e9es +supported-locales.placeholder=Entrez la locale et validez +default-locale=Locale par d\u00e9faut +#localization-upload-file=Upload localization JSON file +#missing-locale=Missing locale. +#missing-file=Missing file. Please select a file to upload. +#localization-file.upload.success=The localization data has been loaded from file. +#localization-file.upload.error=The file can not be uploaded. Please verify the file. +#localization-show=Show realm specific localizations +#no-localizations-configured=No realm specific localizations configured +#add-localization-text=Add localization text +#locale.create.success=The Locale has been created. +#localization-text.create.success=The localization text has been created. +#localization-text.update.success=The localization text has been updated. +#localization-text.remove.success=The localization text has been deleted. +realm-cache-enabled=Cache du domaine activ\u00e9 +realm-cache-enabled.tooltip=Activer/D\u00e9sactiver le cache pour le domaine, client et donn\u00e9es. +user-cache-enabled=Cache utilisateur activ\u00e9 +user-cache-enabled.tooltip=Activer/D\u00e9sactiver le cache utilisateur, et le cache de relation entre utilisateurs et r\u00f4les. +sso-session-idle=Sessions SSO inactives +seconds=Secondes +minutes=Minutes +hours=Heures +days=Jours +sso-session-max=Maximum de sessions SSO +sso-session-idle.tooltip=Temps d''inactivit\u00e9 autoris\u00e9 avant expiration de la session. Les jetons et les sessions navigateurs sont invalid\u00e9es quand la session expire. +sso-session-max.tooltip=Dur\u00e9e maximale avant que la session n''expire. Les jetons et les sessions navigateurs sont invalid\u00e9es quand la session expire. +access-token-lifespan=Dur\u00e9e de vie du jeton d''acc\u00e8s +access-token-lifespan.tooltip=Dur\u00e9e maximale avant que le jeton d''acc\u00e8s n''expire. Cette valeur devrait \u00eatre relativement plus petite que la dur\u00e9e d''inactivit\u00e9 (timeout) du SSO. +client-login-timeout=Dur\u00e9e d''inactivit\u00e9 de connexion (timeout) +client-login-timeout.tooltip=Dur\u00e9e maximale qu''a un client pour finir le protocole du jeton d''acc\u00e8s. Devrait \u00eatre de l''ordre de la minute (1 min). +login-timeout=Dur\u00e9e d''inactivit\u00e9 de connexion +login-timeout.tooltip=Dur\u00e9e maximale autoris\u00e9e pour finaliser la connexion. Devrait \u00eatre relativement long \: 30 minutes, voire plus. +login-action-timeout=Dur\u00e9e d''inactivit\u00e9 des actions de connexions +login-action-timeout.tooltip=Dur\u00e9e maximale qu''a un utilisateur pour finir ses actions concernant la mise \u00e0 jour de son mot de passe ou bien de la configuration du mot de passe \u00e0 usage unique (OTP). Devrait \u00eatre relativement long \: 5 minutes, voire plus. +headers=En-t\u00eates +brute-force-detection=D\u00e9tection des attaques par force brute +x-frame-options=X-Frame-Options +click-label-for-info=Cliquer sur le label pour plus d''information. Les valeurs par d\u00e9faut \u00e9vitent que les pages soient incluses dans des iframes \u00e9trang\u00e8res. +content-sec-policy=Content-Security-Policy +max-login-failures=Nombre maximal d''erreurs de connexion +max-login-failures.tooltip=Nombre d''erreurs avant de d\u00e9clencher le temps d''attente. +wait-increment=Temps d''attente +wait-increment.tooltip=Quand le seuil des erreurs est atteint, combien de temps l''utilisateur est-il bloqu\u00e9 ? +quick-login-check-millis=Nombre de millisecondes entre deux connexions +quick-login-check-millis.tooltip=Si une erreur apparait trop rapidement, bloquer le compte utilisateur. +min-quick-login-wait=Dur\u00e9e minimale d''attente entre deux connexions +min-quick-login-wait.tooltip=Dur\u00e9e d''attente demand\u00e9e apr\u00e8s une erreur entre deux connexions. +max-wait=Dur\u00e9e maximale d''attente +max-wait.tooltip=Dur\u00e9e maximale de blocage du compte utilisateur +failure-reset-time=Dur\u00e9e de remise \u00e0 z\u00e9ro des erreurs +failure-reset-time.tooltip=Quand les erreurs sont-elles remises \u00e0 z\u00e9ro ? +realm-tab-login=Connexion +realm-tab-keys=Clefs +realm-tab-email=Courriels +realm-tab-themes=Th\u00e8mes +#realm-tab-localization=Localization +realm-tab-cache=Cache +realm-tab-tokens=Jetons +realm-tab-security-defenses=Mesures de s\u00e9curit\u00e9 +realm-tab-general=G\u00e9n\u00e9ral +add-realm=Ajouter un domaine + +#Session settings +realm-sessions=Sessions du domaine +revocation=R\u00e9vocation +logout-all=D\u00e9connexion globale +active-sessions=Sessions actives +sessions=Sessions +not-before=Pas avant +not-before.tooltip=R\u00e9voquer tous les jetons demand\u00e9s avant cette date. +set-to-now=Mettre \u00e0 maintenant +push=Appuyer +push.tooltip=Pour tous les clients ayant une URL d''administration, les notifier de la politique de r\u00e9vocation. diff --git a/keycloak-themes/base/admin/messages/admin-messages_it.properties b/keycloak-themes/base/admin/messages/admin-messages_it.properties new file mode 100644 index 0000000..e69de29 diff --git a/keycloak-themes/base/admin/messages/admin-messages_ja.properties b/keycloak-themes/base/admin/messages/admin-messages_ja.properties new file mode 100644 index 0000000..ca3cc1a --- /dev/null +++ b/keycloak-themes/base/admin/messages/admin-messages_ja.properties @@ -0,0 +1,1639 @@ +# encoding: utf-8 +consoleTitle=Keycloak管理コンソール + +# Common messages +enabled=有効 +hidden=非表示 +link-only-column=リンクのみ +name=名前 +displayName=表示名 +displayNameHtml=HTML表示名 +save=保存 +cancel=キャンセル +next=次へ +onText=オン +offText=オフ +client=クライアント +clients=クライアント +clear=クリア +selectOne=1つ選択... + +true=はい +false=いいえ + +endpoints=エンドポイント + +# Realm settings +realm-detail.enabled.tooltip=有効の場合は、ユーザーとクライアントはこのレルムのみアクセス可能になります +realm-detail.protocol-endpoints.tooltip=プロトコル・エンドポイントの設定を表示します。 +realm-detail.protocol-endpoints.oidc=OpenIDエンドポイントの設定 +realm-detail.protocol-endpoints.saml=SAML 2.0アイデンティティー・プロバイダー・メタデータ +realm-detail.userManagedAccess.tooltip=有効にすると、ユーザーはアカウント管理コンソールを使用してリソースとパーミッションを管理できます。 +userManagedAccess=User-Managed Access +registrationAllowed=ユーザー登録 +registrationAllowed.tooltip=登録ページの有効/無効。ログインページに登録のリンクも表示されるようになります。 +registrationEmailAsUsername=Eメールをユーザー名とする +registrationEmailAsUsername.tooltip=有効の場合は、登録フォームにおいてユーザー名フィールドが非表示となり、Eメールが新規ユーザーのユーザー名として使われます。 +editUsernameAllowed=ユーザー名の編集 +editUsernameAllowed.tooltip=有効の場合はユーザー名フィールドが編集可能になり、そうでない場合は読み取り専用になります。 +resetPasswordAllowed=パスワード忘れ +resetPasswordAllowed.tooltip=パスワードを忘れてしまった場合にクリックするリンクを、ログインページに表示します。 +rememberMe=ログイン状態の保存 +rememberMe.tooltip=セッションの有効期限が切れるまではブラウザーの再起動でもログイン状態を保存するチェックボックスをログインページに表示します。 +loginWithEmailAllowed=Eメールでログイン +loginWithEmailAllowed.tooltip=ユーザーがEメールアドレスでログインできるようにします。 +duplicateEmailsAllowed=メールの重複 +duplicateEmailsAllowed.tooltip=複数のユーザーが同じEメールアドレスを持つことを許可します。この設定を変更すると、ユーザーのキャッシュもクリアされます。重複するEメールアドレスのサポートを無効にした後で、データベース内の既存ユーザーのEメールの制約を手動で更新することをお勧めします。 +verifyEmail=Eメールの確認 +verifyEmail.tooltip=初回ログイン後またはアドレスの変更が送信された後に、ユーザーに自分の電子メールアドレスを確認するように要求します。 +sslRequired=SSLの要求 +sslRequired.option.all=全てのリクエスト +sslRequired.option.external=外部リクエスト +sslRequired.option.none=なし +sslRequired.tooltip=HTTPSが必須かどうか。「なし」は、HTTPSがどのIPアドレスのクライアントにも要求されないことを意味します。「外部リクエスト」は、ローカルホストとプライベートIPアドレスのクライアントがHTTPSなしでアクセスできることを意味します。「すべてのリクエスト」は、HTTPSがすべてのIPアドレスのクライアントに要求されることを意味します。 +publicKeys=公開鍵 +publicKey=公開鍵 +privateKey=秘密鍵 +gen-new-keys=新しい鍵を生成する +certificate=証明書 +host=ホスト +smtp-host=SMTPホスト +port=ポート +smtp-port=SMTPポート(デフォルトは25) +smtp-password.tooltip=SMTPパスワード。このフィールドは、ボールトから値を取得できます。${vault.ID}形式を使用します。 +from=差出人 +fromDisplayName=差出人の表示名 +fromDisplayName.tooltip=差出人のアドレスのユーザー・フレンドリーな名前です(オプション)。 +replyTo=返信先 +replyToDisplayName=返信先の表示名 +replyToDisplayName.tooltip=返信先のアドレスのユーザー・フレンドリーな名前です(オプション)。 +envelopeFrom=Envelope From +envelopeFrom.tooltip=バウンスに使用されるEメールアドレス(オプション)。 +sender-email-addr=送信者のメールアドレス +sender-email-addr-display=送信者Eメールアドレスの表示名 +reply-to-email-addr=返信先のメールアドレス +reply-to-email-addr-display=返信先メールアドレスの表示名 +sender-envelope-email-addr=送信者のEnvelope Eメールアドレス +enable-ssl=SSLの有効 +enable-start-tls=StartTLSの有効 +enable-auth=認証の有効 +username=ユーザー名 +login-username=ログインユーザー名 +password=パスワード +login-password=ログイン・パスワード +login-theme=ログインテーマ +login-theme.tooltip=ログイン、OTP、グラント、登録、およびパスワード忘れに使用するページのテーマを選択します。 +account-theme=アカウントテーマ +account-theme.tooltip=ユーザー・アカウント管理画面のテーマを選択します。 +admin-console-theme=管理コンソールテーマ +select-theme-admin-console=管理コンソールのテーマを選択します。 +email-theme=Eメールテーマ +select-theme-email=サーバーから送信されるEメールのテーマを選択します。 +i18n-enabled=国際化の有効 +supported-locales=サポートされるロケール +supported-locales.placeholder=ロケールを入力し、Enterキーを押してください +default-locale=デフォルト・ロケール +#localization-upload-file=Upload localization JSON file +#missing-locale=Missing locale. +#missing-file=Missing file. Please select a file to upload. +#localization-file.upload.success=The localization data has been loaded from file. +#localization-file.upload.error=The file can not be uploaded. Please verify the file. +#localization-show=Show realm specific localizations +#no-localizations-configured=No realm specific localizations configured +#add-localization-text=Add localization text +#locale.create.success=The Locale has been created. +#localization-text.create.success=The localization text has been created. +#localization-text.update.success=The localization text has been updated. +#localization-text.remove.success=The localization text has been deleted. +realm-cache-clear=レルムキャッシュ +realm-cache-clear.tooltip=レルムキャッシュからすべてのエントリーをクリアする(これにより、すべてのレルムのエントリーがクリアされます)。 +user-cache-clear=ユーザー・キャッシュ +user-cache-clear.tooltip=ユーザー・キャッシュからすべてのエントリーを削除します(これにより、すべてのレルムのエントリーがクリアされます)。 +keys-cache-clear=キーキャッシュ +keys-cache-clear.tooltip=外部公開鍵のキャッシュからすべてのエントリーを消去します。これらは、外部のクライアントまたはアイデンティティー・プロバイダーの鍵です(これにより、すべてのレルムのエントリーがクリアされます)。 +default-signature-algorithm=デフォルトの署名アルゴリズム +default-signature-algorithm.tooltip=このレルムでトークンの署名に使用されるデフォルトのアルゴリズム +revoke-refresh-token=リフレッシュ・トークンの無効化 +revoke-refresh-token.tooltip=有効にすると、リフレッシュ・トークンは「リフレッシュ・トークンの最大再利用回数」までしか使用できず、別のトークンが使用されると無効化されます。無効にすると、リフレッシュ・トークンは使用後に無効化されず、複数回使用できます。 +refresh-token-max-reuse=リフレッシュ・トークンの最大再利用回数 +refresh-token-max-reuse.tooltip=リフレッシュ・トークンを再利用できる最大回数。別のトークンが使用された場合、即時に無効化されます。 +sso-session-idle=SSOセッション・アイドル +seconds=秒 +minutes=分 +hours=時 +days=日 +sso-session-max=SSOセッション最大 +sso-session-idle.tooltip=セッションの有効期限が切れるまでのアイドル時間です。セッションの有効期限が切れると、トークンとブラウザー・セッションは無効化されます。 +sso-session-max.tooltip=セッションの有効期限が切れるまでの最大時間です。セッションの有効期限が切れると、トークンとブラウザー・セッションは無効化されます。 +sso-session-idle-remember-me=SSOセッション・アイドル・リメンバーミー +sso-session-idle-remember-me.tooltip=リメンバーミー・セッションの有効期限が切れるまでのアイドル時間です。セッションが期限切れになると、トークンおよびブラウザー・セッションは無効になります。設定されていない場合は、標準のSSOセッション・アイドル値が使用されます。 +sso-session-max-remember-me=SSOセッション最大リメンバーミー +sso-session-max-remember-me.tooltip=ユーザーがリメンバーミー・オプションを設定したときにセッションが期限切れになるまでの最大時間。セッションが期限切れになると、トークンおよびブラウザー・セッションは無効になります。設定されていない場合は、標準のSSOセッション最大の値が使用されます。 +offline-session-idle=オフライン・セッション・アイドル +offline-session-idle.tooltip=セッションの有効期限が切れるまでのオフライン時間です。この期限内に少なくとも1回はオフライン・トークンを使用してリフレッシュしないと、オフライン・セッションは有効期限切れとなります。 +realm-detail.hostname=ホスト名 +realm-detail.hostname.tooltip=レルムに対してホスト名を設定します。特定のレルムのサーバーホスト名を上書きするために、固定ホスト名プロバイダーと組み合わせて使用??します。 +realm-detail.frontendUrl=フロントエンドURL +realm-detail.frontendUrl.tooltip=レルムのフロントエンドURLを設定します。デフォルトのホスト名プロバイダーと組み合わせて使用し、特定のレルムのフロントエンド・リクエストのベースURLをオーバーライドします。 + +## KEYCLOAK-7688 Offline Session Max for Offline Token +offline-session-max-limited=オフライン・セッション最大制限 +offline-session-max-limited.tooltip=オフライン・セッションの最大時間制限を有効にします。 +offline-session-max=オフライン・セッション最大 +offline-session-max.tooltip=アクティビティーに関係なく、オフライン・セッションが期限切れになるまでの最大時間。 +client-session-idle=クライアント・セッション・アイドル +client-session-idle.tooltip=クライアント・セッションが期限切れになるまでアイドル状態にできる時間。トークンは、クライアント・セッションが期限切れになると無効になります。設定しない場合、標準のSSOセッション・アイドルの値が使用されます。 +client-session-max=クライアント・セッション最大 +client-session-max.tooltip=クライアント・セッションが期限切れになるまでの最大時間。トークンは、クライアント・セッションが期限切れになると無効になります。設定されていない場合は、標準のSSOセッション最大の値が使用されます。 +access-token-lifespan=アクセストークン生存期間 +access-token-lifespan.tooltip=アクセストークンが有効期限切れとなる最大時間です。この値はSSOタイムアウトと比べて短くすることをお勧めします。 +access-token-lifespan-for-implicit-flow=インプリシット・フローにおけるアクセストークン生存期間 +access-token-lifespan-for-implicit-flow.tooltip=OpenID Connect インプリシット・フローで発行されたアクセストークンが有効期限切れとなる最大時間です。この値はSSOタイムアウトより短くすることをお勧めします。インプリシット・フローではトークンを更新することはありませんので、「アクセストークン生存期間」とは異なる別々のタイムアウト設定を設けています。 +action-token-generated-by-admin-lifespan=デフォルトの管理者起動アクションの有効期間 +action-token-generated-by-admin-lifespan.tooltip=管理者によってユーザーに送信されたアクション許可の有効期限が切れるまでの最大時間。この値は、管理者が現在オフラインになっているユーザーに対してEメールを送信できるように、長くすることをお勧めします。デフォルトのタイムアウトは、トークンを発行する直前にオーバーライドすることができます。 +action-token-generated-by-user-lifespan=ユーザー起動アクションの有効期間 +action-token-generated-by-user-lifespan.tooltip=ユーザーが送信したアクション許可(パスワード忘れのEメールなど)の有効期限が切れるまでの最大時間。ユーザーが自分で作成した操作にすばやく反応することが期待されるため、この値は短くすることをお勧めします。 +saml-assertion-lifespan=アサーションの有効期限 +saml-assertion-lifespan.tooltip=SAMLアサーション条件に設定された有効期限。その後、アサーションは無効になります。「SessionNotOnOrAfter」属性は変更されず、レルムレベルで定義された「SSOセッション最大」時間を引き続き使用します。 + +action-token-generated-by-user.execute-actions=アクションの実行 +action-token-generated-by-user.idp-verify-account-via-email=IdPアカウントのEメール検証 +action-token-generated-by-user.reset-credentials=パスワード忘れ +action-token-generated-by-user.verify-email=Eメールでの確認 +action-token-generated-by-user.tooltip=ユーザーが送信したアクション許可(パスワード忘れのEメールなど)が特定のアクションで期限切れになるまでの、最大時間のデフォルト設定をオーバーライドします。ユーザーが自分で作成した操作にすばやく反応することが期待されるため、この値は短くすることをお勧めします。 +action-token-generated-by-user.reset=リセット +action-token-generated-by-user.operation=ユーザー起動アクションの有効期間のオーバーライド + +client-login-timeout=クライアントのログイン・タイムアウト +client-login-timeout.tooltip=クライアントがアクセストークン・プロトコルを終了するまでの最大時間。これは通常1分です。 +login-timeout=ログイン・タイムアウト +login-timeout.tooltip=ユーザーがログインを完了するまでの最大時間です。これは30分以上のように比較的長くすることをお勧めします。 +login-action-timeout=ログイン・アクション・タイムアウト +login-action-timeout.tooltip=ユーザーがパスワードの更新やOTPの設定のようなログインに関係するアクションを完了するまでの最大時間です。これは5分以上と比較的長くすることをお勧めします。 +headers=ヘッダー +brute-force-detection=ブルートフォースの検出 +x-frame-options=X-Frame-Options +x-frame-options-tooltip=デフォルト値では別のオリジンのIFrameからの読み込みを防ぎます(詳細はラベルをクリックしてください) +content-sec-policy=Content-Security-Policy +content-sec-policy-tooltip=デフォルト値では別のオリジンのIFrameからの読み込みを防ぎます(詳細はラベルをクリックしてください) +content-sec-policy-report-only=Content-Security-Policy-Report-Only +content-sec-policy-report-only-tooltip=コンテンツ・セキュリティー・ポリシーのテスト用 +content-type-options=X-Content-Type-Options +content-type-options-tooltip=デフォルト値ではInternet ExplorerとGoogle Chromeに対して、宣言されたcontent-typeを避けてレスポンスのMIME-sniffingを行うことを防ぎます(詳細はラベルをクリックしてください) +robots-tag=X-Robots-Tag +robots-tag-tooltip=検索エンジンにページが表示されないようにする(詳細については、ラベルをクリックしてください)。 +x-xss-protection=X-XSS-Protection +x-xss-protection-tooltip=このヘッダーは、ブラウザーにクロス・サイト・スクリプティング(XSS)フィルターを設定します。デフォルトの動作を使用すると、ブラウザーはXSS攻撃が検出されたときにページのレンダリングを防止します(詳細については、ラベルをクリックしてください) +strict-transport-security=HTTP Strict Transport Security(HSTS) +strict-transport-security-tooltip=Strict-Transport-Security HTTPヘッダーは、常にHTTPSを使用するようにブラウザーに指示します。ブラウザーはこのヘッダーを確認すると、max-ageで指定された期間(1年間)、HTTPS経由でのみサイトにアクセスします(サブドメインを含む)。 +permanent-lockout=永久ロックアウト +permanent-lockout.tooltip=最大ログイン失敗回数を超えたときに、ユーザーを永久にロックします。 +max-login-failures=最大ログイン失敗回数 +max-login-failures.tooltip=検出するまでの失敗回数です。 +wait-increment=連続失敗時の待機時間 +wait-increment.tooltip=失敗回数が閾値に達した場合、どれくらいの時間ユーザーはロックアウトされるか設定します。 +quick-login-check-millis=クイックログイン試行間のミリ秒数チェック +quick-login-check-millis.tooltip=クイックログイン失敗があまりにも頻繁に発生した場合は、ユーザーをロックアウトします。 +min-quick-login-wait=クイックログイン失敗時の最小待機時間 +min-quick-login-wait.tooltip=クイックログイン失敗後にどれくらいの時間待機するか設定します。 +max-wait=最大待機時間 +max-wait.tooltip=ユーザーがロックアウトされる最大待機時間を設定します。 +failure-reset-time=ログイン失敗回数のリセット時間 +failure-reset-time.tooltip=いつ失敗回数がリセットされるか設定します。 +realm-tab-login=ログイン +realm-tab-keys=鍵 +realm-tab-email=Eメール +realm-tab-themes=テーマ +#realm-tab-localization=Localization +realm-tab-cache=キャッシュ +realm-tab-tokens=トークン +realm-tab-client-registration=クライアント登録 +realm-tab-security-defenses=セキュリティー防御 +realm-tab-general=一般 +add-realm=レルムの追加 + +#Session settings +realm-sessions=レルムセッション +revocation=無効化 +logout-all=すべてログアウトする +active-sessions=有効なセッション +offline-sessions=オフライン・セッション +sessions=セッション +not-before=この日時より前 +not-before.tooltip=この日時より前に発行されたトークンを無効化します。 +set-to-now=現在日時を設定 +push=プッシュ +push.tooltip=管理URLを持つすべてのクライアントに対して、新しい無効化ポリシーを通知します。 + +#Protocol Mapper +usermodel.prop.label=プロパティー +usermodel.prop.tooltip=UserModelインターフェイスのプロパティー・メソッドの名前です。例えば、「email」の値はUserModel.getEmail()メソッドを参照しています。 +usermodel.attr.label=ユーザー属性 +usermodel.attr.tooltip=格納されるユーザー属性名、UserMode.attributeマップ内の属性名です。 +userSession.modelNote.label=ユーザー・セッション・ノート +userSession.modelNote.tooltip=UserSessionModel.noteマップ内のユーザー・セッション・ノート名です。 +multivalued.label=マルチバリュー +multivalued.tooltip=属性がマルチバリューをサポートしているかどうかを示します。サポートしている場合は、この属性のすべての値リストがクレームとして設定されます。サポートしていない場合は、最初の値だけがクレームとして設定されます。 +aggregate.attrs.label=属性値の集約 +aggregate.attrs.tooltip=属性値をグループ属性と集約する必要があるかどうかを示します。OpenID Connectマッパーを使用している場合は、すべての値を取得するためにマルチバリューのオプションも有効にする必要があります。重複した値は破棄され、値の順序はこのオプションでは保証されません。 +selectRole.label=ロールの選択 +selectRole.tooltip=左側にあるテキストボックスにロールを入力するか、ブラウズして必要なロールを選択するためにこのボタンをクリックしてください。 +tokenClaimName.label=トークンクレーム名 +tokenClaimName.tooltip=トークン内に挿入するクレームの名前を設定します。「address.street」のように完全修飾名で設定します。この場合、ネストされたJSONオブジェクトが作成されます。ネスティングを防ぎ、ドットを文字通りに使用するには、ドットをバックスラッシュ(\\.)でエスケープします。 +jsonType.label=クレームJSONタイプ +jsonType.tooltip=トークンへのJSONクレームの追加で使用されるJSONタイプを設定します。long、int、boolean、String、JSONが有効な値です。 +includeInIdToken.label=IDトークンに追加 +includeInIdToken.tooltip=クレームをIDトークンに追加すべきかどうかを設定します。 +includeInAccessToken.label=アクセストークンに追加 +includeInAccessToken.tooltip=クレームをアクセストークンに追加すべきかどうかを設定します。 +includeInUserInfo.label=UserInfoに追加 +includeInUserInfo.tooltip=クレームをUserInfoに追加すべきかどうかを設定します。 +usermodel.clientRoleMapping.clientId.label=クライアントID +usermodel.clientRoleMapping.clientId.tooltip=ロールマッピング用のクライアントID。このクライアントのクライアント・ロールだけがトークンに追加されます。これが設定されていない場合は、すべてのクライアントのクライアント・ロールがトークンに追加されます。 +usermodel.clientRoleMapping.rolePrefix.label=クライアント・ロールのプレフィックス +usermodel.clientRoleMapping.rolePrefix.tooltip=各クライアント・ロールのプレフィックスを設定します(オプション)。 +usermodel.clientRoleMapping.tokenClaimName.tooltip=トークン内に挿入するクレームの名前を設定します。「address.street」のように完全修飾名で設定します。この場合、ネストされたJSONオブジェクトが作成されます。ネスティングを防ぎ、ドットを文字通りに使用するには、ドットをバックスラッシュ(\\.)でエスケープします。特別なトークン${client_id}を使うことができ、これは実際のクライアントIDに置き換えられます。使用例は「resource_access.${client_id}.roles」です。これは、すべてのクライアントからロールを追加する場合(特に「Client ID」スイッチが設定されていない場合)や、各クライアントのクライアント・ロールを別々の場所に保存する場合に、特に便利です。 +usermodel.realmRoleMapping.rolePrefix.label=レルムロールのプレフィックス +usermodel.realmRoleMapping.rolePrefix.tooltip=各レルムロールのプレフィックスを設定します(オプション)。 +sectorIdentifierUri.label=セクター識別子URI +sectorIdentifierUri.tooltip=pairwise sub値を使用し、かつ動的クライアント登録をサポートするプロバイダーは、sector_identifier_uriパラメーターを使用すべきです(SHOULD)。これは、共通の管理下にあるWebサイト群に対し、個々のドメイン名とは独立してparwise sub値の一貫性を保持する方法を提供します。また、クライアントに対し、すべてのユーザーを再登録させることなしにredirect_uriを変更する方法も提供します。 +pairwiseSubAlgorithmSalt.label=ソルト +pairwiseSubAlgorithmSalt.tooltip=ペアワイズ対象識別子を計算する際に使用するソルトを設定します。空白のままにするとソルトは生成されます。 +addressClaim.street.label=その他住所のユーザー属性名 +addressClaim.street.tooltip=「address」トークンクレーム内の「street_address」サブクレームにマップするために使用されるユーザー属性の名前。デフォルトは「street」です。 +addressClaim.locality.label=市区町村のユーザー属性名 +addressClaim.locality.tooltip=「address」トークンクレーム内の「locality」サブクレームにマップするために使用されるユーザー属性の名前。デフォルトは「locality」です。 +addressClaim.region.label=都道府県のユーザー属性名 +addressClaim.region.tooltip=「address」トークンクレーム内の「region」サブクレームにマップするために使用されるユーザー属性の名前。デフォルトは「region」です。 +addressClaim.postal_code.label=郵便番号のユーザー属性名 +addressClaim.postal_code.tooltip=「address」トークンクレーム内の「postal_code」サブクレームにマップするために使用されるユーザー属性の名前。デフォルトは「postal_code」です。 +addressClaim.country.label=国のユーザー属性名 +addressClaim.country.tooltip=「address」トークンクレーム内の「country」サブクレームにマップするために使用されるユーザー属性の名前。デフォルトは「country」です。 +addressClaim.formatted.label=整形された住所のユーザー属性名 +addressClaim.formatted.tooltip=「address」トークンクレーム内の「formatted」サブクレームにマップするために使用されるユーザー属性の名前。デフォルトは「formatted」です。 +included.client.audience.label=含まれるクライアント・オーディエンス +included.client.audience.tooltip=指定されたオーディエンス・クライアントのクライアントIDが、トークンのオーディエンス(aud)フィールドに含まれます。トークンに既存のオーディエンスが存在する場合は、指定された値が単にそれらに追加されます。既存のオーディエンスを上書きすることはありません。 +included.custom.audience.label=含まれるカスタム・オーディエンス +included.custom.audience.tooltip=これは「含まれるクライアント・オーディエンス」が入力されていない場合にのみ使用されます。指定された値が、トークンのオーディエンス(aud)フィールドに含まれます。トークンに既存のオーディエンスが存在する場合は、指定された値が単にそれらに追加されます。既存のオーディエンスを上書きすることはありません。 + +# client details +clients.tooltip=クライアントとはレルム内の信頼されたブラウザー・アプリケーションやWebサービスです。これらのクライアントはログインを要求することができます。また、クライアント固有のロールを定義することができます。 +search.placeholder=検索... +search.loading=検索しています... +create=作成 +import=インポート +client-id=クライアントID +base-url=ベースURL +actions=アクション +not-defined=未定義 +edit=編集 +delete=削除 +no-results=結果がありません +no-clients-available=使用可能なクライアントはありません +add-client=クライアントの追加 +select-file=ファイルを選択 +view-details=詳細を参照 +clear-import=インポートをクリア +client-id.tooltip=URIとトークンで参照されるIDを指定します。例えば「my-client」です。SAMLにおいては期待されるAuthnRequestのIssuerの値になります。 +client.name.tooltip=クライアントの表示名を指定します。例えば、「My Client」です。ローカライズ用のキーもサポートしています。例\: ${my_client} +client.enabled.tooltip=無効なクライアントはログインを開始したり、アクセストークンを取得したりすることはできません。 +alwaysDisplayInConsole=常にコンソールに表示 +alwaysDisplayInConsole.tooltip=ユーザーのアクティブなセッションがない場合でも、このクライアントを常にアカウント・コンソールに一覧表示します。 +consent-required=同意が必要 +consent-required.tooltip=有効の場合は、ユーザーはクライアント・アクセスに同意する必要があります。 +client.display-on-consent-screen=同意画面でクライアントを表示 +client.display-on-consent-screen.tooltip=同意する必要がある場合にのみ適用されます。このスイッチがオフの場合、同意画面には設定されたクライアント・スコープに対応する同意のみが表示されます。オンの場合、同意画面にこのクライアント自体に関する項目も1つ表示されます。 +client.consent-screen-text=クライアントの同意画面のテキスト +client.consent-screen-text.tooltip=このクライアントに対して、「同意画面でクライアントを表示」がオンの場合にのみ適用されます。このクライアントに対する特定のアクセス許可について、同意画面に表示するテキストを設定します。 +client-protocol=クライアント・プロトコル +client-protocol.tooltip=「OpenID Connect」により、クライアントは認可サーバーによって実行される認証に基づいてエンドユーザーのアイデンティティーを検証できます。「SAML」は、クロスドメインのシングル・サインオン(SSO)を含むWebベースの認証および認可のシナリオを可能にし、アサーションを含むセキュリティー・トークンを使用して情報を渡します。 +access-type=アクセスタイプ +access-type.tooltip=「Confidential」クライアントはログイン・プロトコルを開始するためにシークレットを必要とします。「Public」クライアントはシークレットを必要としません。「Bearer-only」クライアントはログインを開始することはないWebサービスです。 +standard-flow-enabled=標準フローの有効 +standard-flow-enabled.tooltip=OpenID Connectの標準的な、認可コードによるリダイレクト・ベースの認証を有効にします。OpenID ConnectまたはOAuth2の仕様における「認可コードフロー」のサポートを有効にします。 +implicit-flow-enabled=インプリシット・フローの有効 +implicit-flow-enabled.tooltip=OpenID Connectの認可コードなしのリダイレクト・ベース認証のサポートを有効にします。OpenID ConnectまたはOAuth2の仕様における「インプリシット・フロー」のサポートを有効にします。 +direct-access-grants-enabled=ダイレクト・アクセス・グラントの有効 +direct-access-grants-enabled.tooltip=ダイレクト・アクセス・グラントのサポートを有効にします。これは、アクセストークンの取得のためにKeycloakサーバーとユーザーのユーザー名/パスワードで直接アクセスを行います。OAuth2の仕様における「リソース・オーナー・パスワード・クレデンシャル・グラント」のサポートを有効にします。 +service-accounts-enabled=サービス・アカウントの有効 +service-accounts-enabled.tooltip=このクライアントをKeycloakで認証し、このクライアント専用のアクセストークンの取得ができるようになります。OAuth2の仕様における「クライアント・クレデンシャル・グラント」のサポートを有効にします。 +include-authnstatement=AuthnStatementを含める +include-authnstatement.tooltip=認証方式とタイムスタンプを含めたステートメントをログイン・レスポンスに含めるべきか設定します。 +include-onetimeuse-condition=OneTimeUse条件を含める +include-onetimeuse-condition.tooltip=OneTimeUse条件をログイン・レスポンスに含めるべきか設定します。 +sign-documents=ドキュメントを署名する +sign-documents.tooltip=SAMLドキュメントをレルムで署名すべきか設定します。 +sign-documents-redirect-enable-key-info-ext=REDIRECT署名鍵検索の最適化 +sign-documents-redirect-enable-key-info-ext.tooltip=Keycloakアダプターによって保護されたSPのREDIRECTバインディングでSAMLドキュメントに署名する際、署名鍵のIDを要素のSAMLプロトコルメッセージに含める必要があるかどうかを設定します。これにより、検証のために既知のすべてのキーを試行する代わりに単一のキーを使用するため、署名の検証が最適化されます。 +sign-assertions=アサーションを署名する +sign-assertions.tooltip=SAMLドキュメント内のアサーションを署名すべきか設定します。もしドキュメントが既に署名済みの場合は、この設定は不要です。 +signature-algorithm=署名アルゴリズム +signature-algorithm.tooltip=ドキュメントの署名に使用する署名アルゴリズムです。 +canonicalization-method=正規化方式 +canonicalization-method.tooltip=XML署名の正規化方式(Canonicalization Method)を設定します。 +encrypt-assertions=アサーションを暗号化する +encrypt-assertions.tooltip=SAMLアサーションをクライアントの公開鍵でAESを使い暗号化すべきか設定します。 +client-signature-required=クライアント署名が必須 +client-signature-required.tooltip=クライアントがSAMLリクエストとレスポンスを署名するか、そしてそれらを検証すべきどうかか設定します。 +force-post-binding=POSTバインディングを強制 +force-post-binding.tooltip=レスポンスに常にPOSTバインディングを使用します。 +front-channel-logout=フロントチャンネル・ログアウト +front-channel-logout.tooltip=有効の場合は、ログアウトはクライアントへのブラウザー・リダイレクトが必要になります。無効の場合は、サーバーはログアウトのバックグラウンド呼び出しを行います。 +force-name-id-format=Name IDフォーマットを強制 +force-name-id-format.tooltip=要求されたNameIDサブジェクト・フォーマットを無視し、管理コンソールで設定された物を使用します。 +name-id-format=Name IDフォーマット +name-id-format.tooltip=サブジェクトに使用するName IDフォーマットを設定します。 +mapper.nameid.format.tooltip=マッパーを適用するName IDフォーマット +root-url=ルートURL +root-url.tooltip=相対URLに追加するルートURLを設定します。 +valid-redirect-uris=有効なリダイレクトURI +valid-redirect-uris.tooltip=ログインまたはログインの成功後にブラウザーがリダイレクト可能とする、有効なURIパターンを設定します。「http://example.com/*」のような単純なワイルドカードが使用可能です。相対パス、つまり「/my/relative/path/*」も指定可能です。相対パスはクライアントのルートURLを基準とします。または、未指定の場合は認証サーバーのルートURLが使用されます。SAMLでは、ログイン・リクエストに埋め込まれたコンシューマー・サービスのURLに依存している場合は、有効なURIパターンを設定する必要があります。 +base-url.tooltip=認証サーバーがクライアントへのリダイレクトまたは戻るリンクを必要とする際に使用するデフォルトURLを設定します。 +admin-url=管理URL +admin-url.tooltip=クライアントの管理インターフェイスのURLを設定します。クライアントがアダプターのREST APIをサポートしている場合に設定してください。このREST APIにより、認証サーバーは無効化ポリシーや他の管理タスクをプッシュすることができます。通常、クライアントのベースURLを設定します。 +master-saml-processing-url=SAMLを処理するマスターURL +master-saml-processing-url.tooltip=設定された場合は、このURLがSPのアサーション・コンシューマーおよびシングル・ログアウト・サービスの両方のBindingに使われます。これは、SAMLエンドポイントの詳細設定にある各Bindingやサービスの設定にて個別に上書きすることができます。 +idp-sso-url-ref=IDP Initiated SSOのURL名 +idp-sso-url-ref.tooltip=IDP Initiated SSOを行う際にクライアントを参照するためのURLフラグメント名を設定します。空にするとIDP Initiated SSOは無効になります。ブラウザーから参照するURLは「{server-root}/realms/{realm}/protocol/saml/clients/{client-url-name}」になります。 +idp-sso-url-ref.urlhint=対象のIDP initiated SSOのURL: +idp-sso-relay-state=IDP Initiated SSOのRelayState +idp-sso-relay-state.tooltip=IDP Initiated SSOを行う際のSAMLリクエストで送信したいRelayStateを設定します。 +web-origins=Webオリジン +web-origins.tooltip=許可されるCORSオリジンを設定します。有効なリダイレクトURIのすべてのオリジンを許可するには「+」を追加してください。ただし、これには「*」ワイルドカードは含まれません。すべてのオリジンを許可するには、明示的に「*」を追加してください。 +fine-oidc-endpoint-conf=OpenID Connectの詳細設定 +fine-oidc-endpoint-conf.tooltip=このセクションを展開して、OpenID Connectプロトコルに関連するこのクライアントの高度な設定を行います。 +access-token-signed-response-alg=アクセストークン署名アルゴリズム +access-token-signed-response-alg.tooltip=アクセストークンの署名に使用されるJWAアルゴリズム。 +id-token-signed-response-alg=IDトークン署名アルゴリズム +id-token-signed-response-alg.tooltip=IDトークンの署名に使用されるJWAアルゴリズム。 +id-token-encrypted-response-alg=IDトークン暗号化鍵管理アルゴリズム +id-token-encrypted-response-alg.tooltip=IDトークンの暗号化鍵の管理に使用されるJWAアルゴリズム。このオプションは、暗号化されたIDトークンが必要な場合に必須です。空のままにすると、IDトークンは署名されますが、暗号化されません。 +id-token-encrypted-response-enc=IDトークン暗号化コンテンツの暗号化アルゴリズム +id-token-encrypted-response-enc.tooltip=IDトークンの暗号化の際に、コンテンツの暗号化に使用されるJWAアルゴリズム。このオプションは、暗号化されたIDトークンが必要な場合にのみ必須です。空のままにすると、IDトークンは署名されますが、暗号化されません。 +user-info-signed-response-alg=署名付きUserInfoレスポンスのアルゴリズム +user-info-signed-response-alg.tooltip=署名付きUserInfoエンドポイントのレスポンスに使用するJWAアルゴリズムを設定します。「unsigned」に設定した場合は、UserInfoレスポンスは署名されず、application/json形式で返されます。 +request-object-signature-alg=リクエスト・オブジェクトの署名アルゴリズム +request-object-signature-alg.tooltip=クライアントが「request」または「request_uri」パラメーターで指定されたOIDCリクエスト・オブジェクトを送信する際に使用する必要がある、JWAアルゴリズムを設定します。「any」に設定した場合は、リクエスト・オブジェクトは任意のアルゴリズム(「none」を含む)で署名されます。 +request-object-required=リクエスト・オブジェクトが必要 +request-object-required.tooltip=クライアントが認可リクエストとともにリクエスト・オブジェクトを提供する必要があるかどうか、およびそのためにどの方法を使用できるかを指定します。「not required」に設定されている場合、リクエスト・オブジェクトの提供はオプションです。それ以外のケースでは、リクエスト・オブジェクトを提供する必要があります。「request」に設定されている場合、リクエスト・オブジェクトは値で提供される必要があります。「request_uri」に設定されている場合、リクエスト・オブジェクトは参照によって提供される必要があります。「requestまたはrequest_uri」に設定されている場合、いずれの方法も使用できます。 +fine-saml-endpoint-conf=SAMLエンドポイントの詳細設定 +fine-saml-endpoint-conf.tooltip=アサーション・コンシューマーおよびシングル・ログアウト・サービスの正確なURLを設定するにはこのセクションを開きます。 +assertion-consumer-post-binding-url=アサーション・コンシューマー・サービスのPOSTバインディングURL +assertion-consumer-post-binding-url.tooltip=アサーション・コンシューマー・サービス(ログイン・レスポンス)のSAML POSTバインディングURLを設定します。このBindingのためのURLがない場合は空でよいです。 +assertion-consumer-redirect-binding-url=アサーション・コンシューマー・サービスのRedirectバインディングURL +assertion-consumer-redirect-binding-url.tooltip=アサーション・コンシューマー・サービス(ログイン・レスポンス)のSAML RedirectバインディングURLを設定します。このBindingのためのURLがない場合は空でよいです。 +logout-service-post-binding-url=ログアウト・サービスのPOSTバインディングURL +logout-service-post-binding-url.tooltip=シングル・ログアウト・サービスのSAMLPOSTバインディングURLを設定します。異なるBindingを使用している場合は空でよいです。 +logout-service-redir-binding-url=ログアウト・サービスのRedirectバインディングURL +logout-service-redir-binding-url.tooltip=シングル・ログアウト・サービスのSAMLRedirectバインディングURLを設定します。異なるBindingを使用している場合は空でよいです。 +saml-signature-keyName-transformer=SAML署名鍵名 +saml-signature-keyName-transformer.tooltip=署名されたSAML文書には、KeyName要素の署名鍵の識別情報が含まれています。Keycloak / RH-SSOカウンター・パーティーの場合は、KEY_IDを使用し、MS AD FSの場合はCERT_SUBJECTを使用します。他のオプションが動作しない場合はNONEをチェックして使用します。 +oidc-compatibility-modes=OpenID Connect互換モード +oidc-compatibility-modes.tooltip=このセクションを展開して、古いOpenID Connect / OAuth2アダプターとの下位互換性の設定を行います。これは、クライアントが古いバージョンのKeycloak / RH-SSOアダプターを使用している場合に特に便利です。 +exclude-session-state-from-auth-response=認証レスポンスからセッション状態を除外 +exclude-session-state-from-auth-response.tooltip=これがオンの場合、パラメーター「session_state」はOpenID Connect認証レスポンスに含まれません。クライアントが「session_state」パラメーターをサポートしていない古いOIDC / OAuth2アダプターを使用している場合に便利です。 + +# client import +import-client=クライアントのインポート +format-option=フォーマット・オプション +select-format=フォーマットを選択 +import-file=ファイルをインポート + +# client tabs +settings=設定 +credentials=クレデンシャル +roles=ロール +mappers=マッパー +mappers.tooltip=プロトコル・マッパーはトークンやドキュメントの変換を行います。ユーザーデータをプロトコルのクレームにマッピングしたり、クライアントと認証サーバー間の任意のリクエストを単に変換したりすることができます。 +scope=スコープ +scope.tooltip=スコープ・マッピングはクライアントに要求されたアクセストークン内に含まれるユーザーのロールマッピングを制限することができます。 +sessions.tooltip=このクライアントの有効なセッションを参照します。どのユーザーがアクティブでいつログインしたかを見ることができます。 +offline-access=オフライン・アクセス +offline-access.tooltip=このクライアントのオフライン・セッションを参照します。オフライン・トークンをどのユーザーがいつ取得したかを見ることができます。このクライアントのすべてのトークンを取り消すには、無効化タブを開き、「この日時より前」に現在日時を設定してください。 +clustering=クラスタリング +installation=インストール +installation.tooltip=様々なクライアント・アダプターの設定フォーマットを生成するヘルパー・ユーティリティーです。生成したものをダウンロードまたはカット・アンド・ペーストしてクライアントに設定することができます。 +service-account-roles=サービス・アカウント・ロール +service-account-roles.tooltip=このクライアント専用のサービス・アカウントのロールマッピングを認証できるようにします。 + +# client credentials +client-authenticator=クライアント認証 +client-authenticator.tooltip=Keycloakサーバーに対してこのクライアントの認証に使用するクライアント認証方式を設定します。 +certificate.tooltip=クライアントで発行され、キーストアの秘密鍵で署名されたJWTを検証するためのクライアント証明書です。 +publicKey.tooltip=クライアントで発行され、秘密鍵で署名されたJWTを検証するための公開鍵です。 +no-client-certificate-configured=クライアント証明書が設定されていません +gen-new-keys-and-cert=新しい鍵と証明書を生成 +import-certificate=証明書をインポート +gen-client-private-key=クライアントの秘密鍵の生成 +generate-private-key=秘密鍵の生成 +kid=Kid +kid.tooltip=インポートされたJWKSのクライアントの公開鍵のKID(Key ID)を設定します。 +use-jwks-url=JWKS URLの使用 +use-jwks-url.tooltip=有効とした場合は、クライアントの公開鍵が指定のJWKS URLからダウンロードされます。これにより、クライアントが新しい鍵ペアを生成した際に、新しい鍵が常に再ダウンロードされるため、柔軟性が向上します。無効とした場合は、Keycloak DBの公開鍵(または証明書)が使用されるため、クライアントの鍵ペアが変更された際には、常に新しい鍵(または証明書)をKeycloak DBにもインポートする必要があります。 +jwks-url=JWKS URL +jwks-url.tooltip=JWK形式のクライアント鍵が格納されているURLを設定します。詳細はJWKの仕様を参照してください。「jwt」クレデンシャルを持つKeycloakクライアント・アダプターを使用している場合は、アプリケーションに「/k_jwks」という接尾辞を付けたURLを使用することができます。例えば、「http://www.myhost.com/myapp/k_jwks」です。 +archive-format=アーカイブ形式 +archive-format.tooltip=JavaキーストアまたはPKCS12アーカイブ形式 +key-alias=キーエイリアス +key-alias.tooltip=秘密鍵と証明書のアーカイブ・エイリアスです。 +key-password=鍵のパスワード +key-password.tooltip=アーカイブ内の秘密鍵にアクセスするためのパスワード +store-password=ストアのパスワード +store-password.tooltip=アーカイブ自身にアクセスするためのパスワード +generate-and-download=生成&ダウンロード +client-certificate-import=クライアント証明書のインポート +import-client-certificate=クライアント証明書のインポート +jwt-import.key-alias.tooltip=証明書のアーカイブ・エイリアスです。 +secret=シークレット +regenerate-secret=シークレットの再生成 +registrationAccessToken=登録用アクセストークン +registrationAccessToken.regenerate=登録用アクセストークンの再生成 +registrationAccessToken.tooltip=登録用アクセストークンにより、クライアントはクライアント登録サービスにアクセスできます。 +add-role=ロールの追加 +role-name=ロール名 +composite=複合 +description=説明 +no-client-roles-available=使用可能なクライアント・ロールはありません。 +composite-roles=複合ロール +composite-roles.tooltip=このロールがユーザーにアサイン(アサイン解除)された際に、関連するロールが暗黙的にアサイン(アサイン解除)されます。 +realm-roles=レルムロール +available-roles=使用可能なロール +add-selected=選択したものを追加 +associated-roles=関連ロール +composite.associated-realm-roles.tooltip=この複合ロールに関連付けされているレルムレベルのロールです。 +composite.available-realm-roles.tooltip=この複合ロールに関連付け可能なレルムレベルのロールです。 +remove-selected=選択されたものを削除 +client-roles=クライアント・ロール +select-client-to-view-roles=ロールを参照するにはクライアントを選択してください +available-roles.tooltip=この複合ロールに関連付け可能なこのクライアントのロールです。 +client.associated-roles.tooltip=この複合ロールに関連付けされているクライアント・ロールです。 +add-builtin=ビルトインを追加 +category=カテゴリー +type=タイプ +priority-order=優先順位 +no-mappers-available=使用可能なマッパーはありません +add-builtin-protocol-mappers=ビルトイン・プロトコル・マッパーを追加 +add-builtin-protocol-mapper=ビルトイン・プロトコル・マッパーを追加 +scope-mappings=スコープ・マッピング +full-scope-allowed=フルスコープを許可 +full-scope-allowed.tooltip=全ての制限の無効を許可します。 +scope.available-roles.tooltip=スコープにアサイン可能なレルムレベルのロールです。 +assigned-roles=アサイン済みロール +assigned-roles.tooltip=スコープにアサイン済みのレルムレベルのロールです。 +effective-roles=有効なロール +realm.effective-roles.tooltip=複合ロールの継承も含めたアサイン済みのレルムレベルのロールです。 +select-client-roles.tooltip=ロールを参照するにはクライアントを選択してください +assign.available-roles.tooltip=アサイン可能なクライアント・ロールです。 +client.assigned-roles.tooltip=アサイン済みクライアント・ロールです。 +client.effective-roles.tooltip=複合ロールより引き継いでいるロールも含めたアサイン済みのクライアント・ロールです。 +basic-configuration=基本設定 +node-reregistration-timeout=ノード再登録のタイムアウト +node-reregistration-timeout.tooltip=登録されたクライアントをクラスターノードへ再登録する際の最大時間間隔を設定します。クラスターノードがこの時間内にKeycloakに再登録リクエストを送信しない場合は、Keycloakから登録解除されます。 +registered-cluster-nodes=登録済みクラスターノード +register-node-manually=ノードを手動で登録 +test-cluster-availability=クラスターの可用性をテスト +last-registration=最終登録 +node-host=ノードホスト +no-registered-cluster-nodes=使用可能な登録済みクラスターノードがありません +cluster-nodes=クラスターノード +add-node=ノードを追加 +active-sessions.tooltip=このクライントの有効なユーザー・セッションの合計数です。 +show-sessions=セッションを表示 +show-sessions.tooltip=有効なセッション数に応じて高負荷なオペレーションになる恐れがありますので注意してください。 +user=ユーザー +from-ip=From IP +session-start=セッション開始 +first-page=最初のページ +previous-page=前のページ +next-page=次のページ +client-revoke.not-before.tooltip=この日時より前に発行されたこのクライアント用のトークンを無効化します。 +client-revoke.push.tooltip=管理URLがこのクライアントに設定されている場合は、クライアントにポリシーをプッシュします。 +select-a-format=フォーマットを選択 +download=ダウンロード +offline-tokens=オフライン・トークン +offline-tokens.tooltip=このクライアントのオフライン・トークンの合計数です。 +show-offline-tokens=オフライン・トークンを表示 +show-offline-tokens.tooltip=オフライン・トークン数に応じて高負荷なオペレーションになる恐れがありますので注意してください。 +token-issued=発行済みトークン +last-access=最終アクセス +last-refresh=最終リフレッシュ +key-export=鍵をエクスポート +key-import=鍵をインポート +export-saml-key=SAML鍵をエクスポート +import-saml-key=SAML鍵をインポート +realm-certificate-alias=レルム証明書エイリアス +realm-certificate-alias.tooltip=レルム証明書もアーカイブに格納されます。これはそのエイリアスとなります。 +signing-key=署名鍵 +saml-signing-key=SAML署名鍵です。 +private-key=秘密鍵 +generate-new-keys=新しい鍵を生成 +export=エクスポート +encryption-key=暗号化鍵 +saml-encryption-key.tooltip=SAML暗号化鍵です。 +service-accounts=サービス・アカウント +service-account.available-roles.tooltip=サービス・アカウントにアサイン可能なレルムレベルのロールです。 +service-account.assigned-roles.tooltip=サービス・アカウントにアサイン済みのレルムレベルのロールです。 +service-account-is-not-enabled-for={{client}}のサービス・アカウントは有効ではありません +create-protocol-mappers=プロトコル・マッパーを作成 +create-protocol-mapper=プロトコル・マッパーを作成 +protocol=プロトコル +protocol.tooltip=プロトコルです。 +id=ID +mapper.name.tooltip=マッパーの名前です。 +mapper.consent-required.tooltip=一時的なアクセスを許可する際に、クライアントへの提供データにユーザーの同意を必要とするか設定します。 +consent-text=同意のテキスト +consent-text.tooltip=同意ページに表示するテキストです。 +mapper-type=マッパータイプ +mapper-type.tooltip=マッパーのタイプです。 +user-label=ユーザーラベル +data=データ +show-data=データを表示... +position=位置 +# realm identity providers +identity-providers=アイデンティティー・プロバイダー +table-of-identity-providers=アイデンティティー・プロバイダーの一覧表 +add-provider.placeholder=プロバイダーを追加... +provider=プロバイダー +gui-order=GUI順序 +first-broker-login-flow=初回ログインフロー +post-broker-login-flow=ログイン後のフロー +sync-mode=同期モード +sync-mode.tooltip=すべてのマッパーのデフォルトの同期モード。同期モードは、マッパーを使用してユーザーデータを同期するタイミングを決定します。可能な値は次のとおりです。このオプションが導入される前の動作を維持する「レガシー」、このアイデンティティー・プロバイダーを使用したユーザーの初回ログイン時に一度だけユーザーをインポートする「インポート」、このアイデンティティー・プロバイダーでログインするたびにユーザーを常に更新する「強制」。 +sync-mode.inherit=継承 +sync-mode.legacy=レガシー +sync-mode.import=インポート +sync-mode.force=強制 +sync-mode-override=同期モードのオーバーライド +sync-mode-override.tooltip=このマッパーのIDPのデフォルトの同期モードをオーバーライドします。値は次のとおりです。このオプションが導入される前の動作を維持する「レガシー」、このアイデンティティー・プロバイダーを使用したユーザーの初回ログイン時に一度だけユーザーをインポートする「インポート」、このアイデンティティー・プロバイダーでログインするたびにユーザーを常に更新する「強制」、このマッパーのアイデンティティー・プロバイダーで定義された同期モードを使用する「継承」。 +redirect-uri=リダイレクトURI +redirect-uri.tooltip=アイデンティティー・プロバイダーの設定で使用するリダイレクトURIです。 +alias=エイリアス +display-name=表示名 +identity-provider.alias.tooltip=エイリアスは一意にアイデンティティー・プロバイダーを識別するもので、リダイレクトURIの構築にも使用されます。 +identity-provider.display-name.tooltip=アイデンティティー・プロバイダーの分かりやすい名前を設定します。 +identity-provider.enabled.tooltip=このアイデンティティー・プロバイダーの有効/無効を設定します。 +authenticate-by-default=デフォルトで認証 +identity-provider.authenticate-by-default.tooltip=ログイン画面の表示前に、このプロバイダーでデフォルトで認証試行すべきかどうかを示しています。 +store-tokens=トークンの格納 +identity-provider.store-tokens.tooltip=ユーザー認証後のトークン格納の有効/無効を設定します。 +stored-tokens-readable=読み取り可能なトークンを格納 +identity-provider.stored-tokens-readable.tooltip=新しいユーザーが格納されたトークンを読み取り可能かどうかの有効/無効設定です。broker.read-tokenロールをアサインします。 +disableUserInfo=UserInfoの無効 +identity-provider.disableUserInfo.tooltip=追加のユーザー情報を取得するUserInfoサービスの使用を無効にするかどうかを設定します。デフォルトではこのOIDCサービスを使用します。 +userIp=userIpパラメーターの使用 +identity-provider.google-userIp.tooltip=GoogleのUserInfoサービスの呼び出し時に「userIp」クエリー・パラメーターを設定します。これはユーザーのIPアドレスを使用します。GoogleがUserInfoサービスへのアクセスを制限している場合に役立ちます。 +offlineAccess=リフレッシュ・トークンを要求する +identity-provider.google-offlineAccess.tooltip=リフレッシュ・トークンを取得するには、Google認可エンドポイントにリダイレクトするときに「access_type」クエリー・パラメーターを「offline」に設定します。ユーザーがブラウザーを利用していないときに、Google APIにアクセスするためのGoogleトークンを取得するために、トークン交換の使用を計画している場合に便利です。 +hostedDomain=ホストされたドメイン +identity-provider.google-hostedDomain.tooltip=Googleにログインするときに「hd」クエリー・パラメーターを設定します。Googleはこのドメインのみのアカウントを一覧表示します。Keycloakは、返されたIDトークンにこのドメインに対するクレームがあることを検証します。「*」を入力すると、任意のホストされたアカウントを使用できます。 +sandbox=対象のサンドボックス +identity-provider.paypal-sandbox.tooltip=対象のPayPalサンドボックス環境 +update-profile-on-first-login=初回ログイン時にプロファイルを更新 +on=オン +on-missing-info=情報不足の場合 +off=オフ +update-profile-on-first-login.tooltip=初回ログイン時にどのユーザーがプロファイルの更新を必要とするか条件を定義します。 +trust-email=Eメールを信頼 +trust-email.tooltip=有効とした場合は、このレルムでEメールの確認が有効となっている場合でも、このプロバイダーが提供するEメールは確認されなくなります。 +link-only=アカウントのリンクのみ +link-only.tooltip=オンの場合、ユーザーはこのプロバイダーからログインできません。このプロバイダーにリンクすることのみできます。これは、プロバイダーからのログインを許可したくないが、プロバイダーと統合したい場合に便利です +hide-on-login-page=ログインページで非表示 +hide-on-login-page.tooltip=非表示の場合、明示的に要求されていれば(例えば、「kc_idp_hint」パラメーターを使用していれば)、このプロバイダーによるログインが可能です。 +gui-order.tooltip=GUI(例えば、ログインページ上)でのプロバイダーの表示順序を決める番号を設定します。 +first-broker-login-flow.tooltip=このアイデンティティー・プロバイダーでの初回ログイン後に起動させる認証フローのエイリアスです。「初回ログイン」という用語は、認証したアイデンティティー・プロバイダー・アカウントに現在関連付けられているKeycloakアカウントがない状態であることを意味します。 +post-broker-login-flow.tooltip=このアイデンティティー・プロバイダーでの各ログイン後に起動させる認証フローのエイリアスです。このアイデンティティー・プロバイダーで認証された各ユーザーの追加の確認(例えばOTP)を行いたい場合に便利です。このアイデンティティー・プロバイダーによるログイン後に追加のオーセンティケーターを起動する必要がない場合は、空のままとしてください。また、オーセンティケーターの実装では、ClientSessionにはアイデンティティー・プロバイダーによりユーザーが既に設定されていることに注意してください。 +openid-connect-config=OpenID Connectの設定 +openid-connect-config.tooltip=OIDC SPと外部IDPの設定です。 +authorization-url=認可URL +authorization-url.tooltip=認可URLを設定します。 +token-url=トークンURL +token-url.tooltip=トークンURLを設定します。 +loginHint=login_hintを渡す +loginHint.tooltip=アイデンティティー・プロバイダーにlogin_hintを渡します。 +uiLocales=現在のロケールを渡す +uiLocales.tooltip=現在のロケールをui_localesパラメーターとしてアイデンティティー・プロバイダーに渡します。 +logout-url=ログアウトURL +identity-provider.logout-url.tooltip=外部IDPからユーザーのログアウトに使用するセッション終了エンドポイントを設定します。 +backchannel-logout=バックチャンネル・ログアウト +backchannel-logout.tooltip=外部IDPがバックチャンネル・ログアウトをサポートするどうかを設定します。 +user-info-url=UserInfo URL +user-info-url.tooltip=UserInfoのURLを設定します。これはオプションです。 +client-auth=クライアント認証 +client-auth.tooltip=クライアント認証方法(参照:https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication)。秘密鍵で署名されたJWTの場合、レルム秘密鍵が使用されます。 +client-auth.client_secret_post=POSTで送信されたクライアント・シークレット +client-auth.client_secret_basic=基本認証で送信されたクライアント・シークレット +client-auth.client_secret_jwt=JWTでクライアント・シークレット +client-auth.private_key_jwt=秘密鍵で署名されたJWT +identity-provider.client-id.tooltip=アイデンティティー・プロバイダーで登録されているクライアントまたはクライアント識別子を設定します。 +client-secret=クライアント・シークレット +show-secret=シークレットを表示する +hide-secret=シークレットを隠す +client-secret.tooltip=アイデンティティー・プロバイダーで登録されているクライアントまたはクライアント・シークレットを設定します。このフィールドは、ボールトから値を取得できます。${vault.ID}形式を使用します。 +client-assertion-signing-algorithm=クライアントアサーション署名アルゴリズム +client-assertion-signing-algorithm.tooltip=クライアント認証でJWTアサーションを利用するときの署名アルゴリズム。クライアント認証が 秘密鍵で署名されたJWT もしくは JWTでクライアント・シークレット の場合に設定します。アルゴリズムの指定をしなかった場合、 秘密鍵で署名されたJWT ではRS256 JWTでクライアント・シークレット ではHS256のアルゴリズムが使用されます。 +issuer=発行者(Issuer) +issuer.tooltip=レスポンス内の発行者の識別子(Issuer Identifier)を設定します。未設定の場合は、検証は実行されません。 +default-scopes=デフォルト・スコープ +identity-provider.default-scopes.tooltip=認可リクエストの際に送信されるスコープです。スペース区切りでスコープのリストを設定します。デフォルトは「openid」です。 +prompt=プロンプト(prompt) +unspecified.option=未定義 +none.option=none +consent.option=consent +login.option=login +select-account.option=select_account +prompt.tooltip=認証サーバーは再認証や同意をエンドユーザーに促すかどうかを指定します。 +accepts-prompt-none-forward-from-client=クライアントから転送されるprompt=noneを受け入れる +accepts-prompt-none-forward-from-client.tooltip=これは、アイデンティティー・プロバイダー・オーセンティケーターとともに使用されるか、またはkc_idp_hintがこのアイデンティティー・プロバイダーを指す場合に使用されます。クライアントがprompt=noneでリクエストを送信し、ユーザーがまだ認証されていない場合、エラーは直接クライアントに返されませんが、prompt=noneのリクエストはこのアイデンティティー・プロバイダーに転送されます。 +validate-signatures=署名検証 +identity-provider.validate-signatures.tooltip=外部IDPの署名検証の有効/無効を設定します。 +identity-provider.use-jwks-url.tooltip=有効とした場合は、アイデンティティー・プロバイダーの公開鍵が指定されたJWKS URLからダウンロードされます。アイデンティティー・プロバイダーが新しい鍵ペアを生成する際に、新しい鍵が常に再ダウンロードされるため、柔軟性が大幅に向上します。無効とした場合は、Keycloak DBの公開鍵(または証明書)が使用されるため、アイデンティティー・プロバイダーの鍵ペアが変更された際には、常にKeycloak DBに新しい鍵をインポートする必要があります。 +identity-provider.jwks-url.tooltip=JWK形式のアイデンティティー・プロバイダーの鍵が格納されているURLを設定します。詳細はJWKの仕様を参照してください。外部のKeycloakアイデンティティー・プロバイダーを使用する場合は、ブローカーのKeycloakが「http://broker-keycloak:8180」で実行されておりレルムが「test」と仮定すると、「http://broker-keycloak:8180/auth/realms/test/protocol/openid-connect/certs」のようなURLを使用することができます。 +validating-public-key=検証用の公開鍵 +identity-provider.validating-public-key.tooltip=外部IDPの署名検証に使用するPEM形式の公開鍵を設定します。 +validating-public-key-id=検証用の公開鍵ID +identity-provider.validating-public-key-id.tooltip=鍵IDの場合、上記の検証用の公開鍵の明示的なID。外部IDPで指定された鍵IDに関係なく、上記の鍵を常に使用する必要がある場合は空白のままにしてください。鍵を使用する必要がある場合、外部IDPからの鍵IDが一致するかどうかを確認するためにのみ設定します。 +allowed-clock-skew=許容されるクロックスキュー +identity-provider.allowed-clock-skew.tooltip=アイデンティティー・プロバイダーのトークンの検証時に許容されるクロックスキュー(秒単位)。デフォルト値は0です。 +forwarded-query-parameters=転送されるクエリー・パラメーター +identity-provider.forwarded-query-parameters.tooltip=最初のアプリケーションへのリクエストから取得し、外部IDPの認可エンドポイントへ転送されるOpenID Connect/OAuth標準以外のクエリー・パラメーター。複数のパラメーターをカンマ(,)で区切って入力できます。 +import-external-idp-config=外部IDP設定のインポート +import-external-idp-config.tooltip=外部IDPメタデータを設定ファイルよりロード、またはURLよりダウンロードして設定します。 +import-from-url=URLよりインポート +identity-provider.import-from-url.tooltip=リモートIDPディスカバリー・ディスクリプターよりメタデータをインポートします。 +import-from-file=ファイルよりインポート +identity-provider.import-from-file.tooltip=ダウンロードしたIDPディスカバリー・ディスクリプターよりメタデータをインポートします。 +saml-config=SAML設定 +identity-provider.saml-config.tooltip=SAML SPと外部IDPの設定です。 +single-signon-service-url=シングル・サインオン・サービスのURL +saml.single-signon-service-url.tooltip=認証リクエスト(SAML AuthnRequest)の送信に使用するURLを設定します。 +single-logout-service-url=シングル・ログアウト・サービスのURL +saml.single-logout-service-url.tooltip=ログアウト・リクエストの送信に使用するURLを設定します。 +nameid-policy-format=Name IDポリシー・フォーマット +nameid-policy-format.tooltip=Name IDフォーマットに対応するURIリファレンスを指定します。デフォルトはurn:oasis:names:tc:SAML:2.0:nameid-format:persistentになります。 +saml.principal-type=プリンシパル・タイプ +saml.principal-type.tooltip=アサーションから外部ユーザーを識別し、追跡する方法。デフォルトではSubject NameIDを使用しますが、識別属性を設定することもできます。 +saml.principal-attribute=プリンシパル属性 +saml.principal-attribute.tooltip=外部ユーザーを識別するために使用される属性の名前またはフレンドリー名。 +http-post-binding-response=HTTP-POSTバインディング・レスポンス +http-post-binding-response.tooltip=HTTP-POSTバインディングを使用してリクエストに応答するかどうかを設定します。オフの場合は、HTTP-REDIRECTバインディングが使用されます。 +http-post-binding-for-authn-request=AuthnRequestのHTTP-POSTバインディング +http-post-binding-for-authn-request.tooltip=HTTP-POSTバインディングを使用してAuthnRequestを送信するかどうかを設定します。オフの場合は、HTTP-REDIRECTバインディングが使用されます。 +http-post-binding-logout=HTTP-POSTバインディング・ログアウト +http-post-binding-logout.tooltip=HTTP-POSTバインディングを使用してリクエストに応答するかどうかを設定します。オフの場合は、HTTP-REDIRECTバインディングが使用されます。 +want-authn-requests-signed=AuthnRequestの署名が必要 +want-authn-requests-signed.tooltip=アイデンティティー・プロバイダーが署名付きAuthnRequestを要求するかどうかを設定します。 +want-assertions-signed=アサーションの署名が必要 +want-assertions-signed.tooltip=このサービス・プロバイダーが署名付きアサーションを要求するかどうかを設定します。 +want-assertions-encrypted=アサーションの暗号化が必要 +want-assertions-encrypted.tooltip=このサービス・プロバイダーが暗号化されたアサーションを期待するかどうかを設定します。 +force-authentication=認証を強制 +identity-provider.force-authentication.tooltip=アイデンティティー・プロバイダーが以前のセキュリティー・コンテキストに頼るのではなく、プレゼンターを直接認証すべきかどうかを設定します。 +validate-signature=署名検証 +saml.validate-signature.tooltip=SAMLレスポンスの署名検証の有効/無効を設定します。 +validating-x509-certificate=検証用のX509証明書 +validating-x509-certificate.tooltip=署名の確認に使用するPEM形式の証明書を設定します。 +saml.import-from-url.tooltip=リモートIDPのSAMLエンティティー・ディスクリプターからメタデータをインポートします。 +social.client-id.tooltip=アイデンティティー・プロバイダーで登録されているクライアント識別子を設定します。 +social.client-secret.tooltip=アイデンティティー・プロバイダーで登録されているクライアント・シークレットを設定します。このフィールドは、ボールトから値を取得できます。${vault.ID}形式を使用します。 +social.default-scopes.tooltip=認可リクエストの際に送信されるスコープを設定します。設定可能な値、区切り文字、デフォルト値はドキュメントを参照してください。 +key=キー +stackoverflow.key.tooltip=Stack Overflowのクライアント登録で取得したKeyを設定します。 +openshift.base-url=ベースURL +openshift.base-url.tooltip=OpenShift Online APIのベースURL +openshift4.base-url=ベースURL +openshift4.base-url.tooltip=OpenShift Online APIのベースURL +gitlab-application-id=アプリケーションID +gitlab-application-secret=アプリケーション・シークレット +gitlab.application-id.tooltip=GitLabアプリケーションのアカウント・メニューで作成したアプリケーションのアプリケーションID +gitlab.application-secret.tooltip=GitLabアプリケーションのアカウント・メニューで作成したアプリケーションのシークレット +gitlab.default-scopes.tooltip=ログイン時に要求するスコープ。openidは常に要求されます。何も指定しない場合は、さらにapiを追加します。 +bitbucket-consumer-key=コンシューマー・キー +bitbucket-consumer-secret=コンシューマー・シークレット +bitbucket.key.tooltip=Bitbucket OAuthコンシューマー・キー +bitbucket.secret.tooltip=Bitbucket OAuthコンシューマー・シークレット +bitbucket.default-scopes.tooltip=ログイン時に要求するスコープ。何も指定しなければ、scopeはデフォルトで「email」になります。 +# User federation +sync-ldap-roles-to-keycloak=LDAPロールをKeycloakに同期 +sync-keycloak-roles-to-ldap=KeycloakロールをLDAPに同期 +sync-ldap-groups-to-keycloak=LDAPグループをKeycloakに同期 +sync-keycloak-groups-to-ldap=KeycloakグループをLDAPに同期 +realms=レルム +realm=レルム +identity-provider-mappers=アイデンティティー・プロバイダー・マッパー +create-identity-provider-mapper=アイデンティティー・プロバイダー・マッパーを作成 +add-identity-provider-mapper=アイデンティティー・プロバイダー・マッパーを追加 +client.description.tooltip=クライアントの説明を指定します。例えば「タイムシート用のクライアント」です。ローカライズ用のキーもサポートしています。例\: ${my_client_description} +expires=有効期限 +expiration=有効期限 +expiration.tooltip=トークンの有効期間を指定します。 +count=カウント +count.tooltip=このトークンを利用してクライアントをいくつ作成可能か指定します。 +remainingCount=残りのカウント +created=作成日時 +back=戻る +initial-access-tokens=初期アクセストークン +add-initial-access-tokens=初期アクセストークンを追加 +initial-access-token=初期アクセストークン +initial-access.copyPaste.tooltip=このページから移動する前に初期アクセストークンをコピー/ペーストします。後で検索することはできません。 +continue=続ける +initial-access-token.confirm.title=初期アクセストークンのコピー +initial-access-token.confirm.text=後からは取得することはできませんので、初期アクセストークンのコピー&ペーストを行ってください +no-initial-access-available=使用可能な初期アクセストークンはありません +client-reg-policies=クライアント登録ポリシー +client-reg-policy.name.tooltip=ポリシーの表示名を設定します。 +anonymous-policies=匿名アクセスのポリシー +anonymous-policies.tooltip=これらのポリシーはクライアント登録サービスが未認証リクエストによって呼び出された際に使用されます。これは、リクエストには初期アクセストークンもベアラートークンも含まれないことを意味します。 +auth-policies=認証済みアクセスのポリシー +auth-policies.tooltip=これらのポリシーは認証されたリクエストによってクライアント登録サービスが呼び出された際に使用されます。これは、リクエストに初期アクセストークンまたはベアラートークンが含まれていることを意味します。 +policy-name=ポリシー名 +no-client-reg-policies-configured=クライアント登録ポリシーはありません。 +trusted-hosts.label=信頼されたホスト +trusted-hosts.tooltip=信頼され、クライアント登録サービスを呼び出すことが許可されている、および/またはクライアントURIの値として使用されているホストのリストを設定します。ホスト名またはIPアドレスを使用して設定します。アスタリスク(例えば「*.example.com」)を使用すると、example.comのドメイン全体が信頼されます。 +host-sending-registration-request-must-match.label=クライアント登録リクエストを送信するホストの一致が必須 +host-sending-registration-request-must-match.tooltip=有効とした場合は、信頼されたホストまたはドメインから送信されたクライアント登録サービスへのリクエストは許可されます。 +client-uris-must-match.label=クライアントURIの一致が必須 +client-uris-must-match.tooltip=有効とした場合は、すべてのクライアントURI(リダイレクトURIなど)は、信頼されたホストまたはドメインと一致する場合にのみ許可されます。 +allowed-protocol-mappers.label=許可されたプロトコル・マッパー +allowed-protocol-mappers.tooltip=許可されたプロトコル・マッパー・プロバイダーのホワイトリストを設定します。ホワイトリストに登録されていないプロトコル・マッパーを含むクライアントを登録しようとすると、登録リクエストは拒否されます。 +consent-required-for-all-mappers.label=マッパーの同意が必要 +consent-required-for-all-mappers.tooltip=有効とした場合は、新たに登録されたすべてのプロトコル・マッパーは自動的に「同意が必要」が有効となります。これは、ユーザーが同意画面で承認する必要があることを意味します。注記: 同意画面は、クライアントが「同意が必要」を有効にしている場合にのみ表示されます。そのため、通常は同意が必要なポリシーとともに使用します。 +allowed-client-scopes.label=許可されたクライアント・スコープ +allowed-client-scopes.tooltip=クライアント・スコープのホワイトリスト。新しく登録されたクライアントで使用できます。ホワイトリストに登録されていないクライアント・スコープをクライアントに登録しようとすると、拒否されます。デフォルトでは、ホワイトリストは空かレルムのデフォルトのクライアント・スコープが含まれているかのいずれかです(「デフォルト・スコープの許可」設定プロパティーに基づいています)。 +allow-default-scopes.label=デフォルト・スコープの許可 +allow-default-scopes.tooltip=オンの場合、新規に登録されたクライアントは、レルムのデフォルトのクライアント・スコープか、レルムのオプションのクライアント・スコープに記述されたクライアント・スコープを持つことが許可されます。 +max-clients.label=レルムあたりの最大クライアント数 +max-clients.tooltip=レルム内の既存のクライアントの数が設定された制限と同じかそれ以上の場合は、新しいクライアントを登録することはできません。 + +client-scopes=クライアント・スコープ +client-scopes.tooltip=クライアント・スコープを使用すると、複数のクライアント間で共有されるプロトコル・マッパーとロールの共通セットを定義できます + +groups=グループ + +group.add-selected.tooltip=グループにアサイン可能なレルムロールです。 +group.assigned-roles.tooltip=グループにマッピングされたレルムロールです。 +group.effective-roles.tooltip=マッピングされているすべてのレルムロールです。複合ロールより引き継いでいるロールも含みます。 +group.available-roles.tooltip=このクライアントよりアサイン可能なロールです。 +group.assigned-roles-client.tooltip=マッピングされたこのクライアントのロールです。 +group.effective-roles-client.tooltip=マッピングされたこのクライアントのロールです。複合ロールより引き継いでいるロールも含みます。 + +default-roles=デフォルトロール +no-realm-roles-available=使用可能なレルムロールはありません + +users=ユーザー +user.add-selected.tooltip=ユーザーにアサイン可能なレルムロールです。 +user.assigned-roles.tooltip=ユーザーにマッピングされたレルムロールです。 +user.effective-roles.tooltip=マッピングされているすべてのレルムロールです。複合ロールより引き継いでいるロールも含みます。 +user.available-roles.tooltip=このクライアントよりアサイン可能なロールです。 +user.assigned-roles-client.tooltip=マッピングされたこのクライアントのロールです。 +user.effective-roles-client.tooltip=マッピングされたこのクライアントのロールです。複合ロールより引き継いでいるロールも含みます。 +default.available-roles.tooltip=アサイン可能なレルムレベルのロールです。 +realm-default-roles=レルムのデフォルトロール +realm-default-roles.tooltip=ユーザーにアサインされたレルムレベルのロールです。 +default.available-roles-client.tooltip=デフォルトでアサイン可能なこのクライアントのロールです。 +client-default-roles=クライアントのデフォルトロール +client-default-roles.tooltip=デフォルトロールとしてアサインされたこのクライアントのロールです。 +composite.available-roles.tooltip=この複合ロールに関連付け可能なレルムレベルのロールです。 +composite.associated-roles.tooltip=この複合ロールに関連付けされているレルムレベルのロールです。 +composite.available-roles-client.tooltip=この複合ロールに関連付け可能なこのクライアントのロールです。 +composite.associated-roles-client.tooltip=この複合ロールに関連付けされているクライアント・ロールです。 +partial-import=部分インポート +partial-import.tooltip=部分インポートでは、以前にエクスポートしたJSONファイルよりユーザー、クライアント、およびその他のリソースをインポートすることができます。 + +file=ファイル +exported-json-file=エクスポートされたJSONファイル +import-from-realm=レルムからインポート +import-users=ユーザーをインポート +import-groups=グループをインポート +import-clients=クライアントをインポート +import-identity-providers=アイデンティティー・プロバイダーをインポート +import-realm-roles=レルムロールをインポート +import-client-roles=クライアント・ロールをインポート +if-resource-exists=リソースが存在する場合 +fail=失敗 +skip=スキップ +overwrite=上書き +if-resource-exists.tooltip=既に存在するリソースをインポートしようとした場合にどうすべきかを指定します。 + +partial-export=部分エクスポート +partial-export.tooltip=部分エクスポートでは、レルム設定やその他の関連リソースをjsonファイルにエクスポートできます。 +export-groups-and-roles=グループとロールのエクスポート +export-clients=クライアントのエクスポート + +action=アクション +role-selector=ロールの選択 +realm-roles.tooltip=選択可能なレルムロールです。 + +select-a-role=ロールを選択してください +select-realm-role=レルムロールを選択 +client-roles.tooltip=選択可能なクライアント・ロールです。 +select-client-role=クライアント・ロールを選択 + +client-saml-endpoint=クライアントSAMLエンドポイント +add-client-scope=クライアント・スコープの追加 + +default-client-scopes=デフォルトのクライアント・スコープ +default-client-scopes.tooltip=作成された各クライアントに自動的に追加されるクライアント・スコープ +default-client-scopes.default=デフォルトのクライアント・スコープ +default-client-scopes.default.tooltip=作成された各クライアントにデフォルト・スコープとして追加されるクライアント・スコープの定義を許可する +default-client-scopes.default.available=利用可能なクライアント・スコープ +default-client-scopes.default.available.tooltip=レルムのデフォルトまたはオプションのスコープとして割り当てられていないクライアント・スコープ +default-client-scopes.default.assigned=割り当てられたデフォルトのクライアント・スコープ +default-client-scopes.default.assigned.tooltip=作成された各クライアントにデフォルト・スコープとして追加されるクライアント・スコープ +default-client-scopes.optional=オプションのクライアント・スコープ +default-client-scopes.optional.tooltip=作成された各クライアントにオプションのスコープとして追加されるクライアント・スコープの定義を許可する +default-client-scopes.optional.available=利用可能なクライアント・スコープ +default-client-scopes.optional.available.tooltip=レルムのデフォルトまたはオプションのスコープとして割り当てられていないクライアント・スコープ +default-client-scopes.optional.assigned=割り当てられたオプションのクライアント・スコープ +default-client-scopes.optional.assigned.tooltip=作成された各クライアントにオプションのスコープとして追加されるクライアント・スコープ + +client-scopes.setup=セットアップ +client-scopes.setup.tooltip=このクライアントにリンクされたクライアント・スコープを設定できるようにします +client-scopes.default=デフォルトのクライアント・スコープ +client-scopes.default.tooltip=このクライアントにトークンを発行する際に、デフォルトのクライアント・スコープが常に適用されます。プロトコル・マッパーとロールスコープのマッピングは、OIDC認可リクエストで使用されているスコープ・パラメーターの値に関係なく常に適用されます +client-scopes.default.available=利用可能なクライアント・スコープ +client-scopes.default.available.tooltip=デフォルトまたはオプションのスコープとして割り当てられていないクライアント・スコープ +client-scopes.default.assigned=割り当てられたデフォルトのクライアント・スコープ +client-scopes.default.assigned.tooltip=このクライアントのトークンを生成する際に、デフォルト・スコープとして使用されるクライアント・スコープ +client-scopes.optional=オプションのクライアント・スコープ +client-scopes.optional.tooltip=このクライアントのトークンを発行する際に、適用されるオプションのクライアント・スコープ。ただし、OIDC認可リクエストのスコープ・パラメーターによって要求された場合のみ +client-scopes.optional.available=利用可能なクライアント・スコープ +client-scopes.optional.available.tooltip=デフォルトまたはオプションのスコープとして割り当てられていないクライアント・スコープ +client-scopes.optional.assigned=割り当てられたオプションのクライアント・スコープ +client-scopes.optional.assigned.tooltip=このクライアントのトークンを生成する際に、オプションのスコープとして使用できるクライアント・スコープ + +client-scopes.evaluate=評価 +client-scopes.evaluate.tooltip=このクライアントに発行されたトークンで使用されるすべてのプロトコル・マッパーとロールスコープのマッピングを表示することを許可します。また、提供されたスコープ・パラメーターに基づいてサンプル・アクセストークンを生成することもできます +scope-parameter=スコープ・パラメーター +scope-parameter.tooltip=このスコープ・パラメーターの値をコピー/ペーストし、このクライアント・アダプターから送信された最初のOpenID Connect認証リクエストで使用できます。このクライアントに発行されたトークンを生成するときは、デフォルトのクライアント・スコープと選択されたオプションのクライアント・スコープが使用されます +client-scopes.evaluate.scopes=クライアント・スコープ +client-scopes.evaluate.scopes.tooltip=このクライアントに発行されたトークンを生成する際に使用されるオプションのクライアント・スコープを選択することを許可します +client-scopes.evaluate.scopes.available=利用可能なオプションのクライアント・スコープ +client-scopes.evaluate.scopes.available.tooltip=これにはオプションのクライアント・スコープが含まれています。このスコープは、このクライアントのアクセストークンを発行するときにオプションで使用できます +client-scopes.evaluate.scopes.assigned=選択されたオプションのクライアント・スコープ +client-scopes.evaluate.scopes.assigned.tooltip=選択されたオプションのクライアント・スコープは、このクライアントのアクセストークンを発行するときに使用されます。これらのオプションのクライアント・スコープを最初のOpenID Connect認証リクエストがクライアント・アダプターから送信されたときに適用する場合、OAuthスコープ・パラメーターのどの値を使用する必要があるかを上で見ることができます +client-scopes.evaluate.scopes.effective=有効なクライアント・スコープ +client-scopes.evaluate.scopes.effective.tooltip=すべてのデフォルトのクライアント・スコープと選択されたオプションのスコープが含まれます。クライアントに発行されたアクセストークンを生成するときに、すべてのクライアント・スコープのすべてのプロトコル・マッパーとロールスコープのマッピングが使用されます +client-scopes.evaluate.user.tooltip=必要に応じて、サンプルのアクセストークンを生成するユーザーを選択します。ユーザーを選択しないと、評価中にサンプルのアクセストークンは生成されません +send-evaluation-request=評価 +send-evaluation-request.tooltip=これをクリックすると、このクライアントにアクセストークンを発行するときに使用されるすべてのプロトコル・マッパーとロールスコープのマッピングが表示されます。いくつかのユーザーが選択された場合には、オプションでサンプルのアクセストークンも生成されます + +evaluated-protocol-mappers=有効なプロトコル・マッパー +evaluated-protocol-mappers.tooltip=このクライアントにトークンを発行する際に使用されるすべての有効なプロトコル・マッパーを表示します。選択されたオプションのクライアント・スコープのプロトコル・マッパーも含まれます。プロトコル・マッパーごとに、どのクライアント・スコープから継承されているかを見ることができます +evaluated-roles=有効なロールスコープ・マッピング +evaluated-roles.tooltip=このクライアントにトークンを発行するときに使用されるすべての有効なロールスコープ・マッピングを表示します。選択したオプションのクライアント・スコープのロールスコープ・マッピングも含まれます。 +parent-client-scope=親クライアント・スコープ +client-scopes.evaluate.not-granted-roles=許可されていないロール +client-scopes.evaluate.not-granted-roles.tooltip=クライアントには、これらのロールのスコープ・マッピングがありません。これらのロールは、認証されたユーザーがそれらのメンバーであっても、このクライアントに発行されるアクセストークンには含まれません +client-scopes.evaluate.granted-realm-effective-roles=付与された有効なレルムロール +client-scopes.evaluate.granted-realm-effective-roles.tooltip=クライアントには、これらのロールのスコープ・マッピングがあります。認証されたユーザーがそれらのメンバーである場合、これらのロールはこのクライアントに発行されるアクセストークンに含まれます +client-scopes.evaluate.granted-client-effective-roles=付与された有効なクライアント・ロール +generated-access-token=生成されたアクセストークン +generated-access-token.tooltip=選択されたユーザーが認証されると生成され、クライアントに送信されるトークンのサンプルを参照してください。トークンには、有効なプロトコル・マッパーとロールスコープのマッピングに基づいて、またユーザー自身に割り当てられたクレーム/ロールに基づいた、クレームとロールが表示されます + +manage=管理 +authentication=認証 +user-federation=ユーザー・フェデレーション +user-storage=ユーザー・ストレージ +events=イベント +realm-settings=レルムの設定 +configure=設定 +select-realm=レルムの選択 +add=追加 + +client-storage=クライアント・ストレージ +no-client-storage-providers-configured=クライアント・ストレージ・プロバイダーが設定されていません +client-stores.tooltip=Keycloakは、クライアントとその詳細を外部ストアから取得できます。 + +client-scope.name.tooltip=クライアント・スコープの名前。レルム内でユニークでなければなりません。スコープ・パラメーターの値として使用されるため、名前には空白文字を含めないでください +client-scope.description.tooltip=クライアント・スコープの説明 +client-scope.protocol.tooltip=このクライアント・スコープによって提供されているSSOプロトコル設定がどれか +client-scope.display-on-consent-screen=同意画面で表示する +client-scope.display-on-consent-screen.tooltip=オンで、同意が必要なクライアントにこのクライアント・スコープが追加された場合、「同意画面のテキスト」で指定されたテキストが同意画面に表示されます。オフの場合、このクライアント・スコープは同意画面に表示されません +client-scope.consent-screen-text=同意画面のテキスト +client-scope.consent-screen-text.tooltip=このクライアント・スコープが同意が必要なクライアントに追加された場合に、同意画面に表示されるテキスト。指定しない場合は、デフォルトでクライアント・スコープの名前になります +client-scope.gui-order=GUI順序 +client-scope.gui-order.tooltip=GUI(同意ページのような)でのプロバイダーの順序を整数で指定します。 +client-scope.include-in-token-scope=トークンスコープに含める +client-scope.include-in-token-scope.tooltip=オンの場合、このクライアント・スコープの名前がアクセストークン・プロパティーの「scope」と同様にトークン・イントロスペクション・エンドポイントのレスポンスに追加されます。オフの場合、このクライアント・スコープはトークンとトークン・イントロスペクション・エンドポイントのレスポンスから除外されます。 + +add-user-federation-provider=ユーザー・フェデレーション・プロバイダーの追加 +add-user-storage-provider=ユーザー・ストレージ・プロバイダーの追加 +required-settings=必要な設定 +provider-id=プロバイダーID +console-display-name=コンソール表示名 +console-display-name.tooltip=管理コンソール内でのリンク表示名を設定します。 +priority=優先度 +priority.tooltip=ユーザーを検索する際のプロバイダーの優先度を設定します。低い順となります。 +user-storage.enabled.tooltip=プロバイダーが無効になっている場合、クエリーは考慮されず、プロバイダーが再度有効になるまで、インポートされたユーザーは無効かつ読み取り専用になります。 +sync-settings=同期の設定 +periodic-full-sync=定期的なフル同期 +periodic-full-sync.tooltip=プロバイダー・ユーザーのKeycloakへの定期的なフル同期を有効または無効とすべきかを設定します。 +full-sync-period=フル同期の周期 +full-sync-period.tooltip=フル同期の周期を秒で設定します。 +periodic-changed-users-sync=定期的な変更ユーザーの同期 +periodic-changed-users-sync.tooltip=変更または新規作成されたプロバイダー・ユーザーのKeycloakへの定期的な同期を有効または無効とすべきか設定します。 +changed-users-sync-period=変更ユーザーの同期周期 +changed-users-sync-period.tooltip=変更または新規作成されたプロバイダー・ユーザーの同期周期を秒で設定します。 +synchronize-changed-users=変更ユーザーを同期 +synchronize-all-users=すべてのユーザーを同期 +remove-imported-users=インポートを削除 +unlink-users=ユーザーのリンクを解除する +kerberos-realm=Kerberosレルム +kerberos-realm.tooltip=Kerberosレルムの名前を設定します。例えば、FOO.ORGです。 +server-principal=サーバー・プリンシパル +server-principal.tooltip=サーバー、ドメイン名を含むHTTPサービスのサービス・プリンシパルのフルネームを設定します。例えば、HTTP/host.foo.org@FOO.ORGです。 +keytab=KeyTab +keytab.tooltip=サーバー・プリンシパルのクレデンシャルを含むKerberosのKeyTabファイルを設定します。例えば、/etc/krb5.keytabです。 +debug=デバッグ +debug.tooltip=Krb5LoginModuleの標準出力へのデバッグロギングの有効/無効を設定します。 +allow-password-authentication=パスワード認証を許可 +allow-password-authentication.tooltip=Kerberosデータベースに対するユーザー名/パスワード認証の有効/無効を設定します。 +edit-mode=編集モード +edit-mode.tooltip=READ_ONLYは、パスワード更新が許可されず、ユーザーが常にKerberosパスワードで認証されることを意味します。UNSYNCEDは、ユーザーがKeycloakデータベースでパスワードを変更できることを意味し、このパスワードはKerberosパスワードの代わりに使用されます +ldap.edit-mode.tooltip=READ_ONLYの場合、LDAPストアに読み取り専用でアクセスします。WRITABLEは、必要に応じてデータをLDAPに同期させることを意味します。UNSYNCEDは、ユーザーデータをインポートするが、LDAPに同期しないことを意味します。 +update-profile-first-login=初回ログイン時にプロファイルを更新 +update-profile-first-login.tooltip=初回ログイン時のプロファイル更新の有効/無効を設定します。 +sync-registrations=登録の同期 +ldap.sync-registrations.tooltip=LDAPストア内に新規作成ユーザーを作成すべきかどうかを設定します。どのプロバイダーが新しいユーザーの同期先に選択されるかは、優先度が影響します。 +import-enabled=ユーザーのインポート +ldap.import-enabled.tooltip=オンの場合、LDAPユーザーはKeycloak DBにインポートされ、設定された同期ポリシーによって同期されます。 +vendor=ベンダー +ldap.vendor.tooltip=LDAPベンダー(プロバイダー) +username-ldap-attribute=ユーザー名のLDAP属性 +ldap-attribute-name-for-username=ユーザー名のLDAP属性名 +username-ldap-attribute.tooltip=Keycloakユーザー名にマッピングされるLDAP属性名を設定します。多くのLDAPサーバーベンダーでは「uid」となります。Active Directoryでは「sAMAccountName」または「cn」となります。LDAPからKeycloakにインポートするすべてのLDAPユーザーのレコードで、属性は入力されているはずです。 +rdn-ldap-attribute=RDN LDAP属性 +ldap-attribute-name-for-user-rdn=ユーザーRDNのLDAP属性名 +rdn-ldap-attribute.tooltip=一般的なユーザーDNのRDN(top属性)として使用されるLDAP属性名を設定します。通常は、ユーザー名のLDAP属性と同じですが、必須ではありません。例えばActive Directoryでは、ユーザー名が「sAMAccountName」だとRDN属性として「cn」を使用するのが一般的です。 +uuid-ldap-attribute=UUID LDAP属性 +ldap-attribute-name-for-uuid=UUIDのLDAP属性名 +uuid-ldap-attribute.tooltip=LDAP内でオブジェクトのユニークなオブジェクト識別子(UUID)として使用されるLDAP属性名を設定します。多くのLDAPサーバーベンダーでは「entryUUID」となりますが、異なる場合もあります。例えばActive Directoryでは、「objectGUID」となります。LDAPサーバーがUUIDをサポートしていない場合は、ツリー内のLDAPユーザーの中でユニークとなる他の属性を使用することができます。例えば、「uid」や「entryDN」です。 +user-object-classes=ユーザー・オブジェクト・クラス +ldap-user-object-classes.placeholder=LDAPのユーザー・オブジェクト・クラス(カンマ区切り) +ldap-connection-url=LDAP接続URL +ldap-users-dn=LDAPユーザーDN +ldap-bind-dn=LDAPバインドDN +ldap-bind-credentials=LDAPバインド・クレデンシャル +ldap-filter=LDAPフィルター +ldap.user-object-classes.tooltip=LDAPユーザー用のすべてのLDAPオブジェクト・クラスをカンマ区切りで設定します。例:「inetOrgPerson, organizationalPerson」。新規作成されたKeycloakユーザーは、これらすべてのオブジェクト・クラスを使用してLDAPに書き込まれます。また、既存のLDAPユーザーのレコードは、これらすべてのオブジェクト・クラスを含む場合だけ発見されます。 +connection-url=接続URL +ldap.connection-url.tooltip=LDAPサーバーへの接続URL +test-connection=接続テスト +users-dn=ユーザーDN +ldap.users-dn.tooltip=ユーザーがいるLDAPツリーの完全DNを設定します。このDNはLDAPユーザーの親になります。例えば、典型的なユーザーは「uid=john,ou=users,dc=example,dc=com」のようなDNとなりますが、この場合は「ou=users,dc=example,dc=com」となります。 +authentication-type=バインドタイプ +ldap.authentication-type.tooltip=LDAPバインド操作中に使用される認証方式のタイプ。LDAPサーバーに送信されるほとんどのリクエストで使用されます。現時点では「none」(匿名LDAP認証)または「simple」(クレデンシャル・バインド + パスワード・バインドの認証)のメカニズムのみ利用できます。 +bind-dn=バインドDN +ldap.bind-dn.tooltip=KeycloakがLDAPサーバーにアクセスするために使用するLDAP管理者のDNを設定します。 +bind-credential=バインド・クレデンシャル +ldap.bind-credential.tooltip=LDAP管理者のパスワードを設定します。このフィールドは、ボールトから値を取得できます。${vault.ID}形式を使用します。 +test-authentication=認証テスト +custom-user-ldap-filter=カスタムユーザーLDAPフィルター +ldap.custom-user-ldap-filter.tooltip=ユーザー検索のフィルタリングを行うLDAPフィルターを設定します。追加のフィルターが必要ない場合は空のままにしてください。設定は、「(」から始まり「)」で終わることを確認してください。 +search-scope=検索スコープ +ldap.search-scope.tooltip=One Levelでは、ユーザーDNで指定されたDNのユーザーのみが検索されます。Subtreeでは、サブツリー全体を検索します。より詳細についてはLDAPのドキュメントを参照してください。 +use-truststore-spi=トラストストアSPIを使用 +ldap.use-truststore-spi.tooltip=LDAP接続で、standalone.xml/domain.xmlで設定されたトラストストアのトラストストアSPIを使用するかどうかを指定します。「Always」は常に使用することを意味します。「Never」は使用しないことを意味します。「Only for ldaps」は、接続URLがldapsの場合に使用することを意味します。standalone.xml/domain.xmlで設定されていない場合でも、デフォルトのJava CA証明書(cacerts)や「javax.net.ssl.trustStore」プロパティーで指定された証明書が使用される点に注意してください。 +validate-password-policy=パスワード・ポリシーの検証 +connection-pooling=接続プーリング +connection-pooling-settings=接続プーリングの設定 +connection-pooling-authentication=接続プーリング認証 +connection-pooling-authentication-default=none simple +connection-pooling-debug=接続プールのデバッグレベル +connection-pooling-debug-default=オフ +connection-pooling-initsize=接続プールの初期サイズ +connection-pooling-initsize-default=1 +connection-pooling-maxsize=接続プールの最大サイズ +connection-pooling-maxsize-default=1000 +connection-pooling-prefsize=接続プールの推奨サイズ +connection-pooling-prefsize-default=5 +connection-pooling-protocol=接続プールのプロトコル +connection-pooling-protocol-default=plain ssl +connection-pooling-timeout=接続プールのタイムアウト +connection-pooling-timeout-default=300000 +ldap-connection-timeout=接続タイムアウト +ldap.connection-timeout.tooltip=LDAP接続タイムアウト(ミリ秒単位) +ldap-read-timeout=読み取りタイムアウト +ldap.read-timeout.tooltip=LDAP読み取りタイムアウト(ミリ秒単位)。このタイムアウトはLDAP読み取り操作に適用されます +ldap.validate-password-policy.tooltip=パスワードを更新する前に、Keycloakがパスワード・ポリシーでパスワードを検証する必要があるかどうかを決定します +ldap.connection-pooling.tooltip=KeycloakがLDAPサーバーへのアクセスで接続プールを使用するかどうかを決定します +ldap.connection-pooling.authentication.tooltip=プール可能な接続の認証タイプのリスト(スペース区切り)。有効なタイプは「none」、「simple」、「DIGEST-MD5」です。 +ldap.connection-pooling.debug.tooltip=生成するデバッグ出力のレベルを示す文字列。有効な値は、「fine」(接続の作成と削除のトレース)と「all」(すべてのデバッグ情報)です。 +ldap.connection-pooling.initsize.tooltip=アイデンティティー用に最初に接続を作成するときに作成する接続アイデンティティーごとの接続数を表す整数の文字列表現。 +ldap.connection-pooling.maxsize.tooltip=接続アイデンティティーごとに同時に維持できる接続の最大数を表す整数の文字列表現。 +ldap.connection-pooling.prefsize.tooltip=同時に維持する必要がある接続アイデンティティーごとの優先接続数を表す整数の文字列表現。 +ldap.connection-pooling.protocol.tooltip=プール可能な接続のプロトコルタイプのリスト(スペース区切り)。有効なタイプは「plain」と「ssl」です。 +ldap.connection-pooling.timeout.tooltip=アイドル状態の接続がクローズされず、プールからも削除されないままプールに残る時間(ミリ秒)を表す整数の文字列表現。 +ldap.pagination.tooltip=LDAPサーバーはページネーションをサポートするかどうかを設定します。 +ldap.startTls.tooltip=STARTTLSを使用してLDAPへの接続を暗号化します。これにより接続プールが無効になります。 +kerberos-integration=Kerberosと統合 +allow-kerberos-authentication=Kerberos認証を許可 +ldap.allow-kerberos-authentication.tooltip=SPNEGO/Kerberosのトークンを持つユーザーのHTTP認証を有効/無効にします。認証されたユーザーに関するデータはこのLDAPサーバーよりプロビジョニングされます。 +use-kerberos-for-password-authentication=パスワード認証にKerberosを使用 +ldap.use-kerberos-for-password-authentication.tooltip=LDAPサーバーに対してディレクトリー・サービスのAPIで認証する代わりに、Kerberosに対してユーザー名/パスワード認証するKerberosログイン・モジュールを使用します。 +batch-size=バッチサイズ +ldap.batch-size.tooltip=1トランザクションでLDAPからKeycloakにインポートされるLDAPユーザー数を設定します。 +ldap.periodic-full-sync.tooltip=KeycloakへのLDAPユーザーの定期的なフル同期を有効/無効にします。 +ldap.periodic-changed-users-sync.tooltip=Keycloakへの変更または新規作成されたLDAPユーザーの定期的な同期を有効/無効にします。 +ldap.changed-users-sync-period.tooltip=変更または新規作成されたLDAPユーザーの同期周期を秒で設定します。 +user-federation-mappers=ユーザー・フェデレーションのマッパー +create-user-federation-mapper=ユーザー・フェデレーション・マッパーの作成 +add-user-federation-mapper=ユーザー・フェデレーション・マッパーの追加 +provider-name=プロバイダー名 +no-user-federation-providers-configured=設定されているユーザー・フェデレーション・プロバイダーはありません +no-user-storage-providers-configured=設定されているユーザー・ストレージ・プロバイダーはありません +add-identity-provider=アイデンティティー・プロバイダーの登録 +add-identity-provider-link=アイデンティティー・プロバイダーのリンク登録 +identity-provider=アイデンティティー・プロバイダー +identity-provider-user-id=アイデンティティー・プロバイダーのユーザーID +identity-provider-user-id.tooltip=アイデンティティー・プロバイダー側のユーザーのユニークIDです。 +identity-provider-username=アイデンティティー・プロバイダーのユーザー名 +identity-provider-username.tooltip=アイデンティティー・プロバイダー側のユーザー名です。 +pagination=ページネーション +browser-flow=ブラウザーフロー +browser-flow.tooltip=ブラウザー認証で使用したいフローを選択してください。 +registration-flow=登録フロー +registration-flow.tooltip=登録で使用したいフローを選択してください。 +direct-grant-flow=ダイレクト・グラント・フロー +direct-grant-flow.tooltip=ダイレクト・グラント認証で使用したいフローを選択してください。 +reset-credentials=クレデンシャルのリセット +reset-credentials.tooltip=ユーザーがクレデンシャルを忘れた際に使用したいフローを選択してください。 +client-authentication=クライアント認証 +client-authentication.tooltip=クライアント認証で使用したいフローを選択してください。 +docker-auth=Docker認証 +docker-auth.tooltip=Dockerクライアントに対する認証に使用するフローを選択します。 +new=新規作成 +copy=コピー +add-execution=エグゼキューションを追加 +add-flow=フローを追加 +auth-type=認証タイプ +requirement=必要条件 +config=設定 +no-executions-available=使用可能なエグゼキューションがありません +authentication-flows=認証フロー +create-authenticator-config=認証設定の作成 +authenticator.alias.tooltip=この設定の名前を設定します。 +otp-type=OTPタイプ +time-based=タイムベース +counter-based=カウンターベース +otp-type.tooltip=「totp」はタイムベースのワンタイム・パスワードです。「hotp」は、サーバーでハッシュに対してカウンターを保持するカウンターベースのワンタイム・パスワードです。 +otp-hash-algorithm=OTPハッシュ・アルゴリズム +otp-hash-algorithm.tooltip=OTPを生成するのにどのハッシュ・アルゴリズムを使用するか設定します。 +number-of-digits=桁数 +otp.number-of-digits.tooltip=OTPの桁数を設定します。 +look-ahead-window=先読みウィンドウ +otp.look-ahead-window.tooltip=トークン・ジェネレーターとサーバーが時刻同期またはカウンター同期していないことを考慮してどれくらい先読みを行うか設定します。 +initial-counter=初期カウンター +otp.initial-counter.tooltip=初期カウンターの値を設定します。 +otp-token-period=OTPトークンの期間 +otp-token-period.tooltip=OTPトークンが有効な秒数を設定します。デフォルトは30秒です。 +otp-supported-applications=サポートされるアプリケーション +otp-supported-applications.tooltip=現在のOTPポリシーで動作することが分かっているアプリケーション +table-of-password-policies=パスワード・ポリシーの一覧表 +add-policy.placeholder=ポリシーを追加... +policy-type=ポリシーのタイプ +policy-value=ポリシーの値 +webauthn-policy=WebAuthnポリシー +webauthn-policy.tooltip=WebAuthn認証のポリシー。これは、「WebAuthn Register」必須アクションと「WebAuthn Authenticator」オーセンティケーターで使用されます。一般的な用途は、2要素認証にWebAuthnを使用する場合です。 +webauthn-policy-passwordless=WebAuthnパスワードレス・ポリシー +webauthn-policy-passwordless.tooltip=パスワードレスWebAuthn認証のポリシー。これは、「Webauthn Register Passwordless」必須アクションおよび「WebAuthn Passwordless Authenticator」オーセンティケーターによって使用されます。一般的な使用法は、WebAuthnが一要素認証として使用される場合です。「WebAuthnポリシー」と「WebAuthnパスワードレス・ポリシー」の両方を使用すると、WebAuthnを同じレルムの第1要素オーセンティケーターと第2要素オーセンティケーターの両方として使用できます。 +webauthn-rp-entity-name=リライング・パーティー・エンティティー名 +webauthn-rp-entity-name.tooltip=WebAuthnリライング・パーティーとしての人間が読み取れるサーバー名 +webauthn-signature-algorithms=署名アルゴリズム +webauthn-signature-algorithms.tooltip=認証アサーションに使用する署名アルゴリズム。 +webauthn-rp-id=リライング・パーティー・エンティティーID +webauthn-rp-id.tooltip=これは、WebAuthnリライング・パーティーとしてのIDです。オリジンの有効なドメインでなければなりません。 +webauthn-attestation-conveyance-preference=期待する構成証明伝達 +webauthn-attestation-conveyance-preference.tooltip=認証ステートメントを生成する方法の優先権をオーセンティケーターに通知します。 +webauthn-authenticator-attachment=オーセンティケーター・アタッチメント +webauthn-authenticator-attachment.tooltip=受け入れ可能なアタッチメント・パターンでオーセンティケーターと通信します。 +webauthn-require-resident-key=常駐鍵が必要 +webauthn-require-resident-key.tooltip=これは、オーセンティケーターに公開鍵クレデンシャルを常駐鍵として作成するかどうかを指示します。 +webauthn-user-verification-requirement=ユーザー検証要件 +webauthn-user-verification-requirement.tooltip=ユーザーを実際に検証することを確認するためにオーセンティケーターと通信します。 +webauthn-create-timeout=タイムアウト +webauthn-create-timeout.tooltip=ユーザーの公開鍵クレデンシャルの作成に対するタイムアウト値(秒単位)。0に設定すると、このタイムアウト・オプションは適応されません。 +webauthn-avoid-same-authenticator-register=オーセンティケーターの重複登録回避 +webauthn-avoid-same-authenticator-register.tooltip=すでに登録されているオーセンティケーターの登録を避けるかどうかを設定します。 +webauthn-acceptable-aaguids=許容可能なAAGUID +webauthn-acceptable-aaguids.tooltip=登録可能なオーセンティケーターのAAGUIDのリスト。 +manage-webauthn-authenticator=WebAuthnオーセンティケーターの管理 +public-key-credential-id=公開鍵クレデンシャルID +public-key-credential-aaguid=公開鍵クレデンシャルAAGUID +public-key-credential-label=公開鍵クレデンシャル・ラベル +admin-events=管理イベント +admin-events.tooltip=保存されたレルムの管理イベントを表示します。管理イベントは、アカウント管理に関連したイベント、例えばレルムの作成などです。イベントの保存を有効にするには設定へ移動してください。 +login-events=ログインイベント +filter=フィルター +update=更新 +reset=リセット +operation-types=操作タイプ +resource-types=リソースタイプ +select-operations.placeholder=操作を選択... +select-resource-types.placeholder=リソースタイプを選択... +resource-path=リソースパス +resource-path.tooltip=リソースパスでフィルタリングします。ワイルドカード「*」をサポートします(例:「users/*」)。 +date-(from)=日付(From) +date-(to)=日付(To) +authentication-details=認証の詳細 +ip-address=IPアドレス +time=日時 +operation-type=操作タイプ +resource-type=リソースタイプ +auth=認証 +representation=Representation +register=登録 +required-action=必須アクション +default-action=デフォルト・アクション +auth.default-action.tooltip=有効の場合は、新規ユーザーにはこの必須アクションがアサインされます。 +no-required-actions-configured=設定された必須アクションはありません +defaults-to-id=IDがデフォルトになります +flows=フロー +bindings=バインディング +client-flow-bindings=認証フローのオーバーライド +client-flow-bindings.tooltip=レルム認証フロー・バインディングをオーバーライドします。 +required-actions=必須アクション +password-policy=パスワード・ポリシー +otp-policy=OTPポリシー +user-groups=ユーザーグループ +default-groups=デフォルト・グループ +groups.default-groups.tooltip=新規ユーザーが自動的に参加するグループのセットを設定します。 +cut=カット +paste=ペースト +create-group=グループの作成 +create-authenticator-execution=認証エグゼキューションの作成 +create-form-action-execution=フォーム・アクション・エグゼキューションの作成 +create-top-level-form=トップレベル・フォームの作成 +flow.alias.tooltip=フローの表示名を指定します。 +top-level-flow-type=トップレベル・フロー・タイプ +flow.generic=generic +flow.client=client +top-level-flow-type.tooltip=どの種類のトップレベル・フローを作成するか設定します。「client」タイプは、クライアント(アプリケーション)の認証で使用します。「generic」はユーザーと他のすべてで使用します。 +create-execution-flow=エグゼキューション・フローの作成 +flow-type=フロータイプ +flow.form.type=form +flow.generic.type=generic +flow-type.tooltip=どの種類のフォームかを設定します。 +form-provider=フォーム・プロバイダー +default-groups.tooltip=新規作成または登録されたユーザーは自動的にこれらのグループに追加されます。 +select-a-type.placeholder=タイプを選択してください +available-groups=使用可能なグループ +available-groups.tooltip=デフォルトとして追加したいグループを選択してください。 +value=値 +table-of-group-members=グループメンバーの一覧表 +table-of-role-members=ロールメンバーの一覧表 +last-name=姓 +first-name=名 +email=Eメール +toggle-navigation=ナビゲーションの切り替え +manage-account=アカウントの管理 +sign-out=サインアウト +server-info=サーバー情報 +resource-not-found=リソースが見つかりません... +resource-not-found.instruction=お探しのリソースが見つかりませんでした。入力されたURLが正しいかご確認ください。 +go-to-the-home-page=ホームページへ移動 » +page-not-found=ページが見つかりません... +page-not-found.instruction=お探しのページが見つかりませんでした。入力されたURLが正しいかご確認ください。 +events.tooltip=保存されたレルムのイベントを表示します。イベントは、ユーザー・アカウントに関連したイベント、例えばログインなどです。イベントの保存を有効にするには設定へ移動してください。 +select-event-types.placeholder=イベントタイプを選択... +events-config.tooltip=ユーザーイベントと管理イベントの保存を有効にする設定オプションを表示します。 +select-an-action.placeholder=アクションを選択... +event-listeners.tooltip=どのリスナーがレルムのイベントを受け取るか設定します。 +login.save-events.tooltip=有効の場合は、ログインイベントがデータベースに保存され、管理コンソールとアカウント管理で使用することができます。 +clear-events.tooltip=データベース内のすべてのイベントを削除します。 +events.expiration.tooltip=イベントの有効期限を設定します。期限切れのイベントはデータベースから定期的に削除されます。 +admin-events-settings=管理イベントの設定 +save-events=イベントの保存 +admin.save-events.tooltip=有効の場合は、管理イベントがデータベースに保存され、管理コンソールで使用可能になります。 +saved-types.tooltip=どのイベントタイプが保存されるかを設定します。 +include-representation=Representationを含める +include-representation.tooltip=作成または更新リクエストのJSON Representationを含めるかどうかを設定します。 +clear-admin-events.tooltip=データベース内のすべての管理イベントを削除します。 +server-version=サーバーのバージョン +server-profile=サーバー・プロファイル +server-disabled=使用できない機能 +server-disabled.tooltip=現在有効になっていない機能。一部の機能はデフォルトでは有効になっていません。これはすべてのプレビュー機能と実験的機能に適用されます。 +server-preview=プレビュー機能 +server-preview.tooltip=プレビュー機能は本番環境ではサポートされておらず、将来大幅に変更または削除される可能性があります。 +server-experimental=実験的機能 +server-experimental.tooltip=実験的機能は完全に機能しない可能性があります。本番環境では実験的機能を使用しないでください。 +info=情報 +providers=プロバイダー +server-time=サーバーの時刻 +server-uptime=サーバーの稼働時間 +profile=プロファイル +memory=メモリー +total-memory=メモリーの総容量 +free-memory=空きメモリー +used-memory=使用メモリー +system=システム +current-working-directory=現在の作業ディレクトリー +java-version=Javaバージョン +java-vendor=Javaベンダー +java-runtime=Javaランタイム +java-vm=Java VM +java-vm-version=Java VMバージョン +java-home=Javaホーム +user-name=ユーザー名 +user-timezone=ユーザー・タイムゾーン +user-locale=ユーザーロケール +system-encoding=システム・エンコーディング +operating-system=オペレーティング・システム +os-architecture=OSアーキテクチャー +spi=SPI +granted-client-scopes=付与されたクライアント・スコープ +additional-grants=追加の許可 +consent-created-date=作成日 +consent-last-updated-date=最終更新日 +revoke=無効化 +new-password=新しいパスワード +password-confirmation=新しいパスワード(確認) +reset-password=パスワードをリセット +set-password=パスワードを設定 +credentials.temporary.tooltip=有効の場合は、ユーザーは次のログイン時にパスワードの変更が必要となります。 +remove-totp=OTPの削除 +credentials.remove-totp.tooltip=ユーザーのワンタイム・パスワード・ジェネレーターを削除します。 +reset-actions=リセット・アクション +credentials.reset-actions.tooltip=ユーザーにリセット・アクションEメールを送信するときに実行するアクションのセット。「Verify Email」は、Eメールアドレスを確認するためのEメールをユーザーに送信します。「Update Profile」は、新しい個人情報を入力する必要があります。「Update Password」は、ユーザーが新しいパスワードを入力する必要があります。「Configure OTP」は、モバイル・パスワード・ジェネレーターの設定が必要です。 +reset-actions-email=リセット・アクションEメール +send-email=Eメールを送信 +credentials.reset-actions-email.tooltip=リンクを記載したEメールをユーザーに送信します。リンクをクリックすると、ユーザーは最初にログインせずにリセット・アクションを実行できます。たとえば、「Update Password」アクションを設定してこのボタンをクリックすると、ユーザーはログインせずにパスワードを変更できます。 +add-user=ユーザーの追加 +created-at=作成日 +user-enabled=ユーザーの有効 +user-enabled.tooltip=無効なユーザーはログインすることができません。 +user-temporarily-locked=ユーザーの一時的なロック +user-temporarily-locked.tooltip=ユーザーは、ログインに複数回失敗したため、ロックされている可能性があります。 +unlock-user=ユーザーをアンロック +federation-link=フェデレーション・リンク +email-verified=Eメールが確認済み +email-verified.tooltip=ユーザーのEメールが確認済みかどうかを設定します。 +required-user-actions=必要なユーザー・アクション +required-user-actions.tooltip=ユーザーがログインするときに必要なアクションです。「Verify email」は、Eメールアドレスを確認するためのEメールをユーザーに送信します。「Update profile」は、新しい個人情報を入力する必要があります。「Update password」は、ユーザーが新しいパスワードを入力する必要があります。「Configure OTP」は、モバイル・パスワード・ジェネレーターの設定が必要です。 +locale=ロケール +select-one.placeholder=1つ選択... +impersonate=代理ログイン +impersonate-user=ユーザーの代理 +impersonate-user.tooltip=このユーザーとしてログインします。同じレルム内のユーザーの場合は、このユーザーでログインする前に、現在のログイン・セッションがログアウトされます。 +identity-provider-alias=アイデンティティー・プロバイダーのエイリアス +provider-user-id=プロバイダーのユーザーID +provider-username=プロバイダーのユーザー名 +no-identity-provider-links-available=使用可能なアイデンティティー・プロバイダーのリンクはありません +group-membership=グループ・メンバーシップ +leave=外す +group-membership.tooltip=メンバーであるグループです。グループから外すには、グループを選択して「外す」ボタンをクリックしてください。 +membership.available-groups.tooltip=ユーザーが参加可能なグループです。グループを選択して「参加」ボタンをクリックしてください。 +table-of-realm-users=レルムユーザーの一覧表 +view-all-users=すべてのユーザーを参照 +view-all-groups=すべてのグループを参照 +view-all-rolesすべてのロールを参照 +unlock-users=ユーザーのアンロック +no-users-available=使用可能なユーザーはいません +users.instruction=検索を入力するか、「すべてのユーザーを参照」をクリックしてください +clients.instruction=検索を入力してください +consents=同意 +started=開始 +logout-all-sessions=すべてのセッションをログアウト +logout=ログアウト +new-name=新しい名前 +ok=OK +attributes=属性 +role-mappings=ロールマッピング +members=メンバー +details=詳細 +identity-provider-links=アイデンティティー・プロバイダーのリンク +register-required-action=必須アクションの登録 +gender=性別 +address=住所 +phone=電話番号 +profile-url=プロファイルURL +picture-url=画像URL +website=Webサイト +import-keys-and-cert=鍵と証明書をインポート +import-keys-and-cert.tooltip=クライアントの鍵ペアと証明書をアップロードします。 +upload-keys=鍵をアップロード +download-keys-and-cert=鍵と証明書をダウンロード +no-value-assigned.placeholder=アサイン済みの値はありません +remove=削除 +no-group-members=グループメンバーはいません +no-role-members=ロールメンバーはいません +temporary=一時的 +join=参加 +event-type=イベントタイプ +events-config=イベント設定 +event-listeners=イベントリスナー +login-events-settings=ログインイベントの設定 +clear-events=イベントのクリア +saved-types=保存タイプ +clear-admin-events=管理イベントのクリア +clear-changes=変更をクリア +error=エラー +# Authz +# Authz Common +authz-authorization=認可 +authz-owner=オーナー +authz-uri=URI +authz-uris=URI +authz-scopes=スコープ +authz-resource=リソース +authz-resource-type=リソースタイプ +authz-resources=リソース +authz-scope=スコープ +authz-authz-scopes=認可スコープ +authz-policies=ポリシー +authz-policy=ポリシー +authz-permissions=パーミッション +authz-users=ロールのユーザー +authz-evaluate=評価 +authz-icon-uri=アイコンURI +authz-icon-uri.tooltip=アイコンを指すURIを設定します。 +authz-select-scope=スコープを選択 +authz-select-resource=リソースを選択 +authz-associated-policies=関連ポリシー +authz-any-resource=任意のリソース +authz-any-scope=任意のスコープ +authz-any-role=任意のロール +authz-policy-evaluation=ポリシー評価 +authz-select-user=ユーザーを選択 +authz-select-client=クライアントを選択 +authz-entitlements=エンタイトルメント +authz-no-resources=リソースはありません +authz-result=結果 +authz-authorization-services-enabled=認可の有効 +authz-authorization-services-enabled.tooltip=きめ細かい認可のサポートを有効/無効にします。 +authz-required=必須 +authz-show-details=詳細を表示する +authz-hide-details=詳細を非表示にする +authz-associated-permissions=関連付けられたパーミッション +authz-no-permission-associated=パーミッションが関連付けられていません +# Authz Settings +authz-import-config.tooltip=リソースサーバーの認可設定を含むJSONファイルをインポートします。 +authz-policy-enforcement-mode=ポリシー施行モード +authz-policy-enforcement-mode.tooltip=ポリシー施行モードは、認可リクエストを評価する際に適用される方法を決定します。「Enforcing」は、与えられたリソースに関連するポリシーが存在しない場合でも、リクエストはデフォルトで拒否されることを意味します。「Permissive」は、与えられたリソースに関連するポリシーが存在しない場合でも、リクエストは許可されることを意味します。「Disabled」は、完全にポリシーの評価を無効にし、任意のリソースへのアクセスを許可します。 +authz-policy-enforcement-mode-enforcing=実施 +authz-policy-enforcement-mode-permissive=許容 +authz-policy-enforcement-mode-disabled=無効 +authz-remote-resource-management=リモートリソース管理 +authz-remote-resource-management.tooltip=リソースは、リソースサーバーによりリモートで管理すべきかどうかを設定します。オフの場合は、リソースはこの管理コンソールだけで管理されます。 +authz-export-settings=エクスポート設定 +authz-export-settings.tooltip=このリソースサーバーのすべての認可設定をエクスポートしダウンロードします。 +authz-server-decision-strategy.tooltip=決定戦略は、パーミッションの評価方法と最終的な判定の取得方法を決定します。「Affirmative」とは、リソースおよびそのスコープへのアクセスを許可するために、少なくとも1つのパーミッションが肯定的な判定に評価される必要があることを意味します。「Unanimous」とは、最終的な判定も肯定的であるために、すべてのパーミッションが肯定的な判定に評価される必要があることを意味します。 +# Authz Resource List +authz-no-resources-available=使用可能なリソースはありません。 +authz-no-scopes-assigned=アサイン済みのスコープはありません。 +authz-no-type-defined=定義されたタイプはありません。 +authz-no-uri-defined=URIが定義されていません。 +authz-no-permission-assigned=アサイン済みのパーミッションはありません。 +authz-no-policy-assigned=アサイン済みのポリシーはありません。 +authz-create-permission=パーミッションを作成 +# Authz Resource Detail +authz-add-resource=リソースの追加 +authz-resource-name.tooltip=このリソースの一意な名前。この名前は、リソースを一意に識別するために使用でき、特定のリソースを照会するときに便利です。 +authz-resource-owner.tooltip=このリソースのオーナーです。 +authz-resource-type.tooltip=このリソースのタイプを設定します。異なるリソース・インスタンスを同じタイプにグルーピングすることができます。 +authz-resource-uri.tooltip=リソースによって保護されているURIのセット。 +authz-resource-scopes.tooltip=このリソースに関連付けるスコープを設定します。 +authz-resource-attributes=リソース属性 +authz-resource-attributes.tooltip=リソースに関連付けられた属性。 +authz-resource-user-managed-access-enabled=User-Managed Accessの有効 +authz-resource-user-managed-access-enabled.tooltip=有効にすると、このリソースへのアクセスをリソースオーナーが管理できます。 + +# Authz Scope List +authz-add-scope=スコープの追加 +authz-no-scopes-available=使用可能なスコープはありません。 +# Authz Scope Detail +authz-scope-name.tooltip=このスコープのユニークな名前を設定します。名前はスコープの一意な識別に使用され、特定のスコープを照会する際に使用することができます。 +# Authz Policy List +authz-all-types=すべてのタイプ +authz-create-policy=ポリシーを作成 +authz-no-policies-available=使用可能なポリシーはありません。 +# Authz Policy Detail +authz-policy-name.tooltip=このポリシーの名前を設定します。 +authz-policy-description.tooltip=このポリシーの説明を設定します。 +authz-policy-logic=ロジック +authz-policy-logic-positive=Positive +authz-policy-logic-negative=Negative +authz-policy-logic.tooltip=ロジックは、ポリシーの判定方法を決定します。「Positive」の場合は、このポリシーの評価中に得られた結果(許可または拒否)が判定の実行に使用されます。「Negative」の場合は、結果は反転されます。つまり、許可は拒否になり、拒否は許可になります。 +authz-policy-apply-policy=ポリシーの適用 +authz-policy-apply-policy.tooltip=このポリシーやパーミッションで定義されたスコープに適用するすべてのポリシーを設定します。 +authz-policy-decision-strategy=決定戦略 +authz-policy-decision-strategy.tooltip=決定戦略は、ポリシーの評価方法と最終的な判定方法を決定します。「Affirmative」は、最終判定がpositiveとなるためには、少なくとも1つのポリシーがpositiveと評価する必要がある、ということを意味します。「Unanimous」は、全体の判定がpositiveとなるためには、すべてのポリシーがpositiveと評価する必要がある、ということを意味します。「Consensus」は、positiveの数がnegativeの数より多くなければならないことを意味します。positiveとnegativeの数が同じ場合は、最終的な判定はnegativeになります。 +authz-policy-decision-strategy-affirmative=Affirmative +authz-policy-decision-strategy-unanimous=Unanimous +authz-policy-decision-strategy-consensus=Consensus +authz-select-a-policy=既存のポリシーを選択する +authz-no-policies-assigned=ポリシーが割り当てられていません。 +# Authz Role Policy Detail +authz-add-role-policy=ロールポリシーの追加 +authz-no-roles-assigned=アサイン済みのロールはありません。 +authz-policy-role-realm-roles.tooltip=このポリシーで許可されるレルムロールを指定してください。 +authz-policy-role-clients.tooltip=このポリシーに適用されるクライアント・ロールをフィルタリングするために、クライアントを選択してください。 +authz-policy-role-client-roles.tooltip=このポリシーで許可されるクライアント・ロールを指定してください。 +# Authz User Policy Detail +authz-add-user-policy=ユーザーポリシーの追加 +authz-no-users-assigned=アサイン済みのユーザーはいません。 +authz-policy-user-users.tooltip=どのユーザーがこのポリシーで許可されるか指定してください。 +# Authz Client Policy Detail +authz-add-client-policy=クライアント・ポリシーの追加 +authz-no-clients-assigned=クライアントが割り当てられていません。 +authz-policy-client-clients.tooltip=このポリシーで許可されるクライアントを指定します。 +# Authz Time Policy Detail +authz-add-time-policy=タイムポリシーの追加 +authz-policy-time-not-before.tooltip=ポリシーを許可しない日時を定義します。現在日時がこの値より後か、等しい場合にのみ許可されます。 +authz-policy-time-not-on-after=この日時より後 +authz-policy-time-not-on-after.tooltip=ポリシーを許可しない日時を定義します。現在日時がこの値より前か、等しい場合にのみ許可されます。 +authz-policy-time-day-month=日 +authz-policy-time-day-month.tooltip=ポリシーが許可される日を定義します。2番目のフィールドに値を入力して範囲を指定することもできます。この場合、現在の日が指定した2つの値の間にあるか、等しい場合のみ許可されます。 +authz-policy-time-month=月 +authz-policy-time-month.tooltip=ポリシーが許可される月を定義します。2番目のフィールドに値を入力して範囲を指定することもできます。この場合、現在の月が指定した2つの値の間にあるか、等しい場合のみ許可されます。 +authz-policy-time-year=年 +authz-policy-time-year.tooltip=ポリシーが許可される年を定義します。2番目のフィールドに値を入力して範囲を指定することもできます。この場合、現在の年が指定した2つの値の間にあるか、等しい場合のみ許可されます。 +authz-policy-time-hour=時 +authz-policy-time-hour.tooltip=ポリシーが許可される時を定義します。2番目のフィールドに値を入力して範囲を指定することもできます。この場合、現在の時が指定した2つの値の間にあるか、等しい場合のみ許可されます。 +authz-policy-time-minute=分 +authz-policy-time-minute.tooltip=ポリシーが許可される分を定義します。2番目のフィールドに値を入力して範囲を指定することもできます。この場合、現在の分が指定した2つの値の間にあるか、等しい場合のみ許可されます。 +# Authz JS Policy Detail +authz-add-js-policy=JavaScriptポリシーの追加 +authz-policy-js-code=コード +authz-policy-js-code.tooltip=このポリシーに対する条件を提供するJavaScriptコード。 +# Authz Aggregated Policy Detail +authz-aggregated=集約 +authz-add-aggregated-policy=集約ポリシーの追加 +# Authz Group Policy Detail +authz-add-group-policy=グループポリシーを追加する +authz-no-groups-assigned=グループが割り当てられていません。 +authz-policy-group-claim=グループクレーム +authz-policy-group-claim.tooltip=定義されている場合、ポリシーは、パーミッションを要求するアイデンティティーを表すアクセストークンまたはIDトークン内の特定のクレームから、ユーザーのグループを取得します。定義されていない場合、ユーザーのグループはレルム設定から取得されます。 +authz-policy-group-groups.tooltip=このポリシーで許可されるグループを指定します。 + +# Authz Permission List +authz-no-permissions-available=使用可能なパーミッションはありません。 + +# Authz Permission Detail +authz-permission-name.tooltip=このパーミッションの名前を設定します。 +authz-permission-description.tooltip=このパーミッションの説明を設定します。 + +# Authz Resource Permission Detail +authz-add-resource-permission=リソースパーミッションの追加 +authz-permission-resource-apply-to-resource-type=リソースタイプに適用 +authz-permission-resource-apply-to-resource-type.tooltip=このパーミッションが、特定タイプの全リソースに適用されるべきかどうかを指定します。この場合、パーミッションは特定リソースタイプの全インスタンスに対して評価されます。 +authz-permission-resource-resource.tooltip=このパーミッションが適用されるリソース・インスタンスを指定します。 +authz-permission-resource-type.tooltip=このパーミッションが適用されるリソースタイプを指定します。 + +# Authz Scope Permission Detail +authz-add-scope-permission=スコープパーミッションの追加 +authz-permission-scope-resource.tooltip=選択されたリソースに関連するスコープに制限します。選択されていない場合は、すべてのスコープが使用可能になります。 +authz-permission-scope-scope.tooltip=このパーミッションは1つまたは複数のスコープに適用されるように指定してください。 + +# Authz Evaluation +authz-evaluation-identity-information=アイデンティティー情報 +authz-evaluation-identity-information.tooltip=ポリシーの評価の際に使用されるアイデンティティー情報の設定オプションです。 +authz-evaluation-client.tooltip=認可リクエストを作成するクライアントを選択してください。提供されない場合は、認可リクエストは今いるページのクライアントで行われることになります。 +authz-evaluation-user.tooltip=サーバーからパーミッションを検索するためにIDが使用されるユーザーを選択します。 +authz-evaluation-role.tooltip=選択されたユーザーに関連付けたいロールを選択してください。 +authz-evaluation-new=新規に評価 +authz-evaluation-re-evaluate=再評価 +authz-evaluation-previous=前の評価 +authz-evaluation-contextual-info=コンテキスト情報 +authz-evaluation-contextual-info.tooltip=ポリシーの評価の際に使用されるコンテキスト情報の設定オプションです。 +authz-evaluation-contextual-attributes=コンテキスト属性 +authz-evaluation-contextual-attributes.tooltip=実行環境や実行コンテキストによって提供される任意の属性を設定します。 +authz-evaluation-permissions.tooltip=ポリシーが適用されるようにパーミッションを設定するオプションです。 +authz-evaluation-evaluate=評価 +authz-evaluation-any-resource-with-scopes=スコープを持つ任意のリソース +authz-evaluation-no-result=認可リクエストから結果を得ることができませんでした。提供されたリソースまたはスコープが、ポリシーと関連付けられているかどうかを確認してください。 +authz-evaluation-no-policies-resource=このリソースのポリシーが見つかりませんでした。 +authz-evaluation-result.tooltip=このパーミッションの要求の全体的な結果です。 +authz-evaluation-scopes.tooltip=許可されたスコープリストです。 +authz-evaluation-policies.tooltip=どのポリシーが評価され判定されたか詳細を表示しています。 +authz-evaluation-authorization-data=レスポンス +authz-evaluation-authorization-data.tooltip=認可リクエストの処理の結果として送信された認可データのトークンを表示します。これは、許可を求めたクライアントに対してKeycloakが発行する基本的なものです。現在の認可リクエストで付与されたパーミッションについては「authorization」クレームを確認してください。 +authz-show-authorization-data=認可データを表示 + +keys=鍵 +status=ステータス +keystore=キーストア +keystores=キーストア +add-keystore=キーストアの追加 +add-keystore.placeholder=キーストアの追加... +view=ビュー +active=アクティブ +passive=受動的 +disabled=無効 +algorithm=アルゴリズム +providerHelpText=プロバイダーの説明 + +Sunday=日 +Monday=月 +Tuesday=火 +Wednesday=水 +Thursday=木 +Friday=金 +Saturday=土 + +user-storage-cache-policy=キャッシュ設定 +userStorage.cachePolicy=キャッシュ・ポリシー +userStorage.cachePolicy.option.DEFAULT=DEFAULT +userStorage.cachePolicy.option.EVICT_WEEKLY=EVICT_WEEKLY +userStorage.cachePolicy.option.EVICT_DAILY=EVICT_DAILY +userStorage.cachePolicy.option.MAX_LIFESPAN=MAX_LIFESPAN +userStorage.cachePolicy.option.NO_CACHE=NO_CACHE +userStorage.cachePolicy.tooltip=このストレージ・プロバイダーのキャッシュ・ポリシー。「DEFAULT」は、グローバル・キャッシュのデフォルト設定です。「EVICT_DAILY」は、キャッシュが無効になる毎日の時刻です。「EVICT_WEEKLY」は曜日であり、キャッシュが無効になる時刻です。「MAX-LIFESPAN」は、キャッシュ・エントリーの存続期間となるミリ秒単位の時間です。 +userStorage.cachePolicy.evictionDay=エビクションの日 +userStorage.cachePolicy.evictionDay.tooltip=エントリーが無効になる日の曜日を設定します。 +userStorage.cachePolicy.evictionHour=エビクションの時 +userStorage.cachePolicy.evictionHour.tooltip=エントリーが無効になる日の時を設定します。 +userStorage.cachePolicy.evictionMinute=エビクションの分 +userStorage.cachePolicy.evictionMinute.tooltip=エントリーが無効になる日の分を設定します。 +userStorage.cachePolicy.maxLifespan=最大生存期間 +userStorage.cachePolicy.maxLifespan.tooltip=キャッシュ・エントリーの最大生存期間(ミリ秒)。 +user-origin-link=ストレージ・オリジン +user-origin.tooltip=ユーザーが読み込まれたユーザー・ストレージ・プロバイダー +user-link.tooltip=このローカルに格納されたユーザーがインポートされていたユーザー・ストレージ・プロバイダー。 +client-origin-link=ストレージ・オリジン +client-origin.tooltip=クライアントがロードされたプロバイダー + +client-storage-cache-policy=キャッシュ設定 +clientStorage.cachePolicy=キャッシュ・ポリシー +clientStorage.cachePolicy.option.DEFAULT=DEFAULT +clientStorage.cachePolicy.option.EVICT_WEEKLY=EVICT_WEEKLY +clientStorage.cachePolicy.option.EVICT_DAILY=EVICT_DAILY +clientStorage.cachePolicy.option.MAX_LIFESPAN=MAX_LIFESPAN +clientStorage.cachePolicy.option.NO_CACHE=NO_CACHE +clientStorage.cachePolicy.tooltip=このストレージ・プロバイダーのキャッシュ・ポリシー。「DEFAULT」は、グローバル・キャッシュのデフォルト設定です。「EVICT_DAILY」は、キャッシュが無効になる毎日の時刻です。「EVICT_WEEKLY」は曜日であり、キャッシュが無効になる時刻です。「MAX-LIFESPAN」は、キャッシュ・エントリーの存続期間となるミリ秒単位の時間です。 +clientStorage.cachePolicy.evictionDay=エビクションの日 +clientStorage.cachePolicy.evictionDay.tooltip=エントリーが無効になる日の曜日を設定します。 +clientStorage.cachePolicy.evictionHour=エビクションの時 +clientStorage.cachePolicy.evictionHour.tooltip=エントリーが無効になる日の時を設定します。 +clientStorage.cachePolicy.evictionMinute=エビクションの分 +clientStorage.cachePolicy.evictionMinute.tooltip=エントリーが無効になる日の分を設定します。 +clientStorage.cachePolicy.maxLifespan=最大生存期間 +clientStorage.cachePolicy.maxLifespan.tooltip=キャッシュ・エントリーの最大生存期間(ミリ秒)。 + +client-storage-list-no-entries=Keycloakは外部クライアント・データベースと連携できます。デフォルトでは、OpenShiftのOAuthクライアントとサービス・アカウントをサポートしています。開始するには、以下のドロップダウンからプロバイダーを選択します。 + + +disable=無効 +disableable-credential-types=無効化可能なタイプ +credentials.disableable.tooltip=無効にできるクレデンシャル・タイプのリストを設定します。 +disable-credential-types=クレデンシャル・タイプを無効化 +credentials.disable.tooltip=選択したクレデンシャル・タイプを無効にするには、ボタンをクリックします。 +credential-types=クレデンシャル・タイプ +manage-user-password=パスワードの管理 +supported-user-storage-credential-types=サポートされているユーザー・ストレージ・クレデンシャル・タイプ +supported-user-storage-credential-types.tooltip=ユーザー・ストレージ・プロバイダーによって提供され、このユーザー用に設定されているクレデンシャルの種類。特定のプロバイダーの設定と実装に基づいて、これらのタイプのクレデンシャルの検証と最終的な更新をユーザー・ストレージ・プロバイダーに委任できます。 +provided-by=プロバイダー +manage-credentials=クレデンシャルの管理 +manage-credentials.tooltip=ユーザー・ストレージによって提供されないクレデンシャル。それらはローカル・データベースに保存されます。 +disable-credentials=クレデンシャルの無効化 +credential-reset-actions=クレデンシャルのリセット +credential-reset-actions-timeout=有効期限 +credential-reset-actions-timeout.tooltip=アクション許可が失効するまでの最大時間。 +ldap-mappers=LDAPマッパー +create-ldap-mapper=LDAPマッパーの作成 +map-role-mgmt-scope-description=管理者がこのロールをユーザーまたはグループにマッピングできるかどうかを決定するポリシー +manage-authz-users-scope-description=管理者がレルム内のすべてのユーザーを管理できるかどうかを決定するポリシー +view-authz-users-scope-description=管理者がレルム内のすべてのユーザーを表示できるかどうかを決定するポリシー +permissions-enabled-role=パーミッションが有効になっています +permissions-enabled-role.tooltip=このロールを管理するために、きめ細かいパーミッションを有効にするかどうかを決定します。無効にすると、設定されている現在のパーミッションがすべて削除されます。 +manage-permissions-role.tooltip=ロールを管理するためのきめ細かなパーミッション。たとえば、ロールの割り当てを許可されているユーザーに対して、さまざまなポリシーを定義できます。 +lookup=ルックアップ +manage-permissions-users.tooltip=レルム内のすべてのユーザーを管理するきめ細かいパーミッション。レルム内のユーザーを管理できるユーザーには、さまざまなポリシーを定義できます。 +permissions-enabled-users=パーミッションが有効 +permissions-enabled-users.tooltip=ユーザーを管理するために、きめ細かいパーミッションを有効にするかどうかを決定します。無効にすると、設定されている現在のパーミッションがすべて削除されます。 +manage-permissions-client.tooltip=このクライアントを管理したり、このクライアントによって定義されたロールを適用したりする管理者のきめ細かいパーミッションです。 +manage-permissions-group.tooltip=このグループまたはこのグループのメンバーを管理したい管理者のきめ細かいパーミッション。 +manage-authz-group-scope-description=管理者がこのグループを管理できるかどうかを決定するポリシー +view-authz-group-scope-description=管理者がこのグループを表示できるかどうかを決定するポリシー +view-members-authz-group-scope-description=管理者がこのグループのメンバーを管理できるかどうかを決定するポリシー +token-exchange-authz-client-scope-description=このクライアントを対象とするトークンのトークン交換を許可するクライアントを決定するポリシー。 +token-exchange-authz-idp-scope-description=このアイデンティティー・プロバイダーが発行した外部トークンに対して、どのクライアントがトークンを交換できるかを決定するポリシー。 +manage-authz-client-scope-description=管理者がこのクライアントを管理できるかどうかを決定するポリシー +configure-authz-client-scope-description=管理者の管理権限を削減しました。スコープ、テンプレート、またはプロトコル・マッパーを設定できません。 +view-authz-client-scope-description=管理者がこのクライアントを表示できるかどうかを決定するポリシー +map-roles-authz-client-scope-description=管理者がこのクライアントによって定義されたロールをマップできるかどうかを決定するポリシー +map-roles-client-scope-authz-client-scope-description=管理者がこのクライアントによって定義されたロールを別のクライアントのクライアント・スコープに適用できるかどうかを決定するポリシー +map-roles-composite-authz-client-scope-description=管理者がこのクライアントによって定義されたロールをコンポジットとして別のロールに適用できるかどうかを決定するポリシー +map-role-authz-role-scope-description=管理者がこのロールをユーザーまたはグループにマップできるかどうかを決定するポリシー +map-role-client-scope-authz-role-scope-description=管理者がこのロールをクライアントのクライアント・スコープに適用できるかどうかを決定するポリシー +map-role-composite-authz-role-scope-description=管理者がこのロールをコンポジットとして別のロールに適用できるかどうかを決定するポリシー +manage-group-membership-authz-users-scope-description=管理者がレルム内のすべてのユーザーのグループ・メンバーシップを管理できるかどうかを決定するポリシー。これは、特定のグループポリシーと組み合わせて使用??されます +impersonate-authz-users-scope-description=管理者が他のユーザーを偽装できるかどうかを決定するポリシー +map-roles-authz-users-scope-description=管理者がすべてのユーザーのロールをマップできるかどうかを決定するポリシー +user-impersonated-authz-users-scope-description=どのユーザーを偽装するかを決定するポリシー。これらのポリシーは、偽装されているユーザーに適用されます。 +manage-membership-authz-group-scope-description=管理者がこのグループにユーザーを追加または削除できるかどうかを決定するポリシー +manage-members-authz-group-scope-description=管理者がこのグループのメンバーを管理できるかどうかを決定するポリシー + +# KEYCLOAK-6771 Certificate Bound Token +# https://tools.ietf.org/html/draft-ietf-oauth-mtls-08#section-3 +advanced-client-settings=詳細設定 +advanced-client-settings.tooltip=このセクションを展開して、このクライアントの詳細設定を設定します +tls-client-certificate-bound-access-tokens=OAuth 2.0相互TLS証明書バインド・アクセストークンが有効 +tls-client-certificate-bound-access-tokens.tooltip=これにより、OAuth 2.0相互TLS証明書バインド・アクセストークンがサポートされます。つまり、Keycloakは、Keycloakのトークン・エンドポイントとこのクライアントの間で相互TLSにより交換されるクライアントのX.509証明書と、アクセストークンおよびリフレッシュ・トークンをバインドします。これらのトークンは、ベアラートークンの代わりにHolder-of-Keyトークンとして扱うことができます。 +subjectdn=サブジェクトDN +subjectdn-tooltip=クライアント証明書内のサブジェクトDNを検証するための正規表現。あらゆる種類の式に一致させるには、"(.*?)(?:$)"を使用します。 + +pkce-code-challenge-method=Proof Key for Code Exchangeのコードチャレンジ方式 +pkce-code-challenge-method.tooltip=PKCEのどのコードチャレンジ方式を使用するかを選択します。指定しない場合、Keycloakは、クライアントが適切なコードチャレンジとコード交換の方式で認可リクエストを送信しない限り、クライアントにPKCEを適用しません。 + +key-not-allowed-here=キー'{{character}}'はここでは使用できません。 diff --git a/keycloak-themes/base/admin/messages/admin-messages_lt.properties b/keycloak-themes/base/admin/messages/admin-messages_lt.properties new file mode 100644 index 0000000..5fe9e63 --- /dev/null +++ b/keycloak-themes/base/admin/messages/admin-messages_lt.properties @@ -0,0 +1,1219 @@ +# encoding: utf-8 +consoleTitle=Keycloak administravimo konsolė + +# Common messages +enabled=Įgalintas +name=Pavadinimas +displayName=Rodomas pavadinimas +displayNameHtml=Rodomas pavadinimas HTML formatu +save=Saugoti +cancel=Atšaukti +onText=ON +offText=OFF +client=Klientas +clients=Klientai +clear=Išvalyti +selectOne=Pasirinkite vieną... + +true=Taip +false=Ne + +endpoints=Prieigos adresai + +# Realm settings +realm-detail.enabled.tooltip=Naudotojai ir programos prie srities gali prieiti tik tuomet, kai ji įgalinta +realm-detail.oidc-endpoints.tooltip=Atidaromas langas su OpenID Connect prieigos URL adresais +registrationAllowed=Naudotojų registracija +registrationAllowed.tooltip=Įgalina naudotojų registravimosi sąsają. Prisijungimo lange rodoma nuoroda į registravimosi puslapį. +registrationEmailAsUsername=El. paštas kaip naudojo vardas +registrationEmailAsUsername.tooltip=Jei įgalintas tuomet naudotojo vardo laukas registravimosi lange yra slepiamas ir naujai besiregistruojantiems naudotojams el. pašto adresas naudojamas kaip naudotojo vardas. +editUsernameAllowed=Naudotojo vardo redagavimas +editUsernameAllowed.tooltip=Jei įgalintas, tuomet naudotojas gali keisti savo naudotojo vardą. +resetPasswordAllowed=Slaptažodžio priminimas +resetPasswordAllowed.tooltip=Prisijungimo lange rodoma nuoroda pamiršto slaptažodžio atkūrimui. +rememberMe=Prisiminti mane +rememberMe.tooltip=Prisijungimo lange rodyti pasirinkimą leidžiantį naudotojui likti prisijungus netgi tuomet, kai naršyklė yra išjungiama/įjungiama tol, kol nepasibaigia prisijungimo sesija. +verifyEmail=El. pašto patvirtinimas +verifyEmail.tooltip=Reikalauti naudotojo patvirtinti el. pašto adresą pirmojo prisijungimo metu. +sslRequired=Reikalauti SSL +sslRequired.option.all=visoms užklausoms +sslRequired.option.external=išorinėms užklausoms +sslRequired.option.none=niekada +sslRequired.tooltip=Ar HTTPS privalomas? 'niekada' - HTTPS nereikalaujamas. 'išorinėms užklausoms' - jungiantis iš localhost ar serverio IP adresų galima prieiti ir per HTTP. 'visoms užklausoms' - HTTPS reikalaujamas jungiantis iš visų IP adresų. +publicKey=Viešas raktas +privateKey=Privatus raktas +gen-new-keys=Generuoti naujus raktus +certificate=Sertifikatas +host=Serveris +smtp-host=SMTP serveris +port=Prievadas +smtp-port=SMTP prievadas (numatyta reikšmė 25) +from=Nuo +sender-email-addr=Siuntėjo el. pašto adresas +enable-ssl=Įgalinti SSL +enable-start-tls=Įgalinti StartTLS +enable-auth=Įgalinti autentifikaciją +username=Naudotojo vardas +login-username=Prisijungimui naudojamas naudotojo vardas +password=Slaptažodis +login-password=Prisijungimui naudojamas slaptažodis +login-theme=Prisijungimo lango tema +login-theme.tooltip=Pasirinkite kaip atrodys Jūsų prisijungimo, OTP, teisių suteikimo, naudotojų registracijos ir slaptažodžių priminimo langai. +account-theme=Naudotojo profilio tema +account-theme.tooltip=Pasirinkite kaip atrodys naudotojo profilio valdymo langai. +admin-console-theme=Administravimo konsolės tema +select-theme-admin-console=Pasirinkite kaip atrodys administravimo konsolės langai. +email-theme=El. pašto tema +select-theme-email=Pasirinkite kaip atrodys siunčiami el. pašto laiškai. +i18n-enabled=Daugiakalbystės palaikymas +supported-locales=Palaikomos kalbos +supported-locales.placeholder=Pasirinkite arba įrašykite kalbos pavadinimą +default-locale=Numatyta kalba +#localization-upload-file=Upload localization JSON file +#missing-locale=Missing locale. +#missing-file=Missing file. Please select a file to upload. +#localization-file.upload.success=The localization data has been loaded from file. +#localization-file.upload.error=The file can not be uploaded. Please verify the file. +#localization-show=Show realm specific localizations +#no-localizations-configured=No realm specific localizations configured +#add-localization-text=Add localization text +#locale.create.success=The Locale has been created. +#localization-text.create.success=The localization text has been created. +#localization-text.update.success=The localization text has been updated. +#localization-text.remove.success=The localization text has been deleted. +realm-cache-clear=Srities podėlis +realm-cache-clear.tooltip=Iš visų sričių pašalinama visa podėlyje (cache) esanti informacija +user-cache-clear=Naudotojų podėlis +user-cache-clear.tooltip=Iš visų sričių pašalinama visa naudotojų podėlyje (cache) esanti informacija +revoke-refresh-token=Prieigos raktą naudoti tik kartą +revoke-refresh-token.tooltip=Jei įgalintas, tuomet atnaujinimo raktai (Refresh Token) gali būti naudojami tik vieną kartą. Kitu atveju - atnaujinimo raktai gali būti pernaudojami daugelį kartų. +sso-session-idle=SSO sesijos neveikimo laikas +seconds=Sekundės +minutes=Minutės +hours=Valandos +days=Dienos +sso-session-max=SSO sesijos maksimalus laikas +sso-session-idle.tooltip=Laikas, po kurio neaktyvi sesija bus užbaigta. Sesijos pasibaigimo metu visi raktai (Tokens) ir naršyklių sesijos sunaikinamos. +sso-session-max.tooltip=Laikas, po kurio prisijungimo sesija yra sunaikinama. Sesijos pasibaigimo metu visi raktai (Tokens) ir naršyklių sesijos sunaikinamos. +offline-session-idle=Neprisijungusios sesijos neveikimo laikas +offline-session-idle.tooltip=Darbo neprisijungus sesijos neveikimo laikas, po kurio neaktyvi sesija bus užbaigta. Darbo neprisijungus metu, prisijungimo raktai turi būti atnaujinami bent kartą per nurodytą periodą. Kitu atveju sesijos galiojmas bus sustabdytas. +access-token-lifespan=Prisijungimo rakto galiojimo laikas +access-token-lifespan.tooltip=Laikas, po kurio prisijungimui naudojamas raktas (Access Token) nustoja galioti. Rekomenduojama, kad šios reikšmės galiojimas būtų reliatyviai trumpas palyginus su SSO galiojimo laiku. +access-token-lifespan-for-implicit-flow=Prisijungimo rakto galiojimo laikas (Implicit Flow) +access-token-lifespan-for-implicit-flow.tooltip=Laikas, po kurio prisijungimui naudojamas OpenID Connect Implicit Flow raktas nustoja galioti. Rekomenduojama, kad šios reikšmės galiojimas būtų reliatyviai trumpas palyginus su SSO galiojimo laiku. Šis parametras skiriasi nuo 'Prisijungimo rakto galiojimo laikas', nes nėra galimybės atnaujinti prieigos rakto naudojant OpenID Connect Implicit Flow. +client-login-timeout=Kliento prisijungimui skirtas laikas +client-login-timeout.tooltip=Laikas, per kurį klientas turi užbaigti prisijungimo procesą. Normaliu atveju reikšmė turėtų būti 1 minutė. +login-timeout=Naudotojo prisijungimui skirtas laikas +login-timeout.tooltip=Laikas, per kurį naudotojas turi užbaigti prisijungimo procesą. Rekomenduojamas pakankamai ilgas laiko tarpas. Pvz. 30 minučių ar daugiau. +login-action-timeout=Naudotojo prisijungimo veiksmui skirtas laikas +login-action-timeout.tooltip=Laikas, per kurį naudotojas turi užbaigti su prisijungimu susijusį veiksmą. Pavyzdžiui atnaujinti slaptažodį ar sukonfigūruoti OTP. Rekomenduojamas laikas - 5 minutės ar daugiau. +headers=Antraštės +brute-force-detection=Grubios jėgos ataka +x-frame-options=X-Frame-Options +x-frame-options-tooltip=Numatyta reikšmė draudžia puslapius naudoti kitose svetainėse per iframe (paspauskite antraštę norėdami gauti daugiau informacijos) +content-sec-policy=Content-Security-Policy +content-sec-policy-tooltip=Numatyta reikšmė draudžia puslapius naudoti kitose svetainėse per iframe (paspauskite antraštę norėdami gauti daugiau informacijos) +content-type-options=X-Content-Type-Options +content-type-options-tooltip=Numatyta reikšmė draudžia Internet Explorer ir Google Chrome atlikti priimti kitokias MIME reikšmes (MIME-sniffing) nei deklaruotas turinio tipas (content-type) (paspauskite antraštę norėdami gauti daugiau informacijos) +max-login-failures=Maksimalus bandymų prisijungimų skaičius +max-login-failures.tooltip=Pasiekus maksimalų nesėkmingų bandymų prisijungti skaičių įjungiamas specialus rėžimas, kuomet laukimo intervalas yra didinamas po kiekvieno sekančio neteisingo bandymo. +wait-increment=Laukimo laiko didinimas po +wait-increment.tooltip=Laikas, kurį naudotojo prisijungimai yra draudžiami, kai nėsėkmingų bandymų skaičius pasiekia nustatytą ribą +quick-login-check-millis=Per greito bandymo prisijungti laikas milisekundėmis +quick-login-check-millis.tooltip=Jei nėsėkmingi bandymai prisijungti seka vienas kitą per greitai, tuomet naudotojo paskyra yra užrakinama. +min-quick-login-wait=Per greito bandymo prisijungti užrakinimo laikas +min-quick-login-wait.tooltip=Laikas, kurį naudotojo prisijungimai yra draudžiami, kai nėsėkmingi bandymai prisijungti seka vienas kitą per greitai. +max-wait=Maksimalus užrakinimo laikas +max-wait.tooltip=Maksimalus laikas, kuomet naudotojo paskyra yra užrakinama po nesėkmingų bandymų prisijungti. +failure-reset-time=Pamiršti nepavykusius prisijungimus po +failure-reset-time.tooltip=Laikas, po kurio nepavykę prisijungimai bus pamiršti +realm-tab-login=Prisijungimas +realm-tab-keys=Raktai +realm-tab-email=El. paštas +realm-tab-themes=Temos +#realm-tab-localization=Localization +realm-tab-cache=Podėlis +realm-tab-tokens=Raktai +realm-tab-client-registration=Klientų registracija +realm-tab-security-defenses=Saugos priemonės +realm-tab-general=Bendra informacija +add-realm=Pridėti sritį + +#Session settings +realm-sessions=Srities sesijos +revocation=Atšaukimai +logout-all=Atjungti visus +active-sessions=Aktyvios sesijos +sessions=Sesijos +not-before=Ne anksčiau +not-before.tooltip=Atšaukti visus raktus išduotus prieš nurodytą datą. +set-to-now=Parinkti dabartinę datą +push=Informuoti apie atšaukimą +push.tooltip=Visus klientus, kurie turi administravimo URL, informuoti apie naują raktų atšaukimo taisyklę. + +#Protocol Mapper +usermodel.prop.label=Atributas +usermodel.prop.tooltip=Sąsajos UserModel atributo metodo pavadinimas. Pavyzdžiui reikšmė 'email' atitinka UserMode.getEmail() metodą. +usermodel.attr.label=Naudotojo atributas +usermodel.attr.tooltip=Išsaugoto naudotojo atributo pavadinimas kuris naudojamas UserModel.attribute rinkinyje. +userSession.modelNote.label=Naudotojo sesijos pastaba +userSession.modelNote.tooltip=Išsaugotos naudotojo sesijos pastaba, kuri saugoma UserSessionModel.note rinkinyje. +multivalued.label=Daugiareikšmis +multivalued.tooltip=Nurodo, kad atributas gali turėti daugiau nei vieną reikšmę. Jei pažymėtas, tuomet visos reikšmės nustatomos kaip privalomos. Kitu atveju privaloma tik pirmoji reikšmė. +selectRole.label=Parinkite rolę +selectRole.tooltip=Kairėje pusėje esančiame laukelyje įveskite rolės pavadinimą arba paspauskite Rinktis norėdami nurodyti pageidaujamą rolę. +tokenClaimName.label=Reikalaujamo rakto pavadinimas +tokenClaimName.tooltip=Į raktą įterpiamas privalomas atributas. Galite nurodyte pilną kelią iki atributo, pavyzdžiui 'address.street'. Pateiktu atveju bus sukuriamas sudėtinis (nested) JSON objektas. +jsonType.label=Privalomo atributo JSON tipas +jsonType.tooltip=Naudojamas JSON lauko tipas, kuris turi būti užpildomas rakto privalomoje JSON informacijoje. Galimi tipai: long, int, boolean ir String. +includeInIdToken.label=Pridėti prie ID rakto +includeInIdToken.tooltip=Ar privaloma informacija turi būti pridedama prie ID rakto? +includeInAccessToken.label=Pridėti prie prieigos rakto +includeInAccessToken.tooltip=Ar privaloma informacija turi būti pridedama prie prieigos rakto? +includeInUserInfo.label=Pridėti prie naudotojo informacijos +includeInUserInfo.tooltip=Ar privaloma informacija turi būti pridedama prie naudotojo informacijos? +usermodel.clientRoleMapping.clientId.label=Kliento ID +usermodel.clientRoleMapping.clientId.tooltip=Kliento ID naudojamas rolių atributų susiejime +usermodel.clientRoleMapping.rolePrefix.label=Kliento rolės prefiksas +usermodel.clientRoleMapping.rolePrefix.tooltip=Prefiksas, pridedamas prieš kiekvieną kliento rolę (neprivalomas) +usermodel.realmRoleMapping.rolePrefix.label=Srities rolės prefiksas +usermodel.realmRoleMapping.rolePrefix.tooltip=Prefiksas, pridedamas prieš kiekvieną srities rolę (neprivalomas) +sectorIdentifierUri.label=Sektoriaus identifikatoriaus URI +sectorIdentifierUri.tooltip=Paslaugų teikėjai, kurie naudoja porines subreikšmes ir palaiko dinaminę klientų registraciją (Dynamic Client Registration) turėtų naudoti sector_identifier_uri parametrą. Teikiamas funkcionalumas leidžia svetainių grupėms, valdomoms centralizuotos administravimo panelės, turėti pastovias porines subreikšmes nepriklausomas nuo domeno vardų. Tokiu būdu klientai gali keisti domenų redirect_uri neperregistruojant visų naudotojų. +pairwiseSubAlgorithmSalt.label=Druska +pairwiseSubAlgorithmSalt.tooltip=Druska naudojama porinio objekto identifikatoriaus skaičiavimo metu. Jei paliekama tuščia reikšmė, tuomet druskos reikšmė bus automatikšai sugeneruota. + +# client details +clients.tooltip=Klientai - tai srities naršyklės programėlės arba tinklinės paslaugos, kuriomis pasitikima. Klientai gali jungtis prie sistemos. Klientams galima nurodyti specifines roles. +search.placeholder=Ieškoti... +create=Sukurti +import=Importuoti +client-id=Kliento ID +base-url=Pagrindinis URL +actions=Veiksmai +not-defined=Nenurodyta +edit=Redaguoti +delete=Trinti +no-results=Rezultatų nėra +no-clients-available=Nėra sukonfigūruotų klientų +add-client=Pridėti klientą +select-file=Parinkti rinkmeną +view-details=Peržiūrėti detaliau +clear-import=Išvalyti importuojamas rinkmenas +client-id.tooltip=Identifikatorius, naudojamas URI adresuose ir prieigos raktuose. Pavyzdžiui 'my-client'. SAML protokolo atveju, šią reikšmę tikimasi gauti kaip authn užklausos siuntėją +client.name.tooltip=Reikšmė, kuri rodoma naudotojams. Pavyzdžiui 'My Client'. Galimos lokalizuotos reikšmės - pavyzdžiui\: ${my_client} +client.enabled.tooltip=Klientai, kurie nėra įgalinti, negali inicijuoti prisijungimo arba gauti prieigos raktus. +consent-required=Reikalingas patvirtinimas +consent-required.tooltip=Jei įgalinta, tuomet naudotojai privalo patvirtinti, kad pageidauja prisijungti prie kliento (programos). +client-protocol=Kliento protokolas +client-protocol.tooltip='OpenID connect' leidžia klientams tikrinti galutinio naudotojo tapatybę remiantis autorizacijos serverio atlikta autentifikacija. 'SAML' įgalina žiniatinklio, įskaitant skirtingų domenų atvejus, vieningos autentifikacijos ir autorizacijos scenarijus perduodant informaciją saugiose žinutėse. +access-type=Prieigos tipas +access-type.tooltip='Konfidencialus' klientai norėdami inicijuoti prisijungimo protokolą privalo perduoti slaptą kodą. 'Viešas' klientai neprivalo perduoti slapto kodo. 'Tik nešėjas' klientai - tai tinklinės paslaugos, kurios niekada neinicijuoja prisijungimo. +standard-flow-enabled=Įgalinta standartinė seka +standard-flow-enabled.tooltip=Įgalina standartinį OpenID Connect nukreipimą, kuomet autentifikacijos metu yra perduodamas autorizacijos kodas. OpenID Connect arba OAuth2 specifikacijos terminais tai reiškia 'Authorization Code Flow' įgalinimą šiam klientui. +implicit-flow-enabled=Įgalinta išreikštinė seka +implicit-flow-enabled.tooltip=Įgalina OpenID Connect nukreipimą, kuomet autentifikacijos metu nėra perduodamas autorizacijos kodas. OpenID Connect arba OAuth2 specifikacijos terminais tai reiškia 'Implicit Flow' įgalinimą šiam klientui. +direct-access-grants-enabled=Įgalintas tiesioginės prieigos suteikimas +direct-access-grants-enabled.tooltip=Įgalina tiesioginį prieigos suteikimą, kuomet klientas turi prieigą prie naudotojo vardo ir slaptažodžio ir prieigos raktų gavimui šiais duomenimis gali tiesiogiai apsikeisti su Keycloak serveriu. OAuth2 specifikacijos terminais, šiam klientui įgalinimas 'Resource Owner Password Credentials Grant'. +service-accounts-enabled=Įgalintas paslaugos naudotojas +service-accounts-enabled.tooltip=Įgalina klientą autentifikuotis su Keycloak serveriu ir gauti dedikuotą prieigos raktą skirtą šiam klientui. OAuth2 specifikacijos terminais, tai reiškia 'Client Credentials Grant' teisę šiam klientui. +include-authnstatement=Įtraukti AuthnStatement +include-authnstatement.tooltip=Ar prisijungimo būdas ir laikas šurėtų būti įtraukiami į prisijungimo operacijos atsakymą? +sign-documents=Pasirašyti dokumentus +sign-documents.tooltip=Ar SAML dokumentai turi būtį pasirašomi šios srities? +sign-documents-redirect-enable-key-info-ext=Optimizuoti REDIRECT pasirašymo rakto paiešką +sign-documents-redirect-enable-key-info-ext.tooltip=Ar privalo būti itrauktas pasirašymo rakto ID į SAML protokolo žinutės elementą kuomet pasirašomi Keycloak REDIRECT SP sąsajos dokumentai? Tokiu būdu tikrinančioji pusė optimizuoja tikrinimo proceą naudodama tik vieną raktą vietoj to, kad bandytų visų raktų kombinacijas. +sign-assertions=Pasirašyti sprendinius +sign-assertions.tooltip=Ar SAML sprendiniai SAML dokumentuose turi būti pasirašomi? Šis nustatymas nebūtinas, kuomet naudojamas viso dokumento pasirašymas. +signature-algorithm=Parašo algoritmas +signature-algorithm.tooltip=Parašo algoritmas naudojamas dokumentų pasirašymui. +canonicalization-method=Standartizavimo metodas +canonicalization-method.tooltip=XML parašo metodas. +encrypt-assertions=Užkoduoti sprendinius +encrypt-assertions.tooltip=Ar SAML sprendiniai turi būti užkoduojami kliento viešuoju raktu naudojant AES? +client-signature-required=Privalomas kliento parašas +client-signature-required.tooltip=Ar kliento siunčiamos SAML užklausos ir atsakymai bus pasirašyti? Jei taip, tuomet ar juos privaloma tikrinti? +force-post-binding=Priverstinai naudoti POST sąryšį +force-post-binding.tooltip=Visuomet naudoti POST sąryšį siunčiant atsakymus. +front-channel-logout=Išregistravimas per naršyklę +front-channel-logout.tooltip=Jei įgalinta, tuomet atsijungimas atliekamas naršyklės nukreipimu į kliento puslapį. Kitu atveju, atsijungimas atliekamas perduodant serveris-serveris užklausą. +force-name-id-format=Priverstinai naudoti NameID formatą +force-name-id-format.tooltip=Ignoruoti NameID tapatybės identifikatoriaus formatą, naudojant administratoriaus konsolėje nurodytą formatą. +name-id-format=NameID formatas +name-id-format.tooltip=Koks tapatybės identifikatoriaus formatas turi būti naudojamas. +root-url=Šakninis URL +root-url.tooltip=Prie reliatyvių nuorodų pridedamas šakninis URL +valid-redirect-uris=Leidžiamos nukreipimo nuorodos +valid-redirect-uris.tooltip=Nukreipimo URI šablonas, kuomet naršyklei leidžiama nukreipti naudotoją po sėkmingos autentifikacijos ar atsijungimo metu. Leidžiami pakaitos simboliai, pvz. 'http://pavyzdys.lt/*'. Leidžiami reliatyvūs keliai pvz. /mano/reliatyvus/kelias/*. Reliatyvumas skaičiuojamas nuo kliento šakninio URL (jei nurodyta) arba nuo autentifikacijos serverio šakninio adreso. SAML atveju, kuomet tikimasi gavėjo paslaugos URL įtraukimo į prisijungimo užklausą, privaloma nurodyti teisingus URI šablonus. +base-url.tooltip=Numatytas URL, kuris turi būti naudojamas naudotojo nukreipimui atgal į klientą. +admin-url=Administravimo URL +admin-url.tooltip=Kliento administravimo tinklinės sąsajos URL. Įrašyti tuomet, kai klientas palaiko adapterio REST API. Šis REST API leidžia autentifikacijos serveriui perduoti atšaukimo ir kitas su administravimu susijusias taisykles. Dažniausiai šis URL sutampa su kliento pagrindiniu URL. +master-saml-processing-url=Šakninis SAML apdorojimo URL +master-saml-processing-url.tooltip=Kuomet sukonfigūruotas, šis URL bus naudojamas visoms, 'SP Assertion Consumer' ir 'Single Logout Services' užklausoms. Detalioje SAML prieigos adresų konfigūravimo skyriuje šios reikšmės gali būti atskirai pakeistos. +idp-sso-url-ref=IDP inicijuojamo SSO URL fragmento pavadinimas +idp-sso-url-ref.tooltip=Pavadinimas, kuris IDP inicijuoto SSO prisijungimo metu, perduodamas klientui per URL fragmentą. Palikus tuščią reikšmę IDP inicjuojamą SSO prisijungimo funkcionalumas išjungiamas. Šis fragmentas buv naudojamas formuojant šią nuorodą: {server-root}/realms/{realm}/protocol/saml/clients/{client-url-name} +idp-sso-relay-state=IDP inicijuotos SSO būsenos perdavimas +idp-sso-relay-state.tooltip=SSO būsenos parametro (RelayState) perdavimas kartu su IDP inicijuota SSO SAML užklausa. +web-origins=Šakninės nuorodos +web-origins.tooltip=Leidžiamos CORS nuorodos. Norėdami leisti nukreipimą į teisingas nuorodas, naudokite '+'. Norėdami leisti visas nuorodas, naudokite '*'. +fine-oidc-endpoint-conf=Detalioji OpenID prisijungimo konfigūracija +fine-oidc-endpoint-conf.tooltip=Norėdami konfigūruoti kliento sąsajos su OpenID prisijungimo protokolu išplėstines nuostatas, išskleiskite šį skyrių. +user-info-signed-response-alg=Naudotojo informacijos pasirašyto atsako algoritmas +user-info-signed-response-alg.tooltip=JWA algoritmas naudojamas pasirašyti naudotojo informacijos prieigos taško atsaką. Jei nustatyta 'unsigned', tuomet naudotojo informacijos atsakas nebus pasirašytas ir bus grąžintas application/json formatu. +request-object-signature-alg=Užklausos objekto parašo algoritmas +request-object-signature-alg.tooltip=JWA algoritmas, kurį klientas naudoja siunčiant OIDC užklausos objektą, nusakytą 'request' arba 'request_uri' parameterais. Jei nustatyta 'any', tuomet užklausos objektas gali būti nepasirašytas arba pasirašytas bet kuriuo algoritmu. +fine-saml-endpoint-conf=Detalioji SAML prieigos taškų konfigūracija +fine-saml-endpoint-conf.tooltip=Norėdami konfigūruoti sprendinių priėmimo ir vieningo atsijungimo paslaugas, išskleiskite šį skyrių. +assertion-consumer-post-binding-url=Sprendinių naudotojo paslaugos POST jungties URL +assertion-consumer-post-binding-url.tooltip=Kliento sprendinių priėmimo paslaugos (prisijungimo rezultatų) SAML POST jungties URL. Jei tokių jungčių neturite, tuomet palikite tuščias reikšmes. +assertion-consumer-redirect-binding-url=Sprendinių priėmimo paslaugos nukreipimo jungties URL +assertion-consumer-redirect-binding-url.tooltip=Kliento sprendinio priėmimo paslaugos SAML nukreipimo jungties URL (prisijungimo atsakymams). Jei tokių jungčių neturite, tuomet palikite tuščias reikšmes. +logout-service-binding-post-url=Atsijungimo paslaugos POST jungties URL +logout-service-binding-post-url.tooltip=Kliento vieningo atsijungimo SAML POST jungties URL. Jei naudojate kitas jungtis, tuomet šias reikšmes galite palikti neužpildytas. +logout-service-redir-binding-url=Atsijungimo paslaugos nukreipimo jungties URL +logout-service-redir-binding-url.tooltip=Kliento vieningo atsijungimo paslaugos SAML nukreipimo jungties. Jei naudojate kitas jungtis, tuomet šias reikšmes galite palikti neužpildytas. + +# client import +import-client=Įdiegti programos nustatymus +format-option=Formato pasirinkimas +select-format=Pasirinkite formatą +import-file=Importuoti rinkmeną + +# client tabs +settings=Nustatymai +credentials=Prisijungimo duomenys +roles=Rolės +mappers=Atributų atitikmenys +mappers.tooltip=Protokolo atributų susiejimas atlieka raktų ir dokumentų transformacijas. Naudotojo duomenys gali būti verčiami į protokolo teiginius, arba tiesiog transformuoti bet kurias užklausas perduodamas tarp kliento ir autentifikacijos serverio. +scope=Apimtis +scope.tooltip=Apimties atitikmenų parinkimas leidžia apriboti, kurios naudotojo rolės kartu su raktu bus perduodamos klientui. +sessions.tooltip=Peržiūrėti šio kliento aktyvias sesijas. Matysite šiuo metu prisijungusius naudotojus bei jų prisijungimo laikus. +offline-access=Darbas neprisijungus +offline-access.tooltip=Peržiūrėti šio kliento darbo neprisijungus rėžimo aktyvias sesijas. Matysite naudotojus, kuriems yra išduoti darbo neprisijungus raktai bei jų išdavimo laikus. Norėdami atšaukti visus šiam klientui išduotus raktus, eikite į atšaukimų kortelę ir pasirinkite 'Parinkti dabartinę datą' +clustering=Klasteriai +installation=Diegimas +installation.tooltip=Klientų konfigūravimo pagalbinė priemonė, padedanti sugeneruoti klientų adapterių konfigūracijas, kurias galima atsisiųsti, kopijuoti ar įkelti iš iškarpinės +service-account-roles=Paslaugos paskyros rolės +service-account-roles.tooltip=Dedikuotų rolių priskyrimas šios paslaugos naudotojui + +# client credentials +client-authenticator=Kliento autentifikavimo priemonės +client-authenticator.tooltip=Kliento autentifikavimo priemonės naudojamos kliento autentifikavimuisi į Keycloak serverį +certificate.tooltip=Kliento sertifikatas naudojamas kliento išduotų ir privačiu raktu pasirašytų JWT prieigos raktų tikrinimui. +publicKey.tooltip=Kliento išduotas viešasis raktas pasirašytas kliento privačiu raktu ir skirtas JWT tikrinimui. +no-client-certificate-configured=Nesukonfigūruotas nei vienas kliento sertifikatas +gen-new-keys-and-cert=Naujų raktų ir sertifikatų generavimas +import-certificate=Importuoti sertifikatą +gen-client-private-key=Generuoti kliento privatų raktą +generate-private-key=Generuoti privatų raktą +kid=Kid +kid.tooltip=Kliento viešojo rakto identifikatorius (Key ID) importuotas iš JWKS. +use-jwks-url=Naudoti JWKS URL +use-jwks-url.tooltip=Jei įgalinta, tuomet kliento viešasis raktas atsiunčiamas iš pateiktos JWKS URL. Įgalinimas suteikia lankstumo, nes klientui pergeneravus raktus jie automatiškai atsiunčiami. Jei ši nuostata išjungta, tuomet naudojamas Keycloak DB saugomas viešasis raktas (arba sertifikatas) ir klientui sugeneravus naujus raktus juos rankiniu būdu reikės importuoti į Keycloak DB. +jwks-url=JWKS URL +jwks-url.tooltip=URL, kuriuo pasiekiami kliento JWK formatu saugomi raktai. Žiūrėkite JWK specifikaciją detalesnei informacijai. Jei naudojamas kliento adapteris su "jwt" kredencialais, tuomet galite naudoti jūsų programos URL su '/k_jwks' sufiksu. Pavyzdžiui 'http://www.myhost.com/myapp/k_jwks' . +archive-format=Archyvo formatas +archive-format.tooltip=Java raktų saugykla (keystore) arba PKCS12 formato rinkmena. +key-alias=Rakto pseudonimas +key-alias.tooltip=Privataus rakto ir sertifikato rinkmenos pseudonimas. +key-password=Rakto slaptažodis +key-password.tooltip=Slaptažodžių saugykloje esančio privataus rakto slaptažodis +store-password=Saugyklos slaptažodis +store-password.tooltip=Slaptažodis, reikalingas norint atidaryti slaptažodžių saugyklą +generate-and-download=Generuoti ir atsisiųsti +client-certificate-import=Kliento sertifikato importavimas +import-client-certificate=Importuoti kliento sertifikatus +jwt-import.key-alias.tooltip=Slaptažodžių saugyklos pseudonimas +secret=Slaptas kodas +regenerate-secret=Pergeneruoti slaptą kodą +registrationAccessToken=Registracijos prieigos raktas +registrationAccessToken.regenerate=Pergeneruoti registracijos prieigos raktą +registrationAccessToken.tooltip=Registracijos prieigos raktas klientams suteikia prieigą prie klientų registracijos paslaugos +add-role=Pridėti rolę +role-name=Rolės pavadinimas +composite=Sudėtinis +description=Aprašymas +no-client-roles-available=Kliento rolės nesukonfigūruotos +scope-param-required=Privalomas taikymo srities parametras +scope-param-required.tooltip=Ši rolė suteikiama tik tuo atveju, kai taikymo srities parametras su rolės vardu panaudotas autorizacijos užklausoje ar rakte. +composite-roles=Sudėtinės rolės +composite-roles.tooltip=Visos susietos rolės bus automatiškai priskiriamos naudotojui prisikiriant šią sudėtinę rolę. +realm-roles=Srities rolės +available-roles=Galimos rolės +add-selected=Pridėti pažymėtas +associated-roles=Priskirtos rolės +composite.associated-realm-roles.tooltip=Srities apmities rolės susietos su šia sudėtine role. +composite.available-realm-roles.tooltip=Srities apmities rolės, kurias galima susieti su šia sudėtine role. +remove-selected=Pašalinti pažymėtas +client-roles=Kliento rolės +select-client-to-view-roles=Norėdami pamatyti priskirtas roles pažymėkite klientą +available-roles.tooltip=Šio kliento rolės, kurios gali būti priskiritos šiai kompozicinei rolei. +client.associated-roles.tooltip=Su šiuo klientu susietos sudėtinės rolės. +add-builtin=Pridėti numatytuosius +category=Kategorija +type=Tipas +no-mappers-available=Nėra susietų atributų +add-builtin-protocol-mappers=Pridėti numatytuosius protokolo atributų susiejimus +add-builtin-protocol-mapper=Pridėti numatytuosius protokolo atributų susiejimus +scope-mappings=atributų susiejimo taikymo sritis +full-scope-allowed=Taikymas pilna apimtimi +full-scope-allowed.tooltip=Įgalinimo atveju visi apribojimai išjungiami +scope.available-roles.tooltip=Srities lygio rolės, kurios gali būti priskiriamos šiai taikymo sričiai. +assigned-roles=Priskirtos rolės +assigned-roles.tooltip=Srities lygio rolės, kurios yra priskirtos šiai taikymo sričiai. +effective-roles=Aktyvios rolės +realm.effective-roles.tooltip=Priskirtos srities lygio rolės, kurios gali gali būti paveldėtos iš sudėtinių rolių. +select-client-roles.tooltip=Norėdami pamatyti visas roles pažymėkite klientą +assign.available-roles.tooltip=Kliento rolės, kurias galima priskirti. +client.assigned-roles.tooltip=Priskirtos kliento rolės. +client.effective-roles.tooltip=Priskirtos kliento rolės, kurios gali gali būti paveldėtos iš sudėtinių rolių. +basic-configuration=Pagrindinė konfigūracija +node-reregistration-timeout=Mazgo persiregistravimui skirtas laikas +node-reregistration-timeout.tooltip=Nurodykite maksimalų laiko intervalą, per kurį mazgai privalo iš naujo prisiregistruoti. Jei mazgas neatsiųs persiregistravimo užklausos per nurodytą laiką, tuomet šis mazgas bus išregistruojamas iš Keycloak +registered-cluster-nodes=Registruoti klasterio mazgus +register-node-manually=Registruoti mazgą rankiniu būdu +test-cluster-availability=Tikrinti ar mazgas prieinamas +last-registration=Vėliausia registracija +node-host=Mazgo serveris +no-registered-cluster-nodes=Nepriregistuotas nei vienas klasterio mazgas +cluster-nodes=Klasterio mazgai +add-node=Pridėti mazgą +active-sessions.tooltip=Šio kliento aktyvių naudotojų sesijų skaičius. +show-sessions=Rodyti sesijas +show-sessions.tooltip=Dėmesio, šis veiksmas gali ilgai užtrukti priklausomai nuo aktyvių sesijų skaičiaus. +user=Naudotojas +from-ip=Prisijungimo IP +session-start=Sesijos pradžios laikas +first-page=Pirmas puslapis +previous-page=Atgalinis puslapis +next-page=Sekantis puslapis +client-revoke.not-before.tooltip=Atšaukti visus šio kliento raktus išduotus prieš nurodytą datą. +client-revoke.push.tooltip=Kuomet nurodytas administravimo URL, taisyklė perduodama klientui. +select-a-format=Formato parinkimas +download=Atsisiųsti +offline-tokens=Darbo neprisijungus raktai +offline-tokens.tooltip=Raktų skaičius, kurie naudojami darbui neprisijungus +show-offline-tokens=Rodyti raktus +show-offline-tokens.tooltip=Dėmesio, šis veiksmas gali ilgai užtrukti priklausomai nuo aktyvių darbo neprisijungus sesijų skaičiaus. +token-issued=Rakto išdavimo laikas +last-access=Vėliausios prieigos laikas +last-refresh=Vėliausio atnaujinimo laikas +key-export=Eksportuoti raktą +key-import=Importuoti raktą +export-saml-key=Eksportuoti SAML raktą +import-saml-key=Importuoti SAML raktą +realm-certificate-alias=Srities sertifikato pseudonimas +realm-certificate-alias.tooltip=Srities sertifikato, kuris taip pat saugomas saugykloje, pseudonimas. +signing-key=Pasirašymo raktas +saml-signing-key=SAML pasirašymo raktas. +private-key=Privatus raktas +generate-new-keys=Generuoti naujus raktus +export=Eksportuoti +encryption-key=Užkodavimo raktas +saml-encryption-key.tooltip=SAML užkodavimo raktas. +service-accounts=Paslaugos naudotojo profiliai +service-account.available-roles.tooltip=Šios paslaugos paskyrai galimos priskirti srities rolės +service-account.assigned-roles.tooltip=Paslaugos paskyrai priskirtos srities rolės. +service-account-is-not-enabled-for=Kliento {{client}} paslaugos paskyra neįgalinta +create-protocol-mappers=Protokolo atitkmenų susiejimas +create-protocol-mapper=Protokolo atitkmenens susiejimas +protocol=Protokolas +protocol.tooltip=Protokolas... +id=ID +mapper.name.tooltip=Atitikmens susiejimo vardas. +mapper.consent-required.tooltip=Ar teikiant laikiną prieigą naudotojas privalo pateikti sutikimą dėl duomenų perdavimo? +consent-text=Sutikimo tekstas +consent-text.tooltip=Tekstas, kuris rodomas naudotojo sutikimo puslapyje. +mapper-type=Atitikmens tipas +mapper-type.tooltip=Atitikmens tipas +# realm identity providers +identity-providers=Tapatybės teikėjai +table-of-identity-providers=Tapatybės teikėjų sąrašas +add-provider.placeholder=Pridėti teikėją... +provider=Teikėjas +gui-order=GUI eiliškumas +first-broker-login-flow=Pirmojo prisijungimo eiga +post-broker-login-flow=Sekančių prisijungimų eiga +redirect-uri=Nukreipimo URI +redirect-uri.tooltip=Tapatybės teikėjo konfigūravimo nuoroda. +alias=Pseudonimas +display-name=Rodomas vardas +identity-provider.alias.tooltip=Pseudonimas, kuris vienareikšmiškai identifikuoja tapatybės teikėją ir yra naudojamas konstruojant nukreipimo nuorodą. +identity-provider.display-name.tooltip=Žmogui suprantamas, draugiškas tapatybės teikėjo pavadinimas. +identity-provider.enabled.tooltip=Įgalinti šį tapatybės teikėją. +authenticate-by-default=Autentifikuoti iš karto +identity-provider.authenticate-by-default.tooltip=Jei įgalinta, tuomet bus bandoma autentifikuoti naudotoją prieš parodant prisijungimo langą. +store-tokens=Saugoti raktus +identity-provider.store-tokens.tooltip=Jei įgalinta, tuomet po naudotojų prisijungimo, prieigos raktai bus išsaugoti. +stored-tokens-readable=Saugoti raktus skaitomame formate +identity-provider.stored-tokens-readable.tooltip=Jei įgalinta, tuomet naudotojai gali peržiūrėti išsaugotus prieigos raktus. Įgalinama broker.read-token rolė. +disableUserInfo=Uždrausti naudotojo informacijos prieigą +identity-provider.disableUserInfo.tooltip=Ar uždrausti prieigą prie papildomos naudotojo profilio informacijos per User Info paslaugą? Numatyta reikšmė - naudoti šią OIDC paslaugą. +userIp=Naudoti userIp parametrą +identity-provider.google-userIp.tooltip=Ar kviečiant Google naudotojo informacijos paslaugą naudoti 'userIp' užklausos parametrą? Nustačius bus naudojamas naudotojo IP adresas. Nustatymas naudingas tuo atveju, jei Google ribotų užklausų kiekš iš vieno IP adreso. +update-profile-on-first-login=Profilio duomenų atnaujinimas pirmojo prisijungimo metu +on=On +off=Off +on-missing-info=Kuomet trūksta informacijos +update-profile-on-first-login.tooltip=Nurodykite sąlygas, kuomet naudotojas privalo atnaujinti savo profilį pirmojo prisijungimo metu. +trust-email=El. paštas patikimas +trust-email.tooltip=Jei įgalintas, tuomet šio tapatybės teikėjo pateiktas el. pašto adresas laikomas patikimu ir, nepaisant bendrųjų srities nustatymų, nėra papildomai tikrinamas. +gui-order.tooltip=Eiliškumą GUI lange (pvz. Prisijungimo langas) nurodantis skaičius +first-broker-login-flow.tooltip=Autentifikacijos eigos pseudonimas, kuris bus sužadintas šio tapatybės teikėjo naudotojui prisijungus pirmą kartą. Terminas 'pirmas kartas' reiškia, kad Keycloak sistemoje nebuvo saugomas naudotojo profilis susietas su autentifikuotu šio tapatybės teikėjo naudotoju. +post-broker-login-flow.tooltip=Autentifikacijos eigos pseudonimas, kuris bus sužadintas po kiekvieno prisijungimo naudojant šį tapatybės teikėją. Naudingas tuomet, kai atlikti papildomus tikrinimus (pvz. OTP). Palikite tuščią reikšmę jei nenorite sužadinti papildomų tikrinimų autentifikatoriumi jungiantis per šį tapatybės teikėją. Turėkite omenyje, kad autentifikatoriaus realizacijos turi daryti prielaidą, kad ClientSession naudotojas yra tapatybės teikėjo nustatytas. +openid-connect-config=OpenID prisijungimo konfigūracija +openid-connect-config.tooltip=OIDC SP ir išorinio IDP konfigūracija. +authorization-url=Autorizacijos URL +authorization-url.tooltip=Autorizacijos URL adresas. +token-url=Prieigos raktų URL +token-url.tooltip=Prieigos raktų URL. +logout-url=Atsijungimo URL +identity-provider.logout-url.tooltip=Adresas, kuris turi būti naudojamas norint atjungti naudotoją nuo išorinio tapatybės teikėjo. +backchannel-logout=Foninis atjungimas +backchannel-logout.tooltip=Ar išorinis tapatybės teikėjas palaiko serveris-serveris naudotojo atjungimo būdą? +user-info-url=Naudotojo informacijos URL +user-info-url.tooltip=Naudotojo informacijos URL. Neprivalomas. +identity-provider.client-id.tooltip=Kliento identifikatorius užregistruotas tapatybės teikėjo sistemoje. +client-secret=Kliento slaptas kodas +show-secret=Rodysi slaptą kodą +hide-secret=Slėpti slaptą kodą +client-secret.tooltip=Kliento slaptas kodas užregistruotas tapatybės teikėjo sistemoje. +issuer=Išdavėjas +issuer.tooltip=Išdavėjo identifikatorius perduodamas išdavėjo atsakyme. Tikrinimas nebus atliekamas jei reikšmė tuščia. +default-scopes=Numatytosios taikymo sritys +identity-provider.default-scopes.tooltip=Taikymos sritys, kurios siunčiamos autorizavimo užklausoje. Reikšmės turi būti atskirtos tarpo simboliu. Numatyta reikšmė - 'openid'. +prompt=Raginimas +unspecified.option=nenurodyta +none.option=jokio +consent.option=sutikimo tekstas +login.option=prisijungimas +select-account.option=paskyros pasirinkimas +prompt.tooltip=Nurodo, ar autorizacijos serveris galutinių naudotojų reikalauja pakartotinai patvirtinti sutikimą ar prisijungti. +validate-signatures=Parašo tikrinimas +identity-provider.validate-signatures.tooltip=Įgalinamas išorinių IDP parašų tikrinimas. +identity-provider.use-jwks-url.tooltip=Jei įgalinta, tuomet tapatybės teikėjo viešasis raktas atsiunčiamas iš pateiktos JWKS URL. Įgalinimas suteikia lankstumo, nes tapatybės teikėjui pergeneravus raktus jie automatiškai atsiunčiami. Jei ši nuostata išjungta, tuomet naudojamas Keycloak DB saugomas viešasis raktas (arba sertifikatas) ir klientui sugeneravus naujus raktus juos rankiniu būdu reikės importuoti į Keycloak DB. +identity-provider.jwks-url.tooltip=URL, kuriuo pasiekiami tapatybės teikėjo JWK formatu saugomi raktai. Žiūrėkite JWK specifikaciją detalesnei informacijai. Jei naudojamas išorinis Keycloak tapatybės teikėjas, tuomet galite naudoti 'http://broker-keycloak:8180/auth/realms/test/protocol/openid-connect/certs' URL (pavyzdyje darome prielaida, kad Keycloak veikia 'http://broker-keycloak:8180' adresu ir naudojama 'test' sritis) +validating-public-key=Viešas raktas parašo tikrinimui +identity-provider.validating-public-key.tooltip=PEM formato viešasis raktas, kuris turi būti naudojamas išorinio IDP paraštų tikrinimui. +import-external-idp-config=Importuoti išorinio IDP konfigūraciją +import-external-idp-config.tooltip=Leidžia įkelti konfigūracinę rinkmeną arba nurodyti atsisiuntimo URL su išorinio IDP metaduomenimis. +import-from-url=Importuoti iš URL +identity-provider.import-from-url.tooltip=Importuoti metaduomenis iš nutolusio IDP aptikimo aprašo (IDP discovery descriptor). +import-from-file=Importuoti iš rinkmenos +identity-provider.import-from-file.tooltip=Importuoti metaduomenis iš rinkmenos, kurią atsisiuntėte iš IDP aptikimo aprašo (IDP discovery descriptor). +saml-config=SAML konfigūracija +identity-provider.saml-config.tooltip=SAML SP ir išoriniu IDP konfigūracija. +single-signon-service-url=Vieningo prisijungimo paslaugos URL +saml.single-signon-service-url.tooltip=Adresas, kuriuo turi būti siunčiamos autentifikacijos užklausos (SAML AuthnRequest). +single-logout-service-url=Vieningo atsijungimo paslaugos URL +saml.single-logout-service-url.tooltip=Adresas, kuriuo turi būti siunčiamos naudotojo atjungimo užklausos. +nameid-policy-format=NameID taisyklių formatas +nameid-policy-format.tooltip=Nurodykite URI nuorodą atitinkančią vardo identifikatoriaus formatą. Numatyta reikšmė urn:oasis:names:tc:SAML:2.0:nameid-format:persistent. +http-post-binding-response=Siųsti atsakymus HTTP-POST +http-post-binding-response.tooltip=Jei įgalinta, tuomet atsakymai siunčiami HTTP-POST saistymu. Kitu atveju bus naudojamas HTTP-REDIRECT. +http-post-binding-for-authn-request=Siųsti AuthnRequest HTTP-POST +http-post-binding-for-authn-request.tooltip=Jei įgalinta, tuomet AuthnRequest siunčiami HTTP-POST saistymu. Kitu atveju bus naudojamas HTTP-REDIRECT. +want-authn-requests-signed=Reikalaujami pasirašytų AuthnRequests +want-authn-requests-signed.tooltip=Nurodykite, ar tapatybės teikėjas tikisi pasirašytų AuthnRequest užklausų. +force-authentication=Priverstinė autentifikacija +identity-provider.force-authentication.tooltip=Jei įgalinta, tuomet tapatybės teikėjas privalo autentifikuoti naudotoją iš naujo nepasitikint ankstesniu prisijungimu. +validate-signature=Parašo tikrinimas +saml.validate-signature.tooltip=Įjungti/išjungti SAML atsakymų parašo tikrinimą. +validating-x509-certificate=X509 sertifikatai tikrinimui +validating-x509-certificate.tooltip=PEM formato sertifikatai, kurie turi būti naudojami parašų tikrinimui. Reikšmės skiriamos kableliais (,). +saml.import-from-url.tooltip=Importuoti metaduomenis iš nutolusio IDP SAML subjekto aprašo. +social.client-id.tooltip=Kliento identifikatorius užregistruotas tapatybės teikėjo sistemoje. +social.client-secret.tooltip=Kliento saugos kodas užregistruotas tapatybės teikėjo sistemoje. +social.default-scopes.tooltip=Autorizacijos metu siunčiamos taikymo sritys. Galimų reikšmių sąrašo, skirtuko ir numatytos reikšmės ieškokite tapatybės teikėjo sistemos dokumentacijoje.. +key=Raktas +stackoverflow.key.tooltip=Stack Overflow kliento registracijos metu gautas raktas. + +# User federation +sync-ldap-roles-to-keycloak=Sinchronizuoti LDAP roles į Keycloak +sync-keycloak-roles-to-ldap=Sinchronizuoti Keycloak roles į LDAP +sync-ldap-groups-to-keycloak=Sinchronizuoti LDAP grupes į Keycloak +sync-keycloak-groups-to-ldap=Sinchronizuoti Keycloak grupes į LDAP + +realms=Sritys +realm=Sritis + +identity-provider-mappers=Tapatybės teikėjo atitikmenų susiejimai +create-identity-provider-mapper=Sukurti tapatybės teikėjo atitikmens susiejimą +add-identity-provider-mapper=Pridėti tapatybės teikėjo atitikmens susiejimą +client.description.tooltip=Nurodomas kliento aprašas. Pavyzdžiui 'Mano laiko lentelių klientas'. Palaikomos lokalizuotos reikšmės. Pavyzdžiui\: ${my_client_description} + +expires=Galioja iki +expiration=Galiojimas +expiration.tooltip=Nurodykite kiek laiko galios prieigos raktas +count=Kiekis +count.tooltip=Nurodykite kiek klientų gali būti sukurti naudojant prieigos raktą +remainingCount=Likęs kiekis +created=Sukurta +back=Atgal +initial-access-tokens=Pradiniai prieigos raktai +initial-access-tokens.tooltip=Pradiniai prieigos raktai naudojami klientų registracijoms dinaminiu būdu. Užklausos su šiais raktais gali būti siunčiami iš bet kurio serverio. +add-initial-access-tokens=Pridėti pradinį prieigos raktą +initial-access-token=Pradinis prieigos raktas +initial-access.copyPaste.tooltip=Nukopijuokite ir įklijuokite prieigos raktą prieš išeidami iš šio puslapio. Vėliau negalėsite kopijuoti šių prieigos raktų. +continue=Tęsti +initial-access-token.confirm.title=Kopijuoti pradinius prieigos raktus +initial-access-token.confirm.text=Prašome įsitikinti, kad nusikopijavote pradinius prieigos raktus nes vėliau prie raktų nebegalėsite prieiti +no-initial-access-available=Nėra galimų pradinių prieigos rakšų + +client-reg-policies=Klientų registravimo taisyklės +client-reg-policy.name.tooltip=Taisyklės rodomas pavadinimas +anonymous-policies=Anoniminės prieigos taisyklės +anonymous-policies.tooltip=Šios taisyklės naudojamos tuomet, kai klientų registravimo paslauga iškviečiama neautentifikuota užklausa. T.y. užklausa neturi nei pradinių prieigos raktų (Initial Access Token) nei prieigos raktų (Bearer Token). +auth-policies=Autentifikuotos prieigos taisyklės +auth-policies.tooltip=Šios taisyklės naudojamos tuomet, kai klientų registravimo paslauga iškviečiama autentifikuota užklausa. T.y. užklausa turi pradinių prieigos raktų (Initial Access Token) arba prieigos raktų (Bearer Token). +policy-name=Taisyklės pavadinimas +no-client-reg-policies-configured=Nėra klientų registravimo taisyklių +trusted-hosts.label=Patikimi serveriai +trusted-hosts.tooltip=Serverių sąrašas, kuriems suteikiama teisė kviesti klientų registravimo paslaugą (Client Registration Service) ir/arba naudototi šias reikšmes klientų URI parametre (Client URI). Galima naudoti serverių vardus arba IP adresus. Jei kaip pirmas simbolis naudojamas išplečiantis simbolis (pvz '*.example.com') tuomet visas domenas 'example.com' bus patikimas. +host-sending-registration-request-must-match.label=Klientų registracijos paslaugos naudotojo serverio vardas turi sutapti +host-sending-registration-request-must-match.tooltip=Jei šgalinta, tuomet visos klientų registravimo užklausos leidžiamos tik tuo atveju, jei jos buvo išsiųstos iš to pačio patikimo serverio ar domeno. +client-uris-must-match.label=Klientų URI turi sutapti +client-uris-must-match.tooltip=Jei įgalinta, tuomet visos klientų nuorodos (nukreipimo nuorodos ir kitos) leidžiamos tik tuo atveju, jei jos sutampa su patikimu serverio vardu arba domenu. +allowed-protocol-mappers.label=Leidžiami protokolo atitikmenų parinkėjai +allowed-protocol-mappers.tooltip=Nurodykite visus leidžiamus protokolo atitikmenų parinkėjus. Jei bandoma registruoti klientą, kuris turi protokolo atitikmenų parinkėją neštrauktą š leidžiamų sąrašą, tuomet visa registracijos užklausa bus atmesta. +consent-required-for-all-mappers.label=Privalomas visų atitikmenų parinkėjų pritarimas +consent-required-for-all-mappers.label=Consent Required For Mappers +consent-required-for-all-mappers.tooltip=Jei įgalinta, tuomet visi naujai užregistruotiems protokolo parinkėjams automatiškai įgalinama consentRequired opcija. Tai reiškia, kad naudotojas privalo pateikti patvirtinimą. PASTABA: Patvirtinimo ekranas rodomas tik tiems klientams, kuriems įjungtas consentRequired nustatymas. Dažniausiai geriausia nustatyti šią nuostatą kartu su consent-required taisykle. +allowed-client-templates.label=Leidžiami klientų šablonai +allowed-client-templates.tooltip=Leidžiamų kliento šablonų sąrašas, kuriuos galima naudoti naujai registruojamiems klientams. Bandant registruoti klientą naudojant kliento šabloną, kurio nėra sąraše bus atmestas. Pradinė reikšmė - tuščias sąrašas, t.y. neleidžiamas nei vienas kliento šablonas. +max-clients.label=Mksimalus srities klientų skaičius +max-clients.tooltip=Naujų klientų registracija draudžiama, jei užregistruotų klientų skaičius yra toks pats arba didesnis nei nustatytas limitas. + +client-scopes=Klientų šablonai +client-scopes.tooltip=Klientų šablonai leidžia nurodyti bendrą visų klientų konfigūraciją + +groups=Grupės + +group.add-selected.tooltip=Grupei galimos priskirti srities rolės. +group.assigned-roles.tooltip=Su šia grupe susietos srities roles +group.effective-roles.tooltip=Visos srities susietos rolės. Šiame sąraše taip pat rodomos visos rolės, kurios priskirtos sudėtinėms rolėms. +group.available-roles.tooltip=Šio kliento galimos susieti rolės. +group.assigned-roles-client.tooltip=Susietos šio kliento rolės. +group.effective-roles-client.tooltip=Visos šio kliento susietos rolės. Šiame sąraše taip pat rodomos visos rolės, kurios priskirtos sudėtinėms rolėms. + +default-roles=Numatytosios rolės +no-realm-roles-available=Sritis neturi rolių + +users=Naudotojai +user.add-selected.tooltip=Naudotojui galimos priskirti srities rolės. +user.assigned-roles.tooltip=Su šiuo naudotoju susietos srities rolės +user.effective-roles.tooltip=Visos srities susietos rolės. Šiame sąraše taip pat rodomos visos rolės, kurios priskirtos sudėtinėms rolėms. +user.available-roles.tooltip=Šio kliento galimos susieti rolės. +user.assigned-roles-client.tooltip=Susietos šio kliento rolės. +user.effective-roles-client.tooltip=Visos šio kliento susietos rolės. Šiame sąraše taip pat rodomos visos rolės, kurios priskirtos sudėtinėms rolėms. +default.available-roles.tooltip=Galimos priskirti srities rolės. +realm-default-roles=Numatytosios srities rolės +realm-default-roles.tooltip=Srities rolės, kurios automatiškai priskiriamos naujiems naudotojams. +default.available-roles-client.tooltip=Šio kliento rolės, kurios automatiškai gali būti priskiriamos naudotojams. +client-default-roles=Numatytosios kliento rolės +client-default-roles.tooltip=Kliento rolės, kurios automatiškai priskiriamos naujiems naudotojams. +composite.available-roles.tooltip=Srities rolės, kurias galima susieti su šia sudėtine role. +composite.associated-roles.tooltip=Srities rolės, kurios susietos su šia sudėtine role. +composite.available-roles-client.tooltip=Kliento rolės, kurias galima susieti su šia sudėtine role. +composite.associated-roles-client.tooltip=Kliento rolės, kurios susietos su šia sudėtine role. +partial-import=Dalinis duomenų importavimas +partial-import.tooltip=Dalinis duomenų importavimas leidžia įkelti prieš tai eksportuotą JSON rinkmeną su naudotojais, klientais ir kitais resursais. + +file=Rinkmena +exported-json-file=Eksportuota JSON rinkmena +import-from-realm=Įkelti iš srities +import-users=Įkelti naudotojus +import-groups=Įkelti grupes +import-clients=Įkelti klientus +import-identity-providers=Įkelti tapatybės teikėjus +import-realm-roles=Įkelti srities roles +import-client-roles=Įkelti klientų roles +if-resource-exists=Jei resursas egzistuoja +fail=Nevykdyti +skip=Praleisti +overwrite=Perrašyti +if-resource-exists.tooltip=Nurodykite ką daryti kuomet bandoma įkelti jau egzistuojantį resursą. + +action=Veiksmas +role-selector=Rolių parinkimas +realm-roles.tooltip=Srities rolės, kurias galima pasirinkti. + +select-a-role=Pasirinkti rolę +select-realm-role=Pasirinkti srities rolę +client-roles.tooltip=Kliento rolės, kurias galite pažymėti. +select-client-role=Pasirinkti kliento rolę + +client-template=Kliento šablonas +client-template.tooltip=Kliento šablonas, iš kurio paveldima konfigūracija +client-saml-endpoint=Kliento SAML adresas +add-client-scope=Kliento šablono kūrimas + +manage=Valdyti +authentication=Autentifikavimas +user-federation=Naudotojų federavimas +user-storage=Naudotojų saugykla +events=Įvykiai +realm-settings=Srities nustatymai +configure=Konfigūruoti +select-realm=Pasirinkite sritį +add=Pridėti + +client-scope.name.tooltip=Kliento šablono pavadinimas. Privalo būti unikalus šioje srityje +client-scope.description.tooltip=Kliento šablono aprašymas +client-scope.protocol.tooltip=Kurio SSO protokolo konfigūracija teikia šis šablonas + +add-user-federation-provider=Pridėti naudotojų federacijos teikėja +required-settings=Privalomi nustatymai +provider-id=Teikėjo ID +console-display-name=Konsolėje rodomas pavadinimas +console-display-name.tooltip=Administravimo konsolėje rodomas teikėjo pavadinimas. +priority=Prioritetas +priority.tooltip=Skaičius nurodantis naudotojo paieškos šiame federacijos teikėjuje prioritetą. Pirmiausia imama su mažesniu skaičiumi. +sync-settings=Sinchronizuoti nustatymus +periodic-full-sync=Pilnas periodinis sinchronizavimas +periodic-full-sync.tooltip=Ar turi būti atliekamas periodinis pilnas teikėjo naudotojų sinchronizavimas į Keycloak? +full-sync-period=Pilno sinchronizavimo intervalas +full-sync-period.tooltip=Laikas sekundėmis, kas kurį atliekamas pilnas naudotojų sinchronizavimas į Keycloak sistemą +periodic-changed-users-sync=Periodinis pakeitimų sinchronizavimas +periodic-changed-users-sync.tooltip=Ar turi būti atliekamas naujai užregistruotų naudotojų ar naudotojų su redaguotais profilio duomenimis periodinis sinchronizavimas į Keycloak? +changed-users-sync-period=Periodinis sinchronizavimo intervalas +changed-users-sync-period.tooltip=Laikas sekundėmis, kas kurį atliekamas naujai užregistruotų naudotojų ar naudotojų su redaguotais profilio duomenimis sinchronizavimas į Keycloak +synchronize-changed-users=Sinchronizuoti naudotojų pakeitimus +synchronize-all-users=Sinchronizuoti visus naudotojus +kerberos-realm=Kerberos sritis +kerberos-realm.tooltip=Kerberos srities pavadinimas. Pavyzdžiui FOO.ORG +server-principal=Pagrindinis serveris +server-principal.tooltip=Pilnas HTTP paslaugai skirtas pagrindinio serverio su domenu pavadinimas. Pavyzdžiui HTTP/host.foo.org@FOO.ORG +keytab=KeyTab +keytab.tooltip=Kelias iki Kerberos KeyTab rinkmenos talpinančios prisijungimo prie pagrindinio serverio duomenis. Pavyzdžiui /etc/krb5.keytab +debug=Derinti +debug.tooltip=Ar įgalinti Krb5LoginModule veikimo pranešimų rašymą į standarinę išvestį derinimo rėžimu? +allow-password-authentication=Leisti autentifikaciją naudojant slaptažodį +allow-password-authentication.tooltip=Ar suteikti galimybę naudotojui prisijungti prie Kerberos naudojant naudotojo vardą ir slaptažodį? +edit-mode=Pakeitimų rėžimas +edit-mode.tooltip=READ_ONLY reiškia, kad naudotojui neleidžiama keisti slaptažodžio ir autentifikacija visuomet bus atliekama Kerberos. UNSYNCED reiškia, kad naudotojui leidžiama keisti slaptažodį saugomą Keycloak duomenų bazėje ir kuris bus naudojamas autentifikacijos metu vietoj Kerberos slaptažodžio. +ldap.edit-mode.tooltip=READ_ONLY reiškia, kad LDAP saugykla bus naudojama vien tik skaitymo rėžimu. WRITABLE reiškia, kad duomenys sinchronizuojami atgal į LDAP pagal poreikį. UNSYNCED reiškia, kad naudotojų duomenys bus importuoti, tačiau niekuomet nesinchronizuojami atgal į LDAP. +update-profile-first-login=Pirmojo prisijungimo metu atnaujinti duomenis +update-profile-first-login.tooltip=Pirmojo prisijungimo metu atnaujinti naudotojo profilio duomenis +sync-registrations=Sinchronizuoti registracijas +ldap.sync-registrations.tooltip=Ar naujai užsiregistravę naudotojai turėtų būti sinchonizuojami į LDAP saugyklą? Federavimo teikėjas, į kurį sinchronizuojami nauji naudotojai, parenkamas pagal prioritetą. Pirmiausia imami su mažiausiu skaičiumi. +vendor=Gamintojas +ldap.vendor.tooltip=LDAP gamintojas (teikėjas) +username-ldap-attribute=Prisijungimo vardo LDAP atributas +ldap-attribute-name-for-username=LDAP atributo pavadinimas, kuriame saugomas naudotojo prisijungimo vardas +username-ldap-attribute.tooltip=LDAP atributas, kuris turi būti susietas su Keycloak naudotojo prisijungimo vardu. Su daugeliu LDAP serverių gali būti naudojamas 'uid' atributas. ActiveDirectory gali būti 'sAMAccountName' arba 'cn'. Reikalaujama, kad nurodytas LDAP atributas būtų užpildytas visiems naudotojams kurie importuojami iš LDAP į Keycloak. +rdn-ldap-attribute=RDN LDAP atributas +ldap-attribute-name-for-user-rdn=LDAP atributo pavadinimas, kuriame saugomas naudotojo RDN +rdn-ldap-attribute.tooltip=LDAP atributas, kuris naudojamas kaip RDN (Relative Distinguished Name) vietoj tipinio naudotojo DN (Distinguished Name). Dažniausiai reikšmė sutampa su prisijungimo vardo LDAP atributu, tačiau pastarasis nėra privalomas. Pavyzdžiui ActiveDirectory dažniausiai kaip RDN atributas naudojamas 'cn' nors prisijungimo vardo atributas būna 'sAMAccountName'. +uuid-ldap-attribute=UUID LDAP atributas +ldap-attribute-name-for-uuid=LDAP atributo pavadinimas, kuriame saugomas UUID +uuid-ldap-attribute.tooltip=LDAP atributas, kuris naudojamas kaip unikalus LDAP objektų identifikatorius (UUID). Daugelis LDAP serverių naudoja 'entryUUID', tačiau pasitaiko ir išimčių. Pavyzdžiui ActiveDirectory naudojamas 'objectGUID' atributas. Jei jūsų LDAP serveris nepalaiko UUID atributų, tuomet galite naudoti bet kurį kitą atributą kuris užtikrina LDAP naudotojų unikalumą. Pavyzdžiui 'uid' arba 'entryDN'. +user-object-classes=Naudotojų objektų klasės +ldap-user-object-classes.placeholder=LDAP naudotojų objektų klasės (skiriamos kableliu) +ldap.user-object-classes.tooltip=LDAP atributo objectClass atskirtos kableliu reikšmės skirtos LDAP naudotojo objektui. Pavyzdžiui: 'inetOrgPerson, organizationalPerson' . Naujai registruoti Keycloak naudotojai bus įrašyti š LDAP su visomis nurodytomis objektų klasėmis. Egzistuojantys LDAP naudotojų objektai randami tik tuomet, kai jie turi visas šias nurodytas objekto klases. + +ldap-connection-url=LDAP jungties URL +ldap-users-dn=LDAP naudotojų DN +ldap-bind-dn=LDAP prisijungimo DN +ldap-bind-credentials=LDAP prisijungimo slaptažodis +ldap-filter=LDAP filtras + +connection-url=Jungties URL +ldap.connection-url.tooltip=Jungties į LDAP serverį URL +test-connection=Tikrinti jungtį +users-dn=Naudotojų DN +ldap.users-dn.tooltip=Šakninė LDAP medžio DN (Distinguished Name) kuriame saugomi naudotojai. Jei pavyzdžiui tipinio naudotojo DN yra 'uid=john,ou=users,dc=example,dc=com' tuomet šio atributo reikšmė turėtų būti 'ou=users,dc=example,dc=com' +authentication-type=Autentifikacijos tipas +ldap.authentication-type.tooltip=LDAP autentifikacijos tipas. Galimi 'none' (anoniminė LDAP prieiga) arba 'simple' (Prisijungimo DN + slaptažodis autentifikacijai) autentifikacijos būdai +bind-dn=Prisijungimo DN +ldap.bind-dn.tooltip=LDAP administratoriaus DN (Distinguished Name), kuris turi būti naudojamas Keycloak prieiti prie LDAP serverio +bind-credential=Prisijungimo slaptažodis +ldap.bind-credential.tooltip=LDAP administratoriaus slaptažodis +test-authentication=Tikrinti autentifikaciją +custom-user-ldap-filter=Papildomas naudotojų LDAP filtras +ldap.custom-user-ldap-filter.tooltip=Papildomas LDAP filtras, kuris turi būti naudojamas surastų naudotojų nufiltravimui. Palikite tuščią lauką jei papildomas filtravimas nereikalingas. Įsitikinkite, kad filtras prasideda '(' ir baigiasi ')' simboliais +search-scope=Paieškos apimtis +ldap.search-scope.tooltip=Jei pasirinkta vieno lygio paieška, tuomet naudotojų ieškoma vien tik nurodytame naudotojų DN. Kai pasirinkta paieška medyje, tuomet naudotojų ieškoma visose medžio šakose. Išsamesnės informacijos ieškokite LDAP dokumentaciją +use-truststore-spi=Naudoti raktų saugyklos SPI +ldap.use-truststore-spi.tooltip=Nurodykite, kuomet LDAP jungtis naudos standalone.xml/domain.xml sukonfigūruotą patikimų liudijimų/raktų saugyklos SPI. 'Visada' reiškia, kad bus naudojama visada. 'Niekada' reiškia, kad sukonfigūruota liudijimų saugykla nebus naudojama. 'Tik LDAP' reiškia, kad saugykla bus naudojama tik su LDAP jungtimis. Pastaba: jei standalone.xml/domain.xml nesukonfigūruotas, tuomet bus naudojama standartinė Java cacerts arba 'javax.net.ssl.trustStore' parametre nurodyta liudijimų saugykla. +connection-pooling=Jungčių buferizavimas +ldap.connection-pooling.tooltip=Ar Keycloak turėtų naudoti jungčių telkinį jungiantis prie LDAP serverio? +ldap.pagination.tooltip=Ar LDAP serveris palaiko puslapiavimą? +kerberos-integration=Kerberos intergacija +allow-kerberos-authentication=Leisti Kerberos autentifikaciją +ldap.allow-kerberos-authentication.tooltip=Įgalina HTTP naudotojų autentifikaciją naudojant SPNEGO/Kerberos raktus. Duomenys apie prisijungusį naudotoją bus teikiama šio LDAP serverio +use-kerberos-for-password-authentication=Naudoti Kerberos autentifikacijai su slaptažodžiu +ldap.use-kerberos-for-password-authentication.tooltip=Ar jungiantis su naudotojo vardu ir slaptažodžiu naudoti Kerberos serverį vietoj LDAP serverio Directory Service API +batch-size=Paketo dydis +ldap.batch-size.tooltip=Vienos tranzacijos metu į Keycloak importuojamų LDAP naudotojų skaičius. +ldap.periodic-full-sync.tooltip=Ar įgalinti periodinę pilną LDAP naudotojų sinchronizaciją į Keycloak? +ldap.periodic-changed-users-sync.tooltip=Ar įgalinti periodinę naujai registruotų arba su pakeistais duomenimis LDAP naudotojų sinchronizaciją į Keycloak? +ldap.changed-users-sync-period.tooltip=Intervalas sekundėmis, kas kurį atliekamas periodinis naujai registruotų arba su pakeistais duomenimis LDAP naudotojų sinchronizavimas į Keycloak +user-federation-mappers=Federuoto naudotojo atributų atitikmenys +create-user-federation-mapper=Sukurti federuoto naudotojo atributo atitikmenį +add-user-federation-mapper=Pridėti federuoto naudotojo atributo atitikmenį +provider-name=Teikėjo pavadinimas +no-user-federation-providers-configured=Nesukonfigūruotas nei vienas naudotojų federacijos teikėjas +no-user-storage-providers-configured=Nesukonfigūruota nei viena naudotojų saugykla +add-identity-provider=Pridėti tapatybės teikėją +add-identity-provider-link=Pridėti sąsają su tapatybės teikėju +identity-provider=Tapatybės teikėjas +identity-provider-user-id=Tapatybės teikėjo naudotojo ID +identity-provider-user-id.tooltip=Unikalus, tapatybės teikėjo saugomas, naudotojo ID +identity-provider-username=Tapatybės teikėjo naudotojo vardas +identity-provider-username.tooltip=Tapatybės teikėjo sistemoje saugomas naudotojo vardas +pagination=Puslapiavimas + +browser-flow=Autentifikacijos seka +browser-flow.tooltip=Pasirinkite autentifikacijos naršyklėje seką +registration-flow=Registracijos seka +registration-flow.tooltip=Pasirinkite registracijos naršyklėje seką. +direct-grant-flow=Tiesioginių teisių seka +direct-grant-flow.tooltip=Pasirinkite tiesioginių teisių seką (direct grant authentication). +reset-credentials=Prisijungimo duomenų atkūrimo seka +reset-credentials.tooltip=Pasirinkite prisijungimo duomenų priminimo naršyklėje seką +client-authentication=Klientų autentifikacijos seka +client-authentication.tooltip=Pasirinkite klientų autentifikacijos seką. +new=Naujas +copy=Kopijuoti +add-execution=Pridėti išimtį +add-flow=Pridėti seką +auth-type=Autentifikacijos tipas +requirement=Privalomumas +config=Konfigūruoti +no-executions-available=Nėra sukonfigūruotų išimčių +authentication-flows=Autentifikacijos sekos +create-authenticator-config=Sukurti autentifikatoriaus konfigūraciją +authenticator.alias.tooltip=Konfigūracijos pavadinimas +otp-type=OTP tipas +time-based=Paremtas laiku +counter-based=Paremtas skaitliuku +otp-type.tooltip='totp' paremtas ribotą laiką galiojančiu vienkartiniu slaptažodžiu. 'hotp' - ribotą kartų galiojančiu vienkartiniu slaptažodžiu. +otp-hash-algorithm=OTP maišos algoritmas +otp-hash-algorithm.tooltip=Kuris maišos algoritmas turi būti naudojamas OTP generavimui. +number-of-digits=Skaitmenų skaičius +otp.number-of-digits.tooltip=Kiek OTP turėtų turėti skaitmenų? +look-ahead-window=Neatitikimo langas +otp.look-ahead-window.tooltip=Koks intervalas yra leidžiamas tuo atveju, kai prieigos raktų generatoriaus ir serverio laikai arba skaitliukai nesutampa. +initial-counter=Pradinė skaitliuko reikšmė +otp.initial-counter.tooltip=Kokia turi būti pradinė skaitliuko reikšmė? +otp-token-period=OTP rakto galiojimo intervalas +otp-token-period.tooltip=Kiek sekundžiu galios OTP prieigos raktas? Numatyta reikšmė 30 sekundžių. +table-of-password-policies=Slaptažodžio taisyklių lentelė +add-policy.placeholder=Pridėti taisyklę... +policy-type=Taisyklės tipas +policy-value=Taisyklės reikšmė +admin-events=Administravimo įvykiai +admin-events.tooltip=Rodomi srities administravimo įvykiai susiję su administratoriaus paskyra, pvz. srities kūrimas. Pasirinkite konfigūravimo skiltį norėdami kad įvykiai būtų saugomi. +login-events=Prisijungimo įvykiai +filter=Filtruoti +update=Atnaujinti +reset=Išvalyti +resource-types=Resurso tipas +operation-types=Veiksmas +select-operations.placeholder=Pasirinkite veiksmus... +resource-path=Resurso kelias +resource-path.tooltip=Filtravimas pagal resurso kelią. Palaikomas pakaitos simbolis '*' atitinkantis vieną kelio elementą ir '**' daugiau nei vieną elementą. Pavyzdžiui 'realms/*/clients/asbc' visose sritise randa klientą su identifikatoriumi 'asbc'. Kitas pavyzdys 'realms/master/**' randa visus veiksmus 'master' srityje. +date-(from)=Data (Nuo) +date-(to)=Data (Iki) +authentication-details=Autentifikacijos informacija +ip-address=IP adresas +time=Laikas +operation-type=Veiksmo tipas +auth=Autentifikacijos informacija +representation=Reprezentacija +register=Registracijos +required-action=Privalomi veiksmai +default-action=Numatytas veiksmas +auth.default-action.tooltip=Jei įgalintas, tuomet visi nauji naudotojai privalės atlikti pažymėtus veiksmus. +no-required-actions-configured=Nėra nei vieno sukonfigūruoto privalomo veiksmo +defaults-to-id=Nenurodžius bus naudojamas identifikatorius +flows=Sekos +bindings=Sąryšiai +required-actions=Privalomi veiksmai +password-policy=Slaptažodžių taisyklės +otp-policy=OTP taisyklės +user-groups=Naudotojų grupės +default-groups=Numatytos grupės +groups.default-groups.tooltip=Nurodykite grupes, į kurias automatiškai įtraukiami nauji naudotojai. +cut=Iškirpti +paste=Įklijuoti + +create-group=Sukurti grupę +create-authenticator-execution=Sukurti autentifikatoriaus veiksmo vykdymą +create-form-action-execution=Sukurti formos veiksmo vykdymą +create-top-level-form=Sukurti aukščiausio lygio formą +flow.alias.tooltip=Įrašykite sekos rodomą pavadinimą. +top-level-flow-type=Aukščiausio lygio sekos tipas +flow.generic=generic +flow.client=client +top-level-flow-type.tooltip=Kokio tipo ši aukščiausio lygio sritis? 'client' tipas naudojamas klientų (programų) autentifikacijai. 'generic' naudojamas visais kitais atvejais. +create-execution-flow=Sukurti vykdymo seką +flow-type=Sekos tipas +flow.form.type=form +flow-type.tooltip=Kokios rūšies ši forma? +form-provider=Formos teikėjas +default-groups.tooltip=Naujai sukurti ar užregistruoti naudotojai automatiškai priskiriami šioms grupėms +select-a-type.placeholder=pasirinkite tipą +available-groups=Galimos grupės +available-groups.tooltip=Nurodykite grupę, kuri bus numatytoji. +value=Reikšmė +table-of-group-members=Grupės narių lentelė +last-name=Pavardė +first-name=Vardas +email=El. paštas +toggle-navigation=Perjungti navigaciją +manage-account=Valdyti paskyrą +sign-out=Atsijungti +server-info=Serverio informacija +resource-not-found=Resuras nerastas... +resource-not-found.instruction=Negalime rasti jūsų ieškomo resurso. Įsitikinkite, kad įvedėte teisingą URL. +go-to-the-home-page=Eiti į pradinį puslapį » +page-not-found=Puslapis nerastas... +page-not-found.instruction=Negalime rasti jūsų ieškomo puslapio. Įsitikinkite, kad įvedėte teisingą URL. +events.tooltip=Rodomi srities išsaugoti įvykiai. Rodomi įvykiai susiję su naudotojų paskyromis, pavyzdžiui naudotojo prisijungimas. Norėdami keisti nustatymus pasirinkite 'Konfigūruoti' +select-event-types.placeholder=Pasirinkite įvykiu tipus... +events-config.tooltip=Rodoma naudotojų ir administravimo įvykių konfigūracija. +select-an-action.placeholder=Pasirinkite veiksmą... +event-listeners.tooltip=Nurodykite srities įvykių gavėjus. +login.save-events.tooltip=Jei įgalinta, tuomet su prisijungimu susiję veiksmai saugomi duomenų bazėje ir tampa prieinami per administravimo bei naudotojo paskyros valdymo skydus. +clear-events.tooltip=Ištrinti visus įvykius iš duomenų bazės. +events.expiration.tooltip=Nustato įvykių galiojimo laiką. Nebegaliojantys įvykiai periodiškai ištrinami iš duomenų bazės. +admin-events-settings=Administravimo veiksmų nustatymai +save-events=Saugoti įvykius +admin.save-events.tooltip=Jei įgalinta, tuomet administravimo veiksmai saugomi duomenų bazėje ir tampa prieinami per administravimo valdymo skydą. +saved-types.tooltip=Nurodykite veiksmų tipus, kurie turėtų būti išsaugoti. +include-representation=Išsaugoti reprezentaciją +include-representation.tooltip=Išsaugoti kurūmo ir redagavimo užklausų JSON reprezentaciją. +clear-admin-events.tooltip=Ištrina visus su administravimu susijusius veiksmus iš duomenų bazės. +server-version=Serverio versija +server-profile=Serverio profilis +info=Informacija +providers=Teikėjai +server-time=Serverio laikas +server-uptime=Serverio veikimo laikas +memory=Atmintis +total-memory=Viso atminties +free-memory=Laisva atmintis +used-memory=Naudojama atmintis +system=Sistema +current-working-directory=Darbinis katalogas +java-version=Java Version +java-vendor=Java Vendor +java-runtime=Java Runtime +java-vm=Java VM +java-vm-version=Java VM Version +java-home=Java Home +user-name=User Name +user-timezone=User Timezone +user-locale=User Locale +system-encoding=System Encoding +operating-system=Operating System +os-architecture=OS Architecture +spi=SPI +granted-roles=Suteiktos rolės +granted-protocol-mappers=Suteiktos protokolo atitikmenų sąsajos +additional-grants=Papildomai suteikta +consent-created-date=Sukurta +consent-last-updated-date=Pask. kartą atnaujinta +revoke=Atšaukti +new-password=Naujas slaptažodis +password-confirmation=Pakartotas slaptažodis +reset-password=Pakeisti slaptažodį +credentials.temporary.tooltip=Jei įgalinta, tuomet naudotojas privalės pasikeisti slaptažodį sekančio prisijungimo metu +remove-totp=Šalinti OTP +credentials.remove-totp.tooltip=Šalinti vienkartinį naudotojo slaptažodžių generatorių. +reset-actions=Atkurti veiksmus +credentials.reset-actions.tooltip=Nurodykite naudotojui el. paštu siunčiamus privalomus atlikti veiksmus. 'Patvirtinti el. pašto adresą' į naudotojo el. pašto adresą siunčia patvirtinimo nuorodą. 'Atnaujinti profilio informaciją' reikalauja naudotojo peržiūrėti ir atnaujinti profilio informaciją. 'Atnaujinti slaptažodį' reikalauja naudotojo pasikeisti slaptažodį. 'Konfigūruoti OTP' reikalauja atnaujinti mobilaus slaptažodžių generatoriaus konfigūraciją. +reset-actions-email=Atkūrimo veiksmų siuntimas +send-email=Siųsti el. pašto laišką +credentials.reset-actions-email.tooltip=Naudotojui siunčiamas el. pašto laiškas su nuorodomis leidžiančiomis atlikti pasirinktus veiksmus. Naudotojas atidaręs siunčiamą nuorodą galės atlikti atkūrimo veiksmus. Veismų atlikimui naudotojų nebus reikalaujama prisijungti. Pavyzdžiui parinkus slaptažodžio atkūrimo veiksmą, naudotojas galės neprisijungęs nurodyti naują slaptaždį. +add-user=Pridėti naudotoją +created-at=Sukūrimo data +user-enabled=Naudotojas įgalintas +user-enabled.tooltip=Neįgalintam naudotojai neleidžiama prisijungti prie sistemos. +user-temporarily-locked=Naudotojas laikinai užrakintas +user-temporarily-locked.tooltip=Naudotojas laikintai užrakintas, nes per daug klydo prisijungiant prie sistemos. +unlock-user=Atrakinti naudotoją +federation-link=Federacijos sąsaja +email-verified=El. paštas patvirtintas +email-verified.tooltip=Ar naudotojo el. pašto adresas yra patvirtintas? +required-user-actions=Privalomi veiksmai naudotojui +required-user-actions.tooltip=Nurodykite kuriuos veiksmus po prisijungimo naudotojas privalo atlikti. 'Patvirtinti el. pašto adresą' į naudotojo el. pašto adresą siunčia patvirtinimo nuorodą. 'Atnaujinti profilio informaciją' reikalauja naudotojo peržiūrėti ir atnaujinti profilio informaciją. 'Atnaujinti slaptažodį' reikalauja naudotojo pasikeisti slaptažodį. 'Konfigūruoti OTP' reikalauja atnaujinti mobilaus slaptažodžių generatoriaus konfigūraciją. +locale=Lokalė +select-one.placeholder=Pasirinkite... +impersonate=Įkūnyti +impersonate-user=Įkūnyti naudotoją +impersonate-user.tooltip=Prisijungti kaip šis naudotojas. Jei jūsų sritis sutampa su naudotojo sritimi, tuomet jūsų sesija bus baigta prieš prisijungiant šiuo naudotoju. +identity-provider-alias=Tapatybės teikėjo pseudonimas +provider-user-id=Teikėjo naudotojo ID +provider-username=Teikėjo naudotojo vardas +no-identity-provider-links-available=Nėra nei vienos tapatybės teikėjo sąsajos +group-membership=Narystė grupėse +group-membership.tooltip=Visos grupės, kurių narys yra šis naudotojas. Pažymėkite grupę ir paspauskite 'Palikti' norėdami pašalinti naudotoją iš grupės. +leave=Palikti +membership.available-groups.tooltip=Grupės, į kurias galima įtraukti naudotoją. Pažymėkite grupę ir paspauskite įtraukti. +table-of-realm-users=Srities naudotojų sąrašas +view-all-users=Rodyti visus naudotojus +unlock-users=Atrakinti naudotojus +no-users-available=Naudotojų nėra +users.instruction=Įveskite paieškos kriterijų arba paspauskite rodyti visus naudotojus +consents=Sutikimai +started=Pradėta +logout-all-sessions=Atjungti visas sesijas +logout=Seanso pabaiga +new-name=Naujas pavadinimas +ok=Gerai +attributes=Atributai +role-mappings=Rolių susiejimas +members=Nariai +details=Detaliau +identity-provider-links=Sąsajos su tapatybės teikėjais +register-required-action=Registruoti privalomą atlikti veiksmą +gender=Lytis +address=Adresas +phone=Telefonas +profile-url=Profilio URL +picture-url=Nuotraukos URL +website=Internetinė svetainė +import-keys-and-cert=Importuoti raktus ir sertifikatus +import-keys-and-cert.tooltip=Įkelti kliento raktų porą ir sertifikatą. +upload-keys=Įkelti raktus +download-keys-and-cert=Atsisiųsti raktus ir sertifikatą +no-value-assigned.placeholder=Nėra priskirtos reikšmės +remove=Šalinti +no-group-members=Grupė neturi narių +temporary=Laikinas +join=Prijungti +event-type=Įvykio tipas +events-config=Įvykių konfigūracija +event-listeners=Įvykių gavėjai +login-events-settings=Prisijungimo įvykių nustatymai +clear-events=Išvalyti įvykius +saved-types=Saugomi tipai +clear-admin-events=Išvalyti administravimo įvykius +clear-changes=Išvalyti pasikeitimus +error=Klaida + +# Authz +# Authz Common +authz-authorization=Autorizacija +authz-owner=Savininkas +authz-uri=URI +authz-scopes=Taikymo sritys +authz-resource=Resursas +authz-resource-type=Resurso tipas +authz-resources=Resursai +authz-scope=Taikymo sritis +authz-authz-scopes=Autorizacijos taikymo sritys +authz-policies=Taisyklės +authz-permissions=Leidimai +authz-evaluate=Išbandyti +authz-icon-uri=Ikonos URI +authz-icon-uri.tooltip=Ikonos paveiksliuko URI. +authz-select-scope=Parinkite taikymo sritį +authz-select-resource=Parinkite resursą +authz-associated-policies=Susietos taisyklės +authz-any-resource=Bet kuris resursas +authz-any-scope=Bet kuri taikymo sritis +authz-any-role=Bet kuri rolė +authz-policy-evaluation=Išbandyti taisyklę +authz-select-client=Parinkite klientą +authz-select-user=Parinkite naudotoją +authz-entitlements=Teisės +authz-no-resources=Resursų nėra +authz-result=Rezultatas +authz-authorization-services-enabled=Įgalinti autorizaciją +authz-authorization-services-enabled.tooltip=Įgalinti detalų kliento autorizacijos palaikymą +authz-required=Privalomas + +# Authz Settings +authz-import-config.tooltip=Importuoti šio resursų serverio autorizacijos nustatymų JSON rinkmeną. + +authz-policy-enforcement-mode=Taisyklių vykdymo rėžimas +authz-policy-enforcement-mode.tooltip=Taisyklių vykdymo rėžimas nusako kaip turi būti tenkinamos autorizacijos užklausų taisyklės. 'Taikyti' reiškia, kad tuo atveju kai nėra sukonfigūruota nei viena su resursu susijusi taisyklė, prieiga draudžiama. 'Liberalus' reiškia, kad tuo atveju kai nėra sukonfigūruota nei viena su resursu susijusi taisyklė, prieiga leidžiama. 'Išjungta' reiškia, kad neatliekamas taisyklių tikrinimas ir prieiga leidžiama prie visų resursų. +authz-policy-enforcement-mode-enforcing=Taikyti +authz-policy-enforcement-mode-permissive=Liberalus +authz-policy-enforcement-mode-disabled=Išjungta + +authz-remote-resource-management=Nuotolinis resursų valdymas +authz-remote-resource-management.tooltip=Ar leidžiama nuotoliniu būdu resursų serveriui valdyti resursus? Jei neįgalinta, tuomet resursai gali būti valdomi tik per šią administravimo konsolę. + +authz-export-settings=Eksportuoti nustatymus +authz-export-settings.tooltip=Eksportuoti ir atsisiųsti visus šio resursų serverio autorazacijos nustatymus. + +# Authz Resource List +authz-no-resources-available=Nėra galimų resursų. +authz-no-scopes-assigned=Nėra susietų taikymo sričių. +authz-no-type-defined=Nėra nurodytų tipų. +authz-no-permission-assigned=Nera susietų leidimų. +authz-no-policy-assigned=Nėra susietų taisyklių. +authz-create-permission=Sukurti leidimą + +# Authz Resource Detail +authz-add-resource=Pridėti resursą +authz-resource-name.tooltip=Unikalus resurso vardas. Vardas turi unikaliai identifikuoti resursą. Naudingas, kuomet ieškoma specifinių resursų. +authz-resource-owner.tooltip=Šio resurso savininkas. +authz-resource-type.tooltip=Šio resurso tipas. Reikšmė leidžia sugrupuoti skirtingus resursus turinčius tą patį tipą. +authz-resource-uri.tooltip=URI kuris taip pat gali būti naudojamas vienareikšmiškam resurso identifikavimui. +authz-resource-scopes.tooltip=Su šiuo resursu susietos taikymo sritys. + +# Authz Scope List +authz-add-scope=Priėti taikymo sritį +authz-no-scopes-available=Nėra galimų taikymo sričių. + +# Authz Scope Detail +authz-scope-name.tooltip=Unikalus taikymo srities pavadinimas. Šis pavadinimas gali vienareikšmiškai identifikuoti taikymo sritį. Naudingas kuomet ieškoma šios tam tikros srities. + +# Authz Policy List +authz-all-types=Visi tipai +authz-create-policy=Sukurti taisyklę +authz-no-policies-available=Nėra galimų taisyklių. + +# Authz Policy Detail +authz-policy-name.tooltip=Šios taisyklės pavadinimas. +authz-policy-description.tooltip=Šios taisyklės aprašymas. +authz-policy-logic=Logika +authz-policy-logic-positive=Teigiama +authz-policy-logic-negative=Neigiama +authz-policy-logic.tooltip=Logika nurodo kaip turi būti tenkinama taisyklė. Jei nurodyta 'Teigiama', tuomet šios taisyklės vykdymo metu gautas rezultatas (leisti arba drausti) bus naudojamas sprendinio priėmimui. Jei nurodyta 'Neigiama', tuomet šios taisyklės vykdymo rezultatas bus paneigtas, t.y. leidžiama taps draudžiama ir atvirkščiai. +authz-policy-apply-policy=Pritaikyti taisyklę +authz-policy-apply-policy.tooltip=Nurodo visas taisykles, kurios turi būti įvertintos šios taisyklės ar leidimo taikymo sričiai. +authz-policy-decision-strategy=Sprendimo strategija +authz-policy-decision-strategy.tooltip=Sprendimo strategija nurodo kaip priimamas galutinis sprendimas, kuomet yra vykdomos visos šio leidimo taisyklės. 'Pozityvi' reiškia, kad galutiniam teigiamam sprendimui turi būti tenkinama bent viena taisyklė. 'Vienbalsė' reiškia, kad galutiniam teigiamam sprendimui visos taisyklės turi būti teigiamos. 'Daugumos' reiškia, kad galutinis teigiamas sprendimas bus priimtas tuomet, kai teigiamų taisyklių bus daugiau nei neigiamų. Jei teigiamų ir neigiamų taisyklių skaičius yra vienodas, tuomet galutinis rezultatas bus neigiamas. +authz-policy-decision-strategy-affirmative=Pozityvi +authz-policy-decision-strategy-unanimous=Vienbalsė +authz-policy-decision-strategy-consensus=Daugumos +authz-select-a-policy=Parinkite taisyklę + +# Authz Role Policy Detail +authz-add-role-policy=Pridėti rolės taisyklę +authz-no-roles-assigned=Nėra susietų rolių. +authz-policy-role-realm-roles.tooltip=Nurodo kurios *srities* rolė(s) tenkina šią taisyklę. +authz-policy-role-clients.tooltip=Parinkite klieną norėdami rodyti tik šio kliento roles. +authz-policy-role-client-roles.tooltip=Nurodo *kliento* rolė(įs) kurios tenkina šią taisyklę. + +# Authz User Policy Detail +authz-add-user-policy=Pridėti naudotojo taisyklę +authz-no-users-assigned=Nėra susietų naudotojų. +authz-policy-user-users.tooltip=Nurodo kurie naudotojai tenkina šią taisyklę. + +# Authz Time Policy Detail +authz-add-time-policy=Pridėti laiko taisyklę +authz-policy-time-not-before.tooltip=Nurodykite laiką iki kurio ši taisyklė NETENKINAMA. Teigiamas rezultatas duodamas tik tuo atveju, kuomet dabartinė data ir laikas yra vėlesnė arba lygi šiai reikšmei. +authz-policy-time-not-on-after=Ne vėliau +authz-policy-time-not-on-after.tooltip=Nurodykite laiką po kurio ši taisyklė NETENKINAMA. Teigiamas rezultatas duodamas tik tuo atveju, kuomet dabartinė data ir laikas yra ankstesni arba lygi šiai reikšmei. +authz-policy-time-day-month=Mėnesio diena +authz-policy-time-day-month.tooltip=Nurodykite mėnesio dieną iki kurios ši taisyklė TENKINAMA. Užpildžius antrąjį laukelį, taisyklė bus TENKINAMA jei diena patenka į nurodytą intervalą. Reikšmės nurodomos imtinai. +authz-policy-time-month=Mėnesis +authz-policy-time-month.tooltip=Nurodykite mėnesį iki kurio ši taisyklė TENKINAMA. Užpildžius antrąjį laukelį, taisyklė bus TENKINAMA jei mėnesis patenka į nurodytą intervalą. Reikšmės nurodomos imtinai. +authz-policy-time-year=Metai +authz-policy-time-year.tooltip=Nurodykite metus iki kurių ši taisyklė TENKINAMA. Užpildžius antrąjį laukelį, taisyklė bus TENKINAMA jei metai patenka į nurodytą intervalą. Reikšmės nurodomos imtinai. +authz-policy-time-hour=Valanda +authz-policy-time-hour.tooltip=Nurodykite valandą iki kurios ši taisyklė TENKINAMA. Užpildžius antrąjį laukelį, taisyklė bus TENKINAMA jei valanda patenka į nurodytą intervalą. Reikšmės nurodomos imtinai. +authz-policy-time-minute=Minutė +authz-policy-time-minute.tooltip=Nurodykite minutę iki kurios ši taisyklė TENKINAMA. Užpildžius antrąjį laukelį, taisyklė bus TENKINAMA jei minutė patenka į nurodytą intervalą. Reikšmės nurodomos imtinai. + +# Authz JS Policy Detail +authz-add-js-policy=Pridėti JavaScript taisyklę +authz-policy-js-code=Programinis kodas +authz-policy-js-code.tooltip=JavaScript kodas kuriame aprašytos šios taisyklės sąlygos. + + +# Authz Aggregated Policy Detail +authz-aggregated=Agreguota +authz-add-aggregated-policy=Pridėti agreguotą taisyklę + +# Authz Permission List +authz-no-permissions-available=Nėra galimų leidimų. + +# Authz Permission Detail +authz-permission-name.tooltip=Šio leidimo pavadinimas. +authz-permission-description.tooltip=Šio leidimo aprašymas. + +# Authz Resource Permission Detail +authz-add-resource-permission=Pridėti resurso leidimą +authz-permission-resource-apply-to-resource-type=Pritaikyti resurso tipui +authz-permission-resource-apply-to-resource-type.tooltip=Nurodykite ar šis leidimas turi būti pritaikomas visiems šio tipo resursams. Jei įgalinta, tuomet leidimo tikrinimas bus atliekamas visiems nurodyto tipo resursams. +authz-permission-resource-resource.tooltip=Nurodykite, kad šis leidimas turi būti taikomas tik tam tikriems resursams. +authz-permission-resource-type.tooltip=Nurodykite, kad ši taisyklė turi būti taikoma visiems šio tipo resursams. + +# Authz Scope Permission Detail +authz-add-scope-permission=Pridėti taikymo srities leidimą +authz-permission-scope-resource.tooltip=Pasirinkdami resurą apribosite taikymo sričių sąrašą. Jei nepasirinkta, tuomet matysite visas galimas taikymo sritis. +authz-permission-scope-scope.tooltip=Nurodo, kad šis leidimas turi būti pritaikytas vienai ar daugiau taikymo sričių. + +# Authz Evaluation +authz-evaluation-identity-information=Tapatybės informacija +authz-evaluation-identity-information.tooltip=Nurodykite tapatybės informaciją, kuri bus naudojama taisyklių vertinime. +authz-evaluation-client.tooltip=Nurodykite klientą, kuris atlieka autorizacijos užklausas. Nei nenurodyta, tuomet autorizacijos užklausa bus vertinama naudojant dabartinį klientą. +authz-evaluation-user.tooltip=Nurodykite naudotoją, kurio vardu atliekamas teisių serveryje filtravimas. +authz-evaluation-role.tooltip=Nurodykite pasirinkto naudotojo roles. +authz-evaluation-new=Papildyti užklausą +authz-evaluation-re-evaluate=Vertinti pakartotinai +authz-evaluation-previous=Prieš tai buvęs bandymas + +authz-evaluation-contextual-info=Kontekstinė informacija +authz-evaluation-contextual-info.tooltip=Nurodykite kontekstinę informaciją, kuri bus naudojama taisyklių vertinime. +authz-evaluation-contextual-attributes=Kontekstiniai atributai +authz-evaluation-contextual-attributes.tooltip=Galite pateikti vykdymo aplinkos arba vykdymo konteksto atributus. +authz-evaluation-permissions.tooltip=Nurodykite leidimus, kuriems bus taikomos taisyklės. +authz-evaluation-evaluate=Vertinti +authz-evaluation-any-resource-with-scopes=Bet kuris resursas su šia taikymo sritimi (sritimis) +authz-evaluation-no-result=Vertinant autorizacijos užklausą rezultatų nerasta. Patikrinkite ar egzistuoja resursai ar taikymo sritys susietos su taisyklėmis. +authz-evaluation-no-policies-resource=Šiam resursui taisyklės nerastos. +authz-evaluation-result.tooltip=Leidimų užklausos bendras rezultatas. +authz-evaluation-scopes.tooltip=Leidžiamų taikymo sričių sąrašas. +authz-evaluation-policies.tooltip=Informacija apie vertinime dalyvavusias taisykles ir sprendimus. +authz-evaluation-authorization-data=Atsakymas +authz-evaluation-authorization-data.tooltip=Autorizavimo užklausos apdorojimo rezultatas su autorizacijos duomenimis. Rezultatas parodo ką Keycloak grąžina klientui prašančiam leidimo. Peržiūrėkite 'authorization' teiginį su leidimais, kurie buvo suteikti šiai autorizacijos užklausai. +authz-show-authorization-data=Rodyti autorizacijos duomenis + +kid=KID +keys=Raktai +all=Visi +status=Būsena +keystore=Raktų saugykla +keystores=Raktų saugyklos +add-keystore=Pridėti raktų saugyklą +add-keystore.placeholder=Pridėti raktų saugyklą... +view=Žiūrėti +active=Aktyvus + +Sunday=Sekmadienis +Monday=Pirmadienis +Tuesday=Antradienis +Wednesday=Trečiadienis +Thursday=Ketvirtadienis +Friday=Penktadienis +Saturday=Šeštadienis + +user-storage-cache-policy=Podėlio nustatymai +userStorage.cachePolicy=Podėlio taisyklės +userStorage.cachePolicy.option.DEFAULT=DEFAULT +userStorage.cachePolicy.option.EVICT_WEEKLY=EVICT_WEEKLY +userStorage.cachePolicy.option.EVICT_DAILY=EVICT_DAILY +userStorage.cachePolicy.option.MAX_LIFESPAN=MAX_LIFESPAN +userStorage.cachePolicy.option.NO_CACHE=NO_CACHE +userStorage.cachePolicy.tooltip=Saugyklos teikėjo podėlio nustatymai. 'DEFAULT' naudojami numatytieji globalaus naudotojo podėlio nustatymai. 'EVICT_DAILY' naudotojų podėlis išvalomas kiekvieną dieną numatytuoju laiku. 'EVICT_WEEKLY' naudotojų podėlis išvalomas kartą į savaitę numatytą dieną. 'MAX-LIFESPAN' maksimalus podėlio įrašo galiojimo laikas milisekundėmis. +userStorage.cachePolicy.evictionDay=Išvalymo diena +userStorage.cachePolicy.evictionDay.tooltip=Savaitės diena, kuomet podėlio įrašai taps nebeaktualūs +userStorage.cachePolicy.evictionHour=Išvalymo valanda +userStorage.cachePolicy.evictionHour.tooltip=Valanda, kuomet podėlio įrašai taps nebeaktualūs. +userStorage.cachePolicy.evictionMinute=Išvalymo minutė +userStorage.cachePolicy.evictionMinute.tooltip=Minutė, kuomet podėlio įrašai taps nebeaktualūs. +userStorage.cachePolicy.maxLifespan=Maksimalus galiojimo laikas +userStorage.cachePolicy.maxLifespan.tooltip=Maksimalus galiojimo laikas milisekundėmis po kurio podėlio įrašai taps nebeaktualūs. +user-origin-link=Saugojimo kilmė + +disable=Išjungti +disableable-credential-types=Išjungiami tipai +credentials.disableable.tooltip=Galimų išjungti prisijungimo duomenų tipų sąrašas +disable-credential-types=Išjungti prisijungimo duomenų tipus +credentials.disable.tooltip=Paspauskite mygtuką norėdami išjungti pažymėtus prisijungimo duomenų tipus +credential-types=Prisijungimo duomenų tipai +manage-user-password=Tvarkyti slaptažodžius +disable-credentials=Išjungti prisijungimo duomenis +credential-reset-actions=Prisijungimo duomenų atkūrimas +ldap-mappers=LDAP atitikmenų parinkėjai +create-ldap-mapper=Sukurti LDAP atitikmenų parinkėją \ No newline at end of file diff --git a/keycloak-themes/base/admin/messages/admin-messages_lv.properties b/keycloak-themes/base/admin/messages/admin-messages_lv.properties new file mode 100644 index 0000000..dd55d69 --- /dev/null +++ b/keycloak-themes/base/admin/messages/admin-messages_lv.properties @@ -0,0 +1 @@ +# encoding: UTF-8 diff --git a/keycloak-themes/base/admin/messages/admin-messages_nl.properties b/keycloak-themes/base/admin/messages/admin-messages_nl.properties new file mode 100644 index 0000000..e69de29 diff --git a/keycloak-themes/base/admin/messages/admin-messages_no.properties b/keycloak-themes/base/admin/messages/admin-messages_no.properties new file mode 100644 index 0000000..83a0c55 --- /dev/null +++ b/keycloak-themes/base/admin/messages/admin-messages_no.properties @@ -0,0 +1,1127 @@ +consoleTitle=Keycloak administrasjonskonsoll + +# Common messages +enabled=Aktivert +name=Navn +displayName=Vis navn +displayNameHtml=HTML vis navn +save=Lagre +cancel=Avbryt +onText=P\u00C5 +offText=AV +client=Klient +clients=Klienter +clear=T\u00F8m +selectOne=Velg en... + +true=True +false=False + +endpoints=Endepunkter + +# Realm settings +realm-detail.enabled.tooltip=Brukere og klienter har kun tilgang til et sikkerhetsdomene hvis det er aktivert +realm-detail.oidc-endpoints.tooltip=Viser konfigurasjonen av endepunkter for OpenID Connect +registrationAllowed=Registrering av bruker +registrationAllowed.tooltip=Aktiver/deaktiver registreringssiden. En lenke for registrering vil v\u00E6re synlig p\u00E5 innloggingssiden. +registrationEmailAsUsername=E-postadresse som brukernavn +registrationEmailAsUsername.tooltip=Dersom registreringssiden er aktivert, vil feltet for brukernavn v\u00E6re skjult fra registreringsskjema og e-postadresse vil bli brukt som brukernavn for nye brukere. +editUsernameAllowed=Rediger brukernavn +editUsernameAllowed.tooltip=Dersom aktivert, er feltet for brukernavn redigerbart, ellers kun lesbart. +resetPasswordAllowed=Glemt passord +resetPasswordAllowed.tooltip=Vis en lenke p\u00E5 innloggingssiden som brukere kan klikke p\u00E5 om de har glemt sine innloggingsdetaljer. +rememberMe=Husk meg +rememberMe.tooltip=Vis en avkryssingsboks p\u00E5 innloggingssiden som lar brukere forbli innlogget mellom omstart av nettleser og inntil sesjonen utl\u00F8per. +verifyEmail=Bekreft e-postadresse +verifyEmail.tooltip=Krev at bruker verifiserer sin e-postadresse f\u00F8rste gang de logger inn. +sslRequired=Krev SSL +sslRequired.option.all=Alle foresp\u00F8rsler +sslRequired.option.external=Eksterne foresp\u00F8rsler +sslRequired.option.none=Ingen +sslRequired.tooltip=Kreves HTTPS? 'Ingen' betyr at HTTPS ikke kreves for noen klienters IP-adresse. 'Ekstern foresp\u00F8rsel' betyr at localhost og private IP-adresser kan f\u00E5 tilgang uten HTTPS. 'Alle foresp\u00F8rsler' betyr at HTTPS kreves for alle IP-adresser. +publicKey=Offentlig n\u00F8kkel +privateKey=Privat n\u00F8kkel +gen-new-keys=Generer nye n\u00F8kler +certificate=Sertifikat +host=Vert +smtp-host=SMTP Vert +port=Port +smtp-port=SMTP Port (standard er 25) +from=Fra +sender-email-addr=Senders e-postadresse +enable-ssl=Aktiver SSL +enable-start-tls=Aktiver StartTLS +enable-auth=Aktiver autentisering +username=Brukernavn +login-username=Innloggingsbrukernavn +password=Passord +login-password=Innloggingspassord +login-theme=Innloggingstema +login-theme.tooltip=Velg tema for sidene: innlogging, OTP, rettigheter, registrering, glemt passord. +account-theme=Kontotema +account-theme.tooltip=Velg tema for brukerkontoadministrasjonssider. +admin-console-theme=Administrasjonskonsolltema +select-theme-admin-console=Velg et tema for administrasjonskonsollen. +email-theme=E-posttema +select-theme-email=Velg tema for e-post sendt av server. +i18n-enabled=Internasjonalisering aktivert +supported-locales=St\u00F8ttede lokaliteter +supported-locales.placeholder=Skriv inn en lokalitet og klikk enter +default-locale=Standard lokalitet +#localization-upload-file=Upload localization JSON file +#missing-locale=Missing locale. +#missing-file=Missing file. Please select a file to upload. +#localization-file.upload.success=The localization data has been loaded from file. +#localization-file.upload.error=The file can not be uploaded. Please verify the file. +#localization-show=Show realm specific localizations +#no-localizations-configured=No realm specific localizations configured +#add-localization-text=Add localization text +#locale.create.success=The Locale has been created. +#localization-text.create.success=The localization text has been created. +#localization-text.update.success=The localization text has been updated. +#localization-text.remove.success=The localization text has been deleted. +realm-cache-clear=Cache for sikkerhetsdomenet +realm-cache-clear.tooltip=T\u00F8m sikkerhetsdomenecache (Dette vil fjerne oppf\u00F8ringer for alle sikkerhetsdomener) +user-cache-clear=Brukercache +user-cache-clear.tooltip=T\u00F8m brukercache (Dette vil fjerne oppf\u00F8ringer for alle sikkerhetsdomener) +revoke-refresh-token=Fjern refresh token +revoke-refresh-token.tooltip=Hvis aktivert kan refresh token kun bli brukt en gang. Ellers vil refresh tokens kunne bli brukt flere ganger. +sso-session-idle=Inaktiv SSO sesjon +seconds=Sekunder +minutes=Minutter +hours=Timer +days=Dager +sso-session-max=Maksimum SSO sesjon +sso-session-idle.tooltip=Tiden en sesjon er tillatt \u00E5 v\u00E6re inaktiv f\u00F8r den utl\u00F8per. Tokens og nettlesersesjoner vil bli ugyldig n\u00E5r en sesjon utl\u00F8per. +sso-session-max.tooltip=Maksimum tid f\u00F8r en sesjon utl\u00F8per. Tokens og nettlesersesjoner vil bli ugyldig n\u00E5r en sesjon utl\u00F8per. +offline-session-idle=Inaktiv sesjon i frakoblet modus +offline-session-idle.tooltip=Tiden en sesjon i frakoblet modus er tillatt \u00E5 v\u00E6re inaktiv f\u00F8r den utl\u00F8per. Du m\u00E5 bruke tokens for frakoblet modus for \u00E5 oppdatere sesjonen minst en gang i denne perioden, ellers vil sesjonen utl\u00F8pe. +access-token-lifespan=Levetid for access token +access-token-lifespan.tooltip= Maksimum tid f\u00F8r et access token utl\u00F8per. Det anbefales at denne verdien er kort i forhold til SSO timeout. +access-token-lifespan-for-implicit-flow=Access token-levetid for implicit flow +access-token-lifespan-for-implicit-flow.tooltip=Maksimum tid f\u00F8r et access token utstedt under OpenID Connect implicit flow utl\u00F8per. Det anbefales at denne er kortere enn SSO timeout. Det er ingen mulighet til \u00E5 oppdatere tokenet i l\u00F8pet av en implicit flow, derfor er det satt en separat timeout som er forskjellig fra 'Levetid for Access Token'. +client-login-timeout=Timeout av klientinnlogging +client-login-timeout.tooltip=Maksimum tid en klient har for \u00E5 fullf\u00F8re access token protokollen. Dette burde normalt v\u00E6re 1 minutt. +login-timeout=Timeout for innlogging +login-timeout.tooltip=Maksimum tid en bruker har til \u00E5 fullf\u00F8re en innlogging. Det anbefales at denne er relativt lang. 30 minutter eller mer. +login-action-timeout=Timeout for innloggingshandling. +login-action-timeout.tooltip=Maksimum tid en bruker har til \u00E5 fullf\u00F8re handlinger relatert til innlogging, som \u00E5 oppdatere passord eller konfigurere OTP. Det anbefales at denne er relativt lang. 5 minutter eller mer. +headers=Headere +brute-force-detection=Deteksjon av Brute Force +x-frame-options=Alternativer for X-Frame +x-frame-options-tooltip=Standardverdi hindrer sider fra \u00E5 bli inkludert via non-origin iframes. (Klikk p\u00E5 etikett for mer informasjon) +content-sec-policy=Sikkerhetspolicy for innhold +content-sec-policy-tooltip=Standardverdi hindrer sider fra \u00E5 bli inkludert via non-origin iframes. (Klikk p\u00E5 etikett for mer informasjon) +content-sec-policy-report-only=Rapporterende sikkerhetspolicy for innhold +content-sec-policy-report-only-tooltip=Verdi for Content-Security-Policy-Report-Only header. Til bruk for testing av ny sikkerhetspolicy. +content-type-options=Alternativer for X-innholdstyper +content-type-options-tooltip=Standardverdi som forhindrer Internet Explorer og Google Chrome fra \u00E5 MIME-sniffe et svar vekk fra den deklarerte innholdstypen (content-type) (Klikk p\u00E5 etikett for mer informasjon) +max-login-failures=Maksimum antall innloggingsfeil +max-login-failures.tooltip=Hvor mange feil f\u00F8r ventetid blir aktivert. +wait-increment=\u00F8kning av ventetid +wait-increment.tooltip=N\u00E5r terskelen for feil er n\u00E5dd, hvor lenge skal brukeren stenges ute? +quick-login-check-millis=Hurtig innlogging - kontroll av millisekunder +quick-login-check-millis.tooltip=Hvis en feil skjer for raskt samtidig, steng brukeren ute. +min-quick-login-wait=Minimum ventetid for hurtig innlogging +min-quick-login-wait.tooltip=Ventetid etter en hurtig innloggingsfeil. +max-wait=Maksimum ventetid +max-wait.tooltip=Maksimum tid en bruker vil v\u00E6re stengt ute. +failure-reset-time=Tid for tilbakestilling av feil. +failure-reset-time.tooltip=N\u00E5r vil teller for feil nullstilles? +realm-tab-login=Innlogging +realm-tab-keys=N\u00F8kler +realm-tab-email=E-post +realm-tab-themes=Tema +#realm-tab-localization=Localization +realm-tab-cache=Cache +realm-tab-tokens=Tokens +realm-tab-client-initial-access=F\u00F8rste access token +realm-tab-security-defenses=Sikkerhetsmekanismer +realm-tab-general=Generelt +add-realm=Legg til sikkerhetsdomene + +#Session settings +realm-sessions=Sikkerhetsdomenesesjoner +revocation=Oppheving +logout-all=Logg ut alle +active-sessions=Aktive sesjoner +sessions=Sesjoner +not-before=Ikke f\u00F8r +not-before.tooltip=Opphev alle tokens utstedt f\u00F8r denne datoen. +set-to-now=Sett til n\u00E5 +push=Send +push.tooltip=For enhver klient som har en administratorURL, send dem beskjed om den nye opphevingspolicyen. + +#Protocol Mapper +usermodel.prop.label=Egenskap +usermodel.prop.tooltip=Navn p\u00E5 egenskapsmetoden i UserModel-grensesnittet. For eksempel, en verdi av 'e-post' vil referere til metoden UserModel.getEmail(). +usermodel.attr.label=Brukerattributt +usermodel.attr.tooltip=Navn p\u00E5 lagret brukerattributt som er navnet p\u00E5 en attributt innenfor UserModel.attribute map. +userSession.modelNote.label=Brukersesjonsmerknad +userSession.modelNote.tooltip=Navn p\u00E5 lagret brukersesjonsmerknad innenfor UserSessionModel.note map. +multivalued.label=Flere verdier +multivalued.tooltip=Angir om en attributt st\u00F8tter flere verdier. Hvis true, vil listen med alle verdier for dette attributtet bli satt som claims. Hvis false, vil bare den f\u00F8rste verdien bli satt som claim. +selectRole.label=Velg rolle +selectRole.tooltip=Skriv inn rolle i tekstboksen til venstre, eller klikk p\u00E5 denne knappen for \u00E5 bla gjennom og velge rollen du \u00F8nsker. +tokenClaimName.label=Navn p\u00E5 token claim +tokenClaimName.tooltip=Navn p\u00E5 claim som skal legges inn i token. Denne kan v\u00E6re et fullt kvalifisert navn som 'address.street'. I dette tilfellet vil et nestet jsonobjekt bli laget. +jsonType.label=JSON-type for claims +jsonType.tooltip=JSON-type som burde bli brukt for \u00E5 fylle json claimet i tokenet. long, int, boolean og String er gyldige verdier. +includeInIdToken.label=Legg til i ID token +includeInIdToken.tooltip=Burde claim bli lagt til i ID token? +includeInAccessToken.label=Legg til i access token +includeInAccessToken.tooltip=Burde claim bli lagt til i access token? +includeInUserInfo.label=Legg til i brukerinfo +includeInUserInfo.tooltip=Burde claim bli lagt til i brukerinfo? +usermodel.clientRoleMapping.clientId.label=Klient-ID +usermodel.clientRoleMapping.clientId.tooltip=Klient-ID for \u00E5 mappe roller +usermodel.clientRoleMapping.rolePrefix.label=Prefiks for klientrolle +usermodel.clientRoleMapping.rolePrefix.tooltip=Prefiks for hver klientrolle (valgfri). +usermodel.realmRoleMapping.rolePrefix.label=Prefiks for sikkerhetsdomenerolle +usermodel.realmRoleMapping.rolePrefix.tooltip=Prefiks for hver sikkerhetsdomenerolle (valgfri). + +# client details +clients.tooltip=Klienter er betrodde nettleserapplikasjoner og web-tjenester i et sikkerhetsdomene. Disse klientene kan be om en innlogging. Du kan ogs\u00E5 definere klientspesifikke roller. +search.placeholder=S\u00F8k... +create=Opprett +import=Importer +client-id=Klient-ID +base-url=Base URL +actions=Handlinger +not-defined=Ikke definert +edit=Rediger +delete=Slett +no-results=Ingen resultater +no-clients-available=Ingen klienter er tilgjengelige +add-client=Legg til klient +select-file=Velg fil +view-details=Se detaljer +clear-import=T\u00F8m import +client-id.tooltip=Angir ID referert i URI og tokens. For eksempel 'min-klient'. For SAML er dette ogs\u00E5 forventet utgiververdi fra authn-foresp\u00F8rsler +client.name.tooltip=Angir klientnavnet som blir vist. For eksempel, 'Min klient'. St\u00F8tter n\u00F8kler for lokaliserte verdier. For eksempel\: ${my_client} +client.enabled.tooltip=Deaktiverte klienter kan ikke initiere en innlogging eller motta access tokens. +consent-required=Samtykke p\u00E5krevd +consent-required.tooltip=Hvis aktivert m\u00E5 brukere gi samtykke for at klienten skal f\u00E5 tilgang. +client-protocol=Klientprotokoll +client-protocol.tooltip='OpenID connect' tillater klienter \u00E5 verifisere identiteten til sluttbrukeren basert p\u00E5 autentisering utf\u00F8rt av en autorisasjonsserver. 'SAML' aktiverer en web-basert autentisering og autoriseringsscenarier som inkluderer cross-domain single sign-on (SSO) og som bruker security tokens som inneholder assertions for \u00E5 dele informasjon videre. +access-type=Tilgangstype +access-type.tooltip='Confidential' klienter krever en secret for \u00E5 initiere innloggingsprotokoll. 'Public' klienter krever ikke en secret. 'Bearer-only' klienter er webtjenester som aldri initierer en innlogging. +standard-flow-enabled=Standard flow aktivert +standard-flow-enabled.tooltip=Dette aktiverer standard OpenID Connect redirect-basert autentisering med autorisasjonskode. I forhold til OpenID Connect eller OAuth2 spesifikasjoner aktiverer dette st\u00F8tte for 'Authorization Code Flow' for denne klienten. +implicit-flow-enabled=Implicit flow aktivert +implicit-flow-enabled.tooltip=Dette aktiverer st\u00F8tte for OpenID Connect redirect-basert autentisering uten autorisasjonskode. I forhold til OpenID Connect eller OAuth2 spesifikasjoner aktiverer dette st\u00F8tte for 'Implicit Flow' for denne klienten. +direct-access-grants-enabled=Direct access grants aktivert +direct-access-grants-enabled.tooltip=Dette gir st\u00F8tte for Direct Access Grants, som betyr at klienten har tilgang til brukerens brukernavn/passord og kan bytte dette direkte med Keycloak-serveren for access token. I f\u00F8lge OAuth2 spesifikasjonen, aktiverer dette st\u00F8tte for 'Resource Owner Password Credentials Grant' for denne klienten. +service-accounts-enabled=Tjenestekonto aktivert +service-accounts-enabled.tooltip=Lar deg autentisere denne klienten til Keycloak og hente access token dedikert til denne klienten. I f\u00F8lge OAuth2 spesifikasjonen, aktiverer dette st\u00F8tte for 'Client Credentials Grant' for denne klienten. +include-authnstatement=Inkluder AuthnStatement +include-authnstatement.tooltip=Skal et statement som spesifiserer metoden for tidsstempel inng\u00E5 i innloggingssvaret? +sign-documents=Signer dokumenter +sign-documents.tooltip=Skal SAML dokumenter bli signert av sikkerhetsdomenet? +sign-assertions=Signer assertions +sign-assertions.tooltip=Skal assertions i SAML dokumenter bli signert? Denne innstillingen er ikke n\u00F8dvendig hvis et dokument allerede har blitt signert. +signature-algorithm=Signaturalgoritme +signature-algorithm.tooltip=Signaturalgoritmen som brukes for \u00E5 signere et dokument. +canonicalization-method=Kanoniseringsmetode +canonicalization-method.tooltip=Kanoniseringsmetode for XML signaturer. +encrypt-assertions=Krypter assertions +encrypt-assertions.tooltip=Skal SAML assertions bli kryptert med klientens offentlige n\u00F8kkel ved \u00E5 bruke AES? +client-signature-required=Klientens signatur er p\u00E5krevd +client-signature-required.tooltip=Skal klienten signere sine SAML foresp\u00F8rsler og svar? Og skal de valideres? +force-post-binding=Force POST binding +force-post-binding.tooltip=Bruk alltid POST binding for svar. +front-channel-logout=Front channel utlogging +front-channel-logout.tooltip=Hvis satt til true, krever utlogging en redirect i nettleser til klient. Hvis satt til false, vil server utf\u00F8re en bakgrunnskall for utlogging. +force-name-id-format=Force navn-ID format +force-name-id-format.tooltip=Ignorer forespurt format p\u00E5 Navn-ID emnet og bruk den som er konfigurert i administrasjonskonsollen. +name-id-format=Navn-ID format +name-id-format.tooltip=Navn-ID formatet som skal brukes for emnet. +root-url=Root URL +root-url.tooltip=Root URL lagt til relative URLer +valid-redirect-uris=Gyldig redirect URIer +valid-redirect-uris.tooltip=Gyldig URI m\u00F8nster som en nettleser kan redirecte til etter en vellykket innlogging eller utlogging. Enkle jokertegn er tillatt, for eksempel 'http://example.com/*'. Relativ sti kan ogs\u00E5 spesifiseres, for eksempel /my/relative/path/*. Relative stier er relative til klientens root URL, eller hvis ingen er spesifisert brukes root URL for autorisasjonsserveren. For SAML m\u00E5 du sette et gyldig URI m\u00F8nster hvis du er avhengig av at URL for forbrukertjenesten er integrert med foresp\u00F8rselen for p\u00E5logging. +base-url.tooltip=Standard URL som kan brukes n\u00E5r autorisasjonsserveren trenger \u00E5 redirecte eller lenke tilbake til klienten. +admin-url=Admin URL +admin-url.tooltip=URL til administratorgrensesnitt for klienten. Sett denne hvis klienten st\u00F8tter adapter REST API. Dette REST APIet tillater autorisasjonsserveren til \u00E5 sende tilbakekallingsregler og andre administrative oppgaver. Vanligvis er dette satt til klientens base URL. +master-saml-processing-url=Master SAML prosesserings URL +master-saml-processing-url.tooltip=Hvis konfigurert vil denne URLen bli brukt for hver binding til b\u00E5de SPs Assertion Consumer og Single Logout-tjenester. Denne kan bli individuelt overstyrt for hver binding og tjenester i konfigurasjonen for finkornet SAML endepunkt. +idp-sso-url-ref=IDP initiert SSO URL navn +idp-sso-url-ref.tooltip=Navn p\u00E5 URL-fragment som refererer til klienten n\u00E5r du vil gj\u00F8re en IDP initiert SSO. La denne st\u00E5 tom om du \u00F8nsker \u00E5 deaktivere IDP initiert SSO. URLen vil v\u00E6re: {server-root}/realms/{realm}/protocol/saml/clients/{client-url-name} +idp-sso-relay-state=IDP initiert SSO relay state +idp-sso-relay-state.tooltip=Relay state du \u00F8nsker \u00E5 sende med SAML foresp\u00F8rselen n\u00E5r du vil utf\u00F8re en IDP initiert SSO. +web-origins=Web origins +web-origins.tooltip=Tillat CORS origins. For \u00E5 tillate alle origins med gyldig Redirect URIer legg til '+'. For \u00E5 tillate alle origins legg til '*'. +fine-saml-endpoint-conf=Finkornet SAML endepunktskonfigurasjon +fine-saml-endpoint-conf.tooltip=Utvid denne delen til \u00E5 konfigurere n\u00F8yaktige URLer for Assertion Consumer og Single Logout-tjeneste. +assertion-consumer-post-binding-url=Assertion consumer service POST binding URL +assertion-consumer-post-binding-url.tooltip=SAML POST binding URL for klientens assertion customer service (innloggingsrespons). Du kan la denne st\u00E5 tom om du ikke \u00F8nsker en URL for denne bindingen. +assertion-consumer-redirect-binding-url=Assertion Consumer Service redirect binding URL +assertion-consumer-redirect-binding-url.tooltip=SAML redirect for klientens assertion consumer service (innloggingsrespons). Du kan la denne st\u00E5 tom om du ikke \u00F8nsker en URL for denne bindingen. +logout-service-binding-post-url=logout-tjeneste POST binding URL +logout-service-binding-post-url.tooltip=SAML POST binding URL for klientens single logout-tjeneste. Du kan la dette st\u00E5 tomt om du bruker en annen binding. +logout-service-redir-binding-url=Logout-tjeneste redirect binding URL +logout-service-redir-binding-url.tooltip=SAML redirect binding URL for klientens single logout-tjeneste. Du kan la dette st\u00E5 tomt om du bruker en annen binding. + +# client import +import-client=Importer klient +format-option=Formatalternativer +select-format=Velg et format +import-file=Importer fil + +# client tabs +settings=Innstillinger +credentials=Innloggingsdetaljer +roles=Roller +mappers=Mappere +mappers.tooltip=Protokollmappere som utf\u00F8rer endringer av tokens og dokumenter. De kan utf\u00F8re handlinger som \u00E5 mappe brukerdata til protokollclaims, eller bare endre foresp\u00F8rsler som blir sendt mellom klienten og autorisasjonsserver. +scope=Scope +scope.tooltip=Mapping av scope lar deg begrense hvilke rollemappinger som er inkludert i access token som klienten har bedt om. +sessions.tooltip=Viser aktive sesjoner for denne klienten. Tillater deg \u00E5 se hvilke brukere som er aktive og n\u00E5r de logget inn. +offline-access=Frakoblet tilgang +offline-access.tooltip=Viser frakoblede sesjoner for denne klienten. Tillater deg \u00E5 se hvilke brukere som henter tokens for frakoblet modus og n\u00E5r de henter den. For \u00E5 tilbakekalle alle tokens for klienten, g\u00E5 til fanen Opphev og sett verdien for Ikke f\u00F8r til n\u00E5. +clustering=Clustering +installation=Installasjon +installation.tooltip=Verkt\u00F8y for \u00E5 generere ulike konfigurasjonsformater for klientadapter som du kan laste ned eller klippe og lime inn for \u00E5 konfigurere klientene dine. +service-account-roles=Tjenestekonto-roller +service-account-roles.tooltip=Tillater deg \u00E5 autentisere rollemappinger for tjenestekontoen som er dedikert til denne klienten. + +# client credentials +client-authenticator=Klientautentikator +client-authenticator.tooltip=Klientautentikator som blir brukt for \u00E5 autentisere denne klienten mot keycloak-server +certificate.tooltip=Klientsertifikat for \u00E5 validere JWT utstedt av klienten og signert av privatn\u00F8kkel til klient fra din keystore. +publicKey.tooltip=Offentlig n\u00F8kkel for \u00E5 validere JWT utstedt av klient og signert av klientens privatn\u00F8kkel. +no-client-certificate-configured=Ingen klientsertifikat er konfigurert +gen-new-keys-and-cert=Generer nye n\u00F8kler og sertifikater +import-certificate=Importer sertifikat +gen-client-private-key=Generer privatn\u00F8kkel for klient +generate-private-key=Generer privatn\u00F8kkel +archive-format=Arkivformat +archive-format.tooltip=Java keystore eller PKCS12 arkivformat. +key-alias=N\u00F8kkelalias +key-alias.tooltip=Arkiv-alias for din privatn\u00F8kkel og sertifikater. +key-password=N\u00F8kkelpassord +key-password.tooltip=Passord for \u00E5 f\u00E5 tilgang til privatn\u00F8kler i arkivet +store-password=Lagre passord +store-password.tooltip=Passord for \u00E5 f\u00E5 tilgang til arkivet +generate-and-download=Generer og Last ned +client-certificate-import=Import av klientsertifikat +import-client-certificate=Importer klientsertifikat +jwt-import.key-alias.tooltip=Arkiv-alias for sertifikatet ditt. +secret=Secret +regenerate-secret=Regenere secret +registrationAccessToken=Access token for registrering +registrationAccessToken.regenerate=Regenerer access token for registrering +registrationAccessToken.tooltip=Access token for registrering gir klienter tilgang til registreringstjenesten for klienter. +add-role=Legg til rolle +role-name=Rollenavn +composite=Sammensatt +description=Beskrivelse +no-client-roles-available=Ingen klientroller er tilgjengelig +scope-param-required=Scope parameter p\u00E5krevd +scope-param-required.tooltip=Denne rollen vil kun bli gitt hvis parameter for scope med rollenavn blir brukt under foresp\u00F8rsel av autorisasjon/token. +composite-roles=Sammensatte roller +composite-roles.tooltip=N\u00E5r denne rollen er tildelt/ikke tildelt til en bruker, vil hvilken som helst rolle assosiert med denne bli implisitt tildelt/ikke tildelt. +realm-roles=Sikkerhetsdomeneroller +available-roles=Tilgjengelig roller +add-selected=Legg til valgte +associated-roles=Assosierte roller +composite.associated-realm-roles.tooltip=Sikkerhetsdomeneniv\u00E5-rolle knyttet til denne sammensatte rollen. +composite.available-realm-roles.tooltip=Sikkerhetsdomeneniv\u00E5-roller knyttet til denne sammensatte rollen. +remove-selected=Fjern valgte +client-roles=Klientroller +select-client-to-view-roles=Velg klient for \u00E5 se roller for klient +available-roles.tooltip=Roller fra denne klienten som du kan knytte til denne sammensatte rollen. +client.associated-roles.tooltip=Klientrolle assosiert med denne sammensatte rollen. +add-builtin=Legg til Builtin +category=Kategori +type=Type +no-mappers-available=Ingen mappere er tilgjengelig +add-builtin-protocol-mappers=Legg til Builtin protokollmappere +add-builtin-protocol-mapper=Legg til Builtin protokollmapper +scope-mappings=Scopemapping +full-scope-allowed=Tillatt med fullt scope +full-scope-allowed.tooltip=Lar deg \u00E5 deaktivere alle restriksjoner. +scope.available-roles.tooltip=Sikkerhetsdomeneniv\u00E5-roller som kan bli tildelt til scope. +assigned-roles=Tildelte roller +assigned-roles.tooltip=Sikkerhetsdomeneniv\u00E5-roller tildelt til scope. +effective-roles=Effektive roller +realm.effective-roles.tooltip=Tildelte sikkerhetsdomeneniv\u00E5-roller som kan ha blitt arvet fra en sammensatt rolle. +select-client-roles.tooltip=Velg en klient for \u00E5 se roller for klient +assign.available-roles.tooltip=Klientroller som er tilgjengelige til \u00E5 bli tildelt. +client.assigned-roles.tooltip=Tildelte klientroller. +client.effective-roles.tooltip=Tildelte klientroller som kan ha blitt arvet fra en sammensatt rolle. +basic-configuration=Basiskonfigurasjon +node-reregistration-timeout=Timeout for re-registrering av node +node-reregistration-timeout.tooltip=Intervall for \u00E5 angi maksimum tid for registrerte klienters clusternoder for \u00E5 re-registreres. Hvis en clusternode ikke sender re-regisreringsforesp\u00F8rsel til Keycloak innen dette intervallet, vil den bli uregistrert fra Keycloak. +registered-cluster-nodes=Registrerte clusternoder +register-node-manually=Register node manuelt +test-cluster-availability=Test cluster tilgjengelighet +last-registration=Siste registrering +node-host=Nodevert +no-registered-cluster-nodes=Ingen registrerte clusternoder tilgjengelig +cluster-nodes=Clusternoder +add-node=Legg til node +active-sessions.tooltip=Totalt antall aktive brukersesjoner for denne klienten. +show-sessions=Vis sesjoner +show-sessions.tooltip=Advarsel, dette er en potensielt kostbar operasjon avhengig av antall aktive sesjoner. +user=Bruker +from-ip=Fra IP +session-start=Start av sesjon +first-page=F\u00F8rste side +previous-page=Forrige side +next-page=Neste side +client-revoke.not-before.tooltip=Opphev alle token utstedt f\u00F8r denne datoen for denne klienten. +client-revoke.push.tooltip=Hvis administrator URL er konfigurert for denne klienten, dytt denne policyen p\u00E5 denne klienten. +select-a-format=Velg et format +download=Last ned +offline-tokens=Offline tokens +offline-tokens.tooltip=Totalt antall offline tokens for denne klienten. +show-offline-tokens=Vis offline tokens +show-offline-tokens.tooltip=Advarsel, dette er en potensielt kostbar operasjon avhengig av antall offline tokens. +token-issued=Utgitt token +last-access=Sist aksessert +last-refresh=Siste refresh +key-export=Eksporter n\u00F8kkel +key-import=Importer n\u00F8kkel +export-saml-key=Eksporter SAML n\u00F8kkel +import-saml-key=Importer SAML n\u00F8kkel +realm-certificate-alias=Alias for sikkerhetsdomenesertifikat +realm-certificate-alias.tooltip=Sertifikat for sikkerhetsdomenet er ogs\u00E5 lagret i arkivet. Dette er aliaset. +signing-key=Signeringsn\u00F8kkel +saml-signing-key=SAML signeringsn\u00F8kkel +private-key=Privatn\u00F8kkel +generate-new-keys=Generer nye n\u00F8kler +export=Eksporter +encryption-key=Krypteringsn\u00F8kkel +saml-encryption-key.tooltip=SAML krypteringsn\u00F8kkel. +service-accounts=Tjenestekonto-konto +service-account.available-roles.tooltip=Sikkerhetsdomeneniv\u00E5-roller som kan bli tildelt til tjeneste-konto. +service-account.assigned-roles.tooltip=Sikkerhetsdomeneniv\u00E5-roller tildelt service-konto. +service-account-is-not-enabled-for=Tjeneste-konto er ikke aktivert for {{client}} +create-protocol-mappers=Opprett protokollmappere +create-protocol-mapper=Opprett protokollmapper +protocol=Protokoll +protocol.tooltip=Protokoll... +id=ID +mapper.name.tooltip=Navn p\u00E5 mapper. +mapper.consent-required.tooltip=Ved tildeling av midlertidig tilgang m\u00E5 brukeren samtykke til \u00E5 gi denne informasjonen til klienten? +consent-text=Samtykketekst +consent-text.tooltip=Tekst som blir vist p\u00E5 side for samtykke. +mapper-type=Mappertype +mapper-type.tooltip=Type mapper +# realm identity providers +identity-providers=Identitetsleverand\u00F8r +table-of-identity-providers=Liste over identitetsleverand\u00F8rer +add-provider.placeholder=Legg til leverand\u00F8r... +provider=Leverand\u00F8r +gui-order=Rekkef\u00F8lge for brukergrensesnitt +first-broker-login-flow=Flyt for f\u00F8rste innlogging +post-broker-login-flow=Post-p\u00E5loggingsflyt +redirect-uri=Redirect URI +redirect-uri.tooltip=Redirect URI som skal brukes n\u00E5r du konfigurerer identitetsleverand\u00F8ren. +alias=Alias +identity-provider.alias.tooltip=Aliaset identifiserer en identitetsleverand\u00F8r og kan brukes for \u00E5 bygge en redirect uri. +identity-provider.enabled.tooltip=Aktiver/deaktiver denne identitetsleverand\u00F8ren. +authenticate-by-default=Autentiser som standard +identity-provider.authenticate-by-default.tooltip=Indikerer om en leverand\u00F8r burde fors\u00F8kes \u00E5 brukes om standard for autentisering selv om innloggingssiden enda ikke har blitt vist. +store-tokens=Lagre Tokens +identity-provider.store-tokens.tooltip=Aktiver/deaktiver hvis tokens m\u00E5 bli lagret etter at brukere har blitt autentisert. +stored-tokens-readable=Lagrede lesbare tokens +identity-provider.stored-tokens-readable.tooltip=Aktiver/deaktiver hvis nye brukere kan lese lagrede tokens. Dette tildeles broker.read-token rollen. +update-profile-on-first-login=Oppdater profil ved f\u00F8rste innlogging +on=P\u00E5 +on-missing-info=Ved manglende informasjon +off=Av +update-profile-on-first-login.tooltip=Definer vilk\u00E5rene en bruker m\u00E5 oppfylle for \u00E5 oppdatere sin profil ved f\u00F8rste innlogging. +trust-email=Stol p\u00E5 e-post +trust-email.tooltip=Hvis aktivert vil ikke e-post levert av denne leverand\u00F8ren bli verifisert selv om verifisering er aktivert for sikkerhetsdomenet. +gui-order.tooltip=Antall som angir rekkef\u00F8lgen av leverand\u00F8rer i brukergrensesnittet (For eksempel p\u00E5 innloggingssiden). +first-broker-login-flow.tooltip=Alias for autentiseringsflyt, som trigges etter f\u00F8rste innlogging med denne identitetsleverand\u00F8ren. Begrepet 'F\u00F8rste innlogging' betyr at det enn\u00E5 ikke eksisterer en Keycloak-konto koblet til den autentiserte kontoen til identitetsleverand\u00F8ren. +post-broker-login-flow.tooltip=Alias for autentiseringsflyt, som trigges etter hver innlogging med denne identitetsleverand\u00F8ren. Nyttig om man \u00F8nsker tilleggsverifikasjon av hver bruker autentisert med denne identitetsleverand\u00F8ren (for eksempel med engangskode/engangspassord). La denne st\u00E5 tom om du ikke \u00F8nsker at tilleggautentisering skal bli trigget etter en innlogging med denne identitetsleverand\u00F8ren. Merk ogs\u00E5 at implementasjonen av denne autentikatoren m\u00E5 anta at bruker allerede er satt i ClientSession ettersom identitetsleverand\u00F8ren allerede setter det. +openid-connect-config=OpenID Connect konfigurasjon +openid-connect-config.tooltip=OIDC SP og ekstern IDP-konfigurasjon. +authorization-url=Autorisasjons URL +authorization-url.tooltip=Autorisasjons URLen. +token-url=Token URL +token-url.tooltip=Token URLen. +logout-url=Utloggings URL +identity-provider.logout-url.tooltip=Endepunkt for avsluttende sesjon som brukes for \u00E5 logge ut bruker fra ekstern IDP. +backchannel-logout=Backchannel utlogging +backchannel-logout.tooltip=St\u00F8tter ekstern IDP backchannel utlogging? +user-info-url=Brukerinfo URL +user-info-url.tooltip=Brukerinfo URLen. Denne er valgfri. +identity-provider.client-id.tooltip=Klienten eller klientidentifikator registrert hos identitetsleverand\u00F8ren. +client-secret=Klient secret +show-secret=Vis secret +hide-secret=Skjul secret +client-secret.tooltip=Klienten eller klient secret registrert hos identitetsleverand\u00F8ren. +issuer=Utgiver +issuer.tooltip=Identifikator for utgiver av foresp\u00F8rselen. Hvis dette ikke er oppgitt vil ingen validering utf\u00F8res. +default-scopes=Standard Scopes +identity-provider.default-scopes.tooltip=Scopes som sendes n\u00E5r du ber om autorisasjon. Dette kan v\u00E6re en liste med scopes separert med mellomrom. Standard er satt til 'openid'. +prompt=Prompt +unspecified.option=uspesifisert +none.option=Ingen +consent.option=samtykke +login.option=Innlogging +select-account.option=velg_konto (select_account) +prompt.tooltip=Spesifiserer om autorisasjonsserver skal be sluttbruker om re-autentisering og samtykke. +validate-signatures=Valider signaturer +identity-provider.validate-signatures.tooltip=Aktiver/deaktiver signaturvalidering av eksterne IDP signaturer. +validating-public-key=Valider offentlig n\u00F8kkel +identity-provider.validating-public-key.tooltip=PEM format for offentlig n\u00F8kkel som m\u00E5 brukes for \u00E5 kontrollere eksterne IDP signaturer. +import-external-idp-config=Importer ekstern IDP konfigurasjon +import-external-idp-config.tooltip=Lar deg laste inn ekstern IDP metadata fra en konfigurasjonsfil eller ved \u00E5 laste det ned fra en URL. +import-from-url=Importer fra URL +identity-provider.import-from-url.tooltip=Importer metadata fra et eksternt IDP discovery descriptor. +import-from-file=Importer fra fil +identity-provider.import-from-file.tooltip=Importer metadata fra en nedlastet IDP discovery descriptor. +saml-config=SAML konfigurasjon +identity-provider.saml-config.tooltip=SAML SP og ekstern IDP konfigurasjon. +single-signon-service-url=Single sign-on service URL +saml.single-signon-service-url.tooltip=URL som m\u00E5 brukes for \u00E5 sende autentiseringsforesp\u00F8rsler (SAML AuthnRequest). +single-logout-service-url=Single utloggingstjeneste URL +saml.single-logout-service-url.tooltip=URL som m\u00E5 brukes for \u00E5 sende utloggingsforesp\u00F8rsler. +nameid-policy-format=Policy for nameid-format +nameid-policy-format.tooltip=Angir URI-referanse som tilsvarer et format for identifikator-navn. Standard er satt til urn:oasis:names:tc:SAML:2.0:nameid-format:persistent. +http-post-binding-response=HTTP-POST binding svar +http-post-binding-response.tooltip=Indikerer om man skal svare p\u00E5 foresp\u00F8rsler som bruker HTTP-POST binding eller ikke. Hvis satt til false, vil HTTP-REDIRECT binding bli brukt. +http-post-binding-for-authn-request=HTTP-POST binding for AuthnRequest +http-post-binding-for-authn-request.tooltip=Indikerer om AuthnRequests m\u00E5 bli sendt ved \u00E5 bruke en HTTP-POST binding. Hvis satt til false, vil HTTP-REDIRECT binding bli brukt. +want-authn-requests-signed=Vil ha AuthnRequests signert +want-authn-requests-signed.tooltip=Indikerer om identitetsleverand\u00F8r forventer en signert AuthnRequest. +force-authentication=Force autentisering +identity-provider.force-authentication.tooltip=Indikerer om identitetsleverand\u00F8r m\u00E5 autentisere presentat\u00F8ren direkte i stedet for \u00E5 stole p\u00E5 en tidligere sikkerhetskontekst. +validate-signature=Valider signatur +saml.validate-signature.tooltip=Aktiver/deaktiver signaturvalidering av SAML svar. +validating-x509-certificate=Validerer X509 sertifikat +validating-x509-certificate.tooltip=Sertifikatet i PEM format som m\u00E5 brukes for \u00E5 se etter signaturer. +saml.import-from-url.tooltip=Importer metadata fra et eksternt IDP SAML entity descriptor. +social.client-id.tooltip=Identifikator for klient registrert hos identitetsleverand\u00F8r. +social.client-secret.tooltip=Klient secret registrert hos identitetsleverand\u00F8r. +social.default-scopes.tooltip=Scopes som sendes n\u00E5r tillatelse for autorisasjon blir etterspurt. Se dokumentasjon for mulige verdier, separator og standardverdi. +key=N\u00F8kkel +stackoverflow.key.tooltip=N\u00F8kkelen er hentet fra klientregistrering p\u00E5 Stack Overflow. + +# User federation +sync-ldap-roles-to-keycloak=Synkroniser LDAP-roller til Keycloak +sync-keycloak-roles-to-ldap=Synkroniser Keycloak-roller til LDAP +sync-ldap-groups-to-keycloak=Synkroniser LDAP-grupper til Keycloak +sync-keycloak-groups-to-ldap=Synkroniser Keycloak-grupper til LDAP + +realms=Sikkerhetsdomener +realm=Sikkerhetsdomene + +identity-provider-mappers=Identitetsleverand\u00F8rmappere +create-identity-provider-mapper=Opprett identitetsleverand\u00F8rmappere +add-identity-provider-mapper=Legg til identitetsleverand\u00F8rmappere +client.description.tooltip=Angir beskrivelse av klienten. For eksempel\: 'Min klient for timelister'. St\u00F8tter n\u00F8kler for lokaliserte verdier. For eksempel\: ${my_client_description} + +expires=Utl\u00F8per +expiration=Holdbarhet +expiration.tooltip=Angir hvor lenge et token skal v\u00E6re gyldig +count=Teller +count.tooltip=Angir hvor mange klienter som kan bli opprettet ved \u00E5 bruke token. +remainingCount=Resterende antall +created=Opprettet +back=Tilbake +initial-access-tokens=F\u00F8rste access tokens +initial-access-tokens.tooltip=F\u00F8rste access tokens for dynamisk registrering av klienter. Foresp\u00F8rsler med disse tokens kan bli sent fra alle verter. +add-initial-access-tokens=Legg til f\u00F8rste access token +initial-access-token=F\u00F8rste access token +initial-access.copyPaste.tooltip=Kopier/lim inn f\u00F8rste access token f\u00F8r du navigerer vekk fra denne siden ettersom det ikke er mulig \u00E5 hente den senere. +continue=Fortsett +initial-access-token.confirm.title=Kopier f\u00F8rste access token +initial-access-token.confirm.text=Vennligst kopier og lim inn f\u00F8rste access token f\u00F8r du bekrefter ettersom den ikke kan hentes senere +no-initial-access-available=F\u00F8rste access token er ikke tilgjengelig + +trusted-hosts-legend=Betrodde verter for klientregistrering +trusted-hosts-legend.tooltip=Verter, som er betrodd for klientregistrering. klientregistreringsforesp\u00F8rsler fra disse vertene kan bli sent selv uten f\u00F8rste access token. Antall klientregistreringer fra denne spesifikke verten kan bli begrenset til et spesifisert antall. +no-client-trusted-hosts-available=Ingen betrodde verter er tilgjengelig +add-client-reg-trusted-host=Legg til betrodd vert +hostname=Vertsnavn +client-reg-hostname.tooltip=Vertsnavn eller IP-adresse. Klientregistreringsforesp\u00F8rsler fra denne verten/adressen vil bli betrodd og tillat til \u00E5 registrere en ny klient. +client-reg-count.tooltip=Tillat antall klientregistreringsforesp\u00F8rsler fra en spesifikk vert. Du m\u00E5 restarte denne n\u00E5r grensen er n\u00E5dd. +client-reg-remainingCount.tooltip=Gjenv\u00E6rende antall klientregistreringsforesp\u00F8rsler fra denne verten. Du m\u00E5 restarte denne n\u00E5r grensen er n\u00E5dd. +reset-remaining-count=Tilbakestill gjenst\u00E5ende antall + +client-scopes=Klientmaler +client-scopes.tooltip=Klientmaler tillater deg \u00E5 definere felles konfigurasjon som er delt av flere klienter. + +groups=Grupper + +group.add-selected.tooltip=Sikkerhetsdomene-roller som kan bli tildelt gruppen. +group.assigned-roles.tooltip=Sikkerhetsdomene-roller mappet til gruppen. +group.effective-roles.tooltip=Alle sikkerhetsdomene-rollemappinger. Noen roller kan ha blitt arvet fra en sammensatt rolle. +group.available-roles.tooltip=Roller som kan tildeles fra denne klienten. +group.assigned-roles-client.tooltip=Rollemapping for denne klienten. +group.effective-roles-client.tooltip=Rollemapping for denne klienten. Noen roller kan ha blitt arvet fra en mappet sammensatt rolle. + +default-roles=Standardroller +no-realm-roles-available=Ingen sikkerhetsdomener er tilgjengelig + +users=Brukere +user.add-selected.tooltip=Sikkerhetsdomene-roller som kan bli tildelt bruker. +user.assigned-roles.tooltip=Sikkerhetsdomene-roller mappet til bruker +user.effective-roles.tooltip=Alle sikkerhetsdomene-rollemappinger. Noen roller kan ha blitt arvet fra en sammensatt rolle. +user.available-roles.tooltip=Roller som kan tildeles fra denne klienten. +user.assigned-roles-client.tooltip=Rollemapping for denne klienten. +user.effective-roles-client.tooltip=Rollemapping for denne klienten. Noen roller kan ha blitt arvet fra en mappet sammensatt rolle. +default.available-roles.tooltip=Sikkerhetsdomene-roller som kan tildeles. +realm-default-roles=Standardroller for sikkerhetsdomene +realm-default-roles.tooltip=Sikkerhetsdomene-roller tildelt nye brukere. +default.available-roles-client.tooltip=Roller fra denne klienten som blir tildelt som standard. +client-default-roles=Standard klientroller +client-default-roles.tooltip=Roller fra denne klienten blir tildelt som standardrolle. +composite.available-roles.tooltip=Sikkerhetsdomene-roller knyttet til denne sammensatte rollen. +composite.associated-roles.tooltip=Sikkerhetsdomeneniv\u00E5-roller knyttet til denne sammensatte rollen. +composite.available-roles-client.tooltip=Roller fra denne klienten kan du assosiere med denne sammensatte rollen. +composite.associated-roles-client.tooltip=Klientroller knyttet til denne sammensatte rollen. +partial-import=Delvis import +partial-import.tooltip=Delvis import lar deg importere brukere, klienter og andre ressurser fra en tidligere eksportert json-fil. + +file=File +exported-json-file=Eksporter json-fil +import-from-realm=Importer fra sikkerhetsdomene +import-users=Importer brukere +import-groups=Importer grupper +import-clients=Importer klienter +import-identity-providers=Importer identitetsleverand\u00F8rer +import-realm-roles=Importer roller for sikkerhetsdomene +import-client-roles=Importer klientroller +if-resource-exists=Hvis en ressurs eksisterer +fail=Mislykkes +skip=Hopp over +overwrite=Skriv over +if-resource-exists.tooltip=Spesifiser hva som skal gj\u00F8res om du fors\u00F8ker \u00E5 importere en ressurs som allerede eksisterer. + +action=Handling +role-selector=Rollevelger +realm-roles.tooltip=Rolle for sikkerhetsdomene som kan velges. + +select-a-role=Velg en rolle +select-realm-role=Velg en rolle for sikkerhetsdomenet +client-roles.tooltip=Klientroller som kan velges. +select-client-role=Velg klientrolle + +client-template=Klientmal +client-template.tooltip=Klientmal som denne klienten arver konfigurasjonen fra +client-saml-endpoint=Endepunkt for klient-SAML +add-client-scope=Legg til klientmal + +manage=H\u00E5ndter +authentication=Autentisering +user-storage=Brukerlagring +user-federation=Brukerfederering +events=Hendelser +realm-settings=Innstillinger for sikkerhetsdomene +configure=Konfigurer +select-realm=Velg sikkerhetsdomene +add=Legg til + +client-scope.name.tooltip=Navn p\u00E5 klientmal. M\u00E5 v\u00E6re unik i sikkerhetsdomenet. +client-scope.description.tooltip=Beskrivelse av klientmal +client-scope.protocol.tooltip=Hvilken SSO protokoll-konfigurasjon som blir levert av denne klientmalen + +add-user-federation-provider=Legg til leverand\u00F8r for brukerfederering +add-user-storage-provider=Legg til brukerlagringsleverand\u00F8r +required-settings=P\u00E5krevde innstillinger +provider-id=Leverand\u00F8r-ID +console-display-name=Konsoll vis navn +console-display-name.tooltip=Viser navn p\u00E5 leverand\u00F8r n\u00E5r den er lenket i administratorkonsollen. +priority=Prioritet +priority.tooltip=Prioritet av leverand\u00F8r n\u00E5r et oppslag av bruker utf\u00F8res. Lavest f\u00F8rst. +sync-settings=Innstillinger for synkronisering +periodic-full-sync=Fullstendig periodisk synkronisering +periodic-full-sync.tooltip=Skal fullstendig periodisk synkronisering av leverand\u00F8r-brukere til Keycloak v\u00E6re aktivert eller deaktivert +full-sync-period=Fullstendig synkroniseringsperiode +full-sync-period.tooltip=Periode for fullstendig synkronisering i sekunder +periodic-changed-users-sync=Periodisk synkronisering av endrede brukere +periodic-changed-users-sync.tooltip=Skal periodisk synkronisering av endrede eller nylig opprettede leverand\u00F8r-brukere til Keycloak v\u00E6re aktivert eller deaktivert +changed-users-sync-period=Synkroniseringsperiode for endrede brukere +changed-users-sync-period.tooltip=Periode for synkronisering av endrede eller nylig opprettede leverand\u00F8r-brukere i sekunder. +synchronize-changed-users=Synkroniser endrede brukere +synchronize-all-users=Synkroniser alle brukere +kerberos-realm=Sikkerhetsdomene for Kerberos +kerberos-realm.tooltip=Navn p\u00E5 kerberos-sikkerhetsdomene. For eksempel FOO.ORG +server-principal=Server principal +server-principal.tooltip=Fullstendig navn p\u00E5 server principal for HTTP-service som inkluderer server og domenenavn. For eksempel HTTP/host.foo.org@FOO.ORG +keytab=KeyTab +keytab.tooltip=Plassering av Kerberos-keytab fil som inneholder legitimasjonsdetaljer for server principal. For eksempel /etc/krb5.keytab +debug=Feils\u00F8king +debug.tooltip=Aktiver/deaktiver logging av feils\u00F8king til standard output for Krb5LoginModule. +allow-password-authentication=Tillat autentisering med passord +allow-password-authentication.tooltip=Aktiver/deaktivert muligheten for autentisering med brukernavn/passord mot databasen til Kerberos +edit-mode=Redigeringsmodus +edit-mode.tooltip=READ_ONLY betyr at passordoppdateringer ikke er tillatt, og at bruker alltid autentiseres med et Kerberos-passord. UNSYNCED betyr at bruker kan endre sitt passord i databasen til Keycloak og at denne vil bli brukt i stedet for Kerberos-passordet. +ldap.edit-mode.tooltip=READ_ONLY er et skrivebeskyttet LDAP-lager. WRITABLE betyr at data vil bli synkronisert tilbake til LDAP p\u00E5 foresp\u00F8rsel. UNSYNCED betyr at brukerdata vil bli importert, men vil ikke bli synkronisert tilbake til LDAP. +update-profile-first-login=Oppdater profil ved f\u00F8rste innlogging +update-profile-first-login.tooltip=Oppdater profil ved f\u00F8rste innlogging +sync-registrations=Synkroniser registreringer +ldap.sync-registrations.tooltip=Skal nylig opprettede brukere bli opprettet innenfor et LDAP-lager? Prioritet p\u00E5virker hvilken leverand\u00F8r som er valgt for \u00E5 synkronisere den nye brukeren. +vendor=Leverand\u00F8r +ldap.vendor.tooltip=LDAP leverand\u00F8r (provider) +username-ldap-attribute=Brukernavn LDAP-attributt +ldap-attribute-name-for-username=LDAP-attributtnavn for brukernavn +username-ldap-attribute.tooltip=Navn p\u00E5 LDAP-attributt, som er kartlagt som et Keycloak-brukernavn. For mange LDAP-serverleverand\u00F8rer kan dette v\u00E6re 'uid'. For Active directory kan dette v\u00E6re 'sAMAccountName' eller 'cn'. Attributtet burde v\u00E6re fylt for alle LDAP-brukeroppf\u00F8ringer om du vil importere fra LDAP til Keycloak. +rdn-ldap-attribute=RDN LDAP-attributt +ldap-attribute-name-for-user-rdn=LDAP-attributtnavn for RDN-bruker +rdn-ldap-attribute.tooltip=Navn p\u00E5 LDAP-attributt, som brukes som RDN (topp-attributt) for en typisk DN-bruker. Vanligvis er dette det samme som LDAP-attributtet for brukernavn, men det er ikke p\u00E5krevd. For eksempel for Active directory er det vanlig \u00E5 bruke cn' som RDN-attributt n\u00E5r attributtet for brukernavn kan v\u00E6re 'sAMAccountName'. +uuid-ldap-attribute=UUID LDAP-attributt +ldap-attribute-name-for-uuid=LDAP-attributtnavn for UUID. +uuid-ldap-attribute.tooltip=Navn p\u00E5 LDAP-attributtet, som brukes som en unik objekt-identifikator (UUID) for objekter i LDAP. For mange LDAP-serverleverand\u00F8rer er det 'entryUUID', men noen er annerledes. For eksempel for Active directory b\u00F8r det v\u00E6re 'objectGUID'. Hvis din LDAP-server ikke st\u00F8tter UUID, kan du bruke hvilket som helst annet attributt, som er ment \u00E5 v\u00E6re unikt blant LDAP-brukere i treet. For eksempel 'uid' eller 'entryDN'. +user-object-classes=Brukerobjektklasser +ldap-user-object-classes.placeholder=Objektklasser for LDAP-bruker (separert med komma) + +ldap-connection-url=LDAP tilkoblings URL +ldap-users-dn=LDAP brukere DN +ldap-bind-dn=LDAP bind DN +ldap-bind-credentials=LDAP bind innloggingsdetaljer +ldap-filter=LDAP filter +ldap.user-object-classes.tooltip=Alle verdier av LDAP objectClass-attributtet for brukere i LDAP er separert med komma. For eksempel, 'inetOrgPerson, organizationalPerson'. Nylig opprettede Keycloak-brukere vil bli skrevet til LDAP med alle disse objektklassene og eksisterende LDAP-brukeroppf\u00F8ringer vil bli funnet om de inneholder de samme objektklassene. + +connection-url=Tilkoblings URL +ldap.connection-url.tooltip=Tilkoblings URL din til LDAP-server +test-connection=Testkobling +users-dn=DN-brukere +ldap.users-dn.tooltip=Fullstendig DN av LDAP-tre hvor dine brukere befinner seg. Denne spesifikke DN er forelder til LDAP-brukere. Den kan for eksempel v\u00E6re 'ou=users,dc=example,dc=com' hvis din typiske bruker vil ha en DN som 'uid=john,ou=users,dc=example,dc=com' +authentication-type=Autentiseringstype +ldap.authentication-type.tooltip=LDAP Autentiseringstype. For \u00F8yeblikket er kun mekanismene 'ingen' (anonym LDAP autentisering) eller 'enkel' (bind innloggingsdetaljer) tilgjengelig. +bind-dn=Bind DN +ldap.bind-dn.tooltip=DN av LDAP-administrator, som kan brukes av Keycloak for \u00E5 aksessere LDAP-server +bind-credential=Bind innloggingsdetaljer +ldap.bind-credential.tooltip=Passord for LDAP administrator +test-authentication=Testautentisering +custom-user-ldap-filter=Egendefinert filter for LDAP-bruker +ldap.custom-user-ldap-filter.tooltip=TilleggsLDAP-filter for \u00E5 filtrere s\u00F8kte brukere. La filteret v\u00E6re tomt om du ikke trenger et ekstra filter. Pass p\u00E5 at den starter med '(' og slutter med ')' +search-scope=Scope for s\u00F8k +ldap.search-scope.tooltip=For et niv\u00E5 s\u00F8ker vi etter brukere kun i DNser spesifisert av bruker-DNser. For subtre s\u00F8ker vi i hele subtreet. Se LDAP dokumentasjon for mer informasjon. +use-truststore-spi=Bruk Truststore SPI +ldap.use-truststore-spi.tooltip=Spesifiserer om LDAP-koblingen vil bruke truststore SPI med truststore konfigurert i keycloak-server.json. 'Alltid' betyr at den alltid vil brukes. 'Aldri' betyr at den ikke brukes. 'Kun for ldaps' betyr at den vil brukes hvis din koblings URL bruker ldaps. Merk at selv om keycloak-server.json ikke er konfigurert, vil default Java cacerts eller sertifikat spesifisert i 'javax.net.ssl.trustStore' bli brukt. +connection-pooling=Connection Pooling +ldap.connection-pooling.tooltip=Burde Keycloak bruke connection pooling for \u00E5 aksessere LDAP-serveren? +ldap.pagination.tooltip=St\u00F8tter LDAP-serveren paginering? +kerberos-integration=Kerberos Integrasjon +allow-kerberos-authentication=Tillat autentisering med Kerberos +ldap.allow-kerberos-authentication.tooltip=Aktiver/deaktiver HTTP autentisering av brukere med SPNEGO/Kerberos tokens. Informasjonen om autentiserte brukere vil bli klargjort fra denne LDAP-serveren. +use-kerberos-for-password-authentication=Bruk Kerberos for autentisering av passord +ldap.use-kerberos-for-password-authentication.tooltip=Bruk Kerberos-innloggingsmodul for \u00E5 autentisere brukernavn/passord mot Kerberos-server i stedet for autentisering mot LDAP-server med Directory Service API +batch-size=Batch st\u00F8rrelse +ldap.batch-size.tooltip=Antall LDAP-brukere som vil bli importert fra LDAP til Keycloak innen en enkelt transaksjon. +ldap.periodic-full-sync.tooltip=Om fullstendig periodisk synkronisering av LDAP-brukere til Keycloak vil v\u00E6re aktivert eller deaktivert. +ldap.periodic-changed-users-sync.tooltip=Om periodisk synkronisering av endret eller nylig opprettede LDAP-brukere til Keycloak vil v\u00E6re aktivert eller deaktivert. +ldap.changed-users-sync-period.tooltip=Tidsperiode for synkronisering av endrede eller nylig opprettede LDAP-brukere i sekunder. +user-federation-mappers=Mappere for brukerfederering +create-user-federation-mapper=Opprett mapper for brukerfederering +add-user-federation-mapper=Legg til mapper for brukerfederering +provider-name=Leverand\u00F8rnavn +no-user-federation-providers-configured=Ingen leverand\u00F8r for brukerfederering er konfigurert +no-user-storage-providers-configured=Ingen leverand\u00F8r for brukerlagring er konfigurert +add-identity-provider=Legg til identitetsleverand\u00F8r +add-identity-provider-link=Legg til lenke til identitetsleverand\u00F8r +identity-provider=Identitetsleverand\u00F8r +identity-provider-user-id=Bruker-ID for identitetsleverand\u00F8r +identity-provider-user-id.tooltip=Unik ID for brukeren p\u00E5 identitetsleverand\u00F8rens side +identity-provider-username=Brukernavn til identitetsleverand\u00F8r +identity-provider-username.tooltip=Brukernavn p\u00E5 identitetsleverand\u00F8rens side +pagination=Paginering + +browser-flow=Nettleserflyt +browser-flow.tooltip=Velg flyten du \u00F8nsker \u00E5 bruke for nettleser-autentisering. +registration-flow=Registreringsflyt +registration-flow.tooltip=Velg flyten du \u00F8nsker for registrering. +direct-grant-flow=Direct Grant Flyt +direct-grant-flow.tooltip=Velg flyten du \u00F8nsker \u00E5 bruke for direct grant autentisering. +reset-credentials=Tilbakestill innloggingsdetaljer +reset-credentials.tooltip=Velg flyten du \u00F8nsker \u00E5 bruke n\u00E5r brukeren har glemt sine p\u00E5loggingsdetaljer. +client-authentication=Autentisering av klient +client-authentication.tooltip=Velg flyten du \u00F8nsker \u00E5 bruke for autentisering av klienter. +new=Ny +copy=Kopi +add-execution=Legg til eksekvering +add-flow=Legg til flyt +auth-type=Type auth +requirement=Krav +config=Konfig +no-executions-available=Ingen tilgjengelig eksekvering +authentication-flows=Autentiseringsflyt +create-authenticator-config=Opprett konfig for autentikator +authenticator.alias.tooltip=Navn p\u00E5 konfigurasjonen +otp-type=Type engangskode +time-based=Tidsbasert +counter-based=Tellerbasert +otp-type.tooltip=Totp er et tidsbasert engangspassord. 'hotp' er et teller basert engangspassord hvor serveren f\u00F8lger med p\u00E5 en teller som den kan hashe mot. +otp-hash-algorithm=OTP hash-algoritme +otp-hash-algorithm.tooltip=Hva slags hashing algoritme skal brukes for \u00E5 generere OTP. +number-of-digits=Antall siffer +otp.number-of-digits.tooltip=Hvor mange sifre skal OTP ha? +look-ahead-window=Look Ahead Window +otp.look-ahead-window.tooltip=Hvor langt frem b\u00F8r serveren se i tilfelle token generator og server er ute av tidssynkronisering eller tellersynkronisering? +initial-counter=Initiell teller +otp.initial-counter.tooltip=Hva b\u00F8r den initielle tellerverdien v\u00E6re? +otp-token-period=Engangskode token +otp-token-period.tooltip=Hvor mange sekunder burde et engangskode token v\u00E6re gyldig? Standard er satt til 30 sekunder. +table-of-password-policies=Liste over policy for passord +add-policy.placeholder=Legg til policy... +policy-type=Type policy +policy-value=Verdi for policy +admin-events=administratorhendelser +admin-events.tooltip=Viser lagrede administratorhendelser for sikkerhetsdomenet. Hendelser relaterer til administratorkontoen, for eksempel opprettelse av et sikkerhetsdomene. For \u00E5 aktivere persistente hendelser g\u00E5 til konfig. +login-events=innloggingshendelser +filter=Filtrer +update=Oppdater +reset=Tilbakestill +operation-types=Operasjonstyper +resource-types=Ressurstyper +select-operations.placeholder=Velg operasjoner... +select-resource-types.placeholder=Velg ressursyper... +resource-path=Filsti for ressurs +resource-path.tooltip=Sorter etter filsti for ressurs. St\u00F8tter jokertegn '*' for \u00E5 sjekke om den er lik en del av stien, og '**' for \u00E5 sjekke flere deler. For eksempel 'realms/*/clients/asbc' vil v\u00E6re lik klient-ID asbc i alle sikkerhetsdomener, mens 'realms/master/**' er lik alt i mastersikkerhetsdomenet. +date-(from)=Dato (Fra) +date-(to)=Dato (Til) +authentication-details=Autentiseringsdetaljer +ip-address=IP-adresse +time=Tid +operation-type=Operasjonstype +resource-type=Ressurstype +auth=Auth +representation=Representasjon +register=Registrer +required-action=P\u00E5krevd handling +default-action=Standard handling +auth.default-action.tooltip=Hvis aktivert, vil enhver ny bruker bli tilordnet denne p\u00E5krevde handlingen. +no-required-actions-configured=Ingen p\u00E5krevde handlinger er konfigurert +defaults-to-id=Standardverdi er id +flows=Flyt +bindings=Bindinger +required-actions=P\u00E5krevde handlinger +password-policy=Passordpolicy +otp-policy=Policy for engangskode +user-groups=Brukergruppe +default-groups=Standardgrupper +groups.default-groups.tooltip=Sett med grupper som nye brukere automatisk vil bli medlem av. +cut=Klipp +paste=Lim inn + +create-group=Opprett gruppe +create-authenticator-execution=Opprett autentiseringsutf\u00F8relse +create-form-action-execution=Opprett skjema for handlingsutf\u00F8relse +create-top-level-form=Opprett skjema for toppniv\u00E5 +flow.alias.tooltip=Spesifiserer visningsnavn for flyten. +top-level-flow-type=Flytstype for toppniv\u00E5 +flow.generic=generisk +flow.client=klient +top-level-flow-type.tooltip=Hvilken type toppniv\u00E5 flyt er det? Type 'klient' brukes for autentisering av klienter (applikasjoner) n\u00E5r generisk brukes for brukere og alt annet +create-execution-flow=Opprett eksekveringsflyt +flow-type=Type av flyt +flow.form.type=skjema +flow-type.tooltip=Hva slags skjema det er +form-provider=Skjemaleverand\u00F8r +default-groups.tooltip=Nyopprettede eller registrerte brukere vil automatisk bli lagt til disse gruppene +select-a-type.placeholder=velg en type +available-groups=Tilgjengelige grupper +available-groups.tooltip=Velg en gruppe du \u00F8nsker \u00E5 legge til som standard. +value=Verdi +table-of-group-members=Liste over gruppemedlemmer +last-name=Etternavn +first-name=Fornavn +email=E-postadresse +toggle-navigation=Toggle navigasjon +manage-account=Administrer konto +sign-out=Logg ut +server-info=Serverinformasjon +resource-not-found=Ressurs ikke funnet... +resource-not-found.instruction=Vi kunne ikke finne ressursen du leter etter. Vennligst kontroller at nettadressen du oppga er riktig. +go-to-the-home-page=G\u00E5 til hjemmeside » +page-not-found=Side ikke funnet... +page-not-found.instruction=Vi kunne ikke finne siden du ser etter. Vennligst kontroller at nettadressen du skrev inn er riktig. +events.tooltip=Viser lagrede hendelser for sikkerhetsdomenet. Hendelser er relatert til brukerkontoer, for eksempel innlogging av bruker. For \u00E5 aktivere persistente hendelser g\u00E5 til konfig. +select-event-types.placeholder=Velg hendelsestyper... +events-config.tooltip=Viser konfigurasjonsalternativer for \u00E5 muliggj\u00F8re persistente bruker- og administratorhendelser. +select-an-action.placeholder=Velg en handling... +event-listeners.tooltip=Konfigurer hvilke lyttere som skal motta eventer fra sikkerhetsdomenet. +login.save-events.tooltip=Hvis aktivert vil innloggingshendelser bli lagret i databasen, noe som gj\u00F8r hendelsene tilgjengelige for administrator og kontoadministrasjonskonsoll. +clear-events.tooltip=Sletter alle hendelser fra databasen. +events.expiration.tooltip=Setter utl\u00F8pstid for hendelser. Utl\u00F8pte hendelser vil med jevne mellomrom bli slettet fra databasen. +admin-events-settings=Innstillinger for administratorhendelser +save-events=Lagre hendelser +admin.save-events.tooltip=Hvis aktivert vil administratorhendelser bli lagret i databasen, som vil gj\u00F8re hendelsene tilgjengelige i administrasjonskonsollen. +saved-types.tooltip=Konfigurer hvilke eventtyper som lagres. +include-representation=Inkluder representasjon +include-representation.tooltip=Inkluder JSON-representasjon for \u00E5 skape og oppdatere foresp\u00F8rsler. +clear-admin-events.tooltip=Sletter alle administratorhendelser i databasen. +server-version=Serverversjon +info=Info +providers=Leverand\u00F8rer +server-time=Servertid +server-uptime=Oppetid for server +memory=Minne +total-memory=Totalt minne +free-memory=Ledig minne +used-memory=Brukt minne +system=System +current-working-directory=Gjeldende arbeidskatalog +java-version=Java versjon +java-vendor=Java leverand\u00F8r +java-runtime=Java Runtime +java-vm=Java VM +java-vm-version=Java VM versjon +java-home=Java hjem +user-name=Brukers navn +user-timezone=Tidssone for bruker +user-locale=Lokalitet for bruker +system-encoding=Systemenkoding +operating-system=Operativsystem (OS) +os-architecture=OS arkitektur +spi=SPI +granted-roles=Tildelte roller +granted-protocol-mappers=Innvilgede protokollmappere +additional-grants=Tillegsrettigheter +consent-created-date=Opprettet +consent-last-updated-date=Sist oppdatert +revoke=Opphev +new-password=Nytt passord +password-confirmation=Passord bekreftelse +reset-password=Tilbakestill passord +credentials.temporary.tooltip=Hvis aktivert, er brukeren p\u00E5krevd til \u00E5 endre passordet ved neste innlogging +remove-totp=Fjern OTP +credentials.remove-totp.tooltip=Fjern generator for engangspassord for bruker. +reset-actions=Tilbakestill handlinger +credentials.reset-actions.tooltip=Sett med handlinger som kan utf\u00F8res ved \u00E5 sende en bruker en Tilbakestillingshandling for E-post. 'Verifiser e-post' sender en e-post til brukeren for \u00E5 verifisere e-postadresse. 'Oppdater profil' krever at bruker legger inn personlig informasjon. 'Oppdater passord' krever at bruker skriver inn et nytt passord. 'Konfigurer OTP' krever installasjon av en passordgenerator for mobil. +reset-actions-email=Tilbakestillingshandling for E-post. +send-email=Send e-post +credentials.reset-actions-email.tooltip=Sender en e-post til en bruker med en lenke. Ved \u00E5 klikke p\u00E5 denne lenken vil brukeren f\u00E5 lov til \u00E5 utf\u00F8re tilbakestillingshandlinger. Brukeren trenger ikke logge inn f\u00F8r dette. For eksempel, sett handlingen for \u00E5 oppdatere passord, klikk p\u00E5 denne knappen, og brukeren vil kunne endre deres passord uten \u00E5 logge inn. +add-user=Legg til bruker +created-at=Opprettet ved +user-enabled=Bruker aktivert +user-enabled.tooltip=En deaktivert bruker kan ikke logge inn. +user-temporarily-locked=Bruker er midlertidig l\u00E5st. +user-temporarily-locked.tooltip=Brukeren kan ha blitt l\u00E5st p\u00E5 grunn av at innloggingsfors\u00F8k har feilet for mange ganger. +unlock-user=L\u00E5s opp bruker +federation-link=Federeringslenke +email-verified=E-post verifisert +email-verified.tooltip=Har brukerens e-post blitt verifisert? +required-user-actions=P\u00E5krevde brukerhandlinger +required-user-actions.tooltip=Krev en handling n\u00E5r brukeren logger inn. 'Verifiser e-post' sender en e-post til brukeren for \u00E5 verifisere deres e-postadresse. 'Oppdater profil' krever at bruker legger inn personlig informasjon. 'Oppdater passord' krever at bruker skriver inn et nytt passord. 'Konfigurer OTP' krever installasjon av en passordgenerator for mobil. +locale=Lokalitet +select-one.placeholder=Velg en... +impersonate=Utgi deg for \u00E5 v\u00E6re bruker +impersonate-user=Utgi deg for \u00E5 v\u00E6re bruker +impersonate-user.tooltip=Logg inn som denne brukeren. Hvis bruker er i samme sikkerhetsdomene som deg, vil din n\u00E5v\u00E6rende innloggede sesjon bli logget ut f\u00F8r du blir logget inn som denne brukeren. +identity-provider-alias=Alias for identitetsleverand\u00F8r +provider-user-id=Bruker-ID for leverand\u00F8r +provider-username=Brukernavn for leverand\u00F8r +no-identity-provider-links-available=Ingen lenker for identitetsleverand\u00F8r er tilgjengelig +group-membership=Gruppemedlemskap +leave=Forlat +group-membership.tooltip=Gruppen som brukeren er medlem av. Velg en gruppe p\u00E5 listen og klikk p\u00E5 'Forlat' for \u00E5 forlate gruppen. +membership.available-groups.tooltip=Grupper som brukere kan bli medlem av. Velg en gruppe og klikk p\u00E5 'Bli med' knappen. +table-of-realm-users=Liste over sikkerhetsdomenebrukere +view-all-users=Se alle brukere +unlock-users=L\u00E5s opp brukere +no-users-available=Ingen brukere tilgjengelig +users.instruction=Vennligst skriv inn et s\u00F8k, eller klikk p\u00E5 Se alle brukere +consents=Samtykke +started=Startet +logout-all-sessions=Logg ut av alle sesjoner +logout=Logg ut +new-name=Nytt navn +ok=Ok +attributes=Attributter +role-mappings=Mapping av roller +members=Medlemmer +details=Detaljer +identity-provider-links=Lenker til identitetsleverand\u00F8r +register-required-action=Registrer p\u00E5krevd handling +gender=Kj\u00F8nn +address=Adresse +phone=Telefon +profile-url=Profil URL +picture-url=Bilde URL +website=Nettsted +import-keys-and-cert=Importer n\u00F8kler og sertifikat +import-keys-and-cert.tooltip=Last opp klientens n\u00F8kkelpar og sertifikat. +upload-keys=Last opp n\u00F8kler +download-keys-and-cert=Last ned n\u00F8kler og sertifikat +no-value-assigned.placeholder=Ingen tilordnet verdi +remove=Fjern +no-group-members=Ingen gruppemedlemmer +temporary=Midlertidig +join=Bli med +event-type=Hendelsestype +events-config=Hendelseskonfigurasjon +event-listeners=Hendelseslyttere +login-events-settings=Innstillinger for innloggingshendelser +clear-events=Fjern hendelser +saved-types=Lagrede typer +clear-admin-events=Fjern administratorhendelser +clear-changes=Fjern endringer +error=Feil + +# Authz + # Authz Common +authz-authorization=Autorisasjon +authz-owner=Eier +authz-uri=URI +authz-scopes=Scope +authz-resource=Ressurs +authz-resource-type=Ressurstype +authz-resources=Ressurser +authz-scope=Scope +authz-authz-scopes=Autorisasjonsscopes +authz-policies=Policier +authz-permissions=Tillatelser +authz-evaluate=Evaluer +authz-icon-uri=Ikon URI +authz-icon-uri.tooltip=En URI som peker til et ikon. +authz-select-scope=Velg et scope +authz-select-resource=Velg en ressurs +authz-associated-policies=Assosierte policier +authz-any-resource=Enhver ressurs +authz-any-scope=Ethvert scope +authz-any-role=Enhver rolle +authz-policy-evaluation=Evaluering av policy +authz-select-client=Velg en klient +authz-select-user=Velg en bruker +authz-entitlements=Rettigheter +authz-no-resources=Ingen ressurser +authz-result=Resultat +authz-authorization-services-enabled=Autorisasjon aktivert +authz-authorization-services-enabled.tooltip=Aktiver/deaktiver finkornet autorisasjonssupport for en klient +authz-required=P\u00E5krevd + +# Authz Settings +authz-import-config.tooltip=Importer en JSON-fil som inneholder innstillinger for autorisasjon for denne ressursserveren. + +authz-policy-enforcement-mode=Modus for h\u00E5ndhevelse av policy +authz-policy-enforcement-mode.tooltip=Modus for h\u00E5ndhevelse av policy dikterer hvordan policier blir h\u00E5ndhevet n\u00E5r autorisasjonsforesp\u00F8rsler blir evaluert. 'H\u00E5ndhevende' betyr at foresp\u00F8rsler blir nektet som standard selv om det ikke er en policy knyttet til en gitt ressurs. 'Ettergivende' betyr at foresp\u00F8rsler blir tillatt selv om det ikke er en policy knyttet til en gitt ressurs. 'Deaktivert' deaktiverer fullstendig evalueringen av policier og tillater tilgang til enhver ressurs. +authz-policy-enforcement-mode-enforcing=H\u00E5ndhevende +authz-policy-enforcement-mode-permissive=Ettergivende +authz-policy-enforcement-mode-disabled=Deaktivert + +authz-remote-resource-management=H\u00E5ndtering av ekstern ressurs +authz-remote-resource-management.tooltip=Skal ressursene bli h\u00E5ndtert eksternt av ressursserveren? Hvis satt til false kan ressursene kun bli h\u00E5ndtert fra denne administratorkonsollen. + +authz-export-settings=Eksporter innstillinger +authz-export-settings.tooltip=Eksporter og last ned alle innstillinger for autorisasjon for denne ressursserveren. + + # Authz Resource List +authz-no-resources-available=Ingen tilgjengelige ressurser. +authz-no-scopes-assigned=Ingen tildelte scopes. +authz-no-type-defined=Ingen definert type. +authz-no-permission-assigned=Ingen tillatelse er tildelt. +authz-no-policy-assigned=Ingen tildelt policy. +authz-create-permission=Opprett tillatelse + + # Authz Resource Detail +authz-add-resource=Legg til ressurs +authz-resource-name.tooltip=Et unikt navn for denne ressursen. Navnet kan bli brukt til \u00E5 identifisere en ressurs og er nyttig i sp\u00F8rringer for en bestemt ressurs. +authz-resource-owner.tooltip=Eieren av denne ressursen. +authz-resource-type.tooltip=Ressurstype. Den kan brukes til \u00E5 gruppere ulike ressursinstanser av samme type. +authz-resource-uri.tooltip=En URI som ogs\u00E5 kan brukes for \u00E5 identifisere denne ressursen. +authz-resource-scopes.tooltip=Scopes assosiert med denne ressursen. + + # Authz Scope List +authz-add-scope=Legg til scope +authz-no-scopes-available=Ingen tilgjengelige scopes. + + # Authz Scope Detail +authz-scope-name.tooltip=Et unikt navn for dette scopet. Navnet kan bli brukt for \u00E5 identifisere et scope, og er nyttig i sp\u00F8rringer for en bestemt ressurs. + + # Authz Policy List +authz-all-types=Alle typer +authz-create-policy=Opprett policy +authz-no-policies-available=Ingen tilgjengelige policier. + + # Authz Policy Detail +authz-policy-name.tooltip=Navnet p\u00E5 denne policien. +authz-policy-description.tooltip=En beskrivelse av denne policien. +authz-policy-logic=Logikk +authz-policy-logic-positive=Positiv +authz-policy-logic-negative=Negativ +authz-policy-logic.tooltip=Logikken som dikterer hvordan beslutningspolicien skal utf\u00F8rres. Hvis 'Positiv', vil resulterende effekt (tillate eller nekte) oppn\u00E5dd under evalueringen av denne policien bli brukt for \u00E5 ta en beslutning. Hvis 'Negativ', vil resulterende effekt bli opphevet, med andre ord blir en tillatelse til et avslag og motsatt. +authz-policy-apply-policy=Anvend policy +authz-policy-apply-policy.tooltip=Spesifiserer alle policies som m\u00E5 bli anvendt for scopes definert av denne policien eller tillatelsen. +authz-policy-decision-strategy=Beslutningsstrategi +authz-policy-decision-strategy.tooltip=Beslutningsstrategi som dikterer hvordan policies knyttet til en gitt policy blir evaluert og hvordan endelig avgj\u00F8relse oppn\u00E5s. 'Bekreftende' betyr at minst en policy m\u00E5 evalueres til en positiv beslutning for at den samlede avgj\u00F8relsen kan bli positiv. 'Enstemmig' betyr at alle policies m\u00E5 evalueres til en positiv beslutning for at den samlede avgj\u00F8relsen kan bli positiv. 'Konsensus' betyr at antall positive beslutninger m\u00E5 v\u00E6re h\u00F8yere enn antall negative beslutninger. Hvis antallet av positive og negative er likt, blir den samlede avgj\u00F8relsen negativ. +authz-policy-decision-strategy-affirmative=Bekreftende +authz-policy-decision-strategy-unanimous=Enstemmig +authz-policy-decision-strategy-consensus=Konsensus +authz-select-a-policy=Velg en policy + + # Authz Role Policy Detail +authz-add-role-policy=Legg til policy for rolle +authz-no-roles-assigned=Ingen tildelte roller. +authz-policy-role-roles.tooltip=Spesifiser sikkerhetsdomenerolle(r) som tillates av denne policien. +authz-policy-role-clients.tooltip=Velger en klient for \u00E5 filtrere klientroller som kan bli tatt i bruk av denne policien. +authz-policy-role-client-roles.tooltip=Spesifiserer klientroller tillatt av denne policien. + + # Authz User Policy Detail +authz-add-user-policy=Legg til policy for bruker +authz-no-users-assigned=Ingen tildelte brukere. +authz-policy-user-users.tooltip=Spesifiser bruker(e) som tillates av denne policien. + + # Authz Client Policy Detail +authz-add-client-policy=Legg til policy for klient +authz-no-clients-assigned=Ingen tildelte klienter. +authz-policy-client-clients.tooltip=Spesifiser klient(er) som tillates av denne policien. + + # Authz Time Policy Detail +authz-add-time-policy=Legg til policy for tid +authz-policy-time-not-before.tooltip=Definerer tiden f\u00F8r policien M\u00C5 IKKE innvilges. Denne innvilges kun om gjeldende dato/tid er f\u00F8r eller lik denne verdien. +authz-policy-time-not-on-after=Ikke p\u00E5 eller etter +authz-policy-time-not-on-after.tooltip=Definerer tiden etter en policy M\u00C5 IKKE innvilges. Denne innvilges kun om gjeldende dato/tid er f\u00F8r eller lik denne verdien. + + # Authz JS Policy Detail +authz-add-js-policy=Legg til policy for JavaScript +authz-policy-js-code=Kode +authz-policy-js-code.tooltip=JavaScript-koden angir betingelsene for denne politikken. + + + # Authz Aggregated Policy Detail +authz-aggregated=Aggregert +authz-add-aggregated-policy=Legg til policy for aggregering. + + # Authz Permission List +authz-no-permissions-available=Ingen tilgjengelige tillatelser. + + # Authz Permission Detail +authz-permission-name.tooltip=Navnet p\u00E5 denne tillatelsen. +authz-permission-description.tooltip=En beskrivelse av denne tillatelsen. + + # Authz Resource Permission Detail +authz-add-resource-permission=Legg til tillatelse for ressurs. +authz-permission-resource-apply-to-resource-type=Bruk p\u00E5 ressurstype +authz-permission-resource-apply-to-resource-type.tooltip=Spesifiserer om denne tillatelsen skal gjelde for alle ressurser med en gitt type. I dette tilfellet vil tillatelsen bli evaluert for alle instanser av gitt ressurstype. +authz-permission-resource-resource.tooltip=Spesifiserer at denne tillatelsen m\u00E5 bli brukt for en spesifikk ressursinstans. +authz-permission-resource-type.tooltip=Spesifiserer at denne tillatelsen m\u00E5 bli anvendt for alle ressursinstanser for en gitt type. + + # Authz Scope Permission Detail +authz-add-scope-permission=Legg til tillatelse for scope +authz-permission-scope-resource.tooltip=Begrens scopes til de som er tilknyttet den valgte ressursen. Hvis dette ikke er valgt vil alle scopes v\u00E6re tilgjengelige. +authz-permission-scope-scope.tooltip=Spesifiserer at denne tillatelse m\u00E5 anvendes p\u00E5 en eller flere scopes. + + # Authz Evaluation +authz-evaluation-identity-information=Identitetsinformasjon +authz-evaluation-identity-information.tooltip=De tilgjengelige alternativene for \u00E5 konfigurere identitesinformasjon som vil bli brukt ved evaluering av policier. +authz-evaluation-client.tooltip=Velg klienten som vil utf\u00F8re denne autorisasjonsforesp\u00F8rselen. +authz-evaluation-user.tooltip=Velg en bruker hvis identitet vil bli brukt for \u00E5 s\u00F8ke tillatelser fra serveren. +authz-evaluation-role.tooltip=Velg en rolle som du vil knytte til den valgte brukeren. +authz-evaluation-new=Ny evaluering +authz-evaluation-re-evaluate=Re-evaluering +authz-evaluation-previous=Forrige evaluering +authz-evaluation-contextual-info=Kontekstuell informasjon +authz-evaluation-contextual-info.tooltip=Tilgjengelige valg for \u00E5 konfigurere enhver kontekstuell informasjon som vil bli brukt ved evaluering av policier. +authz-evaluation-contextual-attributes=Kontekstuelle attributter +authz-evaluation-contextual-attributes.tooltip=Ethvert attributt gitt av et kj\u00F8rende milj\u00F8 eller ved utf\u00F8relseskontekst. +authz-evaluation-permissions.tooltip=De tilgjengelige alternativene for \u00E5 konfigurere tillatelsene for hvilke policies som skal anvendes. +authz-evaluation-evaluate=Evaluer +authz-evaluation-any-resource-with-scopes=Enhver ressurs med scope(s) +authz-evaluation-no-result=Kunne ikke f\u00E5 et resultat for den gitte autorisasjonsforesp\u00F8rselen. Sjekk om de tilgjengelige ressursene er tilknyttet en policy. +authz-evaluation-no-policies-resource=Ingen policies ble funnet for denne ressursen. +authz-evaluation-result.tooltip=Det samlede resultatet for denne foresp\u00F8rselen for tillatelse. +authz-evaluation-scopes.tooltip=Liste over tillatte scopes. +authz-evaluation-policies.tooltip=Detaljer om hvilke policies som ble evaluert og deres avgj\u00F8relser. +authz-evaluation-authorization-data=Respons +authz-evaluation-authorization-data.tooltip=Representerer et token som b\u00E6rer autorisasjonsdata som et resultat av prosesseringen av en autorisasjonsforesp\u00F8rsel. Denne representasjonen er hva Keycloak sender ut til klienter som ettersp\u00F8r tillatelser. Sjekk autorisasjonsclaim for tillatelsene som ble gitt basert p\u00E5 n\u00E5v\u00E6rende autorisasjonsforesp\u00F8rsel. +authz-show-authorization-data=Vis autorisasjonsdata diff --git a/keycloak-themes/base/admin/messages/admin-messages_pl.properties b/keycloak-themes/base/admin/messages/admin-messages_pl.properties new file mode 100644 index 0000000..dd55d69 --- /dev/null +++ b/keycloak-themes/base/admin/messages/admin-messages_pl.properties @@ -0,0 +1 @@ +# encoding: UTF-8 diff --git a/keycloak-themes/base/admin/messages/admin-messages_pt_BR.properties b/keycloak-themes/base/admin/messages/admin-messages_pt_BR.properties new file mode 100644 index 0000000..dba51b2 --- /dev/null +++ b/keycloak-themes/base/admin/messages/admin-messages_pt_BR.properties @@ -0,0 +1,1097 @@ +#encoding: utf-8 +consoleTitle=Console de Administração do Keycloak + +# Common messages +enabled=Habilitado +name=Nome +displayName=Nome de exibição +displayNameHtml=Nome de exibição HTML +save=Salvar +cancel=Cancelar +onText=Sim +offText=Não +client=Cliente +clients=Clientes +clear=Limpar +selectOne=Selecione Um... + +true=Sim +false=Não + +endpoints=Endpoints + +# Realm settings +realm-detail.enabled.tooltip=Usuários e clientes somente podem acessar um Realm se ele estiver habilitado +realm-detail.oidc-endpoints.tooltip=Exibe a configuração dos endpoints do OpenID Connect +registrationAllowed=Cadastro de usuário +registrationAllowed.tooltip=Habilita/desabilita a página de cadastro. Um link para a página de cadastro também será exibido na tela de login. +registrationEmailAsUsername=Email como nome de usuário +registrationEmailAsUsername.tooltip=Se habilitado o campo 'nome de usuário' será ocultado no formulário de cadastro e o e-mail será usado como nome de usuário para o novo cadastro. +editUsernameAllowed=Editar nome de usuário +editUsernameAllowed.tooltip=Se habilitado, o campo nome de usuário é editável, senão será apenas leitura. +resetPasswordAllowed=Esqueci a senha +resetPasswordAllowed.tooltip=Exibe um link na página de login para o usuário clicar quando houver esquecido suas credenciais. +rememberMe=Lembrar me +rememberMe.tooltip=Exibe um checkbox na página de login para permitir ao usuário continuar logado entre restarts do browser até que a sessão expire. +verifyEmail=Verificar e-mail +verifyEmail.tooltip=Requer que o usuário verifique seu endereço de e-mail na primeira vez que efetuar login. +sslRequired=SSL requerido +sslRequired.option.all=todas requisições +sslRequired.option.external=requisições externas +sslRequired.option.none=nunca +sslRequired.tooltip=É necessário SSL? 'Nunca' significa que HTTPS não é requerido para nenhum endereço IP cliente. 'Requisições externas' significa que localhost e IPs privados podem acessar sem HTTPS. 'Todas requisições' significa que HTTPS é requerido para todos os endereços IPs. +publicKey=Chave pública +privateKey=Chave privada +gen-new-keys=Gerar novas chaves +certificate=Certificado +host=Host +smtp-host=Host SMTP +port=Porta +smtp-port=Porta SMTP (valor padrão: 25) +from=Remetente +sender-email-addr=Endereço de e-mail do remetente +enable-ssl=Habilitar SSL +enable-start-tls=Habilitar StartTLS +enable-auth=Habilitar autenticação +username=Usuário +login-username=Nome de usuário para login +password=Senha +login-password=Senha para login +login-theme=Tema de login +login-theme.tooltip=Selecione o tema para páginas de login, OTP, grant, cadastro e recuperar senha. +account-theme=Tema para conta +account-theme.tooltip=Selecione o tema para as páginas de administração de conta do usuário. +admin-console-theme=Tema para console de administração +select-theme-admin-console=Selecione o tema para o console de administração. +email-theme=Tema de e-mail +select-theme-email=Selecione o tema para os e-mail que são enviados pelo servidor. +i18n-enabled=Habilitar internacionalização +supported-locales=Locais disponíveis +supported-locales.placeholder=Digite um local e pressione Enter +default-locale=Local padrão +#localization-upload-file=Upload localization JSON file +#missing-locale=Missing locale. +#missing-file=Missing file. Please select a file to upload. +#localization-file.upload.success=The localization data has been loaded from file. +#localization-file.upload.error=The file can not be uploaded. Please verify the file. +#localization-show=Show realm specific localizations +#no-localizations-configured=No realm specific localizations configured +#add-localization-text=Add localization text +#locale.create.success=The Locale has been created. +#localization-text.create.success=The localization text has been created. +#localization-text.update.success=The localization text has been updated. +#localization-text.remove.success=The localization text has been deleted. +realm-cache-clear=Realm Cache +realm-cache-clear.tooltip=Remove todas as entradas do cache de realm (isto irá remover as entradas para todos os realms) +user-cache-clear=Cache de usuário +user-cache-clear.tooltip=Remove todas as entradas do cache de usuário (isto irá remover as entradas de todos os realms) +revoke-refresh-token=Revogar Token de Atualização +revoke-refresh-token.tooltip=Se habilitado os tokens de atualização podem ser utilizados somente uma vez. Caso contrário os tokens de atualização não são revogados quando utilizados e podem ser utilizados várias vezes. +sso-session-idle=Sessão SSO inativa +sso-session-idle.tooltip=Tempo que uma sessão pode ficar inativa antes de expirar. Tokens e sessões de navegador são invalidados quando uma sessão é expirada. +seconds=Segundos +minutes=Minutos +hours=Horas +days=Dias +sso-session-max=Sessão SSO Máxima +sso-session-max.tooltip=Tempo máximo antes que uma sessão seja expirada. Tokens e sessões de navegador são invalidados quando uma sessão é expirada. +offline-session-idle=Sessão Offline Inativa +offline-session-idle.tooltip=Tempo que uma sessão offline pode ficar inativa antes de expirar. Você precisa utilizar um token de atualização offline pelo menos uma vez neste período, caso contrário a sessão offline será expirada. +access-token-lifespan=Duração do Token de Acesso +access-token-lifespan.tooltip=Tempo máximo antes que um token de acesso expire. Recomenda-se que este valor seja menor em relação ao tempo de inativação do inativação do SSO. +access-token-lifespan-for-implicit-flow=Duração do token de acesso para fluxos Implícitos +access-token-lifespan-for-implicit-flow.tooltip=Tempo máximo antes que um token de acesso emitido durante o Fluxo Implícito do OpenID Connect expire. Recomenda-se que este valor seja menor em relação ao tempo de inativação do SSO. Não há posibilidade de atualizar este token durante o fluxo implícito, sendo este o motivo de existir um tempo limite diferente para a 'Duração do Token de Acesso'. +client-login-timeout=Tempo limite para login do Cliente +client-login-timeout.tooltip=Tempo máximo que um cliente tem para finalizar o procolo do token de acesso. Normalmente deve ser 1 minuto. +login-timeout=Tempo máximo do Login +login-timeout.tooltip=Tempo máximo que um usuário tempo para completar o login. É recomendado que seja relativamente longo - 30 minutos ou mais. +login-action-timeout=Tempo limite da ação de Login +login-action-timeout.tooltip=Tempo máximo que um usuário tem para completar as ações relacionadas ao login como atualizar senhas ou configurar totp. É recomendado que seja relativamente longo - 5 minutos ou mais. +headers=Cabeçalhos +brute-force-detection=Detecção de ataque de Força Bruta +x-frame-options=X-Frame-Options +x-frame-options-tooltip=O valor padrão impede páginas de serem incluídas via non-origin iframes (clique no label para mais informações) +content-sec-policy=Content-Security-Policy +content-sec-policy-tooltip=O valor padrão impede páginas de serem incluídas via non-origin iframes (clique no label para mais informações) +content-type-options=X-Content-Type-Options +content-type-options-tooltip=O valor padrão impede Internet Explorer and Google Chrome de realizarem MIME-sniffing em uma resposta diferente do content-type declarado (clique no label para mais informações) +max-login-failures=Falhas de login +max-login-failures.tooltip=Quantas falhas de login antes que a espera seja habilitada. +wait-increment=Incremento de Espera +wait-increment.tooltip=Quando a quantidade de falhas for alcançada, quanto tempo o usuário deve aguardar antes de tentar novamente? +quick-login-check-millis=Verificação de Quick Login em Milli Seconds +quick-login-check-millis.tooltip=Se uma falha ocorre concorrentemente neste período, travar a conta do usuário. +min-quick-login-wait=Espera mínima após Quick Login +min-quick-login-wait.tooltip=Quanto tempo aguardar após uma falha de quick login. +max-wait=Espera máxima +max-wait.tooltip=Tempo máximo que um usuário deverá aguardar após uma falha de quick login. +failure-reset-time=Tempo para zerar falhas +failure-reset-time.tooltip=Quando o contador de falhas será resetado? +realm-tab-login=Login +realm-tab-keys=Chaves +realm-tab-email=E-mail +realm-tab-themes=Temas +#realm-tab-localization=Localization +realm-tab-cache=Cache +realm-tab-tokens=Tokens +realm-tab-client-initial-access=Tokens de Acesso inicial +realm-tab-security-defenses=Defesas +realm-tab-general=Geral +add-realm=Adicionar realm + +#Session settings +realm-sessions=Sessões do Realm +revocation=Revogação +logout-all=Deslogar todos +active-sessions=Sessões Ativas +sessions=Sessões +not-before=Não antes de +not-before.tooltip=Revogar qualquer token emitido antes desta data. +set-to-now=Definir como agora +push=Enviar +push.tooltip=Para cada cliente que possui uma URL de administrador, notificá-los da nova política de revogação. + +#Protocol Mapper +usermodel.prop.label=Propriedade +usermodel.attr.label=Atributo do usuário +userSession.modelNote.label=Nota da sessão de usuário +multivalued.label=Múltiplos valores +selectRole.label=Selecione o Role +tokenClaimName.label=Nome do Token Claim +jsonType.label=Tipo JSON do Claim +includeInIdToken.label=Adicionar ao token de ID +includeInAccessToken.label=Adicionar ao token de acesso +includeInUserInfo.label=Adicionar à informação do usuário +usermodel.clientRoleMapping.clientId.label=ID do cliente +usermodel.clientRoleMapping.rolePrefix.label=Prefixo para o role de Cliente +usermodel.realmRoleMapping.rolePrefix.label=Prefixo do Realm Role + +# client details +search.placeholder=Pesquisar... +create=Criar +import=Importar +client-id=ID do cliente +base-url=URL Base +actions=Ações +not-defined=Não definido +edit=Editar +delete=Excluir +no-results=Sem resultados +no-clients-available=Nenhum cliente disponível +add-client=Adicionar cliente +select-file=Selecionar arquivo +view-details=Ver detalhes +clear-import=Cancelar importação +client-id.tooltip=Especifica o ID referenciado em URI e tokens. Por exemplo 'meu-cliente'. Para SAML também representa o valor do emissor esperado dos authn requests +client.name.tooltip=Especifica o nome de exibição do cliente. Por exemplo 'Meu Cliente'. Também aceita chaves para valores localizados. Por exemplo: ${meu_cliente} +client.description.tooltip=Especifica a descrição do cliente. Por exemplo 'Meu cliente para TimeSheets'. Também aceita chaves para valores localizados. Por exemplo: ${meu_cliente_descricao} +client.enabled.tooltip=Clientes desabilitados não podem realizar login ou obter tokens de acesso. +consent-required=Consentimento exigido +consent-required.tooltip=Se habilitado os usuários devem consentir com o acesso ao cliente. +client-protocol=Protocolo cliente +client-protocol.tooltip='OpenID connect' permite aos Clientes verificarem a identidade do usuário final baseado na autenticação realizada por um servidor de Autorização. 'SAML' permite cenários de autenticação e autorização web-based incluindo cross-domain single sign-on (SSO) e utiliza tokens de segurança contendo assertions para trafegar informações. +access-type=Tipo de acesso +access-type.tooltip=Clientes 'Confidential' requerem um secret para iniciar o protocolo de login. Clientes 'Public' não necessitam de secret. Clientes 'Bearer-only' são web services que nunca iniciam um login. +standard-flow-enabled=Fluxo padrão habilitado +standard-flow-enabled.tooltip=Isto habilita a autenticação baseada em redirecionamento com código de autorização padrão do OpenID Connect. Em termos de especificações OpenID Connect ou OAuth2, isto habilita suporte ao 'Fluxo de Código de Autorização' para este cliente. +implicit-flow-enabled=Fluxo implícito habilitado +implicit-flow-enabled.tooltip=Isto habilita suporte a autenticação baseada em redirecionamento sem código de autorização. Em tempos de especificações OpenID Connect ou OAuth2, isto habilita suporte do 'Fluxo Implícito' para este cliente. +direct-access-grants-enabled=Grants de Acesso direto habilitado +service-accounts-enabled=Contas de serviço habilitadas +include-authnstatement=Incluir AuthnStatement +sign-documents=Assinar documentos +sign-assertions=Assinar assertions +signature-algorithm=Algoritmo de assinatura +canonicalization-method=Método de Canonicalization +encrypt-assertions=Encriptar Assertions +client-signature-required=Assinatura do cliente requerida +force-post-binding=Forçar Binding via POST +front-channel-logout=Front Channel Logout +force-name-id-format=Forçar formato do NameID +name-id-format=Formato do NameID +valid-redirect-uris=URIs de redirecionamento válidas +admin-url=URL do administrador +master-saml-processing-url=URL de processamento SAML principal +idp-sso-url-ref=Nome de URL para SSO iniciado via IDP +idp-sso-relay-state=Estado de relay para SSO iniciado via IDP +fine-saml-endpoint-conf=Configuração de endpoint para configuração fina do SAML +assertion-consumer-post-binding-url=URL para conexão post para o serviço consumidor de Assertions +assertion-consumer-redirect-binding-url=URL para conexão de redirecionamento do serviço consumidor de Assertions +logout-service-post-binding-url=URL de conexão POST para o serviço de logout +logout-service-post-binding-url.tooltip=URL de conexão POST para o serviço de logout +logout-service-redir-binding-url=URL de conexão para o redirecionamento do serviço de logout + +# client import +import-client=Importar cliente +format-option=Formato +import-file=Importar arquivo + +# client tabs +settings=Configurações +credentials=Credenciais +roles=Roles +mappers=Mapeamentos +scope=Escopo +offline-access=Acesso offline +installation=Instalação +service-account-roles=Roles de contas de serviço + +# client credentials +client-authenticator=Autenticador do cliente +no-client-certificate-configured=Nenhum certificado cliente configurado +gen-new-keys-and-cert=Gerar novas chaves e certificados +import-certificate=Importar certificado +gen-client-private-key=Gerar chave privada do cliente +generate-private-key=Gerar chave privada +archive-format=Formato do arquivo +key-alias=Alias da chave +key-password=Senha da chave +store-password=Salvar senha +generate-and-download=Gerar e fazer download +client-certificate-import=Importar certificado do cliente +import-client-certificate=Importar certificado do cliente +secret=Segredo +regenerate-secret=Recriar segredo +registrationAccessToken=Token de acesso para registro +registrationAccessToken.regenerate=Regerar token de acesso para registro +add-role=Adicionar Role +role-name=Nome do Role +composite=Composto +description=Descrição +no-client-roles-available=Nenhum role de cliente disponível +scope-param-required=Parâmetro de escopo requerido +composite-roles=Roles compostos +realm-roles=Roles do Realm +available-roles=Roles disponíveis +add-selected=Adicionar selecionados +associated-roles=Roles associados +remove-selected=Remover selecionados +client-roles=Roles de clientes +select-client-to-view-roles=Selecione o cliente para ver os roles do cliente +add-builtin=Adicionar Builtin +category=Categoria +type=Tipo +no-mappers-available=Nenhum mapeamento disponível +add-builtin-protocol-mappers=Adicionar mapeamentos de protocolo Builtin +add-builtin-protocol-mapper=Adicionar mapeamentos de protocolo Builtin + +scope-mappings=Mapeamentos do Escopo +full-scope-allowed=Permitir Escopo completo +assigned-roles=Roles associados +effective-roles=Roles efetivos +basic-configuration=Configuração básica +node-reregistration-timeout=Tempo limite para re-registro de nó +registered-cluster-nodes=Nós de cluster registrados +register-node-manually=Registrar nó manualmente +test-cluster-availability=Testar disponibilidade do cluster +last-registration=Último registro +node-host=Host +no-registered-cluster-nodes=Nenhum nó registrado disponível +cluster-nodes=Nós do cluster +add-node=Adicionar nó +show-sessions=Exibir sessões +user=Usuário +from-ip=Do IP +session-start=Início da sessão +first-page=Primeira página +previous-page=Página anterior +next-page=Próxima página +select-a-format=Selecione um formato +download=Download +offline-tokens=Tokens offline +show-offline-tokens=Exibir tokens offline +token-issued=Token emitido +last-access=Último acesso +last-refresh=Último refresh +key-export=Exportar chave +key-import=Importar chave +export-saml-key=Exportar chave SAML +import-saml-key=Importar chave SAML +realm-certificate-alias=Alias do certificado do Realm +signing-key=Chave de assinatura +saml-signing-key=Chave de assinatura SAML +private-key=Chave privada +generate-new-keys=Gerar novas chaves +export=Exportar +encryption-key=Chave de encriptação +service-accounts=Contas de serviço +service-account-is-not-enabled-for=Contas de serviço não estão habilitadas para {{client}} +create-protocol-mappers=Criar mapeamentos de protocolo +create-protocol-mapper=Criar mapeamento de protocolo +protocol=Protocolo +protocol.tooltip=Protocolo... +id=ID +mapper.name.tooltip=Nome do mapeamento +consent-text=Texto para consentimento +mapper-type=Tipo de mapeamento +# realm identity providers +identity-providers=Provedores de identificação +table-of-identity-providers=Tabela de provedores de identidade +add-provider.placeholder=Adicionar provedor... +provider=Provedor +first-broker-login-flow=Fluxo do primeiro login +post-broker-login-flow=Fluxo pós login +redirect-uri=URI de redirecionamento +alias=Alias +authenticate-by-default=Autenticar por padrão +store-tokens=Salvar Tokens +stored-tokens-readable=Leitura de tokens salvos +trust-email=Confiar no e-mail recebido +gui-order=Ordem na tela +gui-order.tooltip=Número definindo a ordem do provedor na GUI (ex na página de Login). +openid-connect-config=Configuração OpenID Connect +authorization-url=URL de autorização +token-url=URL do Token +logout-url=URL de logout +backchannel-logout=Backchannel Logout +user-info-url=URL de informações do usuário +client-secret=Secret do Cliente +show-secret=Exibir secret +hide-secret=Esconder secret +issuer=Emissor +default-scopes=Escopos padrão +prompt=Prompt +unspecified.option=Não especificado +none.option=Nenhum +consent.option=Consentimento +login.option=Login +select-account.option=select_account +validate-signatures=Validar assinaturas +validating-public-key=Chave pública para validação +import-external-idp-config=Importar configuração de IDP externo +import-from-url=Importar de URL +import-from-file=Importar de arquivo +saml-config=Configuração SAML +single-signon-service-url=URL de serviço do Single Sign On +single-logout-service-url=URL de serviço de Single Logout +nameid-policy-format=Política de formato NameID +http-post-binding-response=Responder com HTTP-POST +http-post-binding-for-authn-request=Utilizar HTTP-POST binding para AuthnRequest +want-authn-requests-signed=Esperar AuthnRequests assinados +force-authentication=Forçar autenticação +validate-signature=Validar assinatura +validating-x509-certificate=Validar certificados X509 +key=Chave + +# User federation +sync-ldap-roles-to-keycloak=Sincronizar os roles do LDAP para o Keycloak +sync-keycloak-roles-to-ldap=Sincronizar os roles do Keycloak para o LDAP +sync-ldap-groups-to-keycloak=Sincronizar os grupos do LDAP para o Keycloak +sync-keycloak-groups-to-ldap=Sincronizar os grupos do Keycloak para o LDAP + +realms=Realms +realm=Realm + +identity-provider-mappers=Mapeamentos de provedores de identificação +create-identity-provider-mapper=Criar mapeamento de provedores de identificação +add-identity-provider-mapper=Adicionar mapeamento de provedor de identificação + +expires=Expira em +expiration=Duração +expiration.tooltip=Especifica por quanto tempo o token deve ser válido +count=Quantidade +count.tooltip=Especifica quantos clientes podem ser criados usando o token +remainingCount=Quantidade restante +created=Criado em +back=Voltar +initial-access-tokens=Tokens de acesso inicial +add-initial-access-tokens=Adicionar token de acesso inicial +initial-access-token=Token de acesso inicial +initial-access.copyPaste.tooltip=Copie/cole o token de acesso inicial antes de sair desta página pois não é possível recuperá-lo depois +continue=Continuar +initial-access-token.confirm.title=Copiar o token de acesso inicial +initial-access-token.confirm.text=Por favor copie e cole o token de acesso inicial antes de confirmar pois não é possível recuperá-lo depois + +client-scopes=Modelos de cliente + +groups=Grupos + +default-roles=Roles padrão +no-realm-roles-available=Nenhum role de realm disponível + +users=Usuários +realm-default-roles=Roles padrão do Realm +client-default-roles=Roles padrão do Cliente +partial-import=Importação parcial + +file=Arquivo +exported-json-file=Arquivo json exportado +import-from-realm=Importar de realm +import-users=Importar usuários +import-groups=Importar grupos +import-clients=Importar clientes +import-identity-providers=Importar provedores de identificação +import-realm-roles=Importar roles do realm +import-client-roles=Importar roles de cliente +if-resource-exists=Se um recurso já existir +fail=Falhar +skip=Pular +overwrite=Sobrescrever + +action=Ações +role-selector=Seletor de roles + +select-a-role=Selecione um role +select-realm-role=Selecione um role de realm +select-client-role=Selecione um role de cliente + +client-template=Modelos de Cliente +client-saml-endpoint=Cliente SAML Endpoint +add-client-scope=Adicionar modelo de cliente + +manage=Administração +authentication=Autenticação +user-federation=Federação de usuários +events=Eventos +realm-settings=Configurações do Realm +configure=Configuração +select-realm=Selecione um realm +add=Adicionar + + +add-user-federation-provider=Adicionar provedor de federação de usuários +required-settings=Configurações obrigatórias +provider-id=ID do provedor +console-display-name=Nome de exibição no console +priority=Prioridade +sync-settings=Configurações de sincronização +periodic-full-sync=Syncronização completa periódica +full-sync-period=Período +periodic-changed-users-sync=Sincronização periódica de usuários alterados +changed-users-sync-period=Período +synchronize-changed-users=Sincronizar usuários alterados +synchronize-all-users=Sincronizar todos os usuários +kerberos-realm=Realm do Kerberos +server-principal=Principal do servidor +keytab=KeyTab +debug=Debug +allow-password-authentication=Permitir autenticação via senha +edit-mode=Modo de edição +update-profile-first-login=Atualizar Profile no primeiro login +sync-registrations=Sincronizar contas +vendor=Vendor +username-ldap-attribute=Atributo LDAP para Username +ldap-attribute-name-for-username=Atributo LDAP para Username +rdn-ldap-attribute=Atributo LDAP para RDN +ldap-attribute-name-for-user-rdn=Atributo LDAP para RDN +uuid-ldap-attribute=Atributo LDAP para UUID +ldap-attribute-name-for-uuid=Atributo LDAP para UUID +user-object-classes=Classes do objeto User + +ldap-connection-url=URL de conexão ao LDAP +ldap-users-dn=DN dos usuários no LDAP +ldap-bind-dn=DN para bind no LDAP +ldap-bind-credentials=Credenciais para conectar ao LDAP +ldap-filter=Filtro do LDAP + +connection-url=URL de conexão +test-connection=Testar conexão +users-dn=Users DN +authentication-type=Tipo de autenticação +bind-dn=Bind DN +bind-credential=Senha para conexão +test-authentication=Testar autenticação +custom-user-ldap-filter=Filtro de usuários LDAP customizado +search-scope=Escopo de pesquisa +use-truststore-spi=Utilizar Truststore SPI +connection-pooling=Pooling de conexões +kerberos-integration=Integração com Kerberos +allow-kerberos-authentication=Permitir autenticação Kerberos +use-kerberos-for-password-authentication=Utilizar Kerberos para autenticação via senha +batch-size=Tamanho do lote +user-federation-mappers=Mapeamentos de federação de usuário +create-user-federation-mapper=Criar mapeamento de federação de usuário +add-user-federation-mapper=Adicionar mapeamento de federação de usuário +provider-name=Nome do provedor +no-user-federation-providers-configured=Nenhum federação de usuários configurada. +add-identity-provider=Adicionar provedor de identificação +add-identity-provider-link=adicionar link para provedor de identificação +identity-provider=Provedor de identificação +identity-provider-user-id=ID de usuário do provedor de identificação +identity-provider-username=Nome de usuário do provedor de identificação +pagination=Paginação + +browser-flow=Fluxo de browser +registration-flow=Fluxo de registro +direct-grant-flow=Fluxo de Direct Grant +reset-credentials=Reiniciar credenciais +client-authentication=Autenticação do cliente +new=Novo +copy=Copiar +add-execution=Adicionar execução +add-flow=Adicionar fluxo +auth-type=Tipo +requirement=Condição +config=Configuração +no-executions-available=Nenhuma execução disponível +authentication-flows=Fluxos de autenticação +create-authenticator-config=Criar configuração de autenticação +otp-type=Tipo OTP +time-based=Baseado em tempo +counter-based=Baseado em contador +otp-hash-algorithm=Algoritmo de hash OTP +number-of-digits=Quantidade de dígitos +look-ahead-window=Look Ahead Window +initial-counter=Contador inicial +otp-token-period=Período de token OTP +table-of-password-policies=Tabela de política de senhas +add-policy.placeholder=Adicionar política... +policy-type=Tipo da política +policy-value=Valor da política +admin-events=Eventos de adminstração +login-events=Eventos de login +filter=Filtro +update=Atualizar +reset=Reiniciar +operation-types=Tipos de operações +select-operations.placeholder=Selecionar operações... +resource-path=Path do recurso +date-(from)=Data (De) +date-(to)=Data (Até) +authentication-details=Detalhes para autenticação +ip-address=Endereço IP +time=Tempo +operation-type=Tipo de operação +auth=Autenticação +representation=Representação +register=Registro +required-action=Ação requerida +default-action=Ação padrão +no-required-actions-configured=Nenhuma ação requerida configurada +defaults-to-id=ID é o padrão +flows=Fluxos +bindings=Ligações +required-actions=Ações requeridas +password-policy=Política de senha +otp-policy=Política OTP +user-groups=Grupos de usuário +default-groups=Grupos Padrão +cut=Recortar +paste=Colar + +create-group=Criar grupo +create-authenticator-execution=Criar execução de autenticação +create-form-action-execution=Criar execução de ação de formulário +create-top-level-form=Criar formulário de nível superior +top-level-flow-type=Tipo do fluxo de nível superior +flow.generic=genérico +flow.client=cliente +create-execution-flow=Criar fluxo de execução +flow-type=Flow Type +flow.form.type=formulário +flow.generic.type=genérico +form-provider=Provedor de formulário +select-a-type.placeholder=selecione um tipo +available-groups=Grupos disponíveis +value=Valor +table-of-group-members=Tabela de membros do grupo +table-of-role-members=Tabela de membros do role +last-name=Sobrenome +first-name=Primeiro nome +email=E-mail +toggle-navigation=Alternar navegação +manage-account=Administrar a conta +sign-out=Sign Out +server-info=Informação do servidor +resource-not-found=Recurso não encontrado... +resource-not-found.instruction=Não foi possível encontrar o recurso solicitado. Por favor verifique se a URL solicitada está correta. +go-to-the-home-page=Ir para a página inicial » +page-not-found=Página não encontrada... +page-not-found.instruction=Não foi possível encontrar a página solicitada. Por favor verifique se a URL solicitada está correta. +select-event-types.placeholder=Selecione os tipos de eventos... +select-an-action.placeholder=Selecione uma ação... +admin-events-settings=Configuração de eventos de administração +save-events=Salvar eventos +include-representation=Incluir representação +server-version=Versão do servidor +info=Informações +providers=Provedores +server-time=Hora do servidor +server-uptime=Uptime do servidor +memory=Memória +total-memory=Memória total +free-memory=Memória livre +used-memory=Memória utilizada +system=Sistema +current-working-directory=Diretório de trabalho atual +java-version=Versão do Java +java-vendor=Java Vendor +java-runtime=Java Runtime +java-vm=Java VM +java-vm-version=Versão da Java VM +java-home=Java Home +user-name=Usuário +user-timezone=Zona horária do usuário +user-locale=Locale do usuário +system-encoding=Enconding do sistema +operating-system=Sistema operacional +os-architecture=Arquitetura do OS +spi=SPI +granted-roles=Roles concedidos +granted-protocol-mappers=Protocol Mappers concedidos +additional-grants=Concessões adicionais +revoke=Revogar +new-password=Nova senha +password-confirmation=Confirmação de senha +reset-password=Reiniciar senha +remove-totp=Remover OTP +reset-actions=Ações para reiniciar +reset-actions-email=Ações para reiniciar e-mail +send-email=Enviar e-mail +add-user=Adicionar usuário +created-at=Criado em +user-enabled=Usuário ativo +user-temporarily-locked=Usuário temporariamente desativado +unlock-user=Liberar usuário +federation-link=Link para federação +email-verified=E-mail verificado +required-user-actions=Ações necessárias do usuário +locale=Locale +select-one.placeholder=Selecione um... +impersonate=Personificar +impersonate-user=Personificar usuário +identity-provider-alias=Alias do Provedor de Identificação +provider-user-id=Provider User ID +provider-username=Provider Username +no-identity-provider-links-available=Nenhum link para provedor de identificação disponível +group-membership=Grupos associados +leave=Sair +table-of-realm-users=Tabela de usuários do Realm +view-all-users=Exibir todos os usuários +unlock-users=Liberar usuários +no-users-available=Nenhum usuário disponível +users.instruction=Por favor faça uma pesquisa, ou clique em Exibir todos os usuários +consents=Consentimentos +started=Iniciado +logout-all-sessions=Logout todas as sessões +logout=Logout +new-name=Novo nome +ok=Ok +attributes=Atributos +role-mappings=Mapeamento de roles +members=Membros +details=Detalhes +identity-provider-links=Links de provedores de identificação. +register-required-action=Registrar ação necessária +gender=Gênero +address=Endereço +phone=Telefone +profile-url=URL do perfil +picture-url=URL da foto +website=Website +import-keys-and-cert=Importar chave e certificado +upload-keys=Carregar chaves +download-keys-and-cert=Download chave e certificado +no-value-assigned.placeholder=Nenhum valor associado +remove=Remover +no-group-members=Nenhum membro +no-role-members=Nenhum membro no role +temporary=Temporária +join=Participar +event-type=Tipo de evento +events-config=Configurar eventos +event-listeners=Listeners de eventos +login-events-settings=Configuração de eventos de login +clear-events=Limpar eventos +saved-types=Tipos salvos +clear-admin-events=Limpar eventos administrativos +clear-changes=Cancelar mudanças +error=Erro + +# Authz +# Authz Common +authz-authorization=Autorização +authz-owner=Proprietário +authz-uri=URI +authz-scopes=Escopos +authz-resource=Recurso +authz-resource-type=Tipo de recurso +authz-resources=Recursos +authz-scope=Escopo +authz-authz-scopes=Autorização de escopos +authz-policies=Políticas +authz-permissions=Permissões +authz-users=Usuários no role +authz-evaluate=Avaliar +authz-icon-uri=URI do ícone +authz-select-scope=Selecione um escopo +authz-select-resource=Selecione um recurso +authz-associated-policies=Políticas associadas +authz-any-resource=Qualquer recurso +authz-any-scope=Qualquer escopo +authz-any-role=Qualquer role +authz-policy-evaluation=Avaliação da política +authz-select-client=Selecione um cliente +authz-select-user=Selecione um usuário +authz-entitlements=Direitos +authz-no-resources=Nenhum recurso +authz-result=Resultado +authz-authorization-services-enabled=Autorização habilitada +authz-required=Obrigatório + +# Authz Settings + +authz-policy-enforcement-mode=Modo de execução da política +authz-policy-enforcement-mode-enforcing=Restritiva +authz-policy-enforcement-mode-permissive=Permissiva +authz-policy-enforcement-mode-disabled=Desabilitada + +authz-remote-resource-management=Administração remota de recursos + +authz-export-settings=Exportar configurações + +# Authz Resource List +authz-no-resources-available=Nenhum recurso disponível. +authz-no-scopes-assigned=Nenhum escopo associado. +authz-no-type-defined=Nenhum tipo definido. +authz-no-permission-assigned=Nenhuma permissão associada. +authz-no-policy-assigned=Nenhuma política associada. +authz-create-permission=Criar permissão + +# Authz Resource Detail +authz-add-resource=Adicionar recurso + +# Authz Scope List +authz-add-scope=Adicionar escopo +authz-no-scopes-available=Nenhum escopo disponível. + +# Authz Scope Detail + +# Authz Policy List +authz-all-types=Todos os tipos +authz-create-policy=Criar política +authz-no-policies-available=Nenhuma política disponível + +# Authz Policy Detail +authz-policy-logic=Lógica +authz-policy-logic-positive=Positiva +authz-policy-logic-negative=Negativa +authz-policy-apply-policy=Aplicar política +authz-policy-decision-strategy=Estratégia de decisão +authz-policy-decision-strategy-affirmative=Afirmativa +authz-policy-decision-strategy-unanimous=Unânime +authz-policy-decision-strategy-consensus=Consensual +authz-select-a-policy=Selecionar uma política + +# Authz Role Policy Detail +authz-add-role-policy=Adicionar política de Role +authz-no-roles-assigned=Nenhum role associado + +# Authz User Policy Detail +authz-add-user-policy=Adicionar política de usuário +authz-no-users-assigned=Nenhum usuário associado + +# Authz Time Policy Detail +authz-add-time-policy=Adicionar política de tempo +authz-policy-time-not-on-after=Não em ou depois + +# Authz JS Policy Detail +authz-add-js-policy=Adicionar política Javascript +authz-policy-js-code=Código + + +# Authz Aggregated Policy Detail +authz-aggregated=Agregado +authz-add-aggregated-policy=Adicionar política agregada + +# Authz Permission List +authz-no-permissions-available=Nenhuma permissão disponível + +# Authz Permission Detail + +# Authz Resource Permission Detail +authz-add-resource-permission=Adicionar permissão para recurso +authz-permission-resource-apply-to-resource-type=Aplicar ao tipo de recurso + +# Authz Scope Permission Detail +authz-add-scope-permission=Adicionar permissão de escopo + +# Authz Evaluation +authz-evaluation-identity-information=Informação de identidade +authz-evaluation-new=Nova avaliação +authz-evaluation-re-evaluate=Re-avaliar +authz-evaluation-previous=Avaliação anterior +authz-evaluation-contextual-info=Informação contextual +authz-evaluation-contextual-attributes=Atributos contextuais +authz-evaluation-evaluate=Avaliar +authz-evaluation-any-resource-with-scopes=Qualquer recurso com escopo(s) +authz-evaluation-no-result=Não foi possível obter nenhum resultado para o pedido de autorização provida. Verifique os recurso(s) ou escopo(s) providos estão associados com alguma política. +authz-evaluation-no-policies-resource=Nenhma política foi encontrada para este recurso. +authz-evaluation-authorization-data=Resposta +authz-show-authorization-data=Exibir dados da autorização + +usermodel.prop.tooltip=Nome do método da propriedade na interface UserModel. Por exemplo, o valor 'email' iria referenciar o método UserModel.getEmail() . +usermodel.attr.tooltip=Nome do atributo do usuário que é uma chave de atributo no mapa UserModel.attribute. +userSession.modelNote.tooltip=Nome da nota de sessão do usuário salva no mapa UserSessionModel.note. +multivalued.tooltip=Indica se um atributo suporta múltiplos valores. Se verdadeiro, então a lista de todos os valores desse atributo será definida como o claim. Se falso, então apenas o primeiro valor será utilizado. +selectRole.tooltip=Entre com o role na caixa à esquerda, ou clique neste botão para navegar e selecionar o role desejado. +tokenClaimName.tooltip=Nome do claim para inserir no token. Pode ser um nome completo (fully qualified) como 'address.street'. Neste caso, um objeto json aninhado será criado. +jsonType.tooltip=Tipo JSON que deve ser utilizado para popular o claim json no token. Os valores válidos são Long, int boolean e String. +includeInIdToken.tooltip=O claim deve ser adicionado ao token de ID? +includeInAccessToken.tooltip=O claim deve ser adicionado ao token de acesso? +includeInUserInfo.tooltip=O claim deve ser adicionado à informação do usuário? +usermodel.clientRoleMapping.clientId.tooltip=ID do cliente para mapeamentos de roles +usermodel.clientRoleMapping.rolePrefix.tooltip=Um prefixo para cada role do cliente (opcional) +usermodel.realmRoleMapping.rolePrefix.tooltip=Um prefixo para cada Realm Role (opcional). +clients.tooltip=Os clientes são aplicativos de browser e serviços web confiáveis em um realm. Esses clientes podem solicitar login. Você também pode definir roles específicos do cliente. +authz-policy-role-clients.tooltip= Selecione um cliente a fim de filtrar os roles de cliente que podem ser aplicados a esta política. +direct-access-grants-enabled.tooltip=Habilita o suporte para concessões de acesso direto (Direct Access Grants), o que significa que o cliente tem acesso ao nome de usuário/senha e negocia diretamente com o servidor Keycloak pelo token de acesso. Em termos de especificações OAuth2, habilita suporte de "Resource Owner Password Credentials Grant" para este cliente. +service-accounts-enabled.tooltip=Permite autenticar este cliente no Keycloak e recuperar tokens de acesso dedicados para este cliente. Em termos da especificações OAuth2, habilita suporte para 'Client Credentials Grants' para este cliente. +include-authnstatement.tooltip=Deve ser adicionado um statement especificando o método e timestamp nas respostas de login? +sign-documents.tooltip=Devem os documentos SAML serem assinados pelo realm? +sign-assertions.tooltip=Devem as asserções dentro dos documentos SAML serem assinadas? Esta configuração não é necessária se o documento já está sendo assinado. +signature-algorithm.tooltip=O algoritmo de assinatura a ser utilizado para assinar documentos. +canonicalization-method.tooltip=Canonicalization Method para assinaturas XML. +encrypt-assertions.tooltip=Devem as asserções SAML serem encriptadas com a chave pública do cliente usando AES? +client-signature-required.tooltip=O cliente irá assinar os pedidos e respostas saml? E eles devem ser validados? +force-post-binding.tooltip=Sempre utilizar POST para respostas. +front-channel-logout.tooltip=Quando marcado, o logout requer um redirecionamento do browser para o cliente. Caso contrário o servidor executo uma invocação em background para o logout. +force-name-id-format.tooltip=Ignora o NameID de assunto solicitado e utiliza o configurado no console de administração. +name-id-format.tooltip=O formato de Name ID para utilizar como assunto. +root-url.tooltip=URL raiz adicionada à URLs relativas +valid-redirect-uris.tooltip=Padrão de URI válido para onde um navegador pode redirecionar depois de um login bem-sucedido ou sair. Wildcards simples são permitidos, por exemplo 'http://example.com/*'. Caminhos relativos podem ser especificados também, ex: /my/relative/path/*. Caminhos relativos são relativos à URL raiz do cliente, ou se nenhum for especificado a URL raiz do servidor é usado. Para SAML, é necessário definir padrões de URI válidos se você está contando com a URL do serviço consumidor incorporada com a solicitação de login. +base-url.tooltip=URL padrão para utilizar quando o servidor de autenticação necessita redirecionar ou linkar para o cliente. +admin-url.tooltip=URL para a inteface administrativa do cliente. Defina este valor se o cliente suporta a API do adaptador REST. Esta API rest permite que o servidor de autenticação envie políticas de revogação e outras tarefas administrativas. Geralmente este valor é definido apontando para a URL base do cliente. +master-saml-processing-url.tooltip=Se configurado, esta URL será utilizada para todos os bindings do "SP's Assertion Consumer" e "Single Logout Services". Ela pode ser sobreescriva idnvidualmente para cada ligação e serviço na Configuração Detalhada do Endpoint SAML. +idp-sso-url-ref.tooltip=Nome do fragmento URL para referenciar o cliente quando você deseja um SSO iniciado por IDP. Deixar este campo vazio irá desabilitar SSO iniciado por IDP. A URL que você irá referenciar do seu browser será: {server-root}/realms/{realm}/protocol/saml/clients/{client-url-name} +idp-sso-relay-state.tooltip=O estado de Relay que você deseja enviar com um pedido SAML quando você deseja realizar SSO iniciado por IDP. +web-origins.tooltip=Permitir origens CORS. Para permitir todas as URIs de redirecionamento de origem válidas adicionar '+'. Para permitir todas as origens adicionar '*'. +fine-saml-endpoint-conf.tooltip=Expanda esta sessão para configurar URLs específics para 'Assertion Consumer' e 'Single Logout Service'. +assertion-consumer-post-binding-url.tooltip=URL de ligação SAML via post para as asserções de consumidor de serviços do cliente (respostas de login). Você pode deixar este campo em branco se você não tiver uma URL para esta ligação. +assertion-consumer-redirect-binding-url.tooltip=URL de ligação SAML de redirecionamento para as asserções de consumidor de serviços do cliente (respostas de login). Você pode deixar este campo em branco se você não tiver uma URL para esta ligação. +logout-service-binding-post-url.tooltip=URL de ligação SAML via post para o serviço de logout único do cliente. Voce pode deixar este campo em branco se estiver usando uma ligação diferente. +logout-service-redir-binding-url.tooltip=URL de ligação SAML de redirecionamento para o serviço de logout único do cliente. Voce pode deixar este campo em branco s e estiver usando uma ligação diferente. +mappers.tooltip=Mapeamentos de protocolo executam transformações em tokens e documentos. Eles podem realizar coisas como mapear dados de usuários para claims de protocolo, ou apenas transformar qualquer solicitação entre o cliente e o servidor de autenticação. +scope.tooltip=Escopos de mapeamento permitem que você restrinja quais mapeamentos de roles de usuário são inclusos nos tokens de acesso solicitado pelo cliente. +ldap.search-scope.tooltip=Para um nível nós pesquisamos somente os usuários nos DNs especificados pelo campo User DNs. Para subtree, nós pesquisamos na sub-árvore completa. Verifique a documentação do LDAP para mais detalhes. +authz-permission-scope-scope.tooltip=Define que esta permissões deve ser aplicada para um ou mais escopos. +sessions.tooltip=Exibir as sessões ativas para este cliente. Permite que você veja quais usuários estão ativos e quando eles logaram. +active-sessions.tooltip=Total de sessões de usuário ativas para este cliente. +show-sessions.tooltip=Atenção, esta é uma operação potencialmente cara dependendo do número de sessões ativas. +offline-access.tooltip=Exibe as sessões offline para este cliente. Permite que você veja quantos usuários obtém tokens offline e quando eles os obtiveram. PAra revogar todos os tokens do cliente, vá para a aba Revogações e defina o valor do campo 'não antes de' para 'agora'. +installation.tooltip=Ferramenta de auxílio para gerar vários formatos de adaptadores de cliente que você poderá fazer download depois ou copiar e colar para configurar seus cliente. +service-account-roles.tooltip=Permite que você autentique mapeamentos de roles para as contas de serviço dedicadas à este cliente. +client-authenticator.tooltip=Autenticador de Cliente usado para autenticar este cliente ao servidor Keycloak +certificate.tooltip=Certificado do cliente para validar JWT emitidos pelo cliente e assinados pela chave privada do cliente da sua keystore. +validating-x509-certificate.tooltip=O certificado em formato PEM que deve ser usado para verificar assinaturas. +archive-format.tooltip=Keystore Java ou arquivo em formato PKCS12. +key-alias.tooltip=Alias do arquivo para sua chave privada e certificado. +key-password.tooltip=Senha para acessar a chave privada no certificado. +store-password.tooltip=Senha para acessar o arquivo em si. +jwt-import.key-alias.tooltip=Alias do arquivo para o seu certificado. +registrationAccessToken.tooltip=O token de acesso para registro provê acesso aos cliente para o serviço de registro cliente. +scope-param-required.tooltip=Este role somente será concedido se os parâmetros de escopo com os nomes dos roles forem utilizados durante a autorização/solicitação de token. +composite-roles.tooltip=Quando este role é associado/removido de um usuário, qualquer role associado com ele também será adicionado/removido implicitamente. +composite.associated-realm-roles.tooltip=Roles de nível de realm associados com este role composto. +composite.available-realm-roles.tooltip=Roles de nível de realm disponíveis para este role composto. +available-roles.tooltip=Roles para este cliente que você pode associar a este role composto. +scope.available-roles.tooltip=Roles do Realm que podem ser associados a este escopo. +service-account.available-roles.tooltip=Roles do Realm que podem ser associados a contas de serviço. +client.associated-roles.tooltip=Roles do Cliente associados a este role composto. +full-scope-allowed.tooltip=Permite a você desabilitar todas as restrições. +assigned-roles.tooltip=Roles do Realm associados ao escopo. +service-account.assigned-roles.tooltip=Roles do Realm associados a conta de serviço. +group.assigned-roles.tooltip=Roles do Realm mapeados ao grupo. +realm.effective-roles.tooltip=Roles do Realm associados que podem ter sido herdados de um role composto. +select-client-roles.tooltip=Selecione o cliente para visualizar os roles de cliente. +assign.available-roles.tooltip=Roles de Cliente disponíveis para associação. +client.assigned-roles.tooltip=Roles de Cliente associados. +client.effective-roles.tooltip=Roles de cliente associados que podem ter sido herdados de um role composto. +node-reregistration-timeout.tooltip=Intervalo para especificar o tempo máximo para nós clientes de cluster registrados se re-registrarem. Se os nós do cluster não enviarem solicitações de re-registro dentro deste intervalo eles serão deregistrados do Keycloak. +client-revoke.not-before.tooltip=Revocar qualquer token emitido antes desta data para este cliente. +client-revoke.push.tooltip=Se a URL de administração estiver configurada para este cliente, envie esta política para este cliente. +offline-tokens.tooltip=Número total de tokens offline para este cliente. +show-offline-tokens.tooltip=Atenção, esta é uma operação potencialmente cara dependendo do número de tokens offline. +realm-certificate-alias.tooltip=O certificado do Realm também é guardado em arquivo. Este é o alias para ele. +saml-encryption-key.tooltip=Chave de encriptação SAML. +mapper.consent-required.tooltip=Ao conceder acesso temporário, deve o usuário consentir em prover esta informação para o cliente? +consent-text.tooltip=Texto para exibir na página de consentimento +mapper-type.tooltip=Tipo do mapeamento +redirect-uri.tooltip=A url de redirecionamento para usar quando da configuração do provedor de identidade. +identity-provider.alias.tooltip=O alias é o identificador único de um provedor de identidade e também é utilizado para construir a uri de redirecionamento. +identity-provider.enabled.tooltip=Habilita/Desabilita este provedor de identidade. +identity-provider.authenticate-by-default.tooltip=Indica se este provedor deve ser tentado por padrão para a autenticação mesmo ante de exibir a tela de login. +identity-provider.store-tokens.tooltip=Habilita/desabilita se os tokens deve ser guardados depois de autenticar os usuários. +identity-provider.stored-tokens-readable.tooltip=Habilita/desabilita se novos usuários podem ler quaisquer tokens salvo. Isto irá adicionar o role broker.read-token. +update-profile-on-first-login.tooltip=Define condições onde um usuário precisa atualizar o seu perfil durante o primeiro login. +trust-email.tooltip=Se habilitado então o e-mail provido por este provedor não será verificado mesmo que a verificação esteja habilitada para este realm. +first-broker-login-flow.tooltip=Alias do fluxo de autenticação que será invocado depois do primeiro login com este provedor de identificação. O termo 'Primeiro Login' significa que ainda não existe uma conta no Keycloak ligada a esta conta autenticada neste provedor. +post-broker-login-flow.tooltip=Alias do fluxo de autenticação que será invocado depois de cada login com esse provedor de identificação. É útil se você pretende adicionar verificações adicionais de cada usuário autenticado com este provedor (por exemplo OTP). Deixa vazio se você não deseja que nenhum autenticador adicionar seja invocado depois do login com este provedor de identificação. Note também que as implementações de autenticação devem assumir que o usuários já está definido na ClientSessioncom e com o provedor de identidade já definido. +openid-connect-config.tooltip=OIDC SP e configuração externa IDP. +authorization-url.tooltip=A URL de autorização. +token-url.tooltip=A URL do Token. +identity-provider.logout-url.tooltip='End session endpoint' para utilizar para realizar logour dos usuários do IDP externo. +backchannel-logout.tooltip=O IDP externo suporta logou via backchannel? +user-info-url.tooltip=A Url de informações de usuário. Opcional. +identity-provider.client-id.tooltip=O cliente ou identificador do cliente registrado junto ao provedor de identificação. +client-secret.tooltip=O cliente ou senha do cliente registrado junto ao provedor de identificação. +social.client-secret.tooltip=A senha do cliente registrado junto ao provedor de identificação. +issuer.tooltip=O identificador de emissor para o emissor da resposta. Se não for provido nenhuma validação será realizada. +identity-provider.default-scopes.tooltip=Os escopos que serão enviados ao solicitar autorização. Pode ser uma lista de escopos separadas por espaço. Valor padrão é 'openid'. +prompt.tooltip=Especifica se o Servidor de Autorização solicita ao Usuário Final reautenticação e consentimento. +identity-provider.validate-signatures.tooltip=Habilita/Desabilita a validação de assinatura de IDP externo. +identity-provider.validating-public-key.tooltip=A chave pública em formato PEM que deve ser usada para verificar assinaturas de IDP externos. +import-external-idp-config.tooltip=Permite que vocÊ carregue metadata de IDP externos de um arquivo de configuração ou baixando a partir de uma URL. +identity-provider.import-from-url.tooltip=Importar metadata de um descritor de descoberta remoto do IDP. +identity-provider.import-from-file.tooltip=Importar metadata fr um descritor de descoberta baixado do IDP. +identity-provider.saml-config.tooltip=SAML SP e configuração de IDP externo. +saml.single-signon-service-url.tooltip=A Url que deve ser utilizada para enviar solicitações de autenticação (SAML AuthnRequest). +saml.single-logout-service-url.tooltip=A Url que deve ser utilizada para enviar solicitações de logout. +nameid-policy-format.tooltip=Especifica a referência de URI correspondente a um formato de nome identificador. O padrão é urn:oasis:names:tc:SAML:2.0:nameid-format:persistent. +http-post-binding-response.tooltip=Indica se deve se responder a solicitações utilizando HTTP-POST. Se falso, HTTP-REDIRECT será utilizado. +http-post-binding-for-authn-request.tooltip=Indica se o AuthnRequest deve ser enviado utilizando HTTP-POST. Se falso, HTTP-REDIRECT será utilizado. +want-authn-requests-signed.tooltip=Indicate se um provedor de identificação deve experar um AuthnRequest assinado. +identity-provider.force-authentication.tooltip=Indica se um provedor de identificação deve autenticar o apresentador diretamente ao invés de confiar em um contexto de segurança anterior. +saml.validate-signature.tooltip=Habilita/Desabilita validação de assinaturas de respostas SAML. +saml.import-from-url.tooltip=Importar metadata de um descritor de entidade IDP SAML remoto. +social.client-id.tooltip=O identificador do cliente registrado com o provedor de identificação. +social.default-scopes.tooltip=Os escopos que serão enviados ao solicitar autorização. Veja a documentação para valores possíveis, separador e valores padrão. +stackoverflow.key.tooltip=A chave de cliente obtida do registro no Stack Overflow. +client-scopes.tooltip=Modelos de cliente permitem que você defina configurações comuns que serão compartilhadas entre múltiplos clientes. +group.add-selected.tooltip=Roles do Realm que serão associadas ao grupo. +group.effective-roles.tooltip=Todos os mapeamentos de roles do Realm. Alguns roles exibidos podem ter sido herdados de um role composto mapeado. +group.available-roles.tooltip=Roles associáveis deste cliente. +group.assigned-roles-client.tooltip=Mapeamentos de roles para este cliente. +group.effective-roles-client.tooltip=Mapeamentos de roles para este cliente. Alguns roles exibidos podem ter sido herdados de um role composto mapeado. +user.add-selected.tooltip=Roles do Realm que podem ser associados ao usuário. +user.assigned-roles.tooltip=Roles do Realm mapeados para o usuário. +user.effective-roles.tooltip=Todos os mapeamentos de roles do Realm. Alguns roles exibidos podem ter sido herdados de um role composto mapeado. +user.available-roles.tooltip=Roles associáveis deste cliente. +user.assigned-roles-client.tooltip=Mapeamentos de roles para este cliente. +user.effective-roles-client.tooltip=Mapeamentos de Role para este cliente. Alguns roles exibidos podem ter sido herdados de um role composto mapeado. +default.available-roles.tooltip=Roles do nível de Realm que podem ser associados. +realm-default-roles.tooltip=Roles do nível de Realm associados a novos usuários. +default.available-roles-client.tooltip=Roles para este cliente que são associáveis por padrão. +client-default-roles.tooltip=Roles para este cliente que são associados como roles padrão. +composite.available-roles.tooltip=Roles do nível de Realm associáveis com este role composto. +composite.associated-roles.tooltip=Roles do nível de Realm associados com este role composto. +composite.available-roles-client.tooltip=Roles para este cliente que podem ser associados com este role composto. +composite.associated-roles-client.tooltip=Roles do cliente associados com este role composto. +partial-import.tooltip=Importação parcial permite que você importe usuários, clientes, e outros recursos de um arquivo json previamente exportado. +if-resource-exists.tooltip=Especifica o que deve ser feito se você tentar importar um recurso já existente. +realm-roles.tooltip=Roles do Realm que podem ser selecionados. +authz-policy-role-realm-roles.tooltip=Especifica quais role(s) de *realm* são permitidos por esta política. +client-roles.tooltip=Roles do cliente que podem ser selecionados. +authz-policy-role-client-roles.tooltip=Especifica quais role(s) do *cliente* são permitidos por esta política. +client-scope.tooltip=Modelo de cliente do qual ete cliente herda as configurações. +client-scope.name.tooltip=Nome do modelo de cliente. Deve ser único neste Realm. +client-scope.description.tooltip=Descrição do modelo de cliente. +client-scope.protocol.tooltip=Qual configuração de protocolo SSO será provida por este modelo de cliente. +console-display-name.tooltip=Nome de exibição do provedor quando linkado no console de administração. +priority.tooltip=Prioridade do provedor quando da busca de usuários. Valores mais baixos são utilizados primeiro. +periodic-full-sync.tooltip=Habilitar ou não a sincronização completa periódica dos usuários deste provedor. +ldap.periodic-full-sync.tooltip=Habilitar ou não a sincronização completa dos usuários do LDAP para o Keycloak. +full-sync-period.tooltip=Intervalo para a sincronização completa em segundos. +periodic-changed-users-sync.tooltip=Habilitar ou não a sincronização de usuários novos ou alterados do provedor para o Keycloak. +ldap.periodic-changed-users-sync.tooltip=Habilitar ou não a sincronização de usuários novos ou alterados do LDAP para o Keycloak. +changed-users-sync-period.tooltip=Intervalo para sincronização dos usuários alterados ou novos do provedor em segundos. +ldap.changed-users-sync-period.tooltip=Intervalo para sincronização dos usuários alterados ou novos do LDAP em segundos. +kerberos-realm.tooltip=Nome do realm kerberos. Por exemplo FOO.ORG +server-principal.tooltip=Nome completo do principal do servidor para o serviço HTTP incluindo o servidor e nome do domínio. Por exemplo HTTP/host.foo.org@FOO.ORG +keytab.tooltip=Localização do arquivo KeyTab do Kerberos contendo as credenciais do principal do servidor. Por exemplo /etc/krb5.keytab +debug.tooltip=Habilita/Desabilita log de nível debug para a saída padrão para Krb5LoginModule. +allow-password-authentication.tooltip=Habilita/Desabilita a possibilidade de autenticação via usuário/senha contra o banco Kerberos +edit-mode.tooltip=READ_ONLY significa que atualizações de senhas não são permitidas e o usuário sempre autenticará com a senha do Kerberos. UNSYNCED significa que o usuário pode alterar a senha no banco do Keycloak e essa senha será utilizda ao invés da senha do Kerberos. +ldap.edit-mode.tooltip=READ_ONLY é um LDAP somente leitura. WRITABLE significa que os dados serão sicronizados de volta para o LDAP on demand. UNSYNCED significa que os dados do usuário serão importados, mas não sicronizados de volta para o LDAP. +update-profile-first-login.tooltip=Atualizar o perfil no primeiro login +ldap.sync-registrations.tooltip=Os novos usuários criados devem ser criados no LDAP? A prioridade afeta qual provedor é utilizado para sincronizar o novo usuário. +ldap.vendor.tooltip=LDAP vendor (provedor) +username-ldap-attribute.tooltip=Nome do atributo do LDAP que será mapeado como nome do usuário no Keycloak. Para muitos servidores LDAP este valor deve ser 'uid'. Para o Active Directory pode ser 'sAMAccountName' ou 'cn'. O atributo deve ser preenchido para todos os registros de usuários do LDAP que você deseja importar do LDAP para o Keycloak. +rdn-ldap-attribute.tooltip=Nome do atributo LDAP que é utilizado como RDN (atributo topo) do DN do usuário típico. Geralmente é o mesmo que o atributo do nome do usuário, mas isto não é obrigatório. Por exemplo para o Active Directory é comum utilizar 'cn' como atributo RDN quando o atributo do nome de usuário pode ser 'sAMAccountName', +uuid-ldap-attribute.tooltip=Nome do atributo LDAP que é utilizado como identificador único do objeto(UUID) para objetos no LDAP. Para muitos servidores LDAP o valor é 'entryUUID', porém alguns são diferentes. Por exemplo para o Active Directory este valor para objetos no LDAP deve ser 'objectGUID'. Se o seu servidor LDAP realmente não suporta a noção de UUID, vocÊ pode usar qualquer outro atributo que seja único na árvore de usuários do LDAP. Por exemplo 'uid' ou 'entryDN'. +ldap.user-object-classes.tooltip=Todos os valores de objectClass para usuários no LDAP separados por vírgula. Por exemplo: 'inetOrgPerson, organizationalPerson'. Usuários criados no Keycloak serão enviados para o LDAP com todas essas classes de objetos associadas e dados de usuários do LDAP somente serão localizados se ele contiverem todas estas classes de objeto. +ldap.connection-url.tooltip=Conexão URL para o seu servidor LDAP +ldap.users-dn.tooltip=DN completo da árvore LDAP onde os usuários estão. Este DN é o pai dos usuários do LDAP. Por exemplo pode ser 'ou=users,dc=example,dc=com' entendendo que o usuário típico irá ter um DN como 'uid=john,ou=users,dc=example,dc=com'. +ldap.authentication-type.tooltip=Tipo de autenticação no LDAP. No momento apenas os mecanismos 'none' (anonymous LDAP authentication) ou 'simple' (Credencial de bind + senha para bind) estão disponíveis. +ldap.bind-dn.tooltip=DN do administrador do LDAP, que será utilizado pelo Keycloak para acessar o servidor LDAP. +ldap.bind-credential.tooltip=Senha do administrador do LDAP +ldap.custom-user-ldap-filter.tooltip=Additional LDAP Filter for filtering searched users. Leave this empty if you don't need additional filter. Make sure that it starts with '(' and ends with ')' +ldap.use-truststore-spi.tooltip=Specifies whether LDAP connection will use the truststore SPI with the truststore configured in keycloak-server.json. 'Always' means that it will always use it. 'Never' means that it won't use it. 'Only for ldaps' means that it will use if your connection URL use ldaps. Note even if keycloak-server.json is not configured, the default Java cacerts or certificate specified by 'javax.net.ssl.trustStore' property will be used. +ldap.connection-pooling.tooltip=Does Keycloak should use connection pooling for accessing LDAP server +ldap.pagination.tooltip=Does the LDAP server support pagination. +ldap.allow-kerberos-authentication.tooltip=Enable/disable HTTP authentication of users with SPNEGO/Kerberos tokens. The data about authenticated users will be provisioned from this LDAP server +ldap.use-kerberos-for-password-authentication.tooltip=Use Kerberos login module for authenticate username/password against Kerberos server instead of authenticating against LDAP server with Directory Service API +ldap.batch-size.tooltip=Count of LDAP users to be imported from LDAP to Keycloak within single transaction. +identity-provider-user-id.tooltip=Unique ID of the user on the Identity Provider side +identity-provider-username.tooltip=Username on the Identity Provider side +browser-flow.tooltip=Select the flow you want to use for browser authentication. +registration-flow.tooltip=Select the flow you want to use for registration. +direct-grant-flow.tooltip=Select the flow you want to use for direct grant authentication. +reset-credentials.tooltip=Select the flow you want to use when the user has forgotten their credentials. +client-authentication.tooltip=Select the flow you want to use for authentication of clients. +authenticator.alias.tooltip=Name of the configuration +otp-type.tooltip=totp is Time-Based One Time Password. 'hotp' is a counter base one time password in which the server keeps a counter to hash against. +otp-hash-algorithm.tooltip=What hashing algorithm should be used to generate the OTP. +otp.number-of-digits.tooltip=How many digits should the OTP have? +otp.look-ahead-window.tooltip=How far ahead should the server look just in case the token generator and server are out of time sync or counter sync? +otp.initial-counter.tooltip=What should the initial counter value be? +otp-token-period.tooltip=How many seconds should an OTP token be valid? Defaults to 30 seconds. +admin-events.tooltip=Displays saved admin events for the realm. Events are related to admin account, for example a realm creation. To enable persisted events go to config. +clear-admin-events.tooltip=Deletes all admin events in the database. +resource-path.tooltip=Filter by resource path. Supports wildcards '*' to match a single part of the path and '**' matches multiple parts. For example 'realms/*/clients/asbc' matches client with id asbc in any realm, while or 'realms/master/**' matches anything in the master realm. +auth.default-action.tooltip=If enabled, any new user will have this required action assigned to it. +groups.default-groups.tooltip=Set of groups that new users will automatically join. +flow.alias.tooltip=Specifies display name for the flow. +top-level-flow-type.tooltip=What kind of top level flow is it? Type 'client' is used for authentication of clients (applications) when generic is for users and everything else +flow-type.tooltip=What kind of form is it +default-groups.tooltip=Newly created or registered users will automatically be added to these groups +available-groups.tooltip=Select a group you want to add as a default. +membership.available-groups.tooltip=Groups a user can join. Select a group and click the join button. +events.tooltip=Displays saved events for the realm. Events are related to user accounts, for example a user login. To enable persisted events go to config. +login.save-events.tooltip=If enabled login events are saved to the database which makes events available to the admin and account management consoles. +admin.save-events.tooltip=If enabled admin events are saved to the database which makes events available to the admin console. +events-config.tooltip=Displays configuration options to enable persistence of user and admin events. +event-listeners.tooltip=Configure what listeners receive events for the realm. +clear-events.tooltip=Deletes all events in the database. +events.expiration.tooltip=Sets the expiration for events. Expired events are periodically deleted from the database. +saved-types.tooltip=Configure what event types are saved. +include-representation.tooltip=Include JSON representation for create and update requests. +credentials.temporary.tooltip=If enabled user is required to change password on next login +credentials.remove-totp.tooltip=Remove one time password generator for user. +credentials.reset-actions.tooltip=Set of actions to execute when sending the user a Reset Actions Email. 'Verify email' sends an email to the user to verify their email address. 'Update profile' requires user to enter in new personal information. 'Update password' requires user to enter in a new password. 'Configure OTP' requires setup of a mobile password generator. +credentials.reset-actions-email.tooltip=Sends an email to user with an embedded link. Clicking on link will allow the user to execute the reset actions. They will not have to login prior to this. For example, set the action to update password, click this button, and the user will be able to change their password without logging in. +user-enabled.tooltip=A disabled user cannot login. +user-temporarily-locked.tooltip=The user may have been locked due to failing to login too many times. +email-verified.tooltip=Has the user's email been verified? +required-user-actions.tooltip=Require an action when the user logs in. 'Verify email' sends an email to the user to verify their email address. 'Update profile' requires user to enter in new personal information. 'Update password' requires user to enter in a new password. 'Configure OTP' requires setup of a mobile password generator. +impersonate-user.tooltip=Login as this user. If user is in same realm as you, your current login session will be logged out before you are logged in as this user. +group-membership.tooltip=Groups user is a member of. Select a listed group and click the Leave button to leave the group. +import-keys-and-cert.tooltip=Upload the client's key pair and cert. +authz-icon-uri.tooltip=An URI pointing to an icon. +authz-authorization-services-enabled.tooltip=Enable/Disable fine-grained authorization support for a client +authz-import-config.tooltip=Import a JSON file containing authorization settings for this resource server. +authz-policy-enforcement-mode.tooltip=The policy enforcement mode dictates how policies are enforced when evaluating authorization requests. 'Enforcing' means requests are denied by default even when there is no policy associated with a given resource. 'Permissive' means requests are allowed even when there is no policy associated with a given resource. 'Disabled' completely disables the evaluation of policies and allow access to any resource. +authz-remote-resource-management.tooltip=Should resources be managed remotely by the resource server? If false, resources can only be managed from this admin console. +authz-export-settings.tooltip=Export and download all authorization settings for this resource server. +authz-resource-name.tooltip=An unique name for this resource. The name can be used to uniquely identify a resource, useful when querying for a specific resource. +authz-resource-owner.tooltip=The owner of this resource. +authz-resource-type.tooltip=The type of this resource. It can be used to group different resource instances with the same type. +authz-resource-uri.tooltip=An URI that can also be used to uniquely identify this resource. +authz-resource-scopes.tooltip=The scopes associated with this resource. +authz-scope-name.tooltip=An unique name for this scope. The name can be used to uniquely identify a scope, useful when querying for a specific scope. +authz-policy-name.tooltip=The name of this policy. +authz-policy-description.tooltip=A description for this policy. +authz-policy-logic.tooltip=The logic dictates how the policy decision should be made. If 'Positive', the resulting effect (permit or deny) obtained during the evaluation of this policy will be used to perform a decision. If 'Negative', the resulting effect will be negated, in other words, a permit becomes a deny and vice-versa. +authz-policy-apply-policy.tooltip=Specifies all the policies that must be applied to the scopes defined by this policy or permission. +authz-policy-decision-strategy.tooltip=The decision strategy dictates how the policies associated with a given policy are evaluated and how a final decision is obtained. 'Affirmative' means that at least one policy must evaluate to a positive decision in order to the overall decision be also positive. 'Unanimous' means that all policies must evaluate to a positive decision in order to the overall decision be also positive. 'Consensus' means that the number of positive decisions must be greater than the number of negative decisions. If the number of positive and negative is the same, the final decision will be negative. +authz-policy-user-users.tooltip=Specifies which user(s) are allowed by this policy. +authz-policy-time-not-before.tooltip=Defines the time before which the policy MUST NOT be granted. Only granted if current date/time is after or equal to this value. +authz-policy-time-not-on-after.tooltip=Defines the time after which the policy MUST NOT be granted. Only granted if current date/time is before or equal to this value. +authz-policy-js-code.tooltip=The JavaScript code providing the conditions for this policy. +authz-permission-name.tooltip=The name of this permission. +authz-permission-description.tooltip=A description for this permission. +authz-permission-resource-apply-to-resource-type.tooltip=Specifies if this permission would be applied to all resources with a given type. In this case, this permission will be evaluated for all instances of a given resource type. +authz-permission-resource-resource.tooltip=Specifies that this permission must be applied to a specific resource instance. +authz-permission-resource-type.tooltip=Specifies that this permission must be applied to all resources instances of a given type. +authz-permission-scope-resource.tooltip=Restrict the scopes to those associated with the selected resource. If not selected all scopes would be available. +authz-evaluation-identity-information.tooltip=The available options to configure the identity information that will be used when evaluating policies. +authz-evaluation-client.tooltip=Select the client making this authorization request. If not provided, authorization requests would be done based on the client you are in. +authz-evaluation-user.tooltip=Select an user whose identity is going to be used to query permissions from the server. +authz-evaluation-role.tooltip=Select the roles you want to associate with the selected user. +authz-evaluation-contextual-info.tooltip=The available options to configure any contextual information that will be used when evaluating policies. +authz-evaluation-contextual-attributes.tooltip=Any attribute provided by a running environment or execution context. +authz-evaluation-permissions.tooltip=The available options to configure the permissions to which policies will be applied. +authz-evaluation-result.tooltip=The overall result for this permission request. +authz-evaluation-scopes.tooltip=The list of allowed scopes. +authz-evaluation-policies.tooltip=Details about which policies were evaluated and their decisions. +authz-evaluation-authorization-data.tooltip=Represents a token carrying authorization data as a result of the processing of an authorization request. This representation is basically what Keycloak issues to clients asking for permissions. Check the 'authorization' claim for the permissions that were granted based on the current authorization request. diff --git a/keycloak-themes/base/admin/messages/admin-messages_ru.properties b/keycloak-themes/base/admin/messages/admin-messages_ru.properties new file mode 100644 index 0000000..2598546 --- /dev/null +++ b/keycloak-themes/base/admin/messages/admin-messages_ru.properties @@ -0,0 +1,1277 @@ +# encoding: utf-8 +consoleTitle=Консоль администратора Keycloak +# Common messages +enabled=Включено +hidden=Скрыто +link-only-column=Только ссылки +name=Имя +displayName=Отображаемое название +displayNameHtml=Отображаемое название в HTML +save=Сохранить +cancel=Отмена +onText=ВКЛ +offText=ВЫК +client=Клиент +clients=Клиенты +clear=Очистить +selectOne=Выбрать... + +true=Да +false=Нет + +endpoints=Конечные точки + +# Realm settings +realm-detail.enabled.tooltip=Пользователи и клиенты могут получить доступ к Realm только если он включен +realm-detail.oidc-endpoints.tooltip=Показать конфигурацию конечных точек OpenID Connect +registrationAllowed=Самостоятельная регистрация пользователей +registrationAllowed.tooltip=Включить/выключить страницу регистрации. Ссылка для регистрации будет также показана на странице входа. +registrationEmailAsUsername=E-mail как имя пользователя +registrationEmailAsUsername.tooltip=Если включено, то на форме регистрации поле имени пользователя будет скрыто и в качестве имени пользователя для новых пользователей будет использоваться E-mail. +editUsernameAllowed=Редактируемое имя пользователя +editUsernameAllowed.tooltip=Если включено,то имя пользователя можно будет отредактировать, иначе оно будет доступным только для чтения. +resetPasswordAllowed=Сброс пароля +resetPasswordAllowed.tooltip=Показывает ссылку на странице входа для пользователя, по переходу на которую пользователь сможет восстановить свои данные для входа. +rememberMe=Запомнить меня +rememberMe.tooltip=Показать чекбокс на странице входа, чтобы разрешить пользователю запомнить вход в учетную запись в случае если браузерная сессия устареет. +loginWithEmailAllowed=Вход по E-mail +loginWithEmailAllowed.tooltip=Разрешает пользователям входить с помощью E-mail. +duplicateEmailsAllowed=Дублирующиеся E-mail +duplicateEmailsAllowed.tooltip=Разрешает разным пользователям иметь один и тот же E-mail. Изменение этой настройки также очистит пользовательский кэш. После выключения поддержки дублирующихся email рекомендуется вручную почистить в базе данных ограничения по E-mail существующим пользователям. +verifyEmail=Подтверждение E-mail +verifyEmail.tooltip=Требует у пользователя подтвердить свой E-mail при первом входе в учетную запись. +sslRequired=Требует SSL +sslRequired.option.all=все запросы +sslRequired.option.external=внешние запросы +sslRequired.option.none=нет +sslRequired.tooltip=Требуется ли HTTPS? 'нет' означает, что HTTPS не требуется для клиентов с любым IP адресом. 'Внешние запросы' означает, что localhost и внутренние IP адреса могут получить доступ без HTTPS. 'Все запросы' означает, что HTTPS требуется вне зависимости от IP адреса. +publicKeys=Публичные ключи +publicKey=Публичный ключ +privateKey=Приватный ключ +gen-new-keys=Сгенерировать новый ключ +certificate=Сертификат +host=Сервер +smtp-host=SMTP сервер +port=Порт +smtp-port=SMTP порт (по умолчанию 25) +from=От +sender-email-addr=E-mail отправителя +enable-ssl=Включить SSL +enable-start-tls=Включить StartTLS +enable-auth=Включить аутентификацию +username=Имя пользователя +login-username=Имя пользователя для входа +password=Пароль +login-password=Пароль для входа +login-theme=Тема страницы входа +login-theme.tooltip=Выберите тему для страниц входа, временного одноразового пароля (OTP), выдачи разрешений, регистрации и восстановления пароля. +account-theme=Тема учетной записи +account-theme.tooltip=Выберите тему для управления учетной записью пользователя. +admin-console-theme=Тема консоли администратора +select-theme-admin-console=Выберите тему для консоли администратора. +email-theme=Тема для E-mail +select-theme-email=Выберите тему для E-mail, которые будут отсылаться с сервера. +i18n-enabled=Интернационализация +supported-locales=Поддерживаемые языки +supported-locales.placeholder=Выберите язык и нажмите Enter +default-locale=Язык по умолчанию +#localization-upload-file=Upload localization JSON file +#missing-locale=Missing locale. +#missing-file=Missing file. Please select a file to upload. +#localization-file.upload.success=The localization data has been loaded from file. +#localization-file.upload.error=The file can not be uploaded. Please verify the file. +#localization-show=Show realm specific localizations +#no-localizations-configured=No realm specific localizations configured +#add-localization-text=Add localization text +#locale.create.success=The Locale has been created. +#localization-text.create.success=The localization text has been created. +#localization-text.update.success=The localization text has been updated. +#localization-text.remove.success=The localization text has been deleted. +realm-cache-clear=Кэш Realm +realm-cache-clear.tooltip=Удалить все записи в кэше realm (удалит все записи для всех realm) +user-cache-clear=Кэш пользователей +user-cache-clear.tooltip=Очистить все записи в пользовательском кэше (это удалит записи для всех realm) +keys-cache-clear=Кэш ключей +keys-cache-clear.tooltip=Очистить все записи в кэше внешних публичных ключей. Эти ключи внешних ключей или провайдеров идентификации. (это очистит все записи для всех realm) +revoke-refresh-token=Одноразовые токены обновления +revoke-refresh-token.tooltip=Если включено, то токены обновления могут быть использованы один раз. Иначе токен отзываться не будет и может использоваться многократно. +sso-session-idle=Таймаут сессии SSO +seconds=секунд +minutes=минут +hours=часов +days=дней +sso-session-max=Ограничение сессии SSO +sso-session-idle.tooltip=Допустимое время бездействия сессии. По истечении этого времени токены и браузерные сессии становятся невалидными. +sso-session-max.tooltip=Максимальное время до того, как истечет сессия. По истечении этого времени токены и браузерные сессии становятся невалидными. +offline-session-idle=Таймаут оффлайн сессии +offline-session-idle.tooltip=Допустимое время бездействия оффлайн сессии. Вам необходимо использовать оффлайн токен для обновления хотя бы раз за этот период, иначе сессия истечет. +access-token-lifespan=Продолжительность жизни токена доступа +access-token-lifespan.tooltip=Максимальное время действия токена доступа. Значение рекомендуется устанавливать как можно ближе к таймауту SSO. +access-token-lifespan-for-implicit-flow=Продолжительность жизни токена доступа для Implicit Flow +access-token-lifespan-for-implicit-flow.tooltip=Максимальное время действия токена доступа после того как сессия токена OpenID Connect Implicit Flow истекла. Это значение рекомендуется установить как можно ближе к таймауту SSO. Нет возможности обновить токен во время Implicit Flow, поэтому этот таймаут отличается от 'Продолжительности жизни токена доступа' +client-login-timeout=Таймаут авторизации клиента +client-login-timeout.tooltip=Максимальное время клиента для завершения протокола access token. Обычно устанавливается равным 1-ой минуте. +login-timeout=Таймаут входа +login-timeout.tooltip=Максимальное время пользователя для завершения входа. Рекомендуется установить относительно большое значение (30 минут и более). +login-action-timeout=Таймаут действий по входу +login-action-timeout.tooltip=Максимальное время, за которое пользователь должен выполнить и завершить действие после входа. Например, обновление пароля или конфигурация одноразового временного пароля. Рекомендуется установить относительно большое значение (5 минут и более). +headers=Заголовки +brute-force-detection=Определение Brute Force +x-frame-options=X-Frame-Options +x-frame-options-tooltip=Значение по умолчанию не позволяет страницам быть включенными в iframe сторонних сайтов (перейдите по ссылке для получения дополнительной информации) +content-sec-policy=Content-Security-Policy +content-sec-policy-tooltip=Значение по умолчанию не позволяет страницам быть включенными в iframe сторонних сайтов (перейдите по ссылке для получения дополнительной информации) +content-type-options=X-Content-Type-Options +content-type-options-tooltip=Значение по умолчанию не позволяет браузерам Internet Explorer и Google Chrome вычислять тип содержимого в ответе от сервера дальше от объявленного типа содержимого (перейдите по ссылке для получения дополнительной информации) +max-login-failures=Максимальное количество неудачных попыток входа +max-login-failures.tooltip=Количество неудачных попыток входа до блокировки пользователя. +wait-increment=Порог ожидания +wait-increment.tooltip=Если порог ошибок превышен, сколько времени пользователь будет заблокирован? +quick-login-check-millis=Проверка количества миллисекунд между попытками входа +quick-login-check-millis.tooltip=Если попытки аутентификации происходят слишком часто, то пользователя необходимо заблокировать. +min-quick-login-wait=Минимальное ожидание быстрого входа +min-quick-login-wait.tooltip=Как долго ждать после неудачной попытки быстрого входа. +max-wait=Максимальное ожидание +max-wait.tooltip=Максимальное время, на которое пользователь будет заблокирован. +failure-reset-time=Время сброса неудачных попыток +failure-reset-time.tooltip=Через какое время счетчик неудачных попыток будет сброшен? +realm-tab-login=Вход +realm-tab-keys=Ключи +realm-tab-email=E-mail +realm-tab-themes=Темы +#realm-tab-localization=Localization +realm-tab-cache=Кэш +realm-tab-tokens=Токены +realm-tab-client-initial-access=Первоначальные токены доступа +realm-tab-security-defenses=Защита безопасности +realm-tab-general=Главная +add-realm=Добавить realm + +#Session settings +realm-sessions=Настройки Realm +revocation=Отзыв +logout-all=Разлогинить все сессии +active-sessions=Активные сессии +sessions=Сессии +not-before=Не ранее чем +not-before.tooltip=Отозвать любые токены, выданные ранее этой даты. +set-to-now=Установить на сейчас +push=Разослать +push.tooltip=Уведомить каждого клиента, имеющего URL администратора, о новой политике отзыва токена. + +#Protocol Mapper +usermodel.prop.label=Свойство +usermodel.prop.tooltip=Имя свойства метода в интерфейсе UserModel. Для примера, значение 'email' будет ссылкой на метод UserModel.getEmail(). +usermodel.attr.label=Атрибут пользователя +usermodel.attr.tooltip=Имя сохраненного атрибута пользователя, которое является именем атрибута, согласованным с UserModel.attribute. +userSession.modelNote.label=Заметка сессии пользователя +userSession.modelNote.tooltip=Наименование процедуры заметки сессии пользователя согласованным с UserSessionModel.note. +multivalued.label=Несколько значений +multivalued.tooltip=Отображается, если атрибут поддерживает несколько значений. Если включен, то список всех значений будет претендовать на этот атрибут. В противном случае выбираться будет только первое значение +selectRole.label=Выберите роль +selectRole.tooltip=Введите роль в текстовом поле слева, или нажмите на кнопку, чтобы выбрать желаемую роль. +tokenClaimName.label=Имя переменной в токене +tokenClaimName.tooltip=Имя переменной при добавлении ее в токен. Может быть полное имя, например 'address.street'. В таком случае будет создан вложенный json объект. +jsonType.label=Тип переменной JSON +jsonType.tooltip=Тип переменной в JSON, который должен использоваться при добавлении ее в токен. Допустимые значения long, int, boolean, и String. +includeInIdToken.label=Добавить в токен ID +includeInIdToken.tooltip=Должно ли значение быть добавлено в токен ID? +includeInAccessToken.label=Добавить в токен доступа +includeInAccessToken.tooltip=Должно ли значение быть добавлено в токен доступа? +includeInUserInfo.label=Добавить в информацию о пользователе +includeInUserInfo.tooltip=Должно ли требование быть добавлено в информацию о пользователе? +usermodel.clientRoleMapping.clientId.label=ID клиента +usermodel.clientRoleMapping.clientId.tooltip=ID клиента для сопоставления ролей +usermodel.clientRoleMapping.rolePrefix.label=Префикс ролей клиента +usermodel.clientRoleMapping.rolePrefix.tooltip=Префикс для каждой роли клиента (опционально). +usermodel.realmRoleMapping.rolePrefix.label=Префикс ролей Realm +usermodel.realmRoleMapping.rolePrefix.tooltip=Префикс для каждой роли Realm (опционально). +sectorIdentifierUri.label=Сектор идентификации URI +sectorIdentifierUri.tooltip=Провайдеры, использующие пары вспомогательных значений и поддерживающие динамическую регистрацию клиентов ДОЛЖНЫ использовать sector_identified_uri параметр. Это обеспечивает способ для группы сайтов под общим административным контролем, чтобы иметь последовательные попарные значения независимо от индивидуальных доменных имен. Это также обеспечивает способ для клиентов для изменения redirect_uri доменов, не имещющих возможности перерегистрации всех своих пользователей. +pairwiseSubAlgorithmSalt.label=Соль +pairwiseSubAlgorithmSalt.tooltip=Соль, используемая для вычисления парного субъекта идентификатора. Если поле не заполнено, то соль будет сгенерирована. +addressClaim.street.label=Имя пользовательского атрибута, обозначающего Улицу +addressClaim.street.tooltip=Имя пользовательского атрибута, которое будет использоваться для сопоставления атрибута 'street_address' внутри атрибута 'address' токена. По умолчанию 'street' . +addressClaim.locality.label=Имя пользовательского атрибута, обозначающего Местонахождение +addressClaim.locality.tooltip=Имя пользовательского атрибута, которое будет использоваться для сопоставления атрибута 'locality' внутри атрибута 'address' токена. По умолчанию 'locality' . +addressClaim.region.label=Имя пользовательского атрибута, обозначающего Регион +addressClaim.region.tooltip=Имя пользовательского атрибута, которое будет использоваться для сопоставления атрибута 'region' внутри атрибута 'address' токена. По умолчанию 'region' . +addressClaim.postal_code.label=Имя пользовательского атрибута, обозначающего Почтовый индекс +addressClaim.postal_code.tooltip=Имя пользоватеслького атрибута, котоое будет использоваться для сопоставления атрибута 'postal_code' внутри атрибута 'address' токена. По умолчанию 'postal_code' . +addressClaim.country.label=Имя пользовательского атрибута, обозначающего Страна +addressClaim.country.tooltip=Имя пользовательского атрибута, которое будет использоватлься для сопоставления атрибута 'country' внутри атрибута 'address' токена. По умолчанию 'country' . +addressClaim.formatted.label=Имя пользовательсокого атрибута, обозначающего Формитированный адрес +addressClaim.formatted.tooltip=Имя пользовательского атрибута, которое будет использоваться для сопоставления атрибута 'formatted' внутри атрибута 'address' токена. По умолчанию 'formatted' . + +# client details +clients.tooltip=Клиенты доверенных браузерных приложений и веб-сервисов в realm. Эти клиенты могут запрашивать вход. Вы также можете определить конкретные роли клиента. +search.placeholder=Поиск... +create=Создать +import=Импорт +client-id=ID клиента +base-url=Базовый URL +actions=Действия +not-defined=Не задан +edit=Редактировать +delete=Удалить +no-results=Нет результатов +no-clients-available=Нет доступных клиентов +add-client=Добавить клиента +select-file=Выберите файл +view-details=Смотреть детали +clear-import=Очистить импорт +client-id.tooltip=Задает идентификатор, указываемый в URI и в токенах. Например 'my-client'. Для SAML это также ожидаемое имя издателя для запросов аутентификации +client.name.tooltip=Задает отображаемое название клиента. Например 'My Client'. Поддерживает ключи для локализованных значений. Например\\: ${my_client} +client.enabled.tooltip=Отключенные клиенты не могут инициировать вход или иметь возможность получить токены доступа. +consent-required=Необходимо согласие +consent-required.tooltip=Если включено, пользователи должны дать согласие на доступ клиентскому приложению. +client-protocol=Протокол клиента +client-protocol.tooltip='OpenID connect' разрешает клиентам проверить личность конечного пользователя, основанного на выполнении аутентификации на Сервере Авторизации.'SAML' включает веб-сценарии аутентификации и авторизации, включая кроссдоменные центры единого управления доступом (SSO) и использующие токены безопасности, содержащие заявления на передачу информации. +access-type=Тип доступа +access-type.tooltip='Confidential' клиенты требуют секрет для инициализации протокола входа. 'Public' клиентам секрет не требуется. 'Bearer-only' клиенты и веб-сервисы никогда не инициализируют вход. +standard-flow-enabled=Standard Flow включен +standard-flow-enabled.tooltip=Включает стандартное OpenID Connect перенаправление, основанное на аутентификации с кодом авторизации. В терминах OpenID Connect или OAuth2 спецификаций включает 'Authorization Code Flow' для этого клиента. +implicit-flow-enabled=Implicit Flow включен +implicit-flow-enabled.tooltip=Включает поддержку OpenID Connect перенаправления, основанного на аутентификации без кода авторизации. В терминах OpenID Connect или OAuth2 спецификаций включает поддержку 'Implicit Flow' для этого клиента. +direct-access-grants-enabled=Direct Access Grants включен +direct-access-grants-enabled.tooltip=Включает поддержку Direct Access Grants, которая означает, что клиент имеет доступ к имени пользователя и пароля и обменивает их напрямую с сервером Keycloak на токен доступа. В терминах OAuth2 спецификации означает поддержку 'Resource Owner Password Credentials Grant' для этого клиента. +service-accounts-enabled=Service Accounts включен +service-accounts-enabled.tooltip=Разрешает Вам аутентифицировать этого клиента в Keycloak и получить токен доступа специально для этого клиента. В терминах OAuth2 спецификации включает поддержку 'Client Credentials Grant' для этого клиента. +include-authnstatement=Включать Аутентификационные Заявки +include-authnstatement.tooltip=Должны ли заявки на методы и временные метки быть включены в ответе на вход? +include-onetimeuse-condition=Включить условие одноразового использования +include-onetimeuse-condition.tooltip=Должно ли условие одноразового использования быть включено в ответе на вход? +sign-documents=Подпись документов +sign-documents.tooltip=Должны ли SAML документы быть подписаны в realm? +sign-documents-redirect-enable-key-info-ext=Оптимизация REDIRECT поиска подписанного ключа +sign-documents-redirect-enable-key-info-ext.tooltip=При подписи SAML документов при REDIRECT сопоставлении с SP, который обеспечивается безопасностью адаптера Keycloak, должен ли включать ID подписанного ключа в сообщение по протоколу SAML в элемент? Это оптимизирует валидацию сигнатуры, где в качестве проверки используется один ключ вместо попытки проверки каждого ключа во время валидации. +sign-assertions=Sign Assertions +sign-assertions.tooltip=Должны ли утверждения внутри SAML документов быть подписаны? Устанавливает отсутствие необходимости подписывать уже подписанные документы. +signature-algorithm=Алгоритм подписи +signature-algorithm.tooltip=Алгоритм, используемый для подписи документов. +canonicalization-method=Метод канонизации +canonicalization-method.tooltip=Метод канонизации для XML сигнатур. +encrypt-assertions=Зашифровка утверждений +encrypt-assertions.tooltip=Должны ли SAML утверждения быть зашифрованы публичным ключом клиента, используя AES? +client-signature-required=Подпись клиента обязательна +client-signature-required.tooltip=Будет ли клиент подписывать свои saml запросы и ответы? И должны ли они быть провалидированы? +force-post-binding=Принудительно использовать POST Binding +force-post-binding.tooltip=Всегда использовать POST Binding для ответов. +front-channel-logout=Выход с переднего канала +front-channel-logout.tooltip=Когда правила, выход требует перенаправить браузер на клиента. Если ложь, сервер выполняет фоновый режим для выхода из системы. +force-name-id-format=Принудительно использовать формат ID +force-name-id-format.tooltip=Игнорирует запрошенный формат заголовка NameID и использует сконфигурированный через консоль администратора. +name-id-format=Наименование формата ID +name-id-format.tooltip=Наименование формата ID для использования в теме. +root-url=Корневой URL +root-url.tooltip=Корневой URL добавляется к относительным URL +valid-redirect-uris=Валидация URI перенаправления +valid-redirect-uris.tooltip=Валидирует паттерн URI, на который может быть перенаправлен браузер после успешного входа или выхода. Разрешены простые ссылки, напр. 'http://example.com/*'. Также допускается использовать относительный путь, напр. '/my/relative/path/*'. Относительные пути необходимо указывать относительно корневого URL клиента, или, если он не специфицирован, корневого URL сервера авторизации. Для SAML Вы должны задать валидный паттерн URI, если Вы полагаетесь на URL сервиса потребителя, внедренного в запрос авторизации. +base-url.tooltip=Используемый URL по умолчанию. Используется в случае, если серверу требуется перенаправление или обратная ссылка на клиента. +admin-url=URL администрирования приложения +admin-url.tooltip=URL для доступа к интерфейсу администратора в заданном клиенте. Необходимо установить, если клиент поддерживает адаптер REST API. Это REST API разрешает серверу авторизации слать политики отзыва и прочие административные задачи. Обычно устанавливается значение, соответствующее базовому URL клиента. +master-saml-processing-url=Основной URL обработчика SAML +master-saml-processing-url.tooltip=Если URL сконфигурирован, то он будет каждый раз для связывания SP's Assertion Consumer и Single Logout Services. Может быть переопределен индивидуально для связывания каждого сервиса в тонкой настройке конфигурации конечных точек доступа SAML. +idp-sso-url-ref=Наименование URL для поставщика идентификации IDP, инициирующего SSO +idp-sso-url-ref.tooltip=Имя URL фрагмента, обозначающего клиента, если вы хотите, чтобы SSO был проинициирован поставщиком идентификации. Оставьте это поле пустым, чтобы отключить инициирование SSO с помощью поставщика идентификации. URL для ссылки вашего браузера может быть в следующем виде: {server-root}/realms/{realm}/protocol/saml/clients/{client-url-name} +idp-sso-relay-state=Передача состояния SSO инициирующим поставщиком идентификации +idp-sso-relay-state.tooltip=Передать состояние, которое вы хотите послать вместе с SAML запросом, которым хотите проиницировать SSO поставщиком идентификации. +web-origins=Web источники +web-origins.tooltip=Разрешает CORS источникам. Чтобы разрешить всем источники с допустимыми URI-адресами переадресации, добавьте '+'. Чтобы разрешить все источники, добавьте '*'. +fine-oidc-endpoint-conf=Тонкая настройка конфигурации OpenID Connect +fine-oidc-endpoint-conf.tooltip=Раскройте эту секцию, чтобы сконфигурировать настройки клиента, связанные с протоколом OpenID Connect +user-info-signed-response-alg=Алгоритм подписи ответа информации о пользователе +user-info-signed-response-alg.tooltip=JWA алгоритм используется для подписи ответа ресурса информации о пользователе. Если установлено в 'unsigned', то ответ инофрмации о пользователе не будет подписан и будет возвращен в формате application/json. +request-object-signature-alg=Алгоритм сигнатуры объекта запроса +request-object-signature-alg.tooltip=JWA алгоритм, который необходим клиенту для использования во время отсылки OIDC запроса объекта, специфицированного по 'request' или 'request_uri' параметрам. Если установлено в 'any', то объект запроса будет подписан любым алгоритмом (включая 'none' ). +fine-saml-endpoint-conf=Тонкая настройка конфигурации конечных точек доступа SAML +fine-saml-endpoint-conf.tooltip=Разверните эту секции, чтобы сконфигурировать точные URL-адреса для утвержденного потребителя и сервиса единого выхода. +assertion-consumer-post-binding-url=Привязка URL POST-запроса для сервиса подтверждения потребителей +assertion-consumer-post-binding-url.tooltip=URL-адрес SAML POST запроса для клиентских сервисов подтверждения потребителей (запросы входа). Вы можете оставить это поле пустым, если не имеете URL для осуществления такой приввязки. +assertion-consumer-redirect-binding-url=Привязка URL-адреса переадресации для сервиса подтверждения потребителей +assertion-consumer-redirect-binding-url.tooltip=SAML переадресация на привязанный URL для клиентского сервиса подтверждения потребителей (запросы входа). Вы можете оставить это поле пустым, если вы не имеете URL для осуществления такой привязки. +logout-service-post-binding-url=URL для выхода из сервиса в привязанном POST-методе +logout-service-post-binding-url.tooltip=SAML POST связанный URL для клиентского сервиса единого выхода. Если Вы используете другие привязки, то можете оставить это поле пустым. +logout-service-redir-binding-url=URL переадресации для выхода из сервиса +logout-service-redir-binding-url.tooltip=SAML переадресует на привязанный URL для единой точки выхода из сервиса для клиентов. Если Вы используете другие привязки, то можете остаавить это поле пустым. +saml-signature-keyName-transformer=Наименование ключа сигнатуры SAML +saml-signature-keyName-transformer.tooltip=Подписанные SAML документы содержат идентификаторы ключей подписи в элементе KeyName. Для Keycloak / RH-SSO контрагентов, используйте KEY_ID, для MS AD FS используйте CERT_SUBJECT, для остальных установите и используйте NONE если другие опции не работают. + +# client import +import-client=Импортировать клиента +format-option=Формат +select-format=Выберите формат +import-file=Импортировать файл + +# client tabs +settings=Настройки +credentials=Учетные данные +roles=Роли +mappers=Сопоставления +mappers.tooltip=Протокол сопоставлений, осуществляющих преобразование в токены и документы. Могут делать такие вещи как сопоставление пользовательских данных в заявки протокола, или просто преобразовать любой запрос, происходящий между клиентом и сервером аутентификации. +scope=Область +scope.tooltip=Сопоставление области позволяет вам ограничить сопоставленные роли пользователя, включаемые вместе с токеном доступа, запрошенного клиентом. +sessions.tooltip=Просмотр сессий для этого клиента. Позволяет Вам увидеть, какие пользователи активны и когда они вошли. +offline-access=Оффлайн доступ +offline-access.tooltip=Просмотр оффлайн сессий для этого клиента. Позволяет Вам увидеть, какие пользователи получали оффлайн токен и когда они его получили. Чтобы выбрать все токены для этого клиента, перейдите на вкладку отзыва и установите значение в текущее время. +clustering=Кластеризация +installation=Установка +installation.tooltip=Вспомогательная утилита для генерации различных форматов конфигурации адаптера клиента, которые Вы можете скачать или скопировать для конфигурации Ваших клиентов. +service-account-roles=Роли Service Account +service-account-roles.tooltip=Разрешают Вам аутентифицировать сопоставленные роли для сервиса учетных записей, выделенного для этого клиента. + +# client credentials +client-authenticator=Проверка подлинности клиента +client-authenticator.tooltip=Проверка подлинности клиента используется для аутентификации этого клиента вместо сервера Keycloak +certificate.tooltip=Клиентский сертификат для валидации JWT, выпущенный клиентом и подписанный клиентским приватным ключом из Вашего хранилища ключей. +publicKey.tooltip=Публичный ключ для валидации JWT, выпущенный клиентом и подписанный клиентским приватным ключом. +no-client-certificate-configured=Клиентский сертификат не сконфигурирован +gen-new-keys-and-cert=Сгенерировать новые ключи и сертификат +import-certificate=Импортировать сертификат +gen-client-private-key=Сгенерировать приватный ключ клиента +generate-private-key=Сгенерировать приватный ключ +kid=KID +kid.tooltip=KID (Key ID) публичного ключа клиента из импортированного JWKS. +use-jwks-url=Использовать JWKS URL +use-jwks-url.tooltip=Если включено, то публичные ключи клиента будут скачиваться с заданного адреса JWKS. Это дает большую гибкость, поскольку в случае, если клиент сгенерирует новую пару, то новые ключи всегда будут перезакачиваться. Если выключено, то используется публичный ключ (или сертификат) из базы Keycloak DB, так если пара клиента изменится, вам будет необходимо всегда импортировать новый ключ (или сертификат) в базу Keycloak. +jwks-url=JWKS URL +jwks-url.tooltip=URL, где клиентские ключи хранятся в формате JWK. Для дополнительных деталей смотрите спецификацию JWK. Если Вы будете использовать адаптер клиента keycloak с учетными записями "jwt", то Вы можете использовать URL вашего приложения с суффиксом '/k_jwks'. Например 'http://www.myhost.com/myapp/k_jwks' . +archive-format=Формат архивации +archive-format.tooltip=Формат архивации Java keystore или PKCS12. +key-alias=Синоним ключа +key-alias.tooltip=Синоним архива для Вашего приватного ключа и сертификата. +key-password=Пароль для ключа +key-password.tooltip=Пароль для доступа к приватного ключу в архиве +store-password=Пароль хранилища +store-password.tooltip=Пароль для доступа в сам архив +generate-and-download=Сгенерировать и скачать +client-certificate-import=Импорт сертификата клиента +import-client-certificate=Импорт сертификата клиента +jwt-import.key-alias.tooltip=Синоним архива для вашего сертификата. +secret=Секрет +regenerate-secret=Перегенерировать секрет +registrationAccessToken=Токен доступа к регистрации +registrationAccessToken.regenerate=Перегенерировать токен доступа к регистрации +registrationAccessToken.tooltip=Токен доступа к регистрации обеспечивает доступ для клиентов к сервису регистрации клиентов. +add-role=Добавить роль +role-name=Наименование роли +composite=Составная +description=Описание +no-client-roles-available=Нет доступных ролей клиента +scope-param-required=Требуется параметр области +scope-param-required.tooltip=Эта роль будет предоставлена только если параметр области с наименованием роли используется в запросах авторизации/получения токена. +composite-roles=Составные роли +composite-roles.tooltip=Когда эта роль (не)ассоциирована с любой ролью пользователей, она (не)будет неявно ассоциирована. +realm-roles=Роли Realm +available-roles=Доступные роли +add-selected=Добавить выбранное +associated-roles=Ассоциированные роли +composite.associated-realm-roles.tooltip=Роли уровня Realm, ассоциированные с составными ролями. +composite.available-realm-roles.tooltip=Роли уровня Realm, ассоциированные с этой составной ролью. +remove-selected=Удалить выбранное +client-roles=Роли клиентов +select-client-to-view-roles=Выберите клиента для просмотра его ролей +available-roles.tooltip=Роли этого клиента, которые вы можете ассоциировать с составной ролью. +client.associated-roles.tooltip=Клиентские роли, ассоциированные с составной ролью. +add-builtin=Добавить встроенные +category=Категория +type=Тип +no-mappers-available=Сопоставления не доступны +add-builtin-protocol-mappers=Добавить встроенные сопоставления протокола +add-builtin-protocol-mapper=Добавить встроенное сопоставление протокола +scope-mappings=Сопоставление областей +full-scope-allowed=Полный доступ к областям +full-scope-allowed.tooltip=Отключает все ограничения. +scope.available-roles.tooltip=Роли уровня Realm, которые могут быть присвоены области. +assigned-roles=Присвоенные роли +assigned-roles.tooltip=Роли уровня Realm, присвоенные области. +effective-roles=Назначенные роли +realm.effective-roles.tooltip=Назначенные роли уровня realm, которые могут быть унаследованы из составной роли. +select-client-roles.tooltip=Выберите клиента для просмотра его ролей +assign.available-roles.tooltip=Роли клиентов, доступные для назначения. +client.assigned-roles.tooltip=Назначенные роли клиента. +client.effective-roles.tooltip=Назначенные роли клиента, которые можно унаследовать из составной роли. +basic-configuration=Основная конфигурация +node-reregistration-timeout=Таймаут узла перерегистрации +node-reregistration-timeout.tooltip=Интервал, означающий максимальное время для узлов кластера зарегистрированных клиентов для их перерегистрации. Если узел кластера не может послать запрос перерегистрации в Keycloak за указанное время, то он будет разрегистрирован из Keycloak +registered-cluster-nodes=Зарегистрированные узлы кластера +register-node-manually=Зарегистрировать узел вручную +test-cluster-availability=Протестировать доступность кластера +last-registration=Последняя регистрация +node-host=Хост узла +no-registered-cluster-nodes=Нет доступных зарегистрированных узлов кластера +cluster-nodes=Узлы кластера +add-node=Добавить узел +active-sessions.tooltip=Общее количество активных сессий пользователей для этого клиента. +show-sessions=Показать сессии +show-sessions.tooltip=Предупреждение! В случае большого числа активных сессий это будет достаточно накладная операция. +user=Пользователь +from-ip=С IP +session-start=Сессия начата +first-page=Первая страница +previous-page=Последняя страница +next-page=Следующая страница +client-revoke.not-before.tooltip=Отозвать любые токены, выданные до указанной даты для этого клиента. +client-revoke.push.tooltip=Если URL системы администрации сконфигурирован для этого клиента, то необходимо послать политики этому клиенту. +select-a-format=Выберите формат +download=Скачать +offline-tokens=Оффлайн токены +offline-tokens.tooltip=Общее количество оффлайн токенов для этого клиента. +show-offline-tokens=Показать оффлайн токены +show-offline-tokens.tooltip=Предупреждение! В случае большого числа активных сессий это будет достаточно накладная операция. +token-issued=Токен выдан +last-access=Последний доступ +last-refresh=Последнее обновление +key-export=Экспорт ключа +key-import=Импорт ключа +export-saml-key=Экспорт SAML ключа +import-saml-key=Импорт SAML ключа +realm-certificate-alias=Синоним сертификата Realm +realm-certificate-alias.tooltip=Это синоним сертификата. Сам сертификат Realm также сохраняется в архиве. +signing-key=Ключ подписи +saml-signing-key=SAML-ключ подписи. +private-key=Приватный ключ +generate-new-keys=Сгенерировать новые ключи +export=Экспорт +encryption-key=Ключ шифрования +saml-encryption-key.tooltip=SAML ключ шифрования. +service-accounts=Учетные записи сервиса +service-account.available-roles.tooltip=Роли уровня Realm, которые могут быть присвоены учетной записи сервиса. +service-account.assigned-roles.tooltip=Роли уровня Realm, назначенные учетной записи сервиса. +service-account-is-not-enabled-for=Учетная запись сервиса не включена для {{client}} +create-protocol-mappers=Создать сопоставление протокола +create-protocol-mapper=Создать сопоставление протокола +protocol=Протокол +protocol.tooltip=Протокол... +id=ID +mapper.name.tooltip=Наименование сопоставления. +mapper.consent-required.tooltip=Необходимо ли согласие пользователя на предоставление этой информации клиенту? +consent-text=Текст согласования +consent-text.tooltip=Текст, который будет показан пользователю на странице согласования. +mapper-type=Тип сопоставления +mapper-type.tooltip=Тип сопоставления +# realm identity providers +identity-providers=Поставщики идентификации +table-of-identity-providers=Таблица поставщиков идентификации +add-provider.placeholder=Добавить поставщика... +provider=Поставщик +gui-order=Очередность в GUI +first-broker-login-flow=Сценарий первого входа +post-broker-login-flow=Сценарий после входа +redirect-uri=URI перенаправления +redirect-uri.tooltip=Этот uri перенаправления используется в том случае, если сконфигурирован поставщик идентификации. +alias=Синоним +display-name=Отображаемое название +identity-provider.alias.tooltip=Синоним уникально идентифицирует поставщика идентификации, а также используется для построения адреса переадресации. +identity-provider.display-name.tooltip=Дружелюбное имя для провайдеров идентификации. +identity-provider.enabled.tooltip=Включает/выключает этого поставщика идентификации. +authenticate-by-default=Аутентификация по умолчанию +identity-provider.authenticate-by-default.tooltip=Отображается, если поставщик должен быть использован для аутентифиакации по умолчанию даже перед отображением экрана входа. +store-tokens=Хранение токенов +identity-provider.store-tokens.tooltip=Включено/выключено хранение токенов после аутентификации пользователя. +stored-tokens-readable=Сохраненные токены доступны на чтение +identity-provider.stored-tokens-readable.tooltip=Включено/выключено чтение новыми пользователями любых сохраненных токенов. Это назначается ролью broker.read-token. +disableUserInfo=Отключить информацию о пользователе +identity-provider.disableUserInfo.tooltip=Отключить использование сервиса информации о пользователе, чтобы получить дополнительную информацию о пользователе? По умолчанию используется сервис OIDC. +userIp=Использовать параметр userIp +identity-provider.google-userIp.tooltip=Установить 'userIp' параметр запроса при вызове сервиса Google's. Будет использовать ip адрес пользователя. Полезно, если Google будет подавлять доступ к сервису информации о пользователе. +update-profile-on-first-login=Обновить профиль при первом входе +on=Вкл +on-missing-info=При пропущенной инфо +off=Вык +update-profile-on-first-login.tooltip=Определить условия, при которых пользователи должны обновлять свой профиль во время первого входа. +trust-email=Подтверждение E-mail +trust-email.tooltip=Если включено, то E-mail, предоставленный этим поставщиком не будет подтвержденным даже если подтверждение включено для realm. +link-only=Только связывание учетной записи +link-only.tooltip=Если установлено, то пользователи не смогут войти через этого провайдера. Только устанавливает связь к этому провайдеру. Используется, если вы не хотите разрешать вход через этого провайдера, но хотите с этим провайдером иметь интеграцию. +hide-on-login-page=Скрыть на странице входа +hide-on-login-page.tooltip=Если скрыто, то вход с этим провайдером возможен только при явном вызове, например при использовании параметра 'kc_idp_hint'. +gui-order.tooltip=Число, определяющее порядок поставщиков в GUI (например, на странице входа). +first-broker-login-flow.tooltip=Синоним сценария аутентификации, который срабатывает после первого входа с этого поставщика идентификации. Термин 'First Login' означает, что еще не существует учетной записи Keycloak связанной с аутентифицированной учетной записью поставщика идентификации. +post-broker-login-flow.tooltip=Синоним сценария аутентификации, который срабатывает после каждого входа из этого поставщика идентификации. Полезно, если вы ходите получить дополнительную проверку каждого пользователя, аутентифицированного в этом поставщике идентификации (например OTP). Оставьте это поле пустым, если не хотите, чтобы срабатывали дополнительные проверки аутенификации после входа пользователя с этим поставщиком идентификации. Также обратите внимание, что реализации аутентификатора должны предполагать что пользователь уже установил ClientSession также как установил ее в поставщике идентификации. +openid-connect-config=Конфигурация OpenID Connect +openid-connect-config.tooltip=OIDC SP и конфигурация внешних IDP. +authorization-url=URL авторизации +authorization-url.tooltip=Url авторизации. +token-url=URL токена +token-url.tooltip=URL токена. +logout-url=URL выхода +identity-provider.logout-url.tooltip=Конечная точка окончания сессии, используемая для выхода пользователя из внешнего IDP. +backchannel-logout=Backchannel Logout +backchannel-logout.tooltip=Поддерживает ли внешний IDP backchannel logout? +user-info-url=URL информации о пользователе +user-info-url.tooltip=Url информации о пользователе. Это поле опционально. +identity-provider.client-id.tooltip=Клиент или идентификатор клиента, зарегистрированного с помощью поставщика идентификации. +client-secret=Секрет клиента +show-secret=Показать секрет +hide-secret=Скрыть секрет +client-secret.tooltip=Клиент или секрет клиента, зарегистрированный с помощью поставщика идентификации. +issuer=Эмитент +issuer.tooltip=Идентификатор эмитента для эмитента ответа. Если не предоставлен, проверка не будет выполняться. +default-scopes=Области по умолчанию +identity-provider.default-scopes.tooltip=Области, которые будут посланы после запроса авторизации. Это может быть список областей, разделенных пробелом. По умолчанию 'openid'. +prompt=Подсказка +unspecified.option=неопределенный +none.option=нет +consent.option=согласие +login.option=вход +select-account.option=выберите_учетную_запись +prompt.tooltip=Указывает, запрашивает ли сервер авторизации у конечного пользователя переаутентификацию и согласие. +validate-signatures=Проверка подписей +identity-provider.validate-signatures.tooltip=Включить/выключить проверку подписей внешних поставщиков идентификации. +identity-provider.use-jwks-url.tooltip=Если включено, то публичные ключи поставщиков идентификации будет скачаны с заданного JWKS URL. Это дает дополнительную гибкость, так как новые ключи скачиваются каждый раз когда поставщик идентификации создает новую пару. Если выключено, то будут использованы публичные ключи (или сертификат) из базы данных Keycloak, и в случае изменений пары на поставщике идентификации вам будет необходимо каждый раз импортировать новые ключи в базу данных Keycloak. +identity-provider.jwks-url.tooltip=URL по которому поставщик идентификации хранит ключи в формате JWK. Для дополнительной информации смотрите спецификацию JWK. Если Вы используете внешнего поставщика идентификации keycloak, то Вы можете использовать URL наподобие 'http://broker-keycloak:8180/auth/realms/test/protocol/openid-connect/certs' предполагая, что ваш посредник keycloak запущен на 'http://broker-keycloak:8180' и его realm 'test' . +validating-public-key=Проверка публичного ключа +identity-provider.validating-public-key.tooltip=Публичный ключ в формате PEM, который должен использоваться для проверки подписей внешних поставщиков идентификации. +validating-public-key-id=Валидация Id публичного ключа +identity-provider.validating-public-key-id.tooltip=Явный ID проверяемого публичного ключа, выданного выше, если есть key ID. Оставьте это поле пустым если ключ выше должен быть использован всегда, независимо от key ID указанного внешнего IDP; установите это если ключ должен быть использован для проверки соответсвтия key ID внешних IDP. +import-external-idp-config=Импортировать конфигурацию внешнего IDP +import-external-idp-config.tooltip=Позволяет вам загрузить метаданные внешнего IDP из файла конфигурации или скачать его из URL. +import-from-url=Импорт из URL +identity-provider.import-from-url.tooltip=Импорт метаданных из дескриптора развертывания удаленного поставщика идентификации. +import-from-file=Импорт из файла +identity-provider.import-from-file.tooltip=Импорт метаданных со скачанного дескриптора развертывания удаленного поставщика идентификации. +saml-config=Конфигурация SAML +identity-provider.saml-config.tooltip=Конфигурация SAML SP и внешних IDP. +single-signon-service-url=Адрес сервиса единой точки входа +saml.single-signon-service-url.tooltip=Url, который должен быть использован для отправленных запросов на аутентификацию (SAML AuthnRequest). +single-logout-service-url=Адреса сервиса единого выхода +saml.single-logout-service-url.tooltip=Url, который должен быть использован для отправленных запросов на выход. +nameid-policy-format=Формат политики NameID +nameid-policy-format.tooltip=Определяет ссылку URI, соответствующую формату идентификатора имени. По умолчанию urn:oasis:names:tc:SAML:2.0:nameid-format:persistent. +saml.principal-type=Тип идентификации +saml.principal-type.tooltip=Определяет, каким образом Keycloak идентифицирует внешних пользователей по SAML-сообщению. По умолчанию идентификация происходит по Subject NameID, в качестве альтернативы можно использовать атрибут-идентификатор. +saml.principal-attribute=Атрибут-идентификатор +saml.principal-attribute.tooltip=Имя (Name) или "дружественное имя" (Friendly Name) атрибута, идентифицирующего внешних пользователей. +http-post-binding-response=Привязанный ответ HTTP-POST +http-post-binding-response.tooltip=Указывает, следует ли отвечать на запросы, используя привязку HTTP-POST. Если нет, то будет использован HTTP-REDIRECT. +http-post-binding-for-authn-request=Привязывание HTTP-POST для AuthnRequest +http-post-binding-for-authn-request.tooltip=Указывает, должны ли AuthnRequest быть посланы, используя привязку HTTP-POST. Если нет, то будет использован HTTP-REDIRECT. +http-post-binding-logout=Привязывание HTTP-POST для выхода +http-post-binding-logout.tooltip=Указывает, необходоимо ли отвечать на завпросы, используя привязку HTTP-POST. Если не задано, то будет использован HTTP-REDIRECT. +want-authn-requests-signed=Ожидание подписи AuthnRequests +want-authn-requests-signed.tooltip=Указывает, ожидает ли поставщик идентификации подписанных AuthnRequest. +force-authentication=Принудительная аутентификация +identity-provider.force-authentication.tooltip=Указывает, должен ли поставщик идентификации аутентифицировать ведущего напрямую, а не использовать предыдущий контекст безопасности. +validate-signature=Проверка подписи +saml.validate-signature.tooltip=Включает/выключает проверку подписи ответов от SAML. +validating-x509-certificate=Проверка X509 сертификатов +validating-x509-certificate.tooltip=Сертификат в формате PEM, который должен быть использован для проверки подписи. +saml.import-from-url.tooltip=Импортировать метаданные из удаленного дескриптора сущностей IDP SAML. +social.client-id.tooltip=Идентификатор клиента, зарегистрированный с помощью поставщика идентификации. +social.client-secret.tooltip=Секрет клиента, зарегистрированный с помощью поставщика идентификации. +social.default-scopes.tooltip=Области, которые будут посланы при запросе авторизации. Смотрите документацию для возможных значений, разделителей и значений по умолчанию. +key=Ключ +stackoverflow.key.tooltip=Ключ, полученный при регистрации клиента в Stack Overflow. + +# User federation +sync-ldap-roles-to-keycloak=Синхронизировать роли LDAP с Keycloak +sync-keycloak-roles-to-ldap=Синхронизировать роли Keycloak с LDAP +sync-ldap-groups-to-keycloak=Синхронизировать группы LDAP с Keycloak +sync-keycloak-groups-to-ldap=Синхронизировать группы Keycloak с LDAP + +realms=Realms +realm=Realm + +identity-provider-mappers=Сопоставление поставщиков идентификации +create-identity-provider-mapper=Создать сопоставление поставщика учетных записей +add-identity-provider-mapper=Добавить сопоставление поставщика учетных записей +client.description.tooltip=Задает описание клиента. Например 'Мой клиент для табеля учета времени'. Поддерживает ключи для локализованных значений. Например: ${my_client_description} + +expires=Истекает +expiration=Истечение +expiration.tooltip=Определяет, как долго токен будет оставаться валидным +count=Счетчик +count.tooltip=Определяет, как много клиентов может быть создано с помощью этого токена +remainingCount=Счетчик остатка +created=Создано +back=Назад +initial-access-tokens=Токены первичного доступа +add-initial-access-tokens=Добавить токен первичного доступа +initial-access-token=Токен первичного доступа +initial-access.copyPaste.tooltip=Необходимо скопировать/вставить токен первичного доступа до того, как покинете эту страницу, т.к. в дальнейшем получить его будет невозможно +continue=Продолжить +initial-access-token.confirm.title=Скопировать токен первичного доступа +initial-access-token.confirm.text=Пожалуйста, скопируйте и вставьте токен первичного доступа до того, как сделаете подтверждение, т.к. в дальнейшем получить его будет невозможно +no-initial-access-available=Нет доступных токенов первичного доступа + +client-reg-policies=Политики регистрации клиента +client-reg-policy.name.tooltip=Отображаемое наименование политики +anonymous-policies=Политики анонимного доступа +anonymous-policies.tooltip=Эти политики будут использоваться, когда сервис регистрации клиента вызывается неаутентифицированным запросом. Это означает, что запрос не содержит ни токена первичного доступа ни Bearer токена. +auth-policies=Политики аутентифицированного доступа +auth-policies.tooltip=Эти политики будут использоваться, когда сервис регистрации клиента вызывается аутентифицированным запросом. Это означает, что запрос содержит токен первичного доступа или Bearer токен. +policy-name=Наименование политики +no-client-reg-policies-configured=Нет политик регистрации клиента +trusted-hosts.label=Доверенные хосты +trusted-hosts.tooltip=Список хостов, которым доверенно и разрешено адресоваться на сервис регистрации клиентов или/или использоваться в значения URI клиентов. Вы можете использовать имена хостов или IP адреса. Если Вы используете звезду If you use star at the beginning (for example '*.example.com' ) then whole domain example.com will be trusted. +host-sending-registration-request-must-match.label=Хост, посылающий запрос на регистрацию клиента должен совпадать +host-sending-registration-request-must-match.tooltip=Если включено, то любой запрос на сервис регистрации клиентов разрешен только если он передан из доверенного хоста или домена. +client-uris-must-match.label=URI клиента должны совпадать +client-uris-must-match.tooltip=Если включено, то все клиентские URI (URI переадресации и прочие) разрешены только если они совпадают с доверенным хостом или доменом. +allowed-protocol-mappers.label=Разрешенные сопоставления протокола +allowed-protocol-mappers.tooltip=Белый список разрешенных поставщиков сопоставления протокола. Если есть попытка регистрации клиента, который содержит какие-либо сопоставления протокола, которые не находятся в белом списке, то регистрация таких клиентов будет отклонена. +consent-required-for-all-mappers.label=Требуется согласие для сопоставлений +consent-required-for-all-mappers.tooltip=Если включено, то то все вновь зарегестрированные сопоставления протокола будут автоматически иметь включенный consentRequired. Это означает, что пользователь должен подтвердить на экране согласия. Примечание: Экран согласия отображается только если клиент имеет включенный consentRequired. Таким образом, как правило этот переключатель используется совместно с политикой согласий. +allowed-client-templates.label=Разрешить шаблоны клиента +allowed-client-templates.tooltip=Белый список шаблонов клиента, который может быть использован при регистрации нового клиента. Попытка зарегестрировать клиента с каким-либо шаблоном не из белого списка будет отклонена. По умолчанию, белый лист пустой, таким образом шаблоны клиентам не доступны. +max-clients.label=Максимальное количество клиентов для Realm +max-clients.tooltip=Не позволяет регистрировать клиентов больше установленного предельного значения. + +client-scopes=Шаблоны клиентов +client-scopes.tooltip=Шаблоны клиентов позволяют вам определить основную конфигурацию, которая может быть общей между несколькими клиентами + +groups=Группы + +group.add-selected.tooltip=Роли Realm, которые могут быть назначены на эту группу. +group.assigned-roles.tooltip=Роли Realm, сопоставленные на группу +group.effective-roles.tooltip=Все сопоставления realm ролей. Некоторые роли здесь могут быть унаследованы из составной роли. +group.available-roles.tooltip=Назначаемые роли этого клиента. +group.assigned-roles-client.tooltip=Сопоставление ролей этого клиента. +group.effective-roles-client.tooltip=Сопоставление ролей этого клиента. Некоторые роли здесь могут быть унаследованы из сопоставленных составных ролей. + +default-roles=Роли по умолчанию +no-realm-roles-available=Роли realm не доступны + +users=Пользователи +user.add-selected.tooltip=Роли Realm, которые могут быть назначены пользователю. +user.assigned-roles.tooltip=Роли Realm, сопоставленные пользователю +user.effective-roles.tooltip=Все соответствия ролей realm. Некоторые роли здесь могут быть унаследованы из соответствующих составных ролей. +user.available-roles.tooltip=Доступные роли для этого клиента. +user.assigned-roles-client.tooltip=Соответствие ролей для этого клиента. +user.effective-roles-client.tooltip=Соответствие ролей для этого клиента. Некоторые роли здесь могут быть унаследованы из соответствующих составных ролей. +default.available-roles.tooltip=Роли уровня Realm, которые могут быть назначены. +realm-default-roles=Роли Realm по умолчанию +realm-default-roles.tooltip=Роли уровня Realm, которые могут быть назначены новым пользователям. +default.available-roles-client.tooltip=Роли из этого клиента, которые могут быть назначены по умолчанию. +client-default-roles=Роли клиента по умолчанию +client-default-roles.tooltip=Роли из этого клиента, назначенные как роли по умолчанию. +composite.available-roles.tooltip=Роли уровня Realm связанные с этой составной ролью. +composite.associated-roles.tooltip=Роли уровня Realm, связанные с этой составной ролью. +composite.available-roles-client.tooltip=Роли из этого клиента, которые могут быть назначены с этой составной ролью. +composite.associated-roles-client.tooltip=Роли клиента, связанные с этой составной ролью. +partial-import=Частичный импорт +partial-import.tooltip=Частичный импорт позволяет импортировать пользователей, клиентов, и другие ресурсы из ранее экспортированного json-файла. + +file=File +exported-json-file=Экспортированный json файл +import-from-realm=Импортировать из realm +import-users=Импортировать пользователей +import-groups=Импортировать группы +import-clients=Импортировать клиентов +import-identity-providers=Импортировать поставщиков идентификации +import-realm-roles=Импортировать роли realm +import-client-roles=Импортировать роли клиентов +if-resource-exists=Если ресурс существует +fail=Неудача +skip=Пропустить +overwrite=Перезаписать +if-resource-exists.tooltip=Указать, что следует делать, если вы пытаетесь импортировать ресурс, который уже существует. + +action=Действие +role-selector=Селектор ролей +realm-roles.tooltip=Роли Realm, которые могут быть выбраны. + +select-a-role=Выберите роль +select-realm-role=Выберите роль realm +client-roles.tooltip=Роли клиента, которые могут быть выбраны. +select-client-role=Выберите роль клиента + +client-template=Шаблон клиента +client-template.tooltip=Шаблон клиента, определяющий наследование конфигурации этого клиента из +client-saml-endpoint=Конечная точка доступа SAML клиента +add-client-scope=Добавить шаблон клиента + +manage=Управление +authentication=Аутентификация +user-federation=Федерация пользователей +user-storage=Хранилище пользователей +events=События +realm-settings=Настройки Realm +configure=Конфигурация +select-realm=Выберите realm +add=Добавить + +client-scope.name.tooltip=Наименование шаблона клиента. Должно быть уникально для realm +client-scope.description.tooltip=Описание шаблона клиента +client-scope.protocol.tooltip=Какая конфигурация протокола SSO будет поддержана шаблоном клиента + +add-user-federation-provider=Добавить службу федерации пользователей +add-user-storage-provider=Добавить службу хранилища пользователей +required-settings=Требуемые настройки +provider-id=ID службы +console-display-name=Наименование в консоли +console-display-name.tooltip=Отображаемое имя службы, связанное с консолью администратора. +priority=Приоритет +priority.tooltip=Приоритет службы при поиске пользователя. Вперед идут более низкие значения. +sync-settings=Синхронизировать настройки +periodic-full-sync=Периодическая полная синхронизация +periodic-full-sync.tooltip=Должна ли периодическая полная синхронизация с поставщиком идентификации в Keycloak включена или нет +full-sync-period=Период полной синхронизации +full-sync-period.tooltip=Период для полной синхронизации в секундах +periodic-changed-users-sync=Периодическая синхронизация изменений пользователей +periodic-changed-users-sync.tooltip=Должна ли происходить периодическая синхронизация новых и измененных пользователей поставщика идентификации с Keycloak +changed-users-sync-period=Период синхронизации измененных пользователей +changed-users-sync-period.tooltip=Период для синхронизации измененных и новых пользователей в поставщике идентификации в секундах +synchronize-changed-users=Синхронизация измененных пользователей +synchronize-all-users=Синхронизация всех пользователей +remove-imported-users=Удалить импортированных +unlink-users=Отвязать пользователей +kerberos-realm=Kerberos Realm +kerberos-realm.tooltip=Наименование kerberos realm. Например FOO.ORG +server-principal=Основной сервер +server-principal.tooltip=Полное имя основного сервера для HTTP сервиса, включая серверное и доменное имя. Например HTTP/host.foo.org@FOO.ORG +keytab=KeyTab +keytab.tooltip=Местоположение файла KeyTab в Kerberos, содержащего учетные данные основного сервера. Например /etc/krb5.keytab +debug=Отладчик +debug.tooltip=Включить/выключить отладочные логи в стандартный вывод для Krb5LoginModule. +allow-password-authentication=Разрешить аутентификацию по паролю +allow-password-authentication.tooltip=Включить/выключить возможность аутентификации по имени/пароля вопреки базе данных Kerberos +edit-mode=Режим редактирования +edit-mode.tooltip=READ_ONLY означает, что обновление пароля не допускается и пользователь всегда аутентифицируется с паролем Kerberos. UNSYNCED означает, что пользователь может изменить свой пароль в базе данных Keycloak и тогда он будет использован вместо пароля Kerberos +ldap.edit-mode.tooltip=READ_ONLY означает доступ только на чтение из LDAP. WRITABLE означает, что данные будут обратно синхронизированы в LDAP по заявке. UNSYNCED означает, что данные пользователя будут импортированы, но не синхронизированы обратно в LDAP. +update-profile-first-login=Обновить профиль при первом входе +update-profile-first-login.tooltip=Обновить профиль при первом входе +sync-registrations=Синхронизировать регистрации +ldap.sync-registrations.tooltip=Должны ли вновь созданные пользователи быть созданы в хранилище LDAP? Приоритет определяет какой из поставщиков будет выбран для синхронизации нового пользователя. +import-enabled=Импортировать пользователей +ldap.import-enabled.tooltip=Если включено, пользователи LDAP будут импортированы в базу данных Keycloak и синхронизированы через сконфигурированные политики синхронизации. +vendor=Поставщик +ldap.vendor.tooltip=LDAP поставщик (провайдер) +username-ldap-attribute=Атрибут Username в LDAP +ldap-attribute-name-for-username=Наименование атрибута LDAP для имени пользователя +username-ldap-attribute.tooltip=Наименование LDAP атрибута, которое отображается как имя пользователя в Keycloak. Для множества серверов LDAP это может быть 'uid'. Для Active directory это может быть 'sAMAccountName' или 'cn'. Атрибут должен быть заполнен для всех LDAP записей пользователей, которые вы хотите импортировать из LDAP в Keycloak. +rdn-ldap-attribute=Атрибут RDN в LDAP +ldap-attribute-name-for-user-rdn=Наименование атрибута LDAP для пользователей RDN +rdn-ldap-attribute.tooltip=Наименование атрибутов LDAP, которое используется как RDN (верхний атрибут) обычного пользователя DN. Обычно оно такое же, как атрибут имени пользователя LDAP, однако он не обязателен. Для примера, для Active directory обычно используется 'cn' как атрибут RDN, в то время как атрибут имени пользователя может быть 'sAMAccountName'. +uuid-ldap-attribute=Атрибут UUID в LDAP +ldap-attribute-name-for-uuid=Наименование LDAP атрибута для UUID +uuid-ldap-attribute.tooltip=Наименование LDAP атрибута,которое используется как уникальный идентификатор объектов (UUID) в LDAP. Для множества LDAP серверов это 'entryUUID' однако некоторые могут отличаться. Для примера, для Active directory он должен быть 'objectGUID'. Если ваш LDAP сервер действительно не поддерживает понятие UUID, вы можете использовать любой другой атрибут, который должен быть уникальным среди пользователей в дереве LDAP. Например 'uid' или 'entryDN'. +user-object-classes=Классы объектов пользователя +ldap-user-object-classes.placeholder=Классы объектов пользователя LDAP (разделенные запятой) + +ldap-connection-url=URL соединения с LDAP +ldap-users-dn=Пользователи DN LDAP +ldap-bind-dn=Сопоставление DN LDAP +ldap-bind-credentials=Сопоставление учетных данных LDAP +ldap-filter=LDAP фильтр +ldap.user-object-classes.tooltip=Все значения из LDAP objectClass атрибутов для пользователей в LDAP, разделенные запятой. Например: 'inetOrgPerson, organizationalPerson' . Вновь созданные пользователи Keycloak будут записаны в LDAP вместе с этими классами объектов, а существующие записи пользователей LDAP будут найдены только если они содержат все эти классы объектов. + +connection-url=URL соединения +ldap.connection-url.tooltip=URL соединения с вашим сервером LDAP +test-connection=Тест соединения +users-dn=Пользователи DN +ldap.users-dn.tooltip=Полный DN из дерева LDAP где присутствуют ваши пользователи. Этот DN является родителем пользователей LDAP. Он может быть, для примера 'ou=users,dc=example,dc=com' при условии, что ваш обычный пользователь будет иметь DN похожий на'uid=john,ou=users,dc=example,dc=com' +authentication-type=Тип аутентификации +ldap.authentication-type.tooltip=Тип LDAP аутентификации. Сейчас доступны только механизмы 'none' (анонимная аутентификация LDAP) или 'simple' (Аутентификация по сопоставленным логину и паролю) +bind-dn=Сопоставление DN +ldap.bind-dn.tooltip=DN администратора LDAP, которые будут использованы Keycloak для доступа на сервер LDAP +bind-credential=Сопоставление учетных данных +ldap.bind-credential.tooltip=Пароль администратора LDAP +test-authentication=Проверка аутентификации +custom-user-ldap-filter=Пользовательский Фильтр LDAP пользователей +ldap.custom-user-ldap-filter.tooltip=Дополнительный фильтр LDAP для фильтрации искомых пользователей. Оставьте поле пустым, если не нуждаетесь в дополнительном фильтре. Убедитесь, что он начинается с '(' и заканчивается ')' +search-scope=Поиск области +ldap.search-scope.tooltip=Для одного уровня мы ищем пользователей только в DN, определенных как пользовательские DN. Для поддеревьев мы ищем полностью в их поддеревьях. Смотрите документацию LDAP для подробных деталей +use-truststore-spi=Использование доверенных сертификатов SPI +ldap.use-truststore-spi.tooltip=Определяет, будет ли соединение с LDAP использовать хранилище доверенных сертификатов SPI вместе с сертификатами, сконфигурированными в keycloak-server.json. 'Всегда' означает, что они будут использоваться всегда. 'Никогда' означает, что они никогда не будут использованы. 'Только для ldap`ов' означает, что они будут использованы вместе с вашими соединениями к ldap серверам. Обратите внимание, что если keycloak-server.json не сконфигурирован, то по умолчанию Java будет использовать cacerts или сертификат, определенный в 'javax.net.ssl.trustStore'. +connection-pooling=Пул соединений +ldap-connection-timeout=Таймаут соединения +ldap.connection-timeout.tooltip=Таймаут соединения с LDAP в миллисекундах +ldap-read-timeout=Таймаут чтения +ldap.read-timeout.tooltip=Таймаут чтения из LDAP в миллисекундах. Этот таймаут применяется к операциям чтения из LDAP +ldap.connection-pooling.tooltip=Должен ли Keycloak использовать пул соединений для доступа к LDAP серверу +ldap.pagination.tooltip=Должен ли LDAP сервер поддерживать постраничный вывод. +kerberos-integration=Интеграция с Kerberos +allow-kerberos-authentication=Разрешить аутентификацию Kerberos +ldap.allow-kerberos-authentication.tooltip=Включить/выключить аутентификацию HTTP пользователей с токенами SPNEGO/Kerberos. Данные об аутентифицированых пользователях будут предусмотрены из этого LDAP сервера +use-kerberos-for-password-authentication=Использовать Kerberos для аутентификации по паролю +ldap.use-kerberos-for-password-authentication.tooltip=Использовать модуль входа Kerberos для аутентификации по логин/пароль с сервера Kerberos вместо аутентификации на сервере LDAP с Directory Service API +batch-size=Размер пачки +ldap.batch-size.tooltip=Количество пользователей LDAP, которые будут импортированы в Keycloak за одну транзакцию. +ldap.periodic-full-sync.tooltip=Должна ли быть включена полная периодическая синхронизация пользователей LDAP в Keycloak или нет +ldap.periodic-changed-users-sync.tooltip=Должна ли быть включена периодическая синхронизация новых и измененных пользователей LDAP в Keycloak или нет +ldap.changed-users-sync-period.tooltip=Период для синхронизации измененных или вновь созданных пользователей LDAP в секундах +user-federation-mappers=Сопоставления федераций пользователей +create-user-federation-mapper=Создать отображение федерации пользователей +add-user-federation-mapper=Добавить отображение федерации пользователей +provider-name=Наименование поставщика +no-user-federation-providers-configured=Не сконфигурирован федеративный поставщик идентификации +no-user-storage-providers-configured=Не сконфигурирован поставщик хранилища учетных записей +add-identity-provider=Добавить поставщика идентификации +add-identity-provider-link=Добавить ссылку на поставщика идентификации +identity-provider=Поставщик идентификации +identity-provider-user-id=ID пользователя поставщика идентификации +identity-provider-user-id.tooltip=Уникальный ID пользователя на стороне поставщика идентификации +identity-provider-username=Имя пользователя поставщика идентификации +identity-provider-username.tooltip=Имя пользователя на стороне поставщика идентификации +pagination=Постраничный вывод + +browser-flow=Сценарий браузера +browser-flow.tooltip=Выберите сценарий, который вы хотите использовать для аутентификации через браузер. +registration-flow=Сценарий регистрации +registration-flow.tooltip=Выберите сценарий, который вы хотите использовать для регистрации пользователя. +direct-grant-flow=Сценарий Direct Grant Flow +direct-grant-flow.tooltip=Выберите сценарий, который вы хотите использоваться для аутентификации direct grant. +reset-credentials=Сбросить учетные данные +reset-credentials.tooltip=Выберите сценарий, который вы хотите использовать когда пользователь забыл свои учетные данные. +client-authentication=Аутентификация клиента +client-authentication.tooltip=Выберите сценарий, который вы хотите использовать для аутентификации клиентов. +new=Создать +copy=Копировать +add-execution=Добавить исполнение +add-flow=Добавить сценарий +auth-type=Тип аутентификации +requirement=Требования +config=Конфигурация +no-executions-available=Нет доступных выполнений +authentication-flows=Сценарии аутентификации +create-authenticator-config=Создать конфигурацию аутентификатора +authenticator.alias.tooltip=Наименование конфигурации +otp-type=Тип одноразового пароля OTP +time-based=Основан на времени +counter-based=Основан на счетчике +otp-type.tooltip=totp является Временным одноразовым паролем. 'hotp' основанный на счетчике одноразовый пароль в котором сервер хранит счетчик хеша. +otp-hash-algorithm=Алгоритм хеша OTP +otp-hash-algorithm.tooltip=Какой алгоритм хеширования должен быть использован для генерации OTP. +number-of-digits=Количество цифр +otp.number-of-digits.tooltip=Сколько цифр должен иметь OTP? +look-ahead-window=Окно вперед +otp.look-ahead-window.tooltip=Как далеко вперед сервер должен выглядеть в случае если сгенерированный токен и сервер не синхронизированы с временем или счетчиком +initial-counter=Начальное значение счетчика +otp.initial-counter.tooltip=Каким должно быть начальное значение счетчика? +otp-token-period=Период токена OTP +otp-token-period.tooltip=Сколько секунд токен OTP должен быть действителен? По умолчанию 30 секунд. +table-of-password-policies=Таблица политик пароля +add-policy.placeholder=Добавить политику... +policy-type=Тип политики +policy-value=Значение политики +admin-events=События администратора +admin-events.tooltip=Отображает сохраненные события администратора в этом realm. События, связанные с учетной записью администратора, например создание realm. Чтобы включить сохранение событий, перейдите в конфигурацию. +login-events=События входа +filter=Фильтр +update=Обновить +reset=Сбросить +operation-types=Типы операций +resource-types=Типы ресурсов +select-operations.placeholder=Выберите операции... +select-resource-types.placeholder=Выберите типы ресурсов... +resource-path=Путь к ресурсу +resource-path.tooltip=Фильтр по пути к ресурсу. Поддерживает подстановку '*' для совпадения одной части пути и '**' совпадение нескольких частей. Например 'realms/*/clients/asbc' выберет клиента с идентификатором asbc в любом realm, в то время как 'realms/master/**' не найдет ничего в master realm. +date-(from)=Дата (С) +date-(to)=Дата (По) +authentication-details=Детали аутентификации +ip-address=IP адрес +time=Время +operation-type=Тип операции +resource-type=Тип ресурса +auth=Аутентификация +representation=Представление +register=Регистрация +required-action=Требуемое действие +default-action=Действие по умолчанию +auth.default-action.tooltip=Если включено, то любому новому пользователю будет будет назначено требуемое действие. +no-required-actions-configured=Требуемые действия не сконфигурированы +defaults-to-id=По умолчанию id +flows=Сценарии +bindings=Сопоставления +required-actions=Требуемые действия +password-policy=Политики пароля +otp-policy=Политики OTP +user-groups=Группы пользователей +default-groups=Группы по умолчанию +groups.default-groups.tooltip=Устанавливает группы, в которые новые пользователи будут включены автоматически. +cut=Вырезать +paste=Вставить + +create-group=Создать группу +create-authenticator-execution=Создать исполнение аутентификатора +create-form-action-execution=Создать форму действия исполнения +create-top-level-form=Создать верхнеуровневую форму +flow.alias.tooltip=Задает отображаемое имя для сценария. +top-level-flow-type=Top Level Flow Type +flow.generic=общий +flow.client=клиент +top-level-flow-type.tooltip=Какой это тип сценария верхнего уровня? Тип "клиент" используется для аутентификации клиентов (приложений), когда "общий" для пользователей и всего остального +create-execution-flow=Создать сценарий исполнения +flow-type=Тип сценария +flow.form.type=форма +flow.generic.type=общий +flow-type.tooltip=Какого типа эта форма +form-provider=Поставщик формы +default-groups.tooltip=Вновь созданные или зарегистрированные пользователи будут автоматически добавлены к этим группам +select-a-type.placeholder=выберите тип +available-groups=Доступные группы +available-groups.tooltip=Выберите группу, которые вы хотите добавить по умолчанию. +value=Значение +table-of-group-members=Таблица членов группы +last-name=Фамилия +first-name=Имя +email=E-mail +toggle-navigation=Переключить навигацию +manage-account=Управление учетной записью +sign-out=Выход +server-info=Информация о сервере +resource-not-found=Ресурс не найден... +resource-not-found.instruction=Мы не смогли найти ресурс, который вы ищете. Пожалуйста, убедитесь, что вы ввели корректный URL. +go-to-the-home-page=Перейти на домашнюю страницу » +page-not-found=Страница не найдена... +page-not-found.instruction=Мы не смогли найти страницу, которую вы ищете. Пожалуйста, убедитесь, что URL-адрес введен правильно. +events.tooltip=Отображает сохраненные события для realm. События, связанные с учетными записями пользователей, например, вход пользователя. Для того, чтобы включить сохранение событий, перейдите в конфигурацию. +select-event-types.placeholder=Выберите тип событий... +events-config.tooltip=Отображает опции конфигурации для включения сохранения событий пользователей и администратора. +select-an-action.placeholder=Выберите действие... +event-listeners.tooltip=Настройка слушателей, получающих события для realm. +login.save-events.tooltip=Если включено, то события будут сохранены в базу данных, что сделает их доступными администратору и консоли управления учетной записью. +clear-events.tooltip=Удаляет все события из базы данных. +events.expiration.tooltip=Установить срок истечения для событий. Истекшие события периодически удаляются из базы данных. +admin-events-settings=Настройки событий администратора +save-events=Сохранять события +admin.save-events.tooltip=Если включено, то события администратора будет сохранены в базу данных, что сделает их доступными через консоль администратора. +saved-types.tooltip=Сконфигурировать, какие типы событий следует сохранять. +include-representation=Включить представление +include-representation.tooltip=Включить JSON представление для запросов на создание и обновление. +clear-admin-events.tooltip=Удалить все события администратора из базы данных. +server-version=Версия сервера +server-profile=Профиль сервера +server-disabled=Отключенные функции сервера +info=Информация +providers=Поставщики +server-time=Время на сервере +server-uptime=Аптайм сервера +memory=Память +total-memory=Всего памяти +free-memory=Свободно памяти +used-memory=Использовано памяти +system=Система +current-working-directory=Текущая рабочая директория +java-version=Версия Java +java-vendor=Поставщик Java +java-runtime=Java Runtime +java-vm=Java VM +java-vm-version=Версия Java VM +java-home=Java Home +user-name=Имя пользователя +user-timezone=Таймзона пользователя +user-locale=Язык пользователя +system-encoding=Системная кодировка +operating-system=Операционная система +os-architecture=Архитектура OS +spi=SPI +granted-roles=Предоставленные роли +granted-protocol-mappers=Сопоставления протокола предоставления +additional-grants=Дополнительные полномочия +consent-created-date=Создано +consent-last-updated-date=Обновлено +revoke=Отобрать +new-password=Новый пароль +password-confirmation=Подтверждение пароля +reset-password=Сброс пароля +credentials.temporary.tooltip=Если включено, пользователю необходимо сменить пароль при следующем входе +remove-totp=Удалить OTP +credentials.remove-totp.tooltip=Удалить генератор одноразовых паролей из пользователя. +reset-actions=Действия сброса +credentials.reset-actions.tooltip=Набор действия для выполнения при отправке пользователю письма с указаниями по сбросу пароля. 'Подтвердить E-mail' высылает пользователю письмо для подтверждения его E-mail. 'Обновить профиль' требует от пользователя ввести новую персональную информацию. 'Обновить пароль' требует от пользователя ввести новый пароль. 'Настроить OTP' требует установить мобильное приложение с генератором паролей. +reset-actions-email=E-mail с действиями для сброса пароля +send-email=Послать письмо +credentials.reset-actions-email.tooltip=Посылает письмо пользователю со встроенной ссылкой. Кликнув на ссылку, пользователю будет разрешено выполнить действия для сброса. Они не должны для этого входить в систему. Например, установка действия обновления пароля, щелкните по этой кнопке, и пользователь получит возможность сменить свой пароль без входа в систему. +add-user=Добавить пользователя +created-at=Создан +user-enabled=Пользователь включен +user-enabled.tooltip=Отключенные пользователи не смогут войти. +user-temporarily-locked=Пользователь временно заблокирован +user-temporarily-locked.tooltip=Пользователь может быть заблокирован в случае многократных неудачных попыток входа. +unlock-user=Разблокировать пользователя +federation-link=Ссылка федерации +email-verified=Подтверждение E-mail +email-verified.tooltip=Должен ли пользователь подтверждать свой E-mail? +required-user-actions=Требуемые действия от пользователя +required-user-actions.tooltip=Требует действий от пользователя когда он входит. 'Подтвердить E-mail' высылает письмо пользователю для подтверждения его E-mail. 'Обновить профиль' требует от пользователя ввести новую персональную информацию. 'Обновить пароль' требует от пользователя ввести новый пароль. 'Настроить OTP' требует установить мобильное приложение генерации паролей. +locale=Язык +select-one.placeholder=Выберите... +impersonate=Имперсонировать +impersonate-user=Имперсонировать +impersonate-user.tooltip=Войти как этот пользователь. Если пользователь в том же самом realm что и вы, то ваша текущая сессия будет разлогинена перед тем как вы войдете как этот пользователь. +identity-provider-alias=Синоним поставщика идентификации +provider-user-id=ID пользователя у поставщика +provider-username=Username у поставщика +no-identity-provider-links-available=Ссылки поставщика идентификации не доступны +group-membership=Членство в группах +leave=Покинуть +group-membership.tooltip=Пользователь является членом группы. Выберите в списке группу и нажмите кнопку Покинуть, чтобы покинуть группу. +membership.available-groups.tooltip=Группы, к которым пользователь может присоединиться. Выберите группу и нажмите кнопку присоединиться. +table-of-realm-users=Таблица пользователей Realm +view-all-users=Показать всех пользователей +unlock-users=Разблокировать пользователей +no-users-available=Пользователи не доступны +users.instruction=Пожалуйста, заполните строку поиска, или нажмите посмотреть всех пользователей +consents=Согласия +started=Начато +logout-all-sessions=Выйти из всех сессий +logout=Выход +new-name=Новое имя +ok=Ок +attributes=Атрибуты +role-mappings=Сопоставление ролей +members=Члены +details=Детали +identity-provider-links=Ссылки поставщика идентификации +register-required-action=Зарегистрировать требуемое действие +gender=Пол +address=Адрес +phone=Телефон +profile-url=URL профиля +picture-url=URL изображения +website=Вебсайт +import-keys-and-cert=Импорт ключей и сертификатов +import-keys-and-cert.tooltip=Загрузить пару ключей и сертификат клиента. +upload-keys=Загрузить ключи +download-keys-and-cert=Скачать ключи и сертификат +no-value-assigned.placeholder=Значение не назначено +remove=Удалить +no-group-members=В группе нет членов +temporary=Временный +join=Присоединиться +event-type=Тип события +events-config=Конфигурация событий +event-listeners=Слушатели событий +login-events-settings=Настройки событий по входу +clear-events=Очистить события +saved-types=Сохраняемые типы событий +clear-admin-events=Очистить события администратора +clear-changes=Очистить изменения +error=Ошибка + +# Authz +# Authz Common +authz-authorization=Авторизация +authz-owner=Владелец +authz-uri=URI +authz-scopes=Области +authz-resource=Ресурс +authz-resource-type=Тип ресурса +authz-resources=Ресурсы +authz-scope=Область +authz-authz-scopes=Области авторизации +authz-policies=Политики +authz-permissions=Разрешения +authz-evaluate=Оценка +authz-icon-uri=Иконка URI +authz-icon-uri.tooltip=URI, указывающий на иконку. +authz-select-scope=Выберите область +authz-select-resource=Выберите ресурс +authz-associated-policies=Назначенные политики +authz-any-resource=Любой ресурс +authz-any-scope=Любая область +authz-any-role=Любая роль +authz-policy-evaluation=Оценки политики +authz-select-client=Выберите клиента +authz-select-user=Выберите пользователя +authz-entitlements=Права +authz-no-resources=Нет ресурсов +authz-result=Результат +authz-authorization-services-enabled=Авторизация включена +authz-authorization-services-enabled.tooltip=Включить/Выключить тонко-настраиваемую поддержку авторизации для клиента +authz-required=Требуется +authz-show-details=Показать детали +authz-hide-details=Скрыть детали +authz-associated-permissions=Назначенные разрешения +authz-no-permission-associated=Разрешения не назначены + +# Authz Settings +authz-import-config.tooltip=Импорт JSON файла, содержащего авторизационные настройки для этого сервера ресурсов. + +authz-policy-enforcement-mode=Режим применения политик +authz-policy-enforcement-mode.tooltip=Режим применения политик диктует, каким образом политики применяются при оценке запросов на авторизацию. «Обязывающая» означает, что запросы запрещены по умолчанию, даже если нет никакой политики, связанной с данным ресурсом. "Разрешающая" означает, что запросы разрешены даже если не существует политика, связанная с данным ресурсом. 'Отключено' полностью отключает оценку политики и позволяет получить доступ к любому ресурсу. +authz-policy-enforcement-mode-enforcing=Обязывающая +authz-policy-enforcement-mode-permissive=Разрешающая +authz-policy-enforcement-mode-disabled=Отключено + +authz-remote-resource-management=Удаленное управление ресурсами +authz-remote-resource-management.tooltip=Должны ли ресурсы управляться удаленно сервером ресурсов? Если нет, то ресурсы могут управляться только через консоль администратора. + +authz-export-settings=Экспортировать настройки +authz-export-settings.tooltip=Экспортировать и скачать все авторизационные настройки для этого сервера ресурсов. + +# Authz Resource List +authz-no-resources-available=Нет доступных ресурсов. +authz-no-scopes-assigned=Нет назначенных областей. +authz-no-type-defined=Нет заданных типов. +authz-no-uri-defined=Нет заданных URI. +authz-no-permission-assigned=Полномочия не назначены. +authz-no-policy-assigned=Политики не заданы. +authz-create-permission=Создать полномочия + +# Authz Resource Detail +authz-add-resource=Добавить ресурс +authz-resource-name.tooltip=Уникальное имя для этого ресурса. Имя может быть использовано для уникальной идентификации ресурса, используется при запросах конкретных ресурсов. +authz-resource-owner.tooltip=Владелец этого ресурса. +authz-resource-type.tooltip=Тип этого ресурса. Может быть использовано для группировки различных экземпляров ресурса с тем же типом. +authz-resource-uri.tooltip=URI, который также может быть использован для уникальной идентификации этого ресурса. +authz-resource-scopes.tooltip=Области, ассоциироваанные с этим ресурсом. + +# Authz Scope List +authz-add-scope=Добавить область +authz-no-scopes-available=Нет доступных областей. + +# Authz Scope Detail +authz-scope-name.tooltip=Уникальное имя для области. Имя может быть использовано для уникальной идентификации области, используется при запросах конкретных областей. + +# Authz Policy List +authz-all-types=Все типы +authz-create-policy=Создать политику +authz-no-policies-available=Нет доступных политик. + +# Authz Policy Detail +authz-policy-name.tooltip=Название этой политики. +authz-policy-description.tooltip=Описание этой политики. +authz-policy-logic=Логика +authz-policy-logic-positive=Позитивная +authz-policy-logic-negative=Негитивная +authz-policy-logic.tooltip=Логика диктует, как политика должна применяться. Если 'Позитивная', результирующий эффект (разрешение или запрещение) полученный в ходе оценки этой политики будет использован для выполнения решения. Если 'Негативная', результирующий эффект будет отрицательным, другими словами, разрешение становится запрещением и наоборот. +authz-policy-apply-policy=Применить политику +authz-policy-apply-policy.tooltip=Определяем все политики, которые должны быть применены к областям, определенным этой политикой или разрешением. +authz-policy-decision-strategy=Стратегия решения +authz-policy-decision-strategy.tooltip=Стратегия решения диктует как политики связаны с заданными разрешениями и как формируется окончательное решение. 'Утвердительная' означает, что, по крайней мере, одна политика должна дать положительную оценку для того, чтобы окончательное решение также было положительным. 'Единогласная' означает что все политики должны дать положительную оценку для того, чтобы окончательная оценка также была положительной. 'Консенсусная' означает, что количество положительных решений должно превышать количество отрицательных решений. Если количество положительных и отрицательных решений совпадает, окончательное решение будет отрицательным. +authz-policy-decision-strategy-affirmative=Утвердительная +authz-policy-decision-strategy-unanimous=Единогласная +authz-policy-decision-strategy-consensus=Консенсусная +authz-select-a-policy=Выберите политику + +# Authz Role Policy Detail +authz-add-role-policy=Добавить роль политики +authz-no-roles-assigned=Нет назначенных ролей. +authz-policy-role-realm-roles.tooltip=Задайте роли *realm*, допущенные этой политикой. +authz-policy-role-clients.tooltip=Выберите клиента в порядке, необходимом для фильтра клиентских ролей, которые могут быть применены к этой политике. +authz-policy-role-client-roles.tooltip=Задайте роли клиента, допущенные этой политикой. + +# Authz User Policy Detail +authz-add-user-policy=Добавить политику пользователей +authz-no-users-assigned=Нет назначенных пользователей. +authz-policy-user-users.tooltip=Задайте, какие пользователи допущены этой политикой. + +# Authz Client Policy Detail +authz-add-client-policy=Добавить политику клиента +authz-no-clients-assigned=Нет назначенных клиентов. +authz-policy-client-clients.tooltip=Задайте, какие клиенты допущеный этой политикой. + +# Authz Time Policy Detail +authz-add-time-policy=Добавить политики времени +authz-policy-time-not-before.tooltip=Определете время, до наступления которого политика НЕ ДОЛЖНА быть разрешена. Разрешено только если текущее время/дата больше или равны заданному значению. +authz-policy-time-not-on-after=Не после +authz-policy-time-not-on-after.tooltip=Определяет время, после которого политика НЕ ДОЛЖНА быть разрешена. Разрешено только если текущее время/дата менеьше или равны заданному значению. +authz-policy-time-day-month=День месяца +authz-policy-time-day-month.tooltip=Определяет день месяца, в который политика ДОЛЖНА быть разрешена. Вы также можете определить диапазон, заполнив второе поле. В этом случае разрешение выдается только если текущий день месяца равен или находится между заданными значениями. +authz-policy-time-month=Месяц +authz-policy-time-month.tooltip=Определяет месяц, в который политика ДОЛЖНА быть разрешена. Вы также можете определить диапазон, заполнив второе поле. В этом случае разрешение выдается только если текущий месяц равен или находится между заданными значениями. +authz-policy-time-year=Год +authz-policy-time-year.tooltip=Определяет год, в который политика ДОЛЖНА быть разрешена. Вы также можете определить диапазон, заполнив второе поле. В этом случае разрешение выдается только если текущий год равен или находится между заданными значениями. +authz-policy-time-hour=Час +authz-policy-time-hour.tooltip=Определяет час, в который политика ДОЛЖНА быть разрешена. Вы также можете определить диапазон, заполнив второе поле. В этом случае разрешение выдается только если текущий час равен или находится между заданными значениями. +authz-policy-time-minute=Минута +authz-policy-time-minute.tooltip=Определяет минуту, в которую политика ДОЛЖНА быть разрешена. Вы также можете определить диапазон, заполнив второе поле. В этом случае разрешение выдается только если текущая минута равна или находится между заданными значениями. + +# Authz JS Policy Detail +authz-add-js-policy=Добавить политику JavaScript +authz-policy-js-code=Код +authz-policy-js-code.tooltip=Код JavaScript, предоставляющий условия для этой политики. + + +# Authz Aggregated Policy Detail +authz-aggregated=Совокупная +authz-add-aggregated-policy=Добавить совокупную политику + +# Authz Permission List +authz-no-permissions-available=Нет доступных разрешений. + +# Authz Permission Detail +authz-permission-name.tooltip=Имя этого разрешения. +authz-permission-description.tooltip=Описание этого разрешения. + +# Authz Resource Permission Detail +authz-add-resource-permission=Добавить разрешение ресурса +authz-permission-resource-apply-to-resource-type=Применить к типу ресурса +authz-permission-resource-apply-to-resource-type.tooltip=Определяет, будет ли это разрешение будет применено ко всем ресурсам с данным типом. В этом случае это разрешение будет вычисляться для всех экземпляров с заданным типом ресурса. +authz-permission-resource-resource.tooltip=Определяет, что это разрешение должно быть применено к конкретному экземпляру ресурсов. +authz-permission-resource-type.tooltip=Определяет, что это разрешение должно быть применено ко всем экземплярам ресурсов заданного типа. + +# Authz Scope Permission Detail +authz-add-scope-permission=Добавить разрешение области +authz-permission-scope-resource.tooltip=Ограничевает области, с которыми связан выбранный ресурс. Если не выбрано, все области будут доступны. +authz-permission-scope-scope.tooltip=Определяет, что разрешение должно быть применено к одной или нескольким областям. + +# Authz Evaluation +authz-evaluation-identity-information=Идентичность данных +authz-evaluation-identity-information.tooltip=Доступные области для конфигурации идентичных данных будут использованы при оценке политик. +authz-evaluation-client.tooltip=Выберите клиента, осуществляющего авторизационный запрос. Если не задан, авторизационные запросы будут основаны на том клиенте, в котором вы находитесь. +authz-evaluation-user.tooltip=Выберите пользователя, идентификационные данные которого будут использованы для запроса разрешений с сервера. +authz-evaluation-role.tooltip=Выберите роли, которые вы хотите связать с выбранным пользователем. +authz-evaluation-new=Новая оценка +authz-evaluation-re-evaluate=Переоценить +authz-evaluation-previous=Предыдущая оценка +authz-evaluation-contextual-info=Контекстная информация +authz-evaluation-contextual-info.tooltip=Достуные опции для конфигурации контекстной информации, которая будет использована при оценке политик. +authz-evaluation-contextual-attributes=Контекстные аттрибуты +authz-evaluation-contextual-attributes.tooltip=Любой аттрибут определяется запущенным окружением или контекстом исполнения. +authz-evaluation-permissions.tooltip=Доступные опции для конфигурации разрешений, к которым будет применяться политика. +authz-evaluation-evaluate=Оценка +authz-evaluation-any-resource-with-scopes=Любой ресурс с областью(ями) +authz-evaluation-no-result=Не удалось получить какой-либо результат для данного запроса авторизации. Проверьте, связаны ли назначенные ресурс(ы) или область(и) с какой-либо политикой. +authz-evaluation-no-policies-resource=Не найдено политик для этого ресурса. +authz-evaluation-result.tooltip=Общий результат для этого запроса разрешений. +authz-evaluation-scopes.tooltip=Список разрешенных областей. +authz-evaluation-policies.tooltip=Подробнее о том, какие политики были расчитаны и их разрешения. +authz-evaluation-authorization-data=Ответ +authz-evaluation-authorization-data.tooltip=Предоставляет токен, содержащий авторизационные данные как результат обработки авторизационного запроса. Это представление преимущественно отображает как Keycloak отвечает на запросы клиентов об авторизации. Проверьте требования 'авторизации' для тех разрешений, которые были выданы на основе текущего авторизационного запроса. +authz-show-authorization-data=Показать авторизационные данные + + +keys=Ключи +all=Все +status=Статус +keystore=Хранилище ключей +keystores=Хранилища ключей +add-keystore=Добавить хранилище ключей +add-keystore.placeholder=Добавить хранилище ключей... +view=Смотреть +active=Активные + +Sunday=Воскресенье +Monday=Понедельник +Tuesday=Вторник +Wednesday=Среда +Thursday=Четверг +Friday=Пятница +Saturday=Суббота + +user-storage-cache-policy=Настройки кэширования +userStorage.cachePolicy=Политики кэширования +userStorage.cachePolicy.option.DEFAULT=DEFAULT +userStorage.cachePolicy.option.EVICT_WEEKLY=EVICT_WEEKLY +userStorage.cachePolicy.option.EVICT_DAILY=EVICT_DAILY +userStorage.cachePolicy.option.MAX_LIFESPAN=MAX_LIFESPAN +userStorage.cachePolicy.option.NO_CACHE=NO_CACHE +userStorage.cachePolicy.tooltip=Политики кэширования для этого поставщика хранения. 'DEFAULT' представляет настройки по-умолчанию для глобального пользовательского кэша. 'EVICT_DAILY' время каждого дня, после которого пользовательский кэш инвалидируется. 'EVICT_WEEKLY' день и время недели после которого пользовательский кэш инвалидируется. 'MAX-LIFESPAN' время в миллисекундах, в течение которого будет существовать жизненный цикл записи в кэше. +userStorage.cachePolicy.evictionDay=День исключения +userStorage.cachePolicy.evictionDay.tooltip=День недели в который запись станет недействительной и будет исключена из кэша. +userStorage.cachePolicy.evictionHour=Час исключения +userStorage.cachePolicy.evictionHour.tooltip=Час дня, в который запись станет недействительной. +userStorage.cachePolicy.evictionMinute=Минута исключения +userStorage.cachePolicy.evictionMinute.tooltip=Минута дня, в которую запись станет недействительной. +userStorage.cachePolicy.maxLifespan=Максимальное время жизни +userStorage.cachePolicy.maxLifespan.tooltip=Максимальное время жизни записи пользовательсткого кэша в секундах. +user-origin-link=Источник хранилища +user-origin.tooltip=UserStorageProvider из которого был загружен пользователь +user-link.tooltip=UserStorageProvider из которого был импортирован локально сохраненный пользователь. + +disable=Отключено +disableable-credential-types=Отключаемые типы +credentials.disableable.tooltip=Список типов учетных данных, которые Вы можете отключить +disable-credential-types=Отключить типы учетных данных +credentials.disable.tooltip=Нажмите кнопку для отключения типов учетных данных +credential-types=Типы учетных данных +manage-user-password=Управление паролями +disable-credentials=Отключить учетные данные +credential-reset-actions=Сброс учетных данных +ldap-mappers=Сопоставления LDAP +create-ldap-mapper=Создать LDAP сопоставление diff --git a/keycloak-themes/base/admin/messages/admin-messages_zh_CN.properties b/keycloak-themes/base/admin/messages/admin-messages_zh_CN.properties new file mode 100644 index 0000000..744560b --- /dev/null +++ b/keycloak-themes/base/admin/messages/admin-messages_zh_CN.properties @@ -0,0 +1,1228 @@ +# encoding: utf-8 +consoleTitle=Keycloak管理界面 + +# Common messages +enabled=开启 +name=名称 +displayName=显示名称 +displayNameHtml=HTML 显示名称 +save=保存 +cancel=取消 +onText=开 +offText=关 +client=客户端 +clients=客户端 +clear=清除 +selectOne=选择一个... + +true=是 +false=否 + +endpoints=服务路径 + +# Realm settings +realm-detail.enabled.tooltip=只有当域启用时,用户和客户程序才能访问 +realm-detail.oidc-endpoints.tooltip=显示openID connect服务路径的配置 +registrationAllowed=用户注册 +registrationAllowed.tooltip=开启/关闭注册页面,注册页面的链接也会显示在登录页面 +registrationEmailAsUsername=Email当做用户名 +registrationEmailAsUsername.tooltip=当开启时注册表单的用户名域会被隐藏而且Email会作为新用户的用户名 +editUsernameAllowed=编辑用户名 +editUsernameAllowed.tooltip=如果开启,用户名域是可以编辑的。否则用户名域是只读的。 +resetPasswordAllowed=忘记密码 +resetPasswordAllowed.tooltip=当用户忘记他们的密码时,在登录界面显示一个连接给用户点击。 +rememberMe=记住我 +rememberMe.tooltip=显示一个选择框来让用户在重启浏览器时仍然处于登录状态,直到会话过期。 +verifyEmail=验证email +verifyEmail.tooltip=要求用户在首次登录时验证他们的邮箱。 +sslRequired=需要SSL +sslRequired.option.all=所有请求 +sslRequired.option.external=外部请求 +sslRequired.option.none=无 +sslRequired.tooltip=是否需要HTTPS?‘无’代表对于任何客户端IP地址都不需要HTTPS,‘外部请求’代表localhost和私有ip地址可以不通过https访问,‘所有请求’代表所有IP地址都需要通过https访问。 +publicKey=公有秘钥 +privateKey=私有秘钥 +gen-new-keys=生成新秘钥 +certificate=证书 +host=主机 +smtp-host=SMTP 主机 +port=端口号 +smtp-port=SMTP 端口号(默认25) +from=来自 +sender-email-addr=邮件发送者email地址 +enable-ssl=启用 SSL +enable-start-tls=启用 StartTLS +enable-auth=启用认证 +username=用户名 +login-username=登录用户名 +password=密码 +login-password=登录密码 +login-theme=登录主题 +login-theme.tooltip=为登录、授权、注册、忘记密码界面选择页面主题 +account-theme=账户主题 +account-theme.tooltip=为用户管理界面选择主题 +admin-console-theme=管理员控制台主题 +select-theme-admin-console=为管理员控制台选择主题 +email-theme=邮件主题 +select-theme-email=为服务器发送的邮件选择主题 +i18n-enabled=启用国际化 +supported-locales=支持的语言 +supported-locales.placeholder=输入一个语言并按回车 +default-locale=默认语言 +localization-upload-file=上传JSON本地化数据文件 +missing-locale=缺少语言。 +missing-file=缺少文件,请选择一个文件上传。 +localization-file.upload.success=本地化数据已经从文件上传。 +localization-file.upload.error=文件无法上传,请检查文件或指定语言是否已经存在。 +localization-show=显示该域的本地化信息 +no-localizations-configured=该域没有已配置的本地化信息 +add-localization-text=添加本地化文本 +locale.create.success=语言已被创建。 +localization-text.create.success=本地化文本已被创建。 +localization-text.update.success=本地化文本已被更新。 +localization-text.remove.success=本地化文本已被删除。 +realm-cache-clear=域缓存 +realm-cache-clear.tooltip=从域缓存中清理所有条目(这会清理所有域的条目) +user-cache-clear=用户缓存 +user-cache-clear.tooltip=清理用户缓存的所有条目(这会清理所有域中的条目) +revoke-refresh-token=收回 Refresh Token +revoke-refresh-token.tooltip=如果开启 refresh tokens只能使用一次,否则refresh token不会被收回并且可以使用多次 +sso-session-idle=SSO会话空闲时间 +seconds=秒 +minutes=分 +hours=小时 +days=天 +sso-session-max=SSO会话最长时间 +sso-session-idle.tooltip=设置会话在过期之前可以空闲的时间长度,当会话过期时 Token 和浏览器会话都会被设置为无效。 +sso-session-max.tooltip=会话的最大时间长度,当会话过期时 Token 和浏览器会话都会被设置为无效。 +offline-session-idle=离线会话的空闲时间 +offline-session-idle.tooltip=离线会话允许的空闲时间。你需要使用离线Token在这段时间内至少刷新一次否则会话就会过期 +access-token-lifespan=Access Token 有效期 +access-token-lifespan.tooltip=access token最长有效时间,这个值推荐要比SSO超时要短一些。 +access-token-lifespan-for-implicit-flow =隐式流的访问令牌生命周期 +access-token-lifespan-for-implicit-flow.tooltip =在OpenID连接隐式流期间发出的访问令牌到期之前的最长时间。建议该值小于SSO超时。没有可能在隐式流期间刷新令牌,这就是为什么有单独的超时不同于“访问令牌寿命”。 +client-login-timeout =客户端登录超时 +client-login-timeout.tooltip =客户端必须完成访问令牌协议的最大时间。这通常是1分钟。 +login-timeout =登录超时 +login-timeout.tooltip =用户必须完成登录的最长时间。这建议比较长。 30分钟以上。 +login-action-timeout =登录操作超时 +login-action-timeout.tooltip =用户必须完成登录相关操作(如更新密码或配置totp)的最长时间。这建议比较长。 5分钟以上。 +headers =标题 +brute-force-detection=强力检测 +x-frame-options = X-Frame-Options +x-frame-options-tooltip =默认值阻止通过非源iframe包含页面(单击标签了解更多信息) +content-sec-policy = Content-Security-Policy +content-sec-policy-tooltip =默认值阻止通过非源iframe包含网页(点击标签了解更多信息) +content-type-options = X-Content-Type-Options +content-type-options-tooltip =默认值阻止Internet Explorer和Google Chrome从已声明的内容类型中嗅探响应(点击标签了解更多信息) +max-login-failures =最大登录失败 +max-login-failures.tooltip =触发等待之前的失败次数。 +wait-increment =等待增量 +wait-increment.tooltip =当满足故障阈值时,用户应该锁定多长时间? +quick-login-check-millis =快速登录检查Milli秒 +quick-login-check-millis.tooltip =如果故障同时发生太快,则锁定用户。 +min-quick-login-wait =最小快速登录等待 +min-quick-login-wait.tooltip =快速登录失败后等待多长时间。 +max-wait = Max Wait +max-wait.tooltip =用户将被锁定的最长时间。 +failure-reset-time =故障复位时间 +failure-reset-time.tooltip =何时将故障计数复位? +realm-tab-login=登录 +realm-tab-keys=秘钥 +realm-tab-email=Email +realm-tab-themes=主题 +realm-tab-localization=本地化 +realm-tab-cache=缓存 +realm-tab-tokens=令牌 +realm-tab-client-registration=客户端注册 +realm-tab-security-defenses=安全防护 +realm-tab-general=通用 +add-realm=添加域 + +#Session settings +realm-sessions=域会话 +revocation=回收 +logout-all=登出所有 +active-sessions=活跃的会话 +sessions=会话 +not-before=不早于 +not-before.tooltip=回收早于该日期授予的令牌 +set-to-now=设置到现在 +push=推送 +push.tooltip=对于每个拥有管理员权限的用户,通知他们新的回收策略 +#Protocol Mapper +usermodel.prop.label=属性 +usermodel.prop.tooltip=UserModel 接口中属性方法的名字. 例如, 'email' 会引用UserModel.getEmail() 方法. +usermodel.attr.label=用户属性 +usermodel.attr.tooltip=在UserModel.attribute映射中定义的存储的用户属性名。 +userSession.modelNote.label=用户会话标记 +userSession.modelNote.tooltip=用户会话标记在 UserSessionModel.note映射中的属性名。 +multivalued.label=多值的 +multivalued.tooltip=表示此值是否支持多值.如果为真,所有值会设置为已知。如果为假,只有第一个值是已知。 +selectRole.label=选择角色 +selectRole.tooltip=在左边文本框输入角色或点击这个按钮浏览并选择您想要的角色。 +tokenClaimName.label=Token申请名 +tokenClaimName.tooltip=token中加入的申请者名. 这可以是个完整的分级信息例如 'address.street'. 这种情况下,会生成一个复杂的json回复 +jsonType.label=申请 JSON 的类型 +jsonType.tooltip=用来展现申请的JSON 类型 long, int, boolean, 和 String 是有效值 +includeInIdToken.label =添加到ID令牌 +includeInIdToken.tooltip =是否应将声明添加到ID令牌? +includeInAccessToken.label =添加到访问令牌 +includeInAccessToken.tooltip =是否应该将声明添加到访问令牌? +includeInUserInfo.label =添加到userinfo +includeInUserInfo.tooltip =是否应该将声明添加到userinfo? +usermodel.clientRoleMapping.clientId.label =客户端ID +usermodel.clientRoleMapping.clientId.tooltip =角色映射的客户端ID +usermodel.clientRoleMapping.rolePrefix.label =客户端角色前缀 +usermodel.clientRoleMapping.rolePrefix.tooltip =每个客户端角色的前缀(可选)。 +usermodel.realmRoleMapping.rolePrefix.label = Realm角色前缀 +usermodel.realmRoleMapping.rolePrefix.tooltip =每个领域角色的前缀(可选)。 +sectorIdentifierUri.label =扇区标识符URI +sectorIdentifierUri.tooltip =使用成对子值和支持的提供程序动态客户端注册应使用sector_identifier_uri参数。它为一组在共同管理控制下的网站提供了一种独立于各个域名的具有一致的成对子值的方法。它还为客户端更改redirect_uri域而不必重新注册其所有用户提供了一种方法。 +pairwiseSubAlgorithmSalt.label = Salt +pairwiseSubAlgorithmSalt.tooltip =计算成对主体标识符时使用的盐。如果留空,将产生盐。 + + + +# client details +clients.tooltip=客户端是域中受信任的应用程序和web应用. 这些程序可以发起登录.您也可以定义应用的角色。 +search.placeholder=搜索... +create=创建 +import=导入 +client-id=客户端 ID +base-url=根 URL +actions=操作 +not-defined=未定义 +edit=编辑 +delete=删除 +no-results=无记录 +no-clients-available=无可用客户 +add-client=添加客户端 +select-file=选择文件 +view-details=查看详情 +clear-import=清除导入 +client-id.tooltip =指定在URI和令牌中引用的ID。例如“my-client”。对于SAML,这也是authn请求的预期发放者值 +client.name.tooltip =指定客户端的显示名称。例如“我的客户端”。支持本地化值的键。例如\\uff1a$ {my_client} +client.enabled.tooltip =禁用客户端无法启动登录或获取访问令牌。 +consent-required =同意必需 +consent-required.tooltip =如果已启用的用户必须同意客户端访问。 +client-protocol =客户端协议 +client-protocol.tooltip ='OpenID connect'允许客户端基于授权服务器执行的认证来验证最终用户的身份。'SAML'启用基于Web的身份验证和授权方案,包括跨域单点登录(SSO),并使用包含断言的安全令牌传递信息。 +access-type =访问类型 +access-type.tooltip ='机密'客户端需要一个秘密启动登录协议。 “公共”客户不需要一个秘密。 “仅承载”客户端是从不启动登录的Web服务。 +standard-flow-enabled =启用标准流程 +standard-flow-enabled.tooltip =这使标准的基于OpenID Connect重定向的身份验证与授权码。根据OpenID Connect或OAuth2规范,这将支持此客户端的“授权代码流”。 +implicit-flow-enabled =启用隐式流 +implicit-flow-enabled.tooltip =这启用对无授权代码的基于OpenID Connect重定向的身份验证的支持。根据OpenID Connect或OAuth2规范,这将支持此客户端的“隐式流”。 +direct-access-grants-enabled =启用直接访问授权 +direct-access-grants-enabled.tooltip =这启用对直接访问授权的支持,这意味着客户端可以访问用户的用户名/密码,并直接与Keycloak服务器交换访问令牌。在OAuth2规范方面,这允许支持此客户端的“资源所有者密码凭据授权”。 +service-accounts-enabled =启用服务帐户 +service-accounts-enabled.tooltip =允许您向Keycloak验证此客户端并检索专用于此客户端的访问令牌。在OAuth2规范方面,这将支持此客户端的“客户端凭据授予”。 +include-authnstatement = Include AuthnStatement +include-authnstatement.tooltip =是否应该在登录响应中包含指定方法和时间戳的语句? +sign-documents =签署文件 +sign-documents.tooltip = SAML文档是否应该由领域签名? +sign-documents-redirect-enable-key-info-ext =优化REDIRECT签名密钥查找 +sign-documents-redirect-enable-key-info-ext.tooltip =在由Keycloak适配器保护的SP的REDIRECT绑定中签名SAML文档时,如果签名密钥的ID包含在元素中的SAML协议消息中?这将优化签名的验证,因为验证方使用单个密钥,而不是尝试每个已知密钥进行验证。 +sign-assertions =符号断言 +sign-assertions.tooltip = SAML文档中的断言是否应该签名?如果文档已签署,则不需要此设置。 +signature-algorithm =签名算法 +signature-algorithm.tooltip =用于签署文档的签名算法。 +canonicalization-method =规范化方法 +canonicalization-method.tooltip = XML签名的规范化方法。 +encrypt-assertions =加密断言 +encrypt-assertions.tooltip =是否应使用AES通过客户端的公钥对SAML断言进行加密? +client-signature-required =需要客户端签名 +client-signature-required.tooltip =客户端是否签署了saml请求和响应?他们应该验证吗? +force-post-binding =强制POST绑定 +force-post-binding.tooltip =始终对POST响应使用POST绑定。 +front-channel-logout =前通道注销 +front-channel-logout.tooltip =当为true时,注销需要浏览器重定向到客户端。当为false时,服务器对注销执行后台调用。 +force-name-id-format =强制名称ID格式 +force-name-id-format.tooltip =忽略请求的NameID主题格式并使用管理控制台配置的。 +name-id-format =名称ID格式 +name-id-format.tooltip =要用于主题的名称ID格式。 +root-url =根URL +root-url.tooltip =附加到相对URL的根URL +valid-redirect-uris =有效的重定向URI +valid-redirect-uris.tooltip =浏览器可以在成功登录或注销后重定向到的有效URI模式。允许使用简单通配符,即“http://example.com/*”。也可以指定相对路径,即/ my / relative / path / *。相对路径是相对于客户端根URL的,如果没有指定,则使用auth服务器根URL。对于SAML,如果您依赖嵌入登录请求的使用者服务URL,则必须设置有效的URI模式。 +base-url.tooltip =当auth服务器需要重定向或链接回客户端时使用的默认URL。 +admin-url =管理员网址 +admin-url.tooltip =客户端管理界面的URL。如果客户端支持适配器REST API,请设置此选项。此REST API允许auth服务器推送吊销策略和其他管理任务。通常将此设置为客户端的基本URL。 +master-saml-processing-url =主SAML处理URL +master-saml-processing-url.tooltip =如果配置,此URL将用于每次绑定到SP的断言使用者和单一注销服务。这可以对细粒度SAML端点配置中的每个绑定和服务单独进行覆盖。 +idp-sso-url-ref = IDP发起的SSO URL名称 +idp-sso-url-ref.tooltip =当您想要进行IDP发起的SSO时,引用客户端的URL片段名称。留下此空将禁用IDP启动的SSO。您将从浏览器引用的URL为:{server-root} / realms / {realm} / protocol / saml / clients / {client-url-name} +idp-sso-relay-state = IDP发起的SSO中继状态 +idp-sso-relay-state.tooltip =当您想要执行IDP发起的SSO时,要使用SAML请求发送的中继状态。 +web-origins = Web起源 +web-origins.tooltip =允许的CORS起点。要允许有效重定向URI的所有来源,请添加“+”。允许所有起点添加'*'。 +fine-oidc-endpoint-conf = Fine Grain OpenID连接配置 +fine-oidc-endpoint-conf.tooltip =展开此部分以配置与OpenID Connect协议相关的此客户端的高级设置 +user-info-signed-response-alg =用户信息签名的响应算法 +user-info-signed-response-alg.tooltip =用于签名的用户信息端点响应的JWA算法。如果设置为“unsigned”,则用户信息响应将不会被签名,并将以application / json格式返回。 +request-object-signature-alg =请求对象签名算法 +request-object-signature-alg.tooltip = JWA算法,客户端在发送由'request'或'request_uri'参数指定的OIDC请求对象时需要使用。如果设置为“any”,则Request对象可以由任何算法(包括“none”)签名。 +fine-saml-endpoint-conf =细粒度SAML端点配置 +fine-saml-endpoint-conf.tooltip =展开此部分以配置Assertion Consumer和单一注销服务的确切URL。 +assertion-consumer-post-binding-url =断言使用者服务POST绑定URL +assertion-consumer-post-binding-url.tooltip = SAML POST绑定客户端断言使用者服务的URL(登录响应)。如果您没有此绑定的URL,则可以将此字段留空。 +assertion-consumer-redirect-binding-url =断言使用者服务重定向绑定URL +assertion-consumer-redirect-binding-url.tooltip = SAML重定向客户端断言使用者服务的绑定URL(登录响应)。如果您没有此绑定的URL,则可以将此字段留空。 +logout-service-post-binding-url =注销服务POST绑定URL +logout-service-post-binding-url.tooltip = SAML POST绑定客户端单一注销服务的URL。如果使用不同的绑定,则可以将此留空 +logout-service-redir-binding-url =注销服务重定向绑定URL +logout-service-redir-binding-url.tooltip = SAML重定向客户端单一注销服务的绑定URL。如果使用不同的绑定,则可以将此留空。 + +#client import +import-client =导入客户端 +format-option =格式选项 +select-format =选择格式 +import-file =导入文件 + +#client tabs +settings =设置 +credentials =凭据 +roles =角色 +mappers = Mappers +mappers.tooltip =协议映射器对令牌和文档执行转换。他们可以做一些事情,例如将用户数据映射到协议声明中,或者只是转换客户端和身份验证服务器之间的任何请求。 +scope =作用域 +scope.tooltip =作用域映射允许您限制哪些用户角色映射包含在客户端请求的访问令牌中。 +sessions.tooltip =查看此客户端的活动会话。允许您查看哪些用户处于活动状态,以及他们何时登录。 +offline-access =离线访问 +offline-access.tooltip =查看此客户端的离线会话。允许您查看哪些用户检索离线令牌以及何时检索离线令牌。要撤销客户端的所有令牌,请转到撤销选项卡,并将不早于值设置到现在。 +clustering =聚类 +installation =安装 +installation.tooltip =用于生成各种客户端适配器配置格式的帮助程序实用程序,您可以下载或剪切和粘贴以配置您的客户端。 +service-account-roles =服务帐户角色 +service-account-roles.tooltip =允许您为专用于此客户端的服务帐户验证角色映射。 + +# client credentials +client-authenticator =客户端认证器 +client-authenticator.tooltip =客户端身份验证器用于认证此客户端对Keycloak服务器 +certificate.tooltip =客户端发出的验证JWT的客户端证书,由客户端私钥从您的密钥库签名。 +publicKey.tooltip =由客户端发出并由客户端私钥签署的validate JWT的公钥。 +no-client-certificate-configured =未配置客户端证书 +gen-new-keys-and-cert =生成新密钥和证书 +import-certificate =导入证书 +gen-client-private-key =生成客户端私钥 +generate-private-key =生成私钥 +kid =孩子 +kid.tooltip =来自导入的JWKS的客户端公钥的KID(密钥ID)。 +use-jwks-url =使用JWKS URL +use-jwks-url.tooltip =如果开关打开,那么将从给定的JWKS URL下载客户端公钥。这允许很大的灵活性,因为当客户端生成新的密钥对时,新密钥将总是重新下载。如果交换机关闭,则使用来自Keycloak DB的公钥(或证书),因此当客户端密钥更改时,您总是需要将新密钥(或证书)导入到Keycloak数据库。 +jwks-url = JWKS URL +jwks-url.tooltip =存储JWK格式的客户端密钥的URL。有关更多详细信息,请参阅JWK规范。如果您使用带有“jwt”凭据的keycloak客户端适配器,那么您可以使用带有'/ k_jwks'后缀的应用程序的URL。例如“http://www.myhost.com/myapp/k_jwks”。 +archive-format =归档格式 +archive-format.tooltip = Java密钥库或PKCS12归档格式。 +key-alias =密钥别名 +key-alias.tooltip =存档您的私钥和证书的别名。 +key-password =密钥密码 +key-password.tooltip =访问存档中私钥的密码 +store-password =存储密码 +store-password.tooltip =访问归档本身的密码 +generate-and-download =生成和下载 +client-certificate-import =客户端证书导入 +import-client-certificate =导入客户端证书 +jwt-import.key-alias.tooltip =您的证书的归档别名。 +secret =秘密 +regenerate-secret =重生秘密 +registrationAccessToken =注册访问令牌 +registrationAccessToken.regenerate =重新生成注册访问令牌 +registrationAccessToken.tooltip =注册访问令牌为客户端提供对客户端注册服务的访问。 +add-role =添加角色 +role-name =角色名称 +composite = Composite +description =描述 +no-client-roles-available =没有可用的客户端角色 +scope-param-required = Scope Param必需 +scope-param-required.tooltip =只有在授权/令牌请求期间使用具有角色名称的scope参数时,才会授予此角色。 +composite-roles =复合角色 +composite-roles.tooltip =当将此角色(un)分配给用户时,与其关联的任何角色将被隐式分配(un)。 +realm-roles = Realm角色 +available-roles =可用角色 +add-selected =添加选择 +associated-roles =关联角色 +composite.associated-realm-roles.tooltip =与此组合角色关联的领域级角色。 +composite.available-realm-roles.tooltip =您可以关联到此组合角色的领域级角色。 +remove-selected =删除所选项 +client-roles =客户端角色 +select-client-to-view-roles =选择客户端以查看客户端的角色 +available-roles.tooltip =您可以与此组合角色关联的来自此客户端的角色。 +client.associated-roles.tooltip =与此组合角色关联的客户端角色。 +add-builtin =添加内置 +category = 目录 +type = 类型 +no-mappers-available =没有可用的映射器 +add-builtin-protocol-mappers =添加内置协议映射器 +add-builtin-protocol-mapper =添加内置协议映射器 +scope-mappings =范围映射 +full-scope-allowed =允许的全范围 +full-scope-allowed.tooltip =允许您禁用所有限制。 +scope.available-roles.tooltip =可以分配到范围的领域级角色。 +assigned-roles =分配的角色 +assigned-roles.tooltip =分配给范围的领域级角色。 +effective-roles =有效角色 +realm.effective-roles.tooltip =可能已从组合角色继承的分配的领域级角色。 +select-client-roles.tooltip =选择客户端以查看客户端的角色 +assign.available-roles.tooltip =可分配的客户端角色。 +client.assigned-roles.tooltip =分配的客户端角色。 +client.effective-roles.tooltip =可能已从组合角色继承的分配的客户端角色。 +basic-configuration =基本配置 +node-reregistration-timeout =节点重新注册超时 +node-reregistration-timeout.tooltip =指定注册的客户端群集节点重新注册的最大时间的间隔。如果集群节点在此时间内不会向Keycloak发送重新注册请求,则它将从Keycloak注销 +registered-cluster-nodes =注册的集群节点 +register-node-manually =手动注册节点 +test-cluster-availability =测试集群可用性 +last-registration =最后一次注册 +node-host =节点主机 +no-registered-cluster-nodes =没有注册的集群节点可用 +cluster-nodes =集群节点 +add-node =添加节点 +active-sessions.tooltip =此客户端的活动用户会话的总数。 +show-sessions =显示会话 +show-sessions.tooltip =警告,这是一个潜在昂贵的操作,取决于活动会话的数量。 +user =用户 +from-ip =从IP +session-start =会话开始 +first-page=第一页 +previous-page=上一页 +next-page =下一页 +client-revoke.not-before.tooltip =撤销此客户端在此日期之前发出的任何令牌。 +client-revoke.push.tooltip =如果为此客户端配置了管理URL,请将此策略推送到该客户端。 +select-a-format =选择格式 +download=下载 +offline-tokens =脱机令牌 +offline-tokens.tooltip =此客户端的脱机令牌的总数。 +show-offline-tokens =显示脱机令牌 +show-offline-tokens.tooltip =警告,这是一个潜在的昂贵的操作,取决于脱机令牌的数量。 +token-issued =发出的令牌 +last-access=最后访问 +last-refresh =上次刷新 +key-export =密钥导出 +key-import =密钥导入 +export-saml-key =导出SAML密钥 +import-saml-key =导入SAML密钥 +realm-certificate-alias =域证书别名 +realm-certificate-alias.tooltip = Realm证书也存储在归档中。这是它的别名。 +signing-key =签名密钥 +saml-signing-key = SAML签名密钥。 +private-key =私钥 +generate-new-keys =生成新密钥 +export =导出 +encryption-key =加密密钥 +saml-encryption-key.tooltip = SAML加密密钥。 +service-accounts =服务帐户 +service-account.available-roles.tooltip =可以分配给服务帐户的领域级角色。 +service-account.assigned-roles.tooltip =分配给服务帐户的领域级角色。 +service-account-is-not-enabled-for = {{client}}未启用服务帐户 +create-protocol-mappers =创建协议映射器 +create-protocol-mapper =创建协议映射器 +protocol =协议 +protocol.tooltip =协议... +id = ID +mapper.name.tooltip =映射器的名称。 +mapper.consent-required.tooltip =授予临时访问权限时,用户是否同意向客户端提供此数据? +consent-text =同意文本 +consent-text.tooltip =在同意页面上显示的文本。 +mapper-type =映射器类型 +mapper-type.tooltip =映射程序的类型 +# realm identity providers +identity-providers =身份提供者 +table-of-identity-providers =身份提供程序表 +add-provider.placeholder =添加提供程序... +provider =提供程序 +gui-order = GUI顺序 +first-broker-login-flow =第一登录流 +post-broker-login-flow =登录后流程 +redirect-uri =重定向URI +redirect-uri.tooltip =配置身份提供程序时要使用的重定向uri。 +alias =别名 +display-name =显示名称 +identity-provider.alias.tooltip =别名唯一标识身份提供者,它也用于构建重定向uri。 +identity-provider.display-name.tooltip =身份提供者的友好名称。 +identity-provider.enabled.tooltip =启用/禁用此身份提供程序。 +authenticate-by-default =默认验证 +identity-provider.authenticate-by-default.tooltip =指示在显示登录屏幕之前是否应默认尝试此提供程序进行身份验证。 +store-tokens =存储令牌 +identity-provider.store-tokens.tooltip =如果在验证用户后必须存储令牌,则启用/禁用。 +stored-tokens-readable=存储令牌可读 +identity-provider.stored-tokens-readable.tooltip =如果新用户可以读取任何存储的令牌,则启用/禁用。这将分配broker.read-token角色。 +disableUserInfo =禁用用户信息 +identity-provider.disableUserInfo.tooltip =禁用用户信息服务的使用以获取其他用户信息?默认是使用此OIDC服务。 +userIp =使用userIp参数 +identity-provider.google-userIp.tooltip =在Google的用户信息服务上调用时设置'userIp'查询参数。这将使用用户的IP地址。如果Google正在限制对用户信息服务的访问,则此选项非常有用。 +update-profile-on-first-login =首次登录时更新配置文件 +on =开 +on-missing-info =缺少信息 +off =关闭 +update-profile-on-first-login.tooltip =定义用户在首次登录期间必须更新其配置文件的条件。 +trust-email =信任电子邮件 +trust-email.tooltip =如果启用,则此提供商提供的电子邮件不会验证,即使已启用对领域的验证。 +gui-order.tooltip = GUI中提供者的定义顺序的数字(例如,在登录页面上)。 +first-broker-login-flow.tooltip =认证流的别名,在首次使用此身份提供者登录后触发。术语“首次登录”意味着尚未存在与认证身份提供商帐户链接的Keycloak帐户。 +post-broker-login-flow.tooltip =认证流的别名,在每次使用此身份提供程序登录后触发。如果您需要对通过此身份提供程序(例如OTP)验证的每个用户进行额外验证,这将非常有用。如果您不希望在使用此身份提供商登录后触发任何其他验证器,请将此空白留空。还要注意,认证者实现必须假定用户已经在ClientSession中设置为身份提供者已经设置。 +openid-connect-config = OpenID连接配置 +openid-connect-config.tooltip = OIDC SP和外部IDP配置。 +authorization-url =授权URL +authorization-url.tooltip =授权网址。 +token-url =令牌URL +token-url.tooltip =令牌URL。 +logout-url =注销URL +identity-provider.logout-url.tooltip =用于从外部IDP注销用户的会话终结点。 +backchannel-logout = Backchannel注销 +backchannel-logout.tooltip =外部IDP是否支持反向通道注销? +user-info-url =用户信息URL +user-info-url.tooltip =用户信息网址。这是可选的。 +identity-provider.client-id.tooltip =在身份提供者中注册的客户端或客户端标识符。 +client-secret =客户端密钥 +show-secret =显示密码 +hide-secret =隐藏秘密 +client-secret.tooltip =在身份提供程序中注册的客户端或客户端机密。 +issuer =发行人 +issuer.tooltip =响应的发行者的发行者标识符。如果未提供,将不执行验证。 +default-scopes =默认范围 +identity-provider.default-scopes.tooltip =在请求授权时要发送的作用域。它可以是以空格分隔的范围列表。默认为'openid'。 +prompt =提示 +unspecified.option =未指定 +none.option = none +consent.option =同意 +login.option = login +select-account.option = select_account +prompt.tooltip =指定授权服务器是否提示最终用户重新认证和同意。 +validate-signatures =验证签名 +identity-provider.validate-signatures.tooltip =启用/禁用外部IDP签名的签名验证。 +identity-provider.use-jwks-url.tooltip =如果交换机打开,那么将从给定的JWKS URL下载身份提供程序公钥。这允许很大的灵活性,因为当身份提供商生成新的密钥对时,新密钥将总是被重新下载。如果交换机关闭,则使用来自Keycloak DB的公钥(或证书),因此当身份提供商密钥更改时,您始终需要将新密钥导入到Keycloak数据库。 +identity-provider.jwks-url.tooltip =存储JWK格式的身份提供者密钥的URL。有关更多详细信息,请参阅JWK规范。如果你使用外部keycloak身份提供者,那么你可以使用像http:// broker-keycloak:8180 / auth / realms / test / protocol / openid-connect / certs这样的URL,假设你的代理keycloak是运行在http: / broker-keycloak:8180',它的境界是'test'。 +validating-public-key =验证公钥 +identity-provider.validating-public-key.tooltip =必须用于验证外部IDP签名的PEM格式的公钥。 +import-external-idp-config =导入外部IDP配置 +import-external-idp-config.tooltip =允许您从配置文件加载外部IDP元数据或从URL下载它。 +import-from-url =从URL导入 +identity-provider.import-from-url.tooltip =从远程IDP发现描述符导入元数据。 +import-from-file =从文件导入 +identity-provider.import-from-file.tooltip =从下载的IDP发现描述符导入元数据。 +saml-config = SAML配置 +identity-provider.saml-config.tooltip = SAML SP和外部IDP配置。 +single-signon-service-url =单点登录服务URL +saml.single-signon-service-url.tooltip =必须用于发送认证请求(SAML AuthnRequest)的URL。 +single-logout-service-url =单一注销服务URL +saml.single-logout-service-url.tooltip =必须用于发送注销请求的网址。 +nameid-policy-format = NameID策略格式 +nameid-policy-format.tooltip =指定与名称标识符格式相对应的URI引用。默认为urn:oasis:names:tc:SAML:2.0:nameid-format:persistent。 +http-post-binding-response = HTTP-POST绑定响应 +http-post-binding-response.tooltip =指示是否使用HTTP-POST绑定响应请求。如果为false,将使用HTTP-REDIRECT绑定。 +http-post-binding-for-authn-request = HTTP-POST AuthnRequest的绑定 +http-post-binding-for-authn-request.tooltip =指示是否必须使用HTTP-POST绑定发送AuthnRequest。如果为false,将使用HTTP-REDIRECT绑定。 +want-authn-requests-signed =需要AuthnRequests签名 +want-authn-requests-signed.tooltip =指示身份提供者是否期望签署AuthnRequest。 +force-authentication =强制验证 +identity-provider.force-authentication.tooltip =指示身份提供者是否必须直接认证演示者,而不是依赖以前的安全上下文。 +validate-signature =验证签名 +saml.validate-signature.tooltip =启用/禁用SAML响应的签名验证。 +validating-x509-certificate =验证X509证书 +validating-x509-certificate.tooltip =必须用于检查签名的PEM格式的证书。可以输入多个证书,用逗号(,)分隔。 +saml.import-from-url.tooltip =从远程IDP SAML实体描述符导入元数据。 +social.client-id.tooltip =向身份提供者注册的客户机标识符。 +social.client-secret.tooltip =向身份提供者注册的客户端密钥。 +social.default-scopes.tooltip =在请求授权时要发送的作用域。有关可能的值,分隔符和默认值,请参阅文档。 +key = Key +stackoverflow.key.tooltip =从Stack Overflow客户端注册获取的密钥。 + +# User federation +sync-ldap-roles-to-keycloak =将LDAP角色同步到Keycloak +sync-keycloak-roles-to-ldap =同步Keycloak到LDAP的角色 +sync-ldap-groups-to-keycloak =将LDAP组同步到Keycloak +sync-keycloak-groups-to-ldap =同步Keycloak组到LDAP + +realms =领域 +realm = 领域 + +identity-provider-mappers =身份提供者映射器 +create-identity-provider-mapper =创建身份提供者映射器 +add-identity-provider-mapper =添加身份提供者映射器 +client.description.tooltip =指定客户端的描述。例如“我的客户端的时间表”。支持本地化值的键。例如\\uff1a$ {my_client_description} + +expires =到期 +expiration =到期 +expiration.tooltip =指定令牌有效的时间 +count = Count +count.tooltip =指定可以使用令牌创建多少个客户端 +remainingCount =剩余计数 +created =已创建 +back =返回 +initial-access-tokens=初始接入令牌 +add-initial-access-tokens =添加初始访问令牌 +initial-access-token=初始接入令牌 +initial-access.copyPaste.tooltip =在导航离开此页面之前复制/粘贴初始访问令牌,因为它不可能稍后检索 +continue =继续 +initial-access-token.confirm.title =复制初始访问令牌 +initial-access-token.confirm.text =在确认之前,请复制并粘贴初始访问令牌,因为以后无法检索 +no-initial-access-available =没有初始访问令牌可用 + +client-reg-policies =客户端注册策略 +client-reg-policy.name.tooltip =显示策略的名称 +anonymous-policies =匿名访问策略 +anonymous-policies.tooltip =当客户端注册服务由未经身份验证的请求调用时,使用这些策略。这意味着请求不包含初始接入令牌或承载令牌。 +auth-policies =验证的访问策略 +auth-policies.tooltip =当通过认证请求调用客户端注册服务时使用这些策略。这意味着请求包含初始接入令牌或承载令牌。 +policy-name =策略名称 +no-client-reg-policies-configured =无客户端注册策略 +trusted-hosts.label =受信任的主机 +trusted-hosts.tooltip =主机列表,它们是受信任的,并且允许调用客户端注册服务和/或用作客户端URI的值。您可以使用主机名或IP地址。如果您在开头使用星号(例如“* .example.com”),则整个域example.com将受信任。 +host-sending-registration-request-must-match.label =主机发送客户端注册请求必须匹配 +host-sending-registration-request-must-match.tooltip =如果开启,则只要客户端注册服务是从某个受信任的主机或域发送的,就允许任何请求。 +client-uris-must-match.label =客户端URI必须匹配 +client-uris-must-match.tooltip =如果启用,则所有客户端URI(重定向URI和其他)只有在它们匹配一些受信任的主机或域时才允许。 +allowed-protocol-mappers.label =允许的协议映射器 +allowed-protocol-mappers.tooltip =允许的协议映射器提供程序的白名单。如果尝试注册客户端,其中包含一些未列入白名单的协议映射器,则注册请求将被拒绝。 +consent-required-for-all-mappers.label =需要同意Mappers +consent-required-for-all-mappers.tooltip =如果打开,则所有新注册的协议映射器将自动具有consentRequired开启。这意味着用户将需要批准同意屏幕。注意:只有在客户端已启用consentRequired开关时,才会显示同意屏幕。所以通常很好地使用这个开关与需要同意的政策。 +allowed-client-templates.label =允许的客户端模板 +allowed-client-templates.tooltip =客户端模板的白名单,可以在新注册的客户端上使用。尝试向某个未列入白名单的客户端模板注册客户端将被拒绝。默认情况下,白名单为空,因此不允许任何客户端模板。 +max-clients.label =每个领域的最大客户端 +max-clients.tooltip =如果域中现有客户端的数量等于或大于配置的限制,将不允许注册新客户端。 + +client-scopes =客户端模板 +client-scopes.tooltip =客户机模板允许您定义在多个客户机之间共享的公共配置 + +groups =组 + +group.add-selected.tooltip =可以分配给组的领域角色。 +group.assigned-roles.tooltip =映射到组的Realm角色 +group.effective-roles.tooltip =所有领域角色映射。这里的一些角色可能从映射组合角色继承。 +group.available-roles.tooltip =可从此客户端分配角色。 +group.assigned-roles-client.tooltip =此客户端的角色映射。 +group.effective-roles-client.tooltip =此客户端的角色映射。这里的一些角色可能从映射组合角色继承。 + +default-roles =默认角色 +no-realm-roles-available =没有领域角色可用 + +users =用户 +user.add-selected.tooltip =可以分配给用户的领域角色。 +user.assigned-roles.tooltip =映射到用户的Realm角色 +user.effective-roles.tooltip =所有领域角色映射。这里的一些角色可能从映射组合角色继承。 +user.available-roles.tooltip =可从此客户端分配角色。 +user.assigned-roles-client.tooltip =此客户端的角色映射。 +user.effective-roles-client.tooltip =此客户端的角色映射。这里的一些角色可能从映射组合角色继承。 +default.available-roles.tooltip =可以分配的领域级角色。 +realm-default-roles = Realm默认角色 +realm-default-roles.tooltip =分配给新用户的领域级别角色。 +default.available-roles-client.tooltip =可作为默认值分配的来自此客户端的角色。 +client-default-roles =客户端默认角色 +client-default-roles.tooltip =来自此客户端的作为默认角色分配的角色。 +composite.available-roles.tooltip =您可以关联到此组合角色的领域级角色。 +composite.associated-roles.tooltip =与此组合角色关联的领域级角色。 +composite.available-roles-client.tooltip =您可以与此组合角色关联的角色。 +composite.associated-roles-client.tooltip =与此组合角色关联的客户端角色。 +partial-import =部分导入 +partial-import.tooltip =部分导入允许您从先前导出的json文件导入用户,客户端和其他资源。 +file = 文件 +exported-json-file =导出的json文件 +import-from-realm =从领域导入 +import-users =导入用户 +import-groups =导入组 +import-clients =导入客户端 +import-identity-providers =导入身份提供者 +import-realm-roles =导入领域角色 +import-client-roles =导入客户端角色 +if-resource-exists =如果资源存在 +fail =失败 +skip =跳过 +overwrite =覆盖 +if-resource-exists.tooltip =指定在尝试导入已存在的资源时应该做什么。 + +action = Action +role-selector =角色选择器 +realm-roles.tooltip =可以选择的领域角色。 + +select-a-role =选择角色 +select-realm-role =选择领域角色 +client-roles.tooltip =可以选择的客户端角色。 +select-client-role =选择客户端角色 + +client-template =客户端模板 +client-template.tooltip =此客户端继承配置的客户端模板 +client-saml-endpoint =客户端SAML端点 +add-client-scope =添加客户端模板 + +manage =管理 +authentication =验证 +user-federation =用户联合 +user-storage =用户存储 +events =事件 +realm-settings =领域设置 +configure =配置 +select-realm =选择领域 +add =添加 + +client-scope.name.tooltip =客户端模板的名称。在领域中必须是唯一的 +client-scope.description.tooltip =客户端模板的描述 +client-scope.protocol.tooltip =此客户端模板提供的SSO协议配置 + +add-user-federation-provider =添加用户联合提供程序 +add-user-storage-provider =添加用户存储提供程序 +required-settings =必需的设置 +provider-id =提供商ID +console-display-name =控制台显示名称 +console-display-name.tooltip =在管理控制台中链接时显示提供程序的名称。 +priority =优先级 +priority.tooltip =执行用户查找时提供程序的优先级。最低优先。 +sync-settings =同步设置 +periodic-full-sync =周期性完全同步 +periodic-full-sync.tooltip =是否应该启用提供程序用户到Keycloak的周期性完全同步 +full-sync-period =完全同步周期 +full-sync-period.tooltip =完全同步的周期(以秒为单位) +periodic-changed-users-sync =定期更改的用户同步 +periodic-changed-users-sync.tooltip =应该启用更改的或新创建的提供程序用户到Keycloak的周期性同步 +changed-users-sync-period =更改的用户同步期间 +changed-users-sync-period.tooltip =用于同步更改的或新创建的提供程序用户的时间段(以秒为单位) +synchronize-changed-users =同步已更改的用户 +synchronize-all-users =同步所有用户 +kerberos-realm = Kerberos领域 +kerberos-realm.tooltip = kerberos域的名称。例如FOO.ORG +server-principal =服务器主体 +server-principal.tooltip = HTTP服务的服务器主体的完整名称,包括服务器和域名。例如HTTP /host.foo.org@FOO.ORG +keytab = KeyTab +keytab.tooltip =包含服务器主体的凭据的Kerberos KeyTab文件的位置。例如/etc/krb5.keytab +debug = Debug +debug.tooltip =启用/禁用调试日志到Krb5LoginModule的标准输出。 +allow-password-authentication =允许密码验证 +allow-password-authentication.tooltip =启用/禁用Kerberos数据库的用户名/密码身份验证的可能性 +edit-mode =编辑模式 +edit-mode.tooltip = READ_ONLY表示不允许更新密码,用户始终使用Kerberos密码进行身份验证。 UNSYNCED表示用户可以在Keycloak数据库中更改其密码,然后将使用此密码而不是Kerberos密码 +ldap.edit-mode.tooltip = READ_ONLY是只读LDAP存储。可写意味着数据将按需同步回LDAP。 UNSYNCED表示将导入用户数据,但不会同步回LDAP。 +update-profile-first-login =更新配置文件首次登录 +update-profile-first-login.tooltip =首次登录时更新配置文件 +sync-registrations =同步注册 +ldap.sync-registrations.tooltip =是否应在LDAP存储中创建新创建的用户?选择提供程序以同步新用户的优先级效果。 +vendor =供应商 +ldap.vendor.tooltip = LDAP供应商(提供者) +username-ldap-attribute =用户名LDAP属性 +ldap-attribute-name-for-username =用户名的LDAP属性名称 +username-ldap-attribute.tooltip = LDAP属性的名称,映射为Keycloak用户名。对于许多LDAP服务器供应商,它可以是“uid”。对于活动目录,可以是“sAMAccountName”或“cn”。应该为要从LDAP导入到Keycloak的所有LDAP用户记录填充该属性。 +rdn-ldap-attribute = RDN LDAP属性 +ldap-attribute-name-for-user-rdn =用户RDN的LDAP属性名称 +rdn-ldap-attribute.tooltip = LDAP属性的名称,用作典型用户DN的RDN(top属性)。通常它与用户名LDAP属性相同,但不是必需的。例如对于Active目录,当username属性可能是“sAMAccountName”时,通常使用“cn”作为RDN属性。 +uuid-ldap-attribute = UUID LDAP属性 +ldap-attribute-name-for-uuid = UUID的LDAP属性名称 +uuid-ldap-attribute.tooltip = LDAP属性的名称,用作LDAP中对象的唯一对象标识符(UUID)。对于许多LDAP服务器供应商,它的'entryUUID',但有些是不同的。例如对于Active目录,它应该是'objectGUID'。如果您的LDAP服务器确实不支持UUID的概念,您可以使用任何其他属性,它应该在树中的LDAP用户中是唯一的。例如“uid”或“entryDN”。 +user-object-classes =用户对象类 +ldap-user-object-classes.placeholder = LDAP用户对象类(以逗号分隔) + +ldap-connection-url = LDAP连接URL +ldap-users-dn = LDAP用户DN +ldap-bind-dn = LDAP绑定DN +ldap-bind-credentials = LDAP绑定凭据 +ldap-filter = LDAP过滤器 +ldap.user-object-classes.tooltip = LDAP中用户的LDAP objectClass属性的所有值除以逗号。例如:'inetOrgPerson,organizationalPerson'。新创建的Keycloak用户将被写入具有所有这些对象类的LDAP,并且只要现有的LDAP用户记录包含所有这些对象类,就会找到它们。 + +connection-url =连接URL +ldap.connection-url.tooltip =与LDAP服务器的连接URL +test-connection =测试连接 +users-dn =用户DN +ldap.users-dn.tooltip =用户所在的LDAP树的完整DN。此DN是LDAP用户的父级。它可以是例如'ou = users,dc = example,dc = com',假设您的典型用户将有DN像'uid = john,ou = users,dc = example,dc = com' +authentication-type =认证类型 +ldap.authentication-type.tooltip = LDAP认证类型。现在只有“无”(匿名LDAP身份验证)或“简单”(绑定凭据+绑定密码身份验证)机制可用 +bind-dn =绑定DN +ldap.bind-dn.tooltip = LDAP管理员的DN,Keycloak将使用它来访问LDAP服务器 +bind-credential =绑定凭据 +ldap.bind-credential.tooltip = LDAP管理员的密码 +test-authentication =测试验证 +custom-user-ldap-filter =自定义用户LDAP过滤器 +ldap.custom-user-ldap-filter.tooltip =用于过滤搜索用户的其他LDAP过滤器。如果您不需要额外的过滤器,请留空。确保它以'('开头,以')结束' +search-scope =搜索范围 +ldap.search-scope.tooltip =对于一个级别,我们仅在用户DN指定的DN中搜索用户。对于子树,我们搜索整个他们的子树。有关更多详细信息,请参阅LDAP文档 +use-truststore-spi =使用Truststore SPI +ldap.use-truststore-spi.tooltip =指定LDAP连接是否将使用具有在standalone.xml / domain.xml中配置的信任库的truststore SPI。 “永远”意味着它总是使用它。 “从不”意味着它不会使用它。 '只有ldaps'意味着它将使用,如果你的连接URL使用ldaps。即使未配置standalone.xml / domain.xml,也将使用由“javax.net.ssl.trustStore”属性指定的缺省Java cacerts或证书。 +connection-pooling =连接池 +ldap.connection-pooling.tooltip = Keycloak是否应该使用连接池来访问LDAP服务器 +ldap.pagination.tooltip = LDAP服务器是否支持分页。 +kerberos-integration = Kerberos集成 +allow-kerberos-authentication =允许Kerberos身份验证 +ldap.allow-kerberos-authentication.tooltip =启用/禁用具有SPNEGO / Kerberos令牌的用户的HTTP身份验证。有关已验证用户的数据将从此LDAP服务器进行配置 +use-kerberos-for-password-authentication =使用Kerberos进行密码验证 +ldap.use-kerberos-for-password-authentication.tooltip =使用Kerberos登录模块用于针对Kerberos服务器的身份验证用户名/密码,而不是使用Directory Service API对LDAP服务器进行身份验证 +batch-size =批量大小 +ldap.batch-size.tooltip =在单个事务中要从LDAP导入到Keycloak的LDAP用户的计数。 +ldap.periodic-full-sync.tooltip =是否应该启用LDAP用户到Keycloak的周期性完全同步 +ldap.periodic-changed-users-sync.tooltip =应该启用更改的或新创建的LDAP用户到Keycloak的周期性同步 +ldap.changed-users-sync-period.tooltip =用于同步更改的或新创建的LDAP用户的时间段(以秒为单位) +user-federation-mappers =用户联合映射器 +create-user-federation-mapper =创建用户联合映射器 +add-user-federation-mapper =添加用户联合映射器 +provider-name =提供程序名称 +no-user-federation-providers-configured =未配置用户联合提供程序 +no-user-storage-providers-configured =未配置用户存储提供程序 +add-identity-provider =添加身份提供者 +add-identity-provider-link =添加身份提供商链接 +identity-provider =身份提供者 +identity-provider-user-id =身份提供者用户ID +identity-provider-user-id.tooltip =身份提供者端的用户的唯一ID +identity-provider-username =身份提供者用户名 +identity-provider-username.tooltip =身份提供者端的用户名 +pagination =分页 + +browser-flow =浏览器流 +browser-flow.tooltip =选择要用于浏览器身份验证的流。 +registration-flow =注册流程 +registration-flow.tooltip =选择要用于注册的流。 +direct-grant-flow =直接授权流 +direct-grant-flow.tooltip =选择要用于直接授予身份验证的流。 +reset-credentials =重置凭据 +reset-credentials.tooltip =选择当用户忘记其凭据时要使用的流。 +client-authentication =客户端验证 +client-authentication.tooltip =选择要用于客户端身份验证的流。 +new =新 +copy =复制 +add-execution =添加执行 +add-flow =添加流 +auth-type =认证类型 +requirement=需求 +config = Config +no-executions-available =没有可用的执行 +authentication-flows =认证流 +create-authenticator-config =创建验证器配置 +authenticator.alias.tooltip =配置的名称 +otp-type = OTP类型 +time-based=基于时间的 +counter-based=基于计数器 +otp-type.tooltip = totp是基于时间的一次性密码。 'hotp'是一个计数器基本一次性密码,其中服务器保持一个计数器哈希。 +otp-hash-algorithm = OTP哈希算法 +otp-hash-algorithm.tooltip =应该使用什么散列算法来生成OTP。 +number-of-digits=位数 +otp.number-of-digits.tooltip = OTP有多少位? +look-ahead-window =向前看窗口 +otp.look-ahead-window.tooltip =如果令牌生成器和服务器不在时间同步或计数器同步,服务器应该向多远前进? +initial-counter=初始计数器 +otp.initial-counter.tooltip =初始计数器值应该是什么? +otp-token-period = OTP令牌周期 +otp-token-period.tooltip = OTP令牌有效多少秒?默认为30秒。 +table-of-password-policies =密码策略表 +add-policy.placeholder =添加策略... +policy-type =策略类型 +policy-value =策略值 +admin-events =管理事件 +admin-events.tooltip =显示领域的已保存管理事件。事件与管理员帐户相关,例如领域创建。要启用持久性事件,请转到配置。 +login-events =登录事件 +filter =过滤器 +update =更新 +reset =复位 +operation-types =操作类型 +resource-types =资源类型 +select-operations.placeholder =选择操作... +select-resource-types.placeholder =选择资源类型... +resource-path =资源路径 +resource-path.tooltip =按资源路径过滤。支持通配符'*'匹配路径的单个部分,'**'匹配多个部分。例如,“realms / * / clients / asbc”匹配任何域中具有id asbc的客户端,而“realms / master / **”匹配主域中的任何内容。 +date-(from)= Date(From) +date-(to)=日期(To) +authentication-details =验证详细信息 +ip-address = IP地址 +time=时间 +operation-type =操作类型 +resource-type =资源类型 +auth = Auth +representation =表示 +register=寄存器 +required-action =必需操作 +default-action =默认操作 +auth.default-action.tooltip =如果启用,任何新用户都将分配此必需操作。 +no-required-actions-configured =未配置所需的操作 +defaults-to-id =默认为id +flows=流量 +bindings =绑定 +required-actions =必需操作 +password-policy =密码策略 +otp-policy = OTP策略 +user-groups =用户组 +default-groups =默认组 +groups.default-groups.tooltip =新用户将自动加入的组的集合。 +cut = 剪切 +paste =粘贴 + +create-group =创建组 +create-authenticator-execution =创建Authenticator执行 +create-form-action-execution =创建表单操作执行 +create-top-level-form =创建顶级表单 +flow.alias.tooltip =指定流的显示名称。 +top-level-flow-type =顶级流类型 +flow.generic = generic +flow.client = client +top-level-flow-type.tooltip =什么样的顶层流是什么?类型“客户端”用于客户端(应用程序)的认证,当通用是为用户和其他 +create-execution-flow =创建执行流 +flow-type =流类型 +flow.form.type = form +flow.generic.type = generic +flow-type.tooltip =它是什么样的形式 +form-provider =表单提供程序 +default-groups.tooltip =新创建或注册的用户将自动添加到这些组 +select-a-type.placeholder =选择一个类型 +available-groups =可用组 +available-groups.tooltip =选择要添加为默认的组。 +value = Value +table-of-group-members =组成员表 +last-name =姓氏 +first-name =名字 +email =电子邮件 +toggle-navigation =切换导航 +manage-account =管理帐户 +sign-out=退出 +server-info =服务器信息 +resource-not-found =资源未找到 ... +resource-not-found.instruction =我们找不到您要找的资源。请确保您输入的网址正确无误。 +go-to-the-home-page =前往首页&raquo; +page-not-found =页面未找到 ... +page-not-found.instruction =我们找不到您要寻找的页面。请确保您输入的网址正确无误。 +events.tooltip =显示领域的已保存事件。事件与用户帐户相关,例如用户登录。要启用持久性事件,请转到配置。 +select-event-types.placeholder =选择事件类型... +events-config.tooltip =显示配置选项以启用用户和管理事件的持久性。 +select-an-action.placeholder =选择操作... +event-listeners.tooltip =配置什么侦听器接收领域的事件。 +login.save-events.tooltip =如果启用的登录事件保存到数据库,使事件可用于管理和帐户管理控制台。 +clear-events.tooltip =删除数据库中的所有事件。 +events.expiration.tooltip =设置事件的到期时间。过期事件将定期从数据库中删除。 +admin-events-settings =管理事件设置 +save-events =保存事件 +admin.save-events.tooltip =如果已启用的管理事件保存到数据库,使事件可用于管理控制台。 +saved-types.tooltip =配置保存的事件类型。 +include-representation =包含表示 +include-representation.tooltip =包含用于创建和更新请求的JSON表示。 +clear-admin-events.tooltip =删除数据库中的所有管理事件。 +server-version =服务器版本 +server-profile =服务器配置文件 +info =信息 +providers =提供者 +server-time =服务器时间 +server-uptime =服务器正常运行时间 +memory =内存 +total-memory =总内存 +free-memory =可用内存 +used-memory =使用的内存 +system = 系统 +current-working-directory =当前工作目录 +java-version = Java版本 +java-vendor = Java供应商 +java-runtime = Java运行时 +java-vm = Java VM +java-vm-version = Java虚拟机版本 +java-home = Java首页 +user-name =用户名 +user-timezone =用户时区 +user-locale =用户区域设置 +system-encoding =系统编码 +operating-system =操作系统 +os-architecture = OS体系结构 +spi = SPI +granted-roles =授予的角色 +granted-protocol-mappers =授予的协议映射器 +additional-grants =附加赠款 +consent-created-date =创建 +consent-last-updated-date =最后更新 +revoke =撤消 +new-password =新密码 +password-confirmation =密码确认 +reset-password =重置密码 +credentials.temporary.tooltip =如果启用,用户需要在下次登录时更改密码 +remove-totp =删除OTP +credentials.remove-totp.tooltip =为用户删除一次性密码生成器。 +reset-actions =复位操作 +credentials.reset-actions.tooltip =发送用户重置操作电子邮件时要执行的操作的集合。 “验证电子邮件”向用户发送电子邮件以验证其电子邮件地址。 “更新个人资料”要求用户输入新的个人信息。 “更新密码”要求用户输入新密码。 '配置OTP'需要设置移动密码生成器。 +reset-actions-email =重置操作电子邮件 +send-email =发送电子邮件 +credentials.reset-actions-email.tooltip =向具有嵌入链接的用户发送电子邮件。单击链接将允许用户执行重置操作。他们不必在此之前登录。例如,将操作设置为更新密码,单击此按钮,用户将无需登录即可更改其密码。 +add-user =添加用户 +created-at =创建于 +user-enabled =用户已启用 +user-enabled.tooltip =禁用的用户无法登录。 +user-temporarily-locked =用户临时锁定 +user-temporarily-locked.tooltip =用户可能由于无法登录太多次而被锁定。 +unlock-user =解锁用户 +federation-link =联合链接 +email-verified =电子邮件验证 +email-verified.tooltip =用户的电子邮件经过验证吗? +required-user-actions =必需的用户操作 +required-user-actions.tooltip =需要用户登录时的操作。“验证电子邮件”向用户发送电子邮件以验证其电子邮件地址。 “更新个人资料”要求用户输入新的个人信息。 “更新密码”要求用户输入新密码。 '配置OTP'需要设置移动密码生成器。 +locale =语言环境 +select-one.placeholder =选择一个... +impersonate =模拟 +impersonate-user =模拟用户 +impersonate-user.tooltip =以此用户身份登录。如果用户与您处于相同的领域,则在您以此用户身份登录之前,当前的登录会话将被注销。 +identity-provider-alias =身份提供者别名 +provider-user-id =提供程序用户ID +provider-username =提供者用户名 +no-identity-provider-links-available =没有可用的身份提供程序链接 +group-membership =组成员资格 +leave =离开 +group-membership.tooltip =组用户是的成员。选择列出的组,然后单击离开按钮退出组。 +membership.available-groups.tooltip =用户可以加入的组。选择一个组,然后单击加入按钮。 +table-of-realm-users =表的Realm用户 +view-all-users =查看所有用户 +unlock-users =解锁用户 +no-users-available =没有可用的用户 +users.instruction =请输入搜索,或点击查看所有用户 +consents=同意 +started =开始 +logout-all-sessions =注销所有会话 +logout =注销 +new-name =新名称 +ok =好的 +attributes =属性 +role-mappings =角色映射 +members =成员 +details =详细 +identity-provider-links =身份提供者链接 +register-required-action =注册所需的操作 +gender =性别 +address = 地址 +phone =电话 +profile-url =个人资料网址 +picture-url =图片网址 +website =网站 +import-keys-and-cert =导入密钥和证书 +import-keys-and-cert.tooltip =上传客户端的密钥对和证书。 +upload-keys =上传密钥 +download-keys-and-cert =下载密钥和证书 +no-value-assigned.placeholder =未分配值 +remove =删除 +no-group-members =没有组成员 +temporary =临时 +join =加入 +event-type =事件类型 +events-config =事件配置 +event-listeners =事件监听器 +login-events-settings =登录事件设置 +clear-events =清除事件 +saved-types =保存的类型 +clear-admin-events =清除管理事件 +clear-changes =清除更改 +error =错误 + +# Authz +# Authz Common +authz-authorization =授权 +authz-owner =所有者 +authz-uri = URI +authz-scopes =范围 +authz-resource =资源 +authz-resource-type =资源类型 +authz-resources =资源 +authz-scope =范围 +authz-authz-scopes =授权范围 +authz-policies =策略 +authz-permissions =权限 +authz-evaluate =评估 +authz-icon-uri =图标URI +authz-icon-uri.tooltip =指向图标的URI。 +authz-select-scope =选择范围 +authz-select-resource =选择资源 +authz-associated-policies =关联策略 +authz-any-resource =任何资源 +authz-any-scope =任何作用域 +authz-any-role =任何角色 +authz-policy-evaluation =政策评估 +authz-select-client =选择客户端 +authz-select-user =选择用户 +authz-entitlements =权利 +authz-no-resources =无资源 +authz-result = Result +authz-authorization-services-enabled =授权已启用 +authz-authorization-services-enabled.tooltip =启用/禁用客户端的细粒度授权支持 +authz-required =必需 + +# Authz Settings +authz-import-config.tooltip =导入包含此资源服务器的授权设置的JSON文件。 + +authz-policy-enforcement-mode =策略强制模式 +authz-policy-enforcement-mode.tooltip =策略强制模式指示在评估授权请求时如何强制执行策略。 “Enforcing”表示即使没有与给定资源相关联的策略,也会默认拒绝请求。 “Permissive”表示即使没有与给定资源相关联的策略也允许请求。 “禁用”完全禁用策略的评估,并允许访问任何资源。 +authz-policy-enforcement-mode-enforcing =强制 +authz-policy-enforcement-mode-permissive = Permissive +authz-policy-enforcement-mode-disabled =禁用 + +authz-remote-resource-management =远程资源管理 +authz-remote-resource-management.tooltip =资源服务器是否应该远程管理资源?如果为false,则只能从此管理控制台管理资源。 + +authz-export-settings =导出设置 +authz-export-settings.tooltip =导出并下载此资源服务器的所有授权设置。 + +# Authz Resource List +authz-no-resources-available =无可用资源。 +authz-no-scopes-assigned =未分配范围。 +authz-no-type-defined =未定义类型。 +authz-no-permission-assigned =未分配权限。 +authz-no-policy-assigned =未分配策略。 +authz-create-permission =创建权限 + +# Authz Resource Detail +authz-add-resource =添加资源 +authz-resource-name.tooltip =此资源的唯一名称。 该名称可用于唯一标识资源,在查询特定资源时很有用。 +authz-resource-owner.tooltip =此资源的所有者。 +authz-resource-type.tooltip =此资源的类型。 它可以用于对具有相同类型的不同资源实例进行分组。 +authz-resource-uri.tooltip =也可以用于唯一标识此资源的URI。 +authz-resource-scopes.tooltip =与此资源关联的范围。 + +# Authz Scope List +authz-add-scope=添加范围 +authz-no-scopes-available=没有可用的范围。 + +#Authz作用域详细信息 +authz-scope-name.tooltip =此作用域的唯一名称。该名称可用于唯一标识范围,在查询特定范围时很有用。 + +#Authz策略列表 +authz-all-types =所有类型 +authz-create-policy =创建策略 +authz-no-policies-available =没有可用的策略。 + +#Authz策略详细信息 +authz-policy-name.tooltip =此策略的名称。 +authz-policy-description.tooltip =此策略的描述。 +authz-policy-logic =逻辑 +authz-policy-logic-positive =肯定 +authz-policy-logic-negative = 否定 +authz-policy-logic.tooltip =逻辑决定如何进行策略决策。如果为“积极”,则在评估本政策期间获得的效果(许可或拒绝)将用于执行决策。如果为“否定”,则所得的效果将被否定,换句话说,许可证变为拒绝,反之亦然。 +authz-policy-apply-policy =应用策略 +authz-policy-apply-policy.tooltip =指定必须应用于此策略或权限定义的范围的所有策略。 +authz-policy-decision-strategy =决策策略 +authz-policy-decision-strategy.tooltip =决策策略规定如何评估与给定权限相关联的策略以及如何获得最终决策。 “肯定”意味着至少一个政策必须评估为积极的决定,以使最终决定也是积极的。 “一致”是指所有政策必须评估为一个积极的决定,以使最终决定也是积极的。 “共识”意味着积极决策的数量必须大于负面决策的数量。如果正数和负数相同,最终决定将为负数。 +authz-policy-decision-strategy-affirmative =肯定 +authz-policy-decision-strategy-unanimous =一致 +authz-policy-decision-strategy-consensus=共识 +authz-select-a-policy =选择一个策略 + +#Authz角色策略详细信息 +authz-add-role-policy =添加角色策略 +authz-no-roles-assigned =未分配角色。 +authz-policy-role-realm-roles.tooltip =指定此策略允许的* realm *角色。 +authz-policy-role-clients.tooltip =选择客户端以过滤可应用于此策略的客户端角色。 +authz-policy-role-client-roles.tooltip =指定此策略允许的客户端角色。 + +#Authz用户策略详细信息 +authz-add-user-policy =添加用户策略 +authz-no-users-assigned =未分配用户。 +authz-policy-user-users.tooltip =指定此策略允许哪些用户。 + +#Authz时间策略详细信息 +authz-add-time-policy =添加时间策略 +authz-policy-time-not-before.tooltip =定义不得授予策略的时间。仅当当前日期/时间晚于或等于此值时才被授予。 +authz-policy-time-not-on-after =不开或之后 +authz-policy-time-not-on-after.tooltip =定义不能授予策略的时间。仅当当前日期/时间在此值之前或之前时才被授予。 +authz-policy-time-day-month =日期 +authz-policy-time-day-month.tooltip =定义必须授予策略的月份日期。您还可以通过填充第二个字段来提供范围。在这种情况下,只有当月的当天介于或等于您提供的两个值之后,才会授予权限。 +authz-policy-time-month = month +authz-policy-time-month.tooltip =定义必须授予策略的月份。您还可以通过填充第二个字段来提供范围。在这种情况下,仅当当前月份介于或等于您提供的两个值之间时才会授予权限。 +authz-policy-time-year =年 +authz-policy-time-year.tooltip =定义策略必须授予的年份。您还可以通过填充第二个字段来提供范围。在这种情况下,仅当当前年份介于或等于您提供的两个值之间时才会授予权限。 +authz-policy-time-hour =小时 +authz-policy-time-hour.tooltip =定义策略必须被授予的小时。您还可以通过填充第二个字段来提供范围。在这种情况下,只有当前小时介于或等于您提供的两个值之间时才会授予权限。 +authz-policy-time-minute =分钟 +authz-policy-time-minute.tooltip =定义策略必须被授予的分钟。您还可以通过填充第二个字段来提供范围。在这种情况下,仅当当前分钟介于或等于您提供的两个值之间时才会授予权限。 + +#Authz JS策略详细信息 +authz-add-js-policy =添加JavaScript策略 +authz-policy-js-code =代码 +authz-policy-js-code.tooltip =提供此策略条件的JavaScript代码。 + + +#Authz聚合策略详细信息 +authz-aggregated=聚合 +authz-add-aggregation-policy =添加聚合策略 + +#Authz权限列表 +authz-no-permissions-available =没有可用的权限。 + +#Authz权限详细信息 +authz-permission-name.tooltip =此权限的名称。 +authz-permission-description.tooltip =此权限的描述。 + +#Authz资源许可详细信息 +authz-add-resource-permission =添加资源权限 +authz-permission-resource-apply-to-resource-type =应用于资源类型 +authz-permission-resource-apply-to-resource-type.tooltip =指定是否将此权限应用于具有给定类型的所有资源。 在这种情况下,将对给定资源类型的所有实例评估此权限。 +authz-permission-resource-resource.tooltip =指定此权限必须应用于特定资源实例。 +authz-permission-resource-type.tooltip =指定此权限必须应用于给定类型的所有资源实例。 + +#Authz Scope Permission Detail +authz-add-scope-permission =添加范围权限 +authz-permission-scope-resource.tooltip =将范围限制为与所选资源关联的范围。 如果未选择,则所有范围都可用。 +authz-permission-scope-scope.tooltip =指定此权限必须应用于一个或多个作用域。 + +# Authz Evaluation +authz-evaluation-identity-information =身份信息 +authz-evaluation-identity-information.tooltip =用于配置在评估策略时将使用的身份信息的可用选项。 +authz-evaluation-client.tooltip =选择进行此授权请求的客户端。如果未提供,授权请求将根据您所在的客户端完成。 +authz-evaluation-user.tooltip =选择一个用户,其身份将被用于查询服务器的权限。 +authz-evaluation-role.tooltip =选择要与所选用户关联的角色。 +authz-evaluation-new =新评估 +authz-evaluation-re-evaluate =重新评估 +authz-evaluation-previous =以前的评估 +authz-evaluation-contextual-info =上下文信息 +authz-evaluation-contextual-info.tooltip =用于配置在评估策略时将使用的任何上下文信息的可用选项。 +authz-evaluation-contextual-attributes =上下文属性 +authz-evaluation-contextual-attributes.tooltip =由正在运行的环境或执行上下文提供的任何属性。 +authz-evaluation-permissions.tooltip =用于配置将应用策略的权限的可用选项。 +authz-evaluation-evaluate =评估 +authz-evaluation-any-resource-with-scopes =任何具有范围的资源 +authz-evaluation-no-result =无法获取给定授权请求的任何结果。检查所提供的资源或范围是否与任何策略相关联。 +authz-evaluation-no-policies-resource =未找到此资源的策略。 +authz-evaluation-result.tooltip =此权限请求的总体结果。 +authz-evaluation-scopes.tooltip =允许的作用域列表。 +authz-evaluation-policies.tooltip =有关评估哪些策略及其决策的详细信息。 +authz-evaluation-authorization-data =响应 +authz-evaluation-authorization-data.tooltip =表示由于处理授权请求而携带授权数据的令牌。这个表示基本上是Keycloak向客户端请求权限的问题。针对根据当前授权请求授予的权限,检查“授权”声明。 +authz-show-authorization-data =显示授权数据 + +keys=秘钥 +all=所有 +status=状态 +keystore=钥匙链 +keystores= 钥匙链 +add-keystore=添加 钥匙链 +add-keystore.placeholder=添加 钥匙链... +view=查看 +active=活跃 + +Sunday=星期天 +Monday=星期一 +Tuesday=星期二 +Wednesday=星期三 +Thursday=星期四 +Friday=星期五 +Saturday=星期六 + +user-storage-cache-policy=缓存设置 +userStorage.cachePolicy=缓存策略 +userStorage.cachePolicy.option.DEFAULT=默认 +userStorage.cachePolicy.option.EVICT_WEEKLY=每周清理 +userStorage.cachePolicy.option.EVICT_DAILY=每日清理 +userStorage.cachePolicy.option.MAX_LIFESPAN=最大生命周期 +userStorage.cachePolicy.option.NO_CACHE=无缓存 +userStorage.cachePolicy.tooltip=这个存储源的缓存策略. '默认' 是全局的默认缓存策略。'每日清理'是每天特定时间缓存会失效. '每周清理'是每周第n天的特定时间缓存会失效. '最大寿命' 是指缓存条目的最大生命周期 +userStorage.cachePolicy.evictionDay=每周清理天数 +userStorage.cachePolicy.evictionDay.tooltip=每周第n天缓存失效 +userStorage.cachePolicy.evictionHour=每日清理小时数 +userStorage.cachePolicy.evictionHour.tooltip=一天中几点缓存失效 +userStorage.cachePolicy.evictionMinute=每日清理分钟数 +userStorage.cachePolicy.evictionMinute.tooltip=缓存失效的分钟 +userStorage.cachePolicy.maxLifespan=最大生命周期 +userStorage.cachePolicy.maxLifespan.tooltip=以微秒计数的最大生命周期 +user-origin-link=存储源 + +disable=关闭 +disableable-credential-types=可以关闭的类型 +credentials.disableable.tooltip=可以关闭的密码类型列表 +disable-credential-types=关闭密码类型 +credentials.disable.tooltip=点击按钮关闭密码类型 +credential-types=密码类型 +manage-user-password=管理密码 +disable-credentials=关闭密码 +credential-reset-actions=重置密码 +ldap-mappers=LDAP 映射器 +create-ldap-mapper=创建 LDAP 映射 +loginWithEmailAllowed=使用电子邮件登录 +duplicateEmailsAllowed=重复的邮件 +hidden=隐藏 + + + + + + diff --git a/keycloak-themes/base/admin/messages/messages_ca.properties b/keycloak-themes/base/admin/messages/messages_ca.properties new file mode 100644 index 0000000..50aa0a0 --- /dev/null +++ b/keycloak-themes/base/admin/messages/messages_ca.properties @@ -0,0 +1,8 @@ +invalidPasswordHistoryMessage=Contrasenya incorrecta: no pot ser igual a cap de les \u00FAltimes {0} contrasenyes. +invalidPasswordMinDigitsMessage=Contrase\u00F1a incorrecta: debe contener al menos {0} caracteres num\u00E9ricos. +invalidPasswordMinLengthMessage=Contrasenya incorrecta: longitud m\u00EDnima {0}. +invalidPasswordMinLowerCaseCharsMessage=Contrasenya incorrecta: ha de contenir almenys {0} lletres min\u00FAscules. +invalidPasswordMinSpecialCharsMessage=Contrasenya incorrecta: ha de contenir almenys {0} car\u00E0cters especials. +invalidPasswordMinUpperCaseCharsMessage=Contrasenya incorrecta: ha de contenir almenys {0} lletres maj\u00FAscules. +invalidPasswordNotUsernameMessage=Contrasenya incorrecta: no pot ser igual al nom d''usuari. +invalidPasswordRegexPatternMessage=Contrasenya incorrecta: no compleix l''expressi\u00F3 regular. diff --git a/keycloak-themes/base/admin/messages/messages_de.properties b/keycloak-themes/base/admin/messages/messages_de.properties new file mode 100644 index 0000000..3902300 --- /dev/null +++ b/keycloak-themes/base/admin/messages/messages_de.properties @@ -0,0 +1,29 @@ +invalidPasswordMinLengthMessage=Ung\u00FCltiges Passwort: muss mindestens {0} Zeichen beinhalten. +invalidPasswordMinLowerCaseCharsMessage=Ung\u00FCltiges Passwort: muss mindestens {0} Kleinbuchstaben beinhalten. +invalidPasswordMinDigitsMessage=Ung\u00FCltiges Passwort: muss mindestens {0} Ziffern beinhalten. +invalidPasswordMinUpperCaseCharsMessage=Ung\u00FCltiges Passwort: muss mindestens {0} Gro\u00DFbuchstaben beinhalten. +invalidPasswordMinSpecialCharsMessage=Ung\u00FCltiges Passwort: muss mindestens {0} Sonderzeichen beinhalten. +invalidPasswordNotUsernameMessage=Ung\u00FCltiges Passwort: darf nicht identisch mit dem Benutzernamen sein. +invalidPasswordNotEmailMessage=Ung\u00FCltiges Passwort: darf nicht identisch mit der E-Mail-Adresse sein. +invalidPasswordRegexPatternMessage=Ung\u00FCltiges Passwort: stimmt nicht mit Regex-Muster \u00FCberein. +invalidPasswordHistoryMessage=Ung\u00FCltiges Passwort: darf nicht identisch mit einem der letzten {0} Passw\u00F6rter sein. +invalidPasswordBlacklistedMessage=Ung\u00FCltiges Passwort: Passwort ist zu bekannt und auf der schwarzen Liste. +invalidPasswordGenericMessage=Ung\u00FCltiges Passwort: neues Passwort erf\u00FCllt die Passwort-Anforderungen nicht. + +#ldapErrorInvalidCustomFilter=Custom configured LDAP filter does not start with "(" or does not end with ")". +#ldapErrorConnectionTimeoutNotNumber=Connection Timeout must be a number +#ldapErrorReadTimeoutNotNumber=Read Timeout must be a number +#ldapErrorMissingClientId=Client ID needs to be provided in config when Realm Roles Mapping is not used. +#ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType=Not possible to preserve group inheritance and use UID membership type together. +#ldapErrorCantWriteOnlyForReadOnlyLdap=Can't set write only when LDAP provider mode is not WRITABLE +#ldapErrorCantWriteOnlyAndReadOnly=Can't set write-only and read-only together + +#clientRedirectURIsFragmentError=Redirect URIs must not contain an URI fragment +#clientRootURLFragmentError=Root URL must not contain an URL fragment + +#pairwiseMalformedClientRedirectURI=Client contained an invalid redirect URI. +#pairwiseClientRedirectURIsMissingHost=Client redirect URIs must contain a valid host component. +#pairwiseClientRedirectURIsMultipleHosts=Without a configured Sector Identifier URI, client redirect URIs must not contain multiple host components. +#pairwiseMalformedSectorIdentifierURI=Malformed Sector Identifier URI. +#pairwiseFailedToGetRedirectURIs=Failed to get redirect URIs from the Sector Identifier URI. +#pairwiseRedirectURIsMismatch=Client redirect URIs does not match redirect URIs fetched from the Sector Identifier URI. diff --git a/keycloak-themes/base/admin/messages/messages_en.properties b/keycloak-themes/base/admin/messages/messages_en.properties new file mode 100644 index 0000000..15c5acf --- /dev/null +++ b/keycloak-themes/base/admin/messages/messages_en.properties @@ -0,0 +1,67 @@ +invalidPasswordMinLengthMessage=Invalid password: minimum length {0}. +invalidPasswordMaxLengthMessage=Invalid password: maximum length {0}. +invalidPasswordMinLowerCaseCharsMessage=Invalid password: must contain at least {0} lower case characters. +invalidPasswordMinDigitsMessage=Invalid password: must contain at least {0} numerical digits. +invalidPasswordMinUpperCaseCharsMessage=Invalid password: must contain at least {0} upper case characters. +invalidPasswordMinSpecialCharsMessage=Invalid password: must contain at least {0} special characters. +invalidPasswordNotUsernameMessage=Invalid password: must not be equal to the username. +invalidPasswordNotEmailMessage=Invalid password: must not be equal to the email. +invalidPasswordRegexPatternMessage=Invalid password: fails to match regex pattern(s). +invalidPasswordHistoryMessage=Invalid password: must not be equal to any of last {0} passwords. +invalidPasswordBlacklistedMessage=Invalid password: password is blacklisted. +invalidPasswordGenericMessage=Invalid password: new password does not match password policies. + +ldapErrorEditModeMandatory=Edit Mode is mandatory +ldapErrorInvalidCustomFilter=Custom configured LDAP filter does not start with "(" or does not end with ")". +ldapErrorConnectionTimeoutNotNumber=Connection Timeout must be a number +ldapErrorReadTimeoutNotNumber=Read Timeout must be a number +ldapErrorMissingClientId=Client ID needs to be provided in config when Realm Roles Mapping is not used. +ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType=Not possible to preserve group inheritance and use UID membership type together. +ldapErrorCantWriteOnlyForReadOnlyLdap=Can not set write only when LDAP provider mode is not WRITABLE +ldapErrorCantWriteOnlyAndReadOnly=Can not set write-only and read-only together +ldapErrorCantEnableStartTlsAndConnectionPooling=Can not enable both StartTLS and connection pooling. +ldapErrorCantEnableUnsyncedAndImportOff=Can not disable Importing users when LDAP provider mode is UNSYNCED +ldapErrorMissingGroupsPathGroup=Groups path group does not exist - please create the group on specified path first +ldapErrorValidatePasswordPolicyAvailableForWritableOnly=Validate Password Policy is applicable only with WRITABLE edit mode + +clientRedirectURIsFragmentError=Redirect URIs must not contain an URI fragment +clientRootURLFragmentError=Root URL must not contain an URL fragment +clientRootURLIllegalSchemeError=Root URL uses an illegal scheme +clientBaseURLIllegalSchemeError=Base URL uses an illegal scheme +backchannelLogoutUrlIllegalSchemeError=Backchannel logout URL uses an illegal scheme +clientRedirectURIsIllegalSchemeError=A redirect URI uses an illegal scheme +clientBaseURLInvalid=Base URL is not a valid URL +clientRootURLInvalid=Root URL is not a valid URL +clientRedirectURIsInvalid=A redirect URI is not a valid URI +backchannelLogoutUrlIsInvalid=Backchannel logout URL is not a valid URL + + +pairwiseMalformedClientRedirectURI=Client contained an invalid redirect URI. +pairwiseClientRedirectURIsMissingHost=Client redirect URIs must contain a valid host component. +pairwiseClientRedirectURIsMultipleHosts=Without a configured Sector Identifier URI, client redirect URIs must not contain multiple host components. +pairwiseMalformedSectorIdentifierURI=Malformed Sector Identifier URI. +pairwiseFailedToGetRedirectURIs=Failed to get redirect URIs from the Sector Identifier URI. +pairwiseRedirectURIsMismatch=Client redirect URIs does not match redirect URIs fetched from the Sector Identifier URI. + +duplicatedJwksSettings=The "Use JWKS" switch and the switch "Use JWKS URL" cannot be ON at the same time. + +error-invalid-value=Invalid value. +error-invalid-blank=Please specify value. +error-empty=Please specify value. +error-invalid-length=Attribute {0} must have a length between {1} and {2}. +error-invalid-length-too-short=Attribute {0} must have minimal length of {1}. +error-invalid-length-too-long=Attribute {0} must have maximal length of {2}. +error-invalid-email=Invalid email address. +error-invalid-number=Invalid number. +error-number-out-of-range=Attribute {0} must be a number between {1} and {2}. +error-number-out-of-range-too-small=Attribute {0} must have minimal value of {1}. +error-number-out-of-range-too-big=Attribute {0} must have maximal value of {2}. +error-pattern-no-match=Invalid value. +error-invalid-uri=Invalid URL. +error-invalid-uri-scheme=Invalid URL scheme. +error-invalid-uri-fragment=Invalid URL fragment. +error-user-attribute-required=Please specify attribute {0}. +error-invalid-date=Attribute {0} is invalid date. +error-user-attribute-read-only=Attribute {0} is read only. +error-username-invalid-character={0} contains invalid character. +error-person-name-invalid-character={0} contains invalid character. \ No newline at end of file diff --git a/keycloak-themes/base/admin/messages/messages_es.properties b/keycloak-themes/base/admin/messages/messages_es.properties new file mode 100644 index 0000000..70e3d73 --- /dev/null +++ b/keycloak-themes/base/admin/messages/messages_es.properties @@ -0,0 +1,8 @@ +invalidPasswordMinLengthMessage=Contrase\u00F1a incorrecta: longitud m\u00EDnima {0}. +invalidPasswordMinLowerCaseCharsMessage=Contrase\u00F1a incorrecta: debe contener al menos {0} letras min\u00FAsculas. +invalidPasswordMinDigitsMessage=Contrase\u00F1a incorrecta: debe contener al menos {0} caracteres num\u00E9ricos. +invalidPasswordMinUpperCaseCharsMessage=Contrase\u00F1a incorrecta: debe contener al menos {0} letras may\u00FAsculas. +invalidPasswordMinSpecialCharsMessage=Contrase\u00F1a incorrecta: debe contener al menos {0} caracteres especiales. +invalidPasswordNotUsernameMessage=Contrase\u00F1a incorrecta: no puede ser igual al nombre de usuario. +invalidPasswordRegexPatternMessage=Contrase\u00F1a incorrecta: no cumple la expresi\u00F3n regular. +invalidPasswordHistoryMessage=Contrase\u00F1a incorrecta: no puede ser igual a ninguna de las \u00FAltimas {0} contrase\u00F1as. diff --git a/keycloak-themes/base/admin/messages/messages_fi.properties b/keycloak-themes/base/admin/messages/messages_fi.properties new file mode 100644 index 0000000..6eb3265 --- /dev/null +++ b/keycloak-themes/base/admin/messages/messages_fi.properties @@ -0,0 +1 @@ +# encoding: UTF-8 \ No newline at end of file diff --git a/keycloak-themes/base/admin/messages/messages_fr.properties b/keycloak-themes/base/admin/messages/messages_fr.properties new file mode 100644 index 0000000..c4a0216 --- /dev/null +++ b/keycloak-themes/base/admin/messages/messages_fr.properties @@ -0,0 +1,8 @@ +invalidPasswordMinLengthMessage=Mot de passe invalide : longueur minimale requise de {0}. +invalidPasswordMinLowerCaseCharsMessage=Mot de passe invalide : doit contenir au moins {0} lettre(s) en minuscule. +invalidPasswordMinDigitsMessage=Mot de passe invalide : doit contenir au moins {0} chiffre(s). +invalidPasswordMinUpperCaseCharsMessage=Mot de passe invalide : doit contenir au moins {0} lettre(s) en majuscule. +invalidPasswordMinSpecialCharsMessage=Mot de passe invalide : doit contenir au moins {0} caract\u00e8re(s) sp\u00e9ciaux. +invalidPasswordNotUsernameMessage=Mot de passe invalide : ne doit pas \u00eatre identique au nom d''utilisateur. +invalidPasswordRegexPatternMessage=Mot de passe invalide : ne valide pas l''expression rationnelle. +invalidPasswordHistoryMessage=Mot de passe invalide : ne doit pas \u00eatre \u00e9gal aux {0} derniers mot de passe. diff --git a/keycloak-themes/base/admin/messages/messages_it.properties b/keycloak-themes/base/admin/messages/messages_it.properties new file mode 100644 index 0000000..e69de29 diff --git a/keycloak-themes/base/admin/messages/messages_ja.properties b/keycloak-themes/base/admin/messages/messages_ja.properties new file mode 100644 index 0000000..1ba814b --- /dev/null +++ b/keycloak-themes/base/admin/messages/messages_ja.properties @@ -0,0 +1,30 @@ +# encoding: utf-8 +invalidPasswordMinLengthMessage=無効なパスワード: 最小{0}の長さが必要です。 +invalidPasswordMinLowerCaseCharsMessage=無効なパスワード: 少なくとも{0}文字の小文字を含む必要があります。 +invalidPasswordMinDigitsMessage=無効なパスワード: 少なくとも{0}文字の数字を含む必要があります。 +invalidPasswordMinUpperCaseCharsMessage=無効なパスワード: 少なくとも{0}文字の大文字を含む必要があります。 +invalidPasswordMinSpecialCharsMessage=無効なパスワード: 少なくとも{0}文字の特殊文字を含む必要があります。 +invalidPasswordNotUsernameMessage=無効なパスワード: ユーザー名と同じパスワードは禁止されています。 +invalidPasswordRegexPatternMessage=無効なパスワード: 正規表現パターンと一致しません。 +invalidPasswordHistoryMessage=無効なパスワード: 最近の{0}パスワードのいずれかと同じパスワードは禁止されています。 +invalidPasswordBlacklistedMessage=無効なパスワード: パスワードがブラックリストに含まれています。 +invalidPasswordGenericMessage=無効なパスワード: 新しいパスワードはパスワード・ポリシーと一致しません。 + +ldapErrorInvalidCustomFilter=LDAPフィルターのカスタム設定が、「(」から開始または「)」で終了となっていません。 +ldapErrorConnectionTimeoutNotNumber=接続タイムアウトは数字でなければなりません +ldapErrorReadTimeoutNotNumber=読み取りタイムアウトは数字でなければなりません +ldapErrorMissingClientId=レルムロール・マッピングを使用しない場合は、クライアントIDは設定内で提供される必要があります。 +ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType=グループの継承を維持することと、UIDメンバーシップ・タイプを使用することは同時にできません。 +ldapErrorCantWriteOnlyForReadOnlyLdap=LDAPプロバイダー・モードがWRITABLEではない場合は、write onlyを設定することはできません。 +ldapErrorCantWriteOnlyAndReadOnly=write-onlyとread-onlyを一緒に設定することはできません。 +ldapErrorCantEnableStartTlsAndConnectionPooling=StartTLSと接続プーリングの両方を有効にできません。 + +clientRedirectURIsFragmentError=リダイレクトURIにURIフラグメントを含めることはできません。 +clientRootURLFragmentError=ルートURLにURLフラグメントを含めることはできません。 + +pairwiseMalformedClientRedirectURI=クライアントに無効なリダイレクトURIが含まれていました。 +pairwiseClientRedirectURIsMissingHost=クライアントのリダイレクトURIには有効なホスト・コンポーネントが含まれている必要があります。 +pairwiseClientRedirectURIsMultipleHosts=設定されたセレクター識別子URIがない場合は、クライアントのリダイレクトURIは複数のホスト・コンポーネントを含むことはできません。 +pairwiseMalformedSectorIdentifierURI=不正なセレクター識別子URIです。 +pairwiseFailedToGetRedirectURIs=セクター識別子URIからリダイレクトURIを取得できませんでした。 +pairwiseRedirectURIsMismatch=クライアントのリダイレクトURIは、セクター識別子URIからフェッチされたリダイレクトURIと一致しません。 diff --git a/keycloak-themes/base/admin/messages/messages_lt.properties b/keycloak-themes/base/admin/messages/messages_lt.properties new file mode 100644 index 0000000..76885b7 --- /dev/null +++ b/keycloak-themes/base/admin/messages/messages_lt.properties @@ -0,0 +1,25 @@ +# encoding: utf-8 +invalidPasswordMinLengthMessage=Per trumpas slaptažodis: mažiausias ilgis {0}. +invalidPasswordMinLowerCaseCharsMessage=Neteisingas slaptažodis: privaloma įvesti {0} mažąją raidę. +invalidPasswordMinDigitsMessage=Neteisingas slaptažodis: privaloma įvesti {0} skaitmenį. +invalidPasswordMinUpperCaseCharsMessage=Neteisingas slaptažodis: privaloma įvesti {0} didžiąją raidę. +invalidPasswordMinSpecialCharsMessage=Neteisingas slaptažodis: privaloma įvesti {0} specialų simbolį. +invalidPasswordNotUsernameMessage=Neteisingas slaptažodis: slaptažodis negali sutapti su naudotojo vardu. +invalidPasswordRegexPatternMessage=Neteisingas slaptažodis: slaptažodis netenkina regex taisyklės(ių). +invalidPasswordHistoryMessage=Neteisingas slaptažodis: slaptažodis negali sutapti su prieš tai buvusiais {0} slaptažodžiais. + +ldapErrorInvalidCustomFilter=Sukonfigūruotas LDAP filtras neprasideda "(" ir nesibaigia ")" simboliais. +ldapErrorMissingClientId=Privaloma nurodyti kliento ID kai srities rolių susiejimas nėra nenaudojamas. +ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType=Grupių paveldėjimo ir UID narystės tipas kartu negali būti naudojami. +ldapErrorCantWriteOnlyForReadOnlyLdap=Negalima nustatyti rašymo rėžimo kuomet LDAP teikėjo rėžimas ne WRITABLE +ldapErrorCantWriteOnlyAndReadOnly=Negalima nustatyti tik rašyti ir tik skaityti kartu + +clientRedirectURIsFragmentError=Nurodykite URI fragmentą, kurio negali būti peradresuojamuose URI adresuose +clientRootURLFragmentError=Nurodykite URL fragmentą, kurio negali būti šakniniame URL adrese + +pairwiseMalformedClientRedirectURI=Klientas pateikė neteisingą nukreipimo nuorodą. +pairwiseClientRedirectURIsMissingHost=Kliento nukreipimo nuorodos privalo būti nurodytos su serverio vardo komponentu. +pairwiseClientRedirectURIsMultipleHosts=Kuomet nesukonfigūruotas sektoriaus identifikatoriaus URL, kliento nukreipimo nuorodos privalo talpinti ne daugiau kaip vieną skirtingą serverio vardo komponentą. +pairwiseMalformedSectorIdentifierURI=Neteisinga sektoriaus identifikatoriaus URI. +pairwiseFailedToGetRedirectURIs=Nepavyko gauti nukreipimo nuorodų iš sektoriaus identifikatoriaus URI. +pairwiseRedirectURIsMismatch=Kliento nukreipimo nuoroda neatitinka nukreipimo nuorodų iš sektoriaus identifikatoriaus URI. \ No newline at end of file diff --git a/keycloak-themes/base/admin/messages/messages_lv.properties b/keycloak-themes/base/admin/messages/messages_lv.properties new file mode 100644 index 0000000..dd55d69 --- /dev/null +++ b/keycloak-themes/base/admin/messages/messages_lv.properties @@ -0,0 +1 @@ +# encoding: UTF-8 diff --git a/keycloak-themes/base/admin/messages/messages_nl.properties b/keycloak-themes/base/admin/messages/messages_nl.properties new file mode 100644 index 0000000..4a04a52 --- /dev/null +++ b/keycloak-themes/base/admin/messages/messages_nl.properties @@ -0,0 +1,27 @@ +invalidPasswordMinLengthMessage=Ongeldig wachtwoord: de minimale lengte is {0} karakters. +invalidPasswordMinLowerCaseCharsMessage=Ongeldig wachtwoord: het moet minstens {0} kleine letters bevatten. +invalidPasswordMinDigitsMessage=Ongeldig wachtwoord: het moet minstens {0} getallen bevatten. +invalidPasswordMinUpperCaseCharsMessage=Ongeldig wachtwoord: het moet minstens {0} hoofdletters bevatten. +invalidPasswordMinSpecialCharsMessage=Ongeldig wachtwoord: het moet minstens {0} speciale karakters bevatten. +invalidPasswordNotUsernameMessage=Ongeldig wachtwoord: het mag niet overeenkomen met de gebruikersnaam. +invalidPasswordRegexPatternMessage=Ongeldig wachtwoord: het voldoet niet aan het door de beheerder ingestelde patroon. +invalidPasswordHistoryMessage=Ongeldig wachtwoord: het mag niet overeen komen met een van de laatste {0} wachtwoorden. +invalidPasswordGenericMessage=Ongeldig wachtwoord: het nieuwe wachtwoord voldoet niet aan het wachtwoordbeleid. + +ldapErrorInvalidCustomFilter=LDAP filter met aangepaste configuratie start niet met "(" of eindigt niet met ")". +ldapErrorConnectionTimeoutNotNumber=Verbindingstimeout moet een getal zijn +ldapErrorReadTimeoutNotNumber=Lees-timeout moet een getal zijn +ldapErrorMissingClientId=Client ID moet ingesteld zijn als Realm Roles Mapping niet gebruikt wordt. +ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType=Kan groepsovererving niet behouden bij UID-lidmaatschapstype. +ldapErrorCantWriteOnlyForReadOnlyLdap=Alleen-schrijven niet mogelijk als LDAP provider mode niet WRITABLE is +ldapErrorCantWriteOnlyAndReadOnly=Alleen-schrijven en alleen-lezen mogen niet tegelijk ingesteld zijn + +clientRedirectURIsFragmentError=Redirect URIs mogen geen URI fragment bevatten +clientRootURLFragmentError=Root URL mag geen URL fragment bevatten + +pairwiseMalformedClientRedirectURI=Client heeft een ongeldige redirect URI. +pairwiseClientRedirectURIsMissingHost=Client redirect URIs moeten een geldige host-component bevatten. +pairwiseClientRedirectURIsMultipleHosts=Zonder een geconfigureerde Sector Identifier URI mogen client redirect URIs niet meerdere host componenten hebben. +pairwiseMalformedSectorIdentifierURI=Onjuist notatie in Sector Identifier URI. +pairwiseFailedToGetRedirectURIs=Kon geen redirect URIs verkrijgen van de Sector Identifier URI. +pairwiseRedirectURIsMismatch=Client redirect URIs komen niet overeen met redict URIs ontvangen van de Sector Identifier URI. diff --git a/keycloak-themes/base/admin/messages/messages_no.properties b/keycloak-themes/base/admin/messages/messages_no.properties new file mode 100644 index 0000000..43cb61d --- /dev/null +++ b/keycloak-themes/base/admin/messages/messages_no.properties @@ -0,0 +1,14 @@ +invalidPasswordMinLengthMessage=Ugyldig passord: minimum lengde {0}. +invalidPasswordMinLowerCaseCharsMessage=Ugyldig passord: m\u00E5 inneholde minst {0} sm\u00E5 bokstaver. +invalidPasswordMinDigitsMessage=Ugyldig passord: m\u00E5 inneholde minst {0} sifre. +invalidPasswordMinUpperCaseCharsMessage=Ugyldig passord: m\u00E5 inneholde minst {0} store bokstaver. +invalidPasswordMinSpecialCharsMessage=Ugyldig passord: m\u00E5 inneholde minst {0} spesialtegn. +invalidPasswordNotUsernameMessage=Ugyldig passord: kan ikke v\u00E6re likt brukernavn. +invalidPasswordRegexPatternMessage=Ugyldig passord: tilfredsstiller ikke kravene for passord-m\u00F8nster. +invalidPasswordHistoryMessage=Ugyldig passord: kan ikke v\u00E6re likt noen av de {0} foreg\u00E5ende passordene. + +ldapErrorInvalidCustomFilter=Tilpasset konfigurasjon av LDAP-filter starter ikke med "(" eller slutter ikke med ")". +ldapErrorMissingClientId=KlientID m\u00E5 v\u00E6re tilgjengelig i config n\u00E5r sikkerhetsdomenerollemapping ikke brukes. +ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType=Ikke mulig \u00E5 bevare gruppearv og samtidig bruke UID medlemskapstype. +ldapErrorCantWriteOnlyForReadOnlyLdap=Kan ikke sette write-only n\u00E5r LDAP leverand\u00F8r-modus ikke er WRITABLE +ldapErrorCantWriteOnlyAndReadOnly=Kan ikke sette b\u00E5de write-only og read-only diff --git a/keycloak-themes/base/admin/messages/messages_pl.properties b/keycloak-themes/base/admin/messages/messages_pl.properties new file mode 100644 index 0000000..dd55d69 --- /dev/null +++ b/keycloak-themes/base/admin/messages/messages_pl.properties @@ -0,0 +1 @@ +# encoding: UTF-8 diff --git a/keycloak-themes/base/admin/messages/messages_pt_BR.properties b/keycloak-themes/base/admin/messages/messages_pt_BR.properties new file mode 100644 index 0000000..b26e465 --- /dev/null +++ b/keycloak-themes/base/admin/messages/messages_pt_BR.properties @@ -0,0 +1,18 @@ +#encoding: utf-8 +invalidPasswordMinLengthMessage=Senha inválida: deve conter ao menos {0} caracteres. +invalidPasswordMinLowerCaseCharsMessage=Senha inválida: deve conter ao menos {0} caracteres minúsculos. +invalidPasswordMinDigitsMessage=Senha inválida: deve conter ao menos {0} digitos numéricos. +invalidPasswordMinUpperCaseCharsMessage=Senha inválida: deve conter ao menos {0} caracteres maiúsculos. +invalidPasswordMinSpecialCharsMessage=Senha inválida: deve conter ao menos {0} caracteres especiais. +invalidPasswordNotUsernameMessage=Senha inválida: não deve ser igual ao nome de usuário. +invalidPasswordRegexPatternMessage=Senha inválida: falha ao passar por padrões. +invalidPasswordHistoryMessage=Senha inválida: não deve ser igual às últimas {0} senhas. + +ldapErrorInvalidCustomFilter=Filtro LDAP não inicia com "(" ou não termina com ")". +ldapErrorMissingClientId=ID do cliente precisa ser definido na configuração quando mapeamentos de Roles do Realm não é utilizado. +ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType=Não é possível preservar herança de grupos e usar tipo de associação de UID ao mesmo tempo. +ldapErrorCantWriteOnlyForReadOnlyLdap=Não é possível definir modo de somente escrita quando o provedor LDAP não suporta escrita +ldapErrorCantWriteOnlyAndReadOnly=Não é possível definir somente escrita e somente leitura ao mesmo tempo + +clientRedirectURIsFragmentError=URIs de redirecionamento não podem conter fragmentos +clientRootURLFragmentError=URL raiz não pode conter fragmentos \ No newline at end of file diff --git a/keycloak-themes/base/admin/messages/messages_ru.properties b/keycloak-themes/base/admin/messages/messages_ru.properties new file mode 100644 index 0000000..efedac4 --- /dev/null +++ b/keycloak-themes/base/admin/messages/messages_ru.properties @@ -0,0 +1,26 @@ +# encoding: utf-8 +invalidPasswordMinLengthMessage=Некорректный пароль: длина пароля должна быть не менее {0} символов(а). +invalidPasswordMinDigitsMessage=Некорректный пароль: должен содержать не менее {0} цифр(ы). +invalidPasswordMinLowerCaseCharsMessage=Некорректный пароль: пароль должен содержать не менее {0} символов(а) в нижнем регистре. +invalidPasswordMinUpperCaseCharsMessage=Некорректный пароль: пароль должен содержать не менее {0} символов(а) в верхнем регистре. +invalidPasswordMinSpecialCharsMessage=Некорректный пароль: пароль должен содержать не менее {0} спецсимволов(а). +invalidPasswordNotUsernameMessage=Некорректный пароль: пароль не должен совпадать с именем пользователя. +invalidPasswordRegexPatternMessage=Некорректный пароль: пароль не прошел проверку по регулярному выражению. +invalidPasswordHistoryMessage=Некорректный пароль: пароль не должен совпадать с последним(и) {0} паролем(ями). +invalidPasswordGenericMessage=Некорректный пароль: новый пароль не соответствует правилам пароля. + +ldapErrorInvalidCustomFilter=Сконфигурированный пользователем фильтр LDAP не должен начинаться с "(" или заканчиваться на ")". +ldapErrorMissingClientId=Client ID должен быть настроен в конфигурации, если не используется сопоставление ролей в realm. +ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType=Не удалось унаследовать группу и использовать членство UID типа вместе. +ldapErrorCantWriteOnlyForReadOnlyLdap=Невозможно установить режим "только на запись", когда LDAP провайдер не в режиме WRITABLE +ldapErrorCantWriteOnlyAndReadOnly=Невозможно одновременно установить режимы "только на чтение" и "только на запись" + +clientRedirectURIsFragmentError=URI перенаправления не должен содержать фрагмент URI +clientRootURLFragmentError=Корневой URL не должен содержать фрагмент URL + +pairwiseMalformedClientRedirectURI=Клиент содержит некорректный URI перенаправления. +pairwiseClientRedirectURIsMissingHost=URI перенаправления клиента должен содержать корректный компонент хоста. +pairwiseClientRedirectURIsMultipleHosts=Без конфигурации по части идентификатора URI, URI перенаправления клиента не может содержать несколько компонентов хоста. +pairwiseMalformedSectorIdentifierURI=Искаженная часть идентификатора URI. +pairwiseFailedToGetRedirectURIs=Не удалось получить идентификаторы URI перенаправления из части идентификатора URI. +pairwiseRedirectURIsMismatch=Клиент URI переадресации не соответствует URI переадресации, полученной из части идентификатора URI. diff --git a/keycloak-themes/base/admin/messages/messages_zh_CN.properties b/keycloak-themes/base/admin/messages/messages_zh_CN.properties new file mode 100644 index 0000000..622dccb --- /dev/null +++ b/keycloak-themes/base/admin/messages/messages_zh_CN.properties @@ -0,0 +1,26 @@ +# encoding: utf-8 +invalidPasswordMinLengthMessage=无效的密码:最短长度 {0}. +invalidPasswordMinLowerCaseCharsMessage=无效的密码:至少包含 {0} 小写字母 +invalidPasswordMinDigitsMessage=无效的密码:至少包含 {0} 个数字 +invalidPasswordMinUpperCaseCharsMessage=无效的密码:最短长度 {0} 大写字母 +invalidPasswordMinSpecialCharsMessage=无效的密码:最短长度 {0} 特殊字符 +invalidPasswordNotUsernameMessage=无效的密码: 不可以与用户名相同 +invalidPasswordRegexPatternMessage=无效的密码: 无法与正则表达式匹配 +invalidPasswordHistoryMessage=无效的密码:不能与最后使用的 {0} 个密码相同 + +ldapErrorInvalidCustomFilter=定制的 LDAP过滤器不是以 "(" 开头或以 ")"结尾. +ldapErrorConnectionTimeoutNotNumber=Connection Timeout 必须是个数字 +ldapErrorMissingClientId=当域角色映射未启用时,客户端 ID 需要指定。 +ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType=无法在使用UID成员类型的同时维护组继承属性。 +ldapErrorCantWriteOnlyForReadOnlyLdap=当LDAP提供方不是可写模式时,无法设置只写 +ldapErrorCantWriteOnlyAndReadOnly=无法同时设置只读和只写 + +clientRedirectURIsFragmentError=重定向URL不应包含URI片段 +clientRootURLFragmentError=根URL 不应包含 URL 片段 + +pairwiseMalformedClientRedirectURI=客户端包含一个无效的重定向URL +pairwiseClientRedirectURIsMissingHost=客户端重定向URL需要有一个有效的主机 +pairwiseClientRedirectURIsMultipleHosts=Without a configured Sector Identifier URI, client redirect URIs must not contain multiple host components. +pairwiseMalformedSectorIdentifierURI=Malformed Sector Identifier URI. +pairwiseFailedToGetRedirectURIs=无法从服务器获得重定向URL +pairwiseRedirectURIsMismatch=客户端的重定向URI与服务器端获取的URI配置不匹配。 diff --git a/keycloak-themes/base/admin/resources/js/app.js b/keycloak-themes/base/admin/resources/js/app.js new file mode 100644 index 0000000..04f0cc6 --- /dev/null +++ b/keycloak-themes/base/admin/resources/js/app.js @@ -0,0 +1,3858 @@ +'use strict'; + +var auth = {}; +var resourceBundle; +var locale = 'en'; + +var module = angular.module('keycloak', [ 'keycloak.services', 'keycloak.loaders', 'ui.bootstrap', 'ui.select2', 'angularFileUpload', 'angularTreeview', 'pascalprecht.translate', 'ngCookies', 'ngSanitize']); +var resourceRequests = 0; +var loadingTimer = -1; +var translateProvider = null; +var currentRealm = null; + +angular.element(document).ready(function () { + var keycloakAuth = new Keycloak(consoleBaseUrl + 'config'); + + function whoAmI(success, error) { + var req = new XMLHttpRequest(); + req.open('GET', consoleBaseUrl + 'whoami', true); + req.setRequestHeader('Accept', 'application/json'); + req.setRequestHeader('Authorization', 'bearer ' + keycloakAuth.token); + + req.onreadystatechange = function () { + if (req.readyState == 4) { + if (req.status == 200) { + var data = JSON.parse(req.responseText); + success(data); + } else { + error(); + } + } + } + + req.send(); + } + + function loadResourceBundle(success, error) { + var req = new XMLHttpRequest(); + req.open('GET', consoleBaseUrl + 'messages.json?lang=' + locale, true); + req.setRequestHeader('Accept', 'application/json'); + + req.onreadystatechange = function () { + if (req.readyState == 4) { + if (req.status == 200) { + var data = JSON.parse(req.responseText); + success && success(data); + } else { + error && error(); + } + } + } + + req.send(); + } + + function loadSelect2Localization() { + // 'en' is the built-in default and does not have to be loaded. + var supportedLocales = ['ar', 'az', 'bg', 'ca', 'cs', 'da', 'de', 'el', 'es', 'et', 'eu', 'fa', 'fi', 'fr', + 'gl', 'he', 'hr', 'hu', 'id', 'is', 'it', 'ja', 'ka', 'ko', 'lt', 'lv', 'mk', 'ms', 'nl', 'no', 'pl', + 'pt-BR', 'pt-PT', 'ro', 'rs', 'ru', 'sk', 'sv', 'th', 'tr', 'ug-CN', 'uk', 'vi', 'zh-CN', 'zh-TW']; + if (supportedLocales.indexOf(locale) == -1) return; + var select2JsUrl; + var allScriptElements = document.getElementsByTagName('script'); + for (var i = 0, n = allScriptElements.length; i < n; i++) { + var src = allScriptElements[i].getAttribute('src'); + if (src && src.match(/\/select2\/select2\.js$/)) { + select2JsUrl = src; + break; + } + } + if (!select2JsUrl) return; + var scriptElement = document.createElement('script'); + scriptElement.src = select2JsUrl.replace(/\/select2\/select2\.js$/, '/select2/select2_locale_'+locale+'.js'); + scriptElement.type = 'text/javascript'; + document.getElementsByTagName('head')[0].appendChild(scriptElement); + } + + function hasAnyAccess(user) { + return user && user['realm_access']; + } + + keycloakAuth.onAuthLogout = function() { + location.reload(); + } + + auth.refreshPermissions = function(success, error) { + whoAmI(function(data) { + auth.user = data; + auth.loggedIn = true; + auth.hasAnyAccess = hasAnyAccess(data); + + success(); + }, function() { + error(); + }); + }; + + module.factory('Auth', function () { + return auth; + }); + + keycloakAuth.init({ onLoad: 'login-required', pkceMethod: 'S256' }).then(function () { + auth.authz = keycloakAuth; + + whoAmI(function(data) { + auth.user = data; + auth.loggedIn = true; + auth.hasAnyAccess = hasAnyAccess(data); + locale = auth.user.locale || locale; + + loadResourceBundle(function(data) { + resourceBundle = data; + + var injector = angular.bootstrap(document, ["keycloak"]); + + injector.get('$translate')('consoleTitle').then(function (consoleTitle) { + document.title = consoleTitle; + }); + }); + }); + + loadSelect2Localization(); + }).catch(function () { + window.location.reload(); + }); +}); + +module.factory('authInterceptor', function($q, Auth) { + return { + request: function (config) { + if (!config.url.match(/.html$/)) { + var deferred = $q.defer(); + if (Auth.authz.token) { + Auth.authz.updateToken(5).then(function () { + config.headers = config.headers || {}; + config.headers.Authorization = 'Bearer ' + Auth.authz.token; + + deferred.resolve(config); + }).catch(function () { + location.reload(); + }); + } + return deferred.promise; + } else { + return config; + } + } + }; +}); + +module.config(['$translateProvider', function($translateProvider) { + translateProvider = $translateProvider; + $translateProvider.useSanitizeValueStrategy('sanitizeParameters'); + $translateProvider.preferredLanguage(locale); + $translateProvider.translations(locale, resourceBundle); +}]); + +// Change for upgrade to AngularJS 1.6 +// See https://github.com/angular/angular.js/commit/aa077e81129c740041438688dff2e8d20c3d7b52 +module.config(['$locationProvider', function($locationProvider) { + $locationProvider.hashPrefix(''); +}]); + +module.config([ '$routeProvider', function($routeProvider) { + $routeProvider + .when('/create/realm', { + templateUrl : resourceUrl + '/partials/realm-create.html', + resolve : { + + }, + controller : 'RealmCreateCtrl' + }) + .when('/realms/:realm', { + templateUrl : resourceUrl + '/partials/realm-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'RealmDetailCtrl' + }) + .when('/realms/:realm/localization', { + templateUrl : resourceUrl + '/partials/realm-localization.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + realmSpecificLocales : function(RealmSpecificLocalesLoader) { + return RealmSpecificLocalesLoader(); + } + }, + controller : 'RealmLocalizationCtrl' + }) + .when('/realms/:realm/localization/upload', { + templateUrl : resourceUrl + '/partials/realm-localization-upload.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'RealmLocalizationUploadCtrl' + }) + .when('/realms/:realm/login-settings', { + templateUrl : resourceUrl + '/partials/realm-login-settings.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'RealmLoginSettingsCtrl' + }) + .when('/realms/:realm/theme-settings', { + templateUrl : resourceUrl + '/partials/realm-theme-settings.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'RealmThemeCtrl' + }) + .when('/realms/:realm/cache-settings', { + templateUrl : resourceUrl + '/partials/realm-cache-settings.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'RealmCacheCtrl' + }) + .when('/realms', { + templateUrl : resourceUrl + '/partials/realm-list.html', + controller : 'RealmListCtrl' + }) + .when('/realms/:realm/token-settings', { + templateUrl : resourceUrl + '/partials/realm-tokens.html', + resolve : { + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + realm : function(RealmLoader) { + return RealmLoader(); + } + }, + controller : 'RealmTokenDetailCtrl' + }) + .when('/realms/:realm/user-profile', { + templateUrl : resourceUrl + '/partials/realm-user-profile.html', + resolve : { + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientScopes : function(ClientScopeListLoader) { + return ClientScopeListLoader(); + }, + }, + controller : 'RealmUserProfileCtrl' + }) + .when('/realms/:realm/client-registration/client-initial-access', { + templateUrl : resourceUrl + '/partials/client-initial-access.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientInitialAccess : function(ClientInitialAccessLoader) { + return ClientInitialAccessLoader(); + } + }, + controller : 'ClientInitialAccessCtrl' + }) + .when('/realms/:realm/client-registration/client-initial-access/create', { + templateUrl : resourceUrl + '/partials/client-initial-access-create.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + } + }, + controller : 'ClientInitialAccessCreateCtrl' + }) + .when('/realms/:realm/client-registration/client-reg-policies', { + templateUrl : resourceUrl + '/partials/client-reg-policies.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + policies : function(ComponentsLoader) { + return ComponentsLoader.loadComponents(null, 'org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy'); + }, + clientRegistrationPolicyProviders : function(ClientRegistrationPolicyProvidersLoader) { + return ClientRegistrationPolicyProvidersLoader(); + } + }, + controller : 'ClientRegPoliciesCtrl' + }) + .when('/realms/:realm/client-registration/client-reg-policies/create/:componentType/:providerId', { + templateUrl : resourceUrl + '/partials/client-reg-policy-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + instance : function($route) { + return { + providerType: 'org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy', + subType: $route.current.params.componentType, + providerId: $route.current.params.providerId + }; + }, + clientRegistrationPolicyProviders : function(ClientRegistrationPolicyProvidersLoader) { + return ClientRegistrationPolicyProvidersLoader(); + } + }, + controller : 'ClientRegPolicyDetailCtrl' + }) + .when('/realms/:realm/client-registration/client-reg-policies/:provider/:componentId', { + templateUrl : resourceUrl + '/partials/client-reg-policy-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + instance : function(ComponentLoader) { + return ComponentLoader(); + }, + clientRegistrationPolicyProviders : function(ClientRegistrationPolicyProvidersLoader) { + return ClientRegistrationPolicyProvidersLoader(); + } + }, + controller : 'ClientRegPolicyDetailCtrl' + }) + .when('/realms/:realm/client-policies/profiles', { + templateUrl : resourceUrl + '/partials/client-policies-profiles-list.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientProfiles : function(ClientPoliciesProfilesLoader) { + return ClientPoliciesProfilesLoader.loadClientProfiles('true'); + }, + }, + controller : 'ClientPoliciesProfilesListCtrl' + }) + .when('/realms/:realm/client-policies/profiles-json', { + templateUrl : resourceUrl + '/partials/client-policies-profiles-json.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientProfiles : function(ClientPoliciesProfilesLoader) { + return ClientPoliciesProfilesLoader.loadClientProfiles('true'); + } + }, + controller : 'ClientPoliciesProfilesJsonCtrl' + }) + .when('/realms/:realm/client-policies/profiles-create', { + templateUrl : resourceUrl + '/partials/client-policies-profiles-edit.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientProfiles : function(ClientPoliciesProfilesLoader) { + return ClientPoliciesProfilesLoader.loadClientProfiles('false'); + } + }, + controller : 'ClientPoliciesProfilesEditCtrl' + }) + .when('/realms/:realm/client-policies/profiles-update/:profileName', { + templateUrl : resourceUrl + '/partials/client-policies-profiles-edit.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientProfiles : function(ClientPoliciesProfilesLoader) { + return ClientPoliciesProfilesLoader.loadClientProfiles('true'); + } + }, + controller : 'ClientPoliciesProfilesEditCtrl' + }) + .when('/realms/:realm/client-policies/profiles-update/:profileName/create-executor', { + templateUrl : resourceUrl + '/partials/client-policies-profiles-edit-executor.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientProfiles : function(ClientPoliciesProfilesLoader) { + return ClientPoliciesProfilesLoader.loadClientProfiles('false'); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ClientPoliciesProfilesEditExecutorCtrl' + }) + .when('/realms/:realm/client-policies/profiles-update/:profileName/update-executor/:executorIndex', { + templateUrl : resourceUrl + '/partials/client-policies-profiles-edit-executor.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientProfiles : function(ClientPoliciesProfilesLoader) { + return ClientPoliciesProfilesLoader.loadClientProfiles('true'); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ClientPoliciesProfilesEditExecutorCtrl' + }) + .when('/realms/:realm/client-policies/policies', { + templateUrl : resourceUrl + '/partials/client-policies-list.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientPolicies : function(ClientPoliciesLoader) { + return ClientPoliciesLoader(); + } + }, + controller : 'ClientPoliciesListCtrl' + }) + .when('/realms/:realm/client-policies/policies-json', { + templateUrl : resourceUrl + '/partials/client-policies-json.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientPolicies : function(ClientPoliciesLoader) { + return ClientPoliciesLoader(); + } + }, + controller : 'ClientPoliciesJsonCtrl' + }) + .when('/realms/:realm/client-policies/policy-create', { + templateUrl : resourceUrl + '/partials/client-policies-policy-edit.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientProfiles : function(ClientPoliciesProfilesLoader) { + return ClientPoliciesProfilesLoader.loadClientProfiles('true'); + }, + clientPolicies : function(ClientPoliciesLoader) { + return ClientPoliciesLoader(); + } + }, + controller : 'ClientPoliciesEditCtrl' + }) + .when('/realms/:realm/client-policies/policies-update/:policyName', { + templateUrl : resourceUrl + '/partials/client-policies-policy-edit.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientProfiles : function(ClientPoliciesProfilesLoader) { + return ClientPoliciesProfilesLoader.loadClientProfiles('true'); + }, + clientPolicies : function(ClientPoliciesLoader) { + return ClientPoliciesLoader(); + } + }, + controller : 'ClientPoliciesEditCtrl' + }) + .when('/realms/:realm/client-policies/policies-update/:policyName/create-condition', { + templateUrl : resourceUrl + '/partials/client-policies-policy-edit-condition.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientPolicies : function(ClientPoliciesLoader) { + return ClientPoliciesLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ClientPoliciesEditConditionCtrl' + }) + .when('/realms/:realm/client-policies/policies-update/:policyName/update-condition/:conditionIndex', { + templateUrl : resourceUrl + '/partials/client-policies-policy-edit-condition.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientPolicies : function(ClientPoliciesLoader) { + return ClientPoliciesLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ClientPoliciesEditConditionCtrl' + }) + .when('/realms/:realm/keys', { + templateUrl : resourceUrl + '/partials/realm-keys.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + keys: function(RealmKeysLoader) { + return RealmKeysLoader(); + } + }, + controller : 'RealmKeysCtrl' + }) + .when('/realms/:realm/keys/passive', { + templateUrl : resourceUrl + '/partials/realm-keys-passive.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + keys: function(RealmKeysLoader) { + return RealmKeysLoader(); + } + }, + controller : 'RealmKeysCtrl' + }) + .when('/realms/:realm/keys/disabled', { + templateUrl : resourceUrl + '/partials/realm-keys-disabled.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + keys: function(RealmKeysLoader) { + return RealmKeysLoader(); + } + }, + controller : 'RealmKeysCtrl' + }) + .when('/realms/:realm/keys/providers', { + templateUrl : resourceUrl + '/partials/realm-keys-providers.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'RealmKeysProvidersCtrl' + }) + .when('/create/keys/:realm/providers/:provider', { + templateUrl : resourceUrl + '/partials/realm-keys-generic.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + instance : function() { + return { + }; + }, + providerId : function($route) { + return $route.current.params.provider; + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'GenericKeystoreCtrl' + }) + .when('/realms/:realm/keys/providers/:provider/:componentId', { + templateUrl : resourceUrl + '/partials/realm-keys-generic.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + instance : function(ComponentLoader) { + return ComponentLoader(); + }, + providerId : function($route) { + return $route.current.params.provider; + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'GenericKeystoreCtrl' + }) + .when('/realms/:realm/identity-provider-settings', { + templateUrl : resourceUrl + '/partials/realm-identity-provider.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + instance : function(IdentityProviderLoader) { + return {}; + }, + providerFactory : function(IdentityProviderFactoryLoader) { + return {}; + }, + authFlows : function(AuthenticationFlowsLoader) { + return {}; + } + }, + controller : 'RealmIdentityProviderCtrl' + }) + .when('/create/identity-provider/:realm/:provider_id', { + templateUrl : function(params){ return resourceUrl + '/partials/realm-identity-provider-' + params.provider_id + '.html'; }, + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + instance : function(IdentityProviderLoader) { + return {}; + }, + providerFactory : function(IdentityProviderFactoryLoader) { + return new IdentityProviderFactoryLoader(); + }, + authFlows : function(AuthenticationFlowsLoader) { + return AuthenticationFlowsLoader(); + } + }, + controller : 'RealmIdentityProviderCtrl' + }) + .when('/realms/:realm/identity-provider-settings/provider/:provider_id/:alias', { + templateUrl : function(params){ return resourceUrl + '/partials/realm-identity-provider-' + params.provider_id + '.html'; }, + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + instance : function(IdentityProviderLoader) { + return IdentityProviderLoader(); + }, + providerFactory : function(IdentityProviderFactoryLoader) { + return IdentityProviderFactoryLoader(); + }, + authFlows : function(AuthenticationFlowsLoader) { + return AuthenticationFlowsLoader(); + } + }, + controller : 'RealmIdentityProviderCtrl' + }) + .when('/realms/:realm/identity-provider-settings/provider/:provider_id/:alias/export', { + templateUrl : resourceUrl + '/partials/realm-identity-provider-export.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + identityProvider : function(IdentityProviderLoader) { + return IdentityProviderLoader(); + }, + providerFactory : function(IdentityProviderFactoryLoader) { + return IdentityProviderFactoryLoader(); + } + }, + controller : 'RealmIdentityProviderExportCtrl' + }) + .when('/realms/:realm/identity-provider-mappers/:alias/mappers', { + templateUrl : function(params){ return resourceUrl + '/partials/identity-provider-mappers.html'; }, + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + identityProvider : function(IdentityProviderLoader) { + return IdentityProviderLoader(); + }, + mapperTypes : function(IdentityProviderMapperTypesLoader) { + return IdentityProviderMapperTypesLoader(); + }, + mappers : function(IdentityProviderMappersLoader) { + return IdentityProviderMappersLoader(); + } + }, + controller : 'IdentityProviderMapperListCtrl' + }) + .when('/realms/:realm/identity-provider-mappers/:alias/mappers/:mapperId', { + templateUrl : function(params){ return resourceUrl + '/partials/identity-provider-mapper-detail.html'; }, + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + identityProvider : function(IdentityProviderLoader) { + return IdentityProviderLoader(); + }, + mapperTypes : function(IdentityProviderMapperTypesLoader) { + return IdentityProviderMapperTypesLoader(); + }, + mapper : function(IdentityProviderMapperLoader) { + return IdentityProviderMapperLoader(); + } + }, + controller : 'IdentityProviderMapperCtrl' + }) + .when('/create/identity-provider-mappers/:realm/:alias', { + templateUrl : function(params){ return resourceUrl + '/partials/identity-provider-mapper-detail.html'; }, + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + identityProvider : function(IdentityProviderLoader) { + return IdentityProviderLoader(); + }, + mapperTypes : function(IdentityProviderMapperTypesLoader) { + return IdentityProviderMapperTypesLoader(); + } + }, + controller : 'IdentityProviderMapperCreateCtrl' + }) + + .when('/realms/:realm/default-roles', { + templateUrl : resourceUrl + '/partials/realm-default-roles.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + roles : function(RoleListLoader) { + return RoleListLoader(); + } + }, + controller : 'RealmDefaultRolesCtrl' + }) + .when('/realms/:realm/smtp-settings', { + templateUrl : resourceUrl + '/partials/realm-smtp.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + } + }, + controller : 'RealmSMTPSettingsCtrl' + }) + .when('/realms/:realm/events', { + templateUrl : resourceUrl + '/partials/realm-events.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'RealmEventsCtrl' + }) + .when('/realms/:realm/admin-events', { + templateUrl : resourceUrl + '/partials/realm-events-admin.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'RealmAdminEventsCtrl' + }) + .when('/realms/:realm/events-settings', { + templateUrl : resourceUrl + '/partials/realm-events-config.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + eventsConfig : function(RealmEventsConfigLoader) { + return RealmEventsConfigLoader(); + } + }, + controller : 'RealmEventsConfigCtrl' + }) + .when('/realms/:realm/partial-import', { + templateUrl : resourceUrl + '/partials/partial-import.html', + resolve : { + resourceName : function() { return 'users'}, + realm : function(RealmLoader) { + return RealmLoader(); + } + }, + controller : 'RealmImportCtrl' + }) + .when('/realms/:realm/partial-export', { + templateUrl : resourceUrl + '/partials/partial-export.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + } + }, + controller : 'RealmExportCtrl' + }) + .when('/create/user/:realm', { + templateUrl : resourceUrl + '/partials/user-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + user : function() { + return {}; + } + }, + controller : 'UserDetailCtrl' + }) + .when('/realms/:realm/users/:user', { + templateUrl : resourceUrl + '/partials/user-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + user : function(UserLoader) { + return UserLoader(); + } + }, + controller : 'UserDetailCtrl' + }) + .when('/realms/:realm/users/:user/user-attributes', { + templateUrl : resourceUrl + '/partials/user-attributes.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + user : function(UserLoader) { + return UserLoader(); + } + }, + controller : 'UserDetailCtrl' + }) + .when('/realms/:realm/users/:user/user-credentials', { + templateUrl : resourceUrl + '/partials/user-credentials.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + user : function(UserLoader) { + return UserLoader(); + } + }, + controller : 'UserCredentialsCtrl' + }) + .when('/realms/:realm/users/:user/role-mappings', { + templateUrl : resourceUrl + '/partials/role-mappings.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + user : function(UserLoader) { + return UserLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + }, + client : function() { + return {}; + } + }, + controller : 'UserRoleMappingCtrl' + }) + .when('/realms/:realm/users/:user/groups', { + templateUrl : resourceUrl + '/partials/user-group-membership.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + user : function(UserLoader) { + return UserLoader(); + } + }, + controller : 'UserGroupMembershipCtrl' + }) + .when('/realms/:realm/users/:user/sessions', { + templateUrl : resourceUrl + '/partials/user-sessions.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + user : function(UserLoader) { + return UserLoader(); + }, + sessions : function(UserSessionsLoader) { + return UserSessionsLoader(); + } + }, + controller : 'UserSessionsCtrl' + }) + .when('/realms/:realm/users/:user/federated-identity', { + templateUrl : resourceUrl + '/partials/user-federated-identity-list.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + user : function(UserLoader) { + return UserLoader(); + }, + federatedIdentities : function(UserFederatedIdentityLoader) { + return UserFederatedIdentityLoader(); + } + }, + controller : 'UserFederatedIdentityCtrl' + }) + .when('/create/federated-identity/:realm/:user', { + templateUrl : resourceUrl + '/partials/user-federated-identity-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + user : function(UserLoader) { + return UserLoader(); + }, + federatedIdentities : function(UserFederatedIdentityLoader) { + return UserFederatedIdentityLoader(); + } + }, + controller : 'UserFederatedIdentityAddCtrl' + }) + .when('/realms/:realm/users/:user/consents', { + templateUrl : resourceUrl + '/partials/user-consents.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + user : function(UserLoader) { + return UserLoader(); + }, + userConsents : function(UserConsentsLoader) { + return UserConsentsLoader(); + } + }, + controller : 'UserConsentsCtrl' + }) + .when('/realms/:realm/users/:user/offline-sessions/:client', { + templateUrl : resourceUrl + '/partials/user-offline-sessions.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + user : function(UserLoader) { + return UserLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + offlineSessions : function(UserOfflineSessionsLoader) { + return UserOfflineSessionsLoader(); + } + }, + controller : 'UserOfflineSessionsCtrl' + }) + .when('/realms/:realm/users', { + templateUrl : resourceUrl + '/partials/user-list.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + } + }, + controller : 'UserListCtrl' + }) + + .when('/create/role/:realm', { + templateUrl : resourceUrl + '/partials/role-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + role : function() { + return {}; + }, + roles : function(RoleListLoader) { + return RoleListLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + } + }, + controller : 'RoleDetailCtrl' + }) + .when('/realms/:realm/roles/:role', { + templateUrl : resourceUrl + '/partials/role-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + role : function(RoleLoader) { + return RoleLoader(); + }, + roles : function(RoleListLoader) { + return RoleListLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + } + }, + controller : 'RoleDetailCtrl' + }) + .when('/realms/:realm/roles/:role/role-attributes', { + templateUrl : resourceUrl + '/partials/role-attributes.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + role : function(RoleLoader) { + return RoleLoader(); + }, + roles : function(RoleListLoader) { + return RoleListLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + } + }, + controller : 'RoleDetailCtrl' + }) + .when('/realms/:realm/roles/:role/users', { + templateUrl : resourceUrl + '/partials/realm-role-users.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + role : function(RoleLoader) { + return RoleLoader(); + } + }, + controller : 'RoleMembersCtrl' + }) + .when('/realms/:realm/roles', { + templateUrl : resourceUrl + '/partials/role-list.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + } + }, + controller : 'RoleListCtrl' + }) + .when('/realms/:realm/groups', { + templateUrl : resourceUrl + '/partials/group-list.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + } + }, + controller : 'GroupListCtrl' + }) + .when('/create/group/:realm/parent/:parentId', { + templateUrl : resourceUrl + '/partials/create-group.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + parentId : function($route) { + return $route.current.params.parentId; + } + }, + controller : 'GroupCreateCtrl' + }) + .when('/realms/:realm/groups/:group', { + templateUrl : resourceUrl + '/partials/group-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + group : function(GroupLoader) { + return GroupLoader(); + } + }, + controller : 'GroupDetailCtrl' + }) + .when('/realms/:realm/groups/:group/attributes', { + templateUrl : resourceUrl + '/partials/group-attributes.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + group : function(GroupLoader) { + return GroupLoader(); + } + }, + controller : 'GroupDetailCtrl' + }) + .when('/realms/:realm/groups/:group/members', { + templateUrl : resourceUrl + '/partials/group-members.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + group : function(GroupLoader) { + return GroupLoader(); + } + }, + controller : 'GroupMembersCtrl' + }) + .when('/realms/:realm/groups/:group/role-mappings', { + templateUrl : resourceUrl + '/partials/group-role-mappings.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + group : function(GroupLoader) { + return GroupLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + }, + client : function() { + return {}; + } + }, + controller : 'GroupRoleMappingCtrl' + }) + .when('/realms/:realm/default-groups', { + templateUrl : resourceUrl + '/partials/default-groups.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + } + }, + controller : 'DefaultGroupsCtrl' + }) + + + .when('/create/role/:realm/clients/:client', { + templateUrl : resourceUrl + '/partials/client-role-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + role : function() { + return {}; + }, + roles : function(RoleListLoader) { + return RoleListLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + } + }, + controller : 'ClientRoleDetailCtrl' + }) + .when('/realms/:realm/clients/:client/roles/:role', { + templateUrl : resourceUrl + '/partials/client-role-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + role : function(ClientRoleLoader) { + return ClientRoleLoader(); + }, + roles : function(RoleListLoader) { + return RoleListLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + } + }, + controller : 'ClientRoleDetailCtrl' + }) + .when('/realms/:realm/clients/:client/roles/:role/role-attributes', { + templateUrl : resourceUrl + '/partials/client-role-attributes.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + role : function(ClientRoleLoader) { + return ClientRoleLoader(); + }, + roles : function(RoleListLoader) { + return RoleListLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + } + }, + controller : 'ClientRoleDetailCtrl' + }) + .when('/realms/:realm/clients/:client/roles/:role/users', { + templateUrl : resourceUrl + '/partials/client-role-users.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + role : function(ClientRoleLoader) { + return ClientRoleLoader(); + } + }, + controller : 'ClientRoleMembersCtrl' + }) + .when('/realms/:realm/clients/:client/mappers', { + templateUrl : resourceUrl + '/partials/client-mappers.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ClientProtocolMapperListCtrl' + }) + .when('/realms/:realm/clients/:client/add-mappers', { + templateUrl : resourceUrl + '/partials/client-mappers-add.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'AddBuiltinProtocolMapperCtrl' + }) + .when('/realms/:realm/clients/:client/mappers/:id', { + templateUrl : resourceUrl + '/partials/client-protocol-mapper-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + mapper : function(ClientProtocolMapperLoader) { + return ClientProtocolMapperLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + } + + }, + controller : 'ClientProtocolMapperCtrl' + }) + .when('/create/client/:realm/:client/mappers', { + templateUrl : resourceUrl + '/partials/client-protocol-mapper-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + } + }, + controller : 'ClientProtocolMapperCreateCtrl' + }) + .when('/realms/:realm/clients/:client/client-scopes/setup-scopes', { + templateUrl : resourceUrl + '/partials/client-scopes-setup.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + clientScopes : function(ClientScopeListLoader) { + return ClientScopeListLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + clientDefaultClientScopes : function(ClientDefaultClientScopesLoader) { + return ClientDefaultClientScopesLoader(); + }, + clientOptionalClientScopes : function(ClientOptionalClientScopesLoader) { + return ClientOptionalClientScopesLoader(); + } + }, + controller : 'ClientClientScopesSetupCtrl' + }) + .when('/realms/:realm/clients/:client/client-scopes/evaluate-scopes', { + templateUrl : resourceUrl + '/partials/client-scopes-evaluate.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + }, + clientScopes : function(ClientScopeListLoader) { + return ClientScopeListLoader(); + }, + clientDefaultClientScopes : function(ClientDefaultClientScopesLoader) { + return ClientDefaultClientScopesLoader(); + }, + clientOptionalClientScopes : function(ClientOptionalClientScopesLoader) { + return ClientOptionalClientScopesLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ClientClientScopesEvaluateCtrl' + }) + .when('/realms/:realm/client-scopes/:clientScope/mappers', { + templateUrl : resourceUrl + '/partials/client-scope-mappers.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientScope : function(ClientScopeLoader) { + return ClientScopeLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ClientScopeProtocolMapperListCtrl' + }) + .when('/realms/:realm/client-scopes/:clientScope/add-mappers', { + templateUrl : resourceUrl + '/partials/client-scope-mappers-add.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientScope : function(ClientScopeLoader) { + return ClientScopeLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ClientScopeAddBuiltinProtocolMapperCtrl' + }) + .when('/realms/:realm/client-scopes/:clientScope/mappers/:id', { + templateUrl : resourceUrl + '/partials/client-scope-protocol-mapper-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientScope : function(ClientScopeLoader) { + return ClientScopeLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + mapper : function(ClientScopeProtocolMapperLoader) { + return ClientScopeProtocolMapperLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + } + + }, + controller : 'ClientScopeProtocolMapperCtrl' + }) + .when('/create/client-scope/:realm/:clientScope/mappers', { + templateUrl : resourceUrl + '/partials/client-scope-protocol-mapper-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + clientScope : function(ClientScopeLoader) { + return ClientScopeLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + } + }, + controller : 'ClientScopeProtocolMapperCreateCtrl' + }) + .when('/realms/:realm/clients/:client/sessions', { + templateUrl : resourceUrl + '/partials/client-sessions.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + sessionCount : function(ClientSessionCountLoader) { + return ClientSessionCountLoader(); + } + }, + controller : 'ClientSessionsCtrl' + }) + .when('/realms/:realm/clients/:client/offline-access', { + templateUrl : resourceUrl + '/partials/client-offline-sessions.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + offlineSessionCount : function(ClientOfflineSessionCountLoader) { + return ClientOfflineSessionCountLoader(); + } + }, + controller : 'ClientOfflineSessionsCtrl' + }) + .when('/realms/:realm/clients/:client/credentials', { + templateUrl : resourceUrl + '/partials/client-credentials.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + clientAuthenticatorProviders : function(ClientAuthenticatorProvidersLoader) { + return ClientAuthenticatorProvidersLoader(); + }, + clientConfigProperties: function(PerClientAuthenticationConfigDescriptionLoader) { + return PerClientAuthenticationConfigDescriptionLoader(); + } + }, + controller : 'ClientCredentialsCtrl' + }) + .when('/realms/:realm/clients/:client/oidc/:keyType/import/:attribute', { + templateUrl : resourceUrl + '/partials/client-oidc-key-import.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + callingContext : function() { + return "oidc"; + } + }, + controller : 'ClientCertificateImportCtrl' + }) + .when('/realms/:realm/clients/:client/oidc/:keyType/export/:attribute', { + templateUrl : resourceUrl + '/partials/client-oidc-key-export.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + callingContext : function() { + return "oidc"; + } + }, + controller : 'ClientCertificateExportCtrl' + }) + .when('/realms/:realm/clients/:client/identity-provider', { + templateUrl : resourceUrl + '/partials/client-identity-provider.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller : 'ClientIdentityProviderCtrl' + }) + .when('/realms/:realm/clients/:client/clustering', { + templateUrl : resourceUrl + '/partials/client-clustering.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller : 'ClientClusteringCtrl' + }) + .when('/register-node/realms/:realm/clients/:client/clustering', { + templateUrl : resourceUrl + '/partials/client-clustering-node.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller : 'ClientClusteringNodeCtrl' + }) + .when('/realms/:realm/clients/:client/clustering/:node', { + templateUrl : resourceUrl + '/partials/client-clustering-node.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller : 'ClientClusteringNodeCtrl' + }) + .when('/realms/:realm/clients/:client/saml/keys', { + templateUrl : resourceUrl + '/partials/client-saml-keys.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller : 'ClientSamlKeyCtrl' + }) + .when('/realms/:realm/clients/:client/saml/:keyType/import/:attribute', { + templateUrl : resourceUrl + '/partials/client-saml-key-import.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + callingContext : function() { + return "saml"; + } + }, + controller : 'ClientCertificateImportCtrl' + }) + .when('/realms/:realm/clients/:client/saml/:keyType/export/:attribute', { + templateUrl : resourceUrl + '/partials/client-saml-key-export.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + callingContext : function() { + return "saml"; + } + }, + controller : 'ClientCertificateExportCtrl' + }) + .when('/realms/:realm/clients/:client/oidc/keys', { + templateUrl : resourceUrl + '/partials/client-oidc-keys.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller : 'ClientOidcKeyCtrl' + }) + .when('/realms/:realm/clients/:client/roles', { + templateUrl : resourceUrl + '/partials/client-role-list.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller : 'ClientRoleListCtrl' + }) + .when('/realms/:realm/clients/:client/revocation', { + templateUrl : resourceUrl + '/partials/client-revocation.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller : 'ClientRevocationCtrl' + }) + .when('/realms/:realm/clients/:client/scope-mappings', { + templateUrl : resourceUrl + '/partials/client-scope-mappings.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + } + }, + controller : 'ClientScopeMappingCtrl' + }) + .when('/realms/:realm/clients/:client/installation', { + templateUrl : resourceUrl + '/partials/client-installation.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ClientInstallationCtrl' + }) + .when('/realms/:realm/clients/:client/service-account-roles', { + templateUrl : resourceUrl + '/partials/client-service-account-roles.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + user : function(ClientServiceAccountUserLoader) { + return ClientServiceAccountUserLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller : 'UserRoleMappingCtrl' + }) + .when('/create/client/:realm', { + templateUrl : resourceUrl + '/partials/create-client.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + }, + client : function() { + return {}; + }, + flows : function(AuthenticationFlowsLoader) { + return AuthenticationFlowsLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'CreateClientCtrl' + }) + .when('/realms/:realm/clients/:client', { + templateUrl : resourceUrl + '/partials/client-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + flows : function(AuthenticationFlowsLoader) { + return AuthenticationFlowsLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ClientDetailCtrl' + }) + .when('/create/client-scope/:realm', { + templateUrl : resourceUrl + '/partials/client-scope-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientScope : function() { + return {}; + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ClientScopeDetailCtrl' + }) + .when('/realms/:realm/client-scopes/:clientScope', { + templateUrl : resourceUrl + '/partials/client-scope-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientScope : function(ClientScopeLoader) { + return ClientScopeLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ClientScopeDetailCtrl' + }) + .when('/realms/:realm/client-scopes/:clientScope/scope-mappings', { + templateUrl : resourceUrl + '/partials/client-scope-scope-mappings.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientScope : function(ClientScopeLoader) { + return ClientScopeLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + } + }, + controller : 'ClientScopeScopeMappingCtrl' + }) + .when('/realms/:realm/clients', { + templateUrl : resourceUrl + '/partials/client-list.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + + }, + controller : 'ClientListCtrl' + }) + .when('/realms/:realm/client-scopes', { + templateUrl : resourceUrl + '/partials/client-scope-list.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientScopes : function(ClientScopeListLoader) { + return ClientScopeListLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + + }, + controller : 'ClientScopeListCtrl' + }) + .when('/realms/:realm/default-client-scopes', { + templateUrl : resourceUrl + '/partials/client-scopes-realm-default.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + clientScopes : function(ClientScopeListLoader) { + return ClientScopeListLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + }, + realmDefaultClientScopes : function(RealmDefaultClientScopesLoader) { + return RealmDefaultClientScopesLoader(); + }, + realmOptionalClientScopes : function(RealmOptionalClientScopesLoader) { + return RealmOptionalClientScopesLoader(); + } + }, + controller : 'ClientScopesRealmDefaultCtrl' + }) + .when('/import/client/:realm', { + templateUrl : resourceUrl + '/partials/client-import.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ClientImportCtrl' + }) + .when('/realms/:realm/client-stores', { + templateUrl : resourceUrl + '/partials/client-storage-list.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ClientStoresCtrl' + }) + .when('/realms/:realm/client-storage/providers/:provider/:componentId', { + templateUrl : resourceUrl + '/partials/client-storage-generic.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + instance : function(ComponentLoader) { + return ComponentLoader(); + }, + providerId : function($route) { + return $route.current.params.provider; + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'GenericClientStorageCtrl' + }) + .when('/create/client-storage/:realm/providers/:provider', { + templateUrl : resourceUrl + '/partials/client-storage-generic.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + instance : function() { + return { + + }; + }, + providerId : function($route) { + return $route.current.params.provider; + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'GenericClientStorageCtrl' + }) + .when('/', { + templateUrl : resourceUrl + '/partials/home.html', + controller : 'HomeCtrl' + }) + .when('/mocks/:realm', { + templateUrl : resourceUrl + '/partials/realm-detail_mock.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'RealmDetailCtrl' + }) + .when('/realms/:realm/sessions/revocation', { + templateUrl : resourceUrl + '/partials/session-revocation.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + } + }, + controller : 'RealmRevocationCtrl' + }) + .when('/realms/:realm/sessions/realm', { + templateUrl : resourceUrl + '/partials/session-realm.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + stats : function(RealmClientSessionStatsLoader) { + return RealmClientSessionStatsLoader(); + } + }, + controller : 'RealmSessionStatsCtrl' + }) + .when('/create/user-storage/:realm/providers/ldap', { + templateUrl : resourceUrl + '/partials/user-storage-ldap.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + instance : function() { + return { + + }; + }, + providerId : function($route) { + return $route.current.params.provider; + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'LDAPUserStorageCtrl' + }) + .when('/create/user-storage/:realm/providers/kerberos', { + templateUrl : resourceUrl + '/partials/user-storage-kerberos.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + instance : function() { + return { + + }; + }, + providerId : function($route) { + return "kerberos"; + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'GenericUserStorageCtrl' + }) + .when('/create/user-storage/:realm/providers/:provider', { + templateUrl : resourceUrl + '/partials/user-storage-generic.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + instance : function() { + return { + + }; + }, + providerId : function($route) { + return $route.current.params.provider; + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'GenericUserStorageCtrl' + }) + .when('/realms/:realm/user-storage/providers/ldap/:componentId', { + templateUrl : resourceUrl + '/partials/user-storage-ldap.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + instance : function(ComponentLoader) { + return ComponentLoader(); + }, + providerId : function($route) { + return $route.current.params.provider; + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'LDAPUserStorageCtrl' + }) + .when('/realms/:realm/user-storage/providers/kerberos/:componentId', { + templateUrl : resourceUrl + '/partials/user-storage-kerberos.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + instance : function(ComponentLoader) { + return ComponentLoader(); + }, + providerId : function($route) { + return "kerberos"; + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'GenericUserStorageCtrl' + }) + .when('/realms/:realm/user-storage/providers/:provider/:componentId', { + templateUrl : resourceUrl + '/partials/user-storage-generic.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + instance : function(ComponentLoader) { + return ComponentLoader(); + }, + providerId : function($route) { + return $route.current.params.provider; + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'GenericUserStorageCtrl' + }) + .when('/realms/:realm/ldap-mappers/:componentId', { + templateUrl : function(params){ return resourceUrl + '/partials/user-storage-ldap-mappers.html'; }, + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + provider : function(ComponentLoader) { + return ComponentLoader(); + }, + mappers : function(ComponentsLoader, $route) { + return ComponentsLoader.loadComponents($route.current.params.componentId, 'org.keycloak.storage.ldap.mappers.LDAPStorageMapper'); + } + }, + controller : 'LDAPMapperListCtrl' + }) + .when('/create/ldap-mappers/:realm/:componentId', { + templateUrl : function(params){ return resourceUrl + '/partials/user-storage-ldap-mapper-detail.html'; }, + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + provider : function(ComponentLoader) { + return ComponentLoader(); + }, + mapperTypes : function(SubComponentTypesLoader, $route) { + return SubComponentTypesLoader.loadComponents($route.current.params.componentId, 'org.keycloak.storage.ldap.mappers.LDAPStorageMapper'); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + } + }, + controller : 'LDAPMapperCreateCtrl' + }) + .when('/realms/:realm/ldap-mappers/:componentId/mappers/:mapperId', { + templateUrl : function(params){ return resourceUrl + '/partials/user-storage-ldap-mapper-detail.html'; }, + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + provider : function(ComponentLoader) { + return ComponentLoader(); + }, + mapperTypes : function(SubComponentTypesLoader, $route) { + return SubComponentTypesLoader.loadComponents($route.current.params.componentId, 'org.keycloak.storage.ldap.mappers.LDAPStorageMapper'); + }, + mapper : function(LDAPMapperLoader) { + return LDAPMapperLoader(); + }, + clients : function(ClientListLoader) { + return ClientListLoader(); + } + }, + controller : 'LDAPMapperCtrl' + }) + .when('/realms/:realm/user-federation', { + templateUrl : resourceUrl + '/partials/user-federation.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'UserFederationCtrl' + }) + .when('/realms/:realm/defense/headers', { + templateUrl : resourceUrl + '/partials/defense-headers.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + + }, + controller : 'DefenseHeadersCtrl' + }) + .when('/realms/:realm/defense/brute-force', { + templateUrl : resourceUrl + '/partials/brute-force.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + } + }, + controller : 'RealmBruteForceCtrl' + }) + .when('/realms/:realm/protocols', { + templateUrl : resourceUrl + '/partials/protocol-list.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + + }, + controller : 'ProtocolListCtrl' + }) + .when('/realms/:realm/authentication/flows', { + templateUrl : resourceUrl + '/partials/authentication-flows.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + flows : function(AuthenticationFlowsLoader) { + return AuthenticationFlowsLoader(); + }, + selectedFlow : function() { + return null; + } + }, + controller : 'AuthenticationFlowsCtrl' + }) + .when('/realms/:realm/authentication/flow-bindings', { + templateUrl : resourceUrl + '/partials/authentication-flow-bindings.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + flows : function(AuthenticationFlowsLoader) { + return AuthenticationFlowsLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'RealmFlowBindingCtrl' + }) + .when('/realms/:realm/authentication/flows/:flow', { + templateUrl : resourceUrl + '/partials/authentication-flows.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + flows : function(AuthenticationFlowsLoader) { + return AuthenticationFlowsLoader(); + }, + selectedFlow : function($route) { + return $route.current.params.flow; + } + }, + controller : 'AuthenticationFlowsCtrl' + }) + .when('/realms/:realm/authentication/flows/:flow/create/execution/:topFlow', { + templateUrl : resourceUrl + '/partials/create-execution.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + topFlow: function($route) { + return $route.current.params.topFlow; + }, + parentFlow : function(AuthenticationFlowLoader) { + return AuthenticationFlowLoader(); + }, + formActionProviders : function(AuthenticationFormActionProvidersLoader) { + return AuthenticationFormActionProvidersLoader(); + }, + authenticatorProviders : function(AuthenticatorProvidersLoader) { + return AuthenticatorProvidersLoader(); + }, + clientAuthenticatorProviders : function(ClientAuthenticatorProvidersLoader) { + return ClientAuthenticatorProvidersLoader(); + } + }, + controller : 'CreateExecutionCtrl' + }) + .when('/realms/:realm/authentication/flows/:flow/create/flow/execution/:topFlow', { + templateUrl : resourceUrl + '/partials/create-flow-execution.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + topFlow: function($route) { + return $route.current.params.topFlow; + }, + parentFlow : function(AuthenticationFlowLoader) { + return AuthenticationFlowLoader(); + }, + formProviders : function(AuthenticationFormProvidersLoader) { + return AuthenticationFormProvidersLoader(); + } + }, + controller : 'CreateExecutionFlowCtrl' + }) + .when('/realms/:realm/authentication/create/flow', { + templateUrl : resourceUrl + '/partials/create-flow.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + } + }, + controller : 'CreateFlowCtrl' + }) + .when('/realms/:realm/authentication/required-actions', { + templateUrl : resourceUrl + '/partials/required-actions.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + unregisteredRequiredActions : function(UnregisteredRequiredActionsListLoader) { + return UnregisteredRequiredActionsListLoader(); + } + }, + controller : 'RequiredActionsCtrl' + }) + .when('/realms/:realm/authentication/password-policy', { + templateUrl : resourceUrl + '/partials/password-policy.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'RealmPasswordPolicyCtrl' + }) + .when('/realms/:realm/authentication/otp-policy', { + templateUrl : resourceUrl + '/partials/otp-policy.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'RealmOtpPolicyCtrl' + }) + .when('/realms/:realm/authentication/webauthn-policy', { + templateUrl : resourceUrl + '/partials/webauthn-policy.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'RealmWebAuthnPolicyCtrl' + }) + .when('/realms/:realm/authentication/webauthn-policy-passwordless', { + templateUrl : resourceUrl + '/partials/webauthn-policy-passwordless.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'RealmWebAuthnPasswordlessPolicyCtrl' + }) + .when('/realms/:realm/authentication/ciba-policy', { + templateUrl : resourceUrl + '/partials/ciba-policy.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'RealmCibaPolicyCtrl' + }) + .when('/realms/:realm/authentication/flows/:flow/config/:provider/:config', { + templateUrl : resourceUrl + '/partials/authenticator-config.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + flow : function(AuthenticationFlowLoader) { + return AuthenticationFlowLoader(); + }, + configType : function(AuthenticationConfigDescriptionLoader) { + return AuthenticationConfigDescriptionLoader(); + }, + config : function(AuthenticationConfigLoader) { + return AuthenticationConfigLoader(); + } + }, + controller : 'AuthenticationConfigCtrl' + }) + .when('/create/authentication/:realm/flows/:flow/execution/:executionId/provider/:provider', { + templateUrl : resourceUrl + '/partials/authenticator-config.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + flow : function(AuthenticationFlowLoader) { + return AuthenticationFlowLoader(); + }, + configType : function(AuthenticationConfigDescriptionLoader) { + return AuthenticationConfigDescriptionLoader(); + }, + execution : function(ExecutionIdLoader) { + return ExecutionIdLoader(); + } + }, + controller : 'AuthenticationConfigCreateCtrl' + }) + .when('/create/localization/:realm/:locale', { + templateUrl : resourceUrl + '/partials/realm-localization-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + locale: function($route) { + return $route.current.params.locale; + }, + key: function() { + return null + }, + localizationText : function() { + return null; + } + }, + controller : 'RealmLocalizationDetailCtrl' + }) + .when('/realms/:realm/localization/:locale/:key', { + templateUrl : resourceUrl + '/partials/realm-localization-detail.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + locale: function($route) { + return $route.current.params.locale; + }, + key: function($route) { + return $route.current.params.key; + }, + localizationText : function(RealmSpecificlocalizationTextLoader) { + return RealmSpecificlocalizationTextLoader(); + } + }, + controller : 'RealmLocalizationDetailCtrl' + }) + .when('/server-info', { + templateUrl : resourceUrl + '/partials/server-info.html', + resolve : { + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ServerInfoCtrl' + }) + .when('/server-info/providers', { + templateUrl : resourceUrl + '/partials/server-info-providers.html', + resolve : { + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller : 'ServerInfoCtrl' + }) + .when('/logout', { + templateUrl : resourceUrl + '/partials/home.html', + controller : 'LogoutCtrl' + }) + .when('/notfound', { + templateUrl : resourceUrl + '/partials/notfound.html' + }) + .when('/forbidden', { + templateUrl : resourceUrl + '/partials/forbidden.html' + }) + .otherwise({ + templateUrl : resourceUrl + '/partials/pagenotfound.html' + }); +} ]); + +module.config(function($httpProvider) { + $httpProvider.interceptors.push('errorInterceptor'); + + var spinnerFunction = function(data, headersGetter) { + if (resourceRequests == 0) { + loadingTimer = window.setTimeout(function() { + $('#loading').show(); + loadingTimer = -1; + }, 500); + } + resourceRequests++; + return data; + }; + $httpProvider.defaults.transformRequest.push(spinnerFunction); + + $httpProvider.interceptors.push('spinnerInterceptor'); + $httpProvider.interceptors.push('authInterceptor'); + +}); + +module.factory('spinnerInterceptor', function($q, $window, $rootScope, $location) { + return { + response: function(response) { + resourceRequests--; + if (resourceRequests == 0) { + if(loadingTimer != -1) { + window.clearTimeout(loadingTimer); + loadingTimer = -1; + } + $('#loading').hide(); + } + return response; + }, + responseError: function(response) { + resourceRequests--; + if (resourceRequests == 0) { + if(loadingTimer != -1) { + window.clearTimeout(loadingTimer); + loadingTimer = -1; + } + $('#loading').hide(); + } + + return $q.reject(response); + } + }; +}); + +module.factory('errorInterceptor', function($q, $window, $rootScope, $location, Notifications, Auth) { + return { + response: function(response) { + return response; + }, + responseError: function(response) { + if (response.status == 401) { + Auth.authz.logout(); + } else if (response.status == 403) { + $location.path('/forbidden'); + } else if (response.status == 404) { + $location.path('/notfound'); + } else if (response.status) { + if (response.data && response.data.errorMessage) { + Notifications.error(response.data.errorMessage); + } else if (response.data && response.data.errors) { + var messages = "Multiple errors found: "; + + for (var i = 0; i < response.data.errors.length; i++) { + messages+=response.data.errors[i].errorMessage + " "; + } + + Notifications.error(messages); + } else if (response.data && response.data.error_description) { + Notifications.error(response.data.error_description); + } else { + Notifications.error("An unexpected server error has occurred"); + } + } else { + Notifications.error("No response from server."); + } + return $q.reject(response); + } + }; +}); + +// collapsable form fieldsets +module.directive('collapsable', function() { + return function(scope, element, attrs) { + element.click(function() { + $(this).toggleClass('collapsed'); + $(this).find('.toggle-icons').toggleClass('kc-icon-collapse').toggleClass('kc-icon-expand'); + $(this).find('.toggle-icons').text($(this).text() == "Icon: expand" ? "Icon: collapse" : "Icon: expand"); + $(this).parent().find('.form-group').toggleClass('hidden'); + }); + } +}); + +// collapsable form fieldsets +module.directive('uncollapsed', function() { + return function(scope, element, attrs) { + element.prepend(' '); + element.click(function() { + $(this).find('.toggle-class').toggleClass('fa-angle-down').toggleClass('fa-angle-right'); + $(this).parent().find('.form-group').toggleClass('hidden'); + }); + } +}); + +// collapsable form fieldsets +module.directive('collapsed', function() { + return function(scope, element, attrs) { + element.prepend(' '); + element.parent().find('.form-group').toggleClass('hidden'); + element.click(function() { + $(this).find('.toggle-class').toggleClass('fa-angle-down').toggleClass('fa-angle-right'); + $(this).parent().find('.form-group').toggleClass('hidden'); + }); + } +}); + +/** + * Directive for presenting an ON-OFF switch for checkbox. + * Usage: + */ +module.directive('onoffswitch', function() { + return { + restrict: "EA", + replace: true, + scope: { + name: '@', + id: '@', + ngModel: '=', + ngDisabled: '=', + kcOnText: '@onText', + kcOffText: '@offText' + }, + // TODO - The same code acts differently when put into the templateURL. Find why and move the code there. + //templateUrl: "templates/kc-switch.html", + template: "
", + compile: function(element, attrs) { + /* + We don't want to propagate basic attributes to the root element of directive. Id should be passed to the + input element only to achieve proper label binding (and validity). + */ + element.removeAttr('name'); + element.removeAttr('id'); + + if (!attrs.onText) { attrs.onText = "ON"; } + if (!attrs.offText) { attrs.offText = "OFF"; } + + element.bind('keydown', function(e){ + var code = e.keyCode || e.which; + if (code === 32 || code === 13) { + e.stopImmediatePropagation(); + e.preventDefault(); + $(e.target).find('input').click(); + } + }); + } + } +}); + +/** + * Directive for presenting an ON-OFF switch for checkbox. The directive expects the value to be string 'true' or 'false', not boolean true/false + * This directive provides some additional capabilities to the default onoffswitch such as: + * + * - Dynamic values for id and name attributes. Useful if you need to use this directive inside a ng-repeat + * - Specific scope to specify the value. Instead of just true or false. + * + * Usage: + */ +module.directive('onoffswitchstring', function() { + return { + restrict: "EA", + replace: true, + scope: { + name: '=', + id: '=', + value: '=', + ngModel: '=', + ngDisabled: '=', + kcOnText: '@onText', + kcOffText: '@offText' + }, + // TODO - The same code acts differently when put into the templateURL. Find why and move the code there. + //templateUrl: "templates/kc-switch.html", + template: '
', + compile: function(element, attrs) { + + if (!attrs.onText) { attrs.onText = "ON"; } + if (!attrs.offText) { attrs.offText = "OFF"; } + + element.bind('keydown click', function(e){ + var code = e.keyCode || e.which; + if (code === 32 || code === 13) { + e.stopImmediatePropagation(); + e.preventDefault(); + $(e.target).find('input').click(); + } + }); + } + } +}); + +/** + * Directive for presenting an ON-OFF switch for checkbox. The directive expects the true-value or false-value to be string like 'true' or 'false', not boolean true/false. + * This directive provides some additional capabilities to the default onoffswitch such as: + * + * - Specific scope to specify the value. Instead of just 'true' or 'false' you can use any other values. For example: true-value="'foo'" false-value="'bar'" . + * But 'true'/'false' are defaults if true-value and false-value are not specified + * + * Usage: + */ +module.directive('onoffswitchvalue', function() { + return { + restrict: "EA", + replace: true, + scope: { + name: '@', + id: '@', + trueValue: '@', + falseValue: '@', + ngModel: '=', + ngDisabled: '=', + kcOnText: '@onText', + kcOffText: '@offText' + }, + // TODO - The same code acts differently when put into the templateURL. Find why and move the code there. + //templateUrl: "templates/kc-switch.html", + template: "
", + compile: function(element, attrs) { + /* + We don't want to propagate basic attributes to the root element of directive. Id should be passed to the + input element only to achieve proper label binding (and validity). + */ + element.removeAttr('name'); + element.removeAttr('id'); + + if (!attrs.trueValue) { attrs.trueValue = "'true'"; } + if (!attrs.falseValue) { attrs.falseValue = "'false'"; } + + if (!attrs.onText) { attrs.onText = "ON"; } + if (!attrs.offText) { attrs.offText = "OFF"; } + + element.bind('keydown', function(e){ + var code = e.keyCode || e.which; + if (code === 32 || code === 13) { + e.stopImmediatePropagation(); + e.preventDefault(); + $(e.target).find('input').click(); + } + }); + } + } +}); + +module.directive('kcInput', function() { + var d = { + scope : true, + replace : false, + link : function(scope, element, attrs) { + var form = element.children('form'); + var label = element.children('label'); + var input = element.children('input'); + + var id = form.attr('name') + '.' + input.attr('name'); + + element.attr('class', 'control-group'); + + label.attr('class', 'control-label'); + label.attr('for', id); + + input.wrap('
'); + input.attr('id', id); + + if (!input.attr('placeHolder')) { + input.attr('placeHolder', label.text()); + } + + if (input.attr('required')) { + label.append(' *'); + } + } + }; + return d; +}); + +module.directive('kcEnter', function() { + return function(scope, element, attrs) { + element.bind("keydown keypress", function(event) { + if (event.which === 13) { + scope.$apply(function() { + scope.$eval(attrs.kcEnter); + }); + + event.preventDefault(); + } + }); + }; +}); + +// Don't allow URI reserved characters +module.directive('kcNoReservedChars', function (Notifications, $translate) { + return function($scope, element) { + element.bind("keypress", function(event) { + var keyPressed = String.fromCharCode(event.which || event.keyCode || 0); + + // ] and ' can not be used inside a character set on POSIX and GNU + if (keyPressed.match('[:/?#[@!$&()*+,;=]') || keyPressed === ']' || keyPressed === '\'') { + event.preventDefault(); + $scope.$apply(function() { + Notifications.warn($translate.instant('key-not-allowed-here', {character: keyPressed})); + }); + } + }); + }; +}); + +module.directive('kcSave', function ($compile, $timeout, Notifications) { + var clickDelay = 500; // 500 ms + + return { + restrict: 'A', + link: function ($scope, elem, attr, ctrl) { + elem.addClass("btn btn-primary"); + elem.attr("type","submit"); + + var disabled = false; + elem.on('click', function(evt) { + if ($scope.hasOwnProperty("changed") && !$scope.changed) return; + + // KEYCLOAK-4121: Prevent double form submission + if (disabled) { + evt.preventDefault(); + evt.stopImmediatePropagation(); + return; + } else { + disabled = true; + $timeout(function () { disabled = false; }, clickDelay, false); + } + + $scope.$apply(function() { + var form = elem.closest('form'); + if (form && form.attr('name')) { + var ngValid = form.find('.ng-valid'); + if ($scope[form.attr('name')].$valid) { + //ngValid.removeClass('error'); + ngValid.parent().removeClass('has-error'); + $scope['save'](); + } else { + Notifications.error("Missing or invalid field(s). Please verify the fields in red.") + //ngValid.removeClass('error'); + ngValid.parent().removeClass('has-error'); + + var ngInvalid = form.find('.ng-invalid'); + //ngInvalid.addClass('error'); + ngInvalid.parent().addClass('has-error'); + } + } + }); + }) + } + } +}); + +module.directive('kcReset', function ($compile, Notifications) { + return { + restrict: 'A', + link: function ($scope, elem, attr, ctrl) { + elem.addClass("btn btn-default"); + elem.attr("type","submit"); + elem.bind('click', function() { + $scope.$apply(function() { + var form = elem.closest('form'); + if (form && form.attr('name')) { + form.find('.ng-valid').removeClass('error'); + form.find('.ng-invalid').removeClass('error'); + $scope['reset'](); + } + }) + }) + } + } +}); + +module.directive('kcCancel', function ($compile, Notifications) { + return { + restrict: 'A', + link: function ($scope, elem, attr, ctrl) { + elem.addClass("btn btn-default"); + elem.attr("type","submit"); + } + } +}); + +module.directive('kcDelete', function ($compile, Notifications) { + return { + restrict: 'A', + link: function ($scope, elem, attr, ctrl) { + elem.addClass("btn btn-danger"); + elem.attr("type","submit"); + } + } +}); + + +module.directive('kcDropdown', function ($compile, Notifications) { + return { + scope: { + kcOptions: '=', + kcModel: '=', + id: "=", + kcPlaceholder: '@' + }, + restrict: 'EA', + replace: true, + templateUrl: resourceUrl + '/templates/kc-select.html', + link: function(scope, element, attr) { + scope.updateModel = function(item) { + scope.kcModel = item; + }; + } + } +}); + +module.directive('kcReadOnly', function() { + var disabled = {}; + + var d = { + replace : false, + link : function(scope, element, attrs) { + var disable = function(i, e) { + if (!e.disabled) { + disabled[e.tagName + i] = true; + e.disabled = true; + } + } + + var enable = function(i, e) { + if (disabled[e.tagName + i]) { + e.disabled = false; + delete disabled[i]; + } + } + + var filterIgnored = function(i, e){ + return !e.attributes['kc-read-only-ignore']; + } + + scope.$watch(attrs.kcReadOnly, function(readOnly) { + if (readOnly) { + element.find('input').filter(filterIgnored).each(disable); + element.find('button').filter(filterIgnored).each(disable); + element.find('select').filter(filterIgnored).each(disable); + element.find('textarea').filter(filterIgnored).each(disable); + } else { + element.find('input').filter(filterIgnored).each(enable); + element.find('input').filter(filterIgnored).each(enable); + element.find('button').filter(filterIgnored).each(enable); + element.find('select').filter(filterIgnored).each(enable); + element.find('textarea').filter(filterIgnored).each(enable); + } + }); + } + }; + return d; +}); + +module.directive('kcMenu', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/kc-menu.html' + } +}); + +module.directive('kcTabsRealm', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/kc-tabs-realm.html' + } +}); + +module.directive('kcTabsAuthentication', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/kc-tabs-authentication.html' + } +}); + +module.directive('kcTabsRole', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/kc-tabs-role.html' + } +}); + +module.directive('kcTabsClientRole', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/kc-tabs-client-role.html' + } +}); + +module.directive('kcTabsUser', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/kc-tabs-user.html' + } +}); + +module.directive('kcTabsUsers', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/kc-tabs-users.html' + } +}); + +module.directive('kcTabsClients', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/kc-tabs-clients.html' + } +}); + +module.directive('kcTabsGroup', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/kc-tabs-group.html' + } +}); + +module.directive('kcTabsGroupList', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/kc-tabs-group-list.html' + } +}); + +module.directive('kcTabsClient', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/kc-tabs-client.html' + } +}); + +module.directive('kcTabsClientScope', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/kc-tabs-client-scope.html' + } +}); + +module.directive('kcNavigationUser', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/kc-navigation-user.html' + } +}); + +module.directive('kcTabsIdentityProvider', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/kc-tabs-identity-provider.html' + } +}); + +module.directive('kcTabsUserFederation', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/kc-tabs-user-federation.html' + } +}); + +module.directive('kcTabsLdap', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/kc-tabs-ldap.html' + } +}); + +module.controller('RoleSelectorModalCtrl', function($scope, realm, config, configName, RealmRoles, Client, ClientRole, $modalInstance) { + $scope.selectedRealmRole = { + role: undefined + }; + $scope.selectedClientRole = { + role: undefined + }; + $scope.client = { + selected: undefined + }; + + $scope.selectRealmRole = function() { + config[configName] = $scope.selectedRealmRole.role.name; + $modalInstance.close(); + } + + $scope.selectClientRole = function() { + config[configName] = $scope.selectedClient.clientId + "." + $scope.selectedClientRole.role.name; + $modalInstance.close(); + } + + $scope.cancel = function() { + $modalInstance.dismiss(); + } + + clientSelectControl($scope, realm.realm, Client); + + $scope.selectedClient = null; + + $scope.changeClient = function(client) { + $scope.selectedClient = client; + if (!client || !client.id) { + $scope.selectedClient = null; + return; + } + if ($scope.selectedClient) { + ClientRole.query({realm: realm.realm, client: $scope.selectedClient.id}, function (data) { + $scope.clientRoles = data; + }); + } else { + console.log('selected client was null'); + $scope.clientRoles = null; + } + + $scope.selectedClient = client; + } + + RealmRoles.query({realm: realm.realm}, function(data) { + $scope.realmRoles = data; + }) +}); + +module.controller('GroupSelectorModalCtrl', function($scope, $q, realm, config, configName, GroupsCount, Groups, Group, GroupChildren, Notifications, Dialog, ComponentUtils, $modalInstance, $translate) { + $scope.realm = realm; + $scope.groupList = [ + { + "id" : "realm", + "name": $translate.instant('groups'), + "subGroups" : [] + } + ]; + $scope.groupSelector = { + searchCriteria: undefined, + currentPage: 1, + pageSize: 20, + numberOfPages: 1 + }; + $scope.groupSelector.currentPageInput = $scope.groupSelector.currentPage; + + var refreshGroups = function (search) { + console.log('refreshGroups'); + $scope.groupSelector.currentPageInput = $scope.groupSelector.currentPage; + + var first = ($scope.groupSelector.currentPage * $scope.groupSelector.pageSize) - $scope.groupSelector.pageSize; + console.log('first:' + first); + var queryParams = { + realm : realm.realm, + first : first, + max : $scope.groupSelector.pageSize + }; + var countParams = { + realm : realm.realm, + top : 'true' + }; + + if(angular.isDefined(search) && search !== '') { + queryParams.search = search; + countParams.search = search; + } + + var promiseGetGroups = $q.defer(); + Groups.query(queryParams, function(entry) { + promiseGetGroups.resolve(entry); + }, function() { + promiseGetGroups.reject($translate.instant('group.fetch.fail', {params: queryParams})); + }); + promiseGetGroups.promise.then(function(groups) { + $scope.groupList = [ + { + "id" : "realm", + "name": $translate.instant('groups'), + "subGroups": ComponentUtils.sortGroups('name', groups) + } + ]; + if (angular.isDefined(search) && search !== '') { + // Add highlight for concrete text match + setTimeout(function () { + document.querySelectorAll('span').forEach(function (element) { + if (element.textContent.indexOf(search) != -1) { + angular.element(element).addClass('highlight'); + } + }); + }, 500); + } + }, function (failed) { + Notifications.error(failed); + }); + + var promiseCount = $q.defer(); + console.log('countParams: realm[' + countParams.realm); + GroupsCount.query(countParams, function(entry) { + promiseCount.resolve(entry); + }, function() { + promiseCount.reject($translate.instant('group.fetch.fail', {params: countParams})); + }); + promiseCount.promise.then(function(entry) { + if(angular.isDefined(entry.count) && entry.count > $scope.groupSelector.pageSize) { + $scope.groupSelector.numberOfPages = Math.ceil(entry.count/$scope.groupSelector.pageSize); + } else { + $scope.groupSelector.numberOfPages = 1; + } + }, function (failed) { + Notifications.error(failed); + }); + }; + + refreshGroups(); + + $scope.$watch('groupSelector.currentPage', function(newValue, oldValue) { + if(parseInt(newValue, 10) !== oldValue) { + refreshGroups($scope.groupSelector.searchCriteria); + } + }); + + $scope.clearSearch = function() { + $scope.groupSelector.searchCriteria = ''; + if (parseInt($scope.groupSelector.currentPage, 10) === 1) { + refreshGroups(); + } else { + $scope.groupSelector.currentPage = 1; + } + }; + + $scope.searchGroup = function() { + if (parseInt($scope.groupSelector.currentPage, 10) === 1) { + refreshGroups($scope.groupSelector.searchCriteria); + } else { + $scope.groupSelector.currentPage = 1; + } + }; + + $scope.selectGroup = function(selected) { + if(!selected || selected.id === "realm") return; + + config[configName] = selected.path; + $modalInstance.close(); + } + + $scope.edit = $scope.selectGroup; + + $scope.cancel = function() { + $modalInstance.dismiss(); + } + + var isLeaf = function(node) { + return node.id !== "realm" && (!node.subGroups || node.subGroups.length === 0); + }; + + $scope.getGroupClass = function(node) { + if (node.id === "realm") { + return 'pficon pficon-users'; + } + if (isLeaf(node)) { + return 'normal'; + } + if (node.subGroups.length && node.collapsed) return 'collapsed'; + if (node.subGroups.length && !node.collapsed) return 'expanded'; + return 'collapsed'; + + }; + + $scope.getSelectedClass = function(node) { + if (node.selected) { + return 'selected'; + } + return undefined; + } +}); + + +module.controller('ProviderConfigCtrl', function ($modal, $scope, $route, ComponentUtils, Client) { + clientSelectControl($scope, $route.current.params.realm, Client); + $scope.fileNames = {}; + $scope.newMapEntries = {}; + var cachedMaps = {}; + var cachedParsedMaps = {}; + var focusMapValueId = null; + + // KEYCLOAK-4463 + $scope.initEditor = function(editor){ + editor.$blockScrolling = Infinity; // suppress warning message + }; + + $scope.initSelectedClient = function(configName, config) { + if(config[configName]) { + $scope.selectedClient = null; + Client.query({realm: $route.current.params.realm, search: false, clientId: config[configName], max: 1}, function(data) { + if(data.length > 0) { + $scope.selectedClient = angular.copy(data[0]); + $scope.selectedClient.text = $scope.selectedClient.clientId; + } + }); + } + } + + $scope.openRoleSelector = function (configName, config) { + $modal.open({ + templateUrl: resourceUrl + '/partials/modal/role-selector.html', + controller: 'RoleSelectorModalCtrl', + resolve: { + realm: function () { + return $scope.realm; + }, + config: function () { + return config; + }, + configName: function () { + return configName; + } + } + }) + } + + $scope.openGroupSelector = function (configName, config) { + $modal.open({ + templateUrl: resourceUrl + '/partials/modal/group-selector.html', + controller: 'GroupSelectorModalCtrl', + resolve: { + realm: function () { + return $scope.realm; + }, + config: function () { + return config; + }, + configName: function () { + return configName; + } + } + }) + } + + $scope.changeClient = function(configName, config, client, multivalued) { + if (!client || !client.id) { + config[configName] = null; + $scope.selectedClient = null; + return; + } + $scope.selectedClient = client; + if (multivalued) { + config[configName][0] = client.clientId; + } else { + config[configName] = client.clientId; + } + }; + + ComponentUtils.convertAllMultivaluedStringValuesToList($scope.properties, $scope.config); + + ComponentUtils.addLastEmptyValueToMultivaluedLists($scope.properties, $scope.config); + + $scope.addValueToMultivalued = function(optionName) { + var configProperty = $scope.config[optionName]; + var lastIndex = configProperty.length - 1; + var lastValue = configProperty[lastIndex]; + console.log("Option=" + optionName + ", lastIndex=" + lastIndex + ", lastValue=" + lastValue); + + if (lastValue.length > 0) { + configProperty.push(''); + } + } + + $scope.deleteValueFromMultivalued = function(optionName, index) { + $scope.config[optionName].splice(index, 1); + } + + $scope.uploadFile = function($files, optionName, config) { + var reader = new FileReader(); + reader.onload = function(e) { + $scope.$apply(function() { + config[optionName][0] = e.target.result; + }); + }; + reader.readAsText($files[0]); + $scope.fileNames[optionName] = $files[0].name; + } + + $scope.addMapEntry = function(optionName) { + $scope.removeMapEntry(optionName, $scope.newMapEntries[optionName].key) + + var parsedMap = JSON.parse($scope.config[optionName]); + parsedMap.push($scope.newMapEntries[optionName]); + $scope.config[optionName] = JSON.stringify(parsedMap); + + delete $scope.newMapEntries[optionName]; + } + + $scope.removeMapEntry = function(optionName, key) { + var parsedMap = JSON.parse($scope.config[optionName]); + + for(var i = parsedMap.length - 1; i >= 0; i--) { + if(parsedMap[i]['key'] === key) { + parsedMap.splice(i, 1); + } + } + + $scope.config[optionName] = JSON.stringify(parsedMap); + } + + $scope.updateMapEntry = function(optionName, key, value) { + var parsedMap = JSON.parse($scope.config[optionName]); + + for(var i = parsedMap.length - 1; i >= 0; i--) { + if(parsedMap[i]['key'] === key) { + parsedMap[i]['value'] = value; + } + } + $scope.config[optionName] = JSON.stringify(parsedMap); + + focusMapValueId = "mapValue-" + optionName + "-" + key; + } + + $scope.jsonParseMap = function(optionName) { + + if(cachedParsedMaps[optionName] === undefined) { + cachedMaps[optionName] = "[]"; + cachedParsedMaps[optionName] = []; + + if(!$scope.config.hasOwnProperty(optionName)){ + $scope.config[optionName]=cachedMaps[optionName]; + } else { + cachedMaps[optionName] = $scope.config[optionName]; + cachedParsedMaps[optionName] = JSON.parse(cachedMaps[optionName]); + } + } + + var mapChanged = $scope.config[optionName] !== cachedMaps[optionName]; + + if(mapChanged){ + cachedMaps[optionName] = $scope.config[optionName]; + cachedParsedMaps[optionName] = JSON.parse(cachedMaps[optionName]); + } + + if(!mapChanged && focusMapValueId !== null){ + document.getElementById(focusMapValueId).focus(); + focusMapValueId = null; + } + + return cachedParsedMaps[optionName]; + } +}); + +module.directive('kcProviderConfig', function ($modal) { + return { + scope: { + config: '=', + properties: '=', + realm: '=', + clients: '=', + configName: '=' + }, + restrict: 'E', + replace: true, + controller: 'ProviderConfigCtrl', + templateUrl: resourceUrl + '/templates/kc-provider-config.html' + } +}); + +module.controller('ComponentRoleSelectorModalCtrl', function($scope, realm, config, configName, RealmRoles, Client, ClientRole, $modalInstance) { + $scope.selectedRealmRole = { + role: undefined + }; + $scope.selectedClientRole = { + role: undefined + }; + $scope.client = { + selected: undefined + }; + + $scope.selectRealmRole = function() { + config[configName][0] = $scope.selectedRealmRole.role.name; + $modalInstance.close(); + } + + $scope.selectClientRole = function() { + config[configName][0] = $scope.client.selected.clientId + "." + $scope.selectedClientRole.role.name; + $modalInstance.close(); + } + + $scope.cancel = function() { + $modalInstance.dismiss(); + } + + $scope.changeClient = function() { + if ($scope.client.selected) { + ClientRole.query({realm: realm.realm, client: $scope.client.selected.id}, function (data) { + $scope.clientRoles = data; + }); + } else { + console.log('selected client was null'); + $scope.clientRoles = null; + } + + } + RealmRoles.query({realm: realm.realm}, function(data) { + $scope.realmRoles = data; + }) + Client.query({realm: realm.realm}, function(data) { + $scope.clients = data; + if (data.length > 0) { + $scope.client.selected = data[0]; + $scope.changeClient(); + } + }) +}); + +module.controller('ComponentConfigCtrl', function ($modal, $scope, $route, Client) { + + $scope.initSelectedClient = function(configName, config) { + if(config[configName]) { + $scope.selectedClient = null; + Client.query({realm: $route.current.params.realm, search: false, clientId: config[configName], max: 1}, function(data) { + if(data.length > 0) { + $scope.selectedClient = angular.copy(data[0]); + $scope.selectedClient.text = $scope.selectedClient.clientId; + } + }); + } + } + + $scope.changeClient = function(configName, config, client) { + if (!client || !client.id) { + config[configName] = null; + $scope.selectedClient = null; + return; + } + $scope.selectedClient = client; + config[configName] = client.clientId; + }; + + + $scope.openRoleSelector = function (configName, config) { + $modal.open({ + templateUrl: resourceUrl + '/partials/modal/component-role-selector.html', + controller: 'ComponentRoleSelectorModalCtrl', + resolve: { + realm: function () { + return $scope.realm; + }, + config: function () { + return config; + }, + configName: function () { + return configName; + } + } + }) + } +}); +module.directive('kcComponentConfig', function ($modal) { + return { + scope: { + config: '=', + properties: '=', + realm: '=', + clients: '=', + configName: '=' + }, + restrict: 'E', + replace: true, + controller: 'ComponentConfigCtrl', + templateUrl: resourceUrl + '/templates/kc-component-config.html' + } +}); + +/* +* Used to select the element (invoke $(elem).select()) on specified action list. +* Usages kc-select-action="click mouseover" +* When used in the textarea element, this will select/highlight the textarea content on specified action (i.e. click). +*/ +module.directive('kcSelectAction', function ($compile, Notifications) { + return { + restrict: 'A', + compile: function (elem, attrs) { + + var events = attrs.kcSelectAction.split(" "); + + for(var i=0; i < events.length; i++){ + + elem.bind(events[i], function(){ + elem.select(); + }); + } + } + } +}); + +module.filter('remove', function() { + return function(input, remove, attribute) { + if (!input || !remove) { + return input; + } + + var out = []; + for ( var i = 0; i < input.length; i++) { + var e = input[i]; + + if (Array.isArray(remove)) { + for (var j = 0; j < remove.length; j++) { + if (attribute) { + if (remove[j][attribute] == e[attribute]) { + e = null; + break; + } + } else { + if (remove[j] == e) { + e = null; + break; + } + } + } + } else { + if (attribute) { + if (remove[attribute] == e[attribute]) { + e = null; + } + } else { + if (remove == e) { + e = null; + } + } + } + + if (e != null) { + out.push(e); + } + } + + return out; + }; +}); + +module.filter('capitalize', function() { + return function(input) { + if (!input) { + return; + } + var splittedWords = input.split(/\s+/); + for (var i=0; i'); + + $compile(label)(scope); + } + }; +}); + +module.directive( 'kcOpen', function ( $location ) { + return function ( scope, element, attrs ) { + var path; + + attrs.$observe( 'kcOpen', function (val) { + path = val; + }); + + element.bind( 'click', function () { + scope.$apply( function () { + $location.path(path); + }); + }); + }; +}); + +module.directive('kcOnReadFile', function ($parse) { + console.debug('kcOnReadFile'); + return { + restrict: 'A', + scope: false, + link: function(scope, element, attrs) { + var fn = $parse(attrs.kcOnReadFile); + + element.on('change', function(onChangeEvent) { + var reader = new FileReader(); + + reader.onload = function(onLoadEvent) { + scope.$apply(function() { + fn(scope, {$fileContent:onLoadEvent.target.result}); + }); + }; + + reader.readAsText((onChangeEvent.srcElement || onChangeEvent.target).files[0]); + }); + } + }; +}); + +module.controller('PagingCtrl', function ($scope) { + $scope.currentPageInput = 1; + + $scope.firstPage = function() { + if (!$scope.hasPrevious()) return; + $scope.currentPage = 1; + $scope.currentPageInput = 1; + }; + + $scope.lastPage = function() { + if (!$scope.hasNext()) return; + $scope.currentPage = $scope.numberOfPages; + $scope.currentPageInput = $scope.numberOfPages; + }; + + $scope.previousPage = function() { + if (!$scope.hasPrevious()) return; + $scope.currentPage--; + $scope.currentPageInput = $scope.currentPage; + }; + + $scope.nextPage = function() { + if (!$scope.hasNext()) return; + $scope.currentPage++; + $scope.currentPageInput = $scope.currentPage; + }; + + $scope.hasNext = function() { + return $scope.currentPage < $scope.numberOfPages; + }; + + $scope.hasPrevious = function() { + return $scope.currentPage > 1; + }; +}); + +// Provides a component for injection with utility methods for manipulating strings +module.factory('KcStrings', function () { + var instance = {}; + + // some IE versions do not support string.endsWith method, this method should be used as an alternative for cross-browser compatibility + instance.endsWith = function(source, suffix) { + return source.indexOf(suffix, source.length - suffix.length) !== -1; + }; + + return instance; +}); + +module.directive('kcPaging', function () { + return { + scope: { + currentPage: '=', + currentPageInput: '=', + numberOfPages: '=' + }, + restrict: 'E', + replace: true, + controller: 'PagingCtrl', + templateUrl: resourceUrl + '/templates/kc-paging.html' + } +}); + +// Tests the page number input from currentPageInput to see +// if it represents a valid page. If so, the current page is changed. +module.directive('kcValidPage', function() { + return { + require: 'ngModel', + link: function(scope, element, attrs, ctrl) { + ctrl.$validators.inRange = function(modelValue, viewValue) { + if (viewValue >= 1 && viewValue <= scope.numberOfPages) { + scope.currentPage = viewValue; + } + + return true; + } + } + } +}); + +// Directive to parse/format strings into numbers +module.directive('stringToNumber', function() { + return { + require: 'ngModel', + link: function(scope, element, attrs, ngModel) { + ngModel.$parsers.push(function(value) { + return (typeof value === 'undefined' || value === null)? '' : '' + value; + }); + ngModel.$formatters.push(function(value) { + return parseFloat(value); + }); + } + }; +}); + +// filter used for paged tables +module.filter('startFrom', function () { + return function (input, start) { + if (input) { + start = +start; + return input.slice(start); + } + return []; + }; +}); + + +module.directive('kcPassword', function ($compile, Notifications) { + return { + restrict: 'A', + link: function ($scope, elem, attr, ctrl) { + function toggleMask(evt) { + if(elem.hasClass('password-conceal')) { + view(); + } else { + conceal(); + } + } + + function view() { + elem.removeClass('password-conceal'); + + var t = elem.next().children().first(); + t.addClass('fa-eye-slash'); + t.removeClass('fa-eye'); + } + + function conceal() { + elem.addClass('password-conceal'); + + var t = elem.next().children().first(); + t.removeClass('fa-eye-slash'); + t.addClass('fa-eye'); + } + + elem.addClass("password-conceal"); + elem.attr("type","text"); + elem.attr("autocomplete", "off"); + + var p = elem.parent(); + + var inputGroup = $('
'); + var eye = $('') + .on('click', toggleMask); + + $scope.$watch(attr.ngModel, function(v) { + if (v && v == '**********') { + elem.next().addClass('disabled') + } else if (v && v.indexOf('${v') == 0) { + elem.next().addClass('disabled') + view(); + } else { + elem.next().removeClass('disabled') + } + }) + + elem.detach().appendTo(inputGroup); + inputGroup.append(eye); + p.append(inputGroup); + } + } +}); + + +module.filter('resolveClientRootUrl', function() { + return function(input) { + if (!input) { + return; + } + return input.replace("${authBaseUrl}", authServerUrl).replace("${authAdminUrl}", authUrl); + }; +}); diff --git a/keycloak-themes/base/admin/resources/js/authz/authz-app.js b/keycloak-themes/base/admin/resources/js/authz/authz-app.js new file mode 100644 index 0000000..2d18049 --- /dev/null +++ b/keycloak-themes/base/admin/resources/js/authz/authz-app.js @@ -0,0 +1,569 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2016 Red Hat, Inc., and individual contributors + * as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module.config(['$routeProvider', function ($routeProvider) { + $routeProvider + .when('/realms/:realm/authz', { + templateUrl: resourceUrl + '/partials/authz/resource-server-list.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + } + }, + controller: 'ResourceServerCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/create', { + templateUrl: resourceUrl + '/partials/authz/resource-server-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + clients: function (ClientListLoader) { + return ClientListLoader(); + } + }, + controller: 'ResourceServerDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server', { + templateUrl: resourceUrl + '/partials/authz/resource-server-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + clients: function (ClientListLoader) { + return ClientListLoader(); + }, + serverInfo: function (ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller: 'ResourceServerDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/export-settings', { + templateUrl: resourceUrl + '/partials/authz/resource-server-export-settings.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + clients: function (ClientListLoader) { + return ClientListLoader(); + }, + serverInfo: function (ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller: 'ResourceServerDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/evaluate', { + templateUrl: resourceUrl + '/partials/authz/policy/resource-server-policy-evaluate.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + clients: function (ClientListLoader) { + return ClientListLoader(); + }, + roles: function (RoleListLoader) { + return new RoleListLoader(); + } + }, + controller: 'PolicyEvaluateCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/evaluate/result', { + templateUrl: resourceUrl + '/partials/authz/policy/resource-server-policy-evaluate-result.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + }, + controller: 'PolicyEvaluateCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/resource', { + templateUrl: resourceUrl + '/partials/authz/resource-server-resource-list.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerResourceCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/resource/create', { + templateUrl: resourceUrl + '/partials/authz/resource-server-resource-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerResourceDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/resource/:rsrid', { + templateUrl: resourceUrl + '/partials/authz/resource-server-resource-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerResourceDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/scope', { + templateUrl: resourceUrl + '/partials/authz/resource-server-scope-list.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerScopeCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/scope/create', { + templateUrl: resourceUrl + '/partials/authz/resource-server-scope-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerScopeDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/scope/:id', { + templateUrl: resourceUrl + '/partials/authz/resource-server-scope-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerScopeDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/permission', { + templateUrl: resourceUrl + '/partials/authz/permission/resource-server-permission-list.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPermissionCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy', { + templateUrl: resourceUrl + '/partials/authz/policy/resource-server-policy-list.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/permission/resource/create', { + templateUrl: resourceUrl + '/partials/authz/permission/provider/resource-server-policy-resource-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyResourceDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/permission/resource/:id', { + templateUrl: resourceUrl + '/partials/authz/permission/provider/resource-server-policy-resource-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyResourceDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/permission/scope/create', { + templateUrl: resourceUrl + '/partials/authz/permission/provider/resource-server-policy-scope-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyScopeDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/permission/scope/:id', { + templateUrl: resourceUrl + '/partials/authz/permission/provider/resource-server-policy-scope-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyScopeDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/user/create', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-user-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyUserDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/user/:id', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-user-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyUserDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/client/create', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-client-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyClientDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/client/:id', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-client-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyClientDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/role/create', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-role-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyRoleDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/role/:id', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-role-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyRoleDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/group/create', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-group-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyGroupDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/group/:id', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-group-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyGroupDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/js/create', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-js-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller: 'ResourceServerPolicyJSDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/js/:id', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-js-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + serverInfo : function(ServerInfoLoader) { + return ServerInfoLoader(); + } + }, + controller: 'ResourceServerPolicyJSDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/time/create', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-time-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyTimeDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/time/:id', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-time-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyTimeDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/aggregate/create', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyAggregateDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/aggregate/:id', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyAggregateDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/client-scope/create', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-client-scope-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyClientScopeDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/client-scope/:id', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-client-scope-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyClientScopeDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/regex/create', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-regex-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyRegexDetailCtrl' + }).when('/realms/:realm/clients/:client/authz/resource-server/policy/regex/:id', { + templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-regex-detail.html', + resolve: { + realm: function (RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller: 'ResourceServerPolicyRegexDetailCtrl' + }).when('/realms/:realm/roles/:role/permissions', { + templateUrl : resourceUrl + '/partials/authz/mgmt/realm-role-permissions.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + role : function(RoleLoader) { + return RoleLoader(); + } + }, + controller : 'RealmRolePermissionsCtrl' + }).when('/realms/:realm/clients/:client/roles/:role/permissions', { + templateUrl : resourceUrl + '/partials/authz/mgmt/client-role-permissions.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + }, + role : function(RoleLoader) { + return RoleLoader(); + } + }, + controller : 'ClientRolePermissionsCtrl' + }).when('/realms/:realm/users-permissions', { + templateUrl : resourceUrl + '/partials/authz/mgmt/users-permissions.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + } + }, + controller : 'UsersPermissionsCtrl' + }) + .when('/realms/:realm/clients/:client/permissions', { + templateUrl : resourceUrl + '/partials/authz/mgmt/client-permissions.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + client : function(ClientLoader) { + return ClientLoader(); + } + }, + controller : 'ClientPermissionsCtrl' + }) + .when('/realms/:realm/groups/:group/permissions', { + templateUrl : resourceUrl + '/partials/authz/mgmt/group-permissions.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + group : function(GroupLoader) { + return GroupLoader(); + } + }, + controller : 'GroupPermissionsCtrl' + }) + .when('/realms/:realm/identity-provider-settings/provider/:provider_id/:alias/permissions', { + templateUrl : function(params){ return resourceUrl + '/partials/authz/mgmt/broker-permissions.html'; }, + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + identityProvider : function(IdentityProviderLoader) { + return IdentityProviderLoader(); + } + }, + controller : 'IdentityProviderPermissionCtrl' + }) + ; +}]); + +module.directive('kcTabsResourceServer', function () { + return { + scope: true, + restrict: 'E', + replace: true, + templateUrl: resourceUrl + '/templates/authz/kc-tabs-resource-server.html' + } +}); + +module.filter('unique', function () { + + return function (items, filterOn) { + + if (filterOn === false) { + return items; + } + + if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) { + var hashCheck = {}, newItems = []; + + var extractValueToCompare = function (item) { + if (angular.isObject(item) && angular.isString(filterOn)) { + return item[filterOn]; + } else { + return item; + } + }; + + angular.forEach(items, function (item) { + var valueToCheck, isDuplicate = false; + + for (var i = 0; i < newItems.length; i++) { + if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) { + isDuplicate = true; + break; + } + } + if (!isDuplicate) { + newItems.push(item); + } + + }); + items = newItems; + } + return items; + }; +}); + +module.filter('toCamelCase', function () { + return function (input) { + input = input || ''; + return input.replace(/\w\S*/g, function (txt) { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); + }); + }; +}) \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/js/authz/authz-controller.js b/keycloak-themes/base/admin/resources/js/authz/authz-controller.js new file mode 100644 index 0000000..1f76afe --- /dev/null +++ b/keycloak-themes/base/admin/resources/js/authz/authz-controller.js @@ -0,0 +1,3034 @@ +module.controller('ResourceServerCtrl', function($scope, realm, ResourceServer) { + $scope.realm = realm; + + ResourceServer.query({realm : realm.realm}, function (data) { + $scope.servers = data; + }); +}); + +module.controller('ResourceServerDetailCtrl', function($scope, $http, $route, $location, $upload, $modal, realm, ResourceServer, client, AuthzDialog, Notifications) { + $scope.realm = realm; + $scope.client = client; + + ResourceServer.get({ + realm : $route.current.params.realm, + client : client.id + }, function(data) { + $scope.server = angular.copy(data); + $scope.changed = false; + + $scope.$watch('server', function() { + if (!angular.equals($scope.server, data)) { + $scope.changed = true; + } + }, true); + + $scope.save = function() { + ResourceServer.update({realm : realm.realm, client : $scope.server.clientId}, $scope.server, function() { + $route.reload(); + Notifications.success("The resource server has been created."); + }); + } + + $scope.reset = function() { + $route.reload(); + } + + $scope.export = function() { + $scope.exportSettings = true; + ResourceServer.settings({ + realm : $route.current.params.realm, + client : client.id + }, function(data) { + var tmp = angular.fromJson(data); + $scope.settings = angular.toJson(tmp, true); + }) + } + + $scope.downloadSettings = function() { + saveAs(new Blob([$scope.settings], { type: 'application/json' }), $scope.server.name + "-authz-config.json"); + } + + $scope.cancelExport = function() { + delete $scope.settings + } + + $scope.onFileSelect = function($fileContent) { + $scope.server = angular.copy(JSON.parse($fileContent)); + $scope.importing = true; + }; + + $scope.viewImportDetails = function() { + $modal.open({ + templateUrl: resourceUrl + '/partials/modal/view-object.html', + controller: 'ObjectModalCtrl', + resolve: { + object: function () { + return $scope.server; + } + } + }) + }; + + $scope.import = function () { + ResourceServer.import({realm : realm.realm, client : client.id}, $scope.server, function() { + $route.reload(); + Notifications.success("The resource server has been updated."); + }); + } + }); +}); + +var Resources = { + delete: function(ResourceServerResource, realm, client, $scope, AuthzDialog, $location, Notifications, $route) { + ResourceServerResource.permissions({ + realm : realm, + client : client.id, + rsrid : $scope.resource._id + }, function (permissions) { + var msg = ""; + + if (permissions.length > 0 && !$scope.deleteConsent) { + msg = "

This resource is referenced in some permissions:

"; + msg += "
    "; + for (i = 0; i < permissions.length; i++) { + msg+= "
  • " + permissions[i].name + "
  • "; + } + msg += "
"; + msg += "

If you remove this resource, the permissions above will be affected and will not be associated with this resource anymore.

"; + } + + AuthzDialog.confirmDeleteWithMsg($scope.resource.name, "Resource", msg, function() { + ResourceServerResource.delete({realm : realm, client : $scope.client.id, rsrid : $scope.resource._id}, null, function() { + $location.url("/realms/" + realm + "/clients/" + $scope.client.id + "/authz/resource-server/resource"); + $route.reload(); + Notifications.success("The resource has been deleted."); + }); + }); + }); + } +} + +var Policies = { + delete: function(service, realm, client, $scope, AuthzDialog, $location, Notifications, $route, isPermission) { + var msg = ""; + + service.dependentPolicies({ + realm : realm, + client : client.id, + id : $scope.policy.id + }, function (dependentPolicies) { + if (dependentPolicies.length > 0 && !$scope.deleteConsent) { + msg = "

This policy is being used by other policies:

"; + msg += "
    "; + for (i = 0; i < dependentPolicies.length; i++) { + msg+= "
  • " + dependentPolicies[i].name + "
  • "; + } + msg += "
"; + msg += "

If you remove this policy, the policies above will be affected and will not be associated with this policy anymore.

"; + } + + AuthzDialog.confirmDeleteWithMsg($scope.policy.name, isPermission ? "Permission" : "Policy", msg, function() { + service.delete({realm : realm, client : $scope.client.id, id : $scope.policy.id}, null, function() { + if (isPermission) { + $location.url("/realms/" + realm + "/clients/" + $scope.client.id + "/authz/resource-server/permission"); + Notifications.success("The permission has been deleted."); + } else { + $location.url("/realms/" + realm + "/clients/" + $scope.client.id + "/authz/resource-server/policy"); + Notifications.success("The policy has been deleted."); + } + $route.reload(); + }); + }); + }); + } +} + +module.controller('ResourceServerResourceCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerResource, client, AuthzDialog, Notifications, viewState) { + $scope.realm = realm; + $scope.client = client; + + $scope.query = { + realm: realm.realm, + client : client.id, + deep: false, + max : 20, + first : 0 + }; + + $scope.listSizes = [5, 10, 20]; + + ResourceServer.get({ + realm : $route.current.params.realm, + client : client.id + }, function(data) { + $scope.server = data; + + $scope.createPolicy = function(resource) { + viewState.state = {}; + viewState.state.previousUrl = '/realms/' + $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/resource'; + $location.path('/realms/' + $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/permission/resource/create').search({rsrid: resource._id}); + } + + $scope.searchQuery(); + }); + + $scope.firstPage = function() { + $scope.query.first = 0; + $scope.searchQuery(); + } + + $scope.previousPage = function() { + $scope.query.first -= parseInt($scope.query.max); + if ($scope.query.first < 0) { + $scope.query.first = 0; + } + $scope.searchQuery(); + } + + $scope.nextPage = function() { + $scope.query.first += parseInt($scope.query.max); + $scope.searchQuery(); + } + + $scope.searchQuery = function() { + $scope.searchLoaded = false; + + ResourceServerResource.query($scope.query, function(response) { + $scope.searchLoaded = true; + $scope.lastSearch = $scope.query.search; + $scope.resources = response; + if ($scope.detailsFilter) { + $scope.showDetails(); + } + }); + }; + + $scope.loadDetails = function (resource) { + if (resource.details) { + resource.details.loaded = !resource.details.loaded; + return; + } + + resource.details = {loaded: false}; + + ResourceServerResource.scopes({ + realm : $route.current.params.realm, + client : client.id, + rsrid : resource._id + }, function(response) { + resource.scopes = response; + ResourceServerResource.permissions({ + realm : $route.current.params.realm, + client : client.id, + rsrid : resource._id + }, function(response) { + resource.policies = response; + resource.details.loaded = true; + }); + }); + } + + $scope.showDetails = function(item, event) { + if (event.target.localName == 'a' || event.target.localName == 'button') { + return; + } + + if (item) { + $scope.loadDetails(item); + } else { + for (i = 0; i < $scope.resources.length; i++) { + $scope.loadDetails($scope.resources[i]); + } + } + }; + + $scope.delete = function(resource) { + $scope.resource = resource; + Resources.delete(ResourceServerResource, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route); + }; +}); + +module.controller('ResourceServerResourceDetailCtrl', function($scope, $http, $route, $location, realm, ResourceServer, client, ResourceServerResource, ResourceServerScope, AuthzDialog, Notifications) { + $scope.realm = realm; + $scope.client = client; + + $scope.scopesUiSelect = { + minimumInputLength: 1, + delay: 500, + allowClear: true, + query: function (query) { + var data = {results: []}; + if ('' == query.term.trim()) { + query.callback(data); + return; + } + $scope.query = { + realm: realm.realm, + client : client.id, + name: query.term.trim(), + deep: false, + max : 20, + first : 0 + }; + ResourceServerScope.query($scope.query, function(response) { + data.results = response; + query.callback(data); + }); + }, + formatResult: function(object, container, query) { + return object.name; + }, + formatSelection: function(object, container, query) { + return object.name; + } + }; + + var $instance = this; + + ResourceServer.get({ + realm : $route.current.params.realm, + client : client.id + }, function(data) { + $scope.server = data; + + var resourceId = $route.current.params.rsrid; + + if (!resourceId) { + $scope.create = true; + $scope.changed = false; + + var resource = {}; + resource.scopes = []; + resource.attributes = {}; + resource.uris = []; + + $scope.resource = angular.copy(resource); + + $scope.$watch('resource', function() { + if (!angular.equals($scope.resource, resource)) { + $scope.changed = true; + } + }, true); + + $scope.$watch('newUri', function() { + if ($scope.newUri && $scope.newUri.length > 0) { + $scope.changed = true; + } + }, true); + + $scope.save = function() { + if ($scope.newUri && $scope.newUri.length > 0) { + $scope.addUri(); + } + + for (i = 0; i < $scope.resource.scopes.length; i++) { + delete $scope.resource.scopes[i].text; + } + $instance.checkNameAvailability(function () { + ResourceServerResource.save({realm : realm.realm, client : $scope.client.id}, $scope.resource, function(data) { + $location.url("/realms/" + realm.realm + "/clients/" + $scope.client.id + "/authz/resource-server/resource/" + data._id); + Notifications.success("The resource has been created."); + }); + }); + } + + $scope.reset = function() { + $location.url("/realms/" + realm.realm + "/clients/" + $scope.client.id + "/authz/resource-server/resource/"); + } + } else { + ResourceServerResource.get({ + realm : $route.current.params.realm, + client : client.id, + rsrid : $route.current.params.rsrid, + }, function(data) { + if (!data.scopes) { + data.scopes = []; + } + + if (!data.attributes) { + data.attributes = {}; + } + + $scope.resource = angular.copy(data); + $scope.changed = false; + + $scope.originalResource = angular.copy($scope.resource); + + $scope.$watch('resource', function() { + if (!angular.equals($scope.resource, data)) { + $scope.changed = true; + } + }, true); + + $scope.$watch('newUri', function() { + if ($scope.newUri && $scope.newUri.length > 0) { + $scope.changed = true; + } + }, true); + + $scope.save = function() { + if ($scope.newUri && $scope.newUri.length > 0) { + $scope.addUri(); + } + + for (i = 0; i < $scope.resource.scopes.length; i++) { + delete $scope.resource.scopes[i].text; + } + + var keys = Object.keys($scope.resource.attributes); + + for (var k = 0; k < keys.length; k++) { + var key = keys[k]; + var value = $scope.resource.attributes[key]; + var values = value.toString().split(','); + + $scope.resource.attributes[key] = []; + + for (j = 0; j < values.length; j++) { + $scope.resource.attributes[key].push(values[j]); + } + } + $instance.checkNameAvailability(function () { + ResourceServerResource.update({realm : realm.realm, client : $scope.client.id, rsrid : $scope.resource._id}, $scope.resource, function() { + $route.reload(); + Notifications.success("The resource has been updated."); + }); + }); + } + + $scope.remove = function() { + Resources.delete(ResourceServerResource, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route); + } + + $scope.reset = function() { + $route.reload(); + } + }); + } + }); + + $scope.checkNewNameAvailability = function () { + $instance.checkNameAvailability(function () {}); + } + + this.checkNameAvailability = function (onSuccess) { + if (!$scope.resource.name || $scope.resource.name.trim().length == 0) { + return; + } + ResourceServerResource.search({ + realm : $route.current.params.realm, + client : client.id, + rsrid : $route.current.params.rsrid, + name: $scope.resource.name + }, function(data) { + if (data && data._id && data._id != $scope.resource._id) { + Notifications.error("Name already in use by another resource, please choose another one."); + } else { + onSuccess(); + } + }); + } + + $scope.addAttribute = function() { + $scope.resource.attributes[$scope.newAttribute.key] = $scope.newAttribute.value; + delete $scope.newAttribute; + } + + $scope.removeAttribute = function(key) { + delete $scope.resource.attributes[key]; + } + + $scope.addUri = function() { + $scope.resource.uris.push($scope.newUri); + $scope.newUri = ""; + } + + $scope.deleteUri = function(index) { + $scope.resource.uris.splice(index, 1); + } +}); + +var Scopes = { + delete: function(ResourceServerScope, realm, client, $scope, AuthzDialog, $location, Notifications, $route) { + ResourceServerScope.permissions({ + realm : realm, + client : client.id, + id : $scope.scope.id + }, function (permissions) { + var msg = ""; + + if (permissions.length > 0 && !$scope.deleteConsent) { + msg = "

This scope is referenced in some permissions:

"; + msg += "
    "; + for (i = 0; i < permissions.length; i++) { + msg+= "
  • " + permissions[i].name + "
  • "; + } + msg += "
"; + msg += "

If you remove this scope, the permissions above will be affected and will not be associated with this scope anymore.

"; + } + + AuthzDialog.confirmDeleteWithMsg($scope.scope.name, "Scope", msg, function() { + ResourceServerScope.delete({realm : realm, client : $scope.client.id, id : $scope.scope.id}, null, function() { + $location.url("/realms/" + realm + "/clients/" + $scope.client.id + "/authz/resource-server/scope"); + $route.reload(); + Notifications.success("The scope has been deleted."); + }); + }); + }); + } +} + +module.controller('ResourceServerScopeCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerScope,client, AuthzDialog, Notifications, viewState) { + $scope.realm = realm; + $scope.client = client; + + $scope.query = { + realm: realm.realm, + client : client.id, + deep: false, + max : 20, + first : 0 + }; + + $scope.listSizes = [5, 10, 20]; + + ResourceServer.get({ + realm : $route.current.params.realm, + client : client.id + }, function(data) { + $scope.server = data; + + $scope.createPolicy = function(scope) { + viewState.state = {}; + viewState.state.previousUrl = '/realms/' + $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/scope'; + $location.path('/realms/' + $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/permission/scope/create').search({scpid: scope.id}); + } + + $scope.searchQuery(); + }); + + $scope.firstPage = function() { + $scope.query.first = 0; + $scope.searchQuery(); + } + + $scope.previousPage = function() { + $scope.query.first -= parseInt($scope.query.max); + if ($scope.query.first < 0) { + $scope.query.first = 0; + } + $scope.searchQuery(); + } + + $scope.nextPage = function() { + $scope.query.first += parseInt($scope.query.max); + $scope.searchQuery(); + } + + $scope.searchQuery = function(detailsFilter) { + $scope.searchLoaded = false; + + ResourceServerScope.query($scope.query, function(response) { + $scope.scopes = response; + $scope.searchLoaded = true; + $scope.lastSearch = $scope.query.search; + if ($scope.detailsFilter) { + $scope.showDetails(); + } + }); + }; + + $scope.loadDetails = function (scope) { + if (scope.details) { + scope.details.loaded = !scope.details.loaded; + return; + } + + scope.details = {loaded: false}; + + ResourceServerScope.resources({ + realm : $route.current.params.realm, + client : client.id, + id : scope.id + }, function(response) { + scope.resources = response; + ResourceServerScope.permissions({ + realm : $route.current.params.realm, + client : client.id, + id : scope.id + }, function(response) { + scope.policies = response; + scope.details.loaded = true; + }); + }); + } + + $scope.showDetails = function(item, event) { + if (event.target.localName == 'a' || event.target.localName == 'button') { + return; + } + if (item) { + $scope.loadDetails(item); + } else { + for (i = 0; i < $scope.scopes.length; i++) { + $scope.loadDetails($scope.scopes[i]); + } + } + }; + + $scope.delete = function(scope) { + $scope.scope = scope; + Scopes.delete(ResourceServerScope, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route); + }; +}); + +module.controller('ResourceServerScopeDetailCtrl', function($scope, $http, $route, $location, realm, ResourceServer, client, ResourceServerScope, AuthzDialog, Notifications) { + $scope.realm = realm; + $scope.client = client; + + var $instance = this; + + ResourceServer.get({ + realm : $route.current.params.realm, + client : client.id + }, function(data) { + $scope.server = data; + + var scopeId = $route.current.params.id; + + if (!scopeId) { + $scope.create = true; + $scope.changed = false; + + var scope = {}; + + $scope.scope = angular.copy(scope); + + $scope.$watch('scope', function() { + if (!angular.equals($scope.scope, scope)) { + $scope.changed = true; + } + }, true); + + $scope.save = function() { + $instance.checkNameAvailability(function () { + ResourceServerScope.save({realm : realm.realm, client : $scope.client.id}, $scope.scope, function(data) { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/scope/" + data.id); + Notifications.success("The scope has been created."); + }); + }); + } + + $scope.reset = function() { + $location.url("/realms/" + realm.realm + "/clients/" + $scope.client.id + "/authz/resource-server/scope/"); + } + } else { + ResourceServerScope.get({ + realm : $route.current.params.realm, + client : client.id, + id : $route.current.params.id, + }, function(data) { + $scope.scope = angular.copy(data); + $scope.changed = false; + + $scope.$watch('scope', function() { + if (!angular.equals($scope.scope, data)) { + $scope.changed = true; + } + }, true); + + $scope.originalScope = angular.copy($scope.scope); + + $scope.save = function() { + $instance.checkNameAvailability(function () { + ResourceServerScope.update({realm : realm.realm, client : $scope.client.id, id : $scope.scope.id}, $scope.scope, function() { + $scope.changed = false; + Notifications.success("The scope has been updated."); + }); + }); + } + + $scope.remove = function() { + Scopes.delete(ResourceServerScope, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route); + } + + $scope.reset = function() { + $route.reload(); + } + }); + } + }); + + $scope.checkNewNameAvailability = function () { + $instance.checkNameAvailability(function () {}); + } + + this.checkNameAvailability = function (onSuccess) { + if (!$scope.scope.name || $scope.scope.name.trim().length == 0) { + return; + } + ResourceServerScope.search({ + realm : $route.current.params.realm, + client : client.id, + name: $scope.scope.name + }, function(data) { + if (data && data.id && data.id != $scope.scope.id) { + Notifications.error("Name already in use by another scope, please choose another one."); + } else { + onSuccess(); + } + }); + } +}); + +module.controller('ResourceServerPolicyCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerPolicy, PolicyProvider, client, AuthzDialog, Notifications, KcStrings) { + $scope.realm = realm; + $scope.client = client; + $scope.policyProviders = []; + + $scope.query = { + realm: realm.realm, + client : client.id, + permission: false, + max: 20, + first : 0 + }; + + $scope.listSizes = [5, 10, 20]; + + PolicyProvider.query({ + realm : $route.current.params.realm, + client : client.id + }, function (data) { + for (i = 0; i < data.length; i++) { + if (data[i].type != 'resource' && data[i].type != 'scope') { + $scope.policyProviders.push(data[i]); + } + } + }); + + ResourceServer.get({ + realm : $route.current.params.realm, + client : client.id + }, function(data) { + $scope.server = data; + $scope.searchQuery(); + }); + + $scope.addPolicy = function(policyType) { + if (KcStrings.endsWith(policyType.type, '.js')) { + ResourceServerPolicy.save({realm : realm.realm, client : client.id, type: policyType.type}, {name: policyType.name, type: policyType.type}, function(data) { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy/"); + Notifications.success("The policy has been created."); + }); + } else { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy/" + policyType.type + "/create"); + } + } + + $scope.firstPage = function() { + $scope.query.first = 0; + $scope.searchQuery(); + } + + $scope.previousPage = function() { + $scope.query.first -= parseInt($scope.query.max); + if ($scope.query.first < 0) { + $scope.query.first = 0; + } + $scope.searchQuery(); + } + + $scope.nextPage = function() { + $scope.query.first += parseInt($scope.query.max); + $scope.searchQuery(); + } + + $scope.searchQuery = function() { + $scope.searchLoaded = false; + + ResourceServerPolicy.query($scope.query, function(data) { + $scope.policies = data; + $scope.searchLoaded = true; + $scope.lastSearch = $scope.query.search; + if ($scope.detailsFilter) { + $scope.showDetails(); + } + }); + }; + + $scope.loadDetails = function (policy) { + if (policy.details) { + policy.details.loaded = !policy.details.loaded; + return; + } + + policy.details = {loaded: false}; + + ResourceServerPolicy.dependentPolicies({ + realm : $route.current.params.realm, + client : client.id, + id : policy.id + }, function(response) { + policy.dependentPolicies = response; + policy.details.loaded = true; + }); + } + + $scope.showDetails = function(item, event) { + if (event.target.localName == 'a' || event.target.localName == 'button') { + return; + } + if (item) { + $scope.loadDetails(item); + } else { + for (i = 0; i < $scope.policies.length; i++) { + $scope.loadDetails($scope.policies[i]); + } + } + }; + + $scope.delete = function(policy) { + $scope.policy = policy; + Policies.delete(ResourceServerPolicy, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route, false); + }; +}); + +module.controller('ResourceServerPermissionCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerPermission, PolicyProvider, client, AuthzDialog, Notifications) { + $scope.realm = realm; + $scope.client = client; + $scope.policyProviders = []; + + $scope.query = { + realm: realm.realm, + client : client.id, + max : 20, + first : 0 + }; + + $scope.listSizes = [5, 10, 20]; + + PolicyProvider.query({ + realm : $route.current.params.realm, + client : client.id + }, function (data) { + for (i = 0; i < data.length; i++) { + if (data[i].type == 'resource' || data[i].type == 'scope') { + $scope.policyProviders.push(data[i]); + } + } + }); + + ResourceServer.get({ + realm : $route.current.params.realm, + client : client.id + }, function(data) { + $scope.server = data; + $scope.searchQuery(); + }); + + $scope.addPolicy = function(policyType) { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/permission/" + policyType.type + "/create"); + } + + $scope.firstPage = function() { + $scope.query.first = 0; + $scope.searchQuery(); + } + + $scope.previousPage = function() { + $scope.query.first -= parseInt($scope.query.max); + if ($scope.query.first < 0) { + $scope.query.first = 0; + } + $scope.searchQuery(); + } + + $scope.nextPage = function() { + $scope.query.first += parseInt($scope.query.max); + $scope.searchQuery(); + } + + $scope.searchQuery = function() { + $scope.searchLoaded = false; + + ResourceServerPermission.query($scope.query, function(data) { + $scope.policies = data; + $scope.searchLoaded = true; + $scope.lastSearch = $scope.query.search; + if ($scope.detailsFilter) { + $scope.showDetails(); + } + }); + }; + + $scope.loadDetails = function (policy) { + if (policy.details) { + policy.details.loaded = !policy.details.loaded; + return; + } + + policy.details = {loaded: false}; + + ResourceServerPermission.associatedPolicies({ + realm : $route.current.params.realm, + client : client.id, + id : policy.id + }, function(response) { + policy.associatedPolicies = response; + policy.details.loaded = true; + }); + } + + $scope.showDetails = function(item, event) { + if (event.target.localName == 'a' || event.target.localName == 'button') { + return; + } + if (item) { + $scope.loadDetails(item); + } else { + for (i = 0; i < $scope.policies.length; i++) { + $scope.loadDetails($scope.policies[i]); + } + } + }; + + $scope.delete = function(policy) { + $scope.policy = policy; + Policies.delete(ResourceServerPermission, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route, true); + }; +}); + +module.controller('ResourceServerPolicyResourceDetailCtrl', function($scope, $route, $location, realm, client, PolicyController, ResourceServerPermission, ResourceServerResource, policyViewState) { + PolicyController.onInit({ + getPolicyType : function() { + return "resource"; + }, + + isPermission : function() { + return true; + }, + + onInit : function() { + $scope.resourcesUiSelect = { + minimumInputLength: 1, + delay: 500, + allowClear: true, + id: function(resource){ return resource._id; }, + query: function (query) { + var data = {results: []}; + if ('' == query.term.trim()) { + query.callback(data); + return; + } + $scope.query = { + realm: realm.realm, + client : client.id, + name: query.term.trim(), + deep: false, + max : 20, + first : 0 + }; + ResourceServerResource.query($scope.query, function(response) { + data.results = response; + query.callback(data); + }); + }, + formatResult: function(object, container, query) { + object.text = object.name; + return object.name; + } + }; + + $scope.policiesUiSelect = { + minimumInputLength: 1, + delay: 500, + allowClear: true, + query: function (query) { + var data = {results: []}; + if ('' == query.term.trim()) { + query.callback(data); + return; + } + $scope.query = { + realm: realm.realm, + client : client.id, + permission: false, + name: query.term.trim(), + max : 20, + first : 0 + }; + ResourceServerPermission.searchPolicies($scope.query, function(response) { + data.results = response; + query.callback(data); + }); + }, + formatResult: function(object, container, query) { + object.text = object.name; + return object.name; + } + }; + + $scope.applyToResourceType = function() { + if ($scope.applyToResourceTypeFlag) { + $scope.selectedResource = null; + } else { + $scope.policy.resourceType = null; + } + } + }, + + onInitUpdate : function(policy) { + if (!policy.resourceType) { + $scope.selectedResource = {}; + ResourceServerPermission.resources({ + realm: $route.current.params.realm, + client: client.id, + id: policy.id + }, function (resources) { + resources[0].text = resources[0].name; + $scope.selectedResource = resources[0]; + var copy = angular.copy($scope.selectedResource); + $scope.$watch('selectedResource', function() { + if (!angular.equals($scope.selectedResource, copy)) { + $scope.changed = true; + } + }, true); + }); + } else { + $scope.applyToResourceTypeFlag = true; + } + + ResourceServerPermission.associatedPolicies({ + realm : $route.current.params.realm, + client : client.id, + id : policy.id + }, function(policies) { + $scope.selectedPolicies = []; + for (i = 0; i < policies.length; i++) { + policies[i].text = policies[i].name; + $scope.selectedPolicies.push(policies[i]); + } + var copy = angular.copy($scope.selectedPolicies); + $scope.$watch('selectedPolicies', function() { + if (!angular.equals($scope.selectedPolicies, copy)) { + $scope.changed = true; + } + }, true); + }); + }, + + onUpdate : function() { + if ($scope.selectedResource && $scope.selectedResource._id) { + $scope.policy.resources = []; + $scope.policy.resources.push($scope.selectedResource._id); + } else { + $scope.policy.resources = []; + } + + var policies = []; + + for (i = 0; i < $scope.selectedPolicies.length; i++) { + policies.push($scope.selectedPolicies[i].id); + } + + $scope.policy.policies = policies; + delete $scope.policy.config; + }, + + onInitCreate : function(newPolicy) { + policyViewState.state.previousPage.name = 'authz-add-resource-permission'; + $scope.selectedResource = null; + var copy = angular.copy($scope.selectedResource); + $scope.$watch('selectedResource', function() { + if (!angular.equals($scope.selectedResource, copy)) { + $scope.changed = true; + } + }, true); + + $scope.selectedPolicies = null; + var copy = angular.copy($scope.selectedPolicies); + $scope.$watch('selectedPolicies', function() { + if (!angular.equals($scope.selectedPolicies, copy)) { + $scope.changed = true; + } + }, true); + + var resourceId = $location.search()['rsrid']; + + if (resourceId) { + ResourceServerResource.get({ + realm : $route.current.params.realm, + client : client.id, + rsrid : resourceId + }, function(data) { + data.text = data.name; + $scope.selectedResource = data; + }); + } + }, + + onCreate : function() { + if ($scope.selectedResource && $scope.selectedResource._id) { + $scope.policy.resources = []; + $scope.policy.resources.push($scope.selectedResource._id); + } else { + delete $scope.policy.resources + } + + var policies = []; + + if ($scope.selectedPolicies) { + for (i = 0; i < $scope.selectedPolicies.length; i++) { + policies.push($scope.selectedPolicies[i].id); + } + } + + $scope.policy.policies = policies; + delete $scope.policy.config; + }, + + onSaveState : function(policy) { + policyViewState.state.selectedResource = $scope.selectedResource; + policyViewState.state.applyToResourceTypeFlag = $scope.applyToResourceTypeFlag; + }, + + onRestoreState : function(policy) { + $scope.selectedResource = policyViewState.state.selectedResource; + $scope.applyToResourceTypeFlag = policyViewState.state.applyToResourceTypeFlag; + policy.resourceType = policyViewState.state.policy.resourceType; + } + }, realm, client, $scope); +}); + +module.controller('ResourceServerPolicyScopeDetailCtrl', function($scope, $route, $location, realm, client, PolicyController, ResourceServerPolicy, ResourceServerResource, ResourceServerScope, policyViewState) { + PolicyController.onInit({ + getPolicyType : function() { + return "scope"; + }, + + isPermission : function() { + return true; + }, + + onInit : function() { + $scope.scopesUiSelect = { + minimumInputLength: 1, + delay: 500, + allowClear: true, + query: function (query) { + var data = {results: []}; + if ('' == query.term.trim()) { + query.callback(data); + return; + } + $scope.query = { + realm: realm.realm, + client : client.id, + name: query.term.trim(), + deep: false, + max : 20, + first : 0 + }; + ResourceServerScope.query($scope.query, function(response) { + data.results = response; + query.callback(data); + }); + }, + formatResult: function(object, container, query) { + object.text = object.name; + return object.name; + } + }; + + $scope.resourcesUiSelect = { + minimumInputLength: 1, + delay: 500, + allowClear: true, + id: function(resource){ return resource._id; }, + query: function (query) { + var data = {results: []}; + if ('' == query.term.trim()) { + query.callback(data); + return; + } + $scope.query = { + realm: realm.realm, + client : client.id, + name: query.term.trim(), + deep: false, + max : 20, + first : 0 + }; + ResourceServerResource.query($scope.query, function(response) { + data.results = response; + query.callback(data); + }); + }, + formatResult: function(object, container, query) { + object.text = object.name; + return object.name; + } + }; + + $scope.policiesUiSelect = { + minimumInputLength: 1, + delay: 500, + allowClear: true, + query: function (query) { + var data = {results: []}; + if ('' == query.term.trim()) { + query.callback(data); + return; + } + $scope.query = { + realm: realm.realm, + client : client.id, + permission: false, + name: query.term.trim(), + max : 20, + first : 0 + }; + ResourceServerPolicy.query($scope.query, function(response) { + data.results = response; + query.callback(data); + }); + }, + formatResult: function(object, container, query) { + object.text = object.name; + return object.name; + } + }; + + $scope.selectResource = function() { + $scope.selectedScopes = null; + if ($scope.selectedResource) { + ResourceServerResource.scopes({ + realm: $route.current.params.realm, + client: client.id, + rsrid: $scope.selectedResource._id + }, function (data) { + $scope.resourceScopes = data; + }); + } + } + }, + + onInitUpdate : function(policy) { + ResourceServerPolicy.resources({ + realm : $route.current.params.realm, + client : client.id, + id : policy.id + }, function(resources) { + if (resources.length > 0) { + for (i = 0; i < resources.length; i++) { + ResourceServerResource.get({ + realm: $route.current.params.realm, + client: client.id, + rsrid: resources[0]._id, + }, function (resource) { + ResourceServerResource.query({ + realm: $route.current.params.realm, + client: client.id, + _id: resource._id, + deep: false + }, function (resource) { + resource[0].text = resource[0].name; + $scope.selectedResource = resource[0]; + var copy = angular.copy($scope.selectedResource); + $scope.$watch('selectedResource', function() { + if (!angular.equals($scope.selectedResource, copy)) { + $scope.changed = true; + } + }, true); + ResourceServerResource.scopes({ + realm: $route.current.params.realm, + client: client.id, + rsrid: resource[0]._id + }, function (scopes) { + $scope.resourceScopes = scopes; + }); + }); + }); + } + + ResourceServerPolicy.scopes({ + realm : $route.current.params.realm, + client : client.id, + id : policy.id + }, function(scopes) { + $scope.selectedScopes = []; + for (i = 0; i < scopes.length; i++) { + scopes[i].text = scopes[i].name; + $scope.selectedScopes.push(scopes[i].id); + } + var copy = angular.copy($scope.selectedScopes); + $scope.$watch('selectedScopes', function() { + if (!angular.equals($scope.selectedScopes, copy)) { + $scope.changed = true; + } + }, true); + }); + } else { + $scope.selectedResource = null; + var copy = angular.copy($scope.selectedResource); + $scope.$watch('selectedResource', function() { + if (!angular.equals($scope.selectedResource, copy)) { + $scope.changed = true; + } + }, true); + ResourceServerPolicy.scopes({ + realm : $route.current.params.realm, + client : client.id, + id : policy.id + }, function(scopes) { + $scope.selectedScopes = []; + for (i = 0; i < scopes.length; i++) { + scopes[i].text = scopes[i].name; + $scope.selectedScopes.push(scopes[i]); + } + var copy = angular.copy($scope.selectedScopes); + $scope.$watch('selectedScopes', function() { + if (!angular.equals($scope.selectedScopes, copy)) { + $scope.changed = true; + } + }, true); + }); + } + }); + + ResourceServerPolicy.associatedPolicies({ + realm : $route.current.params.realm, + client : client.id, + id : policy.id + }, function(policies) { + $scope.selectedPolicies = []; + for (i = 0; i < policies.length; i++) { + policies[i].text = policies[i].name; + $scope.selectedPolicies.push(policies[i]); + } + var copy = angular.copy($scope.selectedPolicies); + $scope.$watch('selectedPolicies', function() { + if (!angular.equals($scope.selectedPolicies, copy)) { + $scope.changed = true; + } + }, true); + }); + }, + + onUpdate : function() { + if ($scope.selectedResource != null) { + $scope.policy.resources = [$scope.selectedResource._id]; + } else { + $scope.policy.resources = []; + } + + var scopes = []; + + for (i = 0; i < $scope.selectedScopes.length; i++) { + if ($scope.selectedScopes[i].id) { + scopes.push($scope.selectedScopes[i].id); + } else { + scopes.push($scope.selectedScopes[i]); + } + } + + $scope.policy.scopes = scopes; + + var policies = []; + + if ($scope.selectedPolicies) { + for (i = 0; i < $scope.selectedPolicies.length; i++) { + policies.push($scope.selectedPolicies[i].id); + } + } + + $scope.policy.policies = policies; + delete $scope.policy.config; + }, + + onInitCreate : function(newPolicy) { + policyViewState.state.previousPage.name = 'authz-add-scope-permission'; + var scopeId = $location.search()['scpid']; + + if (scopeId) { + ResourceServerScope.get({ + realm: $route.current.params.realm, + client: client.id, + id: scopeId, + }, function (data) { + data.text = data.name; + if (!$scope.policy.scopes) { + $scope.selectedScopes = []; + } + $scope.selectedScopes.push(data); + }); + } + }, + + onCreate : function() { + if ($scope.selectedResource != null) { + $scope.policy.resources = [$scope.selectedResource._id]; + } + + var scopes = []; + + for (i = 0; i < $scope.selectedScopes.length; i++) { + if ($scope.selectedScopes[i].id) { + scopes.push($scope.selectedScopes[i].id); + } else { + scopes.push($scope.selectedScopes[i]); + } + } + + $scope.policy.scopes = scopes; + + var policies = []; + + if ($scope.selectedPolicies) { + for (i = 0; i < $scope.selectedPolicies.length; i++) { + policies.push($scope.selectedPolicies[i].id); + } + } + + $scope.policy.policies = policies; + delete $scope.policy.config; + }, + + onSaveState : function(policy) { + policyViewState.state.selectedScopes = $scope.selectedScopes; + policyViewState.state.selectedResource = $scope.selectedResource; + policyViewState.state.resourceScopes = $scope.resourceScopes; + }, + + onRestoreState : function(policy) { + $scope.selectedScopes = policyViewState.state.selectedScopes; + $scope.selectedResource = policyViewState.state.selectedResource; + $scope.resourceScopes = policyViewState.state.resourceScopes; + } + }, realm, client, $scope); +}); + +module.controller('ResourceServerPolicyUserDetailCtrl', function($scope, $route, realm, client, PolicyController, User) { + PolicyController.onInit({ + getPolicyType : function() { + return "user"; + }, + + onInit : function() { + $scope.usersUiSelect = { + minimumInputLength: 1, + delay: 500, + allowClear: true, + query: function (query) { + var data = {results: []}; + if ('' == query.term.trim()) { + query.callback(data); + return; + } + User.query({realm: $route.current.params.realm, search: query.term.trim(), max: 20}, function(response) { + data.results = response; + query.callback(data); + }); + }, + formatResult: function(object, container, query) { + return object.username; + } + }; + + $scope.selectedUsers = []; + + $scope.selectUser = function(user) { + if (!user || !user.id) { + return; + } + + $scope.selectedUser = null; + + for (i = 0; i < $scope.selectedUsers.length; i++) { + if ($scope.selectedUsers[i].id == user.id) { + return; + } + } + + $scope.selectedUsers.push(user); + } + + $scope.removeFromList = function(list, user) { + for (i = 0; i < angular.copy(list).length; i++) { + if (user == list[i]) { + list.splice(i, 1); + } + } + } + }, + + onInitUpdate : function(policy) { + var selectedUsers = []; + + if (policy.users) { + var users = policy.users; + + for (i = 0; i < users.length; i++) { + User.get({realm: $route.current.params.realm, userId: users[i]}, function(data) { + selectedUsers.push(data); + $scope.selectedUsers = angular.copy(selectedUsers); + }); + } + } + + $scope.$watch('selectedUsers', function() { + if (!angular.equals($scope.selectedUsers, selectedUsers)) { + $scope.changed = true; + } else { + $scope.changed = false; + } + }, true); + }, + + onUpdate : function() { + var users = []; + + for (i = 0; i < $scope.selectedUsers.length; i++) { + users.push($scope.selectedUsers[i].id); + } + + $scope.policy.users = users; + delete $scope.policy.config; + }, + + onCreate : function() { + var users = []; + + for (i = 0; i < $scope.selectedUsers.length; i++) { + users.push($scope.selectedUsers[i].id); + } + + $scope.policy.users = users; + delete $scope.policy.config; + } + }, realm, client, $scope); +}); + +module.controller('ResourceServerPolicyClientDetailCtrl', function($scope, $route, realm, client, PolicyController, Client) { + PolicyController.onInit({ + getPolicyType : function() { + return "client"; + }, + + onInit : function() { + clientSelectControl($scope, $route.current.params.realm, Client); + + $scope.selectedClients = []; + + $scope.selectClient = function(client) { + if (!client || !client.id) { + return; + } + + $scope.selectedClient = null; + + for (var i = 0; i < $scope.selectedClients.length; i++) { + if ($scope.selectedClients[i].id == client.id) { + return; + } + } + + $scope.selectedClients.push(client); + } + + $scope.removeFromList = function(client) { + var index = $scope.selectedClients.indexOf(client); + if (index != -1) { + $scope.selectedClients.splice(index, 1); + } + } + }, + + onInitUpdate : function(policy) { + var selectedClients = []; + + if (policy.clients) { + var clients = policy.clients; + + for (var i = 0; i < clients.length; i++) { + Client.get({realm: $route.current.params.realm, client: clients[i]}, function(data) { + selectedClients.push(data); + $scope.selectedClients = angular.copy(selectedClients); + }); + } + } + + $scope.$watch('selectedClients', function() { + if (!angular.equals($scope.selectedClients, selectedClients)) { + $scope.changed = true; + } else { + $scope.changed = false; + } + }, true); + }, + + onUpdate : function() { + var clients = []; + + for (var i = 0; i < $scope.selectedClients.length; i++) { + clients.push($scope.selectedClients[i].id); + } + + $scope.policy.clients = clients; + delete $scope.policy.config; + }, + + onInitCreate : function() { + var selectedClients = []; + + $scope.$watch('selectedClients', function() { + if (!angular.equals($scope.selectedClients, selectedClients)) { + $scope.changed = true; + } + }, true); + }, + + onCreate : function() { + var clients = []; + + for (var i = 0; i < $scope.selectedClients.length; i++) { + clients.push($scope.selectedClients[i].id); + } + + $scope.policy.clients = clients; + delete $scope.policy.config; + } + }, realm, client, $scope); +}); + +module.controller('ResourceServerPolicyRoleDetailCtrl', function($scope, $route, realm, client, Client, ClientRole, PolicyController, Role, RoleById) { + PolicyController.onInit({ + getPolicyType : function() { + return "role"; + }, + + onInit : function() { + Role.query({realm: $route.current.params.realm}, function(data) { + $scope.roles = data; + }); + + Client.query({realm: $route.current.params.realm}, function (data) { + $scope.clients = data; + }); + + $scope.selectedRoles = []; + + $scope.selectRole = function(role) { + if (!role || !role.id) { + return; + } + + $scope.selectedRole = null; + + for (i = 0; i < $scope.selectedRoles.length; i++) { + if ($scope.selectedRoles[i].id == role.id) { + return; + } + } + + $scope.selectedRoles.push(role); + + var clientRoles = []; + + if ($scope.clientRoles) { + for (i = 0; i < $scope.clientRoles.length; i++) { + if ($scope.clientRoles[i].id != role.id) { + clientRoles.push($scope.clientRoles[i]); + } + } + $scope.clientRoles = clientRoles; + } + } + + $scope.removeFromList = function(role) { + if ($scope.clientRoles && $scope.selectedClient && $scope.selectedClient.id == role.containerId) { + $scope.clientRoles.push(role); + } + var index = $scope.selectedRoles.indexOf(role); + if (index != -1) { + $scope.selectedRoles.splice(index, 1); + } + } + + $scope.selectClient = function() { + if (!$scope.selectedClient) { + $scope.clientRoles = []; + return; + } + ClientRole.query({realm: $route.current.params.realm, client: $scope.selectedClient.id}, function(data) { + var roles = []; + + for (j = 0; j < data.length; j++) { + var defined = false; + + for (i = 0; i < $scope.selectedRoles.length; i++) { + if ($scope.selectedRoles[i].id == data[j].id) { + defined = true; + break; + } + } + + if (!defined) { + data[j].container = {}; + data[j].container.name = $scope.selectedClient.clientId; + roles.push(data[j]); + } + } + $scope.clientRoles = roles; + }); + } + }, + + onInitUpdate : function(policy) { + var selectedRoles = []; + + if (policy.roles) { + var roles = policy.roles; + + for (i = 0; i < roles.length; i++) { + RoleById.get({realm: $route.current.params.realm, role: roles[i].id}, function(data) { + for (i = 0; i < roles.length; i++) { + if (roles[i].id == data.id) { + data.required = roles[i].required ? true : false; + } + } + for (i = 0; i < $scope.clients.length; i++) { + if ($scope.clients[i].id == data.containerId) { + data.container = {}; + data.container.name = $scope.clients[i].clientId; + } + } + selectedRoles.push(data); + $scope.selectedRoles = angular.copy(selectedRoles); + }); + } + } + + $scope.$watch('selectedRoles', function() { + if (!angular.equals($scope.selectedRoles, selectedRoles)) { + $scope.changed = true; + } else { + $scope.changed = false; + } + }, true); + }, + + onUpdate : function() { + var roles = []; + + for (i = 0; i < $scope.selectedRoles.length; i++) { + var role = {}; + role.id = $scope.selectedRoles[i].id; + if ($scope.selectedRoles[i].required) { + role.required = $scope.selectedRoles[i].required; + } + roles.push(role); + } + + $scope.policy.roles = roles; + delete $scope.policy.config; + }, + + onCreate : function() { + var roles = []; + + for (i = 0; i < $scope.selectedRoles.length; i++) { + var role = {}; + role.id = $scope.selectedRoles[i].id; + if ($scope.selectedRoles[i].required) { + role.required = $scope.selectedRoles[i].required; + } + roles.push(role); + } + + $scope.policy.roles = roles; + delete $scope.policy.config; + } + }, realm, client, $scope); + + $scope.hasRealmRole = function () { + for (i = 0; i < $scope.selectedRoles.length; i++) { + if (!$scope.selectedRoles[i].clientRole) { + return true; + } + } + return false; + } + + $scope.hasClientRole = function () { + for (i = 0; i < $scope.selectedRoles.length; i++) { + if ($scope.selectedRoles[i].clientRole) { + return true; + } + } + return false; + } +}); + +module.controller('ResourceServerPolicyGroupDetailCtrl', function($scope, $route, realm, client, Client, Groups, Group, PolicyController, Notifications, $translate) { + PolicyController.onInit({ + getPolicyType : function() { + return "group"; + }, + + onInit : function() { + $scope.tree = []; + + Groups.query({realm: $route.current.params.realm}, function(groups) { + $scope.groups = groups; + $scope.groupList = [ + {"id" : "realm", "name": $translate.instant('groups'), + "subGroups" : groups} + ]; + }); + + var isLeaf = function(node) { + return node.id != "realm" && (!node.subGroups || node.subGroups.length == 0); + } + + $scope.getGroupClass = function(node) { + if (node.id == "realm") { + return 'pficon pficon-users'; + } + if (isLeaf(node)) { + return 'normal'; + } + if (node.subGroups.length && node.collapsed) return 'collapsed'; + if (node.subGroups.length && !node.collapsed) return 'expanded'; + return 'collapsed'; + + } + + $scope.getSelectedClass = function(node) { + if (node.selected) { + return 'selected'; + } else if ($scope.cutNode && $scope.cutNode.id == node.id) { + return 'cut'; + } + return undefined; + } + + $scope.selectGroup = function(group) { + for (i = 0; i < $scope.selectedGroups.length; i++) { + if ($scope.selectedGroups[i].id == group.id) { + return + } + } + if (group.id == "realm") { + Notifications.error("You must choose a group"); + return; + } + $scope.selectedGroups.push({id: group.id, path: group.path}); + $scope.changed = true; + } + + $scope.extendChildren = function(group) { + $scope.changed = true; + } + + $scope.removeFromList = function(group) { + var index = $scope.selectedGroups.indexOf(group); + if (index != -1) { + $scope.selectedGroups.splice(index, 1); + $scope.changed = true; + } + } + }, + + onInitCreate : function(policy) { + var selectedGroups = []; + + $scope.selectedGroups = angular.copy(selectedGroups); + + $scope.$watch('selectedGroups', function() { + if (!angular.equals($scope.selectedGroups, selectedGroups)) { + $scope.changed = true; + } else { + $scope.changed = PolicyController.isNewAssociatedPolicy(); + } + }, true); + }, + + onInitUpdate : function(policy) { + $scope.selectedGroups = policy.groups; + + angular.forEach($scope.selectedGroups, function(group, index){ + Group.get({realm: $route.current.params.realm, groupId: group.id}, function (existing) { + group.path = existing.path; + }); + }); + + $scope.$watch('selectedGroups', function() { + if (!$scope.changed) { + return; + } + if (!angular.equals($scope.selectedGroups, selectedGroups)) { + $scope.changed = true; + } else { + $scope.changed = false; + } + }, true); + }, + + onUpdate : function() { + $scope.policy.groups = $scope.selectedGroups; + delete $scope.policy.config; + }, + + onCreate : function() { + $scope.policy.groups = $scope.selectedGroups; + delete $scope.policy.config; + } + }, realm, client, $scope); +}); + +module.controller('ResourceServerPolicyJSDetailCtrl', function($scope, $route, $location, realm, PolicyController, client, serverInfo) { + PolicyController.onInit({ + getPolicyType : function() { + return "js"; + }, + + onInit : function() { + }, + + onInitUpdate : function(policy) { + + }, + + onUpdate : function() { + delete $scope.policy.config; + }, + + onInitCreate : function(newPolicy) { + }, + + onCreate : function() { + delete $scope.policy.config; + } + }, realm, client, $scope); +}); + +module.controller('ResourceServerPolicyTimeDetailCtrl', function($scope, $route, $location, realm, PolicyController, client) { + + function clearEmptyStrings() { + if ($scope.policy.notBefore != undefined && $scope.policy.notBefore.trim() == '') { + $scope.policy.notBefore = null; + } + if ($scope.policy.notOnOrAfter != undefined && $scope.policy.notOnOrAfter.trim() == '') { + $scope.policy.notOnOrAfter = null; + } + } + + PolicyController.onInit({ + getPolicyType : function() { + return "time"; + }, + + onInit : function() { + + }, + + onInitUpdate : function(policy) { + if (policy.dayMonth) { + policy.dayMonth = parseInt(policy.dayMonth); + } + if (policy.dayMonthEnd) { + policy.dayMonthEnd = parseInt(policy.dayMonthEnd); + } + if (policy.month) { + policy.month = parseInt(policy.month); + } + if (policy.monthEnd) { + policy.monthEnd = parseInt(policy.monthEnd); + } + if (policy.year) { + policy.year = parseInt(policy.year); + } + if (policy.yearEnd) { + policy.yearEnd = parseInt(policy.yearEnd); + } + if (policy.hour) { + policy.hour = parseInt(policy.hour); + } + if (policy.hourEnd) { + policy.hourEnd = parseInt(policy.hourEnd); + } + if (policy.minute) { + policy.minute = parseInt(policy.minute); + } + if (policy.minuteEnd) { + policy.minuteEnd = parseInt(policy.minuteEnd); + } + }, + + onUpdate : function() { + clearEmptyStrings(); + delete $scope.policy.config; + }, + + onInitCreate : function(newPolicy) { + }, + + onCreate : function() { + clearEmptyStrings(); + delete $scope.policy.config; + } + }, realm, client, $scope); + + $scope.isRequired = function () { + var policy = $scope.policy; + + if (!policy) { + return true; + } + + if (policy.notOnOrAfter || policy.notBefore + || policy.dayMonth + || policy.month + || policy.year + || policy.hour + || policy.minute) { + return false; + } + return true; + } +}); + +module.controller('ResourceServerPolicyAggregateDetailCtrl', function($scope, $route, $location, realm, PolicyController, ResourceServerPolicy, client, PolicyProvider, policyViewState) { + PolicyController.onInit({ + getPolicyType : function() { + return "aggregate"; + }, + + onInit : function() { + $scope.policiesUiSelect = { + minimumInputLength: 1, + delay: 500, + allowClear: true, + query: function (query) { + var data = {results: []}; + if ('' == query.term.trim()) { + query.callback(data); + return; + } + $scope.query = { + realm: realm.realm, + client : client.id, + permission: false, + name: query.term.trim(), + max : 20, + first : 0 + }; + ResourceServerPolicy.query($scope.query, function(response) { + data.results = response; + query.callback(data); + }); + }, + formatResult: function(object, container, query) { + object.text = object.name; + return object.name; + } + }; + }, + + onInitUpdate : function(policy) { + ResourceServerPolicy.associatedPolicies({ + realm : $route.current.params.realm, + client : client.id, + id : policy.id + }, function(policies) { + $scope.selectedPolicies = []; + for (i = 0; i < policies.length; i++) { + policies[i].text = policies[i].name; + $scope.selectedPolicies.push(policies[i]); + } + var copy = angular.copy($scope.selectedPolicies); + $scope.$watch('selectedPolicies', function() { + if (!angular.equals($scope.selectedPolicies, copy)) { + $scope.changed = true; + } + }, true); + }); + }, + + onUpdate : function() { + var policies = []; + + for (i = 0; i < $scope.selectedPolicies.length; i++) { + policies.push($scope.selectedPolicies[i].id); + } + + $scope.policy.policies = policies; + delete $scope.policy.config; + }, + + onInitCreate : function(newPolicy) { + policyViewState.state.previousPage.name = 'authz-add-aggregated-policy'; + }, + + onCreate : function() { + var policies = []; + + for (i = 0; i < $scope.selectedPolicies.length; i++) { + policies.push($scope.selectedPolicies[i].id); + } + + $scope.policy.policies = policies; + delete $scope.policy.config; + } + }, realm, client, $scope); +}); + +module.controller('ResourceServerPolicyClientScopeDetailCtrl', function($scope, $route, realm, client, ClientScope, PolicyController) { + PolicyController.onInit({ + getPolicyType : function() { + return "client-scope"; + }, + + onInit : function() { + ClientScope.query({realm: $route.current.params.realm}, function(data) { + $scope.clientScopes = data; + }); + + $scope.selectedClientScopes = []; + + $scope.selectClientScope = function(clientScope) { + if (!clientScope || !clientScope.id) { + return; + } + + $scope.selectedClientScope = null; + + for (i = 0; i < $scope.selectedClientScopes.length; i++) { + if ($scope.selectedClientScopes[i].id == clientScope.id) { + return; + } + } + + $scope.selectedClientScopes.push(clientScope); + } + + $scope.removeFromList = function(clientScope) { + var index = $scope.selectedClientScopes.indexOf(clientScope); + if (index != -1) { + $scope.selectedClientScopes.splice(index, 1); + } + } + }, + + onInitUpdate : function(policy) { + var selectedClientScopes = []; + + if (policy.clientScopes) { + var clientScopes = policy.clientScopes; + + for (i = 0; i < clientScopes.length; i++) { + ClientScope.get({realm: $route.current.params.realm, clientScope: clientScopes[i].id}, function(data) { + for (i = 0; i < clientScopes.length; i++) { + if (clientScopes[i].id == data.id) { + data.required = clientScopes[i].required ? true : false; + } + } + selectedClientScopes.push(data); + $scope.selectedClientScopes = angular.copy(selectedClientScopes); + }); + } + } + + $scope.$watch('selectedClientScopes', function() { + if (!angular.equals($scope.selectedClientScopes, selectedClientScopes)) { + $scope.changed = true; + } else { + $scope.changed = false; + } + }, true); + }, + + onUpdate : function() { + var clientScopes = []; + + for (i = 0; i < $scope.selectedClientScopes.length; i++) { + var clientScope = {}; + clientScope.id = $scope.selectedClientScopes[i].id; + if ($scope.selectedClientScopes[i].required) { + clientScope.required = $scope.selectedClientScopes[i].required; + } + clientScopes.push(clientScope); + } + + $scope.policy.clientScopes = clientScopes; + delete $scope.policy.config; + }, + + onCreate : function() { + var clientScopes = []; + + for (i = 0; i < $scope.selectedClientScopes.length; i++) { + var clientScope = {}; + clientScope.id = $scope.selectedClientScopes[i].id; + if ($scope.selectedClientScopes[i].required) { + clientScope.required = $scope.selectedClientScopes[i].required; + } + clientScopes.push(clientScope); + } + + $scope.policy.clientScopes = clientScopes; + delete $scope.policy.config; + } + }, realm, client, $scope); +}); + +module.controller('ResourceServerPolicyRegexDetailCtrl', function($scope, realm, client, PolicyController) { + PolicyController.onInit({ + getPolicyType : function() { + return "regex"; + }, + + onInit : function() { + }, + + onInitUpdate : function(policy) { + }, + + onUpdate : function() { + delete $scope.policy.config; + }, + + onCreate : function() { + delete $scope.policy.config; + } + }, realm, client, $scope); +}); + +module.service("PolicyController", function($http, $route, $location, ResourceServer, ResourceServerPolicy, ResourceServerPermission, AuthzDialog, Notifications, policyViewState, PolicyProvider, viewState) { + + var PolicyController = {}; + + PolicyController.isNewAssociatedPolicy = function() { + return $route.current.params['new_policy'] != null; + } + + PolicyController.isBackNewAssociatedPolicy = function() { + return $route.current.params['back'] != null; + } + + PolicyController.onInit = function(delegate, realm, client, $scope) { + $scope.policyProviders = []; + + PolicyProvider.query({ + realm : $route.current.params.realm, + client : client.id + }, function (data) { + for (i = 0; i < data.length; i++) { + if (data[i].type != 'resource' && data[i].type != 'scope') { + $scope.policyProviders.push(data[i]); + } + } + }); + + if ((!policyViewState.state || !PolicyController.isBackNewAssociatedPolicy()) && !PolicyController.isNewAssociatedPolicy()) { + policyViewState.state = {}; + } + + if (!policyViewState.state.previousPage) { + policyViewState.state.previousPage = {}; + } + + $scope.policyViewState = policyViewState; + + $scope.addPolicy = function(policyType) { + policyViewState.state.policy = $scope.policy; + + if (delegate.onSaveState) { + delegate.onSaveState($scope.policy); + } + + if ($scope.selectedPolicies) { + policyViewState.state.selectedPolicies = $scope.selectedPolicies; + } + var previousUrl = window.location.href.substring(window.location.href.indexOf('/realms')); + + if (previousUrl.indexOf('back=true') == -1) { + previousUrl = previousUrl + (previousUrl.indexOf('?') == -1 ? '?' : '&') + 'back=true'; + } + policyViewState.state.previousUrl = previousUrl; + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy/" + policyType.type + "/create?new_policy=true"); + } + + $scope.detailPolicy = function(policy) { + policyViewState.state.policy = $scope.policy; + if (delegate.onSaveState) { + delegate.onSaveState($scope.policy); + } + if ($scope.selectedPolicies) { + policyViewState.state.selectedPolicies = $scope.selectedPolicies; + } + var previousUrl = window.location.href.substring(window.location.href.indexOf('/realms')); + + if (previousUrl.indexOf('back=true') == -1) { + previousUrl = previousUrl + (previousUrl.indexOf('?') == -1 ? '?' : '&') + 'back=true'; + } + policyViewState.state.previousUrl = previousUrl; + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy/" + policy.type + "/" + policy.id + "?new_policy=true"); + } + + $scope.removePolicy = function(list, policy) { + for (i = 0; i < angular.copy(list).length; i++) { + if (policy.id == list[i].id) { + list.splice(i, 1); + } + } + } + + $scope.selectPolicy = function(policy) { + if (!policy || !policy.id) { + return; + } + + if (!$scope.selectedPolicies) { + $scope.selectedPolicies = []; + } + + $scope.selectedPolicy = null; + + for (i = 0; i < $scope.selectedPolicies.length; i++) { + if ($scope.selectedPolicies[i].id == policy.id) { + return; + } + } + + $scope.selectedPolicies.push(policy); + } + + $scope.createNewPolicy = function() { + $scope.showNewPolicy = true; + } + + $scope.cancelCreateNewPolicy = function() { + $scope.showNewPolicy = false; + } + + $scope.historyBackOnSaveOrCancel = PolicyController.isNewAssociatedPolicy(); + + if (!delegate.isPermission) { + delegate.isPermission = function () { + return false; + } + } + + var service = ResourceServerPolicy; + + if (delegate.isPermission()) { + service = ResourceServerPermission; + } + + $scope.realm = realm; + $scope.client = client; + + $scope.decisionStrategies = ['AFFIRMATIVE', 'UNANIMOUS', 'CONSENSUS']; + $scope.logics = ['POSITIVE', 'NEGATIVE']; + + delegate.onInit(); + + var $instance = this; + + ResourceServer.get({ + realm : $route.current.params.realm, + client : client.id + }, function(data) { + $scope.server = data; + + var policyId = $route.current.params.id; + + if (!policyId) { + $scope.create = true; + + var policy = {}; + + policy.type = delegate.getPolicyType(); + policy.config = {}; + policy.logic = 'POSITIVE'; + policy.decisionStrategy = 'UNANIMOUS'; + + $scope.changed = $scope.historyBackOnSaveOrCancel || PolicyController.isBackNewAssociatedPolicy(); + + if (viewState.state != null && viewState.state.previousUrl != null) { + $scope.previousUrl = viewState.state.previousUrl; + policyViewState.state.rootUrl = $scope.previousUrl; + viewState.state = {}; + } + + $scope.policy = angular.copy(policy); + + $scope.$watch('policy', function() { + if (!angular.equals($scope.policy, policy)) { + $scope.changed = true; + } + }, true); + + if (PolicyController.isBackNewAssociatedPolicy()) { + if (delegate.onRestoreState) { + delegate.onRestoreState($scope.policy); + } + $instance.restoreState($scope); + } else if (delegate.onInitCreate) { + delegate.onInitCreate(policy); + } + + $scope.save = function() { + $instance.checkNameAvailability(function () { + if (delegate.onCreate) { + delegate.onCreate(); + } + + let policyType = $scope.policy.type.endsWith('.js') ? 'js': $scope.policy.type; + + service.save({realm : realm.realm, client : client.id, type: $scope.policy.type}, $scope.policy, function(data) { + if (delegate.isPermission()) { + if ($scope.historyBackOnSaveOrCancel || policyViewState.state.rootUrl != null) { + if (policyViewState.state.rootUrl != null) { + $location.url(policyViewState.state.rootUrl); + } else { + policyViewState.state.newPolicyName = $scope.policy.name; + $location.url(policyViewState.state.previousUrl); + } + } else { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/permission/" + policyType + "/" + data.id); + } + Notifications.success("The permission has been created."); + } else { + if ($scope.historyBackOnSaveOrCancel) { + policyViewState.state.newPolicyName = $scope.policy.name; + $location.url(policyViewState.state.previousUrl); + } else { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy/" + policyType + "/" + data.id); + } + Notifications.success("The policy has been created."); + } + }); + }); + } + + $scope.reset = function() { + if (delegate.isPermission()) { + if ($scope.historyBackOnSaveOrCancel || policyViewState.state.rootUrl != null) { + if (policyViewState.state.rootUrl != null) { + $location.url(policyViewState.state.rootUrl); + } else { + $location.url(policyViewState.state.previousUrl); + } + } else { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/permission/"); + } + } else { + if ($scope.historyBackOnSaveOrCancel) { + $location.url(policyViewState.state.previousUrl); + } else { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy/"); + } + } + } + } else { + service.get({ + realm: realm.realm, + client : client.id, + type: delegate.getPolicyType(), + id: $route.current.params.id + }, function(data) { + $scope.originalPolicy = data; + var policy = angular.copy(data); + + $scope.changed = $scope.historyBackOnSaveOrCancel || PolicyController.isBackNewAssociatedPolicy(); + $scope.policy = angular.copy(policy); + + if (PolicyController.isBackNewAssociatedPolicy()) { + if (delegate.onRestoreState) { + delegate.onRestoreState($scope.policy); + } + $instance.restoreState($scope); + } else if (delegate.onInitUpdate) { + delegate.onInitUpdate($scope.policy); + } + + $scope.$watch('policy', function() { + if (!angular.equals($scope.policy, policy)) { + $scope.changed = true; + } + }, true); + + + $scope.save = function() { + $instance.checkNameAvailability(function () { + if (delegate.onUpdate) { + delegate.onUpdate(); + } + + let policyType = $scope.policy.type.endsWith('.js') ? 'js': $scope.policy.type; + + service.update({realm : realm.realm, client : client.id, type: $scope.policy.type, id : $scope.policy.id}, $scope.policy, function() { + if (delegate.isPermission()) { + if ($scope.historyBackOnSaveOrCancel) { + $location.url(policyViewState.state.previousUrl); + } else { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/permission/" + policyType + "/" + $scope.policy.id); + } + $route.reload(); + Notifications.success("The permission has been updated."); + } else { + if ($scope.historyBackOnSaveOrCancel) { + $location.url(policyViewState.state.previousUrl); + } else { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy/" + policyType + "/" + $scope.policy.id); + } + $route.reload(); + Notifications.success("The policy has been updated."); + } + }); + }); + } + + $scope.reset = function() { + if ($scope.historyBackOnSaveOrCancel) { + $location.url(policyViewState.state.previousUrl); + } else { + var freshPolicy = angular.copy(data); + + if (delegate.onInitUpdate) { + delegate.onInitUpdate(freshPolicy); + } + + $scope.policy = angular.copy(freshPolicy); + $scope.changed = false; + } + } + }); + + $scope.remove = function() { + Policies.delete(ResourceServerPolicy, $route.current.params.realm, client, $scope, AuthzDialog, $location, Notifications, $route, delegate.isPermission()); + } + } + }); + + $scope.checkNewNameAvailability = function () { + $instance.checkNameAvailability(function () {}); + } + + this.checkNameAvailability = function (onSuccess) { + if (!$scope.policy.name || $scope.policy.name.trim().length == 0) { + return; + } + ResourceServerPolicy.search({ + realm: $route.current.params.realm, + client: client.id, + name: $scope.policy.name + }, function(data) { + if (data && data.id && data.id != $scope.policy.id) { + Notifications.error("Name already in use by another policy or permission, please choose another one."); + } else { + onSuccess(); + } + }); + } + + this.restoreState = function($scope) { + $scope.policy.name = policyViewState.state.policy.name; + $scope.policy.description = policyViewState.state.policy.description; + $scope.policy.decisionStrategy = policyViewState.state.policy.decisionStrategy; + $scope.policy.logic = policyViewState.state.policy.logic; + $scope.selectedPolicies = policyViewState.state.selectedPolicies; + + if (!$scope.selectedPolicies) { + $scope.selectedPolicies = []; + } + + $scope.changed = true; + var previousPage = policyViewState.state.previousPage; + + if (policyViewState.state.newPolicyName) { + ResourceServerPolicy.query({ + realm: realm.realm, + client : client.id, + permission: false, + name: policyViewState.state.newPolicyName, + max : 20, + first : 0 + }, function(response) { + for (i = 0; i < response.length; i++) { + if (response[i].name == policyViewState.state.newPolicyName) { + response[i].text = response[i].name; + $scope.selectedPolicies.push(response[i]); + } + } + + var rootUrl = policyViewState.state.rootUrl; + policyViewState.state = {}; + policyViewState.state.previousPage = previousPage; + policyViewState.state.rootUrl = rootUrl; + }); + } else { + var rootUrl = policyViewState.state.rootUrl; + policyViewState.state = {}; + policyViewState.state.previousPage = previousPage; + policyViewState.state.rootUrl = rootUrl; + } + } + } + + return PolicyController; +}); + +module.controller('PolicyEvaluateCtrl', function($scope, $http, $route, $location, realm, clients, roles, ResourceServer, client, ResourceServerResource, ResourceServerScope, User, Notifications) { + $scope.realm = realm; + $scope.client = client; + $scope.clients = clients; + $scope.roles = roles; + $scope.authzRequest = {}; + $scope.authzRequest.resources = []; + $scope.authzRequest.context = {}; + $scope.authzRequest.context.attributes = {}; + $scope.authzRequest.roleIds = []; + $scope.resultUrl = resourceUrl + '/partials/authz/policy/resource-server-policy-evaluate-result.html'; + + $scope.addContextAttribute = function() { + if (!$scope.newContextAttribute.value || $scope.newContextAttribute.value == '') { + Notifications.error("You must provide a value to a context attribute."); + return; + } + + $scope.authzRequest.context.attributes[$scope.newContextAttribute.key] = $scope.newContextAttribute.value; + delete $scope.newContextAttribute; + } + + $scope.removeContextAttribute = function(key) { + delete $scope.authzRequest.context.attributes[key]; + } + + $scope.getContextAttribute = function(key) { + for (i = 0; i < $scope.defaultContextAttributes.length; i++) { + if ($scope.defaultContextAttributes[i].key == key) { + return $scope.defaultContextAttributes[i]; + } + } + + return $scope.authzRequest.context.attributes[key]; + } + + $scope.getContextAttributeName = function(key) { + var attribute = $scope.getContextAttribute(key); + + if (!attribute.name) { + return key; + } + + return attribute.name; + } + + $scope.defaultContextAttributes = [ + { + key : "custom", + name : "Custom Attribute...", + custom: true + }, + { + key : "kc.identity.authc.method", + name : "Authentication Method", + values: [ + { + key : "pwd", + name : "Password" + }, + { + key : "otp", + name : "One-Time Password" + }, + { + key : "kbr", + name : "Kerberos" + } + ] + }, + { + key : "kc.realm.name", + name : "Realm" + }, + { + key : "kc.time.date_time", + name : "Date/Time (MM/dd/yyyy hh:mm:ss)" + }, + { + key : "kc.client.network.ip_address", + name : "Client IPv4 Address" + }, + { + key : "kc.client.network.host", + name : "Client Host" + }, + { + key : "kc.client.user_agent", + name : "Client/User Agent" + } + ]; + + $scope.isDefaultContextAttribute = function() { + if (!$scope.newContextAttribute) { + return true; + } + + if ($scope.newContextAttribute.custom) { + return false; + } + + if (!$scope.getContextAttribute($scope.newContextAttribute.key).custom) { + return true; + } + + return false; + } + + $scope.selectDefaultContextAttribute = function() { + $scope.newContextAttribute = angular.copy($scope.newContextAttribute); + } + + $scope.setApplyToResourceType = function() { + delete $scope.newResource; + $scope.authzRequest.resources = []; + } + + $scope.addResource = function() { + var resource = angular.copy($scope.newResource); + + if (!resource) { + resource = {}; + } + + delete resource.text; + + if (!$scope.newScopes || (resource._id != null && $scope.newScopes.length > 0 && $scope.newScopes[0].id)) { + $scope.newScopes = []; + } + + var scopes = []; + + for (i = 0; i < $scope.newScopes.length; i++) { + if ($scope.newScopes[i].name) { + scopes.push($scope.newScopes[i].name); + } else { + scopes.push($scope.newScopes[i]); + } + } + + resource.scopes = scopes; + + $scope.authzRequest.resources.push(resource); + + delete $scope.newResource; + delete $scope.newScopes; + } + + $scope.removeResource = function(index) { + $scope.authzRequest.resources.splice(index, 1); + } + + $scope.resolveScopes = function() { + if ($scope.newResource._id) { + $scope.newResource.scopes = []; + $scope.scopes = []; + ResourceServerResource.scopes({ + realm: $route.current.params.realm, + client: client.id, + rsrid: $scope.newResource._id + }, function (data) { + $scope.scopes = data; + }); + } + } + + $scope.reevaluate = function() { + if ($scope.authzRequest.entitlements) { + $scope.entitlements(); + } else { + $scope.save(); + } + } + + $scope.showAuthzData = function() { + $scope.showRpt = true; + } + + $scope.save = function() { + $scope.authzRequest.entitlements = false; + if ($scope.applyResourceType) { + if (!$scope.newResource) { + $scope.newResource = {}; + } + if (!$scope.newScopes || ($scope.newResource._id != null && $scope.newScopes.length > 0 && $scope.newScopes[0].id)) { + $scope.newScopes = []; + } + + var scopes = angular.copy($scope.newScopes); + + for (i = 0; i < scopes.length; i++) { + delete scopes[i].text; + } + + $scope.authzRequest.resources[0].scopes = scopes; + } + + $http.post(authUrl + '/admin/realms/'+ $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/policy/evaluate' + , $scope.authzRequest).then(function(response) { + $scope.evaluationResult = response.data; + $scope.showResultTab(); + }); + } + + $scope.entitlements = function() { + $scope.authzRequest.entitlements = true; + $http.post(authUrl + '/admin/realms/'+ $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/policy/evaluate' + , $scope.authzRequest).then(function(response) { + $scope.evaluationResult = response.data; + $scope.showResultTab(); + }); + } + + $scope.showResultTab = function() { + $scope.showResult = true; + $scope.showRpt = false; + } + + $scope.showRequestTab = function() { + $scope.showResult = false; + $scope.showRpt = false; + } + + $scope.usersUiSelect = { + minimumInputLength: 1, + delay: 500, + allowClear: true, + query: function (query) { + var data = {results: []}; + if ('' == query.term.trim()) { + query.callback(data); + return; + } + User.query({realm: $route.current.params.realm, search: query.term.trim(), max: 20}, function(response) { + data.results = response; + query.callback(data); + }); + }, + formatResult: function(object, container, query) { + object.text = object.username; + return object.username; + } + }; + + $scope.resourcesUiSelect = { + minimumInputLength: 1, + delay: 500, + allowClear: true, + id: function(resource){ return resource._id; }, + query: function (query) { + var data = {results: []}; + if ('' == query.term.trim()) { + query.callback(data); + return; + } + $scope.query = { + realm: realm.realm, + client : client.id, + name: query.term.trim(), + deep: false, + max : 20, + first : 0 + }; + ResourceServerResource.query($scope.query, function(response) { + data.results = response; + query.callback(data); + }); + }, + formatResult: function(object, container, query) { + object.text = object.name; + return object.name; + } + }; + + $scope.scopesUiSelect = { + minimumInputLength: 1, + delay: 500, + allowClear: true, + query: function (query) { + var data = {results: []}; + if ('' == query.term.trim()) { + query.callback(data); + return; + } + $scope.query = { + realm: realm.realm, + client : client.id, + name: query.term.trim(), + deep: false, + max : 20, + first : 0 + }; + ResourceServerScope.query($scope.query, function(response) { + data.results = response; + query.callback(data); + }); + }, + formatResult: function(object, container, query) { + object.text = object.name; + return object.name; + } + }; + + ResourceServer.get({ + realm : $route.current.params.realm, + client : client.id + }, function(data) { + $scope.server = data; + }); + + $scope.selectUser = function(user) { + if (!user || !user.id) { + $scope.selectedUser = null; + $scope.authzRequest.userId = ''; + return; + } + + $scope.authzRequest.userId = user.id; + } + + $scope.reset = function() { + $scope.authzRequest = angular.copy(authzRequest); + $scope.changed = false; + } +}); + +getManageClientId = function(realm) { + if (realm.realm == masterRealm) { + return 'master-realm'; + } else { + return 'realm-management'; + } +} + +module.controller('RealmRolePermissionsCtrl', function($scope, $http, $route, $location, realm, role, RoleManagementPermissions, Client, Notifications, Dialog, RealmRoleRemover) { + console.log('RealmRolePermissionsCtrl'); + $scope.role = role; + $scope.realm = realm; + + $scope.remove = function() { + RealmRoleRemover.remove($scope.role, realm, Dialog, $location, Notifications); + }; + + RoleManagementPermissions.get({realm: realm.realm, role: role.id}, function(data) { + $scope.permissions = data; + $scope.$watch('permissions.enabled', function(newVal, oldVal) { + if (newVal != oldVal) { + var param = {enabled: $scope.permissions.enabled}; + $scope.permissions= RoleManagementPermissions.update({realm: realm.realm, role:role.id}, param); + } + }, true); + }); + Client.query({realm: realm.realm, clientId: getManageClientId(realm)}, function(data) { + $scope.realmManagementClientId = data[0].id; + }); +}); +module.controller('ClientRolePermissionsCtrl', function($scope, $http, $route, $location, realm, client, role, Client, RoleManagementPermissions, Client, Notifications) { + console.log('RealmRolePermissionsCtrl'); + $scope.client = client; + $scope.role = role; + $scope.realm = realm; + RoleManagementPermissions.get({realm: realm.realm, role: role.id}, function(data) { + $scope.permissions = data; + $scope.$watch('permissions.enabled', function(newVal, oldVal) { + if (newVal != oldVal) { + var param = {enabled: $scope.permissions.enabled}; + $scope.permissions = RoleManagementPermissions.update({realm: realm.realm, role:role.id}, param); + } + }, true); + }); + Client.query({realm: realm.realm, clientId: getManageClientId(realm)}, function(data) { + $scope.realmManagementClientId = data[0].id; + }); +}); + +module.controller('UsersPermissionsCtrl', function($scope, $http, $route, $location, realm, UsersManagementPermissions, Client, Notifications) { + console.log('UsersPermissionsCtrl'); + $scope.realm = realm; + var first = true; + UsersManagementPermissions.get({realm: realm.realm}, function(data) { + $scope.permissions = data; + $scope.$watch('permissions.enabled', function(newVal, oldVal) { + if (newVal != oldVal) { + var param = {enabled: $scope.permissions.enabled}; + $scope.permissions = UsersManagementPermissions.update({realm: realm.realm}, param); + + } + }, true); + }); + Client.query({realm: realm.realm, clientId: getManageClientId(realm)}, function(data) { + $scope.realmManagementClientId = data[0].id; + }); + + + + +}); + +module.controller('ClientPermissionsCtrl', function($scope, $http, $route, $location, realm, client, Client, ClientManagementPermissions, Notifications) { + $scope.client = client; + $scope.realm = realm; + ClientManagementPermissions.get({realm: realm.realm, client: client.id}, function(data) { + $scope.permissions = data; + $scope.$watch('permissions.enabled', function(newVal, oldVal) { + if (newVal != oldVal) { + var param = {enabled: $scope.permissions.enabled}; + $scope.permissions = ClientManagementPermissions.update({realm: realm.realm, client: client.id}, param); + } + }, true); + }); + Client.query({realm: realm.realm, clientId: getManageClientId(realm)}, function(data) { + $scope.realmManagementClientId = data[0].id; + }); +}); + +module.controller('IdentityProviderPermissionCtrl', function($scope, $http, $route, $location, realm, identityProvider, Client, IdentityProviderManagementPermissions, Notifications) { + $scope.identityProvider = identityProvider; + $scope.realm = realm; + IdentityProviderManagementPermissions.get({realm: realm.realm, alias: identityProvider.alias}, function(data) { + $scope.permissions = data; + $scope.$watch('permissions.enabled', function(newVal, oldVal) { + if (newVal != oldVal) { + var param = {enabled: $scope.permissions.enabled}; + $scope.permissions = IdentityProviderManagementPermissions.update({realm: realm.realm, alias: identityProvider.alias}, param); + } + }, true); + }); + Client.query({realm: realm.realm, clientId: getManageClientId(realm)}, function(data) { + $scope.realmManagementClientId = data[0].id; + }); +}); + +module.controller('GroupPermissionsCtrl', function($scope, $http, $route, $location, realm, group, GroupManagementPermissions, Client, Notifications) { + $scope.group = group; + $scope.realm = realm; + Client.query({realm: realm.realm, clientId: getManageClientId(realm)}, function(data) { + $scope.realmManagementClientId = data[0].id; + }); + GroupManagementPermissions.get({realm: realm.realm, group: group.id}, function(data) { + $scope.permissions = data; + $scope.$watch('permissions.enabled', function(newVal, oldVal) { + if (newVal != oldVal) { + var param = {enabled: $scope.permissions.enabled}; + $scope.permissions = GroupManagementPermissions.update({realm: realm.realm, group: group.id}, param); + } + }, true); + }); +}); \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/js/authz/authz-services.js b/keycloak-themes/base/admin/resources/js/authz/authz-services.js new file mode 100644 index 0000000..5e20472 --- /dev/null +++ b/keycloak-themes/base/admin/resources/js/authz/authz-services.js @@ -0,0 +1,218 @@ +module.factory('ResourceServer', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server', { + realm : '@realm', + client: '@client' + }, { + 'update' : {method : 'PUT'}, + 'import' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/import', method : 'POST'}, + 'settings' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/settings', method : 'GET'} + }); +}); + +module.factory('ResourceServerResource', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/resource/:rsrid', { + realm : '@realm', + client: '@client', + rsrid : '@rsrid' + }, { + 'update' : {method : 'PUT'}, + 'search' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/resource/search', method : 'GET'}, + 'scopes' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/resource/:rsrid/scopes', method : 'GET', isArray: true}, + 'permissions' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/resource/:rsrid/permissions', method : 'GET', isArray: true} + }); +}); + +module.factory('ResourceServerScope', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/scope/:id', { + realm : '@realm', + client: '@client', + id : '@id' + }, { + 'update' : {method : 'PUT'}, + 'search' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/scope/search', method : 'GET'}, + 'resources' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/scope/:id/resources', method : 'GET', isArray: true}, + 'permissions' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/scope/:id/permissions', method : 'GET', isArray: true}, + }); +}); + +module.factory('ResourceServerPolicy', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/policy/:type/:id', { + realm : '@realm', + client: '@client', + id : '@id', + type: '@type' + }, { + 'update' : {method : 'PUT'}, + 'search' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/policy/search', method : 'GET'}, + 'associatedPolicies' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/policy/:id/associatedPolicies', method : 'GET', isArray: true}, + 'dependentPolicies' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/policy/:id/dependentPolicies', method : 'GET', isArray: true}, + 'scopes' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/policy/:id/scopes', method : 'GET', isArray: true}, + 'resources' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/policy/:id/resources', method : 'GET', isArray: true} + }); +}); + +module.factory('ResourceServerPermission', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/permission/:type/:id', { + realm : '@realm', + client: '@client', + type: '@type', + id : '@id' + }, { + 'update' : {method : 'PUT'}, + 'search' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/permission/search', method : 'GET'}, + 'searchPolicies' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/policy', method : 'GET', isArray: true}, + 'associatedPolicies' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/policy/:id/associatedPolicies', method : 'GET', isArray: true}, + 'dependentPolicies' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/policy/:id/dependentPolicies', method : 'GET', isArray: true}, + 'scopes' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/permission/:id/scopes', method : 'GET', isArray: true}, + 'resources' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/permission/:id/resources', method : 'GET', isArray: true} + }); +}); + +module.factory('PolicyProvider', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/policy/providers', { + realm : '@realm', + client: '@client' + }); +}); + +module.service('AuthzDialog', function($modal) { + var dialog = {}; + + var openDialog = function(title, message, btns, template) { + var controller = function($scope, $modalInstance, $sce, title, message, btns) { + $scope.title = title; + $scope.message = $sce.trustAsHtml(message); + $scope.btns = btns; + + $scope.ok = function () { + $modalInstance.close(); + }; + $scope.cancel = function () { + $modalInstance.dismiss('cancel'); + }; + }; + + return $modal.open({ + templateUrl: resourceUrl + template, + controller: controller, + resolve: { + title: function() { + return title; + }, + message: function() { + return message; + }, + btns: function() { + return btns; + } + } + }).result; + } + + dialog.confirmDeleteWithMsg = function(name, type, msg, success) { + var title = 'Delete ' + type; + msg += 'Are you sure you want to permanently delete the ' + type + ' ' + name + ' ?'; + var btns = { + ok: { + label: 'Delete', + cssClass: 'btn btn-danger' + }, + cancel: { + label: 'Cancel', + cssClass: 'btn btn-default' + } + } + + openDialog(title, msg, btns, '/templates/authz/kc-authz-modal.html').then(success); + }; + + dialog.confirmDelete = function(name, type, success) { + var title = 'Delete ' + type; + var msg = 'Are you sure you want to permanently delete the ' + type + ' ' + name + ' ?'; + var btns = { + ok: { + label: 'Delete', + cssClass: 'btn btn-danger' + }, + cancel: { + label: 'Cancel', + cssClass: 'btn btn-default' + } + } + + openDialog(title, msg, btns, '/templates/authz/kc-authz-modal.html').then(success); + } + + return dialog; +}); + +module.factory('RoleManagementPermissions', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role/management/permissions', { + realm : '@realm', + role : '@role' + }, { + update: { + method: 'PUT' + } + }); +}); + +module.factory('UsersManagementPermissions', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users-management-permissions', { + realm : '@realm' + }, { + update: { + method: 'PUT' + } + }); +}); + +module.factory('ClientManagementPermissions', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/management/permissions', { + realm : '@realm', + client : '@client' + }, { + update: { + method: 'PUT' + } + }); +}); + +module.factory('IdentityProviderManagementPermissions', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/identity-provider/instances/:alias/management/permissions', { + realm : '@realm', + alias : '@alias' + }, { + update: { + method: 'PUT' + } + }); +}); + +module.factory('GroupManagementPermissions', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/groups/:group/management/permissions', { + realm : '@realm', + group : '@group' + }, { + update: { + method: 'PUT' + } + }); +}); + +module.factory('policyViewState', [function () { + return { + model: { + state: {} + } + }; +}]); + +module.factory('viewState', [function () { + return { + model: { + state: {} + } + }; +}]); + diff --git a/keycloak-themes/base/admin/resources/js/controllers/clients.js b/keycloak-themes/base/admin/resources/js/controllers/clients.js new file mode 100644 index 0000000..3ef1b95 --- /dev/null +++ b/keycloak-themes/base/admin/resources/js/controllers/clients.js @@ -0,0 +1,4023 @@ +Array.prototype.remove = function(from, to) { + var rest = this.slice((to || from) + 1 || this.length); + this.length = from < 0 ? this.length + from : from; + return this.push.apply(this, rest); +}; + +module.controller('ClientTabCtrl', function(Dialog, $scope, Current, Notifications, $location) { + $scope.removeClient = function() { + Dialog.confirmDelete($scope.client.clientId, 'client', function() { + $scope.client.$remove({ + realm : Current.realm.realm, + client : $scope.client.id + }, function() { + $location.url("/realms/" + Current.realm.realm + "/clients"); + Notifications.success("The client has been deleted."); + }); + }); + }; +}); + +module.controller('ClientRoleListCtrl', function($scope, $route, realm, client, ClientRoleList, RoleById, Notifications, Dialog) { + $scope.realm = realm; + $scope.roles = []; + $scope.client = client; + + $scope.query = { + realm: realm.realm, + client: $scope.client.id, + search : null, + max : 20, + first : 0 + } + + $scope.$watch('query.search', function (newVal, oldVal) { + if($scope.query.search && $scope.query.search.length >= 3) { + $scope.firstPage(); + } + }, true); + + $scope.firstPage = function() { + $scope.query.first = 0; + $scope.searchQuery(); + } + + $scope.previousPage = function() { + $scope.query.first -= parseInt($scope.query.max); + if ($scope.query.first < 0) { + $scope.query.first = 0; + } + $scope.searchQuery(); + } + + $scope.nextPage = function() { + $scope.query.first += parseInt($scope.query.max); + $scope.searchQuery(); + } + + $scope.searchQuery = function() { + $scope.searchLoaded = false; + + $scope.roles = ClientRoleList.query($scope.query, function() { + $scope.searchLoaded = true; + $scope.lastSearch = $scope.query.search; + }); + }; + + $scope.searchQuery(); + + $scope.removeRole = function(role) { + Dialog.confirmDelete(role.name, 'role', function() { + RoleById.remove({ + realm: realm.realm, + role: role.id + }, function () { + $route.reload(); + Notifications.success("The role has been deleted."); + }); + }); + }; +}); + +module.controller('ClientCredentialsCtrl', function($scope, $location, realm, client, clientAuthenticatorProviders, clientConfigProperties, Client, ClientRegistrationAccessToken, Notifications) { + $scope.realm = realm; + $scope.client = angular.copy(client); + $scope.clientAuthenticatorProviders = clientAuthenticatorProviders; + + var updateCurrentPartial = function(val) { + $scope.clientAuthenticatorConfigPartial; + switch(val) { + case 'client-secret': + $scope.clientAuthenticatorConfigPartial = 'client-credentials-secret.html'; + break; + case 'client-jwt': + $scope.clientAuthenticatorConfigPartial = 'client-credentials-jwt.html'; + break; + case 'client-secret-jwt': + $scope.clientAuthenticatorConfigPartial = 'client-credentials-secret-jwt.html'; + break; + case 'client-x509': + $scope.clientAuthenticatorConfigPartial = 'client-credentials-x509.html'; + break; + default: + $scope.currentAuthenticatorConfigProperties = clientConfigProperties[val]; + $scope.clientAuthenticatorConfigPartial = 'client-credentials-generic.html'; + break; + } + }; + + updateCurrentPartial(client.clientAuthenticatorType); + + $scope.$watch('client.clientAuthenticatorType', function() { + if (!angular.equals($scope.client.clientAuthenticatorType, client.clientAuthenticatorType)) { + + Client.update({ + realm : realm.realm, + client : client.id + }, $scope.client, function() { + $scope.changed = false; + client = angular.copy($scope.client); + updateCurrentPartial(client.clientAuthenticatorType) + }); + + } + }, true); + + $scope.regenerateRegistrationAccessToken = function() { + var secret = ClientRegistrationAccessToken.update({ realm : $scope.realm.realm, client : $scope.client.id }, + function(data) { + Notifications.success('The registration access token has been updated.'); + $scope.client['registrationAccessToken'] = data.registrationAccessToken; + }, + function() { + Notifications.error('Failed to update the registration access token'); + } + ); + }; +}); + +module.controller('ClientSecretCtrl', function($scope, $location, Client, ClientSecret, Notifications, $route) { + + var secret = ClientSecret.get({ realm : $scope.realm.realm, client : $scope.client.id }, + function() { + $scope.secret = secret.value; + } + ); + + $scope.changePassword = function() { + var secret = ClientSecret.update({ realm : $scope.realm.realm, client : $scope.client.id }, + function() { + $route.reload(); + Notifications.success('The secret has been changed.'); + }, + function() { + Notifications.error("The secret was not changed due to a problem."); + $scope.secret = "error"; + } + ); + }; + + $scope.removeRotatedSecret = function(){ + ClientSecret.invalidate({realm: $scope.realm.realm, client: $scope.client.id }, + function(){ + $route.reload(); + Notifications.success('The rotated secret has been invalidated.'); + }, + function(){ + Notifications.error("The rotated secret was not invalidated due to a problem."); + } + ); + }; + + $scope.tokenEndpointAuthSigningAlg = $scope.client.attributes['token.endpoint.auth.signing.alg']; + + if ($scope.client.attributes['client.secret.expiration.time']){ + $scope.secret_expiration_time = $scope.client.attributes['client.secret.expiration.time'] * 1000; + } + + if ($scope.client.attributes["client.secret.rotated"]) { + $scope.secretRotated = $scope.client.attributes["client.secret.rotated"]; + } + + if ($scope.client.attributes['client.secret.rotated.expiration.time']){ + $scope.rotated_secret_expiration_time = $scope.client.attributes['client.secret.rotated.expiration.time'] * 1000; + } + + $scope.switchChange = function() { + $scope.changed = true; + } + + $scope.save = function() { + $scope.client.attributes['token.endpoint.auth.signing.alg'] = $scope.tokenEndpointAuthSigningAlg; + + Client.update({ + realm : $scope.realm.realm, + client : $scope.client.id + }, $scope.client, function() { + $scope.changed = false; + $scope.clientCopy = angular.copy($scope.client); + Notifications.success("Client authentication configuration has been saved to the client."); + }); + }; + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); + + $scope.cancel = function() { + $location.url("/realms/" + $scope.realm.realm + "/clients/" + $scope.client.id + "/credentials"); + $route.reload(); + }; + +}); + +module.controller('ClientX509Ctrl', function($scope, $location, Client, Notifications) { + console.log('ClientX509Ctrl invoked'); + + $scope.clientCopy = angular.copy($scope.client); + $scope.changed = false; + + $scope.$watch('client', function() { + if (!angular.equals($scope.client, $scope.clientCopy)) { + $scope.changed = true; + } + }, true); + + function updateProperties() { + if ($scope.client.attributes["x509.allow.regex.pattern.comparison"]) { + if ($scope.client.attributes["x509.allow.regex.pattern.comparison"] == "true") { + $scope.allowRegexPatternComparison = true; + } else { + $scope.allowRegexPatternComparison = false; + } + } + } + + updateProperties(); + + $scope.switchChange = function() { + $scope.changed = true; + } + + $scope.save = function() { + if ($scope.allowRegexPatternComparison == true) { + $scope.client.attributes["x509.allow.regex.pattern.comparison"] = "true"; + } else { + $scope.client.attributes["x509.allow.regex.pattern.comparison"] = "false"; + } + + if (!$scope.client.attributes["x509.subjectdn"]) { + Notifications.error("The SubjectDN must not be empty."); + } else { + Client.update({ + realm : $scope.realm.realm, + client : $scope.client.id + }, $scope.client, function() { + $scope.changed = false; + $scope.clientCopy = angular.copy($scope.client); + Notifications.success("Client authentication configuration has been saved to the client."); + }, function() { + Notifications.error("The SubjectDN was not changed due to a problem."); + $scope.subjectdn = "error"; + }); + } + }; + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); + + $scope.reset = function() { + $scope.client.attributes["x509.subjectdn"] = $scope.clientCopy.attributes["x509.subjectdn"]; + $scope.client.attributes["x509.allow.regex.pattern.comparison"] = $scope.clientCopy.attributes["x509.allow.regex.pattern.comparison"]; + updateProperties(); + $location.url("/realms/" + $scope.realm.realm + "/clients/" + $scope.client.id + "/credentials"); + }; +}); + +module.controller('ClientSignedJWTCtrl', function($scope, Client, Notifications) { + console.log('ClientSignedJWTCtrl invoked'); + + $scope.tokenEndpointAuthSigningAlg = $scope.client.attributes['token.endpoint.auth.signing.alg']; + + $scope.$watch('tokenEndpointAuthSigningAlg', function() { + if (!angular.equals($scope.client.attributes['token.endpoint.auth.signing.alg'], $scope.tokenEndpointAuthSigningAlg)) { + $scope.client.attributes['token.endpoint.auth.signing.alg'] = $scope.tokenEndpointAuthSigningAlg; + + Client.update({ + realm : $scope.realm.realm, + client : $scope.client.id + }, $scope.client, function() { + Notifications.success("Signature algorithm has been saved to the client."); + }); + } + }, true); + +}); + +module.controller('ClientGenericCredentialsCtrl', function($scope, $location, Client, Notifications) { + + console.log('ClientGenericCredentialsCtrl invoked'); + + $scope.clientCopy = angular.copy($scope.client); + $scope.changed = false; + + $scope.$watch('client', function() { + if (!angular.equals($scope.client, $scope.clientCopy)) { + $scope.changed = true; + } + }, true); + + $scope.save = function() { + + Client.update({ + realm : $scope.realm.realm, + client : $scope.client.id + }, $scope.client, function() { + $scope.changed = false; + $scope.clientCopy = angular.copy($scope.client); + Notifications.success("Client authentication configuration has been saved to the client."); + }); + }; + + $scope.reset = function() { + $scope.client = angular.copy($scope.clientCopy); + $scope.changed = false; + }; +}); + +module.controller('ClientIdentityProviderCtrl', function($scope, $location, $route, realm, client, Client, $location, Notifications) { + $scope.realm = realm; + $scope.client = angular.copy(client); + var length = 0; + + if ($scope.client.identityProviders) { + length = $scope.client.identityProviders.length; + + for (i = 0; i < $scope.client.identityProviders.length; i++) { + var clientProvider = $scope.client.identityProviders[i]; + if (clientProvider.retrieveToken) { + clientProvider.retrieveToken = clientProvider.retrieveToken.toString(); + } + } + + } else { + $scope.client.identityProviders = []; + } + + $scope.identityProviders = []; + var providersMissingInClient = []; + + for (j = 0; j < realm.identityProviders.length; j++) { + var identityProvider = realm.identityProviders[j]; + var clientProvider = null; + + for (i = 0; i < $scope.client.identityProviders.length; i++) { + clientProvider = $scope.client.identityProviders[i]; + + if (clientProvider) { + + if (clientProvider.id == identityProvider.id) { + $scope.identityProviders[i] = {}; + $scope.identityProviders[i].identityProvider = identityProvider; + $scope.identityProviders[i].retrieveToken = clientProvider.retrieveToken; + break; + } + + clientProvider = null; + } + } + + if (clientProvider == null) { + providersMissingInClient.push(identityProvider); + } + } + + for (j = 0; j < providersMissingInClient.length; j++) { + var identityProvider = providersMissingInClient[j]; + + var currentProvider = {}; + currentProvider.identityProvider = identityProvider; + currentProvider.retrieveToken = "false"; + $scope.identityProviders.push(currentProvider); + + var currentClientProvider = {}; + currentClientProvider.id = identityProvider.id; + currentClientProvider.retrieveToken = "false"; + $scope.client.identityProviders.push(currentClientProvider); + } + + var oldCopy = angular.copy($scope.client); + + $scope.save = function() { + + Client.update({ + realm : realm.realm, + client : client.id + }, $scope.client, function() { + $scope.changed = false; + $route.reload(); + Notifications.success("Your changes have been saved to the client."); + }); + }; + + $scope.reset = function() { + $scope.client = angular.copy(oldCopy); + $scope.changed = false; + }; + + $scope.$watch('client', function() { + if (!angular.equals($scope.client, oldCopy)) { + $scope.changed = true; + } + }, true); +}); + +module.controller('ClientSamlKeyCtrl', function($scope, $location, $http, $upload, realm, client, + ClientCertificate, ClientCertificateGenerate, + ClientCertificateDownload, Notifications) { + $scope.realm = realm; + $scope.client = client; + + var signingKeyInfo = ClientCertificate.get({ realm : realm.realm, client : client.id, attribute: 'saml.signing' }, + function() { + $scope.signingKeyInfo = signingKeyInfo; + } + ); + + $scope.generateSigningKey = function() { + var keyInfo = ClientCertificateGenerate.generate({ realm : realm.realm, client : client.id, attribute: 'saml.signing' }, + function() { + Notifications.success('Signing key has been regenerated.'); + $scope.signingKeyInfo = keyInfo; + }, + function() { + Notifications.error("Signing key was not regenerated."); + } + ); + }; + + $scope.importSigningKey = function() { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/saml/Signing/import/saml.signing"); + }; + + $scope.exportSigningKey = function() { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/saml/Signing/export/saml.signing"); + }; + + var encryptionKeyInfo = ClientCertificate.get({ realm : realm.realm, client : client.id, attribute: 'saml.encryption' }, + function() { + $scope.encryptionKeyInfo = encryptionKeyInfo; + } + ); + + $scope.generateEncryptionKey = function() { + var keyInfo = ClientCertificateGenerate.generate({ realm : realm.realm, client : client.id, attribute: 'saml.encryption' }, + function() { + Notifications.success('Encryption key has been regenerated.'); + $scope.encryptionKeyInfo = keyInfo; + }, + function() { + Notifications.error("Encryption key was not regenerated."); + } + ); + }; + + $scope.importEncryptionKey = function() { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/saml/Encryption/import/saml.encryption"); + }; + + $scope.exportEncryptionKey = function() { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/saml/Encryption/export/saml.encryption"); + }; + + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); +}); + +module.controller('ClientCertificateImportCtrl', function($scope, $location, $http, $upload, realm, client, callingContext, $routeParams, + ClientCertificate, ClientCertificateGenerate, + ClientCertificateDownload, Notifications) { + + console.log("callingContext: " + callingContext); + + var keyType = $routeParams.keyType; + var attribute = $routeParams.attribute; + $scope.realm = realm; + $scope.client = client; + $scope.keyType = keyType; + + if (callingContext == 'saml') { + var uploadUrl = authUrl + '/admin/realms/' + realm.realm + '/clients/' + client.id + '/certificates/' + attribute + '/upload'; + var redirectLocation = "/realms/" + realm.realm + "/clients/" + client.id + "/saml/keys"; + } else if (callingContext == 'oidc') { + var uploadUrl = authUrl + '/admin/realms/' + realm.realm + '/clients/' + client.id + '/certificates/' + attribute + '/upload-certificate'; + var redirectLocation = "/realms/" + realm.realm + "/clients/" + client.id + "/oidc/keys"; + } + + $scope.files = []; + + $scope.onFileSelect = function($files) { + $scope.files = $files; + }; + + $scope.cancel = function() { + $location.url(redirectLocation); + } + + $scope.keyFormats = [ + "JKS", + "PKCS12", + "Certificate PEM" + ]; + + if (callingContext == 'oidc') { + $scope.keyFormats.push('Public Key PEM'); + $scope.keyFormats.push('JSON Web Key Set'); + } + + $scope.hideKeystoreSettings = function() { + return $scope.uploadKeyFormat == 'Certificate PEM' || $scope.uploadKeyFormat == 'Public Key PEM' || $scope.uploadKeyFormat == 'JSON Web Key Set'; + } + + $scope.uploadKeyFormat = $scope.keyFormats[0]; + + $scope.uploadFile = function() { + //$files: an array of files selected, each file has name, size, and type. + for (var i = 0; i < $scope.files.length; i++) { + var $file = $scope.files[i]; + $scope.upload = $upload.upload({ + url: uploadUrl, + // method: POST or PUT, + // headers: {'headerKey': 'headerValue'}, withCredential: true, + data: {keystoreFormat: $scope.uploadKeyFormat, + keyAlias: $scope.uploadKeyAlias, + keyPassword: $scope.uploadKeyPassword, + storePassword: $scope.uploadStorePassword + }, + file: $file + /* set file formData name for 'Content-Desposition' header. Default: 'file' */ + //fileFormDataName: myFile, + /* customize how data is added to formData. See #40#issuecomment-28612000 for example */ + //formDataAppender: function(formData, key, val){} + }).then(function(data, status, headers) { + Notifications.success("Keystore uploaded successfully."); + $location.url(redirectLocation); + }) + //.then(success, error, progress); + } + }; + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); +}); + +module.controller('ClientCertificateExportCtrl', function($scope, $location, $http, $upload, realm, client, callingContext, $routeParams, + ClientCertificate, ClientCertificateGenerate, + ClientCertificateDownload, Notifications) { + var keyType = $routeParams.keyType; + var attribute = $routeParams.attribute; + $scope.realm = realm; + $scope.client = client; + $scope.keyType = keyType; + + if (callingContext == 'saml') { + var downloadUrl = authUrl + '/admin/realms/' + realm.realm + '/clients/' + client.id + '/certificates/' + attribute + '/download'; + var realmCertificate = true; + } else if (callingContext == 'oidc') { + var downloadUrl = authUrl + '/admin/realms/' + realm.realm + '/clients/' + client.id + '/certificates/' + attribute + '/generate-and-download' + var realmCertificate = false; + } + + var jks = { + keyAlias: client.clientId, + realmAlias: realm.realm, + realmCertificate: realmCertificate + }; + + $scope.keyFormats = [ + "JKS", + "PKCS12" + ]; + + var keyInfo = ClientCertificate.get({ realm : realm.realm, client : client.id, attribute: attribute }, + function() { + $scope.keyInfo = keyInfo; + } + ); + $scope.jks = jks; + $scope.jks.format = $scope.keyFormats[0]; + + $scope.download = function() { + $http({ + url: downloadUrl, + method: 'POST', + responseType: 'arraybuffer', + data: $scope.jks, + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/octet-stream' + } + }).then(function(response){ + var blob = new Blob([response.data], { + type: 'application/octet-stream' + }); + var ext = ".jks"; + if ($scope.jks.format == 'PKCS12') ext = ".p12"; + + if (callingContext == 'oidc') { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/oidc/keys"); + Notifications.success("New keypair and certificate generated successfully. Download keystore file") + } + + saveAs(blob, 'keystore' + ext); + }).catch(function(response) { + var errorMsg = 'Error downloading'; + try { + var error = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(response.data))); + errorMsg = error['error_description'] ? error['error_description'] : errorMsg; + } catch (err) { + } + Notifications.error(errorMsg); + }); + } + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); + + $scope.cancel = function() { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/oidc/keys"); + } +}); + +module.controller('ClientOidcKeyCtrl', function($scope, $location, realm, client, Client, ClientCertificate, Notifications, $route) { + $scope.realm = realm; + $scope.client = angular.copy(client); + + var signingKeyInfo = ClientCertificate.get({ realm : realm.realm, client : client.id, attribute: 'jwt.credential' }, + function() { + $scope.signingKeyInfo = signingKeyInfo; + } + ); + + $scope.changed = false; + + $scope.$watch('client', function() { + if (!angular.equals($scope.client, client)) { + $scope.changed = true; + } + }, true); + + if ($scope.client.attributes["use.jwks.url"]) { + if ($scope.client.attributes["use.jwks.url"] == "true") { + $scope.useJwksUrl = true; + } else { + $scope.useJwksUrl = false; + } + } + + if ($scope.client.attributes["use.jwks.string"]) { + if ($scope.client.attributes["use.jwks.string"] == "true") { + $scope.useJwksString = true; + } else { + $scope.useJwksString = false; + } + } + + $scope.jwksUrlSwitchChange = function() { + $scope.changed = true; + if ($scope.useJwksUrl == false) { + $scope.useJwksString = false; + } + } + + $scope.jwksStringSwitchChange = function() { + $scope.changed = true; + if ($scope.useJwksString == false) { + $scope.useJwksUrl = false; + } + } + + $scope.save = function() { + + if ($scope.useJwksUrl == true) { + $scope.client.attributes["use.jwks.url"] = "true"; + } else { + $scope.client.attributes["use.jwks.url"] = "false"; + } + + if ($scope.useJwksString == true) { + $scope.client.attributes["use.jwks.string"] = "true"; + } else { + $scope.client.attributes["use.jwks.string"] = "false"; + } + + Client.update({ + realm : realm.realm, + client : client.id + }, $scope.client, function() { + $scope.changed = false; + client = angular.copy($scope.client); + Notifications.success("OIDC key has been saved to the client."); + }); + }; + + $scope.importCertificate = function() { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/oidc/Signing/import/jwt.credential"); + }; + + $scope.generateSigningKey = function() { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/oidc/Signing/export/jwt.credential"); + }; + + $scope.reset = function() { + $route.reload(); + }; +}); + +module.controller('ClientSessionsCtrl', function($scope, realm, sessionCount, client, + ClientUserSessions) { + $scope.realm = realm; + $scope.count = sessionCount.count; + $scope.sessions = []; + $scope.client = client; + + $scope.page = 0; + + $scope.query = { + realm : realm.realm, + client: $scope.client.id, + max : 5, + first : 0 + } + + $scope.firstPage = function() { + $scope.query.first = 0; + if ($scope.query.first < 0) { + $scope.query.first = 0; + } + $scope.loadUsers(); + } + + $scope.previousPage = function() { + $scope.query.first -= parseInt($scope.query.max); + if ($scope.query.first < 0) { + $scope.query.first = 0; + } + $scope.loadUsers(); + } + + $scope.nextPage = function() { + $scope.query.first += parseInt($scope.query.max); + $scope.loadUsers(); + } + + $scope.toDate = function(val) { + return new Date(val); + }; + + $scope.loadUsers = function() { + ClientUserSessions.query($scope.query, function(updated) { + $scope.sessions = updated; + }) + }; +}); + +module.controller('ClientOfflineSessionsCtrl', function($scope, realm, offlineSessionCount, client, + ClientOfflineSessions) { + $scope.realm = realm; + $scope.count = offlineSessionCount.count; + $scope.sessions = []; + $scope.client = client; + + $scope.page = 0; + + $scope.query = { + realm : realm.realm, + client: $scope.client.id, + max : 5, + first : 0 + } + + $scope.firstPage = function() { + $scope.query.first = 0; + if ($scope.query.first < 0) { + $scope.query.first = 0; + } + $scope.loadUsers(); + } + + $scope.previousPage = function() { + $scope.query.first -= parseInt($scope.query.max); + if ($scope.query.first < 0) { + $scope.query.first = 0; + } + $scope.loadUsers(); + } + + $scope.nextPage = function() { + $scope.query.first += parseInt($scope.query.max); + $scope.loadUsers(); + } + + $scope.toDate = function(val) { + return new Date(val); + }; + + $scope.loadUsers = function() { + ClientOfflineSessions.query($scope.query, function(updated) { + $scope.sessions = updated; + }) + }; +}); + +module.controller('ClientRoleDetailCtrl', function($scope, $route, realm, client, role, roles, Client, + Role, ClientRole, RoleById, RoleRealmComposites, RoleClientComposites, + $http, $location, Dialog, Notifications, ComponentUtils) { + $scope.realm = realm; + $scope.client = client; + $scope.role = angular.copy(role); + $scope.create = !role.name; + + $scope.changed = $scope.create; + + $scope.save = function() { + convertAttributeValuesToLists(); + if ($scope.create) { + ClientRole.save({ + realm: realm.realm, + client : client.id + }, $scope.role, function (data, headers) { + $scope.changed = false; + convertAttributeValuesToString($scope.role); + role = angular.copy($scope.role); + + ClientRole.get({ realm: realm.realm, client : client.id, role: role.name }, function(role) { + var id = role.id; + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/roles/" + id); + Notifications.success("The role has been created."); + }); + }); + } else { + $scope.update(); + } + }; + + $scope.remove = function() { + Dialog.confirmDelete($scope.role.name, 'role', function() { + $scope.role.$remove({ + realm : realm.realm, + client : client.id, + role : $scope.role.id + }, function() { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/roles"); + Notifications.success("The role has been deleted."); + }); + }); + }; + + $scope.cancel = function () { + $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/roles"); + }; + + $scope.addAttribute = function() { + $scope.role.attributes[$scope.newAttribute.key] = $scope.newAttribute.value; + delete $scope.newAttribute; + } + + $scope.removeAttribute = function(key) { + delete $scope.role.attributes[key]; + } + + function convertAttributeValuesToLists() { + var attrs = $scope.role.attributes; + for (var attribute in attrs) { + if (typeof attrs[attribute] === "string") { + var attrVals = attrs[attribute].split("##"); + attrs[attribute] = attrVals; + } + } + } + + function convertAttributeValuesToString(role) { + var attrs = role.attributes; + for (var attribute in attrs) { + if (typeof attrs[attribute] === "object") { + var attrVals = attrs[attribute].join("##"); + attrs[attribute] = attrVals; + } + } + } + + roleControl($scope, $route, realm, role, roles, Client, + ClientRole, RoleById, RoleRealmComposites, RoleClientComposites, + $http, $location, Notifications, Dialog, ComponentUtils); + +}); + +module.controller('ClientRoleMembersCtrl', function($scope, realm, client, role, ClientRoleMembership, Dialog, Notifications, $location) { + $scope.realm = realm; + $scope.page = 0; + $scope.role = role; + $scope.client = client; + + $scope.query = { + realm: realm.realm, + role: role.name, + client: client.id, + max : 5, + first : 0 + } + + $scope.firstPage = function() { + $scope.query.first = 0; + $scope.searchQuery(); + } + + $scope.previousPage = function() { + $scope.query.first -= parseInt($scope.query.max); + if ($scope.query.first < 0) { + $scope.query.first = 0; + } + $scope.searchQuery(); + } + + $scope.nextPage = function() { + $scope.query.first += parseInt($scope.query.max); + $scope.searchQuery(); + } + + $scope.searchQuery = function() { + $scope.searchLoaded = false; + + $scope.users = ClientRoleMembership.query($scope.query, function() { + console.log('search loaded'); + $scope.searchLoaded = true; + $scope.lastSearch = $scope.query.search; + }); + }; + + $scope.searchQuery(); +}); + +module.controller('ClientImportCtrl', function($scope, $location, $upload, realm, serverInfo, Notifications) { + + $scope.realm = realm; + + $scope.files = []; + + $scope.onFileSelect = function($files) { + $scope.files = $files; + }; + + $scope.clearFileSelect = function() { + $scope.files = null; + } + + $scope.uploadFile = function() { + //$files: an array of files selected, each file has name, size, and type. + for (var i = 0; i < $scope.files.length; i++) { + var $file = $scope.files[i]; + $scope.upload = $upload.upload({ + url: authUrl + '/admin/realms/' + realm.realm + '/client-importers/' + $scope.configFormat.id + '/upload', + // method: POST or PUT, + // headers: {'headerKey': 'headerValue'}, withCredential: true, + data: {myObj: ""}, + file: $file + /* set file formData name for 'Content-Desposition' header. Default: 'file' */ + //fileFormDataName: myFile, + /* customize how data is added to formData. See #40#issuecomment-28612000 for example */ + //formDataAppender: function(formData, key, val){} + }).success(function(data, status, headers) { + Notifications.success("Uploaded successfully."); + $location.url("/realms/" + realm.realm + "/clients"); + }) + .error(function() { + Notifications.error("The file can not be uploaded. Please verify the file."); + + }); + //.then(success, error, progress); + } + }; + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); +}); + + +module.controller('ClientListCtrl', function($scope, realm, Client, ClientListSearchState, $route, Dialog, Notifications) { + $scope.init = function() { + $scope.realm = realm; + $scope.searchLoaded = true; + + ClientListSearchState.query.realm = realm.realm; + $scope.query = ClientListSearchState.query; + + if (!ClientListSearchState.isFirstSearch) { + $scope.searchQuery(); + } else { + $scope.query.clientId = null; + $scope.firstPage(); + } + }; + + $scope.searchQuery = function() { + console.log("query.search: ", $scope.query); + $scope.searchLoaded = false; + + $scope.clients = Client.query($scope.query, function() { + $scope.searchLoaded = true; + $scope.lastSearch = $scope.query.search; + ClientListSearchState.isFirstSearch = false; + }); + }; + + $scope.firstPage = function() { + $scope.query.first = 0; + $scope.searchQuery(); + } + + $scope.previousPage = function() { + $scope.query.first -= parseInt($scope.query.max); + if ($scope.query.first < 0) { + $scope.query.first = 0; + } + $scope.searchQuery(); + } + + $scope.nextPage = function() { + $scope.query.first += parseInt($scope.query.max); + $scope.searchQuery(); + } + + $scope.removeClient = function(client) { + Dialog.confirmDelete(client.clientId, 'client', function() { + Client.remove({ + realm : realm.realm, + client : client.id + }, function() { + $route.reload(); + Notifications.success("The client has been deleted."); + }); + }); + }; + + $scope.exportClient = function(client) { + var clientCopy = angular.copy(client); + delete clientCopy.id; + + if (clientCopy.protocolMappers) { + for (var i = 0; i < clientCopy.protocolMappers.length; i++) { + delete clientCopy.protocolMappers[i].id; + } + } + + saveAs(new Blob([angular.toJson(clientCopy, 4)], { type: 'application/json' }), clientCopy.clientId + '.json'); + } +}); + +module.controller('ClientInstallationCtrl', function($scope, realm, client, serverInfo, ClientInstallation,$http, $routeParams) { + $scope.realm = realm; + $scope.client = client; + $scope.installation = null; + $scope.download = null; + $scope.configFormat = null; + $scope.filename = null; + + var protocol = client.protocol; + if (!protocol) protocol = 'openid-connect'; + $scope.configFormats = serverInfo.clientInstallations[protocol]; + console.log('configFormats.length: ' + $scope.configFormats.length); + + $scope.changeFormat = function() { + var url = ClientInstallation.url({ realm: $routeParams.realm, client: $routeParams.client, provider: $scope.configFormat.id }); + if ($scope.configFormat.mediaType == 'application/zip') { + $http({ + url: url, + method: 'GET', + responseType: 'arraybuffer', + cache: false + }).then(function(response) { + var installation = response.data; + $scope.installation = installation; + } + ); + } else { + $http.get(url).then(function (response) { + var installation = response.data; + if ($scope.configFormat.mediaType == 'application/json') { + installation = angular.fromJson(response.data); + installation = angular.toJson(installation, true); + } + $scope.installation = installation; + }); + } + + }; + $scope.download = function() { + saveAs(new Blob([$scope.installation], { type: $scope.configFormat.mediaType }), $scope.configFormat.filename); + } +}); + + +module.controller('ClientDetailCtrl', function($scope, realm, client, flows, $route, serverInfo, Client, ClientDescriptionConverter, Components, ClientStorageOperations, $location, $modal, Dialog, Notifications, TimeUnit2) { + $scope.serverInfo = serverInfo; + $scope.flows = []; + $scope.clientFlows = []; + var emptyFlow = { + id: "", + alias: "" + } + for (var i=0 ; i 0) { + $scope.client.requestUris = $scope.client.attributes["request.uris"].split("##"); + } else { + $scope.client.requestUris = []; + } + + if ($scope.client.attributes["default.acr.values"] && $scope.client.attributes["default.acr.values"].length > 0) { + $scope.defaultAcrValues = $scope.client.attributes["default.acr.values"].split("##"); + } else { + $scope.defaultAcrValues = []; + } + deletedSomeDefaultAcrValue = false; + + try { + $scope.acrLoaMap = JSON.parse($scope.client.attributes["acr.loa.map"] || "{}"); + } catch (e) { + $scope.acrLoaMap = {}; + } + } + + if (!$scope.create) { + $scope.client = client; + updateProperties(); + + $scope.clientEdit = angular.copy(client); + } + + + $scope.samlIdpInitiatedUrl = function(ssoName) { + return encodeURI($location.absUrl().replace(/\/admin.*/, "/realms/") + realm.realm + "/protocol/saml/clients/") + encodeURIComponent(ssoName) + } + + $scope.importFile = function(fileContent){ + console.debug(fileContent); + ClientDescriptionConverter.save({ + realm: realm.realm + }, fileContent, function (data) { + $scope.client = data; + updateProperties(); + $scope.importing = true; + + $scope.clientEdit = angular.copy(client); + }); + }; + + $scope.viewImportDetails = function() { + $modal.open({ + templateUrl: resourceUrl + '/partials/modal/view-object.html', + controller: 'ObjectModalCtrl', + resolve: { + object: function () { + return $scope.client; + } + } + }) + }; + + $scope.switchChange = function() { + $scope.changed = true; + } + + $scope.changeAccessType = function() { + if ($scope.accessType == "confidential") { + $scope.clientEdit.bearerOnly = false; + $scope.clientEdit.publicClient = false; + } else if ($scope.accessType == "public") { + $scope.clientEdit.bearerOnly = false; + $scope.clientEdit.publicClient = true; + } else if ($scope.accessType == "bearer-only") { + $scope.clientEdit.bearerOnly = true; + $scope.clientEdit.publicClient = false; + $scope.clientEdit.alwaysDisplayInConsole = false; + } + }; + + $scope.changeProtocol = function() { + if ($scope.protocol == "openid-connect") { + $scope.clientEdit.protocol = "openid-connect"; + } else if ($scope.protocol == "saml") { + $scope.clientEdit.protocol = "saml"; + } + }; + + $scope.changeAlgorithm = function() { + $scope.clientEdit.attributes['saml.signature.algorithm'] = $scope.signatureAlgorithm; + }; + + $scope.changeNameIdFormat = function() { + $scope.clientEdit.attributes['saml_name_id_format'] = $scope.nameIdFormat; + }; + + $scope.changeSamlSigKeyNameTranformer = function() { + $scope.clientEdit.attributes['saml.server.signature.keyinfo.xmlSigKeyInfoKeyNameTransformer'] = $scope.samlXmlKeyNameTranformer; + }; + + $scope.changeAccessTokenSignedResponseAlg = function() { + $scope.clientEdit.attributes['access.token.signed.response.alg'] = $scope.accessTokenSignedResponseAlg; + }; + + $scope.changeIdTokenSignedResponseAlg = function() { + $scope.clientEdit.attributes['id.token.signed.response.alg'] = $scope.idTokenSignedResponseAlg; + }; + + $scope.changeIdTokenEncryptedResponseAlg = function() { + $scope.clientEdit.attributes['id.token.encrypted.response.alg'] = $scope.idTokenEncryptedResponseAlg; + }; + + $scope.changeIdTokenEncryptedResponseEnc = function() { + $scope.clientEdit.attributes['id.token.encrypted.response.enc'] = $scope.idTokenEncryptedResponseEnc; + }; + + $scope.changeUserInfoSignedResponseAlg = function() { + if ($scope.userInfoSignedResponseAlg === 'unsigned') { + $scope.clientEdit.attributes['user.info.response.signature.alg'] = null; + } else { + $scope.clientEdit.attributes['user.info.response.signature.alg'] = $scope.userInfoSignedResponseAlg; + } + }; + + $scope.changeRequestObjectSignatureAlg = function() { + if ($scope.requestObjectSignatureAlg === 'any') { + $scope.clientEdit.attributes['request.object.signature.alg'] = null; + } else { + $scope.clientEdit.attributes['request.object.signature.alg'] = $scope.requestObjectSignatureAlg; + } + }; + + $scope.changeRequestObjectRequired = function() { + if ($scope.requestObjectRequired === 'not required') { + $scope.clientEdit.attributes['request.object.required'] = null; + } else { + $scope.clientEdit.attributes['request.object.required'] = $scope.requestObjectRequired; + } + }; + + $scope.changeRequestObjectEncryptionAlg = function() { + if ($scope.requestObjectEncryptionAlg === 'any') { + $scope.clientEdit.attributes['request.object.encryption.alg'] = null; + } else { + $scope.clientEdit.attributes['request.object.encryption.alg'] = $scope.requestObjectEncryptionAlg; + } + }; + + $scope.changeRequestObjectEncryptionEnc = function() { + if ($scope.requestObjectEncryptionEnc === 'any') { + $scope.clientEdit.attributes['request.object.encryption.enc'] = null; + } else { + $scope.clientEdit.attributes['request.object.encryption.enc'] = $scope.requestObjectEncryptionEnc; + } + }; + + $scope.changeUserInfoEncryptedResponseAlg = function() { + $scope.clientEdit.attributes['user.info.encrypted.response.alg'] = $scope.userInfoEncryptedResponseAlg; + }; + + $scope.changeUserInfoEncryptedResponseEnc = function() { + $scope.clientEdit.attributes['user.info.encrypted.response.enc'] = $scope.userInfoEncryptedResponseEnc; + }; + + $scope.changePkceCodeChallengeMethod = function() { + $scope.clientEdit.attributes['pkce.code.challenge.method'] = $scope.pkceCodeChallengeMethod; + }; + + $scope.$watch('newAcr', function() { + $scope.changed = isChanged(); + }, true); + $scope.$watch('newLoa', function() { + $scope.changed = isChanged(); + }, true); + $scope.deleteAcrLoaMapping = function(acr) { + delete $scope.acrLoaMap[acr]; + $scope.changed = true; + } + $scope.addAcrLoaMapping = function() { + if ($scope.newLoa.match(/^[0-9]+$/)) { + $scope.acrLoaMap[$scope.newAcr] = $scope.newLoa; + $scope.newAcr = $scope.newLoa = ""; + $scope.changed = true; + } + } + + $scope.changeCibaBackchannelAuthRequestSigningAlg = function() { + if ($scope.cibaBackchannelAuthRequestSigningAlg === 'any') { + $scope.clientEdit.attributes['ciba.backchannel.auth.request.signing.alg'] = null; + } else { + $scope.clientEdit.attributes['ciba.backchannel.auth.request.signing.alg'] = $scope.cibaBackchannelAuthRequestSigningAlg; + } + }; + + $scope.changeCibaBackchannelTokenDeliveryMode = function() { + $scope.clientEdit.attributes['ciba.backchannel.token.delivery.mode'] = $scope.cibaBackchannelTokenDeliveryMode; + }; + + $scope.changeAuthorizationSignedResponseAlg = function() { + $scope.clientEdit.attributes['authorization.signed.response.alg'] = $scope.authorizationSignedResponseAlg; + }; + + $scope.changeAuthorizationEncryptedResponseAlg = function() { + $scope.clientEdit.attributes['authorization.encrypted.response.alg'] = $scope.authorizationEncryptedResponseAlg; + }; + + $scope.changeAuthorizationEncryptedResponseEnc = function() { + $scope.clientEdit.attributes['authorization.encrypted.response.enc'] = $scope.authorizationEncryptedResponseEnc; + }; + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); + + function isChanged() { + if (!angular.equals($scope.client, $scope.clientEdit)) { + return true; + } + if ($scope.newRedirectUri && $scope.newRedirectUri.length > 0) { + return true; + } + if ($scope.newWebOrigin && $scope.newWebOrigin.length > 0) { + return true; + } + if ($scope.newRequestUri && $scope.newRequestUri.length > 0) { + return true; + } + if ($scope.newDefaultAcrValue && $scope.newDefaultAcrValue.length > 0) { + return true; + } + if (deletedSomeDefaultAcrValue) return true; + if ($scope.newAcr && $scope.newAcr.length > 0 && $scope.newLoa && $scope.newLoa.length > 0) { + return true; + } + return false; + } + + $scope.updateTimeouts = function() { + if ($scope.accessTokenLifespan.time) { + if ($scope.accessTokenLifespan.time === -1) { + $scope.clientEdit.attributes['access.token.lifespan'] = -1; + } else { + $scope.clientEdit.attributes['access.token.lifespan'] = $scope.accessTokenLifespan.toSeconds(); + } + } else { + $scope.clientEdit.attributes['access.token.lifespan'] = null; + } + } + + $scope.updateAssertionLifespan = function() { + if ($scope.samlAssertionLifespan.time) { + $scope.clientEdit.attributes['saml.assertion.lifespan'] = $scope.samlAssertionLifespan.toSeconds(); + } else { + $scope.clientEdit.attributes['saml.assertion.lifespan'] = null; + } + } + + $scope.updateClientSessionIdleTimeout = function() { + if ($scope.clientSessionIdleTimeout.time) { + $scope.clientEdit.attributes['client.session.idle.timeout'] = $scope.clientSessionIdleTimeout.toSeconds(); + } else { + $scope.clientEdit.attributes['client.session.idle.timeout'] = null; + } + } + + $scope.updateClientSessionMaxLifespan = function() { + if ($scope.clientSessionMaxLifespan.time) { + $scope.clientEdit.attributes['client.session.max.lifespan'] = $scope.clientSessionMaxLifespan.toSeconds(); + } else { + $scope.clientEdit.attributes['client.session.max.lifespan'] = null; + } + } + + $scope.updateClientOfflineSessionIdleTimeout = function() { + if ($scope.clientOfflineSessionIdleTimeout.time) { + $scope.clientEdit.attributes['client.offline.session.idle.timeout'] = $scope.clientOfflineSessionIdleTimeout.toSeconds(); + } else { + $scope.clientEdit.attributes['client.offline.session.idle.timeout'] = null; + } + } + + $scope.updateClientOfflineSessionMaxLifespan = function() { + if ($scope.clientOfflineSessionMaxLifespan.time) { + $scope.clientEdit.attributes['client.offline.session.max.lifespan'] = $scope.clientOfflineSessionMaxLifespan.toSeconds(); + } else { + $scope.clientEdit.attributes['client.offline.session.max.lifespan'] = null; + } + } + + $scope.updateOauth2DeviceCodeLifespan = function() { + if ($scope.oauth2DeviceCodeLifespan.time) { + $scope.clientEdit.attributes['oauth2.device.code.lifespan'] = $scope.oauth2DeviceCodeLifespan.toSeconds(); + } else { + $scope.clientEdit.attributes['oauth2.device.code.lifespan'] = null; + } + } + + $scope.updateOauth2DevicePollingInterval = function() { + if ($scope.oauth2DevicePollingInterval) { + $scope.clientEdit.attributes['oauth2.device.polling.interval'] = $scope.oauth2DevicePollingInterval; + } else { + $scope.clientEdit.attributes['oauth2.device.polling.interval'] = null; + } + } + + $scope.confirmChangeAuthzSettings = function($event) { + if ($scope.client.authorizationServicesEnabled && $scope.clientEdit.authorizationServicesEnabled) { + $event.preventDefault(); + Dialog.confirm("Disable Authorization Settings", "Are you sure you want to disable authorization ? Once you save your changes, all authorization settings associated with this client will be removed. This operation can not be reverted.", function () { + $scope.clientEdit.authorizationServicesEnabled = false; + }, function () { + $scope.clientEdit.authorizationServicesEnabled = true; + }); + } + } + + function configureAuthorizationServices() { + if ($scope.clientEdit.authorizationServicesEnabled) { + if ($scope.accessType == 'public') { + $scope.accessType = 'confidential'; + } + $scope.clientEdit.publicClient = false; + $scope.clientEdit.serviceAccountsEnabled = true; + } else if ($scope.clientEdit.bearerOnly) { + $scope.clientEdit.serviceAccountsEnabled = false; + } + } + + $scope.$watch('clientEdit', function() { + $scope.changed = isChanged(); + configureAuthorizationServices(); + }, true); + + $scope.$watch('newRedirectUri', function() { + $scope.changed = isChanged(); + }, true); + + + $scope.$watch('newWebOrigin', function() { + $scope.changed = isChanged(); + }, true); + + $scope.$watch('newRequestUri', function() { + $scope.changed = isChanged(); + }, true); + + $scope.$watch('newDefaultAcrValue', function() { + $scope.changed = isChanged(); + }, true); + + $scope.deleteWebOrigin = function(index) { + $scope.clientEdit.webOrigins.splice(index, 1); + } + $scope.addWebOrigin = function() { + $scope.clientEdit.webOrigins.push($scope.newWebOrigin); + $scope.newWebOrigin = ""; + } + $scope.deleteRequestUri = function(index) { + $scope.clientEdit.requestUris.splice(index, 1); + } + $scope.addRequestUri = function() { + $scope.clientEdit.requestUris.push($scope.newRequestUri); + $scope.newRequestUri = ""; + } + $scope.deleteDefaultAcrValue = function(index) { + $scope.defaultAcrValues.splice(index, 1); + deletedSomeDefaultAcrValue = true; + $scope.changed = isChanged(); + } + $scope.addDefaultAcrValue = function() { + $scope.defaultAcrValues.push($scope.newDefaultAcrValue); + $scope.newDefaultAcrValue = ""; + } + $scope.deleteRedirectUri = function(index) { + $scope.clientEdit.redirectUris.splice(index, 1); + } + + $scope.addRedirectUri = function() { + $scope.clientEdit.redirectUris.push($scope.newRedirectUri); + $scope.newRedirectUri = ""; + } + + $scope.save = function() { + if ($scope.newRedirectUri && $scope.newRedirectUri.length > 0) { + $scope.addRedirectUri(); + } + + if ($scope.newWebOrigin && $scope.newWebOrigin.length > 0) { + $scope.addWebOrigin(); + } + + if ($scope.newRequestUri && $scope.newRequestUri.length > 0) { + $scope.addRequestUri(); + } + if ($scope.clientEdit.requestUris && $scope.clientEdit.requestUris.length > 0) { + $scope.clientEdit.attributes["request.uris"] = $scope.clientEdit.requestUris.join("##"); + } else { + $scope.clientEdit.attributes["request.uris"] = null; + } + if (!$scope.clientEdit.frontchannelLogout) { + $scope.clientEdit.attributes["frontchannel.logout.url"] = null; + } + delete $scope.clientEdit.requestUris; + + if ($scope.newDefaultAcrValue && $scope.newDefaultAcrValue.length > 0) { + $scope.addDefaultAcrValue(); + } + if ($scope.defaultAcrValues && $scope.defaultAcrValues.length > 0) { + $scope.clientEdit.attributes["default.acr.values"] = $scope.defaultAcrValues.join("##"); + } else { + $scope.clientEdit.attributes["default.acr.values"] = null; + } + + if ($scope.samlArtifactBinding == true) { + $scope.clientEdit.attributes["saml.artifact.binding"] = "true"; + } else { + $scope.clientEdit.attributes["saml.artifact.binding"] = "false"; + } + + if ($scope.newAcr && $scope.newAcr.length > 0 && $scope.newLoa && $scope.newLoa.length > 0) { + $scope.addAcrLoaMapping(); + } + + if ($scope.samlServerSignature == true) { + $scope.clientEdit.attributes["saml.server.signature"] = "true"; + } else { + $scope.clientEdit.attributes["saml.server.signature"] = "false"; + } + if ($scope.samlServerSignatureEnableKeyInfoExtension == true) { + $scope.clientEdit.attributes["saml.server.signature.keyinfo.ext"] = "true"; + } else { + $scope.clientEdit.attributes["saml.server.signature.keyinfo.ext"] = "false"; + } + if ($scope.samlAssertionSignature == true) { + $scope.clientEdit.attributes["saml.assertion.signature"] = "true"; + } else { + $scope.clientEdit.attributes["saml.assertion.signature"] = "false"; + } + if ($scope.samlClientSignature == true) { + $scope.clientEdit.attributes["saml.client.signature"] = "true"; + } else { + $scope.clientEdit.attributes["saml.client.signature"] = "false"; + + } + if ($scope.samlEncrypt == true) { + $scope.clientEdit.attributes["saml.encrypt"] = "true"; + } else { + $scope.clientEdit.attributes["saml.encrypt"] = "false"; + + } + if ($scope.samlAuthnStatement == true) { + $scope.clientEdit.attributes["saml.authnstatement"] = "true"; + } else { + $scope.clientEdit.attributes["saml.authnstatement"] = "false"; + + } + if ($scope.samlOneTimeUseCondition == true) { + $scope.clientEdit.attributes["saml.onetimeuse.condition"] = "true"; + } else { + $scope.clientEdit.attributes["saml.onetimeuse.condition"] = "false"; + + } + if ($scope.samlForceNameIdFormat == true) { + $scope.clientEdit.attributes["saml_force_name_id_format"] = "true"; + } else { + $scope.clientEdit.attributes["saml_force_name_id_format"] = "false"; + + } + if ($scope.samlAllowECPFlow == true) { + $scope.clientEdit.attributes["saml.allow.ecp.flow"] = "true"; + } else { + $scope.clientEdit.attributes["saml.allow.ecp.flow"] = "false"; + + } + if ($scope.samlMultiValuedRoles == true) { + $scope.clientEdit.attributes["saml.multivalued.roles"] = "true"; + } else { + $scope.clientEdit.attributes["saml.multivalued.roles"] = "false"; + + } + if ($scope.samlForcePostBinding == true) { + $scope.clientEdit.attributes["saml.force.post.binding"] = "true"; + } else { + $scope.clientEdit.attributes["saml.force.post.binding"] = "false"; + + } + + if ($scope.excludeSessionStateFromAuthResponse == true) { + $scope.clientEdit.attributes["exclude.session.state.from.auth.response"] = "true"; + } else { + $scope.clientEdit.attributes["exclude.session.state.from.auth.response"] = "false"; + + } + + if ($scope.oauth2DeviceAuthorizationGrantEnabled == true) { + $scope.clientEdit.attributes["oauth2.device.authorization.grant.enabled"] = "true"; + } else { + $scope.clientEdit.attributes["oauth2.device.authorization.grant.enabled"] = "false"; + } + + if ($scope.oidcCibaGrantEnabled == true) { + $scope.clientEdit.attributes["oidc.ciba.grant.enabled"] = "true"; + } else { + $scope.clientEdit.attributes["oidc.ciba.grant.enabled"] = "false"; + } + + if ($scope.useRefreshTokens == true) { + $scope.clientEdit.attributes["use.refresh.tokens"] = "true"; + } else { + $scope.clientEdit.attributes["use.refresh.tokens"] = "false"; + } + + if ($scope.useIdTokenAsDetachedSignature == true) { + $scope.clientEdit.attributes["id.token.as.detached.signature"] = "true"; + } else { + $scope.clientEdit.attributes["id.token.as.detached.signature"] = "false"; + } + + // KEYCLOAK-6771 Certificate Bound Token + // https://tools.ietf.org/html/draft-ietf-oauth-mtls-08#section-3 + if ($scope.tlsClientCertificateBoundAccessTokens == true) { + $scope.clientEdit.attributes["tls.client.certificate.bound.access.tokens"] = "true"; + } else { + $scope.clientEdit.attributes["tls.client.certificate.bound.access.tokens"] = "false"; + } + + // PAR request. + if ($scope.requirePushedAuthorizationRequests == true) { + $scope.clientEdit.attributes["require.pushed.authorization.requests"] = "true"; + } else { + $scope.clientEdit.attributes["require.pushed.authorization.requests"] = "false"; + } + + // KEYCLOAK-9551 Client Credentials Grant generates refresh token + // https://tools.ietf.org/html/rfc6749#section-4.4.3 + if ($scope.useRefreshTokenForClientCredentialsGrant === true) { + $scope.clientEdit.attributes["client_credentials.use_refresh_token"] = "true"; + } else { + $scope.clientEdit.attributes["client_credentials.use_refresh_token"] = "false"; + } + + if ($scope.useLowerCaseBearerTypeInTokenResponse === true) { + $scope.clientEdit.attributes["token.response.type.bearer.lower-case"] = "true"; + } else { + $scope.clientEdit.attributes["token.response.type.bearer.lower-case"] = "false"; + } + + if ($scope.displayOnConsentScreen == true) { + $scope.clientEdit.attributes["display.on.consent.screen"] = "true"; + } else { + $scope.clientEdit.attributes["display.on.consent.screen"] = "false"; + } + + if ($scope.backchannelLogoutSessionRequired == true) { + $scope.clientEdit.attributes["backchannel.logout.session.required"] = "true"; + } else { + $scope.clientEdit.attributes["backchannel.logout.session.required"] = "false"; + } + + if ($scope.backchannelLogoutRevokeOfflineSessions == true) { + $scope.clientEdit.attributes["backchannel.logout.revoke.offline.tokens"] = "true"; + } else { + $scope.clientEdit.attributes["backchannel.logout.revoke.offline.tokens"] = "false"; + } + + if ($scope.frontchannelLogoutSessionRequired == true) { + $scope.clientEdit.attributes["frontchannel.logout.session.required"] = "true"; + } else { + $scope.clientEdit.attributes["frontchannel.logout.session.required"] = "false"; + } + + $scope.clientEdit.attributes["acr.loa.map"] = JSON.stringify($scope.acrLoaMap); + + $scope.clientEdit.protocol = $scope.protocol; + $scope.clientEdit.attributes['saml.signature.algorithm'] = $scope.signatureAlgorithm; + $scope.clientEdit.attributes['saml_name_id_format'] = $scope.nameIdFormat; + + if ($scope.clientEdit.protocol != 'saml' && !$scope.clientEdit.bearerOnly && ($scope.clientEdit.standardFlowEnabled || $scope.clientEdit.implicitFlowEnabled) && (!$scope.clientEdit.redirectUris || $scope.clientEdit.redirectUris.length == 0)) { + Notifications.error("You must specify at least one redirect uri"); + } else { + Client.update({ + realm : realm.realm, + client : client.id + }, $scope.clientEdit, function() { + $route.reload(); + Notifications.success("Your changes have been saved to the client."); + }); + } + }; + + $scope.reset = function() { + $route.reload(); + }; + + $scope.cancel = function() { + $location.url("/realms/" + realm.realm + "/clients"); + }; +}); + +module.controller('CreateClientCtrl', function($scope, realm, client, $route, serverInfo, Client, ClientDescriptionConverter, $location, $modal, Dialog, Notifications) { + $scope.protocols = serverInfo.listProviderIds('login-protocol'); + $scope.create = true; + + $scope.realm = realm; + + $scope.client = { + enabled: true, + attributes: {} + }; + $scope.client.redirectUris = []; + $scope.protocol = $scope.protocols[0]; + + + $scope.importFile = function(fileContent){ + console.debug(fileContent); + ClientDescriptionConverter.save({ + realm: realm.realm + }, fileContent, function (data) { + $scope.client = data; + if (data.protocol) { + $scope.protocol = data.protocol; + } + $scope.importing = true; + }); + }; + + $scope.viewImportDetails = function() { + $modal.open({ + templateUrl: resourceUrl + '/partials/modal/view-object.html', + controller: 'ObjectModalCtrl', + resolve: { + object: function () { + return $scope.client; + } + } + }) + }; + + $scope.switchChange = function() { + $scope.changed = true; + } + + $scope.changeProtocol = function() { + if ($scope.protocol == "openid-connect") { + $scope.client.protocol = "openid-connect"; + } else if ($scope.protocol == "saml") { + $scope.client.protocol = "saml"; + } + }; + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); + + function isChanged() { + if (!angular.equals($scope.client, client)) { + return true; + } + return false; + } + + $scope.$watch('client', function() { + $scope.changed = isChanged(); + }, true); + + + $scope.save = function() { + $scope.client.protocol = $scope.protocol; + + Client.save({ + realm: realm.realm, + client: '' + }, $scope.client, function (data, headers) { + $scope.changed = false; + var l = headers().location; + var id = l.substring(l.lastIndexOf("/") + 1); + $location.url("/realms/" + realm.realm + "/clients/" + id); + Notifications.success("The client has been created."); + }); + }; + + $scope.reset = function() { + $route.reload(); + }; + + $scope.cancel = function() { + $location.url("/realms/" + realm.realm + "/clients"); + }; +}); + +module.controller('ClientScopeMappingCtrl', function($scope, $http, realm, $route, client, clients, Notifications, + Client, ClientScope, + ClientRealmScopeMapping, ClientClientScopeMapping, ClientRole, + ClientAvailableRealmScopeMapping, ClientAvailableClientScopeMapping, + ClientCompositeRealmScopeMapping, ClientCompositeClientScopeMapping) { + $scope.realm = realm; + $scope.client = angular.copy(client); + $scope.selectedRealmRoles = []; + $scope.selectedRealmMappings = []; + $scope.realmMappings = []; + $scope.clients = clients; + $scope.clientRoles = []; + $scope.clientComposite = []; + $scope.selectedClientRoles = []; + $scope.selectedClientMappings = []; + $scope.clientMappings = []; + $scope.dummymodel = []; + + $scope.hideRoleSelector = function() { + return $scope.client.fullScopeAllowed; + } + + $scope.changeFlag = function() { + console.log('changeFlag'); + Client.update({ + realm : realm.realm, + client : client.id + }, $scope.client, function() { + $scope.changed = false; + client = angular.copy($scope.client); + updateRealmRoles(); + Notifications.success("Scope mappings updated."); + }); + } + + + $scope.selectedClient = null; + + $scope.selectClient = function(client) { + if (!client || !client.id) { + $scope.selectedClient = null; + return; + } + + $scope.selectedClient = client; + updateClientRoles(); + } + + function updateRealmRoles() { + $scope.realmRoles = ClientAvailableRealmScopeMapping.query({realm : realm.realm, client : client.id}); + $scope.realmMappings = ClientRealmScopeMapping.query({realm : realm.realm, client : client.id}); + $scope.realmComposite = ClientCompositeRealmScopeMapping.query({realm : realm.realm, client : client.id}); + } + + function updateClientRoles() { + if ($scope.selectedClient) { + $scope.clientRoles = ClientAvailableClientScopeMapping.query({realm : realm.realm, client : client.id, targetClient : $scope.selectedClient.id}); + $scope.clientMappings = ClientClientScopeMapping.query({realm : realm.realm, client : client.id, targetClient : $scope.selectedClient.id}); + $scope.clientComposite = ClientCompositeClientScopeMapping.query({realm : realm.realm, client : client.id, targetClient : $scope.selectedClient.id}); + } else { + $scope.clientRoles = null; + $scope.clientMappings = null; + $scope.clientComposite = null; + } + } + + $scope.addRealmRole = function() { + $scope.selectedRealmRolesToAdd = JSON.parse('[' + $scope.selectedRealmRoles + ']'); + $scope.selectedRealmRoles = []; + $http.post(authUrl + '/admin/realms/' + realm.realm + '/clients/' + client.id + '/scope-mappings/realm', + $scope.selectedRealmRolesToAdd).then(function() { + updateRealmRoles(); + $scope.selectedRealmRolesToAdd = []; + Notifications.success("Scope mappings updated."); + }); + }; + + $scope.deleteRealmRole = function() { + $scope.selectedRealmMappingsToRemove = JSON.parse('[' + $scope.selectedRealmMappings + ']'); + $scope.selectedRealmMappings = []; + $http.delete(authUrl + '/admin/realms/' + realm.realm + '/clients/' + client.id + '/scope-mappings/realm', + {data : $scope.selectedRealmMappingsToRemove, headers : {"content-type" : "application/json"}}).then(function () { + updateRealmRoles(); + $scope.selectedRealmMappingsToRemove = []; + Notifications.success("Scope mappings updated."); + }); + }; + + $scope.addClientRole = function() { + $scope.selectedClientRolesToAdd = JSON.parse('[' + $scope.selectedClientRoles + ']'); + $scope.selectedClientRoles = []; + $http.post(authUrl + '/admin/realms/' + realm.realm + '/clients/' + client.id + '/scope-mappings/clients/' + $scope.selectedClient.id, + $scope.selectedClientRolesToAdd).then(function () { + updateClientRoles(); + $scope.selectedClientRolesToAdd = []; + Notifications.success("Scope mappings updated."); + }); + }; + + $scope.deleteClientRole = function() { + $scope.selectedClientMappingsToRemove = JSON.parse('[' + $scope.selectedClientMappings + ']'); + $scope.selectedClientMappings = []; + $http.delete(authUrl + '/admin/realms/' + realm.realm + '/clients/' + client.id + '/scope-mappings/clients/' + $scope.selectedClient.id, + {data : $scope.selectedClientMappingsToRemove, headers : {"content-type" : "application/json"}}).then(function () { + updateClientRoles(); + $scope.selectedClientMappingsToRemove = []; + Notifications.success("Scope mappings updated."); + }); + }; + + clientSelectControl($scope, $route.current.params.realm, Client); + updateRealmRoles(); +}); + +module.controller('ClientRevocationCtrl', function($scope, realm, client, Client, ClientPushRevocation, $location, Dialog, Notifications) { + $scope.realm = realm; + $scope.client = client; + + var setNotBefore = function() { + if ($scope.client.notBefore == 0) { + $scope.notBefore = "None"; + } else { + $scope.notBefore = new Date($scope.client.notBefore * 1000); + } + }; + + setNotBefore(); + + var refresh = function() { + Client.get({ realm : realm.realm, client: $scope.client.id }, function(updated) { + $scope.client = updated; + setNotBefore(); + }) + + }; + + $scope.clear = function() { + $scope.client.notBefore = 0; + Client.update({ realm : realm.realm, client: client.id}, $scope.client, function () { + $scope.notBefore = "None"; + Notifications.success('Not Before cleared for client.'); + refresh(); + }); + } + $scope.setNotBeforeNow = function() { + $scope.client.notBefore = new Date().getTime()/1000; + Client.update({ realm : realm.realm, client: $scope.client.id}, $scope.client, function () { + Notifications.success('Not Before set for client.'); + refresh(); + }); + } + $scope.pushRevocation = function() { + ClientPushRevocation.save({realm : realm.realm, client: $scope.client.id}, function (globalReqResult) { + var successCount = globalReqResult.successRequests ? globalReqResult.successRequests.length : 0; + var failedCount = globalReqResult.failedRequests ? globalReqResult.failedRequests.length : 0; + + if (successCount==0 && failedCount==0) { + Notifications.warn('No push sent. No admin URI configured or no registered cluster nodes available'); + } else if (failedCount > 0) { + var msgStart = successCount>0 ? 'Successfully push notBefore to: ' + globalReqResult.successRequests + ' . ' : ''; + Notifications.error(msgStart + 'Failed to push notBefore to: ' + globalReqResult.failedRequests + '. Verify availability of failed hosts and try again'); + } else { + Notifications.success('Successfully push notBefore to: ' + globalReqResult.successRequests); + } + }); + } + +}); + +module.controller('ClientClusteringCtrl', function($scope, client, Client, ClientTestNodesAvailable, ClientClusterNode, realm, $location, $route, Dialog, Notifications, TimeUnit) { + $scope.client = client; + $scope.realm = realm; + + var oldCopy = angular.copy($scope.client); + $scope.changed = false; + + $scope.$watch('client', function() { + if (!angular.equals($scope.client, oldCopy)) { + $scope.changed = true; + } + }, true); + + $scope.client.nodeReRegistrationTimeoutUnit = TimeUnit.autoUnit(client.nodeReRegistrationTimeout); + $scope.client.nodeReRegistrationTimeout = TimeUnit.toUnit(client.nodeReRegistrationTimeout, $scope.client.nodeReRegistrationTimeoutUnit); + + $scope.save = function() { + var clientCopy = angular.copy($scope.client); + delete clientCopy['nodeReRegistrationTimeoutUnit']; + clientCopy.nodeReRegistrationTimeout = TimeUnit.toSeconds($scope.client.nodeReRegistrationTimeout, $scope.client.nodeReRegistrationTimeoutUnit) + Client.update({ realm : realm.realm, client : client.id }, clientCopy, function () { + $route.reload(); + Notifications.success('Your changes have been saved to the client.'); + }); + }; + + $scope.reset = function() { + $route.reload(); + }; + + $scope.testNodesAvailable = function() { + ClientTestNodesAvailable.get({ realm : realm.realm, client : client.id }, function(globalReqResult) { + $route.reload(); + + var successCount = globalReqResult.successRequests ? globalReqResult.successRequests.length : 0; + var failedCount = globalReqResult.failedRequests ? globalReqResult.failedRequests.length : 0; + + if (successCount==0 && failedCount==0) { + Notifications.warn('No requests sent. No admin URI configured or no registered cluster nodes available'); + } else if (failedCount > 0) { + var msgStart = successCount>0 ? 'Successfully verify availability for ' + globalReqResult.successRequests + ' . ' : ''; + Notifications.error(msgStart + 'Failed to verify availability for: ' + globalReqResult.failedRequests + '. Fix or unregister failed cluster nodes and try again'); + } else { + Notifications.success('Successfully sent requests to: ' + globalReqResult.successRequests); + } + }); + }; + + if (client.registeredNodes) { + var nodeRegistrations = []; + for (node in client.registeredNodes) { + reg = { + host: node, + lastRegistration: new Date(client.registeredNodes[node] * 1000) + } + nodeRegistrations.push(reg); + } + + $scope.nodeRegistrations = nodeRegistrations; + }; + + $scope.removeNode = function(node) { + Dialog.confirmDelete(node.host, 'node', function() { + ClientClusterNode.remove({ realm : realm.realm, client : client.id , node: node.host }, function() { + Notifications.success('Node ' + node.host + ' unregistered successfully.'); + $route.reload(); + }); + }); + }; +}); + +module.controller('ClientClusteringNodeCtrl', function($scope, client, Client, ClientClusterNode, realm, + $location, $routeParams, Notifications, Dialog) { + $scope.client = client; + $scope.realm = realm; + $scope.create = !$routeParams.node; + + $scope.save = function() { + ClientClusterNode.save({ realm : realm.realm, client : client.id , node: $scope.node.host }, function() { + Notifications.success('Node ' + $scope.node.host + ' registered successfully.'); + $location.url('/realms/' + realm.realm + '/clients/' + client.id + '/clustering'); + }); + } + + $scope.unregisterNode = function() { + Dialog.confirmDelete($scope.node.host, 'node', function() { + ClientClusterNode.remove({ realm : realm.realm, client : client.id , node: $scope.node.host }, function() { + Notifications.success('Node ' + $scope.node.host + ' unregistered successfully.'); + $location.url('/realms/' + realm.realm + '/clients/' + client.id + '/clustering'); + }); + }); + } + + if ($scope.create) { + $scope.node = {} + $scope.registered = false; + } else { + var lastRegTime = client.registeredNodes[$routeParams.node]; + + if (lastRegTime) { + $scope.registered = true; + $scope.node = { + host: $routeParams.node, + lastRegistration: new Date(lastRegTime * 1000) + } + + } else { + $scope.registered = false; + $scope.node = { + host: $routeParams.node + } + } + } +}); + +module.controller('AddBuiltinProtocolMapperCtrl', function($scope, realm, client, serverInfo, + ClientProtocolMappersByProtocol, + $http, $location, Dialog, Notifications) { + $scope.realm = realm; + $scope.client = client; + if (client.protocol == null) { + client.protocol = 'openid-connect'; + } + + var protocolMappers = serverInfo.protocolMapperTypes[client.protocol]; + var mapperTypes = {}; + for (var i = 0; i < protocolMappers.length; i++) { + mapperTypes[protocolMappers[i].id] = protocolMappers[i]; + } + $scope.mapperTypes = mapperTypes; + + + + + var updateMappers = function() { + var clientMappers = ClientProtocolMappersByProtocol.query({realm : realm.realm, client : client.id, protocol : client.protocol}, function() { + var builtinMappers = serverInfo.builtinProtocolMappers[client.protocol]; + for (var i = 0; i < clientMappers.length; i++) { + for (var j = 0; j < builtinMappers.length; j++) { + if (builtinMappers[j].name == clientMappers[i].name + && builtinMappers[j].protocolMapper == clientMappers[i].protocolMapper) { + builtinMappers.splice(j, 1); + break; + } + } + } + $scope.mappers = builtinMappers; + for (var i = 0; i < $scope.mappers.length; i++) { + $scope.mappers[i].isChecked = false; + } + + + }); + }; + + updateMappers(); + + $scope.add = function() { + var toAdd = []; + for (var i = 0; i < $scope.mappers.length; i++) { + if ($scope.mappers[i].isChecked) { + delete $scope.mappers[i].isChecked; + toAdd.push($scope.mappers[i]); + } + } + $http.post(authUrl + '/admin/realms/' + realm.realm + '/clients/' + client.id + '/protocol-mappers/add-models', + toAdd).then(function() { + Notifications.success("Mappers added"); + $location.url('/realms/' + realm.realm + '/clients/' + client.id + '/mappers'); + }).catch(function() { + Notifications.error("Error adding mappers"); + $location.url('/realms/' + realm.realm + '/clients/' + client.id + '/mappers'); + }); + }; + +}); + +module.controller('ClientProtocolMapperListCtrl', function($scope, realm, client, serverInfo, + Client, + ClientProtocolMappersByProtocol, ClientProtocolMapper, + $route, Dialog, Notifications) { + $scope.realm = realm; + $scope.client = client; + if (client.protocol == null) { + client.protocol = 'openid-connect'; + } + + $scope.changeFlag = function() { + Client.update({ + realm : realm.realm, + client : client.id + }, $scope.client, function() { + $scope.changed = false; + client = angular.copy($scope.client); + Notifications.success("Client updated."); + }); + } + + var protocolMappers = serverInfo.protocolMapperTypes[client.protocol]; + var mapperTypes = {}; + for (var i = 0; i < protocolMappers.length; i++) { + mapperTypes[protocolMappers[i].id] = protocolMappers[i]; + } + $scope.mapperTypes = mapperTypes; + + $scope.removeMapper = function(mapper) { + console.debug(mapper); + Dialog.confirmDelete(mapper.name, 'mapper', function() { + ClientProtocolMapper.remove({ realm: realm.realm, client: client.id, id : mapper.id }, function() { + Notifications.success("The mapper has been deleted."); + $route.reload(); + }); + }); + }; + + $scope.sortMappersByPriority = function(mapper) { + return $scope.mapperTypes[mapper.protocolMapper].priority; + } + + var updateMappers = function() { + $scope.mappers = ClientProtocolMappersByProtocol.query({realm : realm.realm, client : client.id, protocol : client.protocol}); + }; + + updateMappers(); +}); + +module.controller('ClientProtocolMapperCtrl', function($scope, realm, serverInfo, client, clients, mapper, ClientProtocolMapper, Notifications, Dialog, $location) { + $scope.realm = realm; + $scope.clients = clients; + + /* + $scope.client = client; + $scope.create = false; + $scope.protocol = client.protocol; + $scope.mapper = angular.copy(mapper); + $scope.changed = false; + */ + + if (client.protocol == null) { + client.protocol = 'openid-connect'; + } + + $scope.model = { + realm: realm, + client: client, + create: false, + protocol: client.protocol, + mapper: angular.copy(mapper), + changed: false + }; + + var protocolMappers = serverInfo.protocolMapperTypes[client.protocol]; + for (var i = 0; i < protocolMappers.length; i++) { + if (protocolMappers[i].id === mapper.protocolMapper) { + $scope.model.mapperType = protocolMappers[i]; + } + } + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); + + $scope.$watch('model.mapper', function() { + if (!angular.equals($scope.model.mapper, mapper)) { + $scope.model.changed = true; + } + }, true); + + $scope.save = function() { + ClientProtocolMapper.update({ + realm : realm.realm, + client: client.id, + id : $scope.model.mapper.id + }, $scope.model.mapper, function() { + $scope.model.changed = false; + mapper = angular.copy($scope.mapper); + $location.url("/realms/" + realm.realm + '/clients/' + client.id + "/mappers/" + $scope.model.mapper.id); + Notifications.success("Your changes have been saved."); + }); + }; + + $scope.reset = function() { + $scope.model.mapper = angular.copy(mapper); + $scope.model.changed = false; + }; + + $scope.cancel = function() { + //$location.url("/realms"); + window.history.back(); + }; + + $scope.remove = function() { + Dialog.confirmDelete($scope.model.mapper.name, 'mapper', function() { + ClientProtocolMapper.remove({ realm: realm.realm, client: client.id, id : $scope.model.mapper.id }, function() { + Notifications.success("The mapper has been deleted."); + $location.url("/realms/" + realm.realm + '/clients/' + client.id + "/mappers"); + }); + }); + }; + +}); + +module.controller('ClientProtocolMapperCreateCtrl', function($scope, realm, serverInfo, client, clients, ClientProtocolMapper, Notifications, Dialog, $location) { + $scope.realm = realm; + $scope.clients = clients; + + if (client.protocol == null) { + client.protocol = 'openid-connect'; + } + var protocol = client.protocol; + /* + $scope.client = client; + $scope.create = true; + $scope.protocol = protocol; + $scope.mapper = { protocol : client.protocol, config: {}}; + $scope.mapperTypes = serverInfo.protocolMapperTypes[protocol]; + */ + $scope.model = { + realm: realm, + client: client, + create: true, + protocol: client.protocol, + mapper: { protocol : client.protocol, config: {}}, + changed: false, + mapperTypes: serverInfo.protocolMapperTypes[protocol] + }; + console.log("mapper types: ", $scope.model.mapperTypes); + + // apply default configurations on change for selected protocolmapper type. + $scope.$watch('model.mapperType', function() { + var currentMapperType = $scope.model.mapperType; + var defaultConfig = {}; + + if (currentMapperType && Array.isArray(currentMapperType.properties)) { + for (var i = 0; i < currentMapperType.properties.length; i++) { + var property = currentMapperType.properties[i]; + if (property && property.name && property.defaultValue) { + defaultConfig[property.name] = property.defaultValue; + } + } + } + + $scope.model.mapper.config = defaultConfig; + }, true); + + $scope.model.mapperType = $scope.model.mapperTypes[0]; + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); + + $scope.save = function() { + $scope.model.mapper.protocolMapper = $scope.model.mapperType.id; + ClientProtocolMapper.save({ + realm : realm.realm, client: client.id + }, $scope.model.mapper, function(data, headers) { + var l = headers().location; + var id = l.substring(l.lastIndexOf("/") + 1); + $location.url("/realms/" + realm.realm + '/clients/' + client.id + "/mappers/" + id); + Notifications.success("Mapper has been created."); + }); + }; + + $scope.cancel = function() { + //$location.url("/realms"); + window.history.back(); + }; + + +}); + + +module.controller('ClientClientScopesSetupCtrl', function($scope, realm, Realm, client, clientScopes, serverInfo, + clientDefaultClientScopes, ClientDefaultClientScopes, clientOptionalClientScopes, ClientOptionalClientScopes, $route, Notifications, $location) { + console.log('ClientClientScopesSetupCtrl'); + + $scope.realm = realm; + $scope.client = client; + + $scope.clientDefaultClientScopes = clientDefaultClientScopes; + $scope.clientOptionalClientScopes = clientOptionalClientScopes; + + $scope.availableClientScopes = []; + $scope.selectedDefaultClientScopes = []; + $scope.selectedDefDefaultClientScopes = []; + + $scope.selectedOptionalClientScopes = []; + $scope.selectedDefOptionalClientScopes = []; + + // Populate available client scopes. Available client scopes are neither already assigned to 'default' or 'optional' + for (var i = 0; i < clientScopes.length; i++) { + var clientScope = clientScopes[i]; + var scopeName = clientScopes[i].name; + + var available = true; + if (clientScope.protocol != client.protocol) { + available = false; + } + + for (var j = 0; j < $scope.clientDefaultClientScopes.length; j++) { + if (scopeName === $scope.clientDefaultClientScopes[j].name) { + available = false; + } + } + for (var j = 0; j < $scope.clientOptionalClientScopes.length; j++) { + if (scopeName === $scope.clientOptionalClientScopes[j].name) { + available = false; + } + } + + if (available) { + $scope.availableClientScopes.push(clientScope); + } + } + + $scope.addDefaultClientScope = function () { + $scope.selectedDefaultClientScopesToAdd = JSON.parse('[' + $scope.selectedDefaultClientScopes + ']'); + toAdd = $scope.selectedDefaultClientScopesToAdd.length; + + for (var i = 0; i < $scope.selectedDefaultClientScopesToAdd.length; i++) { + var currentScope = $scope.selectedDefaultClientScopesToAdd[i]; + + ClientDefaultClientScopes.update({ + realm : realm.realm, + client : client.id, + clientScopeId : currentScope.id + }, function () { + toAdd = toAdd - 1; + if (toAdd === 0) { + $route.reload(); + Notifications.success("Default scopes updated."); + } + }); + } + $scope.selectedDefaultClientScopesToAdd = []; + }; + + $scope.deleteDefaultClientScope = function () { + $scope.selectedDefDefaultClientScopesToRemove = JSON.parse('[' + $scope.selectedDefDefaultClientScopes + ']'); + toRemove = $scope.selectedDefDefaultClientScopesToRemove.length; + + for (var i = 0; i < $scope.selectedDefDefaultClientScopesToRemove.length; i++) { + var currentScope = $scope.selectedDefDefaultClientScopesToRemove[i]; + + ClientDefaultClientScopes.remove({ + realm : realm.realm, + client : client.id, + clientScopeId : currentScope.id + }, function () { + toRemove = toRemove - 1; + if (toRemove === 0) { + $route.reload(); + Notifications.success("Default scopes updated."); + } + }); + } + $scope.selectedDefDefaultClientScopesToRemove = []; + }; + + $scope.addOptionalClientScope = function () { + $scope.selectedOptionalClientScopesToAdd = JSON.parse('[' + $scope.selectedOptionalClientScopes + ']'); + toAdd = $scope.selectedOptionalClientScopesToAdd.length; + + for (var i = 0; i < $scope.selectedOptionalClientScopesToAdd.length; i++) { + var currentScope = $scope.selectedOptionalClientScopesToAdd[i]; + + ClientOptionalClientScopes.update({ + realm : realm.realm, + client : client.id, + clientScopeId : currentScope.id + }, function () { + toAdd = toAdd - 1; + if (toAdd === 0) { + $route.reload(); + Notifications.success("Optional scopes updated."); + } + }); + } + }; + + $scope.deleteOptionalClientScope = function () { + $scope.selectedDefOptionalClientScopesToRemove = JSON.parse('[' + $scope.selectedDefOptionalClientScopes + ']'); + toRemove = $scope.selectedDefOptionalClientScopesToRemove.length; + + for (var i = 0; i < $scope.selectedDefOptionalClientScopesToRemove.length; i++) { + var currentScope = $scope.selectedDefOptionalClientScopesToRemove[i]; + + ClientOptionalClientScopes.remove({ + realm : realm.realm, + client : client.id, + clientScopeId : currentScope.id + }, function () { + toRemove = toRemove - 1; + if (toRemove === 0) { + $route.reload(); + Notifications.success("Optional scopes updated."); + } + }); + } + $scope.selectedDefOptionalClientScopesToRemove = []; + }; + +}); + +module.controller('ClientClientScopesEvaluateCtrl', function($scope, Realm, User, ClientEvaluateProtocolMappers, ClientEvaluateGrantedRoles, + ClientEvaluateNotGrantedRoles, ClientEvaluateGenerateExampleAccessToken, ClientEvaluateGenerateExampleIDToken, + ClientEvaluateGenerateExampleUserInfo, realm, client, clients, clientScopes, serverInfo, ComponentUtils, + clientOptionalClientScopes, clientDefaultClientScopes, $route, $routeParams, $http, Notifications, $location, + Client) { + + console.log('ClientClientScopesEvaluateCtrl'); + + var protocolMappers = serverInfo.protocolMapperTypes[client.protocol]; + var mapperTypes = {}; + for (var i = 0; i < protocolMappers.length; i++) { + mapperTypes[protocolMappers[i].id] = protocolMappers[i]; + } + $scope.mapperTypes = mapperTypes; + + $scope.realm = realm; + $scope.client = client; + $scope.clients = clients; + $scope.userId = null; + + $scope.availableClientScopes = []; + $scope.assignedClientScopes = []; + $scope.selectedClientScopes = []; + $scope.selectedDefClientScopes = []; + $scope.effectiveClientScopes = []; + + // Populate available client scopes. Available client scopes are neither already assigned to 'default' or 'optional' + for (var i = 0; i < clientOptionalClientScopes.length; i++) { + $scope.availableClientScopes.push(clientOptionalClientScopes[i]); + } + + function clearEvalResponse() { + $scope.protocolMappers = null; + $scope.grantedRealmRoles = null; + $scope.notGrantedRealmRoles = null; + $scope.grantedClientRoles = null; + $scope.notGrantedClientRoles = null; + $scope.targetClient = null; + $scope.oidcAccessToken = null; + $scope.oidcIDToken = null; + $scope.oidcUserInfo = null; + + $scope.selectedTab = 0; + } + + function updateState() { + // Compute scope parameter + $scope.scopeParam = 'openid'; + for (var i = 0; i < $scope.assignedClientScopes.length; i++) { + var currentScopeParam = $scope.assignedClientScopes[i].name; + $scope.scopeParam = $scope.scopeParam + ' ' + currentScopeParam; + } + + // Compute effective scopes + $scope.effectiveClientScopes = []; + + for (var i = 0; i < clientDefaultClientScopes.length; i++) { + var currentScope = clientDefaultClientScopes[i]; + $scope.effectiveClientScopes.push(currentScope); + } + for (var i = 0; i < $scope.assignedClientScopes.length; i++) { + var currentScope = $scope.assignedClientScopes[i]; + $scope.effectiveClientScopes.push(currentScope); + } + + // Clear the evaluation response + clearEvalResponse(); + } + + updateState(); + + + $scope.addAppliedClientScope = function () { + $scope.selectedClientScopesToAdd = JSON.parse('[' + $scope.selectedClientScopes + ']'); + for (var i = 0; i < $scope.selectedClientScopesToAdd.length; i++) { + var currentScope = $scope.selectedClientScopesToAdd[i]; + + $scope.assignedClientScopes.push(currentScope); + + var index = ComponentUtils.findIndexById($scope.availableClientScopes, currentScope.id); + if (index > -1) { + $scope.availableClientScopes.splice(index, 1); + } + } + + $scope.selectedClientScopes = []; + $scope.selectedClientScopesToAdd = []; + updateState(); + }; + + $scope.deleteAppliedClientScope = function () { + $scope.selectedDefClientScopesToRemove = JSON.parse('[' + $scope.selectedDefClientScopes + ']'); + for (var i = 0; i < $scope.selectedDefClientScopesToRemove.length; i++) { + var currentScope = $scope.selectedDefClientScopesToRemove[i]; + + $scope.availableClientScopes.push(currentScope); + + var index = ComponentUtils.findIndexById($scope.assignedClientScopes, currentScope.id); + if (index > -1) { + $scope.assignedClientScopes.splice(index, 1); + } + } + + $scope.selectedDefClientScopes = []; + $scope.selectedDefClientScopesToRemove = []; + + updateState(); + }; + + $scope.usersUiSelect = { + minimumInputLength: 1, + delay: 500, + allowClear: true, + query: function (query) { + var data = {results: []}; + if ('' == query.term.trim()) { + query.callback(data); + return; + } + User.query({realm: $route.current.params.realm, search: query.term.trim(), max: 20}, function(response) { + data.results = response; + query.callback(data); + }); + }, + formatResult: function(object, container, query) { + object.text = object.username; + return object.username; + } + }; + + $scope.selectedUser = null; + + $scope.selectUser = function(user) { + clearEvalResponse(); + + if (!user || !user.id) { + $scope.selectedUser = null; + $scope.userId = ''; + return; + } + + $scope.userId = user.id; + } + + clientSelectControl($scope, $route.current.params.realm, Client); + + $scope.selectedClient = null; + + $scope.selectClient = function(client) { + console.log("selected client: ", client); + if (!client || !client.id) { + $scope.selectedClient = null; + return; + } + + $scope.selectedClient = client; + updateScopeClientRoles(); + } + + + $scope.sendEvaluationRequest = function () { + + // Send request for retrieve protocolMappers + $scope.protocolMappers = ClientEvaluateProtocolMappers.query({ + realm: realm.realm, + client: client.id, + scopeParam: $scope.scopeParam + }); + + // Send request for retrieve realmRoles + updateScopeRealmRoles(); + + // Send request for retrieve accessToken (in case user was selected) + if (client.protocol === 'openid-connect' && $scope.userId != null && $scope.userId !== '') { + var exampleRequestParams = { + realm: realm.realm, + client: client.id, + userId: $scope.userId, + scopeParam: $scope.scopeParam + }; + + var accessTokenUrl = ClientEvaluateGenerateExampleAccessToken.url(exampleRequestParams); + getPrettyJsonResponse(accessTokenUrl).then(function (result) { + $scope.oidcAccessToken = result; + }); + + var idTokenUrl = ClientEvaluateGenerateExampleIDToken.url(exampleRequestParams); + getPrettyJsonResponse(idTokenUrl).then(function (result) { + $scope.oidcIDToken = result; + }); + + var userInfoUrl = ClientEvaluateGenerateExampleUserInfo.url(exampleRequestParams); + getPrettyJsonResponse(userInfoUrl).then(function (result) { + $scope.oidcUserInfo = result; + }); + } + + $scope.showTab(1); + }; + + function getPrettyJsonResponse(url) { + return $http.get(url).then(function (response) { + if (response.data) { + var responseJson = angular.fromJson(response.data); + return angular.toJson(responseJson, true); + } else { + return null; + } + }); + } + + $scope.isResponseAvailable = function () { + return $scope.protocolMappers != null; + } + + $scope.isAccessTokenAvailable = function () { + return $scope.oidcAccessToken != null; + } + + $scope.isIDTokenAvailable = function () { + return $scope.oidcIDToken != null; + } + + $scope.isUserInfoAvailable = function () { + return $scope.oidcUserInfo != null; + } + + $scope.showTab = function (tab) { + $scope.selectedTab = tab; + + $scope.tabCss = { + tab1: getTabCssClass(1, tab), + tab2: getTabCssClass(2, tab), + tab3: getTabCssClass(3, tab), + tab4: getTabCssClass(4, tab), + tab5: getTabCssClass(5, tab) + } + } + + function getTabCssClass(tabNo, selectedTab) { + return (tabNo === selectedTab) ? 'active' : ''; + } + + $scope.protocolMappersShown = function () { + return $scope.selectedTab === 1; + } + + $scope.rolesShown = function () { + return $scope.selectedTab === 2; + } + + $scope.exampleTabInfo = function() { + switch ($scope.selectedTab) { + case 3: + return { isShown: true, value: $scope.oidcAccessToken} + case 4: + return { isShown: true, value: $scope.oidcIDToken} + case 5: + return { isShown: true, value: $scope.oidcUserInfo} + default: + return { isShown: false, value: null} + } + } + + $scope.sortMappersByPriority = function(mapper) { + return $scope.mapperTypes[mapper.protocolMapper].priority; + } + + + // Roles + + function updateScopeRealmRoles() { + $scope.grantedRealmRoles = ClientEvaluateGrantedRoles.query({ + realm: realm.realm, + client: client.id, + roleContainer: realm.realm, + scopeParam: $scope.scopeParam + }); + $scope.notGrantedRealmRoles = ClientEvaluateNotGrantedRoles.query({ + realm: realm.realm, + client: client.id, + roleContainer: realm.realm, + scopeParam: $scope.scopeParam + }); + } + + function updateScopeClientRoles() { + if ($scope.selectedClient) { + $scope.grantedClientRoles = ClientEvaluateGrantedRoles.query({ + realm: realm.realm, + client: client.id, + roleContainer: $scope.selectedClient.id, + scopeParam: $scope.scopeParam + }); + $scope.notGrantedClientRoles = ClientEvaluateNotGrantedRoles.query({ + realm: realm.realm, + client: client.id, + roleContainer: $scope.selectedClient.id, + scopeParam: $scope.scopeParam + }); + } else { + $scope.grantedClientRoles = null; + $scope.notGrantedClientRoles = null; + } + } +}); + + +module.controller('ClientScopeTabCtrl', function(Dialog, $scope, Current, Notifications, $location) { + $scope.removeClientScope = function() { + Dialog.confirmDelete($scope.clientScope.name, 'client scope', function() { + $scope.clientScope.$remove({ + realm : Current.realm.realm, + clientScope : $scope.clientScope.id + }, function() { + $location.url("/realms/" + Current.realm.realm + "/client-scopes"); + Notifications.success("The client scope has been deleted."); + }); + }); + }; +}); + + + +module.controller('ClientScopeListCtrl', function($scope, realm, clientScopes, ClientScope, serverInfo, $route, Dialog, Notifications, $location) { + $scope.realm = realm; + $scope.clientScopes = clientScopes; + + $scope.removeClientScope = function(clientScope) { + Dialog.confirmDelete(clientScope.name, 'client scope', function() { + ClientScope.remove({ + realm : realm.realm, + clientScope : clientScope.id + }, function() { + $route.reload(); + Notifications.success("The client scope been deleted."); + }); + }); + }; +}); + +module.controller('ClientScopesRealmDefaultCtrl', function($scope, realm, Realm, clientScopes, realmDefaultClientScopes, RealmDefaultClientScopes, + realmOptionalClientScopes, RealmOptionalClientScopes, serverInfo, $route, Dialog, Notifications, $location) { + + console.log('ClientScopesRealmDefaultCtrl'); + + $scope.realm = realm; + $scope.realmDefaultClientScopes = realmDefaultClientScopes; + $scope.realmOptionalClientScopes = realmOptionalClientScopes; + + $scope.availableClientScopes = []; + $scope.selectedDefaultClientScopes = []; + $scope.selectedDefDefaultClientScopes = []; + + $scope.selectedOptionalClientScopes = []; + $scope.selectedDefOptionalClientScopes = []; + + // Populate available client scopes. Available client scopes are neither already assigned to 'default' or 'optional' + for (var i = 0; i < clientScopes.length; i++) { + var scopeName = clientScopes[i].name; + + var available = true; + for (var j = 0; j < $scope.realmDefaultClientScopes.length; j++) { + if (scopeName === $scope.realmDefaultClientScopes[j].name) { + available = false; + } + } + for (var j = 0; j < $scope.realmOptionalClientScopes.length; j++) { + if (scopeName === $scope.realmOptionalClientScopes[j].name) { + available = false; + } + } + + if (available) { + $scope.availableClientScopes.push(clientScopes[i]); + } + } + + $scope.addDefaultClientScope = function () { + $scope.selectedDefaultClientScopesToAdd = JSON.parse('[' + $scope.selectedDefaultClientScopes + ']'); + toAdd = $scope.selectedDefaultClientScopesToAdd.length; + + for (var i = 0; i < $scope.selectedDefaultClientScopesToAdd.length; i++) { + var currentScope = $scope.selectedDefaultClientScopesToAdd[i]; + + RealmDefaultClientScopes.update({ + realm : realm.realm, + clientScopeId : currentScope.id + }, function () { + toAdd = toAdd - 1; + console.log('toAdd: ' + toAdd); + if (toAdd === 0) { + $route.reload(); + Notifications.success("Realm default scopes updated."); + } + }); + } + $scope.selectedDefaultClientScopesToAdd = []; + }; + + $scope.deleteDefaultClientScope = function () { + $scope.selectedDefDefaultClientScopesToRemove = JSON.parse('[' + $scope.selectedDefDefaultClientScopes + ']'); + toRemove = $scope.selectedDefDefaultClientScopesToRemove.length; + + for (var i = 0; i < $scope.selectedDefDefaultClientScopesToRemove.length; i++) { + var currentScope = $scope.selectedDefDefaultClientScopesToRemove[i]; + + RealmDefaultClientScopes.remove({ + realm : realm.realm, + clientScopeId : currentScope.id + }, function () { + toRemove = toRemove - 1; + if (toRemove === 0) { + $route.reload(); + Notifications.success("Realm default scopes updated."); + } + }); + } + $scope.selectedDefDefaultClientScopesToRemove = []; + }; + + $scope.addOptionalClientScope = function () { + $scope.selectedOptionalClientScopesToAdd = JSON.parse('[' + $scope.selectedOptionalClientScopes + ']'); + toAdd = $scope.selectedOptionalClientScopesToAdd.length; + + for (var i = 0; i < $scope.selectedOptionalClientScopesToAdd.length; i++) { + var currentScope = $scope.selectedOptionalClientScopesToAdd[i]; + + RealmOptionalClientScopes.update({ + realm : realm.realm, + clientScopeId : currentScope.id + }, function () { + toAdd = toAdd - 1; + console.log('toAdd: ' + toAdd); + if (toAdd === 0) { + $route.reload(); + Notifications.success("Realm optional scopes updated."); + } + }); + } + $scope.selectedOptionalClientScopesToAdd = []; + }; + + $scope.deleteOptionalClientScope = function () { + $scope.selectedDefOptionalClientScopesToRemove = JSON.parse('[' + $scope.selectedDefOptionalClientScopes + ']'); + toRemove = $scope.selectedDefOptionalClientScopesToRemove.length; + + for (var i = 0; i < $scope.selectedDefOptionalClientScopesToRemove.length; i++) { + var currentScope = $scope.selectedDefOptionalClientScopesToRemove[i]; + + RealmOptionalClientScopes.remove({ + realm : realm.realm, + clientScopeId : currentScope.id + }, function () { + toRemove = toRemove - 1; + if (toRemove === 0) { + $route.reload(); + Notifications.success("Realm optional scopes updated."); + } + }); + } + $scope.selectedDefOptionalClientScopesToRemove = []; + }; +}); + +module.controller('ClientScopeDetailCtrl', function($scope, realm, clientScope, $route, serverInfo, ClientScope, $location, $modal, Dialog, Notifications) { + $scope.protocols = serverInfo.listProviderIds('login-protocol'); + + $scope.realm = realm; + $scope.create = !clientScope.name; + + function updateProperties() { + if (!$scope.clientScope.attributes) { + $scope.clientScope.attributes = {}; + } + + if ($scope.clientScope.protocol) { + $scope.protocol = $scope.protocols[$scope.protocols.indexOf($scope.clientScope.protocol)]; + } else { + $scope.protocol = $scope.protocols[0]; + } + + if ($scope.clientScope.attributes["display.on.consent.screen"]) { + if ($scope.clientScope.attributes["display.on.consent.screen"] == "true") { + $scope.displayOnConsentScreen = true; + } else { + $scope.displayOnConsentScreen = false; + } + } else { + $scope.displayOnConsentScreen = true; + } + + if(serverInfo.featureEnabled("DYNAMIC_SCOPES")) { + if ($scope.clientScope.attributes["is.dynamic.scope"]) { + if ($scope.clientScope.attributes["is.dynamic.scope"] === "true") { + $scope.isDynamicScope = true; + } else { + $scope.isDynamicScope = false; + } + } else { + $scope.isDynamicScope = false; + } + + $scope.clientScope.attributes["dynamic.scope.regexp"] = $scope.clientScope.name + ":*"; + } + + if ($scope.clientScope.attributes["include.in.token.scope"]) { + if ($scope.clientScope.attributes["include.in.token.scope"] == "true") { + $scope.includeInTokenScope = true; + } else { + $scope.includeInTokenScope = false; + } + } else { + $scope.includeInTokenScope = true; + } + } + + if (!$scope.create) { + $scope.clientScope = angular.copy(clientScope); + } else { + $scope.clientScope = {}; + } + + updateProperties(); + + + $scope.switchChange = function() { + $scope.changed = true; + } + + $scope.changeProtocol = function() { + if ($scope.protocol == "openid-connect") { + $scope.clientScope.protocol = "openid-connect"; + } else if ($scope.protocol == "saml") { + $scope.clientScope.protocol = "saml"; + } + }; + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); + + function isChanged() { + if (!angular.equals($scope.clientScope, clientScope)) { + return true; + } + return false; + } + + $scope.$watch('clientScope', function() { + $scope.changed = isChanged(); + }, true); + + $scope.save = function() { + $scope.clientScope.protocol = $scope.protocol; + + if ($scope.displayOnConsentScreen == true) { + $scope.clientScope.attributes["display.on.consent.screen"] = "true"; + } else { + $scope.clientScope.attributes["display.on.consent.screen"] = "false"; + } + + if(serverInfo.featureEnabled("DYNAMIC_SCOPES")) { + if ($scope.isDynamicScope === true) { + $scope.clientScope.attributes["is.dynamic.scope"] = "true"; + } else { + $scope.clientScope.attributes["is.dynamic.scope"] = "false"; + } + } + + if ($scope.includeInTokenScope == true) { + $scope.clientScope.attributes["include.in.token.scope"] = "true"; + } else { + $scope.clientScope.attributes["include.in.token.scope"] = "false"; + } + + if ($scope.create) { + ClientScope.save({ + realm: realm.realm, + clientScope: '' + }, $scope.clientScope, function (data, headers) { + $scope.changed = false; + var l = headers().location; + var id = l.substring(l.lastIndexOf("/") + 1); + $location.url("/realms/" + realm.realm + "/client-scopes/" + id); + Notifications.success("The client scope has been created."); + }); + } else { + ClientScope.update({ + realm : realm.realm, + clientScope : clientScope.id + }, $scope.clientScope, function() { + $scope.changed = false; + clientScope = angular.copy($scope.clientScope); + $location.url("/realms/" + realm.realm + "/client-scopes/" + clientScope.id); + Notifications.success("Your changes have been saved to the client scope."); + }); + } + }; + + $scope.reset = function() { + $route.reload(); + }; + + $scope.cancel = function() { + $location.url("/realms/" + realm.realm + "/client-scopes"); + }; +}); + +module.controller('ClientScopeProtocolMapperListCtrl', function($scope, realm, clientScope, serverInfo, + ClientScopeProtocolMappersByProtocol, ClientScopeProtocolMapper, + $route, Dialog, Notifications) { + $scope.realm = realm; + $scope.clientScope = clientScope; + if (clientScope.protocol == null) { + clientScope.protocol = 'openid-connect'; + } + + var protocolMappers = serverInfo.protocolMapperTypes[clientScope.protocol]; + var mapperTypes = {}; + for (var i = 0; i < protocolMappers.length; i++) { + mapperTypes[protocolMappers[i].id] = protocolMappers[i]; + } + $scope.mapperTypes = mapperTypes; + + $scope.removeMapper = function(mapper) { + console.debug(mapper); + Dialog.confirmDelete(mapper.name, 'mapper', function() { + ClientScopeProtocolMapper.remove({ realm: realm.realm, clientScope: clientScope.id, id : mapper.id }, function() { + Notifications.success("The mapper has been deleted."); + $route.reload(); + }); + }); + }; + + $scope.sortMappersByPriority = function(mapper) { + return $scope.mapperTypes[mapper.protocolMapper].priority; + } + + var updateMappers = function() { + $scope.mappers = ClientScopeProtocolMappersByProtocol.query({realm : realm.realm, clientScope : clientScope.id, protocol : clientScope.protocol}); + }; + + updateMappers(); +}); + +module.controller('ClientScopeProtocolMapperCtrl', function($scope, realm, serverInfo, clientScope, mapper, clients, ClientScopeProtocolMapper, Notifications, Dialog, $location, $route) { + $scope.realm = realm; + $scope.clients = clients; + + if (clientScope.protocol == null) { + clientScope.protocol = 'openid-connect'; + } + + $scope.model = { + realm: realm, + clientScope: clientScope, + create: false, + protocol: clientScope.protocol, + mapper: angular.copy(mapper), + changed: false + } + + var protocolMappers = serverInfo.protocolMapperTypes[clientScope.protocol]; + for (var i = 0; i < protocolMappers.length; i++) { + if (protocolMappers[i].id == mapper.protocolMapper) { + $scope.model.mapperType = protocolMappers[i]; + } + } + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); + + $scope.$watch('model.mapper', function() { + if (!angular.equals($scope.model.mapper, mapper)) { + $scope.model.changed = true; + } + }, true); + + $scope.save = function() { + ClientScopeProtocolMapper.update({ + realm : realm.realm, + clientScope: clientScope.id, + id : mapper.id + }, $scope.model.mapper, function() { + $route.reload(); + Notifications.success("Your changes have been saved."); + }); + }; + + $scope.reset = function() { + $scope.model.mapper = angular.copy(mapper); + $scope.model.changed = false; + }; + + $scope.cancel = function() { + //$location.url("/realms"); + window.history.back(); + }; + + $scope.remove = function() { + Dialog.confirmDelete($scope.model.mapper.name, 'mapper', function() { + ClientScopeProtocolMapper.remove({ realm: realm.realm, clientScope: clientScope.id, id : $scope.model.mapper.id }, function() { + Notifications.success("The mapper has been deleted."); + $location.url("/realms/" + realm.realm + '/client-scopes/' + clientScope.id + "/mappers"); + }); + }); + }; + +}); + +module.controller('ClientScopeProtocolMapperCreateCtrl', function($scope, realm, serverInfo, clientScope, clients, ClientScopeProtocolMapper, Notifications, Dialog, $location) { + $scope.realm = realm; + $scope.clients = clients; + + if (clientScope.protocol == null) { + clientScope.protocol = 'openid-connect'; + } + var protocol = clientScope.protocol; + $scope.model = { + realm: realm, + clientScope: clientScope, + create: true, + protocol: clientScope.protocol, + mapper: { protocol : clientScope.protocol, config: {}}, + changed: false, + mapperTypes: serverInfo.protocolMapperTypes[protocol] + } + + // apply default configurations on change for selected protocolmapper type. + $scope.$watch('model.mapperType', function() { + var currentMapperType = $scope.model.mapperType; + var defaultConfig = {}; + + if (currentMapperType && Array.isArray(currentMapperType.properties)) { + for (var i = 0; i < currentMapperType.properties.length; i++) { + var property = currentMapperType.properties[i]; + if (property && property.name && property.defaultValue) { + defaultConfig[property.name] = property.defaultValue; + } + } + } + + $scope.model.mapper.config = defaultConfig; + }, true); + + $scope.model.mapperType = $scope.model.mapperTypes[0]; + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); + + $scope.save = function() { + $scope.model.mapper.protocolMapper = $scope.model.mapperType.id; + ClientScopeProtocolMapper.save({ + realm : realm.realm, clientScope: clientScope.id + }, $scope.model.mapper, function(data, headers) { + var l = headers().location; + var id = l.substring(l.lastIndexOf("/") + 1); + $location.url("/realms/" + realm.realm + '/client-scopes/' + clientScope.id + "/mappers/" + id); + Notifications.success("Mapper has been created."); + }); + }; + + $scope.cancel = function() { + //$location.url("/realms"); + window.history.back(); + }; + + +}); + +module.controller('ClientScopeAddBuiltinProtocolMapperCtrl', function($scope, realm, clientScope, serverInfo, + ClientScopeProtocolMappersByProtocol, + $http, $location, Dialog, Notifications) { + $scope.realm = realm; + $scope.clientScope = clientScope; + if (clientScope.protocol == null) { + clientScope.protocol = 'openid-connect'; + } + + var protocolMappers = serverInfo.protocolMapperTypes[clientScope.protocol]; + var mapperTypes = {}; + for (var i = 0; i < protocolMappers.length; i++) { + mapperTypes[protocolMappers[i].id] = protocolMappers[i]; + } + $scope.mapperTypes = mapperTypes; + + + + + var updateMappers = function() { + var clientMappers = ClientScopeProtocolMappersByProtocol.query({realm : realm.realm, clientScope : clientScope.id, protocol : clientScope.protocol}, function() { + var builtinMappers = serverInfo.builtinProtocolMappers[clientScope.protocol]; + for (var i = 0; i < clientMappers.length; i++) { + for (var j = 0; j < builtinMappers.length; j++) { + if (builtinMappers[j].name == clientMappers[i].name + && builtinMappers[j].protocolMapper == clientMappers[i].protocolMapper) { + builtinMappers.splice(j, 1); + break; + } + } + } + $scope.mappers = builtinMappers; + for (var i = 0; i < $scope.mappers.length; i++) { + $scope.mappers[i].isChecked = false; + } + + + }); + }; + + updateMappers(); + + $scope.add = function() { + var toAdd = []; + for (var i = 0; i < $scope.mappers.length; i++) { + if ($scope.mappers[i].isChecked) { + delete $scope.mappers[i].isChecked; + toAdd.push($scope.mappers[i]); + } + } + $http.post(authUrl + '/admin/realms/' + realm.realm + '/client-scopes/' + clientScope.id + '/protocol-mappers/add-models', + toAdd).then(function() { + Notifications.success("Mappers added"); + $location.url('/realms/' + realm.realm + '/client-scopes/' + clientScope.id + '/mappers'); + }).catch(function() { + Notifications.error("Error adding mappers"); + $location.url('/realms/' + realm.realm + '/client-scopes/' + clientScope.id + '/mappers'); + }); + }; + +}); + + +module.controller('ClientScopeScopeMappingCtrl', function($scope, $http, $route, realm, clientScope, Notifications, + ClientScope, Client, + ClientScopeRealmScopeMapping, ClientScopeClientScopeMapping, ClientRole, + ClientScopeAvailableRealmScopeMapping, ClientScopeAvailableClientScopeMapping, + ClientScopeCompositeRealmScopeMapping, ClientScopeCompositeClientScopeMapping) { + $scope.realm = realm; + $scope.clientScope = angular.copy(clientScope); + $scope.selectedRealmRoles = []; + $scope.selectedRealmMappings = []; + $scope.realmMappings = []; + $scope.clientRoles = []; + $scope.clientComposite = []; + $scope.selectedClientRoles = []; + $scope.selectedClientMappings = []; + $scope.clientMappings = []; + $scope.dummymodel = []; + $scope.selectedClient = null; + + function updateScopeRealmRoles() { + $scope.realmRoles = ClientScopeAvailableRealmScopeMapping.query({realm : realm.realm, clientScope : clientScope.id}); + $scope.realmMappings = ClientScopeRealmScopeMapping.query({realm : realm.realm, clientScope : clientScope.id}); + $scope.realmComposite = ClientScopeCompositeRealmScopeMapping.query({realm : realm.realm, clientScope : clientScope.id}); + } + + function updateScopeClientRoles() { + if ($scope.selectedClient) { + $scope.clientRoles = ClientScopeAvailableClientScopeMapping.query({realm : realm.realm, clientScope : clientScope.id, targetClient : $scope.selectedClient.id}); + $scope.clientMappings = ClientScopeClientScopeMapping.query({realm : realm.realm, clientScope : clientScope.id, targetClient : $scope.selectedClient.id}); + $scope.clientComposite = ClientScopeCompositeClientScopeMapping.query({realm : realm.realm, clientScope : clientScope.id, targetClient : $scope.selectedClient.id}); + } else { + $scope.clientRoles = null; + $scope.clientMappings = null; + $scope.clientComposite = null; + } + } + + $scope.changeClient = function(client) { + if (!client || !client.id) { + $scope.selectedClient = null; + return; + } + $scope.selectedClient = client; + updateScopeClientRoles(); + }; + + $scope.addRealmRole = function() { + $scope.selectedRealmRolesToAdd = JSON.parse('[' + $scope.selectedRealmRoles + ']'); + $scope.selectedRealmRoles = []; + $http.post(authUrl + '/admin/realms/' + realm.realm + '/client-scopes/' + clientScope.id + '/scope-mappings/realm', + $scope.selectedRealmRolesToAdd).then(function() { + updateScopeRealmRoles(); + $scope.selectedRealmRolesToAdd = []; + Notifications.success("Scope mappings updated."); + }); + }; + + $scope.deleteRealmRole = function() { + $scope.selectedRealmMappingsToRemove = JSON.parse('[' + $scope.selectedRealmMappings + ']'); + $scope.selectedRealmMappings = []; + $http.delete(authUrl + '/admin/realms/' + realm.realm + '/client-scopes/' + clientScope.id + '/scope-mappings/realm', + {data : $scope.selectedRealmMappingsToRemove, headers : {"content-type" : "application/json"}}).then(function () { + updateScopeRealmRoles(); + $scope.selectedRealmMappingsToRemove = []; + Notifications.success("Scope mappings updated."); + }); + }; + + $scope.addClientRole = function() { + $scope.selectedClientRolesToAdd = JSON.parse('[' + $scope.selectedClientRoles + ']'); + $scope.selectedClientRoles = []; + $http.post(authUrl + '/admin/realms/' + realm.realm + '/client-scopes/' + clientScope.id + '/scope-mappings/clients/' + $scope.selectedClient.id, + $scope.selectedClientRolesToAdd).then(function () { + updateScopeClientRoles(); + $scope.selectedClientRolesToAdd = []; + Notifications.success("Scope mappings updated."); + }); + }; + + $scope.deleteClientRole = function() { + $scope.selectedClientMappingsToRemove = JSON.parse('[' + $scope.selectedClientMappings + ']'); + $scope.selectedClientMappings = []; + $http.delete(authUrl + '/admin/realms/' + realm.realm + '/client-scopes/' + clientScope.id + '/scope-mappings/clients/' + $scope.selectedClient.id, + {data : $scope.selectedClientMappingsToRemove, headers : {"content-type" : "application/json"}}).then(function () { + updateScopeClientRoles(); + $scope.selectedClientMappingsToRemove = []; + Notifications.success("Scope mappings updated."); + }); + }; + + clientSelectControl($scope, $route.current.params.realm, Client); + updateScopeRealmRoles(); +}); + +module.controller('ClientStoresCtrl', function($scope, $location, $route, realm, serverInfo, Components, Notifications, Dialog) { + console.log('ClientStoresCtrl ++++****'); + $scope.realm = realm; + $scope.providers = serverInfo.componentTypes['org.keycloak.storage.client.ClientStorageProvider']; + $scope.clientStorageProviders = serverInfo.componentTypes['org.keycloak.storage.client.ClientStorageProvider']; + $scope.instancesLoaded = false; + + if (!$scope.providers) $scope.providers = []; + + $scope.addProvider = function(provider) { + console.log('Add provider: ' + provider.id); + $location.url("/create/client-storage/" + realm.realm + "/providers/" + provider.id); + }; + + $scope.getInstanceLink = function(instance) { + return "/realms/" + realm.realm + "/client-storage/providers/" + instance.providerId + "/" + instance.id; + } + + $scope.getInstanceName = function(instance) { + return instance.name; + } + $scope.getInstanceProvider = function(instance) { + return instance.providerId; + } + + $scope.isProviderEnabled = function(instance) { + return !instance.config['enabled'] || instance.config['enabled'][0] == 'true'; + } + + $scope.getInstancePriority = function(instance) { + if (!instance.config['priority']) { + return "0"; + } + return instance.config['priority'][0]; + } + + Components.query({realm: realm.realm, + parent: realm.id, + type: 'org.keycloak.storage.client.ClientStorageProvider' + }, function(data) { + $scope.instances = data; + $scope.instancesLoaded = true; + }); + + $scope.removeInstance = function(instance) { + Dialog.confirmDelete(instance.name, 'client storage provider', function() { + Components.remove({ + realm : realm.realm, + componentId : instance.id + }, function() { + $route.reload(); + Notifications.success("The provider has been deleted."); + }); + }); + }; +}); + +module.controller('GenericClientStorageCtrl', function($scope, $location, Notifications, $route, Dialog, realm, + serverInfo, instance, providerId, Components) { + console.log('GenericClientStorageCtrl'); + console.log('providerId: ' + providerId); + $scope.create = !instance.providerId; + console.log('create: ' + $scope.create); + var providers = serverInfo.componentTypes['org.keycloak.storage.client.ClientStorageProvider']; + console.log('providers length ' + providers.length); + var providerFactory = null; + for (var i = 0; i < providers.length; i++) { + var p = providers[i]; + console.log('provider: ' + p.id); + if (p.id == providerId) { + $scope.providerFactory = p; + providerFactory = p; + break; + } + + } + $scope.changed = false; + + console.log("providerFactory: " + providerFactory.id); + + function initClientStorageSettings() { + if ($scope.create) { + $scope.changed = true; + instance.name = providerFactory.id; + instance.providerId = providerFactory.id; + instance.providerType = 'org.keycloak.storage.client.ClientStorageProvider'; + instance.parentId = realm.id; + instance.config = { + + }; + instance.config['priority'] = ["0"]; + instance.config['enabled'] = ["true"]; + + $scope.fullSyncEnabled = false; + $scope.changedSyncEnabled = false; + instance.config['cachePolicy'] = ['DEFAULT']; + instance.config['evictionDay'] = ['']; + instance.config['evictionHour'] = ['']; + instance.config['evictionMinute'] = ['']; + instance.config['maxLifespan'] = ['']; + if (providerFactory.properties) { + + for (var i = 0; i < providerFactory.properties.length; i++) { + var configProperty = providerFactory.properties[i]; + if (configProperty.defaultValue) { + instance.config[configProperty.name] = [configProperty.defaultValue]; + } else { + instance.config[configProperty.name] = ['']; + } + + } + } + + } else { + $scope.changed = false; + if (!instance.config['enabled']) { + instance.config['enabled'] = ['true']; + } + if (!instance.config['cachePolicy']) { + instance.config['cachePolicy'] = ['DEFAULT']; + + } + if (!instance.config['evictionDay']) { + instance.config['evictionDay'] = ['']; + + } + if (!instance.config['evictionHour']) { + instance.config['evictionHour'] = ['']; + + } + if (!instance.config['evictionMinute']) { + instance.config['evictionMinute'] = ['']; + + } + if (!instance.config['maxLifespan']) { + instance.config['maxLifespan'] = ['']; + + } + if (!instance.config['priority']) { + instance.config['priority'] = ['0']; + } + + if (providerFactory.properties) { + for (var i = 0; i < providerFactory.properties.length; i++) { + var configProperty = providerFactory.properties[i]; + if (!instance.config[configProperty.name]) { + instance.config[configProperty.name] = ['']; + } + } + } + + } + } + + initClientStorageSettings(); + $scope.instance = angular.copy(instance); + $scope.realm = realm; + + $scope.$watch('instance', function() { + if (!angular.equals($scope.instance, instance)) { + $scope.changed = true; + } + + }, true); + + $scope.save = function() { + console.log('save provider'); + $scope.changed = false; + if ($scope.create) { + console.log('saving new provider'); + Components.save({realm: realm.realm}, $scope.instance, function (data, headers) { + var l = headers().location; + var id = l.substring(l.lastIndexOf("/") + 1); + + $location.url("/realms/" + realm.realm + "/client-storage/providers/" + $scope.instance.providerId + "/" + id); + Notifications.success("The provider has been created."); + }); + } else { + console.log('update existing provider'); + Components.update({realm: realm.realm, + componentId: instance.id + }, + $scope.instance, function () { + $route.reload(); + Notifications.success("The provider has been updated."); + }); + } + }; + + $scope.reset = function() { + $route.reload(); + }; + + $scope.cancel = function() { + console.log('cancel'); + if ($scope.create) { + $location.url("/realms/" + realm.realm + "/client-stores"); + } else { + $route.reload(); + } + }; + + + +}); + + diff --git a/keycloak-themes/base/admin/resources/js/controllers/groups.js b/keycloak-themes/base/admin/resources/js/controllers/groups.js new file mode 100644 index 0000000..e92de0f --- /dev/null +++ b/keycloak-themes/base/admin/resources/js/controllers/groups.js @@ -0,0 +1,625 @@ +module.controller('GroupListCtrl', function($scope, $route, $q, realm, Groups, GroupsCount, Group, GroupChildren, Notifications, $location, Dialog, ComponentUtils, $translate) { + $scope.realm = realm; + $scope.groupList = [ + { + "id" : "realm", + "name": $translate.instant('groups'), + "subGroups" : [] + } + ]; + + $scope.searchCriteria = ''; + $scope.currentPage = 1; + $scope.currentPageInput = $scope.currentPage; + $scope.pageSize = 20; + $scope.numberOfPages = 1; + $scope.tree = []; + + var refreshGroups = function (search) { + console.log('refreshGroups'); + $scope.currentPageInput = $scope.currentPage; + + var first = ($scope.currentPage * $scope.pageSize) - $scope.pageSize; + console.log('first:' + first); + var queryParams = { + realm : realm.realm, + first : first, + max : $scope.pageSize + }; + var countParams = { + realm : realm.realm, + top : 'true' + }; + + if(angular.isDefined(search) && search !== '') { + queryParams.search = search; + countParams.search = search; + } + + var promiseGetGroups = $q.defer(); + Groups.query(queryParams, function(entry) { + promiseGetGroups.resolve(entry); + }, function() { + promiseGetGroups.reject($translate.instant('group.fetch.fail', {params: queryParams})); + }); + promiseGetGroups.promise.then(function(groups) { + $scope.groupList = [ + { + "id" : "realm", + "name": $translate.instant('groups'), + "subGroups": ComponentUtils.sortGroups('name', groups) + } + ]; + if (angular.isDefined(search) && search !== '') { + // Add highlight for concrete text match + setTimeout(function () { + document.querySelectorAll('span').forEach(function (element) { + if (element.textContent.indexOf(search) != -1) { + angular.element(element).addClass('highlight'); + } + }); + }, 500); + } + }, function (failed) { + Notifications.error(failed); + }); + + var promiseCount = $q.defer(); + console.log('countParams: realm[' + countParams.realm); + GroupsCount.query(countParams, function(entry) { + promiseCount.resolve(entry); + }, function() { + promiseCount.reject($translate.instant('group.fetch.fail', {params: countParams})); + }); + promiseCount.promise.then(function(entry) { + if(angular.isDefined(entry.count) && entry.count > $scope.pageSize) { + $scope.numberOfPages = Math.ceil(entry.count/$scope.pageSize); + } else { + $scope.numberOfPages = 1; + } + }, function (failed) { + Notifications.error(failed); + }); + }; + refreshGroups(); + + $scope.$watch('currentPage', function(newValue, oldValue) { + if(parseInt(newValue, 10) !== oldValue) { + refreshGroups($scope.searchCriteria); + } + }); + + $scope.clearSearch = function() { + $scope.searchCriteria = ''; + if (parseInt($scope.currentPage, 10) === 1) { + refreshGroups(); + } else { + $scope.currentPage = 1; + } + }; + + $scope.searchGroup = function() { + if (parseInt($scope.currentPage, 10) === 1) { + refreshGroups($scope.searchCriteria); + } else { + $scope.currentPage = 1; + } + }; + + $scope.edit = function(selected) { + if (selected.id === 'realm') return; + $location.url("/realms/" + realm.realm + "/groups/" + selected.id); + }; + + $scope.cut = function(selected) { + $scope.cutNode = selected; + }; + + $scope.isDisabled = function() { + if (!$scope.tree.currentNode) return true; + return $scope.tree.currentNode.id === 'realm'; + }; + + $scope.paste = function(selected) { + if (selected === null) return; + if ($scope.cutNode === null) return; + if (selected.id === $scope.cutNode.id) return; + if (selected.id === 'realm') { + Groups.save({realm: realm.realm}, {id:$scope.cutNode.id, name: $scope.cutNode.name}, function() { + $route.reload(); + Notifications.success($translate.instant('group.move.success')); + + }); + + } else { + GroupChildren.save({realm: realm.realm, groupId: selected.id}, {id:$scope.cutNode.id, name: $scope.cutNode.name}, function() { + $route.reload(); + Notifications.success($translate.instant('group.move.success')); + + }); + + } + + }; + + $scope.remove = function(selected) { + if (selected === null) return; + Dialog.confirmWithButtonText( + $translate.instant('group.remove.confirm.title', {name: selected.name}), + $translate.instant('group.remove.confirm.message', {name: selected.name}), + $translate.instant('dialogs.delete.confirm'), + function() { + Group.remove({ realm: realm.realm, groupId : selected.id }, function() { + $route.reload(); + Notifications.success($translate.instant('group.remove.success')); + }); + } + ); + }; + + $scope.createGroup = function(selected) { + var parent = 'realm'; + if (selected) { + parent = selected.id; + } + $location.url("/create/group/" + realm.realm + '/parent/' + parent); + + }; + var isLeaf = function(node) { + return node.id !== "realm" && (!node.subGroups || node.subGroups.length === 0); + }; + + $scope.getGroupClass = function(node) { + if (node.id === "realm") { + return 'pficon pficon-users'; + } + if (isLeaf(node)) { + return 'normal'; + } + if (node.subGroups.length && node.collapsed) return 'collapsed'; + if (node.subGroups.length && !node.collapsed) return 'expanded'; + return 'collapsed'; + + }; + + $scope.getSelectedClass = function(node) { + if (node.selected) { + return 'selected'; + } else if ($scope.cutNode && $scope.cutNode.id === node.id) { + return 'cut'; + } + return undefined; + } + +}); + +module.controller('GroupCreateCtrl', function($scope, $route, realm, parentId, Groups, Group, GroupChildren, Notifications, $location, $translate) { + $scope.realm = realm; + $scope.group = {}; + $scope.save = function() { + console.log('save!!!'); + if (parentId === 'realm') { + console.log('realm'); + Groups.save({realm: realm.realm}, $scope.group, function(data, headers) { + var l = headers().location; + + + var id = l.substring(l.lastIndexOf("/") + 1); + + $location.url("/realms/" + realm.realm + "/groups/" + id); + Notifications.success($translate.instant('group.create.success')); + }) + + } else { + GroupChildren.save({realm: realm.realm, groupId: parentId}, $scope.group, function(data, headers) { + var l = headers().location; + + + var id = l.substring(l.lastIndexOf("/") + 1); + + $location.url("/realms/" + realm.realm + "/groups/" + id); + Notifications.success($translate.instant('group.create.success')); + }) + + } + + }; + $scope.cancel = function() { + $location.url("/realms/" + realm.realm + "/groups"); + }; +}); + +module.controller('GroupTabCtrl', function(Dialog, $scope, Current, Group, Notifications, $location, $translate) { + $scope.removeGroup = function() { + Dialog.confirmWithButtonText( + $translate.instant('group.remove.confirm.title', {name: $scope.group.name}), + $translate.instant('group.remove.confirm.message', {name: $scope.group.name}), + $translate.instant('dialogs.delete.confirm'), + function() { + Group.remove({ + realm : Current.realm.realm, + groupId : $scope.group.id + }, function() { + $location.url("/realms/" + Current.realm.realm + "/groups"); + Notifications.success($translate.instant('group.remove.success')); + }); + } + ); + }; +}); + +module.controller('GroupDetailCtrl', function(Dialog, $scope, realm, group, Group, Notifications, $location, $translate) { + $scope.realm = realm; + + if (!group.attributes) { + group.attributes = {} + } + convertAttributeValuesToString(group); + + + $scope.group = angular.copy(group); + + $scope.changed = false; // $scope.create; + $scope.$watch('group', function() { + if (!angular.equals($scope.group, group)) { + $scope.changed = true; + } + }, true); + + $scope.save = function() { + convertAttributeValuesToLists(); + + Group.update({ + realm: realm.realm, + groupId: $scope.group.id + }, $scope.group, function () { + $scope.changed = false; + convertAttributeValuesToString($scope.group); + group = angular.copy($scope.group); + Notifications.success($translate.instant('group.edit.success')); + }); + }; + + function convertAttributeValuesToLists() { + var attrs = $scope.group.attributes; + for (var attribute in attrs) { + if (typeof attrs[attribute] === "string") { + attrs[attribute] = attrs[attribute].split("##"); + } + } + } + + function convertAttributeValuesToString(group) { + var attrs = group.attributes; + for (var attribute in attrs) { + if (typeof attrs[attribute] === "object") { + attrs[attribute] = attrs[attribute].join("##"); + } + } + } + + $scope.reset = function() { + $scope.group = angular.copy(group); + $scope.changed = false; + }; + + $scope.cancel = function() { + $location.url("/realms/" + realm.realm + "/groups"); + }; + + $scope.addAttribute = function() { + $scope.group.attributes[$scope.newAttribute.key] = $scope.newAttribute.value; + delete $scope.newAttribute; + } + + $scope.removeAttribute = function(key) { + delete $scope.group.attributes[key]; + } +}); + +module.controller('GroupRoleMappingCtrl', function($scope, $http, $route, realm, group, clients, client, Client, Notifications, GroupRealmRoleMapping, + GroupClientRoleMapping, GroupAvailableRealmRoleMapping, GroupAvailableClientRoleMapping, + GroupCompositeRealmRoleMapping, GroupCompositeClientRoleMapping, $translate) { + $scope.realm = realm; + $scope.group = group; + $scope.selectedRealmRoles = []; + $scope.selectedRealmMappings = []; + $scope.realmMappings = []; + $scope.clients = clients; + $scope.client = client; + $scope.clientRoles = []; + $scope.clientComposite = []; + $scope.selectedClientRoles = []; + $scope.selectedClientMappings = []; + $scope.clientMappings = []; + $scope.dummymodel = []; + + $scope.realmMappings = GroupRealmRoleMapping.query({realm : realm.realm, groupId : group.id}); + $scope.realmRoles = GroupAvailableRealmRoleMapping.query({realm : realm.realm, groupId : group.id}); + $scope.realmComposite = GroupCompositeRealmRoleMapping.query({realm : realm.realm, groupId : group.id}); + + $scope.addRealmRole = function() { + $scope.selectedRealmRolesToAdd = JSON.parse('[' + $scope.selectedRealmRoles + ']'); + $scope.selectedRealmRoles = []; + $http.post(authUrl + '/admin/realms/' + realm.realm + '/groups/' + group.id + '/role-mappings/realm', + $scope.selectedRealmRolesToAdd).then(function() { + $scope.realmMappings = GroupRealmRoleMapping.query({realm : realm.realm, groupId : group.id}); + $scope.realmRoles = GroupAvailableRealmRoleMapping.query({realm : realm.realm, groupId : group.id}); + $scope.realmComposite = GroupCompositeRealmRoleMapping.query({realm : realm.realm, groupId : group.id}); + $scope.selectedRealmMappings = []; + $scope.selectRealmRoles = []; + if ($scope.selectedClient) { + console.log('load available'); + $scope.clientComposite = GroupCompositeClientRoleMapping.query({realm : realm.realm, groupId : group.id, client : $scope.selectedClient.id}); + $scope.clientRoles = GroupAvailableClientRoleMapping.query({realm : realm.realm, groupId : group.id, client : $scope.selectedClient.id}); + $scope.clientMappings = GroupClientRoleMapping.query({realm : realm.realm, groupId : group.id, client : $scope.selectedClient.id}); + $scope.selectedClientRoles = []; + $scope.selectedClientMappings = []; + } + $scope.selectedRealmRolesToAdd = []; + Notifications.success($translate.instant('group.roles.add.success')); + + }); + }; + + $scope.deleteRealmRole = function() { + $scope.selectedRealmMappingsToRemove = JSON.parse('[' + $scope.selectedRealmMappings + ']'); + $http.delete(authUrl + '/admin/realms/' + realm.realm + '/groups/' + group.id + '/role-mappings/realm', + {data : $scope.selectedRealmMappingsToRemove, headers : {"content-type" : "application/json"}}).then(function() { + $scope.realmMappings = GroupRealmRoleMapping.query({realm : realm.realm, groupId : group.id}); + $scope.realmRoles = GroupAvailableRealmRoleMapping.query({realm : realm.realm, groupId : group.id}); + $scope.realmComposite = GroupCompositeRealmRoleMapping.query({realm : realm.realm, groupId : group.id}); + $scope.selectedRealmMappings = []; + $scope.selectRealmRoles = []; + if ($scope.selectedClient) { + console.log('load available'); + $scope.clientComposite = GroupCompositeClientRoleMapping.query({realm : realm.realm, groupId : group.id, client : $scope.selectedClient.id}); + $scope.clientRoles = GroupAvailableClientRoleMapping.query({realm : realm.realm, groupId : group.id, client : $scope.selectedClient.id}); + $scope.clientMappings = GroupClientRoleMapping.query({realm : realm.realm, groupId : group.id, client : $scope.selectedClient.id}); + $scope.selectedClientRoles = []; + $scope.selectedClientMappings = []; + } + $scope.selectedRealmMappingsToRemove = []; + Notifications.success($translate.instant('group.roles.remove.success')); + }); + }; + + $scope.addClientRole = function() { + $scope.selectedClientRolesToAdd = JSON.parse('[' + $scope.selectedClientRoles + ']'); + $http.post(authUrl + '/admin/realms/' + realm.realm + '/groups/' + group.id + '/role-mappings/clients/' + $scope.selectedClient.id, + $scope.selectedClientRolesToAdd).then(function() { + $scope.clientMappings = GroupClientRoleMapping.query({realm : realm.realm, groupId : group.id, client : $scope.selectedClient.id}); + $scope.clientRoles = GroupAvailableClientRoleMapping.query({realm : realm.realm, groupId : group.id, client : $scope.selectedClient.id}); + $scope.clientComposite = GroupCompositeClientRoleMapping.query({realm : realm.realm, groupId : group.id, client : $scope.selectedClient.id}); + $scope.selectedClientRoles = []; + $scope.selectedClientMappings = []; + $scope.realmComposite = GroupCompositeRealmRoleMapping.query({realm : realm.realm, groupId : group.id}); + $scope.realmRoles = GroupAvailableRealmRoleMapping.query({realm : realm.realm, groupId : group.id}); + $scope.selectedClientRolesToAdd = []; + Notifications.success($translate.instant('group.roles.add.success')); + }); + }; + + $scope.deleteClientRole = function() { + $scope.selectedClientMappingsToRemove = JSON.parse('[' + $scope.selectedClientMappings + ']'); + $http.delete(authUrl + '/admin/realms/' + realm.realm + '/groups/' + group.id + '/role-mappings/clients/' + $scope.selectedClient.id, + {data : $scope.selectedClientMappingsToRemove, headers : {"content-type" : "application/json"}}).then(function() { + $scope.clientMappings = GroupClientRoleMapping.query({realm : realm.realm, groupId : group.id, client : $scope.selectedClient.id}); + $scope.clientRoles = GroupAvailableClientRoleMapping.query({realm : realm.realm, groupId : group.id, client : $scope.selectedClient.id}); + $scope.clientComposite = GroupCompositeClientRoleMapping.query({realm : realm.realm, groupId : group.id, client : $scope.selectedClient.id}); + $scope.selectedClientRoles = []; + $scope.selectedClientMappings = []; + $scope.realmComposite = GroupCompositeRealmRoleMapping.query({realm : realm.realm, groupId : group.id}); + $scope.realmRoles = GroupAvailableRealmRoleMapping.query({realm : realm.realm, groupId : group.id}); + $scope.selectedClientMappingsToRemove = []; + Notifications.success($translate.instant('group.roles.remove.success')); + }); + }; + + + $scope.changeClient = function(client) { + $scope.selectedClient = client; + if (!client || !client.id) { + $scope.selectedClient = null; + $scope.clientRoles = null; + $scope.clientMappings = null; + $scope.clientComposite = null; + return; + } + if ($scope.selectedClient) { + $scope.clientComposite = GroupCompositeClientRoleMapping.query({realm : realm.realm, groupId : group.id, client : $scope.selectedClient.id}); + $scope.clientRoles = GroupAvailableClientRoleMapping.query({realm : realm.realm, groupId : group.id, client : $scope.selectedClient.id}); + $scope.clientMappings = GroupClientRoleMapping.query({realm : realm.realm, groupId : group.id, client : $scope.selectedClient.id}); + } + $scope.selectedClientRoles = []; + $scope.selectedClientMappings = []; + }; + + clientSelectControl($scope, $route.current.params.realm, Client); + +}); + +module.controller('GroupMembersCtrl', function($scope, realm, group, GroupMembership) { + $scope.realm = realm; + $scope.page = 0; + $scope.group = group; + + $scope.query = { + realm: realm.realm, + groupId: group.id, + max : 5, + first : 0 + }; + + + $scope.firstPage = function() { + $scope.query.first = 0; + $scope.searchQuery(); + }; + + $scope.previousPage = function() { + $scope.query.first -= parseInt($scope.query.max); + if ($scope.query.first < 0) { + $scope.query.first = 0; + } + $scope.searchQuery(); + }; + + $scope.nextPage = function() { + $scope.query.first += parseInt($scope.query.max); + $scope.searchQuery(); + }; + + $scope.searchQuery = function() { + console.log("query.search: " + $scope.query.search); + $scope.searchLoaded = false; + + $scope.users = GroupMembership.query($scope.query, function() { + console.log('search loaded'); + $scope.searchLoaded = true; + $scope.lastSearch = $scope.query.search; + }); + }; + + $scope.searchQuery(); + +}); + +module.controller('DefaultGroupsCtrl', function($scope, $q, realm, Groups, GroupsCount, DefaultGroups, Notifications, $translate) { + $scope.realm = realm; + $scope.groupList = []; + $scope.selectedGroup = null; + $scope.tree = []; + + $scope.searchCriteria = ''; + $scope.currentPage = 1; + $scope.currentPageInput = $scope.currentPage; + $scope.pageSize = 20; + $scope.numberOfPages = 1; + + var refreshDefaultGroups = function () { + DefaultGroups.query({realm: realm.realm}, function(data) { + $scope.defaultGroups = data; + }); + } + + var refreshAvailableGroups = function (search) { + var first = ($scope.currentPage * $scope.pageSize) - $scope.pageSize; + $scope.currentPageInput = $scope.currentPage; + var queryParams = { + realm : realm.realm, + first : first, + max : $scope.pageSize + }; + var countParams = { + realm : realm.realm, + top : 'true' + }; + + if(angular.isDefined(search) && search !== '') { + queryParams.search = search; + countParams.search = search; + } + + var promiseGetGroups = $q.defer(); + Groups.query(queryParams, function(entry) { + promiseGetGroups.resolve(entry); + }, function() { + promiseGetGroups.reject($translate.instant('group.fetch.fail', {params: queryParams})); + }); + promiseGetGroups.promise.then(function(groups) { + $scope.groupList = groups; + }, function (failed) { + Notifications.success(failed); + }); + + var promiseCount = $q.defer(); + GroupsCount.query(countParams, function(entry) { + promiseCount.resolve(entry); + }, function() { + promiseCount.reject($translate.instant('group.fetch.fail', {params: countParams})); + }); + promiseCount.promise.then(function(entry) { + if(angular.isDefined(entry.count) && entry.count > $scope.pageSize) { + $scope.numberOfPages = Math.ceil(entry.count/$scope.pageSize); + } + }, function (failed) { + Notifications.success(failed); + }); + }; + + refreshAvailableGroups(); + + $scope.$watch('currentPage', function(newValue, oldValue) { + if(parseInt(newValue, 10) !== parseInt(oldValue, 10)) { + refreshAvailableGroups($scope.searchCriteria); + } + }); + + $scope.clearSearch = function() { + $scope.searchCriteria = ''; + if (parseInt($scope.currentPage, 10) === 1) { + refreshAvailableGroups(); + } else { + $scope.currentPage = 1; + } + }; + + $scope.searchGroup = function() { + if (parseInt($scope.currentPage, 10) === 1) { + refreshAvailableGroups($scope.searchCriteria); + } else { + $scope.currentPage = 1; + } + }; + + refreshDefaultGroups(); + + $scope.addDefaultGroup = function() { + if (!$scope.tree.currentNode) { + Notifications.error($translate.instant('group.default.add.error')); + return; + } + + DefaultGroups.update({realm: realm.realm, groupId: $scope.tree.currentNode.id}, function() { + refreshDefaultGroups(); + Notifications.success($translate.instant('group.default.add.success')); + }); + + }; + + $scope.removeDefaultGroup = function() { + DefaultGroups.remove({realm: realm.realm, groupId: $scope.selectedGroup.id}, function() { + refreshDefaultGroups(); + Notifications.success($translate.instant('group.default.remove.success')); + }); + + }; + + var isLeaf = function(node) { + return node.id !== "realm" && (!node.subGroups || node.subGroups.length === 0); + }; + + $scope.getGroupClass = function(node) { + if (node.id === "realm") { + return 'pficon pficon-users'; + } + if (isLeaf(node)) { + return 'normal'; + } + if (node.subGroups.length && node.collapsed) return 'collapsed'; + if (node.subGroups.length && !node.collapsed) return 'expanded'; + return 'collapsed'; + + }; + + $scope.getSelectedClass = function(node) { + if (node.selected) { + return 'selected'; + } else if ($scope.cutNode && $scope.cutNode.id === node.id) { + return 'cut'; + } + return undefined; + } + +}); diff --git a/keycloak-themes/base/admin/resources/js/controllers/realm.js b/keycloak-themes/base/admin/resources/js/controllers/realm.js new file mode 100644 index 0000000..dbe8f43 --- /dev/null +++ b/keycloak-themes/base/admin/resources/js/controllers/realm.js @@ -0,0 +1,4552 @@ +function getAccess(Auth, Current, role) { + if (!Current.realm)return false; + var realmAccess = Auth.user && Auth.user['realm_access']; + if (realmAccess) { + realmAccess = realmAccess[Current.realm.realm]; + if (realmAccess) { + return realmAccess.indexOf(role) >= 0; + } + } + return false; +} + +function getAccessObject(Auth, Current) { + return { + get createRealm() { + return Auth.user && Auth.user.createRealm; + }, + + get queryUsers() { + return getAccess(Auth, Current, 'query-users') || this.viewUsers; + }, + + get queryGroups() { + return getAccess(Auth, Current, 'query-groups') || this.viewUsers; + }, + + get queryClients() { + return getAccess(Auth, Current, 'query-clients') || this.viewClients; + }, + + get viewRealm() { + return getAccess(Auth, Current, 'view-realm') || getAccess(Auth, Current, 'manage-realm') || this.manageRealm; + }, + + get viewClients() { + return getAccess(Auth, Current, 'view-clients') || getAccess(Auth, Current, 'manage-clients') || this.manageClients; + }, + + get viewUsers() { + return getAccess(Auth, Current, 'view-users') || getAccess(Auth, Current, 'manage-users') || this.manageClients; + }, + + get viewEvents() { + return getAccess(Auth, Current, 'view-events') || getAccess(Auth, Current, 'manage-events') || this.manageClients; + }, + + get viewIdentityProviders() { + return getAccess(Auth, Current, 'view-identity-providers') || getAccess(Auth, Current, 'manage-identity-providers') || this.manageIdentityProviders; + }, + + get viewAuthorization() { + return getAccess(Auth, Current, 'view-authorization') || this.manageAuthorization; + }, + + get manageRealm() { + return getAccess(Auth, Current, 'manage-realm'); + }, + + get manageClients() { + return getAccess(Auth, Current, 'manage-clients'); + }, + + get manageUsers() { + return getAccess(Auth, Current, 'manage-users'); + }, + + get manageEvents() { + return getAccess(Auth, Current, 'manage-events'); + }, + + get manageIdentityProviders() { + return getAccess(Auth, Current, 'manage-identity-providers'); + }, + + get manageAuthorization() { + return getAccess(Auth, Current, 'manage-authorization'); + }, + + get impersonation() { + return getAccess(Auth, Current, 'impersonation'); + } + }; +} + + +module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location, Notifications, ServerInfo, RealmSpecificLocalizationTexts) { + $scope.authUrl = authUrl; + $scope.resourceUrl = resourceUrl; + $scope.auth = Auth; + $scope.serverInfo = ServerInfo.get(); + + $scope.access = getAccessObject(Auth, Current); + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.fragment = $location.path(); + $scope.path = $location.path().substring(1).split("/"); + }); + + $scope.$watch(function() { + return Current.realm; + }, function() { + if(Current.realm !== null && currentRealm !== Current.realm.id) { + currentRealm = Current.realm.id; + translateProvider.translations(locale, resourceBundle); + RealmSpecificLocalizationTexts.get({id: Current.realm.realm, locale: locale}, function (localizationTexts) { + translateProvider.translations(locale, localizationTexts.toJSON()); + }) + } + }) +}); + +module.controller('HomeCtrl', function(Realm, Auth, Current, $location) { + + Realm.query(null, function(realms) { + var realm; + if (realms.length == 1) { + realm = realms[0]; + } else if (realms.length == 2) { + if (realms[0].realm == Auth.user.realm) { + realm = realms[1]; + } else if (realms[1].realm == Auth.user.realm) { + realm = realms[0]; + } + } + if (realm) { + Current.realms = realms; + Current.realm = realm; + var access = getAccessObject(Auth, Current); + if (access.viewRealm || access.manageRealm) { + $location.url('/realms/' + realm.realm ); + } else if (access.queryClients) { + $location.url('/realms/' + realm.realm + "/clients"); + } else if (access.viewIdentityProviders) { + $location.url('/realms/' + realm.realm + "/identity-provider-settings"); + } else if (access.queryUsers) { + $location.url('/realms/' + realm.realm + "/users"); + } else if (access.queryGroups) { + $location.url('/realms/' + realm.realm + "/groups"); + } else if (access.viewEvents) { + $location.url('/realms/' + realm.realm + "/events"); + } + } else { + $location.url('/realms'); + } + }); +}); + +module.controller('RealmTabCtrl', function(Dialog, $scope, Current, Realm, Notifications, $location) { + $scope.removeRealm = function() { + Dialog.confirmDelete(Current.realm.realm, 'realm', function() { + Realm.remove({ id : Current.realm.realm }, function() { + Current.realms = Realm.query(); + Notifications.success("The realm has been deleted."); + $location.url("/"); + }); + }); + }; +}); + +module.controller('ServerInfoCtrl', function($scope, ServerInfo) { + ServerInfo.reload(); + + $scope.serverInfo = ServerInfo.get(); + + $scope.$watch($scope.serverInfo, function() { + $scope.providers = []; + for(var spi in $scope.serverInfo.providers) { + var p = angular.copy($scope.serverInfo.providers[spi]); + p.name = spi; + $scope.providers.push(p) + } + }); + + $scope.serverInfoReload = function() { + ServerInfo.reload(); + } +}); + +module.controller('RealmListCtrl', function($scope, Realm, Current) { + $scope.realms = Realm.query(); + Current.realms = $scope.realms; +}); + +module.controller('RealmDropdownCtrl', function($scope, Realm, Current, Auth, $location) { +// Current.realms = Realm.get(); + $scope.current = Current; + + $scope.isCreateEndpoint = function(endpoint) { + return $scope.path.length > 1 && $scope.path[0] === 'create' && $scope.path[1] === endpoint; + } + + $scope.changeRealm = function(selectedRealm) { + $location.url("/realms/" + selectedRealm); + } +}); + +module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $http, $location, $route, Dialog, Notifications, Auth, $modal) { + console.log('RealmCreateCtrl'); + + Current.realm = null; + + $scope.realm = { + enabled: true + }; + + $scope.changed = false; + $scope.files = []; + + var oldCopy = angular.copy($scope.realm); + + $scope.importFile = function($fileContent){ + $scope.realm = angular.copy(JSON.parse($fileContent)); + $scope.importing = true; + }; + + $scope.viewImportDetails = function() { + $modal.open({ + templateUrl: resourceUrl + '/partials/modal/view-object.html', + controller: 'ObjectModalCtrl', + resolve: { + object: function () { + return $scope.realm; + } + } + }) + }; + + $scope.$watch('realm', function() { + if (!angular.equals($scope.realm, oldCopy)) { + $scope.changed = true; + } + }, true); + + $scope.$watch('realm.realm', function() { + $scope.realm.id = $scope.realm.realm; + }, true); + + $scope.save = function() { + var realmCopy = angular.copy($scope.realm); + Realm.create(realmCopy, function() { + Notifications.success("The realm has been created."); + + Auth.refreshPermissions(function() { + $scope.$apply(function() { + $location.url("/realms/" + realmCopy.realm); + }); + }); + }); + }; + + $scope.cancel = function() { + $location.url("/"); + }; + + $scope.reset = function() { + $route.reload(); + } +}); + +module.controller('ObjectModalCtrl', function($scope, object) { + $scope.object = object; +}); + +module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, serverInfo, $http, $location, $window, Dialog, Notifications, Auth) { + $scope.createRealm = !realm.realm; + $scope.serverInfo = serverInfo; + $scope.realmName = realm.realm; + $scope.disableRename = realm.realm == masterRealm; + $scope.authServerUrl = authServerUrl; + + if (Current.realm == null || Current.realm.realm != realm.realm) { + for (var i = 0; i < Current.realms.length; i++) { + if (realm.realm == Current.realms[i].realm) { + Current.realm = Current.realms[i]; + break; + } + } + } + for (var i = 0; i < Current.realms.length; i++) { + if (Current.realms[i].realm == realm.realm) { + Current.realm = Current.realms[i]; + } + } + $scope.realm = angular.copy(realm); + + if ($scope.realm.attributes != null) { + $scope.realm.attributes['userProfileEnabled'] = $scope.realm.attributes['userProfileEnabled'] == 'true'; + } + + var oldCopy = angular.copy($scope.realm); + $scope.realmCopy = oldCopy; + + $scope.changed = $scope.create; + + $scope.$watch('realm', function() { + if (!angular.equals($scope.realm, oldCopy)) { + $scope.changed = true; + } + }, true); + $scope.$watch('realmName', function() { + if (!angular.equals($scope.realmName, oldCopy.realm)) { + $scope.changed = true; + } + }, true); + + $scope.save = function() { + var realmCopy = angular.copy($scope.realm); + realmCopy.realm = $scope.realmName; + $scope.changed = false; + var nameChanged = !angular.equals($scope.realmName, oldCopy.realm); + var oldName = oldCopy.realm; + Realm.update({ id : oldCopy.realm}, realmCopy, function () { + var data = Realm.query(function () { + Current.realms = data; + for (var i = 0; i < Current.realms.length; i++) { + if (Current.realms[i].realm == realmCopy.realm) { + Current.realm = Current.realms[i]; + oldCopy = angular.copy($scope.realm); + $scope.realmCopy = oldCopy; + } + } + }); + + if (nameChanged) { + console.debug(Auth); + console.debug(Auth.authz.tokenParsed.iss); + + if (Auth.authz.tokenParsed.iss.endsWith(masterRealm)) { + Auth.refreshPermissions(function () { + Auth.refreshPermissions(function () { + Notifications.success("Your changes have been saved to the realm."); + $scope.$apply(function () { + $location.url("/realms/" + realmCopy.realm); + }); + }); + }); + } else { + delete Auth.authz.token; + delete Auth.authz.refreshToken; + + var newLocation = $window.location.href.replace('/' + oldName + '/', '/' + realmCopy.realm + '/') + .replace('/realms/' + oldName, '/realms/' + realmCopy.realm); + window.location.replace(newLocation); + } + } else { + $location.url("/realms/" + realmCopy.realm); + Notifications.success("Your changes have been saved to the realm."); + } + }); + }; + + $scope.reset = function() { + $scope.realm = angular.copy(oldCopy); + $scope.changed = false; + }; + + $scope.cancel = function() { + window.history.back(); + }; +}); + +function genericRealmUpdate($scope, Current, Realm, realm, serverInfo, $http, $route, Dialog, Notifications, url, saveCallback, resetCallback) { + $scope.realm = angular.copy(realm); + $scope.serverInfo = serverInfo; + $scope.registrationAllowed = $scope.realm.registrationAllowed; + + var oldCopy = angular.copy($scope.realm); + + $scope.changed = false; + + $scope.$watch('realm', function() { + if (!angular.equals($scope.realm, oldCopy)) { + $scope.changed = true; + } + }, true); + + $scope.save = function() { + if (saveCallback) { + saveCallback(); + } + var realmCopy = angular.copy($scope.realm); + console.log('updating realm...'); + $scope.changed = false; + console.log('oldCopy.realm - ' + oldCopy.realm); + Realm.update({ id : oldCopy.realm}, realmCopy, function () { + $route.reload(); + Notifications.success("Your changes have been saved to the realm."); + $scope.registrationAllowed = $scope.realm.registrationAllowed; + }); + }; + + $scope.reset = function() { + $scope.realm = angular.copy(oldCopy); + if (resetCallback) { + resetCallback(); + } + $scope.changed = false; + }; + + $scope.cancel = function() { + $route.reload(); + }; + +} + +module.controller('DefenseHeadersCtrl', function($scope, Current, Realm, realm, serverInfo, $http, $route, Dialog, Notifications) { + genericRealmUpdate($scope, Current, Realm, realm, serverInfo, $http, $route, Dialog, Notifications, "/realms/" + realm.realm + "/defense/headers"); +}); + +module.controller('RealmLoginSettingsCtrl', function($scope, Current, Realm, realm, serverInfo, $http, $route, Dialog, Notifications) { + // KEYCLOAK-5474: Make sure duplicateEmailsAllowed is disabled if loginWithEmailAllowed + $scope.$watch('realm.loginWithEmailAllowed', function() { + if ($scope.realm.loginWithEmailAllowed) { + $scope.realm.duplicateEmailsAllowed = false; + } + }); + + var resetCallback = function() { + try { + $scope.acrLoaMap = JSON.parse(realm.attributes["acr.loa.map"] || "{}"); + } catch (e) { + $scope.acrLoaMap = {}; + } + } + resetCallback(); + var previousNewAcr = undefined; + var previousNewLoa = undefined; + + $scope.$watch('newAcr', function() { + var changed = $scope.newAcr != previousNewAcr; + if (changed) { + previousNewAcr = $scope.newAcr; + $scope.changed = true; + } + }, true); + $scope.$watch('newLoa', function() { + var changed = $scope.newLoa != previousNewLoa; + if (changed) { + previousNewLoa = $scope.newLoa; + $scope.changed = true; + } + }, true); + $scope.deleteAcrLoaMapping = function(acr) { + delete $scope.acrLoaMap[acr]; + $scope.changed = true; + updateRealmAcrAttribute(); + } + $scope.checkAddAcrLoaMapping = function() { + if ($scope.newAcr && $scope.newAcr.length > 0 && $scope.newLoa && $scope.newLoa.length > 0 && $scope.newLoa.match(/^[0-9]+$/)) { + console.log("Adding acrLoaMapping: " + $scope.newLoa + " : " + $scope.newAcr); + $scope.acrLoaMap[$scope.newAcr] = $scope.newLoa; + $scope.newAcr = $scope.newLoa = ""; + $scope.changed = true; + updateRealmAcrAttribute(); + } + } + + function updateRealmAcrAttribute() { + var acrLoaMapStr = JSON.stringify($scope.acrLoaMap); + console.log("Updating realm acr.loa.map attribute: " + acrLoaMapStr); + $scope.realm.attributes["acr.loa.map"] = acrLoaMapStr; + } + + genericRealmUpdate($scope, Current, Realm, realm, serverInfo, $http, $route, Dialog, Notifications, "/realms/" + realm.realm + "/login-settings", $scope.checkAddAcrLoaMapping, resetCallback); +}); + +module.controller('RealmOtpPolicyCtrl', function($scope, Current, Realm, realm, serverInfo, $http, $route, Dialog, Notifications) { + $scope.optionsDigits = [ 6, 8 ]; + + genericRealmUpdate($scope, Current, Realm, realm, serverInfo, $http, $route, Dialog, Notifications, "/realms/" + realm.realm + "/authentication/otp-policy"); +}); + +module.controller('RealmWebAuthnPolicyCtrl', function ($scope, Current, Realm, realm, serverInfo, $http, $route, $location, Dialog, Notifications) { + + $scope.deleteAcceptableAaguid = function(index) { + $scope.realm.webAuthnPolicyAcceptableAaguids.splice(index, 1); + }; + + $scope.addAcceptableAaguid = function() { + $scope.realm.webAuthnPolicyAcceptableAaguids.push($scope.newAcceptableAaguid); + $scope.newAcceptableAaguid = ""; + }; + + // Just for case the user fill particular URL with disabled WebAuthn feature. + $scope.redirectIfWebAuthnDisabled = function () { + if (!serverInfo.featureEnabled('WEB_AUTHN')) { + $location.url("/realms/" + $scope.realm.realm + "/authentication"); + } + }; + + genericRealmUpdate($scope, Current, Realm, realm, serverInfo, $http, $route, Dialog, Notifications, "/realms/" + realm.realm + "/authentication/webauthn-policy"); +}); + +module.controller('RealmWebAuthnPasswordlessPolicyCtrl', function ($scope, Current, Realm, realm, serverInfo, $http, $route, $location, Dialog, Notifications) { + + $scope.deleteAcceptableAaguid = function(index) { + $scope.realm.webAuthnPolicyPasswordlessAcceptableAaguids.splice(index, 1); + }; + + $scope.addAcceptableAaguid = function() { + $scope.realm.webAuthnPolicyPasswordlessAcceptableAaguids.push($scope.newAcceptableAaguid); + $scope.newAcceptableAaguid = ""; + }; + + // Just for case the user fill particular URL with disabled WebAuthn feature. + $scope.redirectIfWebAuthnDisabled = function () { + if (!serverInfo.featureEnabled('WEB_AUTHN')) { + $location.url("/realms/" + $scope.realm.realm + "/authentication"); + } + }; + + genericRealmUpdate($scope, Current, Realm, realm, serverInfo, $http, $route, Dialog, Notifications, "/realms/" + realm.realm + "/authentication/webauthn-policy-passwordless"); +}); + +module.controller('RealmCibaPolicyCtrl', function ($scope, Current, Realm, realm, serverInfo, $http, $route, $location, Dialog, Notifications) { + + genericRealmUpdate($scope, Current, Realm, realm, serverInfo, $http, $route, Dialog, Notifications, "/realms/" + realm.realm + "/authentication/ciba-policy"); +}); + +module.controller('RealmThemeCtrl', function($scope, Current, Realm, realm, serverInfo, $http, $route, Dialog, Notifications) { + genericRealmUpdate($scope, Current, Realm, realm, serverInfo, $http, $route, Dialog, Notifications, "/realms/" + realm.realm + "/theme-settings"); + + $scope.supportedLocalesOptions = { + 'multiple' : true, + 'simple_tags' : true, + 'tags' : [] + }; + + updateSupported(); + + function localeForTheme(type, name) { + name = name || 'base'; + for (var i = 0; i < serverInfo.themes[type].length; i++) { + if (serverInfo.themes[type][i].name == name) { + return serverInfo.themes[type][i].locales || []; + } + } + return []; + } + + function updateSupported() { + if ($scope.realm.internationalizationEnabled) { + var accountLocales = localeForTheme('account', $scope.realm.accountTheme); + var loginLocales = localeForTheme('login', $scope.realm.loginTheme); + var emailLocales = localeForTheme('email', $scope.realm.emailTheme); + + var supportedLocales = []; + for (var i = 0; i < accountLocales.length; i++) { + var l = accountLocales[i]; + if (loginLocales.indexOf(l) >= 0 && emailLocales.indexOf(l) >= 0) { + supportedLocales.push(l); + } + } + + $scope.supportedLocalesOptions.tags = supportedLocales; + + if (!$scope.realm.supportedLocales) { + $scope.realm.supportedLocales = supportedLocales; + } else { + for (var i = 0; i < $scope.realm.supportedLocales.length; i++) { + if (supportedLocales.indexOf($scope.realm.supportedLocales[i]) == -1) { + $scope.realm.supportedLocales = supportedLocales; + } + } + } + + if (!$scope.realm.defaultLocale || supportedLocales.indexOf($scope.realm.defaultLocale) == -1) { + $scope.realm.defaultLocale = 'en'; + } + } + } + + $scope.$watch('realm.loginTheme', updateSupported); + $scope.$watch('realm.accountTheme', updateSupported); + $scope.$watch('realm.emailTheme', updateSupported); + $scope.$watch('realm.internationalizationEnabled', updateSupported); +}); + +module.controller('RealmLocalizationCtrl', function($scope, Current, $location, Realm, realm, serverInfo, Notifications, RealmSpecificLocales, realmSpecificLocales, RealmSpecificLocalizationTexts, RealmSpecificLocalizationText, Dialog, $translate){ + $scope.realm = realm; + $scope.realmSpecificLocales = realmSpecificLocales; + $scope.newLocale = null; + $scope.selectedRealmSpecificLocales = null; + $scope.localizationTexts = null; + + $scope.createLocale = function() { + if(!$scope.newLocale) { + Notifications.error($translate.instant('missing-locale')); + return; + } + $scope.realmSpecificLocales.push($scope.newLocale) + $scope.selectedRealmSpecificLocales = $scope.newLocale; + $scope.newLocale = null; + $location.url('/create/localization/' + realm.realm + '/' + $scope.selectedRealmSpecificLocales); + } + + $scope.$watch(function() { + return $scope.selectedRealmSpecificLocales; + }, function() { + if($scope.selectedRealmSpecificLocales != null) { + $scope.updateRealmSpecificLocalizationTexts(); + } + }) + + $scope.updateRealmSpecificLocales = function() { + RealmSpecificLocales.get({id: realm.realm}, function (updated) { + $scope.realmSpecificLocales = updated; + }) + } + + $scope.updateRealmSpecificLocalizationTexts = function() { + RealmSpecificLocalizationTexts.get({id: realm.realm, locale: $scope.selectedRealmSpecificLocales }, function (updated) { + $scope.localizationTexts = getSortedArrayByKeyFromObject(updated); + }) + } + + function getSortedArrayByKeyFromObject(object) { + const keys = Object.keys(object).sort(function (a, b) { + return a.localeCompare(b, locale); + }); + return keys.reduce(function (result, key) { + const value = object[key]; + if (typeof value !== 'string') { + return result; + } + return result.concat([[key, value]]); + }, []); + } + + $scope.removeLocalizationText = function(key) { + Dialog.confirmDelete(key, 'localization text', function() { + RealmSpecificLocalizationText.remove({ + realm: realm.realm, + locale: $scope.selectedRealmSpecificLocales, + key: key + }, function () { + $scope.updateRealmSpecificLocalizationTexts(); + Notifications.success($translate.instant('localization-text.remove.success')); + }); + }); + } +}); + +module.controller('RealmLocalizationUploadCtrl', function($scope, Current, Realm, realm, serverInfo, $http, $route, Dialog, Notifications, $upload, $translate){ + $scope.realm = realm; + $scope.locale = null; + $scope.files = []; + + $scope.onFileSelect = function($files) { + $scope.files = $files; + }; + + $scope.reset = function() { + $scope.locale = null; + $scope.files = null; + }; + + $scope.save = function() { + + if(!$scope.files || $scope.files.length === 0) { + Notifications.error($translate.instant('missing-file')); + return; + } + //$files: an array of files selected, each file has name, size, and type. + for (var i = 0; i < $scope.files.length; i++) { + var $file = $scope.files[i]; + $scope.upload = $upload.upload({ + url: authUrl + '/admin/realms/' + realm.realm + '/localization/' + $scope.locale, + file: $file + }).then(function(response) { + $scope.reset(); + Notifications.success($translate.instant('localization-file.upload.success')); + }).catch(function() { + Notifications.error($translate.instant('localization-file.upload.error')); + }); + } + }; + +}); + +module.controller('RealmLocalizationDetailCtrl', function($scope, Current, $location, Realm, realm, Notifications, locale, key, RealmSpecificLocalizationText, localizationText, $translate){ + $scope.realm = realm; + $scope.locale = locale; + $scope.key = key; + $scope.value = ((localizationText)? localizationText.content : null); + + $scope.create = !key; + + $scope.save = function() { + if ($scope.create) { + RealmSpecificLocalizationText.save({ + realm: realm.realm, + locale: $scope.locale, + key: $scope.key + }, $scope.value, function (data, headers) { + $location.url("/realms/" + realm.realm + "/localization"); + Notifications.success($translate.instant('localization-text.create.success')); + }); + } else { + RealmSpecificLocalizationText.save({ + realm: realm.realm, + locale: $scope.locale, + key: $scope.key + }, $scope.value, function (data, headers) { + $location.url("/realms/" + realm.realm + "/localization"); + Notifications.success($translate.instant('localization-text.update.success')); + }); + } + }; + + $scope.cancel = function () { + $location.url("/realms/" + realm.realm + "/localization"); + }; + +}); + +module.controller('RealmCacheCtrl', function($scope, realm, RealmClearUserCache, RealmClearRealmCache, RealmClearKeysCache, Notifications) { + $scope.realm = angular.copy(realm); + + $scope.clearUserCache = function() { + RealmClearUserCache.save({ realm: realm.realm}, function () { + Notifications.success("User cache cleared"); + }); + } + + $scope.clearRealmCache = function() { + RealmClearRealmCache.save({ realm: realm.realm}, function () { + Notifications.success("Realm cache cleared"); + }); + } + + $scope.clearKeysCache = function() { + RealmClearKeysCache.save({ realm: realm.realm}, function () { + Notifications.success("Public keys cache cleared"); + }); + } + + +}); + +module.controller('RealmPasswordPolicyCtrl', function($scope, Realm, realm, $http, $location, $route, Dialog, Notifications, serverInfo) { + var parse = function(policyString) { + var policies = []; + if (!policyString || policyString.length == 0){ + return policies; + } + + var policyArray = policyString.split(" and "); + + for (var i = 0; i < policyArray.length; i ++){ + var policyToken = policyArray[i]; + var id; + var value; + if (policyToken.indexOf('(') == -1) { + id = policyToken.trim(); + value = null; + } else { + id = policyToken.substring(0, policyToken.indexOf('(')); + value = policyToken.substring(policyToken.indexOf('(') + 1, policyToken.lastIndexOf(')')).trim(); + } + + for (var j = 0; j < serverInfo.passwordPolicies.length; j++) { + if (serverInfo.passwordPolicies[j].id == id) { + // clone + var p = JSON.parse(JSON.stringify(serverInfo.passwordPolicies[j])); + + p.value = value && value || p.defaultValue; + policies.push(p); + } + } + } + return policies; + }; + + var toString = function(policies) { + if (!policies || policies.length == 0) { + return ""; + } + var policyString = ""; + for (var i = 0; i < policies.length; i++) { + policyString += policies[i].id + '(' + policies[i].value + ')'; + if (i != policies.length - 1) { + policyString += ' and '; + } + } + return policyString; + } + + $scope.realm = realm; + $scope.serverInfo = serverInfo; + + $scope.changed = false; + console.log(JSON.stringify(parse(realm.passwordPolicy))); + $scope.policy = parse(realm.passwordPolicy); + var oldCopy = angular.copy($scope.policy); + + $scope.$watch('policy', function() { + $scope.changed = ! angular.equals($scope.policy, oldCopy); + }, true); + + $scope.addPolicy = function(policy){ + policy.value = policy.defaultValue; + if (!$scope.policy) { + $scope.policy = []; + } + $scope.policy.push(policy); + } + + $scope.removePolicy = function(index){ + $scope.policy.splice(index, 1); + } + + $scope.save = function() { + $scope.realm.passwordPolicy = toString($scope.policy); + console.log($scope.realm.passwordPolicy); + + Realm.update($scope.realm, function () { + $route.reload(); + Notifications.success("Your changes have been saved to the realm."); + }); + }; + + $scope.reset = function() { + $route.reload(); + }; +}); + +module.controller('RealmDefaultRolesCtrl', function ($scope, $route, realm, roles, Notifications, ClientRole, Client, RoleRealmComposites, RoleClientComposites, ComponentUtils, $http) { + + console.log('RealmDefaultRolesCtrl'); + + $scope.realm = realm; + $scope.availableRealmRoles = angular.copy(roles); + $scope.selectedRealmRoles = []; + $scope.selectedRealmDefRoles = []; + + $scope.availableClientRoles = []; + $scope.selectedClientRoles = []; + $scope.selectedClientDefRoles = []; + + for (var j = 0; j < $scope.availableRealmRoles.length; j++) { + if ($scope.availableRealmRoles[j].id === realm.defaultRole.id) { + var realmRole = $scope.availableRealmRoles[j]; + var idx = $scope.availableRealmRoles.indexOf(realmRole); + $scope.availableRealmRoles.splice(idx, 1); + break; + } + } + + $scope.realmMappings = RoleRealmComposites.query({realm : realm.realm, role : realm.defaultRole.id}, function(){ + for (var i = 0; i < $scope.realmMappings.length; i++) { + var role = $scope.realmMappings[i]; + for (var j = 0; j < $scope.availableRealmRoles.length; j++) { + var realmRole = $scope.availableRealmRoles[j]; + if (realmRole.id === role.id) { + var idx = $scope.availableRealmRoles.indexOf(realmRole); + if (idx !== -1) { + $scope.availableRealmRoles.splice(idx, 1); + break; + } + } + } + } + }); + + $scope.addRealmDefaultRole = function () { + + $scope.selectedRealmRolesToAdd = JSON.parse('[' + $scope.selectedRealmRoles + ']'); + $http.post(authUrl + '/admin/realms/' + realm.realm + '/roles-by-id/' + realm.defaultRole.id + '/composites', + $scope.selectedRealmRolesToAdd).then(function() { + // Remove selected roles from the Available roles and add them to realm default roles (move from left to right). + for (var i = 0; i < $scope.selectedRealmRolesToAdd.length; i++) { + var selectedRole = $scope.selectedRealmRolesToAdd[i]; + var index = ComponentUtils.findIndexById($scope.availableRealmRoles, selectedRole.id); + if (index > -1) { + $scope.availableRealmRoles.splice(index, 1); + $scope.realmMappings.push(selectedRole); + } + } + + $scope.selectedRealmRoles = []; + $scope.selectedRealmRolesToAdd = []; + Notifications.success("Default roles updated."); + }); + }; + + $scope.deleteRealmDefaultRole = function () { + + $scope.selectedClientRolesToRemove = JSON.parse('[' + $scope.selectedRealmDefRoles + ']'); + $http.delete(authUrl + '/admin/realms/' + realm.realm + '/roles-by-id/' + realm.defaultRole.id + '/composites', + {data : $scope.selectedClientRolesToRemove, headers : {"content-type" : "application/json"}}).then(function() { + // Remove selected roles from the realm default roles and add them to available roles (move from right to left). + for (var i = 0; i < $scope.selectedClientRolesToRemove.length; i++) { + var selectedRole = $scope.selectedClientRolesToRemove[i]; + var index = ComponentUtils.findIndexById($scope.realmMappings, selectedRole.id); + if (index > -1) { + $scope.realmMappings.splice(index, 1); + $scope.availableRealmRoles.push(selectedRole); + } + } + + $scope.selectedRealmDefRoles = []; + $scope.selectedClientRolesToRemove = []; + Notifications.success("Default roles updated."); + }); + }; + + $scope.changeClient = function (client) { + if (!client || !client.id) { + $scope.selectedClient = null; + return; + } + $scope.selectedClient = client; + $scope.selectedClientRoles = []; + $scope.selectedClientDefRoles = []; + + // Populate available roles for selected client + if ($scope.selectedClient) { + $scope.availableClientRoles = ClientRole.query({realm: realm.realm, client: client.id}, function () { + $scope.clientMappings = RoleClientComposites.query({realm : realm.realm, role : realm.defaultRole.id, client : client.id}, function(){ + for (var i = 0; i < $scope.clientMappings.length; i++) { + var role = $scope.clientMappings[i]; + for (var j = 0; j < $scope.availableClientRoles.length; j++) { + var clientRole = $scope.availableClientRoles[j]; + if (clientRole.id === role.id) { + var idx = $scope.availableClientRoles.indexOf(clientRole); + if (idx !== -1) { + $scope.availableClientRoles.splice(idx, 1); + break; + } + } + } + } + }); + for (var j = 0; j < $scope.availableClientRoles.length; j++) { + if ($scope.availableClientRoles[j] === realm.defaultRole.id) { + var clientRole = $scope.availableClientRoles[j]; + var idx = $scope.availableClientRoles.indexof(clientRole); + $scope.availableClientRoles.splice(idx, 1); + break; + } + } + }); + } else { + $scope.availableClientRoles = null; + } + }; + + $scope.addClientDefaultRole = function () { + + $scope.selectedClientRolesToAdd = JSON.parse('[' + $scope.selectedClientRoles + ']'); + $http.post(authUrl + '/admin/realms/' + realm.realm + '/roles-by-id/' + realm.defaultRole.id + '/composites', + $scope.selectedClientRolesToAdd).then(function() { + // Remove selected roles from the app available roles and add them to app default roles (move from left to right). + for (var i = 0; i < $scope.selectedClientRolesToAdd.length; i++) { + var selectedRole = $scope.selectedClientRolesToAdd[i]; + + var index = ComponentUtils.findIndexById($scope.availableClientRoles, selectedRole.id); + if (index > -1) { + $scope.availableClientRoles.splice(index, 1); + $scope.clientMappings.push(selectedRole); + } + } + + $scope.selectedClientRoles = []; + $scope.selectedClientRolesToAdd = []; + Notifications.success("Default roles updated."); + }); + }; + + $scope.rmClientDefaultRole = function () { + + $scope.selectedClientRolesToRemove = JSON.parse('[' + $scope.selectedClientDefRoles + ']'); + $http.delete(authUrl + '/admin/realms/' + realm.realm + '/roles-by-id/' + realm.defaultRole.id + '/composites', + {data : $scope.selectedClientRolesToRemove, headers : {"content-type" : "application/json"}}).then(function() { + // Remove selected roles from the realm default roles and add them to available roles (move from right to left). + for (var i = 0; i < $scope.selectedClientRolesToRemove.length; i++) { + var selectedRole = $scope.selectedClientRolesToRemove[i]; + var index = ComponentUtils.findIndexById($scope.clientMappings, selectedRole.id); + if (index > -1) { + $scope.clientMappings.splice(index, 1); + $scope.availableClientRoles.push(selectedRole); + } + } + + $scope.selectedClientDefRoles = []; + $scope.selectedClientRolesToRemove = []; + Notifications.success("Default roles updated."); + }); + }; + + clientSelectControl($scope, $route.current.params.realm, Client); +}); + + + +module.controller('IdentityProviderTabCtrl', function(Dialog, $scope, Current, Notifications, $location) { + $scope.removeIdentityProvider = function() { + Dialog.confirmDelete($scope.identityProvider.alias, 'provider', function() { + $scope.identityProvider.$remove({ + realm : Current.realm.realm, + alias : $scope.identityProvider.alias + }, function() { + $location.url("/realms/" + Current.realm.realm + "/identity-provider-settings"); + Notifications.success("The identity provider has been deleted."); + }); + }); + }; +}); + +module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload, $http, $route, realm, instance, providerFactory, IdentityProvider, serverInfo, authFlows, $location, Notifications, Dialog) { + $scope.realm = angular.copy(realm); + + $scope.initSamlProvider = function() { + $scope.nameIdFormats = [ + { + format: "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", + name: "Persistent" + + }, + { + format: "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", + name: "Transient" + }, + { + format: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", + name: "Email" + + }, + { + format: "urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos", + name: "Kerberos" + + }, + { + format: "urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName", + name: "X.509 Subject Name" + + }, + { + format: "urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName", + name: "Windows Domain Qualified Name" + + }, + { + format: "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", + name: "Unspecified" + + } + ]; + $scope.signatureAlgorithms = [ + "RSA_SHA1", + "RSA_SHA256", + "RSA_SHA256_MGF1", + "RSA_SHA512", + "RSA_SHA512_MGF1", + "DSA_SHA1" + ]; + $scope.xmlKeyNameTranformers = [ + "NONE", + "KEY_ID", + "CERT_SUBJECT" + ]; + $scope.principalTypes = [ + { + type: "SUBJECT", + name: "Subject NameID" + + }, + { + type: "ATTRIBUTE", + name: "Attribute [Name]" + + }, + { + type: "FRIENDLY_ATTRIBUTE", + name: "Attribute [Friendly Name]" + + } + ]; + if (instance && instance.alias) { + + } else { + $scope.identityProvider.config.nameIDPolicyFormat = $scope.nameIdFormats[0].format; + $scope.identityProvider.config.principalType = $scope.principalTypes[0].type; + $scope.identityProvider.config.signatureAlgorithm = $scope.signatureAlgorithms[1]; + $scope.identityProvider.config.xmlSigKeyInfoKeyNameTransformer = $scope.xmlKeyNameTranformers[1]; + $scope.identityProvider.config.allowCreate = 'true'; + } + $scope.identityProvider.config.entityId = $scope.identityProvider.config.entityId || (authUrl + '/realms/' + realm.realm); + } + + $scope.hidePassword = true; + $scope.fromUrl = { + data: '' + }; + + if (instance && instance.alias) { + $scope.identityProvider = angular.copy(instance); + $scope.newIdentityProvider = false; + for (var i in serverInfo.identityProviders) { + var provider = serverInfo.identityProviders[i]; + + if (provider.id == instance.providerId) { + $scope.provider = provider; + } + } + } else { + $scope.identityProvider = {}; + $scope.identityProvider.config = {}; + $scope.identityProvider.alias = providerFactory.id; + $scope.identityProvider.providerId = providerFactory.id; + + $scope.identityProvider.enabled = true; + $scope.identityProvider.authenticateByDefault = false; + $scope.identityProvider.firstBrokerLoginFlowAlias = 'first broker login'; + $scope.identityProvider.config.useJwksUrl = 'true'; + $scope.identityProvider.config.syncMode = 'IMPORT'; + $scope.newIdentityProvider = true; + } + + $scope.changed = $scope.newIdentityProvider; + + $scope.$watch('identityProvider', function() { + if (!angular.equals($scope.identityProvider, instance)) { + $scope.changed = true; + } + }, true); + + + $scope.serverInfo = serverInfo; + + $scope.allProviders = angular.copy(serverInfo.identityProviders); + + $scope.configuredProviders = angular.copy(realm.identityProviders); + + removeUsedSocial(); + + $scope.authFlows = []; + for (var i=0 ; i 0) { + $scope.importUrl = true; + } else{ + $scope.importUrl = false; + } + }); + + $scope.$watch('configuredProviders', function(configuredProviders) { + if (configuredProviders) { + $scope.configuredProviders = angular.copy(configuredProviders); + + for (var j = 0; j < configuredProviders.length; j++) { + var configProvidedId = configuredProviders[j].providerId; + + for (var i in $scope.allProviders) { + var provider = $scope.allProviders[i]; + if (provider.id == configProvidedId) { + configuredProviders[j].provider = provider; + } + } + } + $scope.configuredProviders = angular.copy(configuredProviders); + } + }, true); + + $scope.callbackUrl = authServerUrl + "/realms/" + realm.realm + "/broker/"; + + $scope.addProvider = function(provider) { + $location.url("/create/identity-provider/" + realm.realm + "/" + provider.id); + }; + + $scope.save = function() { + if ($scope.newIdentityProvider) { + if (!$scope.identityProvider.alias) { + Notifications.error("You must specify an alias"); + return; + } + IdentityProvider.save({ + realm: $scope.realm.realm, alias: '' + }, $scope.identityProvider, function () { + $location.url("/realms/" + realm.realm + "/identity-provider-settings/provider/" + $scope.identityProvider.providerId + "/" + $scope.identityProvider.alias); + Notifications.success("The " + $scope.identityProvider.alias + " provider has been created."); + }); + } else { + IdentityProvider.update({ + realm: $scope.realm.realm, + alias: $scope.identityProvider.alias + }, $scope.identityProvider, function () { + $route.reload(); + Notifications.success("The " + $scope.identityProvider.alias + " provider has been updated."); + }); + } + }; + + $scope.cancel = function() { + if ($scope.newIdentityProvider) { + $location.url("/realms/" + realm.realm + "/identity-provider-settings"); + } else { + $route.reload(); + } + }; + + + $scope.reset = function() { + $scope.identityProvider = {}; + $scope.configuredProviders = angular.copy($scope.realm.identityProviders); + }; + + $scope.showPassword = function(flag) { + $scope.hidePassword = flag; + }; + + $scope.removeIdentityProvider = function(identityProvider) { + Dialog.confirmDelete(identityProvider.alias, 'provider', function() { + IdentityProvider.remove({ + realm : realm.realm, + alias : identityProvider.alias + }, function() { + $route.reload(); + Notifications.success("The identity provider has been deleted."); + }); + }); + }; + + // KEYCLOAK-5932: remove social providers that have already been defined + function removeUsedSocial() { + var i = $scope.allProviders.length; + while (i--) { + if ($scope.allProviders[i].groupName !== 'Social') continue; + if ($scope.configuredProviders != null) { + for (var j = 0; j < $scope.configuredProviders.length; j++) { + if ($scope.configuredProviders[j].providerId === $scope.allProviders[i].id) { + $scope.allProviders.splice(i, 1); + break; + } + } + } + } + }; + + if (instance && instance.alias) { + try { $scope.authnContextClassRefs = JSON.parse($scope.identityProvider.config.authnContextClassRefs || '[]'); } catch (e) { $scope.authnContextClassRefs = []; } + try { $scope.authnContextDeclRefs = JSON.parse($scope.identityProvider.config.authnContextDeclRefs || '[]'); } catch (e) { $scope.authnContextDeclRefs = []; } + } else { + $scope.authnContextClassRefs = []; + $scope.authnContextDeclRefs = []; + } + + $scope.deleteAuthnContextClassRef = function(index) { + $scope.authnContextClassRefs.splice(index, 1); + $scope.identityProvider.config.authnContextClassRefs = JSON.stringify($scope.authnContextClassRefs); + }; + + $scope.addAuthnContextClassRef = function() { + $scope.authnContextClassRefs.push($scope.newAuthnContextClassRef); + $scope.identityProvider.config.authnContextClassRefs = JSON.stringify($scope.authnContextClassRefs); + $scope.newAuthnContextClassRef = ""; + }; + + $scope.deleteAuthnContextDeclRef = function(index) { + $scope.authnContextDeclRefs.splice(index, 1); + $scope.identityProvider.config.authnContextDeclRefs = JSON.stringify($scope.authnContextDeclRefs); + }; + + $scope.addAuthnContextDeclRef = function() { + $scope.authnContextDeclRefs.push($scope.newAuthnContextDeclRef); + $scope.identityProvider.config.authnContextDeclRefs = JSON.stringify($scope.authnContextDeclRefs); + $scope.newAuthnContextDeclRef = ""; + }; +}); + +module.controller('RealmTokenDetailCtrl', function($scope, Realm, realm, $http, $location, $route, Dialog, Notifications, TimeUnit, TimeUnit2, serverInfo) { + $scope.realm = realm; + $scope.serverInfo = serverInfo; + $scope.actionTokenProviders = $scope.serverInfo.providers.actionTokenHandler.providers; + + $scope.realm.accessTokenLifespan = TimeUnit2.asUnit(realm.accessTokenLifespan); + $scope.realm.accessTokenLifespanForImplicitFlow = TimeUnit2.asUnit(realm.accessTokenLifespanForImplicitFlow); + $scope.realm.ssoSessionIdleTimeout = TimeUnit2.asUnit(realm.ssoSessionIdleTimeout); + $scope.realm.ssoSessionMaxLifespan = TimeUnit2.asUnit(realm.ssoSessionMaxLifespan); + $scope.realm.ssoSessionIdleTimeoutRememberMe = TimeUnit2.asUnit(realm.ssoSessionIdleTimeoutRememberMe); + $scope.realm.ssoSessionMaxLifespanRememberMe = TimeUnit2.asUnit(realm.ssoSessionMaxLifespanRememberMe); + $scope.realm.offlineSessionIdleTimeout = TimeUnit2.asUnit(realm.offlineSessionIdleTimeout); + // KEYCLOAK-7688 Offline Session Max for Offline Token + $scope.realm.offlineSessionMaxLifespan = TimeUnit2.asUnit(realm.offlineSessionMaxLifespan); + $scope.realm.clientSessionIdleTimeout = TimeUnit2.asUnit(realm.clientSessionIdleTimeout); + $scope.realm.clientSessionMaxLifespan = TimeUnit2.asUnit(realm.clientSessionMaxLifespan); + $scope.realm.clientOfflineSessionIdleTimeout = TimeUnit2.asUnit(realm.clientOfflineSessionIdleTimeout); + $scope.realm.clientOfflineSessionMaxLifespan = TimeUnit2.asUnit(realm.clientOfflineSessionMaxLifespan); + $scope.realm.accessCodeLifespan = TimeUnit2.asUnit(realm.accessCodeLifespan); + $scope.realm.accessCodeLifespanLogin = TimeUnit2.asUnit(realm.accessCodeLifespanLogin); + $scope.realm.accessCodeLifespanUserAction = TimeUnit2.asUnit(realm.accessCodeLifespanUserAction); + $scope.realm.actionTokenGeneratedByAdminLifespan = TimeUnit2.asUnit(realm.actionTokenGeneratedByAdminLifespan); + $scope.realm.actionTokenGeneratedByUserLifespan = TimeUnit2.asUnit(realm.actionTokenGeneratedByUserLifespan); + $scope.realm.oauth2DeviceCodeLifespan = TimeUnit2.asUnit(realm.oauth2DeviceCodeLifespan); + $scope.realm.attributes.parRequestUriLifespan = TimeUnit2.asUnit(realm.attributes.parRequestUriLifespan); + $scope.realm.attributes = realm.attributes; + + var oldCopy = angular.copy($scope.realm); + $scope.changed = false; + + $scope.$watch('realm', function() { + if (!angular.equals($scope.realm, oldCopy)) { + $scope.changed = true; + } + }, true); + + $scope.$watch('actionLifespanId', function () { + // changedActionLifespanId signals other watchers that we were merely + // changing the dropdown and we should not enable 'save' button + if ($scope.actionTokenAttribute && $scope.actionTokenAttribute.hasOwnProperty('time')) { + $scope.changedActionLifespanId = true; + } + + $scope.actionTokenAttribute = TimeUnit2.asUnit($scope.realm.attributes['actionTokenGeneratedByUserLifespan.' + $scope.actionLifespanId]); + }, true); + + $scope.$watch('actionTokenAttribute', function () { + if ($scope.actionLifespanId === null) return; + + if ($scope.changedActionLifespanId) { + $scope.changedActionLifespanId = false; + return; + } else { + $scope.changed = true; + } + + if ($scope.actionTokenAttribute !== null) { + $scope.realm.attributes['actionTokenGeneratedByUserLifespan.' + $scope.actionLifespanId] = $scope.actionTokenAttribute.toSeconds(); + } + }, true); + + $scope.changeRevokeRefreshToken = function() { + + }; + + $scope.save = function() { + $scope.realm.accessTokenLifespan = $scope.realm.accessTokenLifespan.toSeconds(); + $scope.realm.accessTokenLifespanForImplicitFlow = $scope.realm.accessTokenLifespanForImplicitFlow.toSeconds(); + $scope.realm.ssoSessionIdleTimeout = $scope.realm.ssoSessionIdleTimeout.toSeconds(); + $scope.realm.ssoSessionMaxLifespan = $scope.realm.ssoSessionMaxLifespan.toSeconds(); + $scope.realm.ssoSessionIdleTimeoutRememberMe = $scope.realm.ssoSessionIdleTimeoutRememberMe.toSeconds(); + $scope.realm.ssoSessionMaxLifespanRememberMe = $scope.realm.ssoSessionMaxLifespanRememberMe.toSeconds(); + $scope.realm.offlineSessionIdleTimeout = $scope.realm.offlineSessionIdleTimeout.toSeconds(); + // KEYCLOAK-7688 Offline Session Max for Offline Token + $scope.realm.offlineSessionMaxLifespan = $scope.realm.offlineSessionMaxLifespan.toSeconds(); + $scope.realm.clientSessionIdleTimeout = $scope.realm.clientSessionIdleTimeout.toSeconds(); + $scope.realm.clientSessionMaxLifespan = $scope.realm.clientSessionMaxLifespan.toSeconds(); + $scope.realm.clientOfflineSessionIdleTimeout = $scope.realm.clientOfflineSessionIdleTimeout.toSeconds(); + $scope.realm.clientOfflineSessionMaxLifespan = $scope.realm.clientOfflineSessionMaxLifespan.toSeconds(); + $scope.realm.accessCodeLifespan = $scope.realm.accessCodeLifespan.toSeconds(); + $scope.realm.accessCodeLifespanUserAction = $scope.realm.accessCodeLifespanUserAction.toSeconds(); + $scope.realm.accessCodeLifespanLogin = $scope.realm.accessCodeLifespanLogin.toSeconds(); + $scope.realm.actionTokenGeneratedByAdminLifespan = $scope.realm.actionTokenGeneratedByAdminLifespan.toSeconds(); + $scope.realm.actionTokenGeneratedByUserLifespan = $scope.realm.actionTokenGeneratedByUserLifespan.toSeconds(); + $scope.realm.oauth2DeviceCodeLifespan = $scope.realm.oauth2DeviceCodeLifespan.toSeconds(); + $scope.realm.attributes.parRequestUriLifespan = $scope.realm.attributes.parRequestUriLifespan.toSeconds(); + + Realm.update($scope.realm, function () { + $route.reload(); + Notifications.success("The changes have been saved to the realm."); + }); + }; + + $scope.resetToDefaultToken = function (actionTokenId) { + $scope.actionTokenAttribute = {}; + delete $scope.realm.attributes['actionTokenGeneratedByUserLifespan.' + $scope.actionLifespanId]; + //Only for UI effects, resets to the original state + $scope.actionTokenAttribute.unit = 'Minutes'; + } + + $scope.reset = function() { + $route.reload(); + }; +}); + +module.controller('RealmUserProfileCtrl', function($scope, Realm, realm, clientScopes, $http, $location, $route, UserProfile, Dialog, Notifications, serverInfo) { + $scope.realm = realm; + $scope.validatorProviders = serverInfo.componentTypes['org.keycloak.validate.Validator']; + + $scope.isShowAttributes = true; + $scope.isShowAttributeGroups = false; + $scope.isShowJsonEditor = false; + + UserProfile.get({realm: realm.realm}, function(config) { + $scope.config = config; + $scope.rawConfig = angular.toJson(config, true); + }); + + $scope.isShowAttributes = true; + $scope.isShowAttributeGroups = false; + $scope.isShowJsonEditor = false; + + $scope.showAttributes = function() { + $route.reload(); + delete $scope.currentAttributeGroup; + } + + $scope.showAttributeGroups = function() { + $scope.isShowAttributes = false; + $scope.isShowAttributeGroups = true; + $scope.isShowJsonEditor = false; + delete $scope.currentAttribute; + } + + $scope.showJsonEditor = function() { + $scope.isShowAttributes = false; + $scope.isShowAttributeGroups = false; + $scope.isShowJsonEditor = true; + delete $scope.currentAttribute; + delete $scope.currentAttributeGroup; + } + + $scope.isRequiredRoles = { + minimumInputLength: 0, + delay: 500, + allowClear: true, + id: function(e) { return e; }, + query: function (query) { + var expectedRoles = ['user', 'admin']; + var roles = []; + + if ('' == query.term.trim()) { + roles = expectedRoles; + } else { + for (var i = 0; i < expectedRoles.length; i++) { + if (expectedRoles[i].indexOf(query.term.trim()) != -1) { + roles.push(expectedRoles[i]); + } + } + } + + query.callback({results: roles}); + }, + formatResult: function(object, container, query) { + return object; + }, + formatSelection: function(object, container, query) { + return object; + } + }; + + $scope.isRequiredScopes = { + minimumInputLength: 1, + delay: 500, + allowClear: true, + query: function (query) { + var scopes = []; + + if ('' == query.term.trim()) { + scopes = clientScopes; + } else { + for (var i = 0; i < clientScopes.length; i++) { + if (clientScopes[i].name.indexOf(query.term.trim()) != -1) { + scopes.push(clientScopes[i]); + } + } + } + + query.callback({results: scopes}); + }, + formatResult: function(object, container, query) { + return object.name; + }, + formatSelection: function(object, container, query) { + return object.name; + } + }; + + $scope.selectorByScopeSelect = { + minimumInputLength: 1, + delay: 500, + allowClear: true, + query: function (query) { + var scopes = []; + + if ('' == query.term.trim()) { + scopes = clientScopes; + } else { + for (var i = 0; i < clientScopes.length; i++) { + if (clientScopes[i].name.indexOf(query.term.trim()) != -1) { + scopes.push(clientScopes[i]); + } + } + } + + query.callback({results: scopes}); + }, + formatResult: function(object, container, query) { + return object.name; + }, + formatSelection: function(object, container, query) { + return object.name; + } + }; + + $scope.attributeSelected = false; + + $scope.showAttributeListing = function() { + return !$scope.attributeSelected && $scope.currentAttribute == null && $scope.isShowAttributes; + } + + $scope.showAttributeGroupListing = function() { + return !$scope.attributeGroupSelected && $scope.currentAttributeGroup == null && $scope.isShowAttributeGroups; + } + + $scope.createAttribute = function() { + $scope.isCreateAttribute = true; + $scope.currentAttribute = { + selector: { + scopes: [] + }, + required: { + roles: [], + scopes: [] + }, + permissions: { + view: [], + edit: [] + } + }; + }; + + $scope.createAttributeGroup = function() { + $scope.isCreateAttributeGroup = true; + $scope.currentAttributeGroup = {}; + }; + + $scope.isNotUsernameOrEmail = function(attributeName) { + return attributeName != "username" && attributeName != "email"; + }; + + $scope.guiOrderUp = function(index) { + $scope.moveAttribute(index, index - 1); + }; + + $scope.guiOrderDown = function(index) { + $scope.moveAttribute(index, index + 1); + }; + + $scope.moveAttribute = function(old_index, new_index){ + $scope.config.attributes.splice(new_index, 0, $scope.config.attributes.splice(old_index, 1)[0]); + $scope.save(); + } + + $scope.groupOrderUp = function(index) { + $scope.moveAttributeGroup(index, index - 1); + }; + + $scope.groupOrderDown = function(index) { + $scope.moveAttributeGroup(index, index + 1); + }; + + $scope.moveAttributeGroup = function(old_index, new_index){ + $scope.config.groups.splice(new_index, 0, $scope.config.groups.splice(old_index, 1)[0]); + $scope.save(false); + } + + $scope.removeAttribute = function(attribute) { + Dialog.confirmDelete(attribute.name, 'attribute', function() { + let newAttributes = []; + + for (var v of $scope.config.attributes) { + if (v != attribute) { + newAttributes.push(v); + } + } + + $scope.config.attributes = newAttributes; + $scope.save(); + }); + }; + + $scope.removeAttributeGroup = function(attributeGroup) { + Dialog.confirmDelete(attributeGroup.name, 'group', function() { + let newGroups = []; + + for (var v of $scope.config.groups) { + if (v != attributeGroup) { + newGroups.push(v); + } + } + + $scope.config.groups = newGroups; + $scope.save(); + }); + }; + + $scope.addAttributeAnnotation = function() { + if (!$scope.currentAttribute.annotations) { + $scope.currentAttribute.annotations = {}; + } + $scope.currentAttribute.annotations[$scope.newAnnotation.key] = $scope.newAnnotation.value; + delete $scope.newAnnotation; + } + + $scope.removeAttributeAnnotation = function(key) { + delete $scope.currentAttribute.annotations[key]; + } + + $scope.addAttributeGroupAnnotation = function() { + if (!$scope.currentAttributeGroup.annotations) { + $scope.currentAttributeGroup.annotations = {}; + } + $scope.currentAttributeGroup.annotations[$scope.newAttributeGroupAnnotation.key] = $scope.newAttributeGroupAnnotation.value; + delete $scope.newGroupAnnotation; + } + + $scope.removeAttributeGroupAnnotation = function(key) { + delete $scope.currentAttributeGroup.annotations[key]; + } + + $scope.editAttribute = function(attribute) { + // it isn't be possible to set permissions to username and email + if (attribute.permissions == null && (attribute.name != 'username' && attribute.name != 'email')) { + attribute.permissions = { + view: [], + edit: [] + }; + } + + if (attribute.selector == null) { + attribute.selector = { + scopes: [] + }; + } + + if (attribute.required) { + if (attribute.required.roles) { + $scope.requiredRoles = attribute.required.roles; + } + if (attribute.required.scopes) { + for (var i = 0; i < attribute.required.scopes.length; i++) { + $scope.requiredScopes.push({ + id: attribute.required.scopes[i], + name: attribute.required.scopes[i] + }); + } + } + } + + if (attribute.selector && attribute.selector.scopes) { + for (var i = 0; i < attribute.selector.scopes.length; i++) { + $scope.selectorByScope.push({ + id: attribute.selector.scopes[i], + name: attribute.selector.scopes[i] + }); + } + } + + $scope.isRequired = attribute.required != null; + + if (attribute.permissions != null) { + $scope.canUserView = attribute.permissions.view.includes('user'); + $scope.canAdminView = attribute.permissions.view.includes('admin'); + $scope.canUserEdit = attribute.permissions.edit.includes('user'); + $scope.canAdminEdit = attribute.permissions.edit.includes('admin'); + } + + $scope.currentAttribute = attribute; + $scope.attributeSelected = true; + }; + + $scope.editAttributeGroup = function(attributeGroup) { + $scope.currentAttributeGroup = attributeGroup; + $scope.attributeGroupSelected = true; + }; + + $scope.groupIsReferencedInAnyAttribute = function(group) { + for (var currentAttribute of $scope.config.attributes) { + if (currentAttribute.group === group.name) { + return true + } + } + return false; + } + + $scope.$watch('isRequired', function() { + if ($scope.isRequired) { + $scope.currentAttribute.required = { + roles: [], + scopes: [] + }; + } else if ($scope.currentAttribute) { + delete $scope.currentAttribute.required; + } + }, true); + + handlePermission = function(permission, role, allowed) { + let attribute = $scope.currentAttribute; + + if (attribute && attribute.permissions) { + let roles = []; + + for (let r of attribute.permissions[permission]) { + if (r != role) { + roles.push(r); + } + } + + if (allowed) { + roles.push(role); + } + + attribute.permissions[permission] = roles; + } + } + + $scope.$watch('canUserView', function() { + handlePermission('view', 'user', $scope.canUserView); + }, true); + + $scope.$watch('canAdminView', function() { + handlePermission('view', 'admin', $scope.canAdminView); + }, true); + + $scope.$watch('canUserEdit', function() { + handlePermission('edit', 'user', $scope.canUserEdit); + }, true); + + $scope.$watch('canAdminEdit', function() { + handlePermission('edit', 'admin', $scope.canAdminEdit); + }, true); + + $scope.addValidator = function(validator) { + if ($scope.currentAttribute.validations == null) { + $scope.currentAttribute.validations = {}; + } + + let config = {}; + + for (let key in validator.config) { + let values = validator.config[key]; + + if (Array.isArray(values)) { + config[key] = values; + } else { + for (let k in values) { + config[key] = values[k]; + } + } + } + + $scope.currentAttribute.validations[validator.id] = config; + + delete $scope.newValidator; + }; + + $scope.selectValidator = function(validator) { + validator.config = {}; + }; + + $scope.cancelAddValidator = function() { + delete $scope.newValidator; + }; + + $scope.removeValidator = function(id) { + let newValidators = {}; + + for (let v in $scope.currentAttribute.validations) { + if (v != id) { + newValidators[v] = $scope.currentAttribute.validations[v]; + } + } + + if (newValidators.length == 0) { + delete $scope.currentAttribute.validations; + return; + } + + $scope.currentAttribute.validations = newValidators; + }; + + $scope.reloadConfigurationFromUserProfile = function () { + UserProfile.get({realm: realm.realm}, function(config) { + $scope.config = config; + $scope.rawConfig = angular.toJson(config, true); + }); + } + + $scope.save = function() { + $scope.save(true) + } + + $scope.save = function(reload) { + if ($scope.isShowJsonEditor) { + $scope.config = JSON.parse($scope.rawConfig); + } + + if ($scope.currentAttribute) { + if ($scope.isRequired) { + $scope.currentAttribute.required.roles = $scope.requiredRoles; + + for (var i = 0; i < $scope.requiredScopes.length; i++) { + $scope.currentAttribute.required.scopes.push($scope.requiredScopes[i].name); + } + } + + $scope.currentAttribute.selector = {scopes: []}; + + for (var i = 0; i < $scope.selectorByScope.length; i++) { + $scope.currentAttribute.selector.scopes.push($scope.selectorByScope[i].name); + } + + if ($scope.isCreateAttribute) { + $scope.config['attributes'].push($scope.currentAttribute); + } + } + + if ($scope.currentAttributeGroup) { + if ($scope.config['groups'] == null) { + $scope.config['groups'] = [] + } + if ($scope.isCreateAttributeGroup) { + $scope.config['groups'].push($scope.currentAttributeGroup); + } + } + + UserProfile.update({realm: realm.realm}, + + $scope.config, function () { + $scope.attributeSelected = false; + delete $scope.currentAttribute; + delete $scope.isCreateAttribute + delete $scope.attributeSelected; + delete $scope.currentAttributeGroup; + delete $scope.isCreateAttributeGroup; + delete $scope.attributeGroupSelected; + delete $scope.isRequired; + delete $scope.canUserView; + delete $scope.canAdminView; + delete $scope.canUserEdit; + delete $scope.canAdminEdit; + + if (reload) { + $route.reload(); + } else { + $scope.reloadConfigurationFromUserProfile(); + } + Notifications.success("User Profile configuration has been saved."); + }); + }; + + $scope.cancelEditAttributeGroup = function() { + delete $scope.currentAttributeGroup; + delete $scope.isCreateAttributeGroup; + delete $scope.attributeGroupSelected; + $scope.reloadConfigurationFromUserProfile(); + } + + $scope.reset = function() { + $route.reload(); + }; +}); + +module.controller('ViewKeyCtrl', function($scope, key) { + $scope.key = key; +}); + +module.controller('RealmKeysCtrl', function($scope, Realm, realm, $http, $route, $location, Dialog, Notifications, serverInfo, keys, Components, $modal) { + $scope.realm = angular.copy(realm); + $scope.keys = keys.keys; + $scope.active = {}; + + Components.query({realm: realm.realm, + parent: realm.id, + type: 'org.keycloak.keys.KeyProvider' + }, function(data) { + for (var i = 0; i < keys.keys.length; i++) { + for (var j = 0; j < data.length; j++) { + if (keys.keys[i].providerId == data[j].id) { + keys.keys[i].provider = data[j]; + } + } + } + + for (var t in keys.active) { + for (var i = 0; i < keys.keys.length; i++) { + if (keys.active[t] == keys.keys[i].kid) { + $scope.active[t] = keys.keys[i]; + } + } + } + }); + + $scope.viewKey = function(key) { + $modal.open({ + templateUrl: resourceUrl + '/partials/modal/view-key.html', + controller: 'ViewKeyCtrl', + resolve: { + key: function () { + return key; + } + } + }) + } +}); + +module.controller('RealmKeysProvidersCtrl', function($scope, Realm, realm, $http, $route, $location, Dialog, Notifications, serverInfo, Components, $modal) { + $scope.realm = angular.copy(realm); + $scope.enableUpload = false; + + $scope.providers = serverInfo.componentTypes['org.keycloak.keys.KeyProvider']; + + Components.query({realm: realm.realm, + parent: realm.id, + type: 'org.keycloak.keys.KeyProvider' + }, function(data) { + $scope.instances = data; + + for (var i = 0; i < $scope.instances.length; i++) { + for (var j = 0; j < $scope.providers.length; j++) { + if ($scope.providers[j].id === $scope.instances[i].providerId) { + $scope.instances[i].provider = $scope.providers[j]; + } + } + } + }); + + $scope.addProvider = function(provider) { + $location.url("/create/keys/" + realm.realm + "/providers/" + provider.id); + }; + + $scope.removeInstance = function(instance) { + Dialog.confirmDelete(instance.name, 'key provider', function() { + Components.remove({ + realm : realm.realm, + componentId : instance.id + }, function() { + $route.reload(); + Notifications.success("The provider has been deleted."); + }); + }); + }; +}); + +module.controller('GenericKeystoreCtrl', function($scope, $location, Notifications, $route, Dialog, realm, serverInfo, instance, providerId, Components) { + $scope.create = !instance.providerId; + $scope.realm = realm; + + var providers = serverInfo.componentTypes['org.keycloak.keys.KeyProvider']; + var providerFactory = null; + for (var i = 0; i < providers.length; i++) { + var p = providers[i]; + if (p.id == providerId) { + $scope.providerFactory = p; + providerFactory = p; + break; + } + } + + if ($scope.create) { + $scope.instance = { + name: providerFactory.id, + providerId: providerFactory.id, + providerType: 'org.keycloak.keys.KeyProvider', + parentId: realm.id, + config: { + 'priority': ["0"] + } + } + } else { + $scope.instance = angular.copy(instance); + } + + if (providerFactory.properties) { + for (var i = 0; i < providerFactory.properties.length; i++) { + var configProperty = providerFactory.properties[i]; + if (!$scope.instance.config[configProperty.name]) { + if (configProperty.defaultValue) { + $scope.instance.config[configProperty.name] = [configProperty.defaultValue]; + if (!$scope.create) { + instance.config[configProperty.name] = [configProperty.defaultValue]; + } + } else { + $scope.instance.config[configProperty.name] = ['']; + if (!$scope.create) { + instance.config[configProperty.name] = [configProperty.defaultValue]; + } + } + } + } + } + + $scope.$watch('instance', function() { + if (!angular.equals($scope.instance, instance)) { + $scope.changed = true; + } + + }, true); + + $scope.save = function() { + $scope.changed = false; + if ($scope.create) { + Components.save({realm: realm.realm}, $scope.instance, function (data, headers) { + var l = headers().location; + var id = l.substring(l.lastIndexOf("/") + 1); + + $location.url("/realms/" + realm.realm + "/keys/providers/" + $scope.instance.providerId + "/" + id); + Notifications.success("The provider has been created."); + }); + } else { + Components.update({realm: realm.realm, + componentId: instance.id + }, + $scope.instance, function () { + $route.reload(); + Notifications.success("The provider has been updated."); + }); + } + }; + + $scope.reset = function() { + $route.reload(); + }; + + $scope.cancel = function() { + if ($scope.create) { + $location.url("/realms/" + realm.realm + "/keys"); + } else { + $route.reload(); + } + }; +}); + +module.controller('RealmSessionStatsCtrl', function($scope, realm, stats, RealmClientSessionStats, RealmLogoutAll, Notifications) { + $scope.realm = realm; + $scope.stats = stats; + + $scope.logoutAll = function() { + RealmLogoutAll.save({realm : realm.realm}, function (globalReqResult) { + var successCount = globalReqResult.successRequests ? globalReqResult.successRequests.length : 0; + var failedCount = globalReqResult.failedRequests ? globalReqResult.failedRequests.length : 0; + + if (failedCount > 0) { + var msgStart = successCount>0 ? 'Successfully logout all users under: ' + globalReqResult.successRequests + ' . ' : ''; + Notifications.error(msgStart + 'Failed to logout users under: ' + globalReqResult.failedRequests + '. Verify availability of failed hosts and try again'); + } else { + window.location.reload(); + } + }); + }; +}); + + +module.controller('RealmRevocationCtrl', function($scope, Realm, RealmPushRevocation, realm, $http, $location, Dialog, Notifications) { + $scope.realm = angular.copy(realm); + + var setNotBefore = function() { + if ($scope.realm.notBefore == 0) { + $scope.notBefore = "None"; + } else { + $scope.notBefore = new Date($scope.realm.notBefore * 1000); + } + }; + + setNotBefore(); + + var reset = function() { + Realm.get({ id : realm.realm }, function(updated) { + $scope.realm = updated; + setNotBefore(); + }) + + }; + + $scope.clear = function() { + Realm.update({ realm: realm.realm, notBefore : 0 }, function () { + $scope.notBefore = "None"; + Notifications.success('Not Before cleared for realm.'); + reset(); + }); + } + $scope.setNotBeforeNow = function() { + Realm.update({ realm: realm.realm, notBefore : new Date().getTime()/1000}, function () { + Notifications.success('Not Before set for realm.'); + reset(); + }); + } + $scope.pushRevocation = function() { + RealmPushRevocation.save({ realm: realm.realm}, function (globalReqResult) { + var successCount = globalReqResult.successRequests ? globalReqResult.successRequests.length : 0; + var failedCount = globalReqResult.failedRequests ? globalReqResult.failedRequests.length : 0; + + if (successCount==0 && failedCount==0) { + Notifications.warn('No push sent. No admin URI configured or no registered cluster nodes available'); + } else if (failedCount > 0) { + var msgStart = successCount>0 ? 'Successfully push notBefore to: ' + globalReqResult.successRequests + ' . ' : ''; + Notifications.error(msgStart + 'Failed to push notBefore to: ' + globalReqResult.failedRequests + '. Verify availability of failed hosts and try again'); + } else { + Notifications.success('Successfully push notBefore to all configured clients'); + } + }); + } + +}); + + +module.controller('RoleTabCtrl', function(Dialog, $scope, Current, Notifications, $location) { + $scope.removeRole = function() { + Dialog.confirmDelete($scope.role.name, 'role', function() { + RoleById.remove({ + realm: realm.realm, + role: $scope.role.id + }, function () { + $route.reload(); + Notifications.success("The role has been deleted."); + }); + }); + }; +}); + + +module.controller('RoleListCtrl', function($scope, $route, Dialog, Notifications, realm, RoleList, RoleById, filterFilter) { + $scope.realm = realm; + $scope.roles = []; + $scope.defaultRoleName = realm.defaultRole.name; + + $scope.query = { + realm: realm.realm, + search : null, + max : 20, + first : 0 + } + + $scope.$watch('query.search', function (newVal, oldVal) { + if($scope.query.search && $scope.query.search.length >= 3) { + $scope.firstPage(); + } + }, true); + + $scope.firstPage = function() { + $scope.query.first = 0; + $scope.searchQuery(); + } + + $scope.previousPage = function() { + $scope.query.first -= parseInt($scope.query.max); + if ($scope.query.first < 0) { + $scope.query.first = 0; + } + $scope.searchQuery(); + } + + $scope.nextPage = function() { + $scope.query.first += parseInt($scope.query.max); + $scope.searchQuery(); + } + + $scope.searchQuery = function() { + $scope.searchLoaded = false; + + $scope.roles = RoleList.query($scope.query, function() { + $scope.searchLoaded = true; + $scope.lastSearch = $scope.query.search; + }); + }; + + $scope.searchQuery(); + + $scope.determineEditLink = function(role) { + return role.name === $scope.defaultRoleName ? "/realms/" + $scope.realm.realm + "/default-roles" : "/realms/" + $scope.realm.realm + "/roles/" + role.id; + } + + $scope.removeRole = function (role) { + if (role.name === $scope.defaultRoleName) return; + + Dialog.confirmDelete(role.name, 'role', function () { + RoleById.remove({ + realm: realm.realm, + role: role.id + }, function () { + $route.reload(); + Notifications.success("The role has been deleted."); + }); + }); + }; +}); + + +module.controller('RoleDetailCtrl', function($scope, realm, role, roles, Client, $route, + Role, ClientRole, RoleById, RoleRealmComposites, RoleClientComposites, + $http, $location, Dialog, Notifications, RealmRoleRemover, ComponentUtils) { + $scope.realm = realm; + $scope.role = angular.copy(role); + $scope.create = !role.name; + + $scope.changed = $scope.create; + + $scope.save = function() { + convertAttributeValuesToLists(); + console.log('save'); + if ($scope.create) { + Role.save({ + realm: realm.realm + }, $scope.role, function (data, headers) { + $scope.changed = false; + convertAttributeValuesToString($scope.role); + role = angular.copy($scope.role); + + Role.get({ realm: realm.realm, role: role.name }, function(role) { + var id = role.id; + $location.url("/realms/" + realm.realm + "/roles/" + id); + Notifications.success("The role has been created."); + }); + }); + } else { + $scope.update(); + } + }; + + $scope.remove = function() { + RealmRoleRemover.remove($scope.role, realm, Dialog, $location, Notifications); + }; + + $scope.cancel = function () { + $location.url("/realms/" + realm.realm + "/roles"); + }; + + $scope.addAttribute = function() { + $scope.role.attributes[$scope.newAttribute.key] = $scope.newAttribute.value; + delete $scope.newAttribute; + } + + $scope.removeAttribute = function(key) { + delete $scope.role.attributes[key]; + } + + function convertAttributeValuesToLists() { + var attrs = $scope.role.attributes; + for (var attribute in attrs) { + if (typeof attrs[attribute] === "string") { + var attrVals = attrs[attribute].split("##"); + attrs[attribute] = attrVals; + } + } + } + + function convertAttributeValuesToString(role) { + var attrs = role.attributes; + for (var attribute in attrs) { + if (typeof attrs[attribute] === "object") { + var attrVals = attrs[attribute].join("##"); + attrs[attribute] = attrVals; + console.log("attribute" + attrVals) + } + } + } + + roleControl($scope, $route, realm, role, roles, Client, + ClientRole, RoleById, RoleRealmComposites, RoleClientComposites, + $http, $location, Notifications, Dialog, ComponentUtils); +}); + +module.controller('RealmSMTPSettingsCtrl', function($scope, Current, Realm, realm, $http, $location, Dialog, Notifications, RealmSMTPConnectionTester) { + console.log('RealmSMTPSettingsCtrl'); + + var booleanSmtpAtts = ["auth","ssl","starttls"]; + + $scope.realm = realm; + + if ($scope.realm.smtpServer) { + $scope.realm.smtpServer = typeObject($scope.realm.smtpServer); + }; + + var oldCopy = angular.copy($scope.realm); + $scope.changed = false; + + $scope.$watch('realm', function() { + if (!angular.equals($scope.realm, oldCopy)) { + $scope.changed = true; + } + }, true); + + $scope.save = function() { + var realmCopy = angular.copy($scope.realm); + realmCopy['smtpServer'] = detypeObject(realmCopy.smtpServer); + $scope.changed = false; + Realm.update(realmCopy, function () { + $location.url("/realms/" + realm.realm + "/smtp-settings"); + Notifications.success("Your changes have been saved to the realm."); + }); + }; + + $scope.reset = function() { + $scope.realm = angular.copy(oldCopy); + $scope.changed = false; + }; + + $scope.testConnection = function() { + RealmSMTPConnectionTester.save({realm: realm.realm}, realm.smtpServer, function() { + Notifications.success("SMTP connection successful. E-mail was sent!"); + }, function(errorResponse) { + if (error.data.errorMessage) { + Notifications.error(error.data.errorMessage); + } else { + Notifications.error('Unexpected error during SMTP validation'); + } + }); + }; + + /* Convert string attributes containing a boolean to actual boolean type + convert an integer string (port) to integer. */ + function typeObject(obj){ + for (var att in obj){ + if (booleanSmtpAtts.indexOf(att) < 0) + continue; + if (obj[att] === "true"){ + obj[att] = true; + } else if (obj[att] === "false"){ + obj[att] = false; + } + } + + obj['port'] = parseInt(obj['port']); + + return obj; + } + + /* Convert all non-string values to strings to invert changes caused by the typeObject function. */ + function detypeObject(obj){ + for (var att in obj){ + if (booleanSmtpAtts.indexOf(att) < 0) + continue; + if (obj[att] === true){ + obj[att] = "true"; + } else if (obj[att] === false){ + obj[att] = "false" + } + } + + obj['port'] = obj['port'] && obj['port'].toString(); + + return obj; + } +}); + +module.controller('RealmEventsConfigCtrl', function($scope, eventsConfig, RealmEventsConfig, RealmEvents, RealmAdminEvents, realm, serverInfo, $location, Notifications, TimeUnit, Dialog) { + $scope.realm = realm; + + $scope.eventsConfig = eventsConfig; + + $scope.eventsConfig.expirationUnit = TimeUnit.autoUnit(eventsConfig.eventsExpiration); + $scope.eventsConfig.eventsExpiration = TimeUnit.toUnit(eventsConfig.eventsExpiration, $scope.eventsConfig.expirationUnit); + + $scope.eventListeners = Object.keys(serverInfo.providers.eventsListener.providers); + + $scope.eventsConfigSelectOptions = { + 'multiple': true, + 'simple_tags': true, + 'tags': $scope.eventListeners + }; + + $scope.eventSelectOptions = { + 'multiple': true, + 'simple_tags': true, + 'tags': serverInfo.enums['eventType'] + }; + + var oldCopy = angular.copy($scope.eventsConfig); + $scope.changed = false; + + $scope.$watch('eventsConfig', function() { + if (!angular.equals($scope.eventsConfig, oldCopy)) { + $scope.changed = true; + } + }, true); + + $scope.save = function() { + $scope.changed = false; + + var copy = angular.copy($scope.eventsConfig) + delete copy['expirationUnit']; + + copy.eventsExpiration = TimeUnit.toSeconds($scope.eventsConfig.eventsExpiration, $scope.eventsConfig.expirationUnit); + + RealmEventsConfig.update({ + id : realm.realm + }, copy, function () { + $location.url("/realms/" + realm.realm + "/events-settings"); + Notifications.success("Your changes have been saved to the realm."); + }); + }; + + $scope.reset = function() { + $scope.eventsConfig = angular.copy(oldCopy); + $scope.changed = false; + }; + + $scope.clearEvents = function() { + Dialog.confirmDelete($scope.realm.realm, 'events', function() { + RealmEvents.remove({ id : $scope.realm.realm }, function() { + Notifications.success("The events has been cleared."); + }); + }); + }; + + $scope.clearAdminEvents = function() { + Dialog.confirmDelete($scope.realm.realm, 'admin-events', function() { + RealmAdminEvents.remove({ id : $scope.realm.realm }, function() { + Notifications.success("The admin events has been cleared."); + }); + }); + }; +}); + +module.controller('RealmEventsCtrl', function($scope, RealmEvents, realm, serverInfo) { + $scope.realm = realm; + $scope.page = 0; + + $scope.eventSelectOptions = { + 'multiple': true, + 'simple_tags': true, + 'tags': serverInfo.enums['eventType'] + }; + + $scope.query = { + id : realm.realm, + max : 5, + first : 0 + } + + $scope.disablePaste = function(e) { + e.preventDefault(); + return false; + } + + $scope.update = function() { + $scope.query.first = 0; + for (var i in $scope.query) { + if ($scope.query[i] === '') { + delete $scope.query[i]; + } + } + $scope.events = RealmEvents.query($scope.query); + } + + $scope.reset = function() { + $scope.query.first = 0; + $scope.query.max = 5; + $scope.query.type = ''; + $scope.query.client = ''; + $scope.query.user = ''; + $scope.query.dateFrom = ''; + $scope.query.dateTo = ''; + + $scope.update(); + } + + $scope.queryUpdate = function() { + for (var i in $scope.query) { + if ($scope.query[i] === '') { + delete $scope.query[i]; + } + } + $scope.events = RealmEvents.query($scope.query); + } + + $scope.firstPage = function() { + $scope.query.first = 0; + $scope.queryUpdate(); + } + + $scope.previousPage = function() { + $scope.query.first -= parseInt($scope.query.max); + if ($scope.query.first < 0) { + $scope.query.first = 0; + } + $scope.queryUpdate(); + } + + $scope.nextPage = function() { + $scope.query.first += parseInt($scope.query.max); + $scope.queryUpdate(); + } + + $scope.update(); +}); + +module.controller('RealmAdminEventsCtrl', function($scope, RealmAdminEvents, realm, serverInfo, $modal, $filter) { + $scope.realm = realm; + $scope.page = 0; + + $scope.query = { + id : realm.realm, + max : 5, + first : 0 + }; + + $scope.adminEnabledEventOperationsOptions = { + 'multiple': true, + 'simple_tags': true, + 'tags': serverInfo.enums['operationType'] + }; + + $scope.adminEnabledEventResourceTypesOptions = { + 'multiple': true, + 'simple_tags': true, + 'tags': serverInfo.enums['resourceType'] + }; + + $scope.disablePaste = function(e) { + e.preventDefault(); + return false; + } + + $scope.update = function() { + $scope.query.first = 0; + for (var i in $scope.query) { + if ($scope.query[i] === '') { + delete $scope.query[i]; + } + } + $scope.events = RealmAdminEvents.query($scope.query); + }; + + $scope.reset = function() { + $scope.query.first = 0; + $scope.query.max = 5; + $scope.query.operationTypes = ''; + $scope.query.resourceTypes = ''; + $scope.query.resourcePath = ''; + $scope.query.authRealm = ''; + $scope.query.authClient = ''; + $scope.query.authUser = ''; + $scope.query.authIpAddress = ''; + $scope.query.dateFrom = ''; + $scope.query.dateTo = ''; + + $scope.update(); + }; + + $scope.queryUpdate = function() { + for (var i in $scope.query) { + if ($scope.query[i] === '') { + delete $scope.query[i]; + } + } + $scope.events = RealmAdminEvents.query($scope.query); + } + + $scope.firstPage = function() { + $scope.query.first = 0; + $scope.queryUpdate(); + } + + $scope.previousPage = function() { + $scope.query.first -= parseInt($scope.query.max); + if ($scope.query.first < 0) { + $scope.query.first = 0; + } + $scope.queryUpdate(); + } + + $scope.nextPage = function() { + $scope.query.first += parseInt($scope.query.max); + $scope.queryUpdate(); + } + + $scope.update(); + + $scope.viewRepresentation = function(event) { + $modal.open({ + templateUrl: resourceUrl + '/partials/modal/realm-events-admin-representation.html', + controller: 'RealmAdminEventsModalCtrl', + resolve: { + event: function () { + return event; + } + } + }) + } + + $scope.viewAuth = function(event) { + $modal.open({ + templateUrl: resourceUrl + '/partials/modal/realm-events-admin-auth.html', + controller: 'RealmAdminEventsModalCtrl', + resolve: { + event: function () { + return event; + } + } + }) + } +}); + +module.controller('RealmAdminEventsModalCtrl', function($scope, $filter, event) { + $scope.event = event; +}); + +module.controller('RealmBruteForceCtrl', function($scope, Realm, realm, $http, $location, Dialog, Notifications, TimeUnit, $route) { + console.log('RealmBruteForceCtrl'); + + $scope.realm = realm; + + $scope.realm.waitIncrementUnit = TimeUnit.autoUnit(realm.waitIncrementSeconds); + $scope.realm.waitIncrement = TimeUnit.toUnit(realm.waitIncrementSeconds, $scope.realm.waitIncrementUnit); + + $scope.realm.minimumQuickLoginWaitUnit = TimeUnit.autoUnit(realm.minimumQuickLoginWaitSeconds); + $scope.realm.minimumQuickLoginWait = TimeUnit.toUnit(realm.minimumQuickLoginWaitSeconds, $scope.realm.minimumQuickLoginWaitUnit); + + $scope.realm.maxFailureWaitUnit = TimeUnit.autoUnit(realm.maxFailureWaitSeconds); + $scope.realm.maxFailureWait = TimeUnit.toUnit(realm.maxFailureWaitSeconds, $scope.realm.maxFailureWaitUnit); + + $scope.realm.maxDeltaTimeUnit = TimeUnit.autoUnit(realm.maxDeltaTimeSeconds); + $scope.realm.maxDeltaTime = TimeUnit.toUnit(realm.maxDeltaTimeSeconds, $scope.realm.maxDeltaTimeUnit); + + var oldCopy = angular.copy($scope.realm); + $scope.changed = false; + + $scope.$watch('realm', function() { + if (!angular.equals($scope.realm, oldCopy)) { + $scope.changed = true; + } + }, true); + + $scope.save = function() { + var realmCopy = angular.copy($scope.realm); + delete realmCopy["waitIncrementUnit"]; + delete realmCopy["waitIncrement"]; + delete realmCopy["minimumQuickLoginWaitUnit"]; + delete realmCopy["minimumQuickLoginWait"]; + delete realmCopy["maxFailureWaitUnit"]; + delete realmCopy["maxFailureWait"]; + delete realmCopy["maxDeltaTimeUnit"]; + delete realmCopy["maxDeltaTime"]; + + realmCopy.waitIncrementSeconds = TimeUnit.toSeconds($scope.realm.waitIncrement, $scope.realm.waitIncrementUnit) + realmCopy.minimumQuickLoginWaitSeconds = TimeUnit.toSeconds($scope.realm.minimumQuickLoginWait, $scope.realm.minimumQuickLoginWaitUnit) + realmCopy.maxFailureWaitSeconds = TimeUnit.toSeconds($scope.realm.maxFailureWait, $scope.realm.maxFailureWaitUnit) + realmCopy.maxDeltaTimeSeconds = TimeUnit.toSeconds($scope.realm.maxDeltaTime, $scope.realm.maxDeltaTimeUnit) + + $scope.changed = false; + Realm.update(realmCopy, function () { + oldCopy = angular.copy($scope.realm); + $location.url("/realms/" + realm.realm + "/defense/brute-force"); + Notifications.success("Your changes have been saved to the realm."); + }); + }; + + $scope.reset = function() { + $route.reload(); + }; +}); + + +module.controller('IdentityProviderMapperListCtrl', function($scope, realm, identityProvider, mapperTypes, mappers) { + $scope.realm = realm; + $scope.identityProvider = identityProvider; + $scope.mapperTypes = mapperTypes; + $scope.mappers = mappers; +}); + +module.controller('IdentityProviderMapperCtrl', function ($scope, realm, identityProvider, mapperTypes, mapper, IdentityProviderMapper, Notifications, Dialog, ComponentUtils, $location) { + $scope.realm = realm; + $scope.identityProvider = identityProvider; + $scope.create = false; + $scope.changed = false; + $scope.mapperType = mapperTypes[mapper.identityProviderMapper]; + + ComponentUtils.convertAllMultivaluedStringValuesToList($scope.mapperType.properties, mapper.config); + ComponentUtils.addLastEmptyValueToMultivaluedLists($scope.mapperType.properties, mapper.config); + + $scope.mapper = angular.copy(mapper); + + $scope.$watch(function () { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); + + $scope.$watch('mapper', function() { + if (!angular.equals($scope.mapper, mapper)) { + $scope.changed = true; + } + }, true); + + $scope.save = function() { + let mapperCopy = angular.copy($scope.mapper); + ComponentUtils.convertAllListValuesToMultivaluedString($scope.mapperType.properties, mapperCopy.config); + + IdentityProviderMapper.update({ + realm : realm.realm, + alias : identityProvider.alias, + mapperId : mapper.id + }, mapperCopy, function () { + $scope.changed = false; + ComponentUtils.addLastEmptyValueToMultivaluedLists($scope.mapperType.properties, $scope.mapper.config); + mapper = angular.copy($scope.mapper); + $location.url("/realms/" + realm.realm + '/identity-provider-mappers/' + identityProvider.alias + "/mappers/" + mapper.id); + Notifications.success("Your changes have been saved."); + }); + }; + + $scope.reset = function() { + $scope.mapper = angular.copy(mapper); + $scope.changed = false; + }; + + $scope.cancel = function() { + //$location.url("/realms"); + window.history.back(); + }; + + $scope.remove = function() { + Dialog.confirmDelete($scope.mapper.name, 'mapper', function() { + IdentityProviderMapper.remove({ realm: realm.realm, alias: mapper.identityProviderAlias, mapperId : $scope.mapper.id }, function() { + Notifications.success("The mapper has been deleted."); + $location.url("/realms/" + realm.realm + '/identity-provider-mappers/' + identityProvider.alias + "/mappers"); + }); + }); + }; + +}); + +module.controller('IdentityProviderMapperCreateCtrl', function ($scope, realm, identityProvider, mapperTypes, IdentityProviderMapper, Notifications, Dialog, ComponentUtils, $location) { + $scope.realm = realm; + $scope.identityProvider = identityProvider; + $scope.create = true; + $scope.mapper = { identityProviderAlias: identityProvider.alias, config: {}}; + $scope.mapperTypes = mapperTypes; + + // make first type the default + $scope.mapperType = mapperTypes[Object.keys(mapperTypes)[0]]; + $scope.mapper.config.syncMode = 'INHERIT'; + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); + + $scope.save = function () { + $scope.mapper.identityProviderMapper = $scope.mapperType.id; + let copyMapper = angular.copy($scope.mapper); + ComponentUtils.convertAllListValuesToMultivaluedString($scope.mapperType.properties, copyMapper.config); + + IdentityProviderMapper.save({ + realm : realm.realm, + alias : identityProvider.alias + }, copyMapper, function (data, headers) { + var l = headers().location; + var id = l.substring(l.lastIndexOf("/") + 1); + $location.url("/realms/" + realm.realm + '/identity-provider-mappers/' + identityProvider.alias + "/mappers/" + id); + Notifications.success("Mapper has been created."); + }); + }; + + $scope.cancel = function() { + //$location.url("/realms"); + window.history.back(); + }; + + +}); + +module.controller('RealmFlowBindingCtrl', function($scope, flows, Current, Realm, realm, serverInfo, $http, $route, Dialog, Notifications) { + $scope.flows = []; + $scope.clientFlows = []; + for (var i=0 ; i 0) { + $scope.provider = formProviders[0]; + } + + $scope.save = function() { + $scope.flow.provider = $scope.provider.id; + CreateExecutionFlow.save({realm: realm.realm, alias: parentFlow.alias}, $scope.flow, function() { + $location.url("/realms/" + realm.realm + "/authentication/flows"); + Notifications.success("Flow Created."); + }) + } + $scope.cancel = function() { + $location.url("/realms/" + realm.realm + "/authentication/flows"); + }; +}); + +module.controller('CreateExecutionCtrl', function($scope, realm, parentFlow, formActionProviders, authenticatorProviders, clientAuthenticatorProviders, + CreateExecution, + Notifications, $location) { + $scope.realm = realm; + $scope.parentFlow = parentFlow; + + if (parentFlow.providerId == 'form-flow') { + $scope.providers = formActionProviders; + } else if (parentFlow.providerId == 'client-flow') { + $scope.providers = clientAuthenticatorProviders; + } else { + $scope.providers = authenticatorProviders; + } + + $scope.provider = {}; + if ($scope.providers.length > 0) { + $scope.provider = $scope.providers[0]; + } + + $scope.save = function() { + var execution = { + provider: $scope.provider.id + } + CreateExecution.save({realm: realm.realm, alias: parentFlow.alias}, execution, function() { + $location.url("/realms/" + realm.realm + "/authentication/flows"); + Notifications.success("Execution Created."); + }) + } + $scope.cancel = function() { + $location.url("/realms/" + realm.realm + "/authentication/flows"); + }; +}); + + + +module.controller('AuthenticationFlowsCtrl', function($scope, $route, realm, flows, selectedFlow, LastFlowSelected, Dialog, + AuthenticationFlows, AuthenticationFlowsCopy, AuthenticationFlowsUpdate, AuthenticationFlowExecutions, + AuthenticationExecution, AuthenticationExecutionRaisePriority, AuthenticationExecutionLowerPriority, + $modal, Notifications, CopyDialog, UpdateDialog, $location) { + $scope.realm = realm; + $scope.flows = flows; + + if (selectedFlow !== null) { + LastFlowSelected.alias = selectedFlow; + } + + if (selectedFlow === null && LastFlowSelected.alias !== null) { + selectedFlow = LastFlowSelected.alias; + } + + if (flows.length > 0) { + $scope.flow = flows[0]; + if (selectedFlow) { + for (var i = 0; i < flows.length; i++) { + if (flows[i].alias == selectedFlow) { + $scope.flow = flows[i]; + break; + } + } + } + } + + $scope.selectFlow = function(flow) { + $location.url("/realms/" + realm.realm + '/authentication/flows/' + flow.alias); + }; + + var setupForm = function() { + AuthenticationFlowExecutions.query({realm: realm.realm, alias: $scope.flow.alias}, function(data) { + $scope.executions = data; + $scope.choicesmax = 0; + $scope.levelmax = 0; + for (var i = 0; i < $scope.executions.length; i++ ) { + var execution = $scope.executions[i]; + if (execution.requirementChoices.length > $scope.choicesmax) { + $scope.choicesmax = execution.requirementChoices.length; + } + if (execution.level > $scope.levelmax) { + $scope.levelmax = execution.level; + } + } + $scope.levelmaxempties = []; + for (j = 0; j < $scope.levelmax; j++) { + $scope.levelmaxempties.push(j); + + } + for (var i = 0; i < $scope.executions.length; i++ ) { + var execution = $scope.executions[i]; + execution.empties = []; + for (j = 0; j < $scope.choicesmax - execution.requirementChoices.length; j++) { + execution.empties.push(j); + } + execution.preLevels = []; + for (j = 0; j < execution.level; j++) { + execution.preLevels.push(j); + } + execution.postLevels = []; + for (j = execution.level; j < $scope.levelmax; j++) { + execution.postLevels.push(j); + } + } + }) + }; + + $scope.copyFlow = function() { + CopyDialog.open('Copy Authentication Flow', $scope.flow.alias, function(name) { + AuthenticationFlowsCopy.save({realm: realm.realm, alias: $scope.flow.alias}, { + newName: name + }, function() { + $location.url("/realms/" + realm.realm + '/authentication/flows/' + name); + Notifications.success("Flow copied."); + }) + }) + }; + + $scope.deleteFlow = function() { + Dialog.confirmDelete($scope.flow.alias, 'flow', function() { + $scope.removeFlow(); + }); + }; + + $scope.removeFlow = function() { + console.log('Remove flow:' + $scope.flow.alias); + if (realm.browserFlow == $scope.flow.alias) { + Notifications.error("Cannot remove flow, it is currently being used as the browser flow."); + + } else if (realm.registrationFlow == $scope.flow.alias) { + Notifications.error("Cannot remove flow, it is currently being used as the registration flow."); + + } else if (realm.directGrantFlow == $scope.flow.alias) { + Notifications.error("Cannot remove flow, it is currently being used as the direct grant flow."); + + } else if (realm.resetCredentialsFlow == $scope.flow.alias) { + Notifications.error("Cannot remove flow, it is currently being used as the reset credentials flow."); + + } else if (realm.clientAuthenticationFlow == $scope.flow.alias) { + Notifications.error("Cannot remove flow, it is currently being used as the client authentication flow."); + + } else if (realm.dockerAuthenticationFlow == $scope.flow.alias) { + Notifications.error("Cannot remove flow, it is currently being used as the docker authentication flow."); + } else { + AuthenticationFlows.remove({realm: realm.realm, flow: $scope.flow.id}, function () { + $location.url("/realms/" + realm.realm + '/authentication/flows/' + flows[0].alias); + Notifications.success("Flow removed"); + }) + } + + }; + + $scope.editFlow = function(flow) { + var copy = angular.copy(flow); + UpdateDialog.open('Update Authentication Flow', copy.alias, copy.description, function(name, desc) { + copy.alias = name; + copy.description = desc; + AuthenticationFlowsUpdate.update({realm: realm.realm, flow: flow.id}, copy, function() { + $location.url("/realms/" + realm.realm + '/authentication/flows/' + name); + Notifications.success("Flow updated"); + }); + }) + }; + + $scope.addFlow = function() { + $location.url("/realms/" + realm.realm + '/authentication/flows/' + $scope.flow.id + '/create/flow/execution/' + $scope.flow.id); + + } + + $scope.addSubFlow = function(execution) { + $location.url("/realms/" + realm.realm + '/authentication/flows/' + execution.flowId + '/create/flow/execution/' + $scope.flow.alias); + + } + + $scope.addSubFlowExecution = function(execution) { + $location.url("/realms/" + realm.realm + '/authentication/flows/' + execution.flowId + '/create/execution/' + $scope.flow.alias); + + } + + $scope.addExecution = function() { + $location.url("/realms/" + realm.realm + '/authentication/flows/' + $scope.flow.id + '/create/execution/' + $scope.flow.id); + + } + + $scope.createFlow = function() { + $location.url("/realms/" + realm.realm + '/authentication/create/flow'); + } + + $scope.updateExecution = function(execution) { + var copy = angular.copy(execution); + delete copy.empties; + delete copy.levels; + delete copy.preLevels; + delete copy.postLevels; + AuthenticationFlowExecutions.update({realm: realm.realm, alias: $scope.flow.alias}, copy, function() { + Notifications.success("Auth requirement updated"); + setupForm(); + }); + + }; + + $scope.editExecutionFlow = function(execution) { + var copy = angular.copy(execution); + delete copy.empties; + delete copy.levels; + delete copy.preLevels; + delete copy.postLevels; + UpdateDialog.open('Update Execution Flow', copy.displayName, copy.description, function(name, desc) { + copy.displayName = name; + copy.description = desc; + AuthenticationFlowExecutions.update({realm: realm.realm, alias: $scope.flow.alias}, copy, function() { + Notifications.success("Execution Flow updated"); + setupForm(); + }); + }) + }; + + $scope.removeExecution = function(execution) { + console.log('removeExecution: ' + execution.id); + var exeOrFlow = execution.authenticationFlow ? 'flow' : 'execution'; + Dialog.confirmDelete(execution.displayName, exeOrFlow, function() { + AuthenticationExecution.remove({realm: realm.realm, execution: execution.id}, function() { + Notifications.success("The " + exeOrFlow + " was removed."); + setupForm(); + }); + }); + + } + + $scope.raisePriority = function(execution) { + AuthenticationExecutionRaisePriority.save({realm: realm.realm, execution: execution.id}, function() { + Notifications.success("Priority raised"); + setupForm(); + }) + } + + $scope.lowerPriority = function(execution) { + AuthenticationExecutionLowerPriority.save({realm: realm.realm, execution: execution.id}, function() { + Notifications.success("Priority lowered"); + setupForm(); + }) + } + + $scope.setupForm = setupForm; + + if (selectedFlow == null) { + $scope.selectFlow(flows[0]); + } else { + setupForm(); + } +}); + +module.controller('RequiredActionsCtrl', function($scope, realm, unregisteredRequiredActions, + $modal, $route, + RegisterRequiredAction, RequiredActions, RequiredActionRaisePriority, RequiredActionLowerPriority, Notifications) { + console.log('RequiredActionsCtrl'); + $scope.realm = realm; + $scope.unregisteredRequiredActions = unregisteredRequiredActions; + $scope.requiredActions = []; + var setupRequiredActionsForm = function() { + console.log('setupRequiredActionsForm'); + RequiredActions.query({realm: realm.realm}, function(data) { + $scope.requiredActions = []; + for (var i = 0; i < data.length; i++) { + $scope.requiredActions.push(data[i]); + } + }); + }; + + $scope.updateRequiredAction = function(action) { + RequiredActions.update({realm: realm.realm, alias: action.alias}, action, function() { + Notifications.success("Required action updated"); + setupRequiredActionsForm(); + }); + } + + $scope.raisePriority = function(action) { + RequiredActionRaisePriority.save({realm: realm.realm, alias: action.alias}, function() { + Notifications.success("Required action's priority raised"); + setupRequiredActionsForm(); + }) + } + + $scope.lowerPriority = function(action) { + RequiredActionLowerPriority.save({realm: realm.realm, alias: action.alias}, function() { + Notifications.success("Required action's priority lowered"); + setupRequiredActionsForm(); + }) + } + + $scope.register = function() { + var controller = function($scope, $modalInstance) { + $scope.unregisteredRequiredActions = unregisteredRequiredActions; + $scope.selected = { + selected: $scope.unregisteredRequiredActions[0] + } + $scope.ok = function () { + $modalInstance.close(); + RegisterRequiredAction.save({realm: realm.realm}, $scope.selected.selected, function() { + $route.reload(); + }); + }; + $scope.cancel = function () { + $modalInstance.dismiss('cancel'); + }; + } + $modal.open({ + templateUrl: resourceUrl + '/partials/modal/unregistered-required-action-selector.html', + controller: controller, + resolve: { + } + }); + } + + setupRequiredActionsForm(); + + +}); + +module.controller('AuthenticationConfigCtrl', function($scope, realm, flow, configType, config, AuthenticationConfig, Notifications, + Dialog, $location, ComponentUtils) { + $scope.realm = realm; + $scope.flow = flow; + $scope.configType = configType; + $scope.create = false; + $scope.config = angular.copy(config); + $scope.changed = false; + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); + + $scope.$watch('config', function() { + if (!angular.equals($scope.config, config)) { + $scope.changed = true; + } + }, true); + + $scope.save = function() { + var configCopy = angular.copy($scope.config); + ComponentUtils.convertAllListValuesToMultivaluedString(configType.properties, configCopy.config); + + AuthenticationConfig.update({ + realm : realm.realm, + config : config.id + }, configCopy, function() { + $scope.changed = false; + config = angular.copy($scope.config); + Notifications.success("Your changes have been saved."); + $location.reload(); + }); + }; + + $scope.reset = function() { + $scope.config = angular.copy(config); + $scope.changed = false; + }; + + $scope.cancel = function() { + //$location.url("/realms"); + window.history.back(); + }; + + $scope.remove = function() { + Dialog.confirmDelete($scope.config.alias, 'config', function() { + AuthenticationConfig.remove({ realm: realm.realm, config : $scope.config.id }, function() { + Notifications.success("The config has been deleted."); + $location.url("/realms/" + realm.realm + '/authentication/flows/' + flow.id); + }); + }); + }; + +}); + +module.controller('AuthenticationConfigCreateCtrl', function($scope, realm, flow, configType, execution, AuthenticationExecutionConfig, + Notifications, Dialog, $location, ComponentUtils) { + $scope.realm = realm; + $scope.flow = flow; + $scope.create = true; + $scope.configType = configType; + + var defaultConfig = {}; + if (configType && Array.isArray(configType.properties)) { + for(var i = 0; i < configType.properties.length; i++) { + var property = configType.properties[i]; + if (property && property.name) { + defaultConfig[property.name] = property.defaultValue; + } + } + } + + $scope.config = { config: defaultConfig}; + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); + + $scope.save = function() { + var configCopy = angular.copy($scope.config); + ComponentUtils.convertAllListValuesToMultivaluedString(configType.properties, configCopy.config); + + AuthenticationExecutionConfig.save({ + realm : realm.realm, + execution: execution + }, configCopy, function(data, headers) { + var l = headers().location; + var id = l.substring(l.lastIndexOf("/") + 1); + var url = "/realms/" + realm.realm + '/authentication/flows/' + flow.id + '/config/' + configType.providerId + "/" + id; + console.log('redirect url: ' + url); + $location.url(url); + Notifications.success("Config has been created."); + }); + }; + + $scope.cancel = function() { + //$location.url("/realms"); + window.history.back(); + }; +}); + +module.controller('ClientInitialAccessCtrl', function($scope, realm, clientInitialAccess, ClientInitialAccess, Dialog, Notifications, $route, $location) { + $scope.realm = realm; + $scope.clientInitialAccess = clientInitialAccess; + + $scope.remove = function(id) { + Dialog.confirmDelete(id, 'initial access token', function() { + ClientInitialAccess.remove({ realm: realm.realm, id: id }, function() { + Notifications.success("The initial access token was deleted."); + $route.reload(); + }); + }); + } +}); + +module.controller('ClientInitialAccessCreateCtrl', function($scope, realm, ClientInitialAccess, TimeUnit, Dialog, $location, $translate) { + $scope.expirationUnit = 'Days'; + $scope.expiration = TimeUnit.toUnit(0, $scope.expirationUnit); + $scope.count = 1; + $scope.realm = realm; + + $scope.save = function() { + var expiration = TimeUnit.toSeconds($scope.expiration, $scope.expirationUnit); + ClientInitialAccess.save({ + realm: realm.realm + }, { expiration: expiration, count: $scope.count}, function (data) { + console.debug(data); + $scope.id = data.id; + $scope.token = data.token; + }); + }; + + $scope.cancel = function() { + $location.url('/realms/' + realm.realm + '/client-registration/client-initial-access'); + }; + + $scope.done = function() { + var btns = { + ok: { + label: $translate.instant('continue'), + cssClass: 'btn btn-primary' + }, + cancel: { + label: $translate.instant('cancel'), + cssClass: 'btn btn-default' + } + } + + var title = $translate.instant('initial-access-token.confirm.title'); + var message = $translate.instant('initial-access-token.confirm.text'); + Dialog.open(title, message, btns, function() { + $location.url('/realms/' + realm.realm + '/client-registration/client-initial-access'); + }); + }; +}); + +module.controller('ClientRegPoliciesCtrl', function($scope, realm, clientRegistrationPolicyProviders, policies, Dialog, Notifications, Components, $route, $location) { + $scope.realm = realm; + $scope.providers = clientRegistrationPolicyProviders; + $scope.anonPolicies = []; + $scope.authPolicies = []; + for (var i=0 ; i { + $scope.headerTitle = translatedValue; + }).catch(() => { + $scope.headerTitle = $scope.instance.providerId; + }); + + if ($scope.create) { + $scope.instance.name = ""; + $scope.instance.parentId = realm.id; + $scope.instance.config = {}; + + if ($scope.providerType.properties) { + + for (let i = 0; i < $scope.providerType.properties.length; i++) { + let configProperty = $scope.providerType.properties[i]; + $scope.instance.config[configProperty.name] = toDefaultValue(configProperty); + } + } + } + + if ($scope.providerType.properties) { + ComponentUtils.addLastEmptyValueToMultivaluedLists($scope.providerType.properties, $scope.instance.config); + ComponentUtils.addMvOptionsToMultivaluedLists($scope.providerType.properties); + } + + let oldCopy = angular.copy($scope.instance); + $scope.changed = false; + + $scope.$watch('instance', function() { + if (!angular.equals($scope.instance, oldCopy)) { + $scope.changed = true; + } + }, true); + + $scope.reset = function() { + $scope.create ? window.history.back() : $route.reload(); + }; + + $scope.hasValidValues = () => $scope.changed && $scope.instance.name; + + $scope.save = function() { + $scope.changed = false; + if ($scope.create) { + Components.save({realm: realm.realm}, $scope.instance, function (data, headers) { + var l = headers().location; + var id = l.substring(l.lastIndexOf("/") + 1); + $location.url("/realms/" + realm.realm + "/client-registration/client-reg-policies/" + $scope.instance.providerId + "/" + id); + Notifications.success("The policy has been created."); + }); + } else { + Components.update({realm: realm.realm, + componentId: instance.id + }, + $scope.instance, function () { + $route.reload(); + Notifications.success("The policy has been updated."); + }); + } + }; + +}); + +module.controller('ClientPoliciesProfilesListCtrl', function($scope, realm, clientProfiles, ClientPoliciesProfiles, Dialog, Notifications, $route, $location) { + console.log('ClientPoliciesProfilesListCtrl'); + $scope.realm = realm; + $scope.clientProfiles = clientProfiles; + + $scope.removeClientProfile = function(clientProfile) { + Dialog.confirmDelete(clientProfile.name, 'client profile', function() { + console.log("Deleting client profile from the JSON: " + clientProfile.name); + + for (var i = 0; i < $scope.clientProfiles.profiles.length; i++) { + var currentProfile = $scope.clientProfiles.profiles[i]; + if (currentProfile.name === clientProfile.name) { + $scope.clientProfiles.profiles.splice(i, 1); + break; + } + } + + ClientPoliciesProfiles.update({ + realm: realm.realm, + }, $scope.clientProfiles, function () { + $route.reload(); + Notifications.success("The client profile was deleted."); + }, function (errorResponse) { + $route.reload(); + var errDetails = (!errorResponse.data.errorMessage) ? "unknown error, please see the server log" : errorResponse.data.errorMessage + Notifications.error('Failed to delete client profile: ' + errDetails); + }); + }); + }; + +}); + +module.controller('ClientPoliciesProfilesJsonCtrl', function($scope, realm, clientProfiles, ClientPoliciesProfiles, Dialog, Notifications, $route, $location) { + console.log('ClientPoliciesProfilesJsonCtrl'); + $scope.realm = realm; + $scope.clientProfilesString = angular.toJson(clientProfiles, true); + + $scope.save = function() { + var clientProfilesObj = null; + try { + clientProfilesObj = angular.fromJson($scope.clientProfilesString); + } catch (e) { + Notifications.error("Provided JSON is incorrect: " + e.message); + console.log(e); + return; + } + var clientProfilesCompressed = angular.toJson(clientProfilesObj, false); + + ClientPoliciesProfiles.update({ + realm: realm.realm, + }, clientProfilesCompressed, function () { + $route.reload(); + Notifications.success("The client profiles configuration was updated."); + }, function(errorResponse) { + var errDetails = (!errorResponse.data.errorMessage) ? "unknown error, please see the server log" : errorResponse.data.errorMessage + Notifications.error("Failed to update client profiles: " + errDetails); + console.log("Error response when updating client profiles JSON: Status: " + errorResponse.status + + ", statusText: " + errorResponse.statusText + ", data: " + JSON.stringify(errorResponse.data)); + }); + }; + + $scope.reset = function() { + $route.reload(); + }; + +}); + +module.controller('ClientPoliciesProfilesEditCtrl', function($scope, realm, clientProfiles, ClientPoliciesProfiles, Dialog, Notifications, $route, $location) { + var targetProfileName = $route.current.params.profileName; + $scope.createNew = targetProfileName == null; + if ($scope.createNew) { + console.log('ClientPoliciesProfilesEditCtrl: creating new profile'); + } else { + console.log('ClientPoliciesProfilesEditCtrl: updating profile ' + targetProfileName); + } + + $scope.realm = realm; + $scope.editedProfile = null; + + function getProfileByName(profilesArray) { + if (!profilesArray) return null; + for (var i=0 ; i < profilesArray.length ; i++) { + var currentProfile = profilesArray[i]; + if (targetProfileName === currentProfile.name) { + return currentProfile; + } + } + } + + if ($scope.createNew) { + $scope.editedProfile = { + name: "", + executors: [] + }; + } else { + var globalProfile = false; + $scope.editedProfile = getProfileByName(clientProfiles.profiles); + if (!$scope.editedProfile) { + $scope.editedProfile = getProfileByName(clientProfiles.globalProfiles); + globalProfile = true; + } + + if ($scope.editedProfile == null) { + console.log("Profile of name " + targetProfileName + " not found"); + throw 'Profile not found'; + } + } + + // needs to be a function because when this controller runs, the permissions might not be loaded yet + $scope.isReadOnly = function() { + return !$scope.access.manageRealm || globalProfile; + } + + $scope.removeExecutor = function(executorIndex) { + Dialog.confirmDelete($scope.editedProfile.executors[executorIndex].executor, 'executor', function() { + console.log("remove executor of index " + executorIndex); + + // Delete executor + $scope.editedProfile.executors.splice(executorIndex, 1); + + ClientPoliciesProfiles.update({ + realm: realm.realm, + }, clientProfiles, function () { + Notifications.success("The executor was deleted."); + }, function (errorResponse) { + $route.reload(); + var errDetails = (!errorResponse.data.errorMessage) ? "unknown error, please see the server log" : errorResponse.data.errorMessage + Notifications.error('Failed to delete executor: ' + errDetails); + }); + }); + } + + $scope.save = function() { + if (!$scope.editedProfile.name || $scope.editedProfile.name === '') { + Notifications.error('Name must be provided'); + return; + } + + if ($scope.createNew) { + clientProfiles.profiles.push($scope.editedProfile); + } + + ClientPoliciesProfiles.update({ + realm: realm.realm, + }, clientProfiles, function () { + if ($scope.createNew) { + Notifications.success("The client profile was created."); + $location.url('/realms/' + realm.realm + '/client-policies/profiles-update/' + $scope.editedProfile.name); + } else { + Notifications.success("The client profile was updated."); + $location.url('/realms/' + realm.realm + '/client-policies/profiles'); + } + }, function(errorResponse) { + var errDetails = (!errorResponse.data.errorMessage) ? "unknown error, please see the server log" : errorResponse.data.errorMessage + if ($scope.createNew) { + Notifications.error('Failed to create client profile: ' + errDetails); + } else { + Notifications.error('Failed to update client profile: ' + errDetails); + } + }); + + }; + + $scope.back = function() { + $location.url('/realms/' + realm.realm + '/client-policies/profiles'); + }; + +}); + +module.controller('ClientPoliciesProfilesEditExecutorCtrl', function($scope, realm, serverInfo, clientProfiles, ClientPoliciesProfiles, ComponentUtils, Dialog, Notifications, $route, $location) { + var updatedExecutorIndex = $route.current.params.executorIndex; + var targetProfileName = $route.current.params.profileName; + $scope.createNew = updatedExecutorIndex == null; + if ($scope.createNew) { + console.log('ClientPoliciesProfilesEditExecutorCtrl: adding executor to profile ' + targetProfileName); + } else { + console.log('ClientPoliciesProfilesEditExecutorCtrl: updating executor with index ' + updatedExecutorIndex + ' of profile ' + targetProfileName); + } + $scope.realm = realm; + + function getProfileByName(profilesArray) { + if (!profilesArray) return null; + for (var i=0 ; i < profilesArray.length ; i++) { + var currentProfile = profilesArray[i]; + if (targetProfileName === currentProfile.name) { + return currentProfile; + } + } + } + + var globalProfile = false; + $scope.editedProfile = getProfileByName(clientProfiles.profiles); + if (!$scope.editedProfile) { + $scope.editedProfile = getProfileByName(clientProfiles.globalProfiles); + globalProfile = true; + } + if ($scope.editedProfile == null) { + throw 'Client profile of specified name not found'; + } + + // needs to be a function because when this controller runs, the permissions might not be loaded yet + $scope.isReadOnly = function() { + return !$scope.access.manageRealm || globalProfile; + } + + $scope.executorTypes = serverInfo.componentTypes['org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProvider']; + + for (var j=0 ; j < $scope.executorTypes.length ; j++) { + var currExecutorType = $scope.executorTypes[j]; + if (currExecutorType.properties) { + console.log("Adjusting executorType: " + currExecutorType.id); + ComponentUtils.addMvOptionsToMultivaluedLists(currExecutorType.properties); + } + } + + function getExecutorByIndex(clientProfile, executorIndex) { + if (clientProfile.executors.length <= executorIndex) { + console.error('Client profile does not have executor of specified index'); + $location.path('/notfound'); + return null; + } else { + return clientProfile.executors[executorIndex]; + } + } + + if ($scope.createNew) { + // make first type the default + $scope.executorType = $scope.executorTypes[0]; + var oldExecutorType = $scope.executorType; + initConfig(); + + $scope.$watch('executorType', function() { + if (!angular.equals($scope.executorType, oldExecutorType)) { + oldExecutorType = $scope.executorType; + initConfig(); + } + }, true); + } else { + var exec = getExecutorByIndex($scope.editedProfile, updatedExecutorIndex); + if (exec) { + // a failsafe in case the configuration was deleted entirely (or set to null) in the JSON view + if (!exec.configuration) { + exec.configuration = {} + } + + $scope.executor = { + config: exec.configuration + }; + + $scope.executorType = null; + for (var j=0 ; j < $scope.executorTypes.length ; j++) { + var currentExType = $scope.executorTypes[j]; + if (exec.executor === currentExType.id) { + $scope.executorType = currentExType; + break; + } + } + + for (var j=0 ; j < $scope.executorType.properties.length ; j++) { + // Convert boolean properties from the configuration to strings as expected by the kc-provider-config directive + var currentProperty = $scope.executorType.properties[j]; + if (currentProperty.type === 'boolean') { + $scope.executor.config[currentProperty.name] = ($scope.executor.config[currentProperty.name]) ? "true" : "false"; + } + + // a workaround for select2 to prevent displaying empty boxes + var configProperty = $scope.executor.config[$scope.executorType.properties[j].name]; + if (Array.isArray(configProperty) && configProperty.length === 0) { + $scope.executor.config[$scope.executorType.properties[j].name] = null + } + + } + } + + } + + function toDefaultValue(configProperty) { + if (configProperty.type === 'boolean') { + return (configProperty.defaultValue) ? "true" : "false"; + } + + if (configProperty.defaultValue !== undefined) { + if ((configProperty.type === 'MultivaluedString' || configProperty.type === 'MultivaluedList') && !Array.isArray(configProperty.defaultValue)) { + return [configProperty.defaultValue] + } + return configProperty.defaultValue; + } else { + return null; + } + } + + function initConfig() { + console.log("Initialized config now. ConfigType is: " + $scope.executorType.id); + $scope.executor = { + config: {} + }; + + for (let i = 0; i < $scope.executorType.properties.length; i++) { + let configProperty = $scope.executorType.properties[i]; + $scope.executor.config[configProperty.name] = toDefaultValue(configProperty); + } + } + + $scope.save = function() { + console.log("save: " + $scope.executorType.id); + + var executorName = $scope.executorType.id; + if (!$scope.editedProfile.executors) { + $scope.editedProfile.executors = []; + } + + ComponentUtils.removeLastEmptyValue($scope.executor.config); + + // Convert String properties required by the kc-provider-config directive back to booleans + for (var j=0 ; j < $scope.executorType.properties.length ; j++) { + var currentProperty = $scope.executorType.properties[j]; + if (currentProperty.type === 'boolean') { + $scope.executor.config[currentProperty.name] = ($scope.executor.config[currentProperty.name] === "true") ? true : false; + } + } + + if ($scope.createNew) { + var selectedExecutor = { + executor: $scope.executorType.id, + configuration: $scope.executor.config + }; + $scope.executors = $scope.editedProfile.executors.map((ex) => ex); //clone current executors + $scope.editedProfile.executors.push(selectedExecutor); + } else { + var currentExecutor = getExecutorByIndex($scope.editedProfile, updatedExecutorIndex); + if (currentExecutor) { + currentExecutor.configuration = $scope.executor.config; + } + } + + ClientPoliciesProfiles.update({ + realm: realm.realm, + }, clientProfiles, function () { + if ($scope.createNew) { + Notifications.success("Executor created successfully"); + } else { + Notifications.success("Executor updated successfully"); + } + $location.url('/realms/' + realm.realm + '/client-policies/profiles-update/' + $scope.editedProfile.name); + }, function(errorResponse) { + var errDetails = (!errorResponse.data.errorMessage) ? "unknown error, please see the server log" : errorResponse.data.errorMessage + if ($scope.createNew) { + $scope.editedProfile.executors = $scope.executors.map((ex) => ex); + $scope.executors = undefined; + Notifications.error('Failed to create executor: ' + errDetails); + } else { + Notifications.error('Failed to update executor: ' + errDetails); + } + }); + + }; + + $scope.cancel = function() { + $location.url('/realms/' + realm.realm + '/client-policies/profiles-update/' + $scope.editedProfile.name); + }; + +}); + +module.controller('ClientPoliciesListCtrl', function($scope, realm, clientPolicies, ClientPolicies, Dialog, Notifications, $route, $location) { + console.log('ClientPoliciesListCtrl'); + $scope.realm = realm; + $scope.clientPolicies = clientPolicies; + + $scope.removeClientPolicy = function(clientPolicy) { + Dialog.confirmDelete(clientPolicy.name, 'client policy', function() { + console.log("Deleting client policy from the JSON: " + clientPolicy.name); + + for (var i = 0; i < $scope.clientPolicies.policies.length; i++) { + var currentPolicy = $scope.clientPolicies.policies[i]; + if (currentPolicy.name === clientPolicy.name) { + $scope.clientPolicies.policies.splice(i, 1); + break; + } + } + + ClientPolicies.update({ + realm: realm.realm, + }, $scope.clientPolicies, function () { + $route.reload(); + Notifications.success("The client policy was deleted."); + }, function (errorResponse) { + $route.reload(); + var errDetails = (!errorResponse.data.errorMessage) ? "unknown error, please see the server log" : errorResponse.data.errorMessage + Notifications.error('Failed to delete client policy: ' + errDetails); + }); + }); + }; + +}); + +module.controller('ClientPoliciesJsonCtrl', function($scope, realm, clientPolicies, Dialog, Notifications, ClientPolicies, $route, $location) { + console.log('ClientPoliciesJsonCtrl'); + $scope.realm = realm; + $scope.clientPoliciesString = angular.toJson(clientPolicies, true); + + $scope.save = function() { + var clientPoliciesObj = null; + try { + var clientPoliciesObj = angular.fromJson($scope.clientPoliciesString); + } catch (e) { + Notifications.error("Provided JSON is incorrect: " + e.message); + console.log(e); + return; + } + var clientPoliciesCompressed = angular.toJson(clientPoliciesObj, false); + + ClientPolicies.update({ + realm: realm.realm, + }, clientPoliciesCompressed, function () { + $route.reload(); + Notifications.success("The client policies configuration was updated."); + }, function(errorResponse) { + var errDetails = (!errorResponse.data.errorMessage) ? "unknown error, please see the server log" : errorResponse.data.errorMessage + Notifications.error("Failed to update client policies: " + errDetails); + console.log("Error response when updating client policies JSON: Status: " + errorResponse.status + + ", statusText: " + errorResponse.statusText + ", data: " + JSON.stringify(errorResponse.data)); + }); + }; + + $scope.reset = function() { + $route.reload(); + }; +}); + +module.controller('ClientPoliciesEditCtrl', function($scope, realm, clientProfiles, clientPolicies, ClientPolicies, Dialog, Notifications, $route, $location) { + var targetPolicyName = $route.current.params.policyName; + $scope.createNew = targetPolicyName == null; + if ($scope.createNew) { + console.log('ClientPoliciesEditCtrl: creating new policy'); + } else { + console.log('ClientPoliciesEditCtrl: updating policy ' + targetPolicyName); + } + + $scope.realm = realm; + $scope.clientPolicies = clientPolicies; + $scope.clientProfiles = clientProfiles; + $scope.editedPolicy = null; + + if ($scope.createNew) { + $scope.editedPolicy = { + name: "", + enabled: true, + profiles: [], + conditions: [] + }; + } else { + for (var i=0 ; i < $scope.clientPolicies.policies.length ; i++) { + var currentPolicy = $scope.clientPolicies.policies[i]; + if (targetPolicyName === currentPolicy.name) { + $scope.editedPolicy = currentPolicy; + break; + } + } + + if ($scope.editedPolicy == null) { + console.log("Policy of name " + targetPolicyName + " not found"); + throw 'Policy not found'; + } + } + + // needs to be a function because when this controller runs, the permissions might not be loaded yet + $scope.isReadOnly = function() { + return !$scope.access.manageRealm; + } + + $scope.availableProfiles = []; + var allClientProfiles = clientProfiles.profiles; + if (clientProfiles.globalProfiles) { + allClientProfiles = allClientProfiles.concat(clientProfiles.globalProfiles); + } + for (var k=0 ; k 0)) { + if ($scope.rawContent.length > 1) $scope.isMultiRealm = true; + $scope.fileContent = $scope.rawContent[0]; + } else { + $scope.fileContent = $scope.rawContent; + } + + $scope.importing = true; + setOnOffSwitchDefaults(); + $scope.results = {}; + if (!$scope.hasResources()) { + $scope.nothingToImport(); + } + }; + + $scope.hasResults = function() { + return (Object.keys($scope.results).length > 0) && + ($scope.results.results !== undefined) && + ($scope.results.results.length > 0); + } + + $scope.resultsPage = function() { + if (!$scope.hasResults()) return {}; + return $scope.results.results.slice(startIndex(), endIndex()); + } + + function startIndex() { + return pageSize * $scope.currentPage; + } + + function endIndex() { + var length = $scope.results.results.length; + var endIndex = startIndex() + pageSize; + if (endIndex > length) endIndex = length; + return endIndex; + } + + function setOnOffSwitchDefaults() { + $scope.importUsers = $scope.hasArray('users'); + $scope.importGroups = $scope.hasArray('groups'); + $scope.importClients = $scope.hasArray('clients'); + $scope.importIdentityProviders = $scope.hasArray('identityProviders'); + $scope.importRealmRoles = $scope.hasRealmRoles(); + $scope.importClientRoles = $scope.hasClientRoles(); + } + + $scope.setFirstPage = function() { + $scope.currentPage = 0; + } + + $scope.setNextPage = function() { + $scope.currentPage++; + } + + $scope.setPreviousPage = function() { + $scope.currentPage--; + } + + $scope.hasNext = function() { + if (!$scope.hasResults()) return false; + var length = $scope.results.results.length; + //console.log('length=' + length); + var endIndex = startIndex() + pageSize; + //console.log('endIndex=' + endIndex); + return length > endIndex; + } + + $scope.hasPrevious = function() { + if (!$scope.hasResults()) return false; + return $scope.currentPage > 0; + } + + $scope.viewImportDetails = function() { + $modal.open({ + templateUrl: resourceUrl + '/partials/modal/view-object.html', + controller: 'ObjectModalCtrl', + resolve: { + object: function () { + return $scope.fileContent; + } + } + }) + }; + + $scope.hasArray = function(section) { + return ($scope.fileContent !== 'undefined') && + ($scope.fileContent.hasOwnProperty(section)) && + ($scope.fileContent[section] instanceof Array) && + ($scope.fileContent[section].length > 0); + } + + $scope.hasRealmRoles = function() { + return $scope.hasRoles() && + ($scope.fileContent.roles.hasOwnProperty('realm')) && + ($scope.fileContent.roles.realm instanceof Array) && + ($scope.fileContent.roles.realm.length > 0); + } + + $scope.hasRoles = function() { + return ($scope.fileContent !== 'undefined') && + ($scope.fileContent.hasOwnProperty('roles')) && + ($scope.fileContent.roles !== 'undefined'); + } + + $scope.hasClientRoles = function() { + return $scope.hasRoles() && + ($scope.fileContent.roles.hasOwnProperty('client')) && + (Object.keys($scope.fileContent.roles.client).length > 0); + } + + $scope.itemCount = function(section) { + if (!$scope.importing) return 0; + if ($scope.hasRealmRoles() && (section === 'roles.realm')) return $scope.fileContent.roles.realm.length; + if ($scope.hasClientRoles() && (section === 'roles.client')) return clientRolesCount($scope.fileContent.roles.client); + + if (!$scope.fileContent.hasOwnProperty(section)) return 0; + + return $scope.fileContent[section].length; + } + + clientRolesCount = function(clientRoles) { + var total = 0; + for (var clientName in clientRoles) { + total += clientRoles[clientName].length; + } + return total; + } + + $scope.hasResources = function() { + return ($scope.importUsers && $scope.hasArray('users')) || + ($scope.importGroups && $scope.hasArray('groups')) || + ($scope.importClients && $scope.hasArray('clients')) || + ($scope.importIdentityProviders && $scope.hasArray('identityProviders')) || + ($scope.importRealmRoles && $scope.hasRealmRoles()) || + ($scope.importClientRoles && $scope.hasClientRoles()); + } + + $scope.nothingToImport = function() { + Notifications.error('No resources specified to import.'); + } + + $scope.$watch('fileContent', function() { + if (!angular.equals($scope.fileContent, oldCopy)) { + $scope.changed = true; + } + setOnOffSwitchDefaults(); + }, true); + + $scope.successMessage = function() { + var message = $scope.results.added + ' records added. '; + if ($scope.ifResourceExists === 'SKIP') { + message += $scope.results.skipped + ' records skipped.' + } + if ($scope.ifResourceExists === 'OVERWRITE') { + message += $scope.results.overwritten + ' records overwritten.'; + } + return message; + } + + $scope.save = function() { + var json = angular.copy($scope.fileContent); + json.ifResourceExists = $scope.ifResourceExists; + if (!$scope.importUsers) delete json.users; + if (!$scope.importGroups) delete json.groups; + if (!$scope.importIdentityProviders) delete json.identityProviders; + if (!$scope.importClients) delete json.clients; + + if (json.hasOwnProperty('roles')) { + if (!$scope.importRealmRoles) delete json.roles.realm; + if (!$scope.importClientRoles) delete json.roles.client; + } + + var importFile = $resource(authUrl + '/admin/realms/' + realm.realm + '/partialImport'); + $scope.results = importFile.save(json, function() { + Notifications.success($scope.successMessage()); + }, function(error) { + if (error.data.errorMessage) { + Notifications.error(error.data.errorMessage); + } else { + Notifications.error('Unexpected error during import'); + } + }); + }; + + $scope.reset = function() { + $route.reload(); + } + +}); + +module.controller('RealmExportCtrl', function($scope, realm, $http, + $httpParamSerializer, Notifications, Dialog) { + $scope.realm = realm; + $scope.exportGroupsAndRoles = false; + $scope.exportClients = false; + + $scope.export = function() { + if ($scope.exportGroupsAndRoles || $scope.exportClients) { + Dialog.confirm('Export', 'This operation may make server unresponsive for a while.\n\nAre you sure you want to proceed?', download); + } else { + download(); + } + } + + function download() { + var exportUrl = authUrl + '/admin/realms/' + realm.realm + '/partial-export'; + var params = {}; + if ($scope.exportGroupsAndRoles) { + params['exportGroupsAndRoles'] = true; + } + if ($scope.exportClients) { + params['exportClients'] = true; + } + if (Object.keys(params).length > 0) { + exportUrl += '?' + $httpParamSerializer(params); + } + $http.post(exportUrl) + .then(function(response) { + var download = angular.fromJson(response.data); + download = angular.toJson(download, true); + saveAs(new Blob([download], { type: 'application/json' }), 'realm-export.json'); + }).catch(function() { + Notifications.error("Sorry, something went wrong."); + }); + } +}); diff --git a/keycloak-themes/base/admin/resources/js/controllers/roles.js b/keycloak-themes/base/admin/resources/js/controllers/roles.js new file mode 100644 index 0000000..bc24c57 --- /dev/null +++ b/keycloak-themes/base/admin/resources/js/controllers/roles.js @@ -0,0 +1,48 @@ +module.controller('RoleMembersCtrl', function($scope, realm, role, RoleMembership, Dialog, Notifications, $location, RealmRoleRemover) { + $scope.realm = realm; + $scope.page = 0; + $scope.role = role; + + $scope.query = { + realm: realm.realm, + role: role.name, + max : 5, + first : 0 + } + + $scope.remove = function() { + RealmRoleRemover.remove($scope.role, realm, Dialog, $location, Notifications); + }; + + $scope.firstPage = function() { + $scope.query.first = 0; + $scope.searchQuery(); + } + + $scope.previousPage = function() { + $scope.query.first -= parseInt($scope.query.max); + if ($scope.query.first < 0) { + $scope.query.first = 0; + } + $scope.searchQuery(); + } + + $scope.nextPage = function() { + $scope.query.first += parseInt($scope.query.max); + $scope.searchQuery(); + } + + $scope.searchQuery = function() { + console.log("query.search: " + $scope.query.search); + $scope.searchLoaded = false; + + $scope.users = RoleMembership.query($scope.query, function() { + console.log('search loaded'); + $scope.searchLoaded = true; + $scope.lastSearch = $scope.query.search; + }); + }; + + $scope.searchQuery(); + +}); diff --git a/keycloak-themes/base/admin/resources/js/controllers/users.js b/keycloak-themes/base/admin/resources/js/controllers/users.js new file mode 100644 index 0000000..515c3bb --- /dev/null +++ b/keycloak-themes/base/admin/resources/js/controllers/users.js @@ -0,0 +1,2042 @@ +module.controller('UserRoleMappingCtrl', function($scope, $http, $route, realm, user, client, Client, Notifications, RealmRoleMapping, + ClientRoleMapping, AvailableRealmRoleMapping, AvailableClientRoleMapping, + CompositeRealmRoleMapping, CompositeClientRoleMapping, $translate) { + $scope.realm = realm; + $scope.user = user; + $scope.selectedRealmRoles = []; + $scope.selectedRealmMappings = []; + $scope.realmMappings = []; + $scope.client = client; + $scope.clientRoles = []; + $scope.clientComposite = []; + $scope.selectedClientRoles = []; + $scope.selectedClientMappings = []; + $scope.clientMappings = []; + $scope.dummymodel = []; + $scope.selectedClient = null; + + + $scope.realmMappings = RealmRoleMapping.query({realm : realm.realm, userId : user.id}); + $scope.realmRoles = AvailableRealmRoleMapping.query({realm : realm.realm, userId : user.id}); + $scope.realmComposite = CompositeRealmRoleMapping.query({realm : realm.realm, userId : user.id}); + + $scope.addRealmRole = function() { + $scope.realmRolesToAdd = JSON.parse('[' + $scope.selectedRealmRoles + ']'); + $scope.selectedRealmRoles = []; + $http.post(authUrl + '/admin/realms/' + realm.realm + '/users/' + user.id + '/role-mappings/realm', + $scope.realmRolesToAdd).then(function() { + $scope.realmMappings = RealmRoleMapping.query({realm : realm.realm, userId : user.id}); + $scope.realmRoles = AvailableRealmRoleMapping.query({realm : realm.realm, userId : user.id}); + $scope.realmComposite = CompositeRealmRoleMapping.query({realm : realm.realm, userId : user.id}); + $scope.selectedRealmMappings = []; + $scope.selectRealmRoles = []; + if ($scope.selectedClient) { + console.log('load available'); + $scope.clientComposite = CompositeClientRoleMapping.query({realm : realm.realm, userId : user.id, client : $scope.selectedClient.id}); + $scope.clientRoles = AvailableClientRoleMapping.query({realm : realm.realm, userId : user.id, client : $scope.selectedClient.id}); + $scope.clientMappings = ClientRoleMapping.query({realm : realm.realm, userId : user.id, client : $scope.selectedClient.id}); + $scope.selectedClientRoles = []; + $scope.selectedClientMappings = []; + } + Notifications.success($translate.instant('user.roles.add.success')); + + }); + }; + + $scope.deleteRealmRole = function() { + $scope.realmRolesToRemove = JSON.parse('[' + $scope.selectedRealmMappings + ']'); + $http.delete(authUrl + '/admin/realms/' + realm.realm + '/users/' + user.id + '/role-mappings/realm', + {data : $scope.realmRolesToRemove, headers : {"content-type" : "application/json"}}).then(function() { + $scope.realmMappings = RealmRoleMapping.query({realm : realm.realm, userId : user.id}); + $scope.realmRoles = AvailableRealmRoleMapping.query({realm : realm.realm, userId : user.id}); + $scope.realmComposite = CompositeRealmRoleMapping.query({realm : realm.realm, userId : user.id}); + $scope.selectedRealmMappings = []; + $scope.selectRealmRoles = []; + if ($scope.selectedClient) { + console.log('load available'); + $scope.clientComposite = CompositeClientRoleMapping.query({realm : realm.realm, userId : user.id, client : $scope.selectedClient.id}); + $scope.clientRoles = AvailableClientRoleMapping.query({realm : realm.realm, userId : user.id, client : $scope.selectedClient.id}); + $scope.clientMappings = ClientRoleMapping.query({realm : realm.realm, userId : user.id, client : $scope.selectedClient.id}); + $scope.selectedClientRoles = []; + $scope.selectedClientMappings = []; + } + Notifications.success($translate.instant('user.roles.remove.success')); + }); + }; + + $scope.addClientRole = function() { + $scope.clientRolesToAdd = JSON.parse('[' + $scope.selectedClientRoles + ']'); + $http.post(authUrl + '/admin/realms/' + realm.realm + '/users/' + user.id + '/role-mappings/clients/' + $scope.selectedClient.id, + $scope.clientRolesToAdd).then(function() { + $scope.clientMappings = ClientRoleMapping.query({realm : realm.realm, userId : user.id, client : $scope.selectedClient.id}); + $scope.clientRoles = AvailableClientRoleMapping.query({realm : realm.realm, userId : user.id, client : $scope.selectedClient.id}); + $scope.clientComposite = CompositeClientRoleMapping.query({realm : realm.realm, userId : user.id, client : $scope.selectedClient.id}); + $scope.selectedClientRoles = []; + $scope.selectedClientMappings = []; + $scope.realmComposite = CompositeRealmRoleMapping.query({realm : realm.realm, userId : user.id}); + $scope.realmRoles = AvailableRealmRoleMapping.query({realm : realm.realm, userId : user.id}); + Notifications.success($translate.instant('user.roles.add.success')); + }); + }; + + $scope.deleteClientRole = function() { + $scope.clientRolesToRemove = JSON.parse('[' + $scope.selectedClientMappings + ']'); + $http.delete(authUrl + '/admin/realms/' + realm.realm + '/users/' + user.id + '/role-mappings/clients/' + $scope.selectedClient.id, + {data : $scope.clientRolesToRemove, headers : {"content-type" : "application/json"}}).then(function() { + $scope.clientMappings = ClientRoleMapping.query({realm : realm.realm, userId : user.id, client : $scope.selectedClient.id}); + $scope.clientRoles = AvailableClientRoleMapping.query({realm : realm.realm, userId : user.id, client : $scope.selectedClient.id}); + $scope.clientComposite = CompositeClientRoleMapping.query({realm : realm.realm, userId : user.id, client : $scope.selectedClient.id}); + $scope.selectedClientRoles = []; + $scope.selectedClientMappings = []; + $scope.realmComposite = CompositeRealmRoleMapping.query({realm : realm.realm, userId : user.id}); + $scope.realmRoles = AvailableRealmRoleMapping.query({realm : realm.realm, userId : user.id}); + Notifications.success($translate.instant('user.roles.remove.success')); + }); + }; + + $scope.changeClient = function(client) { + console.log("selected client: ", client); + if (!client || !client.id) { + $scope.selectedClient = null; + return; + } else { + $scope.selectedClient = client; + } + if ($scope.selectedClient) { + console.log('load available'); + $scope.clientComposite = CompositeClientRoleMapping.query({realm : realm.realm, userId : user.id, client : $scope.selectedClient.id}); + $scope.clientRoles = AvailableClientRoleMapping.query({realm : realm.realm, userId : user.id, client : $scope.selectedClient.id}); + $scope.clientMappings = ClientRoleMapping.query({realm : realm.realm, userId : user.id, client : $scope.selectedClient.id}); + } else { + $scope.clientRoles = null; + $scope.clientMappings = null; + $scope.clientComposite = null; + } + $scope.selectedClientRoles = []; + $scope.selectedClientMappings = []; + }; + + clientSelectControl($scope, $route.current.params.realm, Client); +}); + +module.controller('UserSessionsCtrl', function($scope, realm, user, sessions, UserSessions, UserLogout, UserSessionLogout, Notifications, $translate) { + $scope.realm = realm; + $scope.user = user; + $scope.sessions = sessions; + + $scope.logoutAll = function() { + UserLogout.save({realm : realm.realm, user: user.id}, function () { + Notifications.success($translate.instant('user.logout.all.success')); + UserSessions.query({realm: realm.realm, user: user.id}, function(updated) { + $scope.sessions = updated; + }) + }); + }; + + $scope.logoutSession = function(sessionId) { + console.log('here in logoutSession'); + UserSessionLogout.delete({realm : realm.realm, session: sessionId}, function() { + UserSessions.query({realm: realm.realm, user: user.id}, function(updated) { + $scope.sessions = updated; + Notifications.success($translate.instant('user.logout.session.success')); + }) + }); + } +}); + +module.controller('UserFederatedIdentityCtrl', function($scope, $location, realm, user, federatedIdentities, UserFederatedIdentity, Notifications, Dialog, $translate) { + $scope.realm = realm; + $scope.user = user; + $scope.federatedIdentities = federatedIdentities; + + $scope.hasAnyProvidersToCreate = function() { + return realm.identityProviders.length - $scope.federatedIdentities.length > 0; + } + + $scope.removeProviderLink = function(providerLink) { + + console.log("Removing provider link: " + providerLink.identityProvider); + + Dialog.confirmWithButtonText( + $translate.instant('user.fedid.link.remove.confirm.title', {name: providerLink.identityProvider}), + $translate.instant('user.fedid.link.remove.confirm.message', {name: providerLink.identityProvider}), + $translate.instant('dialogs.delete.confirm'), + function() { + UserFederatedIdentity.remove({ realm: realm.realm, user: user.id, provider: providerLink.identityProvider }, function() { + Notifications.success($translate.instant('user.fedid.link.remove.success')); + var indexToRemove = $scope.federatedIdentities.indexOf(providerLink); + $scope.federatedIdentities.splice(indexToRemove, 1); + }); + } + ); + } +}); + +module.controller('UserFederatedIdentityAddCtrl', function($scope, $location, realm, user, federatedIdentities, UserFederatedIdentity, Notifications, $translate) { + $scope.realm = realm; + $scope.user = user; + $scope.federatedIdentity = {}; + + var getAvailableProvidersToCreate = function() { + var realmProviders = []; + for (var i=0 ; i 0) { + $scope.previousPage(); + } + + Notifications.success($translate.instant('user.remove.success')); + }, function() { + Notifications.error($translate.instant('user.remove.error')); + }); + } + ); + }; +}); + + +module.controller('UserTabCtrl', function($scope, $location, Dialog, Notifications, Current) { + $scope.removeUser = function() { + Dialog.confirmDelete($scope.user.id, 'user', function() { + $scope.user.$remove({ + realm : Current.realm.realm, + userId : $scope.user.id + }, function() { + $location.url("/realms/" + Current.realm.realm + "/users"); + Notifications.success($translate.instant('user.remove.success')); + }, function() { + Notifications.error($translate.instant('user.remove.error')); + }); + }); + }; +}); + +function loadUserStorageLink(realm, user, console, Components, UserStorageOperations, $scope, $location) { + if(user.federationLink) { + console.log("federationLink is not null. It is " + user.federationLink); + + if ($scope.access.viewRealm) { + Components.get({realm: realm.realm, componentId: user.federationLink}, function (link) { + $scope.federationLinkName = link.name; + $scope.federationLink = "#/realms/" + realm.realm + "/user-storage/providers/" + link.providerId + "/" + link.id; + }); + } else { + // KEYCLOAK-4328 + UserStorageOperations.simpleName.get({realm: realm.realm, componentId: user.federationLink}, function (link) { + $scope.federationLinkName = link.name; + $scope.federationLink = $location.absUrl(); + }) + } + + } else { + console.log("federationLink is null"); + } + + if(user.origin) { + if ($scope.access.viewRealm) { + Components.get({realm: realm.realm, componentId: user.origin}, function (link) { + $scope.originName = link.name; + $scope.originLink = "#/realms/" + realm.realm + "/user-storage/providers/" + link.providerId + "/" + link.id; + }) + } + else { + // KEYCLOAK-4328 + UserStorageOperations.simpleName.get({realm: realm.realm, componentId: user.origin}, function (link) { + $scope.originName = link.name; + $scope.originLink = $location.absUrl(); + }) + } + } else { + console.log("origin is null"); + } +}; + +module.controller('UserDetailCtrl', function($scope, realm, user, BruteForceUser, User, + Components, + UserImpersonation, RequiredActions, + UserStorageOperations, + $location, $http, Dialog, Notifications, $translate, $route, Groups) { + $scope.realm = realm; + $scope.create = !user.id; + $scope.editUsername = $scope.create || $scope.realm.editUsernameAllowed; + $scope.emailAsUsername = $scope.realm.registrationEmailAsUsername; + $scope.groupSearch = { selectedGroup : null }; + + if ($scope.create) { + $scope.user = { enabled: true, attributes: {}, groups: [] } + } else { + if (!user.attributes) { + user.attributes = {} + } + convertAttributeValuesToString(user); + + + $scope.user = angular.copy(user); + $scope.impersonate = function() { + UserImpersonation.save({realm : realm.realm, user: $scope.user.id}, function (data) { + if (data.sameRealm) { + window.location = data.redirect; + } else { + window.open(data.redirect, "_blank"); + } + }); + }; + + loadUserStorageLink(realm, user, console, Components, UserStorageOperations, $scope, $location); + + console.log('realm brute force? ' + realm.bruteForceProtected) + $scope.temporarilyDisabled = false; + var isDisabled = function () { + BruteForceUser.get({realm: realm.realm, userId: user.id}, function(data) { + console.log('here in isDisabled ' + data.disabled); + $scope.temporarilyDisabled = data.disabled; + }); + }; + + console.log("check if disabled"); + isDisabled(); + + $scope.unlockUser = function() { + BruteForceUser.delete({realm: realm.realm, userId: user.id}, function(data) { + isDisabled(); + }); + } + } + + $scope.changed = false; // $scope.create; + if (user.requiredActions) { + for (var i = 0; i < user.requiredActions.length; i++) { + console.log("user require action: " + user.requiredActions[i]); + } + } + // ID - Name map for required actions. IDs are enum names. + RequiredActions.query({realm: realm.realm}, function(data) { + $scope.userReqActionList = []; + for (var i = 0; i < data.length; i++) { + console.log("listed required action: " + data[i].name); + if (data[i].enabled) { + var item = data[i]; + $scope.userReqActionList.push(item); + } + } + console.log("---------------------"); + console.log("ng-model: user.requiredActions=" + JSON.stringify($scope.user.requiredActions)); + console.log("---------------------"); + console.log("ng-repeat: userReqActionList=" + JSON.stringify($scope.userReqActionList)); + console.log("---------------------"); + }); + $scope.$watch('user', function() { + if (!angular.equals($scope.user, user)) { + $scope.changed = true; + } + }, true); + + $scope.save = function() { + convertAttributeValuesToLists(); + + if ($scope.create) { + pushSelectedGroupsToUser(); + + User.save({ + realm: realm.realm + }, $scope.user, function (data, headers) { + $scope.changed = false; + convertAttributeValuesToString($scope.user); + user = angular.copy($scope.user); + var l = headers().location; + + console.debug("Location == " + l); + + var id = l.substring(l.lastIndexOf("/") + 1); + + + $location.url("/realms/" + realm.realm + "/users/" + id); + Notifications.success($translate.instant('user.create.success')); + }); + } else { + User.update({ + realm: realm.realm, + userId: $scope.user.id + }, $scope.user, function () { + Notifications.success($translate.instant('user.edit.success')); + $route.reload(); + }); + } + }; + + function convertAttributeValuesToLists() { + var attrs = $scope.user.attributes; + for (var attribute in attrs) { + if (typeof attrs[attribute] === "string") { + var attrVals = attrs[attribute].split("##"); + attrs[attribute] = attrVals; + } + } + } + + function convertAttributeValuesToString(user) { + var attrs = user.attributes; + for (var attribute in attrs) { + if (typeof attrs[attribute] === "object") { + var attrVals = attrs[attribute].join("##"); + attrs[attribute] = attrVals; + } + } + } + + function pushSelectedGroupsToUser() { + var groups = $scope.user.groups; + if ($scope.selectedGroups) { + for (i = 0; i < $scope.selectedGroups.length; i++) { + var groupPath = $scope.selectedGroups[i].path; + if (!groups.includes(groupPath)) { + groups.push(groupPath); + } + } + } + } + + function bfs(tree, collection) { + if (!tree["subGroups"] || tree["subGroups"].length === 0) return; + for (var i=0; i < tree["subGroups"].length; i++) { + var child = tree["subGroups"][i] + collection.push(child); + bfs(child, collection); + } + return; + } + + function flattenGroups(groups) { + var flattenedGroups = []; + if (!groups || groups.length === 0) return groups; + for (var i=0; i < groups.length; i++) { + flattenedGroups.push(groups[i]); + bfs(groups[i], flattenedGroups); + } + + return flattenedGroups; + } + + /** + * Only keep groups that : + * - include the search term in their path + * - are not already selected + */ + function filterSearchedGroups(groups, term, selectedGroups) { + if (!groups || groups.length === 0) return groups; + if (!selectedGroups) selectedGroups = []; + + return groups.filter(group => group.path?.includes(term) && !selectedGroups.some(selGroup => selGroup.id === group.id)); + } + + $scope.reset = function() { + $scope.user = angular.copy(user); + $scope.changed = false; + }; + + $scope.cancel = function() { + $location.url("/realms/" + realm.realm + "/users"); + }; + + $scope.addAttribute = function() { + $scope.user.attributes[$scope.newAttribute.key] = $scope.newAttribute.value; + delete $scope.newAttribute; + } + + $scope.removeAttribute = function(key) { + delete $scope.user.attributes[key]; + } + + $scope.groupsUiSelect = { + minimumInputLength: 1, + delay: 500, + allowClear: true, + query: function (query) { + var data = {results: []}; + if ('' == query.term.trim()) { + query.callback(data); + return; + } + $scope.query = { + realm: realm.realm, + search: query.term.trim(), + max : 20, + first : 0 + }; + Groups.query($scope.query, function(response) { + data.results = filterSearchedGroups(flattenGroups(response), query.term.trim(), $scope.selectedGroups); + query.callback(data); + }); + }, + formatResult: function(object, container, query) { + object.text = object.path; + return object.path; + } + }; + + $scope.removeGroup = function(list, group) { + for (i = 0; i < angular.copy(list).length; i++) { + if (group.id == list[i].id) { + list.splice(i, 1); + } + } + } + + $scope.selectGroup = function(group) { + if (!group || !group.id) { + return; + } + + $scope.groupSearch.selectedGroup = group; + + if (!$scope.selectedGroups) { + $scope.selectedGroups = []; + } + + for (i = 0; i < $scope.selectedGroups.length; i++) { + if ($scope.selectedGroups[i].id == group.id) { + return; + } + } + + $scope.selectedGroups.push(group); + $scope.groupSearch.selectedGroup = null; + } + + $scope.clearGroupSelection = function() { + $scope.groupSearch.selectedGroup = null; + $('#groups').val(null).trigger('change.select2'); + } +}); + +module.controller('UserCredentialsCtrl', function($scope, realm, user, $route, $location, RequiredActions, User, UserExecuteActionsEmail, + UserCredentials, Notifications, Dialog, TimeUnit2, Components, UserStorageOperations, $modal, $translate) { + console.log('UserCredentialsCtrl'); + + $scope.hasPassword = false; + + loadCredentials(); + + loadUserStorageLink(realm, user, console, Components, UserStorageOperations, $scope, $location); + + $scope.getUserStorageProviderName = function() { + return user.federationLink ? $scope.federationLinkName : $scope.originName; + } + + $scope.getUserStorageProviderLink = function() { + return user.federationLink ? $scope.federationLink : $scope.originLink; + } + + $scope.updateCredentialLabel = function(credential) { + UserCredentials.updateCredentialLabel({ realm: realm.realm, userId: user.id, credentialId: credential.id }, { + 'id': credential.id, + 'userLabel': credential.userLabel ? credential.userLabel : "", + // We JSONify the credential data + 'credentialData': JSON.stringify(credential.credentialData) + }, function() { + Notifications.success($translate.instant('user.credential.update.success')); + }, function(err) { + Notifications.error($translate.instant('user.credential.update.error')); + console.log(err); + }); + } + + $scope.deleteCredential = function(credential) { + Dialog.confirmWithButtonText( + $translate.instant('user.credential.remove.confirm.title', {name: credential.id}), + $translate.instant('user.credential.remove.confirm.message', {name: credential.id}), + $translate.instant('dialogs.delete.confirm'), + function() { + UserCredentials.deleteCredential({ realm: realm.realm, userId: user.id, credentialId: credential.id }, null, function() { + Notifications.success($translate.instant('user.credential.remove.success')); + $route.reload(); + }, function(err) { + Notifications.error($translate.instant('user.credential.remove.error')); + console.log(err); + }) + } + ); + } + + $scope.moveUp = function(credentials, index) { + // Safety first + if (index == 0) { + return; + } else if (index == 1) { + UserCredentials.moveToFirst( + { + realm: realm.realm, + userId: user.id, + credentialId: credentials[index].id + }, + function () { + $route.reload(); + }, + function (err) { + Notifications.error($translate.instant('user.credential.move-top.error')); + console.log(err); + }); + + } else { + UserCredentials.moveCredentialAfter( + { + realm: realm.realm, + userId: user.id, + credentialId: credentials[index].id, + newPreviousCredentialId: credentials[index - 2].id + }, + function () { + $route.reload(); + }, + function (err) { + Notifications.error($translate.instant('user.credential.move-up.error')); + console.log(err); + }); + } + } + + $scope.moveDown = function(credentials, index) { + // Safety first + if (index == credentials.length - 1) { + return; + } + UserCredentials.moveCredentialAfter( + { + realm: realm.realm, + userId: user.id, + credentialId: credentials[index].id, + newPreviousCredentialId: credentials[index + 1].id + }, + function() { + $route.reload(); + }, + function(err) { + Notifications.error($translate.instant('user.credential.move-down.error')); + console.log(err); + }); + } + + $scope.showData = function(credentialData) { + $modal.open({ + templateUrl: resourceUrl + '/partials/modal/user-credential-data.html', + controller: 'UserCredentialsDataModalCtrl', + resolve: { + credentialData: function () { + return credentialData; + } + } + }) + } + + $scope.realm = realm; + $scope.user = angular.copy(user); + $scope.temporaryPassword = true; + + $scope.isTotp = false; + if(!!user.totp){ + $scope.isTotp = user.totp; + } + // ID - Name map for required actions. IDs are enum names. + RequiredActions.query({realm: realm.realm}, function(data) { + $scope.userReqActionList = []; + for (var i = 0; i < data.length; i++) { + console.log("listed required action: " + data[i].name); + if (data[i].enabled) { + var item = data[i]; + $scope.userReqActionList.push(item); + } + } + + }); + + function loadCredentials() { + UserCredentials.getCredentials({ realm: realm.realm, userId: user.id }, null, function(credentials) { + $scope.credentials = credentials.map(function(c) { + // We de-JSONify the credential data + if (c.credentialData) { + c.credentialData = JSON.parse(c.credentialData); + } + if (c.type == 'password') { + $scope.hasPassword = true; + } + return c; + }); + }, function(err) { + Notifications.error($translate.instant('user.credential.fetch.error')); + console.log(err); + }); + + UserCredentials.getConfiguredUserStorageCredentialTypes({ realm: realm.realm, userId: user.id }, null, function(userStorageCredentialTypes) { + $scope.userStorageCredentialTypes = userStorageCredentialTypes; + $scope.hasPassword = $scope.hasPassword || userStorageCredentialTypes.lastIndexOf("password") > -1; + }, function(err) { + Notifications.error($translate.instant('user.credential.storage.fetch.error')); + console.log(err); + }); + } + + $scope.resetPassword = function() { + // hit enter without entering both fields - ignore + if (!$scope.passwordAndConfirmPasswordEntered()) return; + + if ($scope.pwdChange) { + if ($scope.password != $scope.confirmPassword) { + Notifications.error($translate.instant('user.password.error.not-matching')); + return; + } + } + + var msgTitle = ($scope.hasPassword ? $translate.instant('user.password.reset.confirm.title') : $translate.instant('user.password.set.confirm.title')); + var msg = ($scope.hasPassword ? $translate.instant('user.password.reset.confirm.message') : $translate.instant('user.password.set.confirm.message')); + var msgSuccess = ($scope.hasPassword ? $translate.instant('user.password.reset.success') : $translate.instant('user.password.set.success')); + + Dialog.confirm(msgTitle, msg, function() { + UserCredentials.resetPassword({ realm: realm.realm, userId: user.id }, { type : "password", value : $scope.password, temporary: $scope.temporaryPassword }, function() { + Notifications.success(msgSuccess); + $scope.password = null; + $scope.confirmPassword = null; + $route.reload(); + }); + }, function() { + $scope.password = null; + $scope.confirmPassword = null; + }); + }; + + $scope.passwordAndConfirmPasswordEntered = function() { + return $scope.password && $scope.confirmPassword; + } + + $scope.disableCredentialTypes = function() { + Dialog.confirm( + $translate.instant('user.credential.disable.confirm.title'), + $translate.instant('user.credential.disable.confirm.message'), + function() { + UserCredentials.disableCredentialTypes({ realm: realm.realm, userId: user.id }, $scope.disableableCredentialTypes, function() { + $route.reload(); + Notifications.success($translate.instant('user.credential.disable.confirm.success')); + }, function() { + Notifications.error($translate.instant('user.credential.disable.confirm.error')); + }); + }); + }; + + $scope.emailActions = []; + $scope.emailActionsTimeout = TimeUnit2.asUnit(realm.actionTokenGeneratedByAdminLifespan); + $scope.disableableCredentialTypes = []; + + $scope.sendExecuteActionsEmail = function() { + if ($scope.changed) { + Dialog.message($translate.instant('user.actions-email.send.pending-changes.title'), + $translate.instant('user.actions-email.send.pending-changes.message')); + return; + } + Dialog.confirm( + $translate.instant('user.actions-email.send.confirm.title'), + $translate.instant('user.actions-email.send.confirm.message'), + function() { + UserExecuteActionsEmail.update({ realm: realm.realm, userId: user.id, lifespan: $scope.emailActionsTimeout.toSeconds() }, $scope.emailActions, function() { + Notifications.success($translate.instant('user.actions-email.send.confirm.success')); + }, function() { + Notifications.error($translate.instant('user.actions-email.send.confirm.error')); + }); + }); + }; + + + + $scope.$watch('user', function() { + if (!angular.equals($scope.user, user)) { + $scope.userChange = true; + } else { + $scope.userChange = false; + } + }, true); + + $scope.$watch('password', function() { + if (!!$scope.password){ + $scope.pwdChange = true; + } else { + $scope.pwdChange = false; + } + }, true); + + $scope.reset = function() { + $scope.password = ""; + $scope.confirmPassword = ""; + + $scope.user = angular.copy(user); + + $scope.isTotp = false; + if(!!user.totp){ + $scope.isTotp = user.totp; + } + + $scope.pwdChange = false; + $scope.userChange = false; + }; +}); + +module.controller('UserCredentialsDataModalCtrl', function($scope, credentialData) { + $scope.credentialData = credentialData; + + $scope.keys = function(object) { + return object ? Object.keys(object) : []; + } +}); + +module.controller('UserFederationCtrl', function($scope, $location, $route, realm, serverInfo, Components, Notifications, Dialog, $translate) { + console.log('UserFederationCtrl ++++****'); + $scope.realm = realm; + $scope.providers = serverInfo.componentTypes['org.keycloak.storage.UserStorageProvider']; + $scope.instancesLoaded = false; + + if (!$scope.providers) $scope.providers = []; + + $scope.addProvider = function(provider) { + console.log('Add provider: ' + provider.id); + $location.url("/create/user-storage/" + realm.realm + "/providers/" + provider.id); + }; + + $scope.getInstanceLink = function(instance) { + return "/realms/" + realm.realm + "/user-storage/providers/" + instance.providerId + "/" + instance.id; + } + + $scope.getInstanceName = function(instance) { + return instance.name; + } + $scope.getInstanceProvider = function(instance) { + return instance.providerId; + } + + $scope.isProviderEnabled = function(instance) { + return !instance.config['enabled'] || instance.config['enabled'][0] == 'true'; + } + + $scope.getInstancePriority = function(instance) { + if (!instance.config['priority']) { + console.log('getInstancePriority is undefined'); + return -1; + } + return +instance.config['priority'][0]; + } + + Components.query({realm: realm.realm, + parent: realm.id, + type: 'org.keycloak.storage.UserStorageProvider' + }, function(data) { + $scope.instances = data; + $scope.instancesLoaded = true; + }); + + $scope.removeInstance = function(instance) { + Dialog.confirmWithButtonText( + $translate.instant('user.storage.remove.confirm.title', {name: instance.name}), + $translate.instant('user.storage.remove.confirm.message', {name: instance.name}), + $translate.instant('dialogs.delete.confirm'), + function() { + Components.remove({ + realm : realm.realm, + componentId : instance.id + }, function() { + $route.reload(); + Notifications.success($translate.instant('user.storage.remove.success')); + }); + } + ); + }; +}); + +module.controller('GenericUserStorageCtrl', function($scope, $location, Notifications, $route, Dialog, realm, + serverInfo, instance, providerId, Components, UserStorageOperations, $translate) { + console.log('GenericUserStorageCtrl'); + console.log('providerId: ' + providerId); + $scope.create = !instance.providerId; + console.log('create: ' + $scope.create); + var providers = serverInfo.componentTypes['org.keycloak.storage.UserStorageProvider']; + console.log('providers length ' + providers.length); + var providerFactory = null; + for (var i = 0; i < providers.length; i++) { + var p = providers[i]; + console.log('provider: ' + p.id); + if (p.id == providerId) { + $scope.providerFactory = p; + providerFactory = p; + break; + } + + } + $scope.showSync = false; + $scope.changed = false; + + console.log("providerFactory: " + providerFactory.id); + + function initUserStorageSettings() { + if ($scope.create) { + $scope.changed = true; + instance.name = providerFactory.id; + instance.providerId = providerFactory.id; + instance.providerType = 'org.keycloak.storage.UserStorageProvider'; + instance.parentId = realm.id; + instance.config = { + + }; + instance.config['priority'] = ["0"]; + instance.config['enabled'] = ["true"]; + + $scope.fullSyncEnabled = false; + $scope.changedSyncEnabled = false; + if (providerFactory.metadata.synchronizable) { + instance.config['fullSyncPeriod'] = ['-1']; + instance.config['changedSyncPeriod'] = ['-1']; + + } + instance.config['cachePolicy'] = ['DEFAULT']; + instance.config['evictionDay'] = ['']; + instance.config['evictionHour'] = ['']; + instance.config['evictionMinute'] = ['']; + instance.config['maxLifespan'] = ['']; + if (providerFactory.properties) { + + for (var i = 0; i < providerFactory.properties.length; i++) { + var configProperty = providerFactory.properties[i]; + if (configProperty.defaultValue) { + instance.config[configProperty.name] = [configProperty.defaultValue]; + } else { + instance.config[configProperty.name] = ['']; + } + + } + } + + } else { + $scope.changed = false; + $scope.fullSyncEnabled = (instance.config['fullSyncPeriod'] && instance.config['fullSyncPeriod'][0] > 0); + $scope.changedSyncEnabled = (instance.config['changedSyncPeriod'] && instance.config['changedSyncPeriod'][0]> 0); + if (providerFactory.metadata.synchronizable) { + if (!instance.config['fullSyncPeriod']) { + console.log('setting to -1'); + instance.config['fullSyncPeriod'] = ['-1']; + + } + if (!instance.config['changedSyncPeriod']) { + console.log('setting to -1'); + instance.config['changedSyncPeriod'] = ['-1']; + + } + } + if (!instance.config['enabled']) { + instance.config['enabled'] = ['true']; + } + if (!instance.config['cachePolicy']) { + instance.config['cachePolicy'] = ['DEFAULT']; + + } + if (!instance.config['evictionDay']) { + instance.config['evictionDay'] = ['']; + + } + if (!instance.config['evictionHour']) { + instance.config['evictionHour'] = ['']; + + } + if (!instance.config['evictionMinute']) { + instance.config['evictionMinute'] = ['']; + + } + if (!instance.config['maxLifespan']) { + instance.config['maxLifespan'] = ['']; + + } + if (!instance.config['priority']) { + instance.config['priority'] = ['0']; + } + + if (providerFactory.properties) { + for (var i = 0; i < providerFactory.properties.length; i++) { + var configProperty = providerFactory.properties[i]; + if (!instance.config[configProperty.name]) { + instance.config[configProperty.name] = ['']; + } + } + } + + } + if (providerFactory.metadata.synchronizable) { + if (instance.config && instance.config['importEnabled']) { + $scope.showSync = instance.config['importEnabled'][0] == 'true'; + } else { + $scope.showSync = true; + } + } + + } + + initUserStorageSettings(); + $scope.instance = angular.copy(instance); + $scope.realm = realm; + + $scope.$watch('instance', function() { + if (!angular.equals($scope.instance, instance)) { + $scope.changed = true; + } + + }, true); + + $scope.$watch('fullSyncEnabled', function(newVal, oldVal) { + if (oldVal == newVal) { + return; + } + + $scope.instance.config['fullSyncPeriod'][0] = $scope.fullSyncEnabled ? "604800" : "-1"; + $scope.changed = true; + }); + + $scope.$watch('changedSyncEnabled', function(newVal, oldVal) { + if (oldVal == newVal) { + return; + } + + $scope.instance.config['changedSyncPeriod'][0] = $scope.changedSyncEnabled ? "86400" : "-1"; + $scope.changed = true; + }); + + + $scope.save = function() { + console.log('save provider'); + $scope.changed = false; + if ($scope.create) { + console.log('saving new provider'); + Components.save({realm: realm.realm}, $scope.instance, function (data, headers) { + var l = headers().location; + var id = l.substring(l.lastIndexOf("/") + 1); + + $location.url("/realms/" + realm.realm + "/user-storage/providers/" + $scope.instance.providerId + "/" + id); + Notifications.success($translate.instant('user.storage.create.success')); + }); + } else { + console.log('update existing provider'); + Components.update({realm: realm.realm, + componentId: instance.id + }, + $scope.instance, function () { + $route.reload(); + Notifications.success($translate.instant('user.storage.edit.success')); + }); + } + }; + + $scope.reset = function() { + //initUserStorageSettings(); + //$scope.instance = angular.copy(instance); + $route.reload(); + }; + + $scope.cancel = function() { + console.log('cancel'); + if ($scope.create) { + $location.url("/realms/" + realm.realm + "/user-federation"); + } else { + $route.reload(); + } + }; + + $scope.triggerFullSync = function() { + console.log('GenericCtrl: triggerFullSync'); + triggerSync('triggerFullSync'); + } + + $scope.triggerChangedUsersSync = function() { + console.log('GenericCtrl: triggerChangedUsersSync'); + triggerSync('triggerChangedUsersSync'); + } + + function triggerSync(action) { + UserStorageOperations.sync.save({ action: action, realm: $scope.realm.realm, componentId: $scope.instance.id }, {}, function(syncResult) { + $route.reload(); + Notifications.success($translate.instant('user.storage.sync.success',{status: syncResult.status})); + }, function() { + $route.reload(); + Notifications.error($translate.instant('user.storage.sync.error')); + }); + } + $scope.removeImportedUsers = function() { + UserStorageOperations.removeImportedUsers.save({ realm: $scope.realm.realm, componentId: $scope.instance.id }, {}, function(syncResult) { + $route.reload(); + Notifications.success($translate.instant('user.storage.remove-users.success')); + }, function() { + $route.reload(); + Notifications.error($translate.instant('user.storage.remove-users.error')); + }); + }; + $scope.unlinkUsers = function() { + UserStorageOperations.unlinkUsers.save({ realm: $scope.realm.realm, componentId: $scope.instance.id }, {}, function(syncResult) { + $route.reload(); + Notifications.success($translate.instant('user.storage.unlink.success')); + }, function() { + $route.reload(); + Notifications.error($translate.instant('user.storage.unlink.error')); + }); + }; + +}); + + +function removeGroupMember(groups, member) { + for (var j = 0; j < groups.length; j++) { + //console.log('checking: ' + groups[j].path); + if (member.path == groups[j].path) { + groups.splice(j, 1); + break; + } + if (groups[j].subGroups && groups[j].subGroups.length > 0) { + //console.log('going into subgroups'); + removeGroupMember(groups[j].subGroups, member); + } + } +} + +module.controller('UserGroupMembershipCtrl', function($scope, $q, realm, user, UserGroupMembership, UserGroupMembershipCount, UserGroupMapping, Notifications, Groups, GroupsCount, ComponentUtils, $translate) { + $scope.realm = realm; + $scope.user = user; + $scope.groupList = []; + $scope.allGroupMemberships = []; + $scope.groupMemberships = []; + $scope.tree = []; + $scope.membershipTree = []; + + $scope.searchCriteria = ''; + $scope.searchCriteriaMembership = ''; + $scope.currentPage = 1; + $scope.currentMembershipPage = 1; + $scope.currentPageInput = $scope.currentPage; + $scope.currentMembershipPageInput = $scope.currentMembershipPage; + $scope.pageSize = 20; + $scope.numberOfPages = 1; + $scope.numberOfMembershipPages = 1; + + var refreshCompleteUserGroupMembership = function() { + var queryParams = { + realm : realm.realm, + userId: user.id + }; + + var promiseGetCompleteUserGroupMembership = $q.defer(); + UserGroupMembership.query(queryParams, function(entry) { + promiseGetCompleteUserGroupMembership.resolve(entry); + }, function() { + promiseGetCompleteUserGroupMembership.reject($translate.instant('user.groups.fetch.all.error', {params: queryParams})); + }); + promiseGetCompleteUserGroupMembership.promise.then(function(groups) { + for (var i = 0; i < groups.length; i++) { + $scope.allGroupMemberships.push(groups[i]); + $scope.getGroupClass(groups[i]); + } + }, function (failed) { + Notifications.error(failed); + }); + return promiseGetCompleteUserGroupMembership.promise; + }; + + var refreshUserGroupMembership = function (search) { + $scope.currentMembershipPageInput = $scope.currentMembershipPage; + var first = ($scope.currentMembershipPage * $scope.pageSize) - $scope.pageSize; + var queryParams = { + realm : realm.realm, + userId: user.id, + first : first, + max : $scope.pageSize + }; + + var countParams = { + realm : realm.realm, + userId: user.id + }; + + var isSearch = function() { + return angular.isDefined(search) && search !== ''; + }; + + if (isSearch()) { + queryParams.search = search; + countParams.search = search; + } + + var promiseGetUserGroupMembership = $q.defer(); + UserGroupMembership.query(queryParams, function(entry) { + promiseGetUserGroupMembership.resolve(entry); + }, function() { + promiseGetUserGroupMembership.reject($translate.instant('user.groups.fetch.error', {params: queryParams})); + }); + + var promiseMembershipCount = $q.defer(); + + promiseGetUserGroupMembership.promise.then(function(groups) { + $scope.groupMemberships = groups; + UserGroupMembershipCount.query(countParams, function(entry) { + promiseMembershipCount.resolve(entry); + }, function() { + promiseMembershipCount.reject($translate.instant('user.groups.fetch.error', {params: countParams})); + }); + promiseMembershipCount.promise.then(function(membershipEntry) { + if(angular.isDefined(membershipEntry.count) && membershipEntry.count > $scope.pageSize) { + $scope.numberOfMembershipPages = Math.ceil(membershipEntry.count/$scope.pageSize); + } else { + $scope.numberOfMembershipPages = 1; + } + if (parseInt($scope.currentMembershipPage, 10) > $scope.numberOfMembershipPages) { + $scope.currentMembershipPage = $scope.numberOfMembershipPages; + } + }, function (failed) { + Notifications.error(failed); + }); + }, function (failed) { + Notifications.error(failed); + }); + + return promiseMembershipCount.promise; + }; + + var refreshAvailableGroups = function (search) { + $scope.currentPageInput = $scope.currentPage; + var first = ($scope.currentPage * $scope.pageSize) - $scope.pageSize; + var queryParams = { + realm : realm.realm, + first : first, + max : $scope.pageSize + }; + + var countParams = { + realm : realm.realm, + top : 'true' + }; + + if(angular.isDefined(search) && search !== '') { + queryParams.search = search; + countParams.search = search; + } + + var promiseGetGroups = $q.defer(); + Groups.query(queryParams, function(entry) { + promiseGetGroups.resolve(entry); + }, function() { + promiseGetGroups.reject($translate.instant('user.groups.fetch.error', {params: queryParams})); + }); + + var promiseCount = $q.defer(); + + promiseGetGroups.promise.then(function(groups) { + $scope.groupList = ComponentUtils.sortGroups('name', groups); + GroupsCount.query(countParams, function(entry) { + promiseCount.resolve(entry); + }, function() { + promiseCount.reject($translate.instant('user.groups.fetch.error', {params: countParams})); + }); + promiseCount.promise.then(function(entry) { + if(angular.isDefined(entry.count) && entry.count > $scope.pageSize) { + $scope.numberOfPages = Math.ceil(entry.count/$scope.pageSize); + } else { + $scope.numberOfPages = 1; + } + }, function (failed) { + Notifications.error(failed); + }); + }, function (failed) { + Notifications.error(failed); + }); + + return promiseCount.promise; + }; + + $scope.clearSearchMembership = function() { + $scope.searchCriteriaMembership = ''; + if (parseInt($scope.currentMembershipPage, 10) === 1) { + refreshUserGroupMembership(); + } else { + $scope.currentMembershipPage = 1; + } + }; + + $scope.searchGroupMembership = function() { + if (parseInt($scope.currentMembershipPage, 10) === 1) { + refreshUserGroupMembership($scope.searchCriteriaMembership); + } else { + $scope.currentMembershipPage = 1; + } + }; + + refreshUserGroupMembership().then(function() { + refreshAvailableGroups(); + refreshCompleteUserGroupMembership(); + }); + + $scope.$watch('currentPage', function(newValue, oldValue) { + if(parseInt(newValue, 10) !== parseInt(oldValue, 10)) { + refreshAvailableGroups($scope.searchCriteria); + } + }); + + $scope.$watch('currentMembershipPage', function(newValue, oldValue) { + if(parseInt(newValue, 10) !== parseInt(oldValue, 10)) { + refreshUserGroupMembership($scope.searchCriteriaMembership); + } + }); + + $scope.clearSearch = function() { + $scope.searchCriteria = ''; + if (parseInt($scope.currentPage, 10) === 1) { + refreshAvailableGroups(); + } else { + $scope.currentPage = 1; + } + }; + + $scope.searchGroup = function() { + if (parseInt($scope.currentPage, 10) === 1) { + refreshAvailableGroups($scope.searchCriteria); + } else { + $scope.currentPage = 1; + } + }; + + $scope.joinGroup = function() { + if (!$scope.tree.currentNode) { + Notifications.error($translate.instant('user.groups.join.error.no-group-selected')); + return; + } + if (isMember($scope.tree.currentNode)) { + Notifications.error($translate.instant('user.groups.join.error.already-added')); + return; + } + UserGroupMapping.update({realm: realm.realm, userId: user.id, groupId: $scope.tree.currentNode.id}, function() { + $scope.allGroupMemberships.push($scope.tree.currentNode); + refreshUserGroupMembership($scope.searchCriteriaMembership); + Notifications.success($translate.instant('user.groups.join.success')); + }); + + }; + + $scope.leaveGroup = function() { + if (!$scope.membershipTree.currentNode) { + Notifications.error($translate.instant('user.groups.leave.error.no-group-selected')); + return; + } + UserGroupMapping.remove({realm: realm.realm, userId: user.id, groupId: $scope.membershipTree.currentNode.id}, function () { + removeGroupMember($scope.allGroupMemberships, $scope.membershipTree.currentNode); + refreshUserGroupMembership($scope.searchCriteriaMembership); + Notifications.success($translate.instant('user.groups.leave.success')); + }); + + }; + + var isLeaf = function(node) { + return node.id !== 'realm' && (!node.subGroups || node.subGroups.length === 0); + }; + + var isMember = function(node) { + for (var i = 0; i < $scope.allGroupMemberships.length; i++) { + var member = $scope.allGroupMemberships[i]; + if (node.id === member.id) { + return true; + } + } + return false; + }; + + $scope.getGroupClass = function(node) { + if (node.id == "realm") { + return 'pficon pficon-users'; + } + if (isMember(node)) { + return 'normal deactivate'; + } + if (isLeaf(node)) { + return 'normal'; + } + if (node.subGroups.length && node.collapsed) return 'collapsed'; + if (node.subGroups.length && !node.collapsed) return 'expanded'; + return 'collapsed'; + + } + + $scope.getSelectedClass = function(node) { + if (node.selected) { + if (isMember(node)) { + return "deactivate_selected"; + } else { + return 'selected'; + } + } else if ($scope.cutNode && $scope.cutNode.id === node.id) { + return 'cut'; + } + return undefined; + } + +}); + +module.controller('LDAPUserStorageCtrl', function($scope, $location, Notifications, $route, Dialog, realm, + serverInfo, instance, Components, UserStorageOperations, + RealmLDAPConnectionTester, $http) { + console.log('LDAPUserStorageCtrl'); + var providerId = 'ldap'; + console.log('providerId: ' + providerId); + $scope.create = !instance.providerId; + console.log('create: ' + $scope.create); + var providers = serverInfo.componentTypes['org.keycloak.storage.UserStorageProvider']; + console.log('providers length ' + providers.length); + var providerFactory = null; + for (var i = 0; i < providers.length; i++) { + var p = providers[i]; + console.log('provider: ' + p.id); + if (p.id == providerId) { + $scope.providerFactory = p; + providerFactory = p; + break; + } + + } + + $scope.provider = instance; + $scope.showSync = false; + + if (serverInfo.profileInfo.name == 'community') { + $scope.ldapVendors = [ + {"id": "ad", "name": "Active Directory"}, + {"id": "rhds", "name": "Red Hat Directory Server"}, + {"id": "tivoli", "name": "Tivoli"}, + {"id": "edirectory", "name": "Novell eDirectory"}, + {"id": "other", "name": "Other"} + ]; + } else { + $scope.ldapVendors = [ + {"id": "ad", "name": "Active Directory"}, + {"id": "rhds", "name": "Red Hat Directory Server"} + ]; + } + + $scope.authTypes = [ + { "id": "none", "name": "none" }, + { "id": "simple", "name": "simple" } + ]; + + $scope.searchScopes = [ + { "id": "1", "name": "One Level" }, + { "id": "2", "name": "Subtree" } + ]; + + $scope.useTruststoreOptions = [ + { "id": "always", "name": "Always" }, + { "id": "ldapsOnly", "name": "Only for ldaps" }, + { "id": "never", "name": "Never" } + ]; + + var DEFAULT_BATCH_SIZE = "1000"; + + + console.log("providerFactory: " + providerFactory.id); + + $scope.changed = false; + function initUserStorageSettings() { + if ($scope.create) { + $scope.changed = true; + instance.name = 'ldap'; + instance.providerId = 'ldap'; + instance.providerType = 'org.keycloak.storage.UserStorageProvider'; + instance.parentId = realm.id; + instance.config = { + + }; + instance.config['enabled'] = ["true"]; + instance.config['priority'] = ["0"]; + + $scope.fullSyncEnabled = false; + $scope.changedSyncEnabled = false; + instance.config['fullSyncPeriod'] = ['-1']; + instance.config['changedSyncPeriod'] = ['-1']; + instance.config['cachePolicy'] = ['DEFAULT']; + instance.config['evictionDay'] = ['']; + instance.config['evictionHour'] = ['']; + instance.config['evictionMinute'] = ['']; + instance.config['maxLifespan'] = ['']; + instance.config['batchSizeForSync'] = [DEFAULT_BATCH_SIZE]; + //instance.config['importEnabled'] = ['true']; + + if (providerFactory.properties) { + + for (var i = 0; i < providerFactory.properties.length; i++) { + var configProperty = providerFactory.properties[i]; + if (configProperty.defaultValue) { + instance.config[configProperty.name] = [configProperty.defaultValue]; + } else { + instance.config[configProperty.name] = ['']; + } + + } + } + + + } else { + $scope.changed = false; + $scope.fullSyncEnabled = (instance.config['fullSyncPeriod'] && instance.config['fullSyncPeriod'][0] > 0); + $scope.changedSyncEnabled = (instance.config['changedSyncPeriod'] && instance.config['changedSyncPeriod'][0]> 0); + if (!instance.config['fullSyncPeriod']) { + console.log('setting to -1'); + instance.config['fullSyncPeriod'] = ['-1']; + + } + if (!instance.config['enabled']) { + instance.config['enabled'] = ['true']; + } + if (!instance.config['changedSyncPeriod']) { + console.log('setting to -1'); + instance.config['changedSyncPeriod'] = ['-1']; + + } + if (!instance.config['cachePolicy']) { + instance.config['cachePolicy'] = ['DEFAULT']; + + } + if (!instance.config['evictionDay']) { + instance.config['evictionDay'] = ['']; + + } + if (!instance.config['evictionHour']) { + instance.config['evictionHour'] = ['']; + + } + if (!instance.config['evictionMinute']) { + instance.config['evictionMinute'] = ['']; + + } + if (!instance.config['maxLifespan']) { + instance.config['maxLifespan'] = ['']; + + } + if (!instance.config['priority']) { + instance.config['priority'] = ['0']; + } + if (!instance.config['importEnabled']) { + instance.config['importEnabled'] = ['true']; + } + + if (providerFactory.properties) { + + for (var i = 0; i < providerFactory.properties.length; i++) { + var configProperty = providerFactory.properties[i]; + if (!instance.config[configProperty.name]) { + if (configProperty.defaultValue) { + instance.config[configProperty.name] = [configProperty.defaultValue]; + } else { + instance.config[configProperty.name] = ['']; + } + } + + } + } + + for (var i=0 ; i<$scope.ldapVendors.length ; i++) { + if ($scope.ldapVendors[i].id === instance.config['vendor'][0]) { + $scope.vendorName = $scope.ldapVendors[i].name; + } + }; + + + + } + if (instance.config && instance.config['importEnabled']) { + $scope.showSync = instance.config['importEnabled'][0] == 'true'; + } else { + $scope.showSync = true; + } + + $scope.lastVendor = instance.config['vendor'][0]; + } + + initUserStorageSettings(); + $scope.instance = angular.copy(instance); + $scope.realm = realm; + + $scope.$watch('instance', function() { + if (!angular.equals($scope.instance, instance)) { + $scope.changed = true; + } + + if (!angular.equals($scope.instance.config['vendor'][0], $scope.lastVendor)) { + console.log("LDAP vendor changed. Previous=" + $scope.lastVendor + " New=" + $scope.instance.config['vendor'][0]); + $scope.lastVendor = $scope.instance.config['vendor'][0]; + + if ($scope.lastVendor === "ad") { + $scope.instance.config['usernameLDAPAttribute'][0] = "cn"; + $scope.instance.config['userObjectClasses'][0] = "person, organizationalPerson, user"; + } else { + $scope.instance.config['usernameLDAPAttribute'][0] = "uid"; + $scope.instance.config['userObjectClasses'][0] = "inetOrgPerson, organizationalPerson"; + } + + $scope.instance.config['rdnLDAPAttribute'][0] = $scope.instance.config['usernameLDAPAttribute'][0]; + + var vendorToUUID = { + rhds: "nsuniqueid", + tivoli: "uniqueidentifier", + edirectory: "guid", + ad: "objectGUID", + other: "entryUUID" + }; + $scope.instance.config['uuidLDAPAttribute'][0] = vendorToUUID[$scope.lastVendor]; + } + + + }, true); + + $scope.$watch('fullSyncEnabled', function(newVal, oldVal) { + if (oldVal == newVal) { + return; + } + + $scope.instance.config['fullSyncPeriod'][0] = $scope.fullSyncEnabled ? "604800" : "-1"; + $scope.changed = true; + }); + + $scope.$watch('changedSyncEnabled', function(newVal, oldVal) { + if (oldVal == newVal) { + return; + } + + $scope.instance.config['changedSyncPeriod'][0] = $scope.changedSyncEnabled ? "86400" : "-1"; + $scope.changed = true; + }); + + + $scope.save = function() { + $scope.changed = false; + if (!$scope.instance.config['batchSizeForSync'] || !parseInt($scope.instance.config['batchSizeForSync'][0])) { + $scope.instance.config['batchSizeForSync'] = [ DEFAULT_BATCH_SIZE ]; + } else { + $scope.instance.config['batchSizeForSync'][0] = parseInt($scope.instance.config.batchSizeForSync).toString(); + } + + if ($scope.create) { + Components.save({realm: realm.realm}, $scope.instance, function (data, headers) { + var l = headers().location; + var id = l.substring(l.lastIndexOf("/") + 1); + + $location.url("/realms/" + realm.realm + "/user-storage/providers/" + $scope.instance.providerId + "/" + id); + Notifications.success("The provider has been created."); + }); + } else { + Components.update({realm: realm.realm, + componentId: instance.id + }, + $scope.instance, function () { + $route.reload(); + Notifications.success("The provider has been updated."); + }); + } + }; + + $scope.reset = function() { + $route.reload(); + }; + + $scope.cancel = function() { + if ($scope.create) { + $location.url("/realms/" + realm.realm + "/user-federation"); + } else { + $route.reload(); + } + }; + + $scope.triggerFullSync = function() { + console.log('GenericCtrl: triggerFullSync'); + triggerSync('triggerFullSync'); + } + + $scope.triggerChangedUsersSync = function() { + console.log('GenericCtrl: triggerChangedUsersSync'); + triggerSync('triggerChangedUsersSync'); + } + + + function triggerSync(action) { + UserStorageOperations.sync.save({ action: action, realm: $scope.realm.realm, componentId: $scope.instance.id }, {}, function(syncResult) { + $route.reload(); + Notifications.success("Sync of users finished successfully. " + syncResult.status); + }, function() { + $route.reload(); + Notifications.error("Error during sync of users"); + }); + } + $scope.removeImportedUsers = function() { + UserStorageOperations.removeImportedUsers.save({ realm: $scope.realm.realm, componentId: $scope.instance.id }, {}, function(syncResult) { + $route.reload(); + Notifications.success("Remove imported users finished successfully. "); + }, function() { + $route.reload(); + Notifications.error("Error during remove"); + }); + }; + $scope.unlinkUsers = function() { + UserStorageOperations.unlinkUsers.save({ realm: $scope.realm.realm, componentId: $scope.instance.id }, {}, function(syncResult) { + $route.reload(); + Notifications.success("Unlink of users finished successfully. "); + }, function() { + $route.reload(); + Notifications.error("Error during unlink"); + }); + }; + + var initConnectionTest = function(testAction, ldapConfig) { + return { + action: testAction, + connectionUrl: ldapConfig.connectionUrl && ldapConfig.connectionUrl[0], + authType: ldapConfig.authType && ldapConfig.authType[0], + bindDn: ldapConfig.bindDn && ldapConfig.bindDn[0], + bindCredential: ldapConfig.bindCredential && ldapConfig.bindCredential[0], + useTruststoreSpi: ldapConfig.useTruststoreSpi && ldapConfig.useTruststoreSpi[0], + connectionTimeout: ldapConfig.connectionTimeout && ldapConfig.connectionTimeout[0], + startTls: ldapConfig.startTls && ldapConfig.startTls[0], + componentId: instance.id + }; + }; + + $scope.testConnection = function() { + console.log('LDAPCtrl: testConnection'); + RealmLDAPConnectionTester.save({realm: realm.realm}, initConnectionTest("testConnection", $scope.instance.config), function() { + Notifications.success("LDAP connection successful."); + }, function() { + Notifications.error("Error when trying to connect to LDAP. See server.log for details."); + }); + } + + $scope.testAuthentication = function() { + console.log('LDAPCtrl: testAuthentication'); + RealmLDAPConnectionTester.save({realm: realm.realm}, initConnectionTest("testAuthentication", $scope.instance.config), function() { + Notifications.success("LDAP authentication successful."); + }, function() { + Notifications.error("LDAP authentication failed. See server.log for details"); + }); + } + + $scope.queryAndSetLdapSupportedExtensions = function() { + console.log('LDAPCtrl: getLdapSupportedExtensions'); + const PASSWORD_MODIFY_OID = '1.3.6.1.4.1.4203.1.11.1'; + + $http.post( + authUrl + '/admin/realms/' + realm.realm + '/ldap-server-capabilities', + initConnectionTest("queryServerCapabilities", $scope.instance.config)).then( + function(response) { + Notifications.success("LDAP supported extensions successfully requested."); + const ldapOids = response.data; + if (angular.isArray(ldapOids)) { + const passwordModifyOid = ldapOids.filter(function(ldapOid) { return ldapOid.oid === PASSWORD_MODIFY_OID; }); + $scope.instance.config['usePasswordModifyExtendedOp'][0] = (passwordModifyOid.length > 0).toString(); + } + }, + function() { + Notifications.error("Error when trying to request supported extensions of LDAP. See server.log for details."); + }); + } + +}); + +module.controller('LDAPTabCtrl', function(Dialog, $scope, Current, Notifications, $location) { + $scope.removeUserFederation = function() { + Dialog.confirmDelete($scope.instance.name, 'ldap provider', function() { + $scope.instance.$remove({ + realm : Current.realm.realm, + componentId : $scope.instance.id + }, function() { + $location.url("/realms/" + Current.realm.realm + "/user-federation"); + Notifications.success("The provider has been deleted."); + }); + }); + }; +}); + + +module.controller('LDAPMapperListCtrl', function($scope, $location, Notifications, $route, Dialog, realm, provider, mappers) { + console.log('LDAPMapperListCtrl'); + + $scope.realm = realm; + $scope.provider = provider; + $scope.instance = provider; + + $scope.mappers = mappers; + +}); + +module.controller('LDAPMapperCtrl', function($scope, $route, realm, provider, mapperTypes, mapper, clients, Components, LDAPMapperSync, Notifications, Dialog, $location) { + console.log('LDAPMapperCtrl'); + $scope.realm = realm; + $scope.provider = provider; + $scope.clients = clients; + $scope.create = false; + $scope.changed = false; + + for (var i = 0; i < mapperTypes.length; i++) { + console.log('mapper.providerId: ' + mapper.providerId); + console.log('mapperTypes[i].id ' + mapperTypes[i].id); + if (mapperTypes[i].id == mapper.providerId) { + $scope.mapperType = mapperTypes[i]; + break; + } + } + + if ($scope.mapperType.properties) { + + for (var i = 0; i < $scope.mapperType.properties.length; i++) { + var configProperty = $scope.mapperType.properties[i]; + if (!mapper.config[configProperty.name]) { + if (configProperty.defaultValue) { + mapper.config[configProperty.name] = [configProperty.defaultValue]; + } else { + mapper.config[configProperty.name] = ['']; + } + } + + } + } + $scope.mapper = angular.copy(mapper); + + + $scope.$watch('mapper', function() { + if (!angular.equals($scope.mapper, mapper)) { + $scope.changed = true; + } + }, true); + + $scope.save = function() { + Components.update({realm: realm.realm, + componentId: mapper.id + }, + $scope.mapper, function () { + $route.reload(); + Notifications.success("The mapper has been updated."); + }); + }; + + $scope.reset = function() { + $scope.mapper = angular.copy(mapper); + $scope.changed = false; + }; + + $scope.remove = function() { + Dialog.confirmDelete($scope.mapper.name, 'ldap mapper', function() { + Components.remove({ + realm : realm.realm, + componentId : mapper.id + }, function() { + $location.url("/realms/" + realm.realm + '/ldap-mappers/' + provider.id); + Notifications.success("The provider has been deleted."); + }); + }); + }; + + $scope.triggerFedToKeycloakSync = function() { + triggerMapperSync("fedToKeycloak") + } + + $scope.triggerKeycloakToFedSync = function() { + triggerMapperSync("keycloakToFed"); + } + + function triggerMapperSync(direction) { + LDAPMapperSync.save({ direction: direction, realm: realm.realm, parentId: provider.id, mapperId : $scope.mapper.id }, {}, function(syncResult) { + Notifications.success("Data synced successfully. " + syncResult.status); + }, function(error) { + Notifications.error(error.data.errorMessage); + }); + } + +}); + +module.controller('LDAPMapperCreateCtrl', function($scope, realm, provider, mapperTypes, clients, Components, Notifications, Dialog, $location) { + console.log('LDAPMapperCreateCtrl'); + $scope.realm = realm; + $scope.provider = provider; + $scope.clients = clients; + $scope.create = true; + $scope.mapper = { config: {}}; + $scope.mapperTypes = mapperTypes; + $scope.mapperType = null; + $scope.changed = true; + + $scope.$watch('mapperType', function() { + if ($scope.mapperType != null) { + $scope.mapper.config = {}; + if ($scope.mapperType.properties) { + + for (var i = 0; i < $scope.mapperType.properties.length; i++) { + var configProperty = $scope.mapperType.properties[i]; + if (!$scope.mapper.config[configProperty.name]) { + if (configProperty.defaultValue) { + $scope.mapper.config[configProperty.name] = [configProperty.defaultValue]; + } else { + $scope.mapper.config[configProperty.name] = ['']; + } + } + + } + } + } + }, true); + + $scope.save = function() { + if ($scope.mapperType == null) { + Notifications.error("You need to select mapper type!"); + return; + } + + $scope.mapper.providerId = $scope.mapperType.id; + $scope.mapper.providerType = 'org.keycloak.storage.ldap.mappers.LDAPStorageMapper'; + $scope.mapper.parentId = provider.id; + + if ($scope.mapper.config && $scope.mapper.config["role"] && !Array.isArray($scope.mapper.config["role"])) { + $scope.mapper.config["role"] = [$scope.mapper.config["role"]]; + } + + Components.save({realm: realm.realm}, $scope.mapper, function (data, headers) { + var l = headers().location; + var id = l.substring(l.lastIndexOf("/") + 1); + + $location.url("/realms/" + realm.realm + "/ldap-mappers/" + $scope.mapper.parentId + "/mappers/" + id); + Notifications.success("The mapper has been created."); + }); + }; + + $scope.reset = function() { + $location.url("/realms/" + realm.realm + '/ldap-mappers/' + provider.id); + }; + + +}); diff --git a/keycloak-themes/base/admin/resources/js/loaders.js b/keycloak-themes/base/admin/resources/js/loaders.js new file mode 100644 index 0000000..1f89852 --- /dev/null +++ b/keycloak-themes/base/admin/resources/js/loaders.js @@ -0,0 +1,587 @@ +'use strict'; + +var module = angular.module('keycloak.loaders', [ 'keycloak.services', 'ngResource' ]); + +module.factory('Loader', function($q) { + var loader = {}; + loader.get = function(service, id) { + return function() { + var i = id && id(); + var delay = $q.defer(); + service.get(i, function(entry) { + delay.resolve(entry); + }, function() { + delay.reject('Unable to fetch ' + i); + }); + return delay.promise; + }; + }; + loader.query = function(service, id) { + return function() { + var i = id && id(); + var delay = $q.defer(); + service.query(i, function(entry) { + delay.resolve(entry); + }, function() { + delay.reject('Unable to fetch ' + i); + }); + return delay.promise; + }; + }; + return loader; +}); + +module.factory('RealmListLoader', function(Loader, Realm, $q) { + return Loader.get(Realm); +}); + +module.factory('ServerInfoLoader', function(Loader, ServerInfo) { + return function() { + return ServerInfo.promise; + }; +}); + +module.factory('RealmLoader', function(Loader, Realm, $route, $q) { + return Loader.get(Realm, function() { + return { + id : $route.current.params.realm + } + }); +}); + +module.factory('RealmKeysLoader', function(Loader, RealmKeys, $route, $q) { + return Loader.get(RealmKeys, function() { + return { + id : $route.current.params.realm + } + }); +}); + +module.factory('RealmSpecificLocalesLoader', function(Loader, RealmSpecificLocales, $route, $q) { + return Loader.get(RealmSpecificLocales, function() { + return { + id : $route.current.params.realm + } + }); +}); + +module.factory('RealmSpecificlocalizationTextLoader', function(Loader, RealmSpecificLocalizationText, $route, $q) { + return Loader.get(RealmSpecificLocalizationText, function() { + return { + realm : $route.current.params.realm, + locale : $route.current.params.locale, + key: $route.current.params.key + } + }); +}); + +module.factory('RealmEventsConfigLoader', function(Loader, RealmEventsConfig, $route, $q) { + return Loader.get(RealmEventsConfig, function() { + return { + id : $route.current.params.realm + } + }); +}); + +module.factory('UserListLoader', function(Loader, User, $route, $q) { + return Loader.query(User, function() { + return { + realm : $route.current.params.realm + } + }); +}); + +module.factory('RequiredActionsListLoader', function(Loader, RequiredActions, $route, $q) { + return Loader.query(RequiredActions, function() { + return { + realm : $route.current.params.realm + } + }); +}); + +module.factory('UnregisteredRequiredActionsListLoader', function(Loader, UnregisteredRequiredActions, $route, $q) { + return Loader.query(UnregisteredRequiredActions, function() { + return { + realm : $route.current.params.realm + } + }); +}); + +module.factory('RealmSessionStatsLoader', function(Loader, RealmSessionStats, $route, $q) { + return Loader.get(RealmSessionStats, function() { + return { + realm : $route.current.params.realm + } + }); +}); + +module.factory('RealmClientSessionStatsLoader', function(Loader, RealmClientSessionStats, $route, $q) { + return Loader.query(RealmClientSessionStats, function() { + return { + realm : $route.current.params.realm + } + }); +}); + +module.factory('ClientProtocolMapperLoader', function(Loader, ClientProtocolMapper, $route, $q) { + return Loader.get(ClientProtocolMapper, function() { + return { + realm : $route.current.params.realm, + client : $route.current.params.client, + id: $route.current.params.id + } + }); +}); + +module.factory('ClientScopeProtocolMapperLoader', function(Loader, ClientScopeProtocolMapper, $route, $q) { + return Loader.get(ClientScopeProtocolMapper, function() { + return { + realm : $route.current.params.realm, + clientScope : $route.current.params.clientScope, + id: $route.current.params.id + } + }); +}); + +module.factory('UserLoader', function(Loader, User, $route, $q) { + return Loader.get(User, function() { + return { + realm : $route.current.params.realm, + userId : $route.current.params.user + } + }); +}); + +module.factory('ComponentLoader', function(Loader, Components, $route, $q) { + return Loader.get(Components, function() { + return { + realm : $route.current.params.realm, + componentId: $route.current.params.componentId + } + }); +}); + +module.factory('LDAPMapperLoader', function(Loader, Components, $route, $q) { + return Loader.get(Components, function() { + return { + realm : $route.current.params.realm, + componentId: $route.current.params.mapperId + } + }); +}); + +module.factory('ComponentsLoader', function(Loader, Components, $route, $q) { + var componentsLoader = {}; + + componentsLoader.loadComponents = function(parent, componentType) { + return Loader.query(Components, function() { + return { + realm : $route.current.params.realm, + parent : parent, + type: componentType + } + })(); + }; + + return componentsLoader; +}); + +module.factory('SubComponentTypesLoader', function(Loader, SubComponentTypes, $route, $q) { + var componentsLoader = {}; + + componentsLoader.loadComponents = function(parent, componentType) { + return Loader.query(SubComponentTypes, function() { + return { + realm : $route.current.params.realm, + componentId : parent, + type: componentType + } + })(); + }; + + return componentsLoader; +}); + +module.factory('UserSessionStatsLoader', function(Loader, UserSessionStats, $route, $q) { + return Loader.get(UserSessionStats, function() { + return { + realm : $route.current.params.realm, + user : $route.current.params.user + } + }); +}); + +module.factory('UserSessionsLoader', function(Loader, UserSessions, $route, $q) { + return Loader.query(UserSessions, function() { + return { + realm : $route.current.params.realm, + user : $route.current.params.user + } + }); +}); + +module.factory('UserOfflineSessionsLoader', function(Loader, UserOfflineSessions, $route, $q) { + return Loader.query(UserOfflineSessions, function() { + return { + realm : $route.current.params.realm, + user : $route.current.params.user, + client : $route.current.params.client + } + }); +}); + +module.factory('UserFederatedIdentityLoader', function(Loader, UserFederatedIdentities, $route, $q) { + return Loader.query(UserFederatedIdentities, function() { + return { + realm : $route.current.params.realm, + user : $route.current.params.user + } + }); +}); + +module.factory('UserConsentsLoader', function(Loader, UserConsents, $route, $q) { + return Loader.query(UserConsents, function() { + return { + realm : $route.current.params.realm, + user : $route.current.params.user + } + }); +}); + + + +module.factory('RoleLoader', function(Loader, RoleById, $route, $q) { + return Loader.get(RoleById, function() { + return { + realm : $route.current.params.realm, + role : $route.current.params.role + } + }); +}); + +module.factory('RoleListLoader', function(Loader, Role, $route, $q) { + return Loader.query(Role, function() { + return { + realm : $route.current.params.realm + } + }); +}); + +module.factory('ClientRoleLoader', function(Loader, RoleById, $route, $q) { + return Loader.get(RoleById, function() { + return { + realm : $route.current.params.realm, + client : $route.current.params.client, + role : $route.current.params.role + } + }); +}); + +module.factory('ClientSessionStatsLoader', function(Loader, ClientSessionStats, $route, $q) { + return Loader.get(ClientSessionStats, function() { + return { + realm : $route.current.params.realm, + client : $route.current.params.client + } + }); +}); + +module.factory('ClientSessionCountLoader', function(Loader, ClientSessionCount, $route, $q) { + return Loader.get(ClientSessionCount, function() { + return { + realm : $route.current.params.realm, + client : $route.current.params.client + } + }); +}); + +module.factory('ClientOfflineSessionCountLoader', function(Loader, ClientOfflineSessionCount, $route, $q) { + return Loader.get(ClientOfflineSessionCount, function() { + return { + realm : $route.current.params.realm, + client : $route.current.params.client + } + }); +}); + +module.factory('ClientDefaultClientScopesLoader', function(Loader, ClientDefaultClientScopes, $route, $q) { + return Loader.query(ClientDefaultClientScopes, function() { + return { + realm : $route.current.params.realm, + client : $route.current.params.client + } + }); +}); + +module.factory('ClientOptionalClientScopesLoader', function(Loader, ClientOptionalClientScopes, $route, $q) { + return Loader.query(ClientOptionalClientScopes, function() { + return { + realm : $route.current.params.realm, + client : $route.current.params.client + } + }); +}); + +module.factory('ClientLoader', function(Loader, Client, $route, $q) { + return Loader.get(Client, function() { + return { + realm : $route.current.params.realm, + client : $route.current.params.client + } + }); +}); + +module.factory('ClientListLoader', function(Loader, Client, $route, $q) { + return Loader.query(Client, function() { + return { + realm : $route.current.params.realm, + first: 0, + max: 20 + } + }); +}); + +module.factory('ClientScopeLoader', function(Loader, ClientScope, $route, $q) { + return Loader.get(ClientScope, function() { + return { + realm : $route.current.params.realm, + clientScope : $route.current.params.clientScope + } + }); +}); + +module.factory('ClientScopeListLoader', function(Loader, ClientScope, $route, $q) { + return Loader.query(ClientScope, function() { + return { + realm : $route.current.params.realm + } + }); +}); + +module.factory('RealmDefaultClientScopesLoader', function(Loader, RealmDefaultClientScopes, $route, $q) { + return Loader.query(RealmDefaultClientScopes, function() { + return { + realm : $route.current.params.realm + } + }); +}); + +module.factory('RealmOptionalClientScopesLoader', function(Loader, RealmOptionalClientScopes, $route, $q) { + return Loader.query(RealmOptionalClientScopes, function() { + return { + realm : $route.current.params.realm + } + }); +}); + +module.factory('ClientServiceAccountUserLoader', function(Loader, ClientServiceAccountUser, $route, $q) { + return Loader.get(ClientServiceAccountUser, function() { + return { + realm : $route.current.params.realm, + client : $route.current.params.client + } + }); +}); + + +module.factory('RoleMappingLoader', function(Loader, RoleMapping, $route, $q) { + var realm = $route.current.params.realm || $route.current.params.client; + + return Loader.query(RoleMapping, function() { + return { + realm : realm, + role : $route.current.params.role + } + }); +}); + +module.factory('IdentityProviderLoader', function(Loader, IdentityProvider, $route, $q) { + return Loader.get(IdentityProvider, function () { + return { + realm: $route.current.params.realm, + alias: $route.current.params.alias + } + }); +}); + +module.factory('IdentityProviderFactoryLoader', function(Loader, IdentityProviderFactory, $route, $q) { + return Loader.get(IdentityProviderFactory, function () { + return { + realm: $route.current.params.realm, + provider_id: $route.current.params.provider_id + } + }); +}); + +module.factory('IdentityProviderMapperTypesLoader', function(Loader, IdentityProviderMapperTypes, $route, $q) { + return Loader.get(IdentityProviderMapperTypes, function () { + return { + realm: $route.current.params.realm, + alias: $route.current.params.alias + } + }); +}); + +module.factory('IdentityProviderMappersLoader', function(Loader, IdentityProviderMappers, $route, $q) { + return Loader.query(IdentityProviderMappers, function () { + return { + realm: $route.current.params.realm, + alias: $route.current.params.alias + } + }); +}); + +module.factory('IdentityProviderMapperLoader', function(Loader, IdentityProviderMapper, $route, $q) { + return Loader.get(IdentityProviderMapper, function () { + return { + realm: $route.current.params.realm, + alias: $route.current.params.alias, + mapperId: $route.current.params.mapperId + } + }); +}); + +module.factory('AuthenticationFlowsLoader', function(Loader, AuthenticationFlows, $route, $q) { + return Loader.query(AuthenticationFlows, function() { + return { + realm : $route.current.params.realm, + flow: '' + } + }); +}); + +module.factory('AuthenticationFormProvidersLoader', function(Loader, AuthenticationFormProviders, $route, $q) { + return Loader.query(AuthenticationFormProviders, function() { + return { + realm : $route.current.params.realm + } + }); +}); + +module.factory('AuthenticationFormActionProvidersLoader', function(Loader, AuthenticationFormActionProviders, $route, $q) { + return Loader.query(AuthenticationFormActionProviders, function() { + return { + realm : $route.current.params.realm + } + }); +}); + +module.factory('AuthenticatorProvidersLoader', function(Loader, AuthenticatorProviders, $route, $q) { + return Loader.query(AuthenticatorProviders, function() { + return { + realm : $route.current.params.realm + } + }); +}); + +module.factory('ClientAuthenticatorProvidersLoader', function(Loader, ClientAuthenticatorProviders, $route, $q) { + return Loader.query(ClientAuthenticatorProviders, function() { + return { + realm : $route.current.params.realm + } + }); +}); + +module.factory('AuthenticationFlowLoader', function(Loader, AuthenticationFlows, $route, $q) { + return Loader.get(AuthenticationFlows, function() { + return { + realm : $route.current.params.realm, + flow: $route.current.params.flow + } + }); +}); + +module.factory('AuthenticationConfigDescriptionLoader', function(Loader, AuthenticationConfigDescription, $route, $q) { + return Loader.get(AuthenticationConfigDescription, function () { + return { + realm: $route.current.params.realm, + provider: $route.current.params.provider + } + }); +}); + +module.factory('PerClientAuthenticationConfigDescriptionLoader', function(Loader, PerClientAuthenticationConfigDescription, $route, $q) { + return Loader.get(PerClientAuthenticationConfigDescription, function () { + return { + realm: $route.current.params.realm + } + }); +}); + +module.factory('ExecutionIdLoader', function($route) { + return function() { return $route.current.params.executionId; }; +}); + +module.factory('AuthenticationConfigLoader', function(Loader, AuthenticationConfig, $route, $q) { + return Loader.get(AuthenticationConfig, function () { + return { + realm: $route.current.params.realm, + config: $route.current.params.config + } + }); +}); + +module.factory('GroupListLoader', function(Loader, Groups, $route, $q) { + return Loader.query(Groups, function() { + return { + realm : $route.current.params.realm + } + }); +}); + +module.factory('GroupCountLoader', function(Loader, GroupsCount, $route, $q) { + return Loader.query(GroupsCount, function() { + return { + realm : $route.current.params.realm, + top : true + } + }); +}); + +module.factory('GroupLoader', function(Loader, Group, $route, $q) { + return Loader.get(Group, function() { + return { + realm : $route.current.params.realm, + groupId : $route.current.params.group + } + }); +}); + +module.factory('ClientInitialAccessLoader', function(Loader, ClientInitialAccess, $route) { + return Loader.query(ClientInitialAccess, function() { + return { + realm: $route.current.params.realm + } + }); +}); + +module.factory('ClientRegistrationPolicyProvidersLoader', function(Loader, ClientRegistrationPolicyProviders, $route) { + return Loader.query(ClientRegistrationPolicyProviders, function() { + return { + realm: $route.current.params.realm + } + }); +}); + +module.factory('ClientPoliciesProfilesLoader', function(Loader, ClientPoliciesProfiles, $route , $q) { + var clientPoliciesLoader = {}; + + clientPoliciesLoader.loadClientProfiles = function(includeGlobalProfiles) { + return Loader.get(ClientPoliciesProfiles, function() { + return { + realm : $route.current.params.realm, + includeGlobalProfiles : includeGlobalProfiles + } + })(); + }; + + return clientPoliciesLoader; +}); + +module.factory('ClientPoliciesLoader', function(Loader, ClientPolicies, $route) { + return Loader.get(ClientPolicies, function() { + return { + realm: $route.current.params.realm + } + }); +}); diff --git a/keycloak-themes/base/admin/resources/js/services.js b/keycloak-themes/base/admin/resources/js/services.js new file mode 100644 index 0000000..370f303 --- /dev/null +++ b/keycloak-themes/base/admin/resources/js/services.js @@ -0,0 +1,2261 @@ +'use strict'; + +var module = angular.module('keycloak.services', [ 'ngResource', 'ngRoute' ]); + +module.service('Dialog', function($modal, $translate) { + var dialog = {}; + + var openDialog = function(title, message, btns, template) { + var controller = function($scope, $modalInstance, title, message, btns) { + $scope.title = title; + $scope.message = message; + $scope.btns = btns; + + $scope.ok = function () { + $modalInstance.close(); + }; + $scope.cancel = function () { + $modalInstance.dismiss('cancel'); + }; + }; + + return $modal.open({ + templateUrl: resourceUrl + template, + controller: controller, + resolve: { + title: function() { + return title; + }, + message: function() { + return message; + }, + btns: function() { + return btns; + } + } + }).result; + } + + var escapeHtml = function(str) { + var div = document.createElement('div'); + div.appendChild(document.createTextNode(str)); + return div.innerHTML; + }; + + dialog.confirmDelete = function(name, type, success) { + var title = $translate.instant('dialogs.delete.title', {type: escapeHtml(type.charAt(0).toUpperCase() + type.slice(1))}); + var msg = $translate.instant('dialogs.delete.message', {type: type, name: name}); + var confirm = $translate.instant('dialogs.delete.confirm'); + + dialog.confirmWithButtonText(title, msg, confirm, success); + } + + dialog.confirmGenerateKeys = function(name, type, success) { + var title = 'Generate new keys for realm'; + var msg = 'Are you sure you want to permanently generate new keys for ' + name + '?'; + var btns = { + ok: { + label: 'Generate Keys', + cssClass: 'btn btn-danger' + }, + cancel: { + label: 'Cancel', + cssClass: 'btn btn-default' + } + } + + openDialog(title, msg, btns, '/templates/kc-modal.html').then(success); + } + + dialog.confirm = function(title, message, success, cancel) { + dialog.confirmWithButtonText(title, message, title, success, cancel); + } + + dialog.confirmWithButtonText = function(title, message, confirm, success, cancel) { + var btns = { + ok: { + label: confirm, + cssClass: 'btn btn-danger' + }, + cancel: { + label: $translate.instant('dialogs.cancel'), + cssClass: 'btn btn-default' + } + } + + openDialog(title, message, btns, '/templates/kc-modal.html').then(success, cancel); + } + + dialog.message = function(title, message, success, cancel) { + var btns = { + ok: { + label: $translate.instant('dialogs.ok'), + cssClass: 'btn btn-default' + } + } + + openDialog(title, message, btns, '/templates/kc-modal-message.html').then(success, cancel); + } + + dialog.open = function(title, message, btns, success, cancel) { + openDialog(title, message, btns, '/templates/kc-modal.html').then(success, cancel); + } + + return dialog +}); + +module.service('CopyDialog', function($modal) { + var dialog = {}; + dialog.open = function (title, suggested, success) { + var controller = function($scope, $modalInstance, title) { + $scope.title = title; + $scope.name = { value: 'Copy of ' + suggested }; + $scope.ok = function () { + console.log('ok with name: ' + $scope.name); + $modalInstance.close(); + success($scope.name.value); + }; + $scope.cancel = function () { + $modalInstance.dismiss('cancel'); + }; + } + $modal.open({ + templateUrl: resourceUrl + '/templates/kc-copy.html', + controller: controller, + resolve: { + title: function() { + return title; + } + } + }); + }; + return dialog; +}); + +module.service('UpdateDialog', function($modal) { + var dialog = {}; + dialog.open = function (title, name, desc, success) { + var controller = function($scope, $modalInstance, title) { + $scope.title = title; + $scope.name = { value: name }; + $scope.description = { value: desc }; + $scope.ok = function () { + console.log('ok with name: ' + $scope.name + 'and description: ' + $scope.description); + $modalInstance.close(); + success($scope.name.value, $scope.description.value); + }; + $scope.cancel = function () { + $modalInstance.dismiss('cancel'); + }; + } + $modal.open({ + templateUrl: resourceUrl + '/templates/kc-edit.html', + controller: controller, + resolve: { + title: function() { + return title; + } + } + }); + }; + return dialog; +}); + +module.factory('Notifications', function($rootScope, $timeout, $translate) { + // time (in ms) the notifications are shown + var delay = 5000; + + var notifications = {}; + notifications.current = { display: false }; + notifications.current.remove = function() { + if (notifications.scheduled) { + $timeout.cancel(notifications.scheduled); + delete notifications.scheduled; + } + delete notifications.current.type; + delete notifications.current.header; + delete notifications.current.message; + notifications.current.display = false; + console.debug("Remove message"); + } + + $rootScope.notification = notifications.current; + + notifications.message = function(type, header, message) { + notifications.current.remove(); + + notifications.current.type = type; + notifications.current.header = header; + notifications.current.message = message; + notifications.current.display = true; + + notifications.scheduled = $timeout(function() { + notifications.current.remove(); + }, delay); + + console.debug("Added message"); + } + + notifications.info = function(message) { + notifications.message("info", $translate.instant('notifications.info.header'), message); + }; + + notifications.success = function(message) { + notifications.message("success", $translate.instant('notifications.success.header'), message); + }; + + notifications.error = function(message) { + notifications.message("danger", $translate.instant('notifications.error.header'), message); + }; + + notifications.warn = function(message) { + notifications.message("warning", $translate.instant('notifications.warn.header'), message); + }; + + return notifications; +}); + + +module.factory('ComponentUtils', function() { + + function sortGroups(prop, arr) { + // sort current elements + arr.sort(function (a, b) { + if (a[prop] < b[prop]) { return -1; } + if (a[prop] > b[prop]) { return 1; } + return 0; + }); + // check sub groups + arr.forEach(function (item, index) { + if (!!item.subGroups) { + sortGroups(prop, item.subGroups); + } + }); + return arr; + }; + + var utils = {}; + + utils.sortGroups = sortGroups; + + utils.findIndexById = function(array, id) { + for (var i = 0; i < array.length; i++) { + if (array[i].id === id) return i; + } + return -1; + } + + utils.convertAllMultivaluedStringValuesToList = function(properties, config) { + if (!properties) { + return; + } + + for (var i=0 ; i 0) { + var lastVal = configVal[configVal.length - 1]; + if (lastVal === '') { + console.log('Remove empty value from config property: ' + prop.name); + configVal.splice(configVal.length - 1, 1); + } + } + + var attrVals = configVal.join("##"); + config[prop.name] = attrVals; + + } + } + } + } + + + + utils.addLastEmptyValueToMultivaluedLists = function(properties, config) { + if (!properties) { + return; + } + + for (var i=0 ; i 0) { + configProperty.push(''); + } + } + } + } + + + utils.removeLastEmptyValue = function(componentConfig) { + + for (var configPropertyName in componentConfig) { + var configVal = componentConfig[configPropertyName]; + if (configVal && configVal.length > 0) { + var lastVal = configVal[configVal.length - 1]; + if (lastVal === '') { + console.log('Remove empty value from config property: ' + configPropertyName); + configVal.splice(configVal.length - 1, 1); + } + } + } + } + + // Allows you to use ui-select2 with tag. + // In HTML you will then use property.mvOptions like this: + // Flows tab +module.service('LastFlowSelected', function() { + this.alias = null; +}); + +module.service('RealmRoleRemover', function() { + this.remove = function (role, realm, Dialog, $location, Notifications) { + Dialog.confirmDelete(role.name, 'role', function () { + role.$remove({ + realm: realm.realm, + role: role.id + }, function () { + $location.url("/realms/" + realm.realm + "/roles"); + Notifications.success("The role has been deleted."); + }); + }); + }; +}); + +module.factory('UserSessionStats', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:user/session-stats', { + realm : '@realm', + user : '@user' + }); +}); +module.factory('UserSessions', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:user/sessions', { + realm : '@realm', + user : '@user' + }); +}); +module.factory('UserOfflineSessions', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:user/offline-sessions/:client', { + realm : '@realm', + user : '@user', + client : '@client' + }); +}); + +module.factory('UserSessionLogout', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/sessions/:session', { + realm : '@realm', + session : '@session' + }); +}); + +module.factory('UserLogout', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:user/logout', { + realm : '@realm', + user : '@user' + }); +}); + +module.factory('UserFederatedIdentities', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:user/federated-identity', { + realm : '@realm', + user : '@user' + }); +}); +module.factory('UserFederatedIdentity', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:user/federated-identity/:provider', { + realm : '@realm', + user : '@user', + provider : '@provider' + }); +}); + +module.factory('UserConsents', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:user/consents/:client', { + realm : '@realm', + user : '@user', + client: '@client' + }); +}); + +module.factory('UserImpersonation', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:user/impersonation', { + realm : '@realm', + user : '@user' + }); +}); + +module.factory('UserCredentials', function($resource) { + var credentials = {}; + + credentials.getCredentials = $resource(authUrl + '/admin/realms/:realm/users/:userId/credentials', { + realm : '@realm', + userId : '@userId' + }).query; + + credentials.getConfiguredUserStorageCredentialTypes = $resource(authUrl + '/admin/realms/:realm/users/:userId/configured-user-storage-credential-types', { + realm : '@realm', + userId : '@userId' + }).query; + + credentials.deleteCredential = $resource(authUrl + '/admin/realms/:realm/users/:userId/credentials/:credentialId', { + realm : '@realm', + userId : '@userId', + credentialId : '@credentialId' + }).delete; + + credentials.updateCredentialLabel = $resource(authUrl + '/admin/realms/:realm/users/:userId/credentials/:credentialId/userLabel', { + realm : '@realm', + userId : '@userId', + credentialId : '@credentialId' + }, { + update : { + method : 'PUT', + headers: { + 'Content-Type': 'text/plain;charset=utf-8' + }, + transformRequest: function(credential, getHeaders) { + return credential.userLabel; + } + } + }).update; + + credentials.resetPassword = $resource(authUrl + '/admin/realms/:realm/users/:userId/reset-password', { + realm : '@realm', + userId : '@userId' + }, { + update : { + method : 'PUT' + } + }).update; + + credentials.removeTotp = $resource(authUrl + '/admin/realms/:realm/users/:userId/remove-totp', { + realm : '@realm', + userId : '@userId' + }, { + update : { + method : 'PUT' + } + }).update; + + credentials.disableCredentialTypes = $resource(authUrl + '/admin/realms/:realm/users/:userId/disable-credential-types', { + realm : '@realm', + userId : '@userId' + }, { + update : { + method : 'PUT' + } + }).update; + + credentials.moveCredentialAfter = $resource(authUrl + '/admin/realms/:realm/users/:userId/credentials/:credentialId/moveAfter/:newPreviousCredentialId', { + realm : '@realm', + userId : '@userId', + credentialId : '@credentialId', + newPreviousCredentialId : '@newPreviousCredentialId' + }, { + update : { + method : 'POST' + } + }).update; + + credentials.moveToFirst = $resource(authUrl + '/admin/realms/:realm/users/:userId/credentials/:credentialId/moveToFirst', { + realm : '@realm', + userId : '@userId', + credentialId : '@credentialId' + }, { + update : { + method : 'POST' + } + }).update; + + return credentials; +}); + +module.factory('UserExecuteActionsEmail', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:userId/execute-actions-email', { + realm : '@realm', + userId : '@userId', + lifespan : '@lifespan', + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('RealmRoleMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/realm', { + realm : '@realm', + userId : '@userId' + }); +}); + +module.factory('CompositeRealmRoleMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/realm/composite', { + realm : '@realm', + userId : '@userId' + }); +}); + +module.factory('AvailableRealmRoleMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/realm/available', { + realm : '@realm', + userId : '@userId' + }); +}); + + +module.factory('ClientRoleMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/clients/:client', { + realm : '@realm', + userId : '@userId', + client : "@client" + }); +}); + +module.factory('AvailableClientRoleMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/clients/:client/available', { + realm : '@realm', + userId : '@userId', + client : "@client" + }); +}); + +module.factory('CompositeClientRoleMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/clients/:client/composite', { + realm : '@realm', + userId : '@userId', + client : "@client" + }); +}); + +module.factory('ClientRealmScopeMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/scope-mappings/realm', { + realm : '@realm', + client : '@client' + }); +}); + +module.factory('ClientAvailableRealmScopeMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/scope-mappings/realm/available', { + realm : '@realm', + client : '@client' + }); +}); + +module.factory('ClientCompositeRealmScopeMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/scope-mappings/realm/composite', { + realm : '@realm', + client : '@client' + }); +}); + +module.factory('ClientClientScopeMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/scope-mappings/clients/:targetClient', { + realm : '@realm', + client : '@client', + targetClient : '@targetClient' + }); +}); + +module.factory('ClientAvailableClientScopeMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/scope-mappings/clients/:targetClient/available', { + realm : '@realm', + client : '@client', + targetClient : '@targetClient' + }); +}); + +module.factory('ClientCompositeClientScopeMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/scope-mappings/clients/:targetClient/composite', { + realm : '@realm', + client : '@client', + targetClient : '@targetClient' + }); +}); + + + +module.factory('RealmRoles', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/roles', { + realm : '@realm' + }); +}); + +module.factory('RoleRealmComposites', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role/composites/realm', { + realm : '@realm', + role : '@role' + }); +}); + +module.factory('RealmPushRevocation', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/push-revocation', { + realm : '@realm' + }); +}); + +module.factory('RealmClearUserCache', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clear-user-cache', { + realm : '@realm' + }); +}); + +module.factory('RealmClearRealmCache', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clear-realm-cache', { + realm : '@realm' + }); +}); + +module.factory('RealmClearKeysCache', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clear-keys-cache', { + realm : '@realm' + }); +}); + +module.factory('RealmSessionStats', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/session-stats', { + realm : '@realm' + }); +}); + +module.factory('RealmClientSessionStats', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/client-session-stats', { + realm : '@realm' + }); +}); + + +module.factory('RoleClientComposites', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role/composites/clients/:client', { + realm : '@realm', + role : '@role', + client : "@client" + }); +}); + +function clientSelectControl($scope, realm, Client) { + $scope.clientsUiSelect = { + minimumInputLength: 0, + delay: 500, + allowClear: true, + query: function (query) { + var data = {results: []}; + Client.query({realm: realm, search: true, clientId: query.term.trim(), max: 20}, function(response) { + data.results = response; + query.callback(data); + }); + }, + formatResult: function(object, container, query) { + object.text = object.clientId; + return object.clientId; + } + }; +} + +function roleControl($scope, $route, realm, role, roles, Client, + ClientRole, RoleById, RoleRealmComposites, RoleClientComposites, + $http, $location, Notifications, Dialog, ComponentUtils) { + $scope.$watch(function () { + return $location.path(); + }, function () { + $scope.path = $location.path().substring(1).split("/"); + }); + + $scope.$watch('role', function () { + if (!angular.equals($scope.role, role)) { + $scope.changed = true; + } + }, true); + + $scope.update = function () { + RoleById.update({ + realm: realm.realm, + role: role.id + }, $scope.role, function () { + $scope.changed = false; + role = angular.copy($scope.role); + Notifications.success("Your changes have been saved to the role."); + }); + }; + + $scope.reset = function () { + $scope.role = angular.copy(role); + $scope.changed = false; + }; + + if (!role.id) return; + + $scope.compositeSwitch = role.composite; + $scope.compositeSwitchDisabled = role.composite; + $scope.realmRoles = angular.copy(roles); + $scope.selectedRealmRoles = []; + $scope.selectedRealmMappings = []; + $scope.realmMappings = []; + $scope.clientRoles = []; + $scope.selectedClientRoles = []; + $scope.selectedClientMappings = []; + $scope.clientMappings = []; + + for (var j = 0; j < $scope.realmRoles.length; j++) { + if ($scope.realmRoles[j].id == role.id) { + var realmRole = $scope.realmRoles[j]; + var idx = $scope.realmRoles.indexOf(realmRole); + $scope.realmRoles.splice(idx, 1); + break; + } + } + + + clientSelectControl($scope, $route.current.params.realm, Client); + + $scope.selectedClient = null; + + + $scope.realmMappings = RoleRealmComposites.query({realm : realm.realm, role : role.id}, function(){ + for (var i = 0; i < $scope.realmMappings.length; i++) { + var role = $scope.realmMappings[i]; + for (var j = 0; j < $scope.realmRoles.length; j++) { + var realmRole = $scope.realmRoles[j]; + if (realmRole.id == role.id) { + var idx = $scope.realmRoles.indexOf(realmRole); + if (idx != -1) { + $scope.realmRoles.splice(idx, 1); + break; + } + } + } + } + }); + + $scope.addRealmRole = function() { + $scope.compositeSwitchDisabled=true; + $scope.selectedRealmRolesToAdd = JSON.parse('[' + $scope.selectedRealmRoles + ']'); + $http.post(authUrl + '/admin/realms/' + realm.realm + '/roles-by-id/' + role.id + '/composites', + $scope.selectedRealmRolesToAdd).then(function() { + for (var i = 0; i < $scope.selectedRealmRolesToAdd.length; i++) { + var role = $scope.selectedRealmRolesToAdd[i]; + var idx = ComponentUtils.findIndexById($scope.realmRoles, role.id); + if (idx != -1) { + $scope.realmRoles.splice(idx, 1); + $scope.realmMappings.push(role); + } + } + $scope.selectedRealmRoles = []; + $scope.selectedRealmRolesToAdd = []; + Notifications.success("Role added to composite."); + }); + }; + + $scope.deleteRealmRole = function() { + $scope.compositeSwitchDisabled=true; + $scope.selectedRealmMappingsToRemove = JSON.parse('[' + $scope.selectedRealmMappings + ']'); + $http.delete(authUrl + '/admin/realms/' + realm.realm + '/roles-by-id/' + role.id + '/composites', + {data : $scope.selectedRealmMappingsToRemove, headers : {"content-type" : "application/json"}}).then(function() { + for (var i = 0; i < $scope.selectedRealmMappingsToRemove.length; i++) { + var role = $scope.selectedRealmMappingsToRemove[i]; + var idx = ComponentUtils.findIndexById($scope.realmMappings, role.id); + if (idx != -1) { + $scope.realmMappings.splice(idx, 1); + $scope.realmRoles.push(role); + } + } + $scope.selectedRealmMappings = []; + $scope.selectedRealmMappingsToRemove = []; + Notifications.success("Role removed from composite."); + }); + }; + + $scope.addClientRole = function() { + $scope.compositeSwitchDisabled=true; + $scope.selectedClientRolesToAdd = JSON.parse('[' + $scope.selectedClientRoles + ']'); + $http.post(authUrl + '/admin/realms/' + realm.realm + '/roles-by-id/' + role.id + '/composites', + $scope.selectedClientRolesToAdd).then(function() { + for (var i = 0; i < $scope.selectedClientRolesToAdd.length; i++) { + var role = $scope.selectedClientRolesToAdd[i]; + var idx = ComponentUtils.findIndexById($scope.clientRoles, role.id); + if (idx != -1) { + $scope.clientRoles.splice(idx, 1); + $scope.clientMappings.push(role); + } + } + $scope.selectedClientRoles = []; + $scope.selectedClientRolesToAdd = []; + Notifications.success("Client role added."); + }); + }; + + $scope.deleteClientRole = function() { + $scope.compositeSwitchDisabled=true; + $scope.selectedClientMappingsToRemove = JSON.parse('[' + $scope.selectedClientMappings + ']'); + $http.delete(authUrl + '/admin/realms/' + realm.realm + '/roles-by-id/' + role.id + '/composites', + {data : $scope.selectedClientMappingsToRemove, headers : {"content-type" : "application/json"}}).then(function() { + for (var i = 0; i < $scope.selectedClientMappingsToRemove.length; i++) { + var role = $scope.selectedClientMappingsToRemove[i]; + var idx = ComponentUtils.findIndexById($scope.clientMappings, role.id); + if (idx != -1) { + $scope.clientMappings.splice(idx, 1); + $scope.clientRoles.push(role); + } + } + $scope.selectedClientMappings = []; + $scope.selectedClientMappingsToRemove = []; + Notifications.success("Client role removed."); + }); + }; + + + $scope.changeClient = function(client) { + console.log("selected client: ", client); + if (!client || !client.id) { + $scope.selectedClient = null; + return; + } + $scope.selectedClient = client; + $scope.clientRoles = ClientRole.query({realm : realm.realm, client : client.id}, function() { + $scope.clientMappings = RoleClientComposites.query({realm : realm.realm, role : role.id, client : client.id}, function(){ + for (var i = 0; i < $scope.clientMappings.length; i++) { + var role = $scope.clientMappings[i]; + for (var j = 0; j < $scope.clientRoles.length; j++) { + var realmRole = $scope.clientRoles[j]; + if (realmRole.id == role.id) { + var idx = $scope.clientRoles.indexOf(realmRole); + if (idx != -1) { + $scope.clientRoles.splice(idx, 1); + break; + } + } + } + } + }); + for (var j = 0; j < $scope.clientRoles.length; j++) { + if ($scope.clientRoles[j] == role.id) { + var appRole = $scope.clientRoles[j]; + var idx = $scope.clientRoles.indexof(appRole); + $scope.clientRoles.splice(idx, 1); + break; + } + } + } + ); + }; + + + + +} + + +module.factory('Role', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/roles/:role', { + realm : '@realm', + role : '@role' + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('RoleById', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role', { + realm : '@realm', + role : '@role' + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('ClientRole', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/roles/:role', { + realm : '@realm', + client : "@client", + role : '@role' + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('ClientDefaultClientScopes', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/default-client-scopes/:clientScopeId', { + realm : '@realm', + client : "@client", + clientScopeId : '@clientScopeId' + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('ClientOptionalClientScopes', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/optional-client-scopes/:clientScopeId', { + realm : '@realm', + client : "@client", + clientScopeId : '@clientScopeId' + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('ClientEvaluateProtocolMappers', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/evaluate-scopes/protocol-mappers?scope=:scopeParam', { + realm : '@realm', + client : "@client", + scopeParam : "@scopeParam" + }); +}); + +module.factory('ClientEvaluateGrantedRoles', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/evaluate-scopes/scope-mappings/:roleContainer/granted?scope=:scopeParam', { + realm : '@realm', + client : "@client", + roleContainer : "@roleContainer", + scopeParam : "@scopeParam" + }); +}); + +module.factory('ClientEvaluateNotGrantedRoles', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/evaluate-scopes/scope-mappings/:roleContainer/not-granted?scope=:scopeParam', { + realm : '@realm', + client : "@client", + roleContainer : "@roleContainer", + scopeParam : "@scopeParam" + }); +}); + +module.factory('ClientEvaluateGenerateExampleAccessToken', function($resource) { + return buildClientEvaluateGenerateExampleUrl('generate-example-access-token'); +}); + +module.factory('ClientEvaluateGenerateExampleIDToken', function($resource) { + return buildClientEvaluateGenerateExampleUrl('generate-example-id-token'); +}); + +module.factory('ClientEvaluateGenerateExampleUserInfo', function($resource) { + return buildClientEvaluateGenerateExampleUrl('generate-example-userinfo'); +}); + +function buildClientEvaluateGenerateExampleUrl(subPath) { + var urlTemplate = authUrl + '/admin/realms/:realm/clients/:client/evaluate-scopes/' + subPath + '?scope=:scopeParam&userId=:userId'; + return { + url: function (parameters) { + return urlTemplate + .replace(':realm', parameters.realm) + .replace(':client', parameters.client) + .replace(':scopeParam', parameters.scopeParam) + .replace(':userId', parameters.userId); + } + } +} + +module.factory('ClientProtocolMappersByProtocol', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/protocol-mappers/protocol/:protocol', { + realm : '@realm', + client : "@client", + protocol : "@protocol" + }); +}); + +module.factory('ClientScopeProtocolMappersByProtocol', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/client-scopes/:clientScope/protocol-mappers/protocol/:protocol', { + realm : '@realm', + clientScope : "@clientScope", + protocol : "@protocol" + }); +}); + +module.factory('ClientScopeRealmScopeMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/client-scopes/:clientScope/scope-mappings/realm', { + realm : '@realm', + clientScope : '@clientScope' + }); +}); + +module.factory('ClientScopeAvailableRealmScopeMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/client-scopes/:clientScope/scope-mappings/realm/available', { + realm : '@realm', + clientScope : '@clientScope' + }); +}); + +module.factory('ClientScopeCompositeRealmScopeMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/client-scopes/:clientScope/scope-mappings/realm/composite', { + realm : '@realm', + clientScope : '@clientScope' + }); +}); + +module.factory('ClientScopeClientScopeMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/client-scopes/:clientScope/scope-mappings/clients/:targetClient', { + realm : '@realm', + clientScope : '@clientScope', + targetClient : '@targetClient' + }); +}); + +module.factory('ClientScopeAvailableClientScopeMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/client-scopes/:clientScope/scope-mappings/clients/:targetClient/available', { + realm : '@realm', + clientScope : '@clientScope', + targetClient : '@targetClient' + }); +}); + +module.factory('ClientScopeCompositeClientScopeMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/client-scopes/:clientScope/scope-mappings/clients/:targetClient/composite', { + realm : '@realm', + clientScope : '@clientScope', + targetClient : '@targetClient' + }); +}); + + +module.factory('ClientSessionStats', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/session-stats', { + realm : '@realm', + client : "@client" + }); +}); + +module.factory('ClientSessionStatsWithUsers', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/session-stats?users=true', { + realm : '@realm', + client : "@client" + }); +}); + +module.factory('ClientSessionCount', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/session-count', { + realm : '@realm', + client : "@client" + }); +}); + +module.factory('ClientUserSessions', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/user-sessions', { + realm : '@realm', + client : "@client" + }); +}); + +module.factory('ClientOfflineSessionCount', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/offline-session-count', { + realm : '@realm', + client : "@client" + }); +}); + +module.factory('ClientOfflineSessions', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/offline-sessions', { + realm : '@realm', + client : "@client" + }); +}); + +module.factory('RealmLogoutAll', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/logout-all', { + realm : '@realm' + }); +}); + +module.factory('ClientPushRevocation', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/push-revocation', { + realm : '@realm', + client : "@client" + }); +}); + +module.factory('ClientClusterNode', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/nodes/:node', { + realm : '@realm', + client : "@client" + }); +}); + +module.factory('ClientTestNodesAvailable', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/test-nodes-available', { + realm : '@realm', + client : "@client" + }); +}); + +module.factory('ClientCertificate', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/certificates/:attribute', { + realm : '@realm', + client : "@client", + attribute: "@attribute" + }); +}); + +module.factory('ClientCertificateGenerate', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/certificates/:attribute/generate', { + realm : '@realm', + client : "@client", + attribute: "@attribute" + }, + { + generate : { + method : 'POST' + } + }); +}); + +module.factory('ClientCertificateDownload', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/certificates/:attribute/download', { + realm : '@realm', + client : "@client", + attribute: "@attribute" + }, + { + download : { + method : 'POST', + responseType: 'arraybuffer' + } + }); +}); + +module.factory('Client', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client', { + realm : '@realm', + client : '@client' + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('ClientScope', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/client-scopes/:clientScope', { + realm : '@realm', + clientScope : '@clientScope' + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('RealmDefaultClientScopes', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/default-default-client-scopes/:clientScopeId', { + realm : '@realm', + clientScopeId : '@clientScopeId' + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('RealmOptionalClientScopes', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/default-optional-client-scopes/:clientScopeId', { + realm : '@realm', + clientScopeId : '@clientScopeId' + }, { + update : { + method : 'PUT' + } + }); +}); + + +module.factory('ClientDescriptionConverter', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/client-description-converter', { + realm : '@realm' + }); +}); + +/* +module.factory('ClientInstallation', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/installation/providers/:provider', { + realm : '@realm', + client : '@client', + provider : '@provider' + }); +}); +*/ + + + +module.factory('ClientInstallation', function($resource) { + var url = authUrl + '/admin/realms/:realm/clients/:client/installation/providers/:provider'; + return { + url : function(parameters) + { + return url.replace(':realm', parameters.realm).replace(':client', parameters.client).replace(':provider', parameters.provider); + } + } +}); + +module.factory('ClientInstallationJBoss', function($resource) { + var url = authUrl + '/admin/realms/:realm/clients/:client/installation/jboss'; + return { + url : function(parameters) + { + return url.replace(':realm', parameters.realm).replace(':client', parameters.client); + } + } +}); + +module.factory('ClientSecret', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/client-secret', { + realm : '@realm', + client : '@client' + }, { + update : { + method : 'POST' + }, + invalidate: { + url: authUrl + '/admin/realms/:realm/clients/:client/client-secret/rotated', + method: 'DELETE' + } + } + ); +}); + +module.factory('ClientRegistrationAccessToken', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/registration-access-token', { + realm : '@realm', + client : '@client' + }, { + update : { + method : 'POST' + } + }); +}); + +module.factory('ClientOrigins', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/allowed-origins', { + realm : '@realm', + client : '@client' + }, { + update : { + method : 'PUT', + isArray : true + } + }); +}); + +module.factory('ClientServiceAccountUser', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/service-account-user', { + realm : '@realm', + client : '@client' + }); +}); + +module.factory('Current', function(Realm, $route, $rootScope) { + var current = { + realms: {}, + realm: null + }; + + $rootScope.$on('$routeChangeStart', function() { + current.realms = Realm.query({briefRepresentation: true}, function(realms) { + var currentRealm = null; + if ($route.current.params.realm) { + for (var i = 0; i < realms.length; i++) { + if (realms[i].realm == $route.current.params.realm) { + currentRealm = realms[i]; + } + } + } + current.realm = currentRealm; + }); + }); + + return current; +}); + +module.factory('TimeUnit', function() { + var t = {}; + + t.autoUnit = function(time) { + if (!time) { + return 'Hours'; + } + + var unit = 'Seconds'; + if (time % 60 == 0) { + unit = 'Minutes'; + time = time / 60; + if (time % 60 == 0) { + unit = 'Hours'; + time = time / 60; + if (time % 24 == 0) { + unit = 'Days'; + } + } + } + + return unit; + } + + t.toSeconds = function(time, unit) { + switch (unit) { + case 'Seconds': return time; + case 'Minutes': return time * 60; + case 'Hours': return time * 3600; + case 'Days': return time * 86400; + default: throw 'invalid unit ' + unit; + } + } + + t.toUnit = function(time, unit) { + switch (unit) { + case 'Seconds': return time; + case 'Minutes': return Math.ceil(time / 60); + case 'Hours': return Math.ceil(time / 3600); + case 'Days': return Math.ceil(time / 86400); + default: throw 'invalid unit ' + unit; + } + } + + return t; +}); + +module.factory('TimeUnit2', function() { + var t = {}; + + t.asUnit = function(time) { + + var unit = 'Minutes'; + + if (time) { + if (time == -1) { + time = -1; + } else { + if (time < 60) { + time = 60; + } + + if (time % 60 == 0) { + unit = 'Minutes'; + time = time / 60; + if (time % 60 == 0) { + unit = 'Hours'; + time = time / 60; + if (time % 24 == 0) { + unit = 'Days'; + time = time / 24; + } + } + } + } + } + + var v = { + unit: unit, + time: time, + toSeconds: function() { + switch (v.unit) { + case 'Minutes': + return v.time * 60; + case 'Hours': + return v.time * 3600; + case 'Days': + return v.time * 86400; + } + } + } + + return v; + } + + return t; +}); + +module.filter('removeSelectedPolicies', function() { + return function(policies, selectedPolicies) { + var result = []; + for(var i in policies) { + var policy = policies[i]; + var policyAvailable = true; + for(var j in selectedPolicies) { + if(policy.id === selectedPolicies[j].id && !policy.multipleSupported) { + policyAvailable = false; + } + } + if(policyAvailable) { + result.push(policy); + } + } + return result; + } +}); + +module.factory('IdentityProvider', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/identity-provider/instances/:alias', { + realm : '@realm', + alias : '@alias' + }, { + update: { + method : 'PUT' + } + }); +}); + +module.factory('IdentityProviderExport', function($resource) { + var url = authUrl + '/admin/realms/:realm/identity-provider/instances/:alias/export'; + return { + url : function(parameters) + { + return url.replace(':realm', parameters.realm).replace(':alias', parameters.alias); + } + } +}); + +module.factory('IdentityProviderFactory', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/identity-provider/providers/:provider_id', { + realm : '@realm', + provider_id : '@provider_id' + }); +}); + +module.factory('IdentityProviderMapperTypes', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/identity-provider/instances/:alias/mapper-types', { + realm : '@realm', + alias : '@alias' + }); +}); + +module.factory('IdentityProviderMappers', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/identity-provider/instances/:alias/mappers', { + realm : '@realm', + alias : '@alias' + }); +}); + +module.factory('IdentityProviderMapper', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/identity-provider/instances/:alias/mappers/:mapperId', { + realm : '@realm', + alias : '@alias', + mapperId: '@mapperId' + }, { + update: { + method : 'PUT' + } + }); +}); + +module.factory('AuthenticationFlowExecutions', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:alias/executions', { + realm : '@realm', + alias : '@alias' + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('CreateExecutionFlow', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:alias/executions/flow', { + realm : '@realm', + alias : '@alias' + }); +}); + +module.factory('CreateExecution', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:alias/executions/execution', { + realm : '@realm', + alias : '@alias' + }); +}); + +module.factory('AuthenticationFlows', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:flow', { + realm : '@realm', + flow: '@flow' + }); +}); + +module.factory('AuthenticationFormProviders', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/form-providers', { + realm : '@realm' + }); +}); + +module.factory('AuthenticationFormActionProviders', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/form-action-providers', { + realm : '@realm' + }); +}); + +module.factory('AuthenticatorProviders', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/authenticator-providers', { + realm : '@realm' + }); +}); + +module.factory('ClientAuthenticatorProviders', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/client-authenticator-providers', { + realm : '@realm' + }); +}); + + +module.factory('AuthenticationFlowsCopy', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:alias/copy', { + realm : '@realm', + alias : '@alias' + }); +}); + +module.factory('AuthenticationFlowsUpdate', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:flow', { + realm : '@realm', + flow : '@flow' + }, { + update : { + method : 'PUT' + } + }); +}); + + +module.factory('AuthenticationConfigDescription', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/config-description/:provider', { + realm : '@realm', + provider: '@provider' + }); +}); +module.factory('PerClientAuthenticationConfigDescription', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/per-client-config-description', { + realm : '@realm' + }); +}); + +module.factory('AuthenticationConfig', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/config/:config', { + realm : '@realm', + config: '@config' + }, { + update: { + method : 'PUT' + } + }); +}); +module.factory('AuthenticationExecutionConfig', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/executions/:execution/config', { + realm : '@realm', + execution: '@execution' + }); +}); + +module.factory('AuthenticationExecution', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/executions/:execution', { + realm : '@realm', + execution : '@execution' + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('AuthenticationExecutionRaisePriority', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/executions/:execution/raise-priority', { + realm : '@realm', + execution : '@execution' + }); +}); + +module.factory('AuthenticationExecutionLowerPriority', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/executions/:execution/lower-priority', { + realm : '@realm', + execution : '@execution' + }); +}); + + + +module.service('SelectRoleDialog', function($modal) { + var dialog = {}; + + var openDialog = function(title, message, btns) { + var controller = function($scope, $modalInstance, title, message, btns) { + $scope.title = title; + $scope.message = message; + $scope.btns = btns; + + $scope.ok = function () { + $modalInstance.close(); + }; + $scope.cancel = function () { + $modalInstance.dismiss('cancel'); + }; + }; + + return $modal.open({ + templateUrl: resourceUrl + '/templates/kc-modal.html', + controller: controller, + resolve: { + title: function() { + return title; + }, + message: function() { + return message; + }, + btns: function() { + return btns; + } + } + }).result; + } + + var escapeHtml = function(str) { + var div = document.createElement('div'); + div.appendChild(document.createTextNode(str)); + return div.innerHTML; + }; + + dialog.confirmDelete = function(name, type, success) { + var title = 'Delete ' + escapeHtml(type.charAt(0).toUpperCase() + type.slice(1)); + var msg = 'Are you sure you want to permanently delete the ' + type + ' ' + name + '?'; + var btns = { + ok: { + label: 'Delete', + cssClass: 'btn btn-danger' + }, + cancel: { + label: 'Cancel', + cssClass: 'btn btn-default' + } + } + + openDialog(title, msg, btns).then(success); + } + + dialog.confirmGenerateKeys = function(name, type, success) { + var title = 'Generate new keys for realm'; + var msg = 'Are you sure you want to permanently generate new keys for ' + name + '?'; + var btns = { + ok: { + label: 'Generate Keys', + cssClass: 'btn btn-danger' + }, + cancel: { + label: 'Cancel', + cssClass: 'btn btn-default' + } + } + + openDialog(title, msg, btns).then(success); + } + + dialog.confirm = function(title, message, success, cancel) { + var btns = { + ok: { + label: title, + cssClass: 'btn btn-danger' + }, + cancel: { + label: 'Cancel', + cssClass: 'btn btn-default' + } + } + + openDialog(title, message, btns).then(success, cancel); + } + + return dialog +}); + +module.factory('Group', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/groups/:groupId', { + realm : '@realm', + userId : '@groupId' + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('GroupChildren', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/groups/:groupId/children', { + realm : '@realm', + groupId : '@groupId' + }); +}); + +module.factory('GroupsCount', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/groups/count', { + realm : '@realm' + }, + { + query: { + isArray: false, + method: 'GET', + params: {}, + transformResponse: function (data) { + return angular.fromJson(data) + } + } + }); +}); + +module.factory('Groups', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/groups', { + realm : '@realm' + }) +}); + +module.factory('GroupRealmRoleMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/groups/:groupId/role-mappings/realm', { + realm : '@realm', + groupId : '@groupId' + }); +}); + +module.factory('GroupCompositeRealmRoleMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/groups/:groupId/role-mappings/realm/composite', { + realm : '@realm', + groupId : '@groupId' + }); +}); + +module.factory('GroupAvailableRealmRoleMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/groups/:groupId/role-mappings/realm/available', { + realm : '@realm', + groupId : '@groupId' + }); +}); + + +module.factory('GroupClientRoleMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/groups/:groupId/role-mappings/clients/:client', { + realm : '@realm', + groupId : '@groupId', + client : "@client" + }); +}); + +module.factory('GroupAvailableClientRoleMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/groups/:groupId/role-mappings/clients/:client/available', { + realm : '@realm', + groupId : '@groupId', + client : "@client" + }); +}); + +module.factory('GroupCompositeClientRoleMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/groups/:groupId/role-mappings/clients/:client/composite', { + realm : '@realm', + groupId : '@groupId', + client : "@client" + }); +}); + +module.factory('GroupMembership', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/groups/:groupId/members', { + realm : '@realm', + groupId : '@groupId' + }); +}); + +module.factory('RoleList', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/roles', { + realm : '@realm' + }); +}); + +module.factory('RoleMembership', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/roles/:role/users', { + realm : '@realm', + role : '@role' + }); +}); + +module.factory('ClientRoleList', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/roles', { + realm : '@realm', + client : '@client' + }); +}); + +module.factory('ClientRoleMembership', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/clients/:client/roles/:role/users', { + realm : '@realm', + client : '@client', + role : '@role' + }); +}); + +module.factory('UserGroupMembership', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:userId/groups', { + realm : '@realm', + userId : '@userId' + }); +}); + +module.factory('UserGroupMapping', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:userId/groups/:groupId', { + realm : '@realm', + userId : '@userId', + groupId : '@groupId' + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('UserProfile', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/profile', { + realm : '@realm' + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('DefaultGroups', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/default-groups/:groupId', { + realm : '@realm', + groupId : '@groupId' + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('SubComponentTypes', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/components/:componentId/sub-component-types', { + realm: '@realm', + componentId: '@componentId' + }); +}); + +module.factory('Components', function($resource, ComponentUtils) { + return $resource(authUrl + '/admin/realms/:realm/components/:componentId', { + realm : '@realm', + componentId : '@componentId' + }, { + update : { + method : 'PUT', + transformRequest: function(componentInstance) { + + if (componentInstance.config) { + ComponentUtils.removeLastEmptyValue(componentInstance.config); + } + + return angular.toJson(componentInstance); + } + }, + save : { + method : 'POST', + transformRequest: function(componentInstance) { + + if (componentInstance.config) { + ComponentUtils.removeLastEmptyValue(componentInstance.config); + } + + return angular.toJson(componentInstance); + } + } + }); +}); + +module.factory('UserStorageOperations', function($resource) { + var object = {} + object.sync = $resource(authUrl + '/admin/realms/:realm/user-storage/:componentId/sync', { + realm : '@realm', + componentId : '@componentId' + }); + object.removeImportedUsers = $resource(authUrl + '/admin/realms/:realm/user-storage/:componentId/remove-imported-users', { + realm : '@realm', + componentId : '@componentId' + }); + object.unlinkUsers = $resource(authUrl + '/admin/realms/:realm/user-storage/:componentId/unlink-users', { + realm : '@realm', + componentId : '@componentId' + }); + object.simpleName = $resource(authUrl + '/admin/realms/:realm/user-storage/:componentId/name', { + realm : '@realm', + componentId : '@componentId' + }); + return object; +}); + + +module.factory('ClientStorageOperations', function($resource) { + var object = {} + object.simpleName = $resource(authUrl + '/admin/realms/:realm/client-storage/:componentId/name', { + realm : '@realm', + componentId : '@componentId' + }); + return object; +}); + + +module.factory('ClientRegistrationPolicyProviders', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/client-registration-policy/providers', { + realm : '@realm', + }); +}); + +module.factory('ClientPoliciesProfiles', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/client-policies/profiles?include-global-profiles=:includeGlobalProfiles', { + realm : '@realm', + includeGlobalProfiles : '@includeGlobalProfiles' + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('ClientPolicies', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/client-policies/policies', { + realm : '@realm', + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('LDAPMapperSync', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/user-storage/:parentId/mappers/:mapperId/sync', { + realm : '@realm', + componentId : '@componentId', + mapperId: '@mapperId' + }); +}); + + +module.factory('UserGroupMembershipCount', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/users/:userId/groups/count', { + realm : '@realm', + userId : '@userId' + }, + { + query: { + isArray: false, + method: 'GET', + params: {}, + transformResponse: function (data) { + return angular.fromJson(data) + } + } + }); +}); diff --git a/keycloak-themes/base/admin/resources/partials/authentication-flow-bindings.html b/keycloak-themes/base/admin/resources/partials/authentication-flow-bindings.html new file mode 100644 index 0000000..6bf39f3 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authentication-flow-bindings.html @@ -0,0 +1,83 @@ +
+

{{:: 'authentication' | translate}}

+ + + +
+
+ +
+
+ +
+
+ {{:: 'browser-flow.tooltip' | translate}} +
+
+ +
+
+ +
+
+ {{:: 'registration-flow.tooltip' | translate}} +
+
+ +
+
+ +
+
+ {{:: 'direct-grant-flow.tooltip' | translate}} +
+ +
+ +
+
+ +
+
+ {{:: 'reset-credentials.tooltip' | translate}} +
+ +
+ +
+
+ +
+
+ {{:: 'client-authentication.tooltip' | translate}} +
+ + +
+ +
+
+ +
+
+ {{:: 'docker-auth.tooltip' | translate}} +
+ +
+
+ + +
+
+
+ +
+ + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authentication-flows.html b/keycloak-themes/base/admin/resources/partials/authentication-flows.html new file mode 100644 index 0000000..eb8e721 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authentication-flows.html @@ -0,0 +1,72 @@ +
+

{{:: 'authentication' | translate}}

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +    +
+ + + + + + +
+
{{:: 'auth-type' | translate}}{{:: 'requirement' | translate}} 
+ + + {{execution.displayName|capitalize}}({{execution.alias}}) +    + + + + + +
{{:: 'no-executions-available' | translate}}
+
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authenticator-config.html b/keycloak-themes/base/admin/resources/partials/authenticator-config.html new file mode 100644 index 0000000..1b34406 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authenticator-config.html @@ -0,0 +1,52 @@ +
+ + + +

{{:: 'create-authenticator-config' | translate}}

+

+ {{config.alias|capitalize}} + {{config.id}} + +

+ +
+
+
+ +
+ +
+
+
+ +
+ +
+ {{:: 'authenticator.alias.tooltip' | translate}} +
+ +
+ +
+
+ + +
+
+ +
+
+ + +
+
+
+
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/mgmt/broker-permissions.html b/keycloak-themes/base/admin/resources/partials/authz/mgmt/broker-permissions.html new file mode 100644 index 0000000..2e389ff --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/mgmt/broker-permissions.html @@ -0,0 +1,40 @@ +
+ + + + +
+
+
+ +
+ +
+ {{:: 'permissions-enabled-role.tooltip' | translate}} +
+
+
+ + + + + + + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/mgmt/client-permissions.html b/keycloak-themes/base/admin/resources/partials/authz/mgmt/client-permissions.html new file mode 100644 index 0000000..7f29fd7 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/mgmt/client-permissions.html @@ -0,0 +1,39 @@ +
+ + + + +
+
+
+ +
+ +
+ {{:: 'permissions-enabled-role.tooltip' | translate}} +
+
+
+ + + + + + + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/mgmt/client-role-permissions.html b/keycloak-themes/base/admin/resources/partials/authz/mgmt/client-role-permissions.html new file mode 100644 index 0000000..c76ecec --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/mgmt/client-role-permissions.html @@ -0,0 +1,40 @@ +
+ + + + +
+
+
+ +
+ +
+ {{:: 'permissions-enabled-role.tooltip' | translate}} +
+
+
+ + + + + + + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/mgmt/group-permissions.html b/keycloak-themes/base/admin/resources/partials/authz/mgmt/group-permissions.html new file mode 100644 index 0000000..f2be6d9 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/mgmt/group-permissions.html @@ -0,0 +1,39 @@ +
+ + + + +
+
+
+ +
+ +
+ {{:: 'permissions-enabled-role.tooltip' | translate}} +
+
+
+ + + + + + + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/mgmt/realm-role-permissions.html b/keycloak-themes/base/admin/resources/partials/authz/mgmt/realm-role-permissions.html new file mode 100644 index 0000000..e21ee63 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/mgmt/realm-role-permissions.html @@ -0,0 +1,39 @@ +
+ + + + +
+
+
+ +
+ +
+ {{:: 'permissions-enabled-role.tooltip' | translate}} +
+
+
+ + + + + + + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/mgmt/users-permissions.html b/keycloak-themes/base/admin/resources/partials/authz/mgmt/users-permissions.html new file mode 100644 index 0000000..2665bba --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/mgmt/users-permissions.html @@ -0,0 +1,35 @@ +
+ + + +
+
+
+ +
+ +
+ {{:: 'permissions-enabled-users.tooltip' | translate}} +
+
+
+ + + + + + + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/permission/provider/resource-server-policy-resource-detail.html b/keycloak-themes/base/admin/resources/partials/authz/permission/provider/resource-server-policy-resource-detail.html new file mode 100644 index 0000000..af5aace --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/permission/provider/resource-server-policy-resource-detail.html @@ -0,0 +1,131 @@ +
+ + + +

{{:: 'authz-add-resource-permission' | translate}}

+

{{originalPolicy.name|capitalize}}

+ +
+
+
+ +
+ +
+ {{:: 'authz-permission-name.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-permission-description.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-permission-resource-apply-to-resource-type.tooltip' | translate}} +
+
+ + +
+ +
+ {{:: 'authz-permission-resource-resource.tooltip' | translate}} +
+
+ + +
+ +
+ + {{:: 'authz-permission-resource-type.tooltip' | translate}} +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+
+
+
+
+ +
+
{{:: 'name' | translate}}{{:: 'description' | translate}}{{:: 'actions' | translate}}
{{policy.name}}{{policy.name}}{{policy.description}} + {{:: 'remove' | translate}} +
{{:: 'authz-no-policies-assigned' | translate}}
+
+ {{:: 'authz-policy-apply-policy.tooltip' | translate}} +
+
+ + +
+ +
+ + {{:: 'authz-policy-decision-strategy.tooltip' | translate}} +
+ +
+ +
+
+ + +
+
+
+
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/permission/provider/resource-server-policy-scope-detail.html b/keycloak-themes/base/admin/resources/partials/authz/permission/provider/resource-server-policy-scope-detail.html new file mode 100644 index 0000000..17ee7cb --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/permission/provider/resource-server-policy-scope-detail.html @@ -0,0 +1,134 @@ +
+ + + +

{{:: 'authz-add-scope-permission' | translate}}

+

{{originalPolicy.name|capitalize}}

+ +
+
+
+ +
+ +
+ {{:: 'authz-permission-name.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-permission-description.tooltip' | translate}} +
+
+ + +
+ +
+ {{:: 'authz-permission-scope-resource.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-permission-scope-scope.tooltip' | translate}} +
+
+ + +
+ +
+ {{:: 'authz-permission-scope-scope.tooltip' | translate}} +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+
+
+
+
+ +
+
{{:: 'name' | translate}}{{:: 'description' | translate}}{{:: 'actions' | translate}}
{{policy.name}}{{policy.name}}{{policy.description}} + {{:: 'remove' | translate}} +
{{:: 'authz-no-policies-assigned' | translate}}
+
+ {{:: 'authz-policy-apply-policy.tooltip' | translate}} +
+
+ + +
+ +
+ + {{:: 'authz-policy-decision-strategy.tooltip' | translate}} +
+ +
+
+
+ + +
+
+
+
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/permission/resource-server-permission-list.html b/keycloak-themes/base/admin/resources/partials/authz/permission/resource-server-permission-list.html new file mode 100644 index 0000000..40dfacd --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/permission/resource-server-permission-list.html @@ -0,0 +1,118 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ {{:: 'filter' | translate}}:   +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+
+ +
+
+
{{:: 'name' | translate}}{{:: 'description' | translate}}{{:: 'type' | translate}}{{:: 'actions' | translate}}
+
+ + + +
+
+ + + {{policy.name}}{{policy.description}}{{policy.type}} + +
+
+
+ +
+
+
+
+
{{:: 'authz-associated-policies' | translate}}
+
+ {{:: 'authz-no-policies-available' | translate}} + {{dep.name}}{{$last ? '' : ', '}} +
+
+
+
+
+
{{:: 'no-results' | translate}}{{:: 'authz-no-permissions-available' | translate}}
+
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html new file mode 100644 index 0000000..25be65b --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html @@ -0,0 +1,123 @@ +
+ + + +

{{:: 'authz-add-aggregated-policy' | translate}}

+

{{originalPolicy.name|capitalize}}

+ +
+
+
+ +
+ +
+ {{:: 'authz-policy-name.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-policy-description.tooltip' | translate}} +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+
+
+
+
+ +
+
{{:: 'name' | translate}}{{:: 'description' | translate}}{{:: 'actions' | translate}}
{{policy.name}}{{policy.name}}{{policy.description}} + {{:: 'remove' | translate}} +
{{:: 'authz-no-policies-assigned' | translate}}
+
+ {{:: 'authz-policy-apply-policy.tooltip' | translate}} +
+
+ +
+ +
+ + {{:: 'authz-policy-decision-strategy.tooltip' | translate}} +
+
+ + +
+ +
+ + {{:: 'authz-policy-logic.tooltip' | translate}} +
+ +
+ +
+
+ + +
+
+
+
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-client-detail.html b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-client-detail.html new file mode 100644 index 0000000..9c5630a --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-client-detail.html @@ -0,0 +1,93 @@ +
+ + + +

{{:: 'authz-add-client-policy' | translate}}

+

{{originalPolicy.name|capitalize}}

+ +
+
+
+ +
+ +
+ {{:: 'authz-policy-name.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-policy-description.tooltip' | translate}} +
+
+ + +
+ + +
+ {{:: 'authz-policy-client-clients.tooltip' | translate}} +
+
+ +
+ + + + + + + + + + + + + + + + +
{{:: 'clientId' | translate}}{{:: 'actions' | translate}}
{{client.clientId}} + +
{{:: 'authz-no-clients-assigned' | translate}}
+
+
+
+ + +
+ +
+ + {{:: 'authz-policy-logic.tooltip' | translate}} +
+ +
+ +
+
+ + +
+
+
+
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-client-scope-detail.html b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-client-scope-detail.html new file mode 100644 index 0000000..e48f550 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-client-scope-detail.html @@ -0,0 +1,126 @@ + + +
+ + + +

{{:: 'authz-add-client-scope-policy' | translate}}

+

+ {{originalPolicy.name|capitalize}} +

+ +
+
+
+ +
+ +
+ {{:: 'authz-policy-name.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-policy-description.tooltip' | translate}} +
+
+ + +
+ +
+ + {{:: 'authz-policy-client-scope-client-scopes.tooltip' | translate}} +
+
+ +
+ + + + + + + + + + + + + + + + + + +
{{:: 'name' | translate}}{{:: 'authz-required' | translate}}{{:: 'actions' | translate}}
{{clientScope.name}} + +
{{:: 'authz-no-client-scopes-assigned' | translate}}
+
+
+
+ + +
+ +
+ + {{:: 'authz-policy-logic.tooltip' | translate}} +
+ +
+
+
+ + +
+
+
+
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-group-detail.html b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-group-detail.html new file mode 100644 index 0000000..cc1353b --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-group-detail.html @@ -0,0 +1,126 @@ + + +
+ + + +

{{:: 'authz-add-group-policy' | translate}}

+

{{originalPolicy.name|capitalize}}

+ +
+
+
+ +
+ +
+ {{:: 'authz-policy-name.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-policy-description.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-policy-group-claim.tooltip' | translate}} +
+
+ +
+
+
+ + +
+ {{:: 'authz-policy-user-users.tooltip' | translate}} +
+
+ +
+ + + + + + + + + + + + + + + + + + +
{{:: 'path' | translate}}Extend to Children{{:: 'actions' | translate}}
{{group.path}} + + + +
{{:: 'authz-no-groups-assigned' | translate}}
+
+
+
+ + +
+ +
+ + {{:: 'authz-policy-logic.tooltip' | translate}} +
+ +
+
+
+ + +
+
+
+
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-js-detail.html b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-js-detail.html new file mode 100644 index 0000000..a0eb0d9 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-js-detail.html @@ -0,0 +1,68 @@ +
+ + + +

{{:: 'authz-add-js-policy' | translate}}

+

{{originalPolicy.name|capitalize}}

+ +
+
+
+ +
+ +
+ {{:: 'authz-policy-name.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-policy-description.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-policy-js-code.tooltip' | translate}} +
+
+ + +
+ +
+ + {{:: 'authz-policy-logic.tooltip' | translate}} +
+ +
+ +
+
+ + +
+
+
+
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-regex-detail.html b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-regex-detail.html new file mode 100644 index 0000000..83c6bbf --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-regex-detail.html @@ -0,0 +1,100 @@ + + +
+ + + +

{{:: 'authz-add-regex-policy' | translate}}

+

+ {{originalPolicy.name|capitalize}} +

+ +
+
+
+ +
+ +
+ {{:: 'authz-policy-name.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-policy-description.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-policy-target-claim.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-policy-regex-pattern.tooltip' | translate}} +
+
+ + +
+ +
+ + {{:: 'authz-policy-logic.tooltip' | translate}} +
+ +
+
+
+ + +
+
+
+
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-role-detail.html b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-role-detail.html new file mode 100644 index 0000000..9448682 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-role-detail.html @@ -0,0 +1,169 @@ + + +
+ + + +

{{:: 'authz-add-role-policy' | translate}}

+

{{originalPolicy.name|capitalize}}

+ +
+
+
+ +
+ +
+ {{:: 'authz-policy-name.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-policy-description.tooltip' | translate}} +
+
+ + +
+ +
+ + {{:: 'authz-policy-role-realm-roles.tooltip' | translate}} +
+
+ +
+ + + + + + + + + + + + + + + + + + +
{{:: 'name' | translate}}{{:: 'authz-required' | translate}}{{:: 'actions' | translate}}
{{role.name}} + +
{{:: 'authz-no-roles-assigned' | translate}}
+
+
+
+ + +
+ +
+ {{:: 'authz-policy-role-clients.tooltip' | translate}} +
+
+ + +
+ +
+ + {{:: 'authz-policy-role-client-roles.tooltip' | translate}} +
+
+ +
+ + + + + + + + + + + + + + + + + + + + +
{{:: 'name' | translate}}{{:: 'client' | translate}}{{:: 'authz-required' | translate}}{{:: 'actions' | translate}}
{{role.name}}{{role.container.name}} + +
{{:: 'authz-no-roles-assigned' | translate}}
+
+
+
+ + +
+ +
+ + {{:: 'authz-policy-logic.tooltip' | translate}} +
+ +
+
+
+ + +
+
+ {{policyState.page.previous}} +
+
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-time-detail.html b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-time-detail.html new file mode 100644 index 0000000..4af9014 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-time-detail.html @@ -0,0 +1,119 @@ + +
+ + + + +

{{:: 'authz-add-time-policy' | translate}}

+

{{originalPolicy.name|capitalize}}

+ +
+
+
+ +
+ +
+ {{:: 'authz-policy-name.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-policy-description.tooltip' | translate}} +
+
+ + +
+ +
+ {{:: 'authz-policy-time-not-before.tooltip' | translate}} +
+
+ + +
+ +
+ {{:: 'authz-policy-time-not-on-after.tooltip' | translate}} +
+
+ + +
+   to   +
+ {{:: 'authz-policy-time-day-month.tooltip' | translate}} +
+
+ + +
+   to   +
+ {{:: 'authz-policy-time-month.tooltip' | translate}} +
+
+ + +
+   to   +
+ {{:: 'authz-policy-time-year.tooltip' | translate}} +
+
+ + +
+   to   +
+ {{:: 'authz-policy-time-hour.tooltip' | translate}} +
+
+ + +
+   to   +
+ {{:: 'authz-policy-time-minute.tooltip' | translate}} +
+
+ + +
+ +
+ + {{:: 'authz-policy-logic.tooltip' | translate}} +
+ +
+ +
+
+ + +
+
+
+
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-user-detail.html b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-user-detail.html new file mode 100644 index 0000000..80d81ac --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/policy/provider/resource-server-policy-user-detail.html @@ -0,0 +1,93 @@ +
+ + + +

{{:: 'authz-add-user-policy' | translate}}

+

{{originalPolicy.name|capitalize}}

+ +
+
+
+ +
+ +
+ {{:: 'authz-policy-name.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'authz-policy-description.tooltip' | translate}} +
+
+ + +
+ + +
+ {{:: 'authz-policy-user-users.tooltip' | translate}} +
+
+ +
+ + + + + + + + + + + + + + + + +
{{:: 'username' | translate}}{{:: 'actions' | translate}}
{{user.username}} + +
{{:: 'authz-no-users-assigned' | translate}}
+
+
+
+ + +
+ +
+ + {{:: 'authz-policy-logic.tooltip' | translate}} +
+ +
+ +
+
+ + +
+
+
+
+ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/policy/resource-server-policy-evaluate-result.html b/keycloak-themes/base/admin/resources/partials/authz/policy/resource-server-policy-evaluate-result.html new file mode 100644 index 0000000..19ff720 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/policy/resource-server-policy-evaluate-result.html @@ -0,0 +1,72 @@ +
+
+ {{:: 'authz-evaluation-no-result' | translate}} +
+ {{result.resource.name}} + +
+ + +
+
+ {{result.status}} + {{result.status}} +
+
+ {{:: 'authz-evaluation-result.tooltip' | translate}} +
+
+ + +
+ {{:: 'authz-no-scopes-available' | translate}} + +
+
    +
  • + {{scope.name}} +
  • +
+
+
+ {{:: 'authz-evaluation-scopes.tooltip' | translate}} +
+
+ + +
+ {{:: 'authz-evaluation-no-policies-resource' | translate}} +
+
+
  • + + {{policyResult.policy.name}} + + {{policyResult.policy.description}} + + + decision was {{policyResult.status}} + {{policyResult.status}} + by {{policyResult.policy.decisionStrategy}} decision. {{policyResult.policy.scopes.length > 0 ? (policyResult.status == 'DENY' ? 'Denied Scopes:' : 'Granted Scopes:') : ''}} {{scope}}{{$last ? '' : ', '}}{{policyResult.policy.scopes.length > 0 ? '.' : ''}} + +
  • + +
    +
    + {{:: 'authz-evaluation-policies.tooltip' | translate}} +
    +
    +
    +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/policy/resource-server-policy-evaluate.html b/keycloak-themes/base/admin/resources/partials/authz/policy/resource-server-policy-evaluate.html new file mode 100644 index 0000000..aedbdea --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/policy/resource-server-policy-evaluate.html @@ -0,0 +1,267 @@ +
    + + + + + + + + + +
    +
    + +
    + +
    + {{:: 'authz-evaluation-authorization-data.tooltip' | translate}} +
    +
    + +
    +
    +
    +
    + {{:: 'authz-evaluation-identity-information' | translate}} + {{:: 'authz-evaluation-identity-information.tooltip' | translate}} + +
    + + +
    +
    + +
    +
    + {{:: 'authz-evaluation-client.tooltip' | translate}} +
    +
    + + +
    + + +
    + + {{:: 'authz-evaluation-user.tooltip' | translate}} +
    + +
    + + +
    + +
    + + {{:: 'authz-evaluation-role.tooltip' | translate}} +
    +
    +
    + {{:: 'authz-evaluation-contextual-info' | translate}} + {{:: 'authz-evaluation-contextual-info.tooltip' | translate}} + +
    + + +
    + + + + + + + + + + + + + + + + + + + + +
    {{:: 'key' | translate}}{{:: 'value' | translate}}{{:: 'actions' | translate}}
    {{getContextAttributeName(key)}} + + + + +
    + + + + + + + +
    +
    + + {{:: 'authz-evaluation-contextual-attributes.tooltip' | translate}} +
    +
    +
    + {{:: 'authz-permissions' | translate}} + {{:: 'authz-evaluation-permissions.tooltip' | translate}} + +
    + + +
    + +
    + {{:: 'authz-permission-resource-apply-to-resource-type.tooltip' | translate}} + +
    +
    + + +
    + +
    + {{:: 'authz-permission-resource-resource.tooltip' | translate}} +
    +
    + + +
    + +
    + + {{:: 'authz-permission-resource-type.tooltip' | translate}} +
    +
    + + +
    + +
    + + {{:: 'authz-permission-scope-scope.tooltip' | translate}} +
    +
    + + +
    + +
    + + {{:: 'authz-permission-scope-scope.tooltip' | translate}} +
    +
    + + +
    + + + + + + + + + + + + + + + + + + + +
    {{:: 'authz-resource' | translate}}{{:: 'authz-scopes' | translate}}{{:: 'actions' | translate}}
    + {{:: 'authz-no-resources' | translate}} +
    {{resource.name ? resource.name : 'authz-evaluation-any-resource-with-scopes' | translate}} + {{:: 'authz-any-scope' | translate}}. + + + {{scope.name ? scope.name : scope}} {{$last ? '' : ', '}} + + + + +
    +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/policy/resource-server-policy-list.html b/keycloak-themes/base/admin/resources/partials/authz/policy/resource-server-policy-list.html new file mode 100644 index 0000000..d142c44 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/policy/resource-server-policy-list.html @@ -0,0 +1,117 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + {{:: 'filter' | translate}}:   +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    +
    {{:: 'name' | translate}}{{:: 'description' | translate}}{{:: 'type' | translate}}{{:: 'actions' | translate}}
    +
    + + + +
    +
    + + + {{policy.name}}{{policy.description}}{{policy.type}} + +
    +
    +
    + +
    +
    +
    +
    +
    Dependent Permissions
    +
    + {{:: 'authz-no-policies-available' | translate}} + {{dep.name}}{{$last ? '' : ', '}} +
    +
    +
    +
    +
    +
    {{:: 'no-results' | translate}}{{:: 'authz-no-policies-available' | translate}}
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/authz/resource-server-detail.html b/keycloak-themes/base/admin/resources/partials/authz/resource-server-detail.html new file mode 100644 index 0000000..5bf7d88 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/resource-server-detail.html @@ -0,0 +1,77 @@ +
    + + + + + +
    +
    +
    + +
    +
    + + +
    +
    + +
    +
    + {{:: 'authz-import-config.tooltip' | translate}} +
    +
    +
    + + +
    +
    +
    +
    +
    + +
    + +
    + {{:: 'authz-policy-enforcement-mode.tooltip' | translate}} +
    +
    + + +
    + +
    + + {{:: 'authz-server-decision-strategy.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'authz-remote-resource-management.tooltip' | translate}} +
    +
    +
    + + +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/resource-server-export-settings.html b/keycloak-themes/base/admin/resources/partials/authz/resource-server-export-settings.html new file mode 100644 index 0000000..86505db --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/resource-server-export-settings.html @@ -0,0 +1,35 @@ +
    + + + + + +
    +
    +
    + +
    + + + +
    + {{:: 'authz-export-settings.tooltip' | translate}} +
    +
    +
    +
    + {{:: 'download' | translate}} + +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/resource-server-list.html b/keycloak-themes/base/admin/resources/partials/authz/resource-server-list.html new file mode 100644 index 0000000..3b4130e --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/resource-server-list.html @@ -0,0 +1,49 @@ +
    +

    + Resource Servers + Resource Servers are applications serving resources to their users. These resources can be a RESTFul API, web pages or any other kind of resource that must be managed and protected by a set of authorization policies. +

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + Create +
    +
    +
    NamePolicy Enforcement ModeAllows Remote Resource Management ?Allows Entitlement ?
    {{server.name}}{{server.policyEnforcementMode | toCamelCase}}{{server.allowRemoteResourceManagement}}{{server.allowEntitlements}}
    No resultsNo servers available
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/resource-server-resource-detail.html b/keycloak-themes/base/admin/resources/partials/authz/resource-server-resource-detail.html new file mode 100644 index 0000000..b3d6eca --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/resource-server-resource-detail.html @@ -0,0 +1,126 @@ +
    + + + +

    {{:: 'authz-add-resource' | translate}}

    +

    {{originalResource.name|capitalize}}

    + +
    +
    +
    + +
    + +
    + {{:: 'authz-resource-name.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'authz-resource-name.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'authz-resource-owner.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'authz-resource-type.tooltip' | translate}} +
    +
    + +
    +
    + +
    + +
    +
    + +
    + +
    + +
    +
    +
    + {{:: 'authz-resource-uri.tooltip' | translate}} +
    +
    + + +
    + +
    + + {{:: 'authz-resource-scopes.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'authz-icon-uri.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'authz-resource-user-managed-access-enabled.tooltip' | translate}} +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + +
    {{:: 'key' | translate}}{{:: 'value' | translate}}{{:: 'actions' | translate}}
    {{key}}{{:: 'delete' | translate}}
    {{:: 'add' | translate}}
    +
    + {{:: 'authz-resource-attributes.tooltip' | translate}} +
    +
    + +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/resource-server-resource-list.html b/keycloak-themes/base/admin/resources/partials/authz/resource-server-resource-list.html new file mode 100644 index 0000000..dce000e --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/resource-server-resource-list.html @@ -0,0 +1,169 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + {{:: 'filter' | translate}}:   +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    {{:: 'name' | translate}}{{:: 'type' | translate}}{{:: 'authz-uris' | translate}}{{:: 'authz-owner' | translate}}{{:: 'actions' | translate}}
    +
    + + + +
    +
    + + + + {{resource.name}} + + {{resource.type}} + {{:: 'authz-no-type-defined' | translate}} + + {{:: 'authz-no-uri-defined' | translate}} + {{resource.uris[0]}} + {{resource.uris.length}} {{:: 'authz-uris' | translate}} + {{resource.owner.name}} + +
    +
    +
    + +
    +
    +
    +
    +
    {{:: 'authz-scopes' | translate}}
    +
    + {{:: 'authz-no-scopes-assigned' | translate}} + {{scope.name}}{{$last ? '' : ', '}} +
    +
    {{:: 'authz-associated-permissions' | translate}}
    +
    + {{:: 'authz-no-permission-assigned' | translate}} + {{policy.name}}{{$last ? '' : ', '}} +
    +
    {{:: 'authz-uris' | translate}}
    +
    + {{:: 'authz-no-uri-defined' | translate}} + {{uri}}{{$last ? '' : ', '}} +
    +
    +
    +
    +
    +
    {{:: 'no-results' | translate}}{{:: 'authz-no-resources-available' | + translate}} +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/authz/resource-server-scope-detail.html b/keycloak-themes/base/admin/resources/partials/authz/resource-server-scope-detail.html new file mode 100644 index 0000000..d296abd --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/resource-server-scope-detail.html @@ -0,0 +1,50 @@ +
    + + + +

    {{:: 'authz-add-scope' | translate}}

    +

    {{originalScope.name|capitalize}}

    + +
    +
    +
    + +
    + +
    + {{:: 'authz-scope-name.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'authz-scope-name.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'authz-icon-uri.tooltip' | translate}} +
    +
    + +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/authz/resource-server-scope-list.html b/keycloak-themes/base/admin/resources/partials/authz/resource-server-scope-list.html new file mode 100644 index 0000000..22c7f38 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/authz/resource-server-scope-list.html @@ -0,0 +1,102 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    {{:: 'name' | translate}}{{:: 'actions' | translate}}
    +
    + + + +
    +
    + + + {{scope.name}} + +
    +
    +
    + +
    +
    +
    +
    +
    {{:: 'authz-resources' | translate}}
    +
    + {{:: 'authz-no-resources-assigned' | translate}} + {{resource.name}}{{$last ? '' : ', '}} +
    +
    {{:: 'authz-associated-permissions' | translate}}
    +
    + {{:: 'authz-no-permission-assigned' | translate}} + {{policy.name}}{{$last ? '' : ', '}} +
    +
    +
    +
    +
    +
    {{:: 'no-results' | translate}}{{:: 'authz-no-scopes-available' | translate}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/brute-force.html b/keycloak-themes/base/admin/resources/partials/brute-force.html new file mode 100644 index 0000000..6ab0092 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/brute-force.html @@ -0,0 +1,114 @@ +
    + + + + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    + {{:: 'permanent-lockout.tooltip' | translate}} +
    + +
    + + +
    + +
    + {{:: 'max-login-failures.tooltip' | translate}} +
    +
    + +
    + + +
    + {{:: 'wait-increment.tooltip' | translate}} +
    +
    + + +
    + +
    + {{:: 'quick-login-check-millis.tooltip' | translate}} +
    +
    + +
    + + +
    + {{:: 'min-quick-login-wait.tooltip' | translate}} +
    +
    + +
    + + +
    + {{:: 'max-wait.tooltip' | translate}} +
    +
    + +
    + + +
    + {{:: 'failure-reset-time.tooltip' | translate}} +
    +
    + +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/ciba-policy.html b/keycloak-themes/base/admin/resources/partials/ciba-policy.html new file mode 100644 index 0000000..bfcf591 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/ciba-policy.html @@ -0,0 +1,63 @@ +
    +

    {{:: 'authentication' | translate}}

    + + +
    + +
    + +
    +
    + +
    +
    + {{:: 'ciba-backchannel-tokendelivery-mode.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'ciba-expires-in.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'ciba-interval.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'ciba-auth-requested-user-hint.tooltip' | translate}} +
    + +
    +
    + + +
    +
    +
    + +
    + + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/claims.html b/keycloak-themes/base/admin/resources/partials/claims.html new file mode 100644 index 0000000..27357ca --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/claims.html @@ -0,0 +1,62 @@ +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-clustering-node.html b/keycloak-themes/base/admin/resources/partials/client-clustering-node.html new file mode 100644 index 0000000..56eb9db --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-clustering-node.html @@ -0,0 +1,37 @@ +
    + + +

    {{:: 'add-node' | translate}}

    +

    + {{node.host|capitalize}} + +

    + +
    +
    + +
    + +
    +
    +
    + +
    + {{node.lastRegistration}} +
    +
    +
    +
    + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-clustering.html b/keycloak-themes/base/admin/resources/partials/client-clustering.html new file mode 100644 index 0000000..72ff437 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-clustering.html @@ -0,0 +1,76 @@ +
    + + + + + +
    + {{:: 'basic-configuration' | translate}} +
    +
    + +
    +
    +
    + + +
    +
    +
    + {{:: 'node-reregistration-timeout.tooltip' | translate}} +
    + +
    +
    + + +
    +
    +
    + +
    + {{:: 'registered-cluster-nodes' | translate}} + + + + + + + + + + + + + + + + + + + + + + +
    + +
    {{:: 'node-host' | translate}}{{:: 'last-registration' | translate}}{{:: 'actions' | translate}}
    {{node.host}}{{node.lastRegistration}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    {{:: 'no-registered-cluster-nodes' | translate}}
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-credentials-generic.html b/keycloak-themes/base/admin/resources/partials/client-credentials-generic.html new file mode 100644 index 0000000..39e9ebc --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-credentials-generic.html @@ -0,0 +1,14 @@ +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-credentials-jwt.html b/keycloak-themes/base/admin/resources/partials/client-credentials-jwt.html new file mode 100644 index 0000000..43a3ca7 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-credentials-jwt.html @@ -0,0 +1,26 @@ +
    + +
    + +
    +
    + +
    +
    + {{:: 'token-endpoint-auth-signing-alg.tooltip' | translate}} +
    + +
    + +
    +
    +
    {{:: 'need-to-configure-keys' | translate}}
    +
    +
    +
    + +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-credentials-secret-jwt.html b/keycloak-themes/base/admin/resources/partials/client-credentials-secret-jwt.html new file mode 100644 index 0000000..4189963 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-credentials-secret-jwt.html @@ -0,0 +1,55 @@ +
    +
    +
    + +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    + +
    + +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    + +
    + +
    +
    + +
    +
    + {{:: 'token-endpoint-auth-signing-alg.tooltip' | translate}} +
    + +
    +
    + +
    +
    + +
    +
    diff --git a/keycloak-themes/base/admin/resources/partials/client-credentials-secret.html b/keycloak-themes/base/admin/resources/partials/client-credentials-secret.html new file mode 100644 index 0000000..d1b1b80 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-credentials-secret.html @@ -0,0 +1,33 @@ +
    +
    +
    + +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    + +
    + +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    +
    diff --git a/keycloak-themes/base/admin/resources/partials/client-credentials-x509.html b/keycloak-themes/base/admin/resources/partials/client-credentials-x509.html new file mode 100644 index 0000000..6811724 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-credentials-x509.html @@ -0,0 +1,28 @@ +
    +
    +
    + + {{:: 'subjectdn-tooltip' | translate}} +
    +
    +
    + +
    +
    +
    +
    +
    + +
    + +
    + {{:: 'allow-regex-pattern-comparison.tooltip' | translate}} +
    +
    +
    + + +
    +
    +
    +
    diff --git a/keycloak-themes/base/admin/resources/partials/client-credentials.html b/keycloak-themes/base/admin/resources/partials/client-credentials.html new file mode 100644 index 0000000..e6865a3 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-credentials.html @@ -0,0 +1,38 @@ +
    + + + + + +
    +
    +
    + +
    +
    + +
    +
    + {{:: 'client-authenticator.tooltip' | translate}} +
    +
    +
    + +
    +
    + +
    + +
    +
    + +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/client-detail.html b/keycloak-themes/base/admin/resources/partials/client-detail.html new file mode 100644 index 0000000..3baadde --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-detail.html @@ -0,0 +1,1058 @@ +
    + + + + + +
    +
    +
    + +
    + +
    + {{:: 'client-id.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'client.name.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'client.description.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'client.enabled.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'alwaysDisplayInConsole.tooltip' | translate}} +
    +
    + +
    + {{originName}} +
    + {{:: 'client-origin.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'consent-required.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'client.display-on-consent-screen.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'client.consent-screen-text.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'login-theme.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'client-protocol.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'access-type.tooltip' | translate}} +
    +
    + + {{:: 'standard-flow-enabled.tooltip' | translate}} +
    + +
    +
    +
    + + {{:: 'implicit-flow-enabled.tooltip' | translate}} +
    + +
    +
    +
    + + {{:: 'direct-access-grants-enabled.tooltip' | translate}} +
    + +
    +
    +
    + + {{:: 'service-accounts-enabled.tooltip' | translate}} +
    + +
    +
    +
    + + {{:: 'oauth2-device-authorization-grant-enabled.tooltip' | translate}} +
    + +
    +
    +
    + + {{:: 'oidc-ciba-grant-enabled.tooltip' | translate}} +
    + +
    +
    +
    + + {{:: 'authz-authorization-services-enabled.tooltip' | translate}} +
    + +
    +
    +
    + +
    + +
    + {{:: 'include-authnstatement.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'include-onetimeuse-condition.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'artifact-binding.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'sign-documents.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'sign-documents-redirect-enable-key-info-ext.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'sign-assertions.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'signature-algorithm.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'saml-signature-keyName-transformer.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'canonicalization-method.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'encrypt-assertions.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'client-signature-required.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'force-post-binding.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'front-channel-logout.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'front-channel-logout-url.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'front-channel-logout-session-required.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'force-name-id-format.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'allow-ecp-flow.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'name-id-format.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'root-url.tooltip' | translate}} +
    + +
    + + +
    +
    + +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + {{:: 'valid-redirect-uris.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'base-url.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'admin-url.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'master-saml-processing-url.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'idp-sso-url-ref.urlhint' | translate}} {{samlIdpInitiatedUrl(clientEdit.attributes.saml_idp_initiated_sso_url_name)}} +
    +
    + {{:: 'idp-sso-url-ref.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'logo-uri.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'policy-uri.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'tos-uri.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'idp-sso-relay-state.tooltip' | translate}} +
    +
    + + +
    +
    + +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + {{:: 'web-origins.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'backchannel-logout-url.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'backchannel-logout-session-required.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'backchannel-logout-revoke-offline-sessions.tooltip' | translate}} +
    +
    +
    + {{:: 'fine-saml-endpoint-conf' | translate}} {{:: 'fine-saml-endpoint-conf.tooltip' | translate}} +
    + +
    + +
    + {{:: 'assertion-consumer-post-binding-url.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'assertion-consumer-redirect-binding-url.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'logout-service-post-binding-url.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'logout-service-redir-binding-url.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'logout-service-artifact-binding-url.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'artifact-binding-url.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'artifact-resolution-service-url.tooltip' | translate}} +
    +
    + +
    + {{:: 'fine-oidc-endpoint-conf' | translate}} {{:: 'fine-oidc-endpoint-conf.tooltip' | translate}} + +
    + +
    +
    + +
    +
    + {{:: 'access-token-signed-response-alg.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'id-token-signed-response-alg.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'id-token-encrypted-response-alg.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'id-token-encrypted-response-enc.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'user-info-signed-response-alg.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'user-info-encrypted-response-alg.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'user-info-encrypted-response-enc.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'request-object-signature-alg.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'request-object-encryption-alg.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'request-object-encryption-enc.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'request-object-required.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'ciba-backchannel-token-delivery-mode.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ciba-backchannel-client-notification-endpoint.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'ciba-backchannel-auth-request-signing-alg.tooltip' | translate}} +
    +
    + +
    +
    + +
    + +
    +
    + +
    + +
    + +
    +
    +
    + {{:: 'request-uris.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'authorization-signed-response-alg.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'authorization-encrypted-response-alg.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'authorization-encrypted-response-enc.tooltip' | translate}} +
    +
    + +
    + {{:: 'oidc-compatibility-modes' | translate}} {{:: 'oidc-compatibility-modes.tooltip' | translate}} +
    + +
    + +
    + {{:: 'exclude-session-state-from-auth-response.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'use-refresh-tokens.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'use-refresh-token-for-client-credentials-grant.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'use-lower-case-bearer-in-token-responses.tooltip' | translate}} +
    +
    + +
    + {{:: 'advanced-client-settings' | translate}} {{:: 'advanced-client-settings.tooltip' | translate}} + +
    + + +
    + + +
    + {{:: 'access-token-lifespan.tooltip' | translate}} +
    + +
    + + +
    + + +
    + {{:: 'saml-assertion-lifespan.tooltip' | translate}} +
    + +
    + +
    + + +
    + {{:: 'client-session-idle.tooltip' | translate}} +
    + +
    + +
    + + +
    + {{:: 'client-session-max.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'client-offline-session-idle.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'client-offline-session-max.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'oauth2-device-code-lifespan.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'oauth2-device-polling-interval.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'tls-client-certificate-bound-access-tokens.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'use-idtoken-as-detached-signature.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'pkce-code-challenge-method.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'require-pushed-authorization-requests.tooltip' | translate}} +
    + +
    + +
    +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    + {{:: 'acr-loa-map-client.tooltip' | translate}} +
    + +
    + + +
    +
    + +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + {{:: 'default-acr-values.tooltip' | translate}} +
    + +
    + +
    + {{:: 'client-flow-bindings' | translate}} {{:: 'client-flow-bindings.tooltip' | translate}} +
    + +
    +
    + +
    +
    + {{:: 'browser-flow.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'direct-grant-flow.tooltip' | translate}} +
    +
    + + + +
    +
    + + +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/client-import.html b/keycloak-themes/base/admin/resources/partials/client-import.html new file mode 100644 index 0000000..18ec93c --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-import.html @@ -0,0 +1,46 @@ +
    + + + +

    {{:: 'import-client' | translate}}

    + +
    +
    +
    + +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    + + +
    + + {{files[0].name}} + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-initial-access-create.html b/keycloak-themes/base/admin/resources/partials/client-initial-access-create.html new file mode 100644 index 0000000..8c0cb19 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-initial-access-create.html @@ -0,0 +1,63 @@ +
    + + + +

    {{:: 'add-client' | translate}}

    + +
    + +
    + + +
    + + +
    + {{:: 'expiration.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'count.tooltip' | translate}} +
    + +
    +
    + + +
    +
    +
    + +
    +
    + + +
    + +
    + + {{:: 'initial-access.copyPaste.tooltip' | translate}} +
    + +
    +
    + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-initial-access.html b/keycloak-themes/base/admin/resources/partials/client-initial-access.html new file mode 100644 index 0000000..b2e683d --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-initial-access.html @@ -0,0 +1,55 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    + + +
    +
    {{:: 'id' | translate}}{{:: 'created' | translate}}{{:: 'expires' | translate}}{{:: 'count' | translate}}{{:: 'remainingCount' | translate}}{{:: 'actions' | translate}}
    {{ia.id}}{{(ia.timestamp * 1000)|date:('dateFormat' | translate)}} {{(ia.timestamp * 1000)|date:('timeFormat' | translate)}}{{((ia.timestamp + ia.expiration) * 1000)|date:('dateFormat' | translate)}} {{((ia.timestamp + ia.expiration) * 1000)|date:('timeFormat' | translate)}}{{ia.count}}{{ia.remainingCount}}{{:: 'delete' | translate}}
    {{:: 'no-results' | translate}}{{:: 'no-initial-access-available' | translate}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-installation.html b/keycloak-themes/base/admin/resources/partials/client-installation.html new file mode 100644 index 0000000..d03fdd2 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-installation.html @@ -0,0 +1,36 @@ +
    + + + + + +
    +
    +
    + +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    + {{:: 'download' | translate}} + +
    +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/client-keys.html b/keycloak-themes/base/admin/resources/partials/client-keys.html new file mode 100644 index 0000000..c412e27 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-keys.html @@ -0,0 +1,146 @@ +
    + + + + + +
    +
    + {{:: 'import-keys-and-cert' | translate}} {{:: 'import-keys-and-cert.tooltip' | translate}} +
    + +
    +
    + +
    +
    + {{:: 'archive-format.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'key-alias.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'key-password.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'store-password.tooltip' | translate}} +
    +
    + + +
    +
    + + +
    +
    +
    + {{:: 'download-keys-and-cert' | translate}} Client key pair, cert, and realm certificate will be stuffed into a PKCS12 or Java keystore that you can use in your clients. +
    + +
    +
    + +
    +
    + Java keystore or PKCS12 archive format. +
    +
    + +
    + +
    + Archive alias for your private key and certificate. +
    +
    + +
    + +
    + Password to access the private key in the archive +
    +
    + +
    + +
    + Realm certificate is stored in archive too. This is the alias to it. +
    +
    + +
    + +
    + Password to access the archive itself +
    +
    +
    + +
    +
    +
    +
    + Keys and Certificate Keys and cert in PEM format. +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-list.html b/keycloak-themes/base/admin/resources/partials/client-list.html new file mode 100644 index 0000000..8c26669 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-list.html @@ -0,0 +1,68 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-mappers-add.html b/keycloak-themes/base/admin/resources/partials/client-mappers-add.html new file mode 100644 index 0000000..6537779 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-mappers-add.html @@ -0,0 +1,53 @@ +
    + + + +

    {{:: 'add-builtin-protocol-mapper' | translate}}

    + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    {{:: 'name' | translate}}{{:: 'category' | translate}}{{:: 'type' | translate}}{{:: 'add' | translate}}
    {{mapper.name}}{{mapperTypes[mapper.protocolMapper].category}}{{mapperTypes[mapper.protocolMapper].name}}
    {{:: 'no-mappers-available' | translate}}
    + +
    + +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-mappers.html b/keycloak-themes/base/admin/resources/partials/client-mappers.html new file mode 100644 index 0000000..83123c2 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-mappers.html @@ -0,0 +1,55 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    {{:: 'name' | translate}}{{:: 'category' | translate}}{{:: 'type' | translate}}{{:: 'priority-order' | translate}}{{:: 'actions' | translate}}
    {{mapper.name}}{{mapperTypes[mapper.protocolMapper].category}}{{mapperTypes[mapper.protocolMapper].name}}{{mapperTypes[mapper.protocolMapper].priority}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    {{:: 'no-mappers-available' | translate}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-offline-sessions.html b/keycloak-themes/base/admin/resources/partials/client-offline-sessions.html new file mode 100644 index 0000000..3d2aaf7 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-offline-sessions.html @@ -0,0 +1,59 @@ +
    + + + + + +
    +
    +
    + +
    + +
    + {{:: 'offline-tokens.tooltip' | translate}} +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    {{:: 'user' | translate}}{{:: 'from-ip' | translate}}{{:: 'token-issued' | translate}}{{:: 'last-refresh' | translate}}
    +
    + + + +
    +
    {{session.username}}{{session.ipAddress}}{{session.start | date:'medium'}}{{session.lastAccess | date:'medium'}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-oidc-key-export.html b/keycloak-themes/base/admin/resources/partials/client-oidc-key-export.html new file mode 100644 index 0000000..b293cdc --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-oidc-key-export.html @@ -0,0 +1,57 @@ +
    + + + +

    {{:: 'generate-private-key' | translate}}

    + +
    +
    +
    + +
    +
    + +
    +
    + {{:: 'archive-format.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'key-alias.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'key-password.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'store-password.tooltip' | translate}} +
    +
    +
    + + +
    +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/client-oidc-key-import.html b/keycloak-themes/base/admin/resources/partials/client-oidc-key-import.html new file mode 100644 index 0000000..1b91e43 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-oidc-key-import.html @@ -0,0 +1,62 @@ +
    + + + +

    {{:: 'import-client-certificate' | translate}}

    + +
    +
    +
    + +
    +
    + +
    +
    + {{:: 'archive-format.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'jwt-import.key-alias.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'store-password.tooltip' | translate}} +
    +
    + +
    +
    + + +
    + + {{files[0].name}} + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/client-oidc-keys.html b/keycloak-themes/base/admin/resources/partials/client-oidc-keys.html new file mode 100644 index 0000000..c1d4d09 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-oidc-keys.html @@ -0,0 +1,108 @@ +
    + + + + + +
    +
    + +
    + +
    + {{:: 'use-jwks-url.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'jwks-url.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'use-jwks-string.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'jwks-string.tooltip' | translate}} +
    + +
    + +
    + + {{:: 'certificate.tooltip' | translate}} + +
    + +
    +
    + +
    + + {{:: 'publicKey.tooltip' | translate}} + +
    + +
    +
    + +
    + + {{:: 'kid.tooltip' | translate}} + +
    +
    +
    + +
    +
    +
    +
    + +
    + +
    +
    +
    {{:: 'no-client-certificate-configured' | translate}}
    +
    +
    +
    + +
    + +
    +
    + + + + +
    +
    + +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-policies-json.html b/keycloak-themes/base/admin/resources/partials/client-policies-json.html new file mode 100644 index 0000000..a6150df --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-policies-json.html @@ -0,0 +1,60 @@ + + +
    + + + + + + +
    + + +
    +
    +
    + +
    +
    +
    + +
    +
    + + +
    +
    +
    + +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-policies-list.html b/keycloak-themes/base/admin/resources/partials/client-policies-list.html new file mode 100644 index 0000000..0875105 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-policies-list.html @@ -0,0 +1,74 @@ + + +
    + + + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + +
    + +
    {{:: 'name' | translate}}{{:: 'description' | translate}}{{:: 'enabled' | translate}}{{:: 'actions' | translate}}
    {{clientPolicy.name}}{{clientPolicy.description}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    +
    + +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/client-policies-policy-edit-condition.html b/keycloak-themes/base/admin/resources/partials/client-policies-policy-edit-condition.html new file mode 100644 index 0000000..45c0a8a --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-policies-policy-edit-condition.html @@ -0,0 +1,65 @@ + + +
    + + + +

    {{conditionType.id|capitalize}}

    +

    {{:: 'create-condition' | translate}}

    + +
    +
    +
    + +
    +
    + +
    +
    + {{conditionType.helpText}} +
    +
    + +
    + +
    + {{conditionType.helpText}} +
    + +
    + +
    +
    + + +
    +
    + +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-policies-policy-edit.html b/keycloak-themes/base/admin/resources/partials/client-policies-policy-edit.html new file mode 100644 index 0000000..41476f6 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-policies-policy-edit.html @@ -0,0 +1,140 @@ + + +
    + + + +

    {{:: 'create-client-policy' | translate}}

    +

    {{editedPolicy.name|capitalize}}

    + +
    + +
    + +
    + +
    + +
    + {{:: 'client-policy-name.tooltip' | translate}} +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    + {{:: 'client-policy-enabled.tooltip' | translate}} +
    + +
    + +
    + +
    +
    + + +
    +
    + +
    + +
    + + {{:: 'conditions' | translate}} {{:: 'client-policy-conditions.tooltip' | translate}} + + + + + + + + + + + + + + + + + + + + +
    + +
    {{:: 'type' | translate}}{{:: 'actions' | translate}}
    {{condition.condition}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    {{:: 'no-conditions-available' | translate}}
    + +
    + +
    + {{:: 'client-profiles' | translate}}{{:: 'client-profiles.tooltip' | translate}} + + + + + + + + + + + + + + + + + + + +
    +
    +
    + +
    +
    +
    {{:: 'name' | translate}}{{:: 'actions' | translate}}
    {{profileName}}{{:: 'delete' | translate}}
    {{:: 'no-client-profiles-configured' | translate}}
    +
    + +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-policies-profiles-edit-executor.html b/keycloak-themes/base/admin/resources/partials/client-policies-profiles-edit-executor.html new file mode 100644 index 0000000..5bf8da6 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-policies-profiles-edit-executor.html @@ -0,0 +1,65 @@ + + +
    + + + +

    {{executorType.id|capitalize}}

    +

    {{:: 'create-executor' | translate}}

    + +
    +
    +
    + +
    +
    + +
    +
    + {{executorType.helpText}} +
    +
    + +
    + +
    + {{executorType.helpText}} +
    + +
    + +
    +
    + + +
    +
    + +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-policies-profiles-edit.html b/keycloak-themes/base/admin/resources/partials/client-policies-profiles-edit.html new file mode 100644 index 0000000..1e3e71e --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-policies-profiles-edit.html @@ -0,0 +1,97 @@ + + +
    + + + +

    {{:: 'create-client-profile' | translate}}

    +

    {{editedProfile.name|capitalize}}

    + +
    + +
    + +
    + +
    + +
    + {{:: 'client-profile-name.tooltip' | translate}} +
    + +
    + +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    + +
    + +
    + + {{:: 'executors' | translate}} {{:: 'client-profile-executors.tooltip' | translate}} + + + + + + + + + + + + + + + + + + + + +
    + +
    {{:: 'type' | translate}}{{:: 'actions' | translate}}
    {{executor.executor}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    {{:: 'no-executors-available' | translate}}
    + +
    + +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-policies-profiles-json.html b/keycloak-themes/base/admin/resources/partials/client-policies-profiles-json.html new file mode 100644 index 0000000..e2fae4a --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-policies-profiles-json.html @@ -0,0 +1,60 @@ + + +
    + + + + + + +
    + + +
    +
    +
    + +
    +
    +
    + +
    +
    + + +
    +
    +
    + +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-policies-profiles-list.html b/keycloak-themes/base/admin/resources/partials/client-policies-profiles-list.html new file mode 100644 index 0000000..a0b9f89 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-policies-profiles-list.html @@ -0,0 +1,80 @@ + + +
    + + + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    {{:: 'name' | translate}}{{:: 'description' | translate}}{{:: 'global' | translate}}{{:: 'actions' | translate}}
    {{clientProfile.name}}{{clientProfile.description}}{{:: 'true' | translate}}{{:: 'edit' | translate}}
    {{clientProfile.name}}{{clientProfile.description}}{{:: 'false' | translate}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    +
    + +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/client-protocol-mapper-detail.html b/keycloak-themes/base/admin/resources/partials/client-protocol-mapper-detail.html new file mode 100644 index 0000000..b2af24a --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-protocol-mapper-detail.html @@ -0,0 +1,13 @@ +
    + + +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-reg-policies.html b/keycloak-themes/base/admin/resources/partials/client-reg-policies.html new file mode 100644 index 0000000..9ca912f --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-reg-policies.html @@ -0,0 +1,106 @@ + + +
    + + + + +
    + +
    + {{:: 'anonymous-policies' | translate}}{{:: 'anonymous-policies.tooltip' | translate}} + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + +
    +
    +
    {{:: 'policy-name' | translate}}{{:: 'provider-id' | translate}}{{:: 'actions' | translate}}
    {{instance.name}}{{instance.providerId}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    {{:: 'no-client-reg-policies-configured' | translate}}
    +
    + +
    + {{:: 'auth-policies' | translate}}{{:: 'auth-policies.tooltip' | translate}} + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + +
    +
    +
    {{:: 'policy-name' | translate}}{{:: 'provider-id' | translate}}{{:: 'actions' | translate}}
    {{instance.name}}{{instance.providerId}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    {{:: 'no-client-reg-policies-configured' | translate}}
    +
    + + +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-reg-policy-detail.html b/keycloak-themes/base/admin/resources/partials/client-reg-policy-detail.html new file mode 100644 index 0000000..91a8ed9 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-reg-policy-detail.html @@ -0,0 +1,68 @@ + + +
    + + + +
    +
    + {{headerTitle}}{{:: providerType.helpText | translate}} +
    + +
    + +
    +
    +
    + +
    + +
    + {{:: 'client-reg-policy.name.tooltip' | translate}} +
    +
    + +
    + +
    + {{providerType.helpText}} +
    + +
    + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    +
    + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-reg-trusted-host-create.html b/keycloak-themes/base/admin/resources/partials/client-reg-trusted-host-create.html new file mode 100644 index 0000000..cb07613 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-reg-trusted-host-create.html @@ -0,0 +1,55 @@ + + +
    + + + +

    {{:: 'add-client-reg-trusted-host' | translate}}

    + +
    + +
    + +
    + +
    + {{:: 'client-reg-hostname.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'client-reg-count.tooltip' | translate}} +
    + +
    +
    + + +
    +
    +
    + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-reg-trusted-host-detail.html b/keycloak-themes/base/admin/resources/partials/client-reg-trusted-host-detail.html new file mode 100644 index 0000000..5644fc1 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-reg-trusted-host-detail.html @@ -0,0 +1,64 @@ + + +
    + + + +

    {{hostName}}

    + +
    + +
    + +
    + +
    + {{:: 'client-reg-hostname.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'client-reg-count.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'client-reg-remainingCount.tooltip' | translate}} +
    + +
    +
    + + + +
    +
    +
    + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-registration-access-token.html b/keycloak-themes/base/admin/resources/partials/client-registration-access-token.html new file mode 100644 index 0000000..327b70d --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-registration-access-token.html @@ -0,0 +1,18 @@ +
    +
    +
    + +
    +
    +
    + +
    +
    + +
    +
    +
    + {{:: 'registrationAccessToken.tooltip' | translate}} +
    +
    +
    diff --git a/keycloak-themes/base/admin/resources/partials/client-revocation.html b/keycloak-themes/base/admin/resources/partials/client-revocation.html new file mode 100644 index 0000000..95db767 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-revocation.html @@ -0,0 +1,30 @@ +
    + + + + + +
    +
    +
    + +
    + +
    + {{:: 'client-revoke.not-before.tooltip' | translate}} +
    +
    +
    +
    + + + +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/client-role-attributes.html b/keycloak-themes/base/admin/resources/partials/client-role-attributes.html new file mode 100644 index 0000000..47ef416 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-role-attributes.html @@ -0,0 +1,45 @@ +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + +
    {{:: 'key' | translate}}{{:: 'value' | translate}}{{:: 'actions' | translate}}
    {{key}}{{:: 'delete' | translate}}
    {{:: 'add' | translate}}
    + +
    +
    + + +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/client-role-detail.html b/keycloak-themes/base/admin/resources/partials/client-role-detail.html new file mode 100644 index 0000000..8877dbe --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-role-detail.html @@ -0,0 +1,140 @@ +
    + + + + + +
    + +
    +
    + + +
    + +
    +
    +
    + + +
    + + +
    +
    +
    + +
    + +
    + {{:: 'composite-roles.tooltip' | translate}} +
    +
    + +
    +
    + + +
    +
    +
    +
    + + +
    +
    + +
    + {{:: 'composite-roles' | translate}} + +
    + + +
    +
    +
    + + {{:: 'composite.available-realm-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'composite.associated-realm-roles.tooltip' | translate}} + + +
    +
    +
    +
    + +
    + +
    + + +
    + + +
    +
    +
    + + {{:: 'available-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'client.associated-roles.tooltip' | translate}} + + +
    +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-role-list.html b/keycloak-themes/base/admin/resources/partials/client-role-list.html new file mode 100644 index 0000000..4feff0a --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-role-list.html @@ -0,0 +1,64 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    + + +
    +
    {{:: 'role-name' | translate}}{{:: 'composite' | translate}}{{:: 'description' | translate}}{{:: 'actions' | translate}}
    {{role.name}}{{role.description}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    {{:: 'no-results' | translate}}{{:: 'no-client-roles-available' | translate}}
    +
    + + + +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/client-role-users.html b/keycloak-themes/base/admin/resources/partials/client-role-users.html new file mode 100644 index 0000000..5349171 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-role-users.html @@ -0,0 +1,52 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{:: 'username' | translate}}{{:: 'last-name' | translate}}{{:: 'first-name' | translate}}{{:: 'email' | translate}}
    +
    + + + +
    +
    {{user.username}}{{user.lastName}}{{user.firstName}}{{user.email}}{{:: 'edit' | translate}}
    {{:: 'no-role-members' | translate}}{{:: 'no-role-members' | translate}}
    + +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/client-saml-key-export.html b/keycloak-themes/base/admin/resources/partials/client-saml-key-export.html new file mode 100644 index 0000000..7610192 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-saml-key-export.html @@ -0,0 +1,63 @@ +
    + + + +

    {{:: 'export-saml-key' | translate}} {{client.clientId|capitalize}}

    + +
    +
    +
    + +
    +
    + +
    +
    + {{:: 'archive-format.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'key-alias.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'key-password.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'realm-certificate-alias.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'store-password.tooltip' | translate}} +
    +
    +
    + +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-saml-key-import.html b/keycloak-themes/base/admin/resources/partials/client-saml-key-import.html new file mode 100644 index 0000000..f37ac7a --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-saml-key-import.html @@ -0,0 +1,62 @@ +
    + + + +

    {{:: 'import-saml-key' | translate}} {{client.clientId|capitalize}}

    + +
    +
    +
    + +
    +
    + +
    +
    + {{:: 'archive-format.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'key-alias.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'store-password.tooltip' | translate}} +
    +
    + +
    +
    + + +
    + + {{files[0].name}} + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-saml-keys.html b/keycloak-themes/base/admin/resources/partials/client-saml-keys.html new file mode 100644 index 0000000..776349d --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-saml-keys.html @@ -0,0 +1,66 @@ +
    + + + + + +
    +
    + {{:: 'signing-key' | translate}} {{:: 'saml-signing-key' | translate}} +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    +
    + + + +
    +
    +
    +
    + {{:: 'encryption-key' | translate}} {{:: 'saml-encryption-key.tooltip' | translate}} +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    +
    + + + +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-scope-detail.html b/keycloak-themes/base/admin/resources/partials/client-scope-detail.html new file mode 100644 index 0000000..9f1ba99 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-scope-detail.html @@ -0,0 +1,102 @@ +
    + + + + + +
    +
    +
    + +
    + +
    + {{:: 'client-scope.name.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'client-scope.is-dynamic-scope.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'client-scope.dynamic-scope-regexp.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'client-scope.description.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'client-scope.protocol.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'client-scope.display-on-consent-screen.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'client-scope.consent-screen-text.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'client-scope.include-in-token-scope.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'client-scope.gui-order.tooltip' | translate}} +
    +
    + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-scope-list.html b/keycloak-themes/base/admin/resources/partials/client-scope-list.html new file mode 100644 index 0000000..1f945fc --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-scope-list.html @@ -0,0 +1,60 @@ +
    +

    + {{:: 'client-scopes' | translate}} + {{:: 'client-scopes.tooltip' | translate}} +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    + + +
    +
    {{:: 'name' | translate}}{{:: 'protocol' | translate}}{{:: 'gui-order' | translate}}{{:: 'actions' | translate}}
    {{clientScope.name}}{{clientScope.protocol}}{{clientScope.attributes['gui.order']}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    {{:: 'no-results' | translate}}{{:: 'no-clients-available' | translate}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-scope-mappers-add.html b/keycloak-themes/base/admin/resources/partials/client-scope-mappers-add.html new file mode 100644 index 0000000..413c065 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-scope-mappers-add.html @@ -0,0 +1,53 @@ +
    + + + +

    {{:: 'add-builtin-protocol-mapper' | translate}}

    + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    {{:: 'name' | translate}}{{:: 'category' | translate}}{{:: 'type' | translate}}{{:: 'add' | translate}}
    {{mapper.name}}{{mapperTypes[mapper.protocolMapper].category}}{{mapperTypes[mapper.protocolMapper].name}}
    {{:: 'no-mappers-available' | translate}}
    + +
    + +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-scope-mappers.html b/keycloak-themes/base/admin/resources/partials/client-scope-mappers.html new file mode 100644 index 0000000..3b95910 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-scope-mappers.html @@ -0,0 +1,55 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    {{:: 'name' | translate}}{{:: 'category' | translate}}{{:: 'type' | translate}}{{:: 'priority-order' | translate}}{{:: 'actions' | translate}}
    {{mapper.name}}{{mapperTypes[mapper.protocolMapper].category}}{{mapperTypes[mapper.protocolMapper].name}}{{mapperTypes[mapper.protocolMapper].priority}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    {{:: 'no-mappers-available' | translate}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-scope-mappings.html b/keycloak-themes/base/admin/resources/partials/client-scope-mappings.html new file mode 100644 index 0000000..1343f1b --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-scope-mappings.html @@ -0,0 +1,127 @@ +
    + + + + + +

    {{client.clientId}} {{:: 'scope-mappings' | translate}}

    +

    +
    +
    +
    + + {{:: 'full-scope-allowed.tooltip' | translate}} +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    + + {{:: 'scope.available-roles.tooltip' | translate}} + + + +
    +
    + + {{:: 'assigned-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'realm.effective-roles.tooltip' | translate}} + +
    +
    +
    +
    + +
    + +
    + + +
    + +
    +
    +
    + + {{:: 'assign.available-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'client.assigned-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'client.effective-roles.tooltip' | translate}} + +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-scope-protocol-mapper-detail.html b/keycloak-themes/base/admin/resources/partials/client-scope-protocol-mapper-detail.html new file mode 100644 index 0000000..0f6cb5c --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-scope-protocol-mapper-detail.html @@ -0,0 +1,13 @@ +
    + + +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-scope-scope-mappings.html b/keycloak-themes/base/admin/resources/partials/client-scope-scope-mappings.html new file mode 100644 index 0000000..3180826 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-scope-scope-mappings.html @@ -0,0 +1,116 @@ +
    + + + + + +

    {{clientScope.name}} {{:: 'scope-mappings' | translate}}

    +

    + +
    +
    + +
    +
    +
    + + {{:: 'scope.available-roles.tooltip' | translate}} + + + +
    +
    + + {{:: 'assigned-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'realm.effective-roles.tooltip' | translate}} + +
    +
    +
    +
    + +
    + +
    + + +
    + +
    +
    +
    + + {{:: 'assign.available-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'client.assigned-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'client.effective-roles.tooltip' | translate}} + +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-scopes-evaluate.html b/keycloak-themes/base/admin/resources/partials/client-scopes-evaluate.html new file mode 100644 index 0000000..e8702ad --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-scopes-evaluate.html @@ -0,0 +1,268 @@ + + +
    + + + + + + + +
    +
    +
    + +
    + +
    + {{:: 'scope-parameter.tooltip' | translate}} +
    +
    + +
    + + {{:: 'client-scopes.evaluate.scopes.tooltip' | translate}} + +
    +
    +
    + + {{:: 'client-scopes.evaluate.scopes.available.tooltip' | translate}} + + +
    +
    + + {{:: 'client-scopes.evaluate.scopes.assigned.tooltip' | translate}} + + +
    +
    + + {{:: 'client-scopes.evaluate.scopes.effective.tooltip' | translate}} + +
    +
    +
    +
    + +
    + + +
    + + +
    + + {{:: 'client-scopes.evaluate.user.tooltip' | translate}} +
    + +
    +
    + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    {{:: 'name' | translate}}{{:: 'parent-client-scope' | translate}}{{:: 'category' | translate}}{{:: 'type' | translate}}{{:: 'priority-order' | translate}}
    {{mapper.mapperName}}{{mapper.containerName}}{{mapperTypes[mapper.protocolMapper].category}}{{mapperTypes[mapper.protocolMapper].name}}{{mapperTypes[mapper.protocolMapper].priority}}
    {{:: 'no-mappers-available' | translate}}
    + + + +
    +
    + +
    +
    +
    + + {{:: 'client-scopes.evaluate.not-granted-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'client-scopes.evaluate.granted-realm-effective-roles.tooltip' | translate}} + +
    +
    +
    +
    + +
    + +
    + + +
    + +
    +
    +
    + + {{:: 'client-scopes.evaluate.not-granted-roles.tooltip' | translate}} + +
    +
    + + {{:: 'client-scopes.evaluate.granted-realm-effective-roles.tooltip' | translate}} + +
    +
    +
    +
    +
    + + + +
    +
    +
    + +
    +
    +
    + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-scopes-realm-default.html b/keycloak-themes/base/admin/resources/partials/client-scopes-realm-default.html new file mode 100644 index 0000000..e30570a --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-scopes-realm-default.html @@ -0,0 +1,99 @@ +
    +

    + {{:: 'default-client-scopes' | translate}} + {{:: 'default-client-scopes.tooltip' | translate}} +

    + + + +
    +
    + + {{:: 'default-client-scopes.default.tooltip' | translate}} + +
    +
    +
    + + {{:: 'default-client-scopes.default.available.tooltip' | translate}} + + +
    +
    + + {{:: 'default-client-scopes.default.assigned.tooltip' | translate}} + + +
    +
    +
    +
    + +
    + + {{:: 'default-client-scopes.optional.tooltip' | translate}} + +
    +
    +
    + + {{:: 'default-client-scopes.optional.available.tooltip' | translate}} + + +
    +
    + + {{:: 'default-client-scopes.optional.assigned.tooltip' | translate}} + + +
    +
    +
    +
    + +
    + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-scopes-setup.html b/keycloak-themes/base/admin/resources/partials/client-scopes-setup.html new file mode 100644 index 0000000..50f10b6 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-scopes-setup.html @@ -0,0 +1,123 @@ + + +
    + + + + + + + +
    +
    + + {{:: 'client-scopes.default.tooltip' | translate}} + +
    +
    +
    + + {{:: 'client-scopes.default.available.tooltip' | translate}} + + +
    +
    + + {{:: 'client-scopes.default.assigned.tooltip' | translate}} + + +
    +
    +
    +
    + +
    + + {{:: 'client-scopes.optional.tooltip' | translate}} + +
    +
    +
    + + {{:: 'client-scopes.optional.available.tooltip' | translate}} + + +
    +
    + + {{:: 'client-scopes.optional.assigned.tooltip' | translate}} + + +
    +
    +
    +
    + +
    + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-service-account-roles.html b/keycloak-themes/base/admin/resources/partials/client-service-account-roles.html new file mode 100644 index 0000000..36905a7 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-service-account-roles.html @@ -0,0 +1,140 @@ +
    + + + + + +
    + +

    {{:: 'service-account' | translate}}

    + +
    + + + {{:: 'service-account.user.tooltip' | translate}} +
    +

    + + +

    {{:: 'service-account.roles' | translate}}

    +

    + +
    + +
    +
    +
    + + {{:: 'service-account.available-roles.tooltip' | translate}} + + + +
    +
    + + {{:: 'service-account.assigned-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'realm.effective-roles.tooltip' | translate}} + +
    +
    +
    +
    + +
    + +
    + + +
    + +
    +
    +
    + + {{:: 'assign.available-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'client.assigned-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'client.effective-roles.tooltip' | translate}} + +
    +
    +
    +
    +
    + +
    + +
    + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-sessions.html b/keycloak-themes/base/admin/resources/partials/client-sessions.html new file mode 100644 index 0000000..5dbb2af --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-sessions.html @@ -0,0 +1,57 @@ +
    + + + + + +
    +
    +
    + +
    + +
    + {{:: 'active-sessions.tooltip' | translate}} +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    {{:: 'user' | translate}}{{:: 'from-ip' | translate}}{{:: 'session-start' | translate}}
    +
    + + + +
    +
    {{session.username}}{{session.ipAddress}}{{session.start | date:'medium'}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-storage-generic.html b/keycloak-themes/base/admin/resources/partials/client-storage-generic.html new file mode 100644 index 0000000..90ed088 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-storage-generic.html @@ -0,0 +1,207 @@ +
    + + +
    +
    + {{:: 'required-settings' | translate}} +
    + +
    + +
    +
    +
    + +
    + +
    + {{:: 'client-storage.enabled.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'console-display-name.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'priority.tooltip' | translate}} +
    + + + +
    + +
    + {{:: 'client-storage-cache-policy' | translate}} +
    + +
    +
    + +
    +
    + {{:: 'clientStorage.cachePolicy.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'clientStorage.cachePolicy.evictionDay.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'clientStorage.cachePolicy.evictionHour.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'clientStorage.cachePolicy.evictionMinute.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'clientStorage.cachePolicy.maxLifespan.tooltip' | translate}} +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/client-storage-list.html b/keycloak-themes/base/admin/resources/partials/client-storage-list.html new file mode 100644 index 0000000..c111eaa --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/client-storage-list.html @@ -0,0 +1,67 @@ +
    + + + +
    +
    + +
    +

    + {{:: 'client-storage' | translate}} +

    + {{:: 'client-storage-list-no-entries' | translate}} +
    +
    +
    +
    + +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + +
    +
    +
    {{:: 'id' | translate}}{{:: 'enabled' | translate}}{{:: 'provider-name' | translate}}{{:: 'priority' | translate}}{{:: 'actions' | translate}}
    {{getInstanceName(instance)}}{{isProviderEnabled(instance)}}{{getInstanceProvider(instance) | capitalize}}{{getInstancePriority(instance)}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    {{:: 'no-client-storage-providers-configured' | translate}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/create-client.html b/keycloak-themes/base/admin/resources/partials/create-client.html new file mode 100644 index 0000000..0c47b31 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/create-client.html @@ -0,0 +1,72 @@ +
    + + + + + +
    +
    +
    + + +
    + + +
    + +
    + + +
    +
    + +
    + +
    + +
    + {{:: 'client-id.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'client-protocol.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'root-url.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'master-saml-processing-url.tooltip' | translate}} +
    +
    +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/create-execution.html b/keycloak-themes/base/admin/resources/partials/create-execution.html new file mode 100644 index 0000000..d68dc9c --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/create-execution.html @@ -0,0 +1,31 @@ +
    + +
    +

    {{:: 'create-authenticator-execution' | translate}}

    +

    {{:: 'create-authenticator-execution' | translate}}

    +

    {{:: 'create-form-action-execution' | translate}}

    +
    + +
    +
    + +
    +
    + +
    +
    + {{provider.description}} +
    +
    +
    + + +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/create-flow-execution.html b/keycloak-themes/base/admin/resources/partials/create-flow-execution.html new file mode 100644 index 0000000..195a7ff --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/create-flow-execution.html @@ -0,0 +1,55 @@ +
    +

    {{:: 'create-execution-flow' | translate}}

    + + + +
    +
    + +
    + +
    + {{:: 'flow.alias.tooltip' | translate}} +
    +
    + + +
    + +
    +
    +
    + +
    +
    + +
    +
    + {{:: 'flow-type.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{provider.description}} +
    +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/create-flow.html b/keycloak-themes/base/admin/resources/partials/create-flow.html new file mode 100644 index 0000000..efd34e9 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/create-flow.html @@ -0,0 +1,43 @@ +
    +

    {{:: 'create-top-level-form' | translate}}

    + + + +
    +
    + +
    + +
    + {{:: 'flow.alias.tooltip' | translate}} +
    +
    + + +
    + +
    +
    +
    + +
    +
    + +
    +
    + {{:: 'top-level-flow-type.tooltip' | translate}} +
    +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/create-group.html b/keycloak-themes/base/admin/resources/partials/create-group.html new file mode 100644 index 0000000..255cf32 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/create-group.html @@ -0,0 +1,25 @@ +
    +
    +

    {{:: 'create-group' | translate}}

    +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/default-groups.html b/keycloak-themes/base/admin/resources/partials/default-groups.html new file mode 100644 index 0000000..8d0866e --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/default-groups.html @@ -0,0 +1,91 @@ +
    + + +
    +
    + + +
    +
    +
    + + + + + + + + + + + +
    +
    + + {{:: 'default-groups.tooltip' | translate}} + +
    + +
    +
    +
    + +
    +
    +
    + + + + + + + + + + + +
    +
    +
    + + {{:: 'available-groups.tooltip' | translate}} +
    +
    +
    + +
    + +
    +
    +
    +   + +
    + +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/defense-headers.html b/keycloak-themes/base/admin/resources/partials/defense-headers.html new file mode 100644 index 0000000..51acdf1 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/defense-headers.html @@ -0,0 +1,71 @@ +
    + + + + +
    +
    +
    + +
    + +
    + {{:: 'x-frame-options-tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'content-sec-policy-tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'content-sec-policy-report-only-tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'content-type-options-tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'robots-tag-tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'x-xss-protection-tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'strict-transport-security-tooltip' | translate}} +
    +
    +
    +
    + + +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/forbidden.html b/keycloak-themes/base/admin/resources/partials/forbidden.html new file mode 100644 index 0000000..b40f2e7 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/forbidden.html @@ -0,0 +1,7 @@ +
    +
    +

    Forbidden

    +

    You don't have access to the requested resource.

    + Go to the home page » +
    +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/group-attributes.html b/keycloak-themes/base/admin/resources/partials/group-attributes.html new file mode 100644 index 0000000..e12c553 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/group-attributes.html @@ -0,0 +1,41 @@ +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + +
    {{:: 'key' | translate}}{{:: 'value' | translate}}{{:: 'actions' | translate}}
    {{key}}{{:: 'delete' | translate}}
    {{:: 'add' | translate}}
    + +
    +
    + + +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/group-detail.html b/keycloak-themes/base/admin/resources/partials/group-detail.html new file mode 100644 index 0000000..8fd6461 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/group-detail.html @@ -0,0 +1,28 @@ +
    + + + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/group-list.html b/keycloak-themes/base/admin/resources/partials/group-list.html new file mode 100644 index 0000000..3412e6a --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/group-list.html @@ -0,0 +1,50 @@ +
    + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + + + + + +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/group-members.html b/keycloak-themes/base/admin/resources/partials/group-members.html new file mode 100644 index 0000000..ffdf362 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/group-members.html @@ -0,0 +1,48 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{:: 'username' | translate}}{{:: 'last-name' | translate}}{{:: 'first-name' | translate}}{{:: 'email' | translate}}
    +
    + + + +
    +
    {{user.username}}{{user.lastName}}{{user.firstName}}{{user.email}}{{:: 'edit' | translate}}
    {{:: 'no-group-members' | translate}}{{:: 'no-group-members' | translate}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/group-role-mappings.html b/keycloak-themes/base/admin/resources/partials/group-role-mappings.html new file mode 100644 index 0000000..fc3f6ee --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/group-role-mappings.html @@ -0,0 +1,111 @@ +
    + + + + +
    +
    + + +
    +
    +
    + + + + {{:: 'group.add-selected.tooltip' | translate}} +
    +
    + + {{:: 'group.assigned-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'group.effective-roles.tooltip' | translate}} + +
    +
    +
    +
    + +
    + +
    + + +
    +
    +
    +
    + + {{:: 'group.available-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'group.assigned-roles-client.tooltip' | translate}} + + +
    +
    + + {{:: 'group.effective-roles-client.tooltip' | translate}} + +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/home.html b/keycloak-themes/base/admin/resources/partials/home.html new file mode 100644 index 0000000..dc2471b --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/home.html @@ -0,0 +1,4 @@ +
    +
    +
    +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/identity-provider-mapper-detail.html b/keycloak-themes/base/admin/resources/partials/identity-provider-mapper-detail.html new file mode 100644 index 0000000..7e62b14 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/identity-provider-mapper-detail.html @@ -0,0 +1,84 @@ +
    + + +

    {{mapper.name|capitalize}}

    +

    {{:: 'add-identity-provider-mapper' | translate}}

    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    + {{:: 'mapper.name.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'sync-mode-override.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{mapperType.helpText}} +
    +
    + +
    + +
    + {{mapperType.helpText}} +
    + +
    + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/identity-provider-mappers.html b/keycloak-themes/base/admin/resources/partials/identity-provider-mappers.html new file mode 100644 index 0000000..23705c0 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/identity-provider-mappers.html @@ -0,0 +1,49 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    {{:: 'name' | translate}}{{:: 'category' | translate}}{{:: 'type' | translate}}
    {{mapper.name}}{{mapperTypes[mapper.identityProviderMapper].category}}{{mapperTypes[mapper.identityProviderMapper].name}}
    {{:: 'no-mappers-available' | translate}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/menu.html b/keycloak-themes/base/admin/resources/partials/menu.html new file mode 100644 index 0000000..dc41323 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/menu.html @@ -0,0 +1,26 @@ + + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/modal/group-selector.html b/keycloak-themes/base/admin/resources/partials/modal/group-selector.html new file mode 100644 index 0000000..d6dfa4d --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/modal/group-selector.html @@ -0,0 +1,50 @@ + +
    +
    + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    + + +
    + +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/modal/realm-events-admin-auth.html b/keycloak-themes/base/admin/resources/partials/modal/realm-events-admin-auth.html new file mode 100644 index 0000000..c8da93e --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/modal/realm-events-admin-auth.html @@ -0,0 +1,8 @@ +
    + + + + + +
    {{:: 'realm' | translate}}{{event.authDetails.realmId}}
    {{:: 'client' | translate}}{{event.authDetails.clientId}}
    {{:: 'user' | translate}}{{event.authDetails.userId}}
    {{:: 'ip-address' | translate}}{{event.authDetails.ipAddress}}
    +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/modal/realm-events-admin-representation.html b/keycloak-themes/base/admin/resources/partials/modal/realm-events-admin-representation.html new file mode 100644 index 0000000..837a164 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/modal/realm-events-admin-representation.html @@ -0,0 +1,3 @@ +
    +
    
    +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/modal/role-selector.html b/keycloak-themes/base/admin/resources/partials/modal/role-selector.html new file mode 100644 index 0000000..b4dd43f --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/modal/role-selector.html @@ -0,0 +1,39 @@ + +
    +
    +
    + + {{:: 'realm-roles.tooltip' | translate}} + + +
    +
    + + + + + +
    +
    +
    diff --git a/keycloak-themes/base/admin/resources/partials/modal/unregistered-required-action-selector.html b/keycloak-themes/base/admin/resources/partials/modal/unregistered-required-action-selector.html new file mode 100644 index 0000000..bc9995f --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/modal/unregistered-required-action-selector.html @@ -0,0 +1,21 @@ + + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/modal/user-credential-data.html b/keycloak-themes/base/admin/resources/partials/modal/user-credential-data.html new file mode 100644 index 0000000..342b3f6 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/modal/user-credential-data.html @@ -0,0 +1,8 @@ +
    + + + + + +
    {{key}}{{credentialData[key]}}
    +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/modal/view-key.html b/keycloak-themes/base/admin/resources/partials/modal/view-key.html new file mode 100644 index 0000000..5d53d3f --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/modal/view-key.html @@ -0,0 +1,18 @@ + + +
    {{key}}
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/modal/view-object.html b/keycloak-themes/base/admin/resources/partials/modal/view-object.html new file mode 100644 index 0000000..ee50aee --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/modal/view-object.html @@ -0,0 +1,3 @@ +
    +
    
    +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/notfound.html b/keycloak-themes/base/admin/resources/partials/notfound.html new file mode 100644 index 0000000..62a1a5b --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/notfound.html @@ -0,0 +1,7 @@ +
    +
    +

    +

    {{:: 'resource-not-found.instruction' | translate}}

    + +
    +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/otp-policy.html b/keycloak-themes/base/admin/resources/partials/otp-policy.html new file mode 100644 index 0000000..e44afa9 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/otp-policy.html @@ -0,0 +1,96 @@ +
    +

    {{:: 'authentication' | translate}}

    + + + +
    +
    + +
    +
    + +
    +
    + {{:: 'otp-type.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'otp-hash-algorithm.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'otp.number-of-digits.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'otp.look-ahead-window.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'otp.look-around-window.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'otp.initial-counter.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'otp-token-period.tooltip' | translate}} +
    + +
    + +
    + {{realm.otpSupportedApplications.join(', ')}} +
    + {{:: 'otp-supported-applications.tooltip' | translate}} +
    + + +
    +
    + + +
    +
    +
    + +
    + + + diff --git a/keycloak-themes/base/admin/resources/partials/pagenotfound.html b/keycloak-themes/base/admin/resources/partials/pagenotfound.html new file mode 100644 index 0000000..c15a051 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/pagenotfound.html @@ -0,0 +1,7 @@ +
    +
    +

    +

    {{:: 'page-not-found.instruction' | translate}}

    + +
    +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/partial-export.html b/keycloak-themes/base/admin/resources/partials/partial-export.html new file mode 100644 index 0000000..1ceed8c --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/partial-export.html @@ -0,0 +1,34 @@ +
    + +

    + {{:: 'partial-export' | translate}} + {{:: 'partial-export.tooltip' | translate}} +

    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    + +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/partial-import.html b/keycloak-themes/base/admin/resources/partials/partial-import.html new file mode 100644 index 0000000..4df1207 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/partial-import.html @@ -0,0 +1,130 @@ +
    + +

    + {{:: 'partial-import' | translate}} + {{:: 'partial-import.tooltip' | translate}} +

    + +
    +
    +
    + + +
    + + +
    + +
    + + +
    +
    + +
    + +
    +
    + +
    +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    +
    + +
    +
    + {{:: 'if-resource-exists.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + +
    + {{successMessage()}} + + + + + + + + + + + + + + + + + + + +
    {{:: 'action' | translate}}{{:: 'type' | translate}}{{:: 'name' | translate}}{{:: 'id' | translate}}
    {{result.action}}{{result.action}}{{result.action}}{{result.resourceType}}{{result.resourceName}}{{result.id}}
    + +
    + + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/password-policy.html b/keycloak-themes/base/admin/resources/partials/password-policy.html new file mode 100644 index 0000000..f211dba --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/password-policy.html @@ -0,0 +1,51 @@ +
    +

    {{:: 'authentication' | translate}}

    + + + +
    + + + + + + + + + + + + + + + + + + + +
    +
    +
    + +
    +
    +
    {{:: 'policy-type' | translate}}{{:: 'policy-value' | translate}}{{:: 'actions' | translate}}
    {{p.displayName}} + + {{:: 'delete' | translate}}
    + +
    +
    + + +
    +
    +
    + +
    + + + diff --git a/keycloak-themes/base/admin/resources/partials/protocol-mapper-detail.html b/keycloak-themes/base/admin/resources/partials/protocol-mapper-detail.html new file mode 100644 index 0000000..e555aaf --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/protocol-mapper-detail.html @@ -0,0 +1,64 @@ +

    {{:: 'create-protocol-mapper' | translate}}

    +

    {{model.mapper.name|capitalize}}

    + +
    + +
    +
    + +
    + +
    + {{:: 'protocol.tooltip' | translate}} +
    +
    + +
    + +
    +
    +
    + +
    + +
    + {{:: 'mapper.name.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{model.mapperType.helpText}} +
    +
    + +
    + +
    + {{model.mapperType.helpText}} +
    + +
    + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    +
    diff --git a/keycloak-themes/base/admin/resources/partials/realm-cache-settings.html b/keycloak-themes/base/admin/resources/partials/realm-cache-settings.html new file mode 100644 index 0000000..53a7987 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-cache-settings.html @@ -0,0 +1,30 @@ +
    + + +
    +
    + +
    + +
    + + {{:: 'realm-cache-clear.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'user-cache-clear.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'keys-cache-clear.tooltip' | translate}} +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-create.html b/keycloak-themes/base/admin/resources/partials/realm-create.html new file mode 100644 index 0000000..f156c3b --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-create.html @@ -0,0 +1,45 @@ +
    + +

    {{:: 'add-realm' | translate}}

    + +
    +
    +
    + + +
    + + +
    + +
    + + +
    +
    + +
    + + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-default-roles.html b/keycloak-themes/base/admin/resources/partials/realm-default-roles.html new file mode 100644 index 0000000..41cb09b --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-default-roles.html @@ -0,0 +1,88 @@ +
    +

    {{:: 'roles' | translate}}

    + + +
    +
    + + +
    +
    +
    + + {{:: 'default.available-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'realm-default-roles.tooltip' | translate}} + + +
    +
    +
    +
    + +
    + +
    + + +
    +
    +
    +
    + + {{:: 'default.available-roles-client.tooltip' | translate}} + + +
    +
    + + {{:: 'client-default-roles.tooltip' | translate}} + + +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-detail.html b/keycloak-themes/base/admin/resources/partials/realm-detail.html new file mode 100644 index 0000000..5ae2af8 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-detail.html @@ -0,0 +1,90 @@ +
    + + +
    +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    + {{:: 'realm-detail.frontendUrl.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'realm-detail.hostname.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'realm-detail.enabled.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'realm-detail.userManagedAccess.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'userProfileEnabled.tooltip' | translate}} +
    + +
    + + + {{:: 'realm-detail.protocol-endpoints.tooltip' | translate}} +
    + +
    +
    + + +
    + +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-events-admin.html b/keycloak-themes/base/admin/resources/partials/realm-events-admin.html new file mode 100644 index 0000000..d727976 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-events-admin.html @@ -0,0 +1,134 @@ +
    +

    + {{:: 'admin-events' | translate}} + {{:: 'admin-events.tooltip' | translate}} +

    + + +

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + + {{:: 'resource-path.tooltip' | translate}} +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    + +
    + {{:: 'authentication-details' | translate}} + +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    {{:: 'time' | translate}}{{:: 'operation-type' | translate}}{{:: 'resource-type' | translate}}{{:: 'resource-path' | translate}}{{:: 'details' | translate}}
    + + + +
    {{event.time|date:('dateFormat' | translate)}}
    {{event.time|date:('timeFormat' | translate)}}
    {{event.operationType}}{{event.resourceType}}{{event.resourcePath}} + + +
    +
    +
    + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-events-config.html b/keycloak-themes/base/admin/resources/partials/realm-events-config.html new file mode 100644 index 0000000..b47d6e1 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-events-config.html @@ -0,0 +1,106 @@ +
    +

    + {{:: 'events-config' | translate}} + {{:: 'events-config.tooltip' | translate}} +

    + + +
    +

    {{:: 'events-config' | translate}}

    + +
    + +
    +
    + + {{:: 'event-listeners.tooltip' | translate}} +
    + +
    +
    +
    + +
    + {{:: 'login-events-settings' | translate}} + +
    + + {{:: 'login.save-events.tooltip' | translate}} +
    + +
    +
    + +
    + + {{:: 'saved-types.tooltip' | translate}} +
    + +
    +
    + +
    + + {{:: 'clear-events.tooltip' | translate}} +
    + +
    +
    +
    + + {{:: 'events.expiration.tooltip' | translate}} +
    + + +
    +
    +
    + + +
    + {{:: 'admin-events-settings' | translate}} + +
    + + {{:: 'admin.save-events.tooltip' | translate}} +
    + +
    +
    + +
    + + {{:: 'include-representation.tooltip' | translate}} +
    + +
    +
    + +
    + + {{:: 'clear-admin-events.tooltip' | translate}} +
    + +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-events.html b/keycloak-themes/base/admin/resources/partials/realm-events.html new file mode 100644 index 0000000..91c7aab --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-events.html @@ -0,0 +1,124 @@ +
    +

    + {{:: 'events' | translate}} + {{:: 'events.tooltip' | translate}} +

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    + +
    + +
    + +
    +
    +
    + +
    + +
    +
    + +
    +
    {{:: 'time' | translate}}{{:: 'event-type' | translate}}{{:: 'details' | translate}}
    + + + +
    {{event.time|date:('dateFormat' | translate)}}
    {{event.time|date:('timeFormat' | translate)}}
    {{event.type}} + + + + + + + + + + + + + +
    {{:: 'client' | translate}}{{event.clientId}}
    {{:: 'user' | translate}}{{event.userId}}
    {{:: 'ip-address' | translate}}{{event.ipAddress}}
    {{:: 'error' | translate}}{{event.error}}
    {{:: 'details' | translate}} + + + + + + +
    {{key}}{{value}}
    +
    {{:: 'representation' | translate}} + +
    {{event.representation}}
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-bitbucket.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-bitbucket.html new file mode 100644 index 0000000..fab751e --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-bitbucket.html @@ -0,0 +1,142 @@ +
    + + + + +
    +
    +
    + +
    + +
    + {{:: 'redirect-uri.tooltip' | translate}} +
    +
    +
    +
    + +
    + +
    + {{:: 'bitbucket.key.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'bitbucket.secret.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'bitbucket.default-scopes.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.store-tokens.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.stored-tokens-readable.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.enabled.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'trust-email.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'link-only.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'hide-on-login-page.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'gui-order.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'first-broker-login-flow.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'post-broker-login-flow.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'sync-mode.tooltip' | translate}} +
    +
    + +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-facebook-ext.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-facebook-ext.html new file mode 100644 index 0000000..c8f111a --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-facebook-ext.html @@ -0,0 +1,7 @@ +
    + +
    + +
    + {{:: 'identity-provider.facebook-fetchedFields.tooltip' | translate}} +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-facebook.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-facebook.html new file mode 100644 index 0000000..a4630ac --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-facebook.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-github-ext.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-github-ext.html new file mode 100644 index 0000000..8c9e30f --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-github-ext.html @@ -0,0 +1,14 @@ +
    + +
    + +
    + {{:: 'identity-provider.base-url.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.api-url.tooltip' | translate}} +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-github.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-github.html new file mode 100644 index 0000000..a4630ac --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-github.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-gitlab.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-gitlab.html new file mode 100644 index 0000000..6efcc19 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-gitlab.html @@ -0,0 +1,142 @@ +
    + + + + +
    +
    +
    + +
    + +
    + {{:: 'redirect-uri.tooltip' | translate}} +
    +
    +
    +
    + +
    + +
    + {{:: 'gitlab.application-id.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'gitlab.application-secret.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'gitlab.default-scopes.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.store-tokens.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.stored-tokens-readable.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.enabled.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'trust-email.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'link-only.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'hide-on-login-page.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'gui-order.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'first-broker-login-flow.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'post-broker-login-flow.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'sync-mode.tooltip' | translate}} +
    +
    + +
    +
    + + +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-google-ext.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-google-ext.html new file mode 100644 index 0000000..4f313a8 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-google-ext.html @@ -0,0 +1,21 @@ +
    + +
    + +
    + {{:: 'identity-provider.google-hostedDomain.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.google-userIp.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.google-offlineAccess.tooltip' | translate}} +
    diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-google.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-google.html new file mode 100644 index 0000000..a4630ac --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-google.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-instagram-ext.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-instagram-ext.html new file mode 100644 index 0000000..e69de29 diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-instagram.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-instagram.html new file mode 100644 index 0000000..a4630ac --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-instagram.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-keycloak-oidc.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-keycloak-oidc.html new file mode 100644 index 0000000..d380749 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-keycloak-oidc.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-linkedin-ext.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-linkedin-ext.html new file mode 100644 index 0000000..e69de29 diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-linkedin.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-linkedin.html new file mode 100644 index 0000000..a4630ac --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-linkedin.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-microsoft-ext.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-microsoft-ext.html new file mode 100644 index 0000000..e69de29 diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-microsoft.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-microsoft.html new file mode 100644 index 0000000..a4630ac --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-microsoft.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-oidc.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-oidc.html new file mode 100644 index 0000000..e9b28e2 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-oidc.html @@ -0,0 +1,388 @@ +
    + + + + +
    +
    +
    + +
    + +
    + {{:: 'redirect-uri.tooltip' | translate}} +
    +
    +
    +
    + +
    + +
    + {{:: 'identity-provider.alias.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.display-name.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.enabled.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.store-tokens.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.stored-tokens-readable.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'trust-email.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'link-only.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'hide-on-login-page.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'gui-order.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'first-broker-login-flow.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'post-broker-login-flow.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'sync-mode.tooltip' | translate}} +
    +
    +
    + {{:: 'openid-connect-config' | translate}} {{:: 'openid-connect-config.tooltip' | translate}} +
    + +
    + +
    + {{:: 'authorization-url.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'loginHint.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'uiLocales.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'token-url.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.logout-url.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'backchannel-logout.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.disableUserInfo.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'user-info-url.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'client-auth.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.client-id.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'client-secret.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'client-assertion-signing-algorithm.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'issuer.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.default-scopes.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'prompt.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'accepts-prompt-none-forward-from-client.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.validate-signatures.tooltip' | translate}} +
    + +
    + +
    + +
    + +
    + {{:: 'identity-provider.use-jwks-url.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'identity-provider.jwks-url.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'identity-provider.validating-public-key.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'identity-provider.validating-public-key-id.tooltip' | translate}} +
    + +
    + +
    + +
    + +
    + {{:: 'pkce-enabled.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'pkce-method.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'identity-provider.allowed-clock-skew.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.forwarded-query-parameters.tooltip' | translate}} +
    +
    +
    + {{:: 'import-external-idp-config' | translate}} {{:: 'import-external-idp-config.tooltip' | translate}} +
    + +
    + +
    + {{:: 'identity-provider.import-from-url.tooltip' | translate}} +
    +
    + +
    + +
    +
    +
    + + {{:: 'identity-provider.import-from-file.tooltip' | translate}} +
    +
    + + +
    + + {{files[0].name}} + +
    +
    + +
    + +
    +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    + + + diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-openshift-v3-ext.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-openshift-v3-ext.html new file mode 100644 index 0000000..b1c27de --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-openshift-v3-ext.html @@ -0,0 +1,7 @@ +
    + +
    + +
    + {{:: 'openshift.base-url.tooltip' | translate}} +
    diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-openshift-v3.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-openshift-v3.html new file mode 100644 index 0000000..eb42ba1 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-openshift-v3.html @@ -0,0 +1,164 @@ +
    + + + + +
    +
    +
    + +
    + +
    + {{:: 'redirect-uri.tooltip' | translate}} +
    +
    +
    +
    + +
    + +
    + {{:: 'identity-provider.alias.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.display-name.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'social.client-id.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'social.client-secret.tooltip' | translate}} +
    +
    +
    + +
    + +
    + {{:: 'social.default-scopes.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.store-tokens.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.stored-tokens-readable.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.enabled.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.disableUserInfo.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'trust-email.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'link-only.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'hide-on-login-page.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'gui-order.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'first-broker-login-flow.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'post-broker-login-flow.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'sync-mode.tooltip' | translate}} +
    +
    + +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-openshift-v4-ext.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-openshift-v4-ext.html new file mode 100644 index 0000000..46254be --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-openshift-v4-ext.html @@ -0,0 +1,7 @@ +
    + +
    + +
    + {{:: 'openshift4.base-url.tooltip' | translate}} +
    diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-openshift-v4.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-openshift-v4.html new file mode 100644 index 0000000..9e14154 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-openshift-v4.html @@ -0,0 +1,164 @@ +
    + + + + +
    +
    +
    + +
    + +
    + {{:: 'redirect-uri.tooltip' | translate}} +
    +
    +
    +
    + +
    + +
    + {{:: 'identity-provider.alias.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.display-name.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'social.client-id.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'social.client-secret.tooltip' | translate}} +
    +
    +
    + +
    + +
    + {{:: 'social.default-scopes.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.store-tokens.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.stored-tokens-readable.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.enabled.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.disableUserInfo.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'trust-email.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'linkOnly.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'hide-on-login-page.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'gui-order.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'first-broker-login-flow.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'post-broker-login-flow.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'sync-mode.tooltip' | translate}} +
    +
    + +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-paypal-ext.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-paypal-ext.html new file mode 100644 index 0000000..692a078 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-paypal-ext.html @@ -0,0 +1,7 @@ +
    + +
    + +
    + {{:: 'identity-provider.paypal-sandbox.tooltip' | translate}} +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-paypal.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-paypal.html new file mode 100644 index 0000000..62e97ba --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-paypal.html @@ -0,0 +1 @@ +
    diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-saml.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-saml.html new file mode 100644 index 0000000..0142179 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-saml.html @@ -0,0 +1,428 @@ +
    + + + + +
    +
    +
    + +
    + +
    + {{:: 'redirect-uri.tooltip' | translate}} +
    +
    +
    +
    + +
    + +
    + {{:: 'identity-provider.alias.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.display-name.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.enabled.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.store-tokens.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.stored-tokens-readable.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'trust-email.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'link-only.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'hide-on-login-page.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'gui-order.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'first-broker-login-flow.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'post-broker-login-flow.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'sync-mode.tooltip' | translate}} +
    +
    + + + {{:: 'identity-provider.saml.protocol-endpoints.saml.tooltip' | translate}} +
    +
    +
    + {{:: 'saml-config' | translate}} {{:: 'identity-provider.saml-config.tooltip' | translate}} + +
    + +
    + +
    + {{:: 'identity-provider.saml.entity-id.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'saml.single-signon-service-url.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'saml.single-logout-service-url.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'backchannel-logout.tooltip' | translate}} +
    +
    + +
    + + +
    + {{:: 'nameid-policy-format.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'saml.principal-type.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'saml.principal-attribute.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'saml.allow-create.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'http-post-binding-response.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'http-post-binding-for-authn-request.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'http-post-binding-logout.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'want-authn-requests-signed.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'want-assertions-signed.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'want-assertions-encrypted.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'signature-algorithm.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'saml-signature-keyName-transformer.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.force-authentication.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'saml.validate-signature.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'validating-x509-certificate.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.saml.sign-sp-metadata.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'saml.loginHint.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.allowed-clock-skew.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.saml.attribute-consuming-service-index.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.saml.attribute-consuming-service-name.tooltip' | translate}} +
    +
    +
    + {{:: 'identity-provider.saml.requested-authncontext' | translate}} {{:: 'identity-provider.saml.requested-authncontext.tooltip' | translate}} + +
    + +
    +
    + +
    +
    + {{:: 'identity-provider.saml.authncontext-comparison-type.tooltip' | translate}} +
    +
    + +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + {{:: 'identity-provider.saml.authncontext-class-ref.tooltip' | translate}} +
    +
    + +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + {{:: 'identity-provider.saml.authncontext-decl-ref.tooltip' | translate}} +
    +
    +
    + {{:: 'import-external-idp-config' | translate}} {{:: 'import-external-idp-config.tooltip' | translate}} +
    + +
    + +
    + {{:: 'saml.import-from-url.tooltip' | translate}} +
    +
    + +
    + +
    +
    +
    + +
    +
    + + +
    + + {{files[0].name}} + +
    +
    + +
    + +
    +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-social.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-social.html new file mode 100644 index 0000000..b745634 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-social.html @@ -0,0 +1,157 @@ +
    + + + + +
    +
    +
    + +
    + +
    + {{:: 'redirect-uri.tooltip' | translate}} +
    +
    +
    +
    + +
    + +
    + {{:: 'social.client-id.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'social.client-secret.tooltip' | translate}} +
    +
    +
    + +
    + +
    + {{:: 'social.default-scopes.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.store-tokens.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.stored-tokens-readable.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.enabled.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'accepts-prompt-none-forward-from-client.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider.disableUserInfo.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'trust-email.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'link-only.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'hide-on-login-page.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'gui-order.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'first-broker-login-flow.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'post-broker-login-flow.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'sync-mode.tooltip' | translate}} +
    +
    + +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-stackoverflow-ext.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-stackoverflow-ext.html new file mode 100644 index 0000000..5e478f6 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-stackoverflow-ext.html @@ -0,0 +1,7 @@ +
    + +
    + +
    + {{:: 'stackoverflow.key.tooltip' | translate}} +
    diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-stackoverflow.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-stackoverflow.html new file mode 100644 index 0000000..a4630ac --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-stackoverflow.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-twitter-ext.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-twitter-ext.html new file mode 100644 index 0000000..e69de29 diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider-twitter.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-twitter.html new file mode 100644 index 0000000..a4630ac --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider-twitter.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-identity-provider.html b/keycloak-themes/base/admin/resources/partials/realm-identity-provider.html new file mode 100644 index 0000000..3422752 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-identity-provider.html @@ -0,0 +1,81 @@ +
    +

    {{:: 'identity-providers' | translate}}

    +
    +
    + +
    +

    + {{:: 'identity-providers' | translate}} +

    +

    + Through Identity Brokering it's easy to allow users to authenticate to Keycloak using external Identity Providers or Social Networks.
    We have built-in support for OpenID Connect and SAML 2.0 as well as a number of social networks such as Google, GitHub, Facebook and Twitter. +

    +

    To get started select a provider from the dropdown below:

    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    {{:: 'name' | translate}}{{:: 'provider' | translate}}{{:: 'enabled' | translate}}{{:: 'hidden' | translate}}{{:: 'link-only-column' | translate}}{{:: 'gui-order' | translate}}{{:: 'actions' | translate}}
    + + {{identityProvider.displayName}} + {{identityProvider.provider.name}} + {{identityProvider.alias}} + + {{identityProvider.providerId}}{{identityProvider.config.guiOrder}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-keys-disabled.html b/keycloak-themes/base/admin/resources/partials/realm-keys-disabled.html new file mode 100644 index 0000000..242c841 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-keys-disabled.html @@ -0,0 +1,70 @@ + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    {{:: 'algorithm' | translate}}{{:: 'type' | translate}}{{:: 'kid' | translate}}{{:: 'priority' | translate}}{{:: 'provider' | translate}}{{:: 'publicKeys' | translate}}
    {{key.algorithm}}{{key.type}}{{key.kid}}{{key.providerPriority}}{{key.provider.name}}{{:: 'publicKey' | translate}}{{:: 'certificate' | translate}}
    + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-keys-generic.html b/keycloak-themes/base/admin/resources/partials/realm-keys-generic.html new file mode 100644 index 0000000..dd2017a --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-keys-generic.html @@ -0,0 +1,69 @@ + + +
    + + + + + + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    + {{:: 'console-display-name.tooltip' | translate}} +
    + + +
    + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-keys-passive.html b/keycloak-themes/base/admin/resources/partials/realm-keys-passive.html new file mode 100644 index 0000000..65f934a --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-keys-passive.html @@ -0,0 +1,70 @@ + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    {{:: 'algorithm' | translate}}{{:: 'type' | translate}}{{:: 'kid' | translate}}{{:: 'priority' | translate}}{{:: 'provider' | translate}}{{:: 'publicKeys' | translate}}
    {{key.algorithm}}{{key.type}}{{key.kid}}{{key.providerPriority}}{{key.provider.name}}{{:: 'publicKey' | translate}}{{:: 'certificate' | translate}}
    + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-keys-providers.html b/keycloak-themes/base/admin/resources/partials/realm-keys-providers.html new file mode 100644 index 0000000..c303a38 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-keys-providers.html @@ -0,0 +1,75 @@ + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    {{:: 'name' | translate}}{{:: 'provider' | translate}}{{:: 'providerHelpText' | translate}}{{:: 'priority' | translate}}{{:: 'actions' | translate}}
    {{instance.name}}{{instance.providerId}}{{instance.provider.helpText}}{{instance.config['priority'][0]}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    + +
    + + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-keys.html b/keycloak-themes/base/admin/resources/partials/realm-keys.html new file mode 100644 index 0000000..ef05d45 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-keys.html @@ -0,0 +1,73 @@ + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    {{:: 'algorithm' | translate}}{{:: 'type' | translate}}{{:: 'kid' | translate}}{{:: 'use' | translate}}{{:: 'priority' | translate}}{{:: 'provider' | translate}}{{:: 'publicKeys' | translate}}
    {{key.algorithm}}{{key.type}}{{key.kid}}{{key.use}}{{key.providerPriority}}{{key.provider.name}}{{:: 'publicKey' | translate}}{{:: 'certificate' | translate}}
    + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-list.html b/keycloak-themes/base/admin/resources/partials/realm-list.html new file mode 100644 index 0000000..099fe6d --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-list.html @@ -0,0 +1,20 @@ +
    + +

    {{:: 'realms' | translate}}

    + + + + + + + + + + + + +
    {{:: 'realm' | translate}}
    {{r.realm}}
    +
    + + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-localization-detail.html b/keycloak-themes/base/admin/resources/partials/realm-localization-detail.html new file mode 100644 index 0000000..c790256 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-localization-detail.html @@ -0,0 +1,50 @@ +
    + + + +
    +
    +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    + +
    +
    + + +
    +
    + +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-localization-upload.html b/keycloak-themes/base/admin/resources/partials/realm-localization-upload.html new file mode 100644 index 0000000..a15352c --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-localization-upload.html @@ -0,0 +1,37 @@ +
    + + + + +
    +
    + +
    + +
    +
    +
    + +
    +
    + + +
    + + {{files[0].name}} + +
    +
    +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-localization.html b/keycloak-themes/base/admin/resources/partials/realm-localization.html new file mode 100644 index 0000000..04f9bd6 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-localization.html @@ -0,0 +1,61 @@ +
    + + + + +
    +
    + +
    + +
    +
    + {{:: 'no-localizations-configured' | translate}} +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + + + + + + + + + + + + + + + +
    + +
    {{:: 'key' | translate}}{{:: 'value' | translate}}{{:: 'actions' | translate}}
    {{pair[0]}}{{pair[1]}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-login-settings.html b/keycloak-themes/base/admin/resources/partials/realm-login-settings.html new file mode 100644 index 0000000..7f68373 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-login-settings.html @@ -0,0 +1,107 @@ +
    + + +
    +
    +
    + +
    + +
    + {{:: 'registrationAllowed.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'registrationEmailAsUsername.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'editUsernameAllowed.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'resetPasswordAllowed.tooltip' |translate}} +
    +
    + +
    + +
    + {{:: 'rememberMe.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'verifyEmail.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'loginWithEmailAllowed.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'duplicateEmailsAllowed.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'sslRequired.tooltip' | translate}} +
    +
    + +
    +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    + {{:: 'acr-loa-map.tooltip' | translate}} +
    +
    + +
    +
    + + +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-role-users.html b/keycloak-themes/base/admin/resources/partials/realm-role-users.html new file mode 100644 index 0000000..11cbbc6 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-role-users.html @@ -0,0 +1,50 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{:: 'username' | translate}}{{:: 'last-name' | translate}}{{:: 'first-name' | translate}}{{:: 'email' | translate}}
    +
    + + + +
    +
    {{user.username}}{{user.lastName}}{{user.firstName}}{{user.email}}{{:: 'edit' | translate}}
    {{:: 'no-role-members' | translate}}{{:: 'no-role-members' | translate}}
    + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-smtp.html b/keycloak-themes/base/admin/resources/partials/realm-smtp.html new file mode 100644 index 0000000..7533071 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-smtp.html @@ -0,0 +1,96 @@ +
    + + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    +
    +
    + +
    + +
    + {{:: 'fromDisplayName.tooltip' | translate}} +
    +
    + +
    + +
    +
    +
    + +
    + +
    + {{:: 'replyToDisplayName.tooltip' | translate}} +
    +
    + +
    + +
    +
    +
    + +
    + +
    + {{:: 'envelopeFrom.tooltip' | translate}} +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    + +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    + {{:: 'smtp-password.tooltip' | translate}} +
    + +
    +
    + + +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-theme-settings.html b/keycloak-themes/base/admin/resources/partials/realm-theme-settings.html new file mode 100644 index 0000000..be74a2a --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-theme-settings.html @@ -0,0 +1,97 @@ +
    + + +
    +
    +
    + +
    +
    + +
    +
    + {{:: 'login-theme.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{ 'account-theme.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'select-theme-admin-console' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'select-theme-email' | translate}} +
    +
    + +
    + +
    +
    +
    + + +
    + +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-tokens.html b/keycloak-themes/base/admin/resources/partials/realm-tokens.html new file mode 100644 index 0000000..65232d2 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-tokens.html @@ -0,0 +1,401 @@ +
    + + +
    + +
    + + +
    + +
    + + {{:: 'default-signature-algorithm.tooltip' | translate}} + +
    + +
    + + +
    + +
    + + {{:: 'revoke-refresh-token.tooltip' | translate}} + +
    + +
    + + +
    + +
    + + {{:: 'refresh-token-max-reuse.tooltip' | translate}} + +
    + +
    + + +
    + + +
    + {{:: 'sso-session-idle.tooltip' | translate}} + +
    + +
    + + +
    + + +
    + {{:: 'sso-session-max.tooltip' | translate}} +
    + +
    + + +
    + + +
    + {{:: 'sso-session-idle-remember-me.tooltip' | translate}} +
    + +
    + + +
    + + +
    + {{:: 'sso-session-max-remember-me.tooltip' | translate}} +
    + +
    + + +
    + + +
    + {{:: 'offline-session-idle.tooltip' | translate}} +
    + + +
    + +
    + +
    + {{:: 'offline-session-max-limited.tooltip' | translate}} +
    +
    + +
    + + +
    + {{:: 'offline-session-max.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'client-offline-session-idle.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'client-offline-session-max.tooltip' | translate}} +
    + +
    + +
    + + +
    + {{:: 'client-session-idle.tooltip' | translate}} +
    + +
    + +
    + + +
    + {{:: 'client-session-max.tooltip' | translate}} +
    + +
    + + +
    + + +
    + {{:: 'access-token-lifespan.tooltip' | translate}} +
    + +
    + + +
    + + +
    + {{:: 'access-token-lifespan-for-implicit-flow.tooltip' | translate}} +
    + +
    + + +
    + + +
    + {{:: 'client-login-timeout.tooltip' | translate}} +
    + +
    + + +
    + + +
    + {{:: 'login-timeout.tooltip' | translate}} +
    + +
    + + +
    + + +
    + + {{:: 'login-action-timeout.tooltip' | translate}} + +
    + +
    + + +
    + + +
    + + {{:: 'action-token-generated-by-user-lifespan.tooltip' | translate}} + +
    + +
    + + +
    + + +
    + + {{:: 'action-token-generated-by-admin-lifespan.tooltip' | translate}} + +
    + +
    + + +
    + + +
    + + {{:: 'request-uri-lifespan.tooltip' | translate}} + +
    + +
    + +
    + + + + +
    + + {{:: 'action-token-generated-by-user.tooltip' | translate}} + +
    + +
    + + +
    + + +
    + {{:: 'oauth2-device-code-lifespan.tooltip' | translate}} +
    + +
    + + +
    + +
    + {{:: 'oauth2-device-polling-interval.tooltip' | translate}} +
    + +
    +
    + + +
    +
    + +
    + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/realm-user-profile.html b/keycloak-themes/base/admin/resources/partials/realm-user-profile.html new file mode 100644 index 0000000..a8c9b03 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/realm-user-profile.html @@ -0,0 +1,372 @@ +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    + + +
    +
    +
    + +
    + +
    +

    + {{:: 'user.profile.attribute' | translate}} {{currentAttribute.name}} {{:: 'configuration' | translate}} + +

    + + {{:: 'user.profile.attribute.name.tooltip' | translate}} +
    + +
    +
    +
    + + {{:: 'user.profile.attribute.displayName.tooltip' | translate}} +
    + +
    +
    + +
    + +
    +
    + +
    +
    + {{:: 'user.profile.attribute.group.tooltip' | translate}} +
    + +
    + + {{:: 'user.profile.attribute.selector.scopes.tooltip' | translate}} +
    + +
    +
    +
    + + {{:: 'user.profile.attribute.required.tooltip' | translate}} +
    + +
    +
    +
    + + {{:: 'user.profile.attribute.required.roles.tooltip' | translate}} +
    + +
    +
    +
    + + {{:: 'user.profile.attribute.required.scopes.tooltip' | translate}} +
    + +
    +
    +
    + {{:: 'user.profile.attribute.permission' | translate}} +
    + + {{:: 'user.profile.attribute.canUserView.tooltip' | translate}} +
    + +
    +
    +
    + + {{:: 'user.profile.attribute.canAdminView.tooltip' | translate}} +
    + +
    +
    +
    + + {{:: 'user.profile.attribute.canUserEdit.tooltip' | translate}} +
    + +
    +
    +
    + + {{:: 'user.profile.attribute.canAdminEdit.tooltip' | translate}} +
    + +
    +
    +
    +
    + {{:: 'user.profile.attribute.validation' | translate}} +
    + + {{:: 'user.profile.attribute.validation.add.validator.tooltip' | translate}} +
    + +
    +
    + +

    +

    +
    + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + +
    +
    +
    + {{:: 'user.profile.attribute.annotation' | translate}} +
    + + + + + + + + + + + + + + + + + + + + +
    {{:: 'key' | translate}}{{:: 'value' | translate}}{{:: 'actions' | translate}}
    {{key}}{{:: 'delete' | translate}}
    {{:: 'add' | translate}} +
    +
    +
    +
    +

    +

    + + +
    +
    +
    + +
    +

    + {{:: 'user.profile.attributegroup' | translate}} {{currentAttributeGroup.name}} {{:: 'configuration' | translate}} + +

    + + {{:: 'user.profile.attributegroup.name.tooltip' | translate}} +
    + +
    +
    +
    + + {{:: 'user.profile.attributegroup.displayHeader.tooltip' | translate}} +
    + +
    +
    +
    + + {{:: 'user.profile.attributegroup.displayDescription.tooltip' | translate}} +
    + +
    +
    + +
    + {{:: 'user.profile.attributegroup.annotation' | translate}} +
    + + + + + + + + + + + + + + + + + + + + +
    {{:: 'key' | translate}}{{:: 'value' | translate}}{{:: 'actions' | translate}}
    {{key}}{{:: 'delete' | translate}}
    {{:: 'add' | translate}} +
    +
    +
    +
    +

    +

    + + +
    +
    +
    + +
    + + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/required-actions.html b/keycloak-themes/base/admin/resources/partials/required-actions.html new file mode 100644 index 0000000..ab16456 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/required-actions.html @@ -0,0 +1,38 @@ +
    +

    {{:: 'authentication' | translate}}

    + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    {{:: 'required-action' | translate}}{{:: 'enabled' | translate}}{{:: 'default-action' | translate}}
    + + + {{requiredAction.name}} +
    {{:: 'no-required-actions-configured' | translate}}
    + +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/role-attributes.html b/keycloak-themes/base/admin/resources/partials/role-attributes.html new file mode 100644 index 0000000..b9cbbd7 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/role-attributes.html @@ -0,0 +1,41 @@ +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + +
    {{:: 'key' | translate}}{{:: 'value' | translate}}{{:: 'actions' | translate}}
    {{key}}{{:: 'delete' | translate}}
    {{:: 'add' | translate}}
    + +
    +
    + + +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/role-detail.html b/keycloak-themes/base/admin/resources/partials/role-detail.html new file mode 100644 index 0000000..7595f65 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/role-detail.html @@ -0,0 +1,135 @@ +
    + + + + + +
    +
    +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    + +
    + +
    + {{:: 'composite-roles.tooltip' | translate}} +
    +
    + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    + +
    + {{:: 'composite-roles' | translate}} +
    + + +
    +
    +
    + + {{:: 'composite.available-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'composite.associated-roles.tooltip' | translate}} + + +
    +
    +
    +
    + +
    + +
    + + +
    + + +
    +
    +
    + + {{:: 'composite.available-roles-client.tooltip' | translate}} + + +
    +
    + + {{:: 'composite.associated-roles-client.tooltip' | translate}} + + +
    +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/role-list.html b/keycloak-themes/base/admin/resources/partials/role-list.html new file mode 100644 index 0000000..6329ccc --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/role-list.html @@ -0,0 +1,63 @@ +
    +

    Roles

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    + + +
    +
    {{:: 'role-name' | translate}}{{:: 'composite' | translate}}{{:: 'description' | translate}}{{:: 'actions' | translate}}
    {{role.name}}{{role.description}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    {{:: 'no-results' | translate}}{{:: 'no-realm-roles-available' | translate}}
    +
    + + + +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/role-mappings.html b/keycloak-themes/base/admin/resources/partials/role-mappings.html new file mode 100644 index 0000000..184a849 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/role-mappings.html @@ -0,0 +1,119 @@ +
    + + + + +
    +
    + + +
    +
    +
    + + + + {{:: 'user.add-selected.tooltip' | translate}} +
    +
    + + {{:: 'user.assigned-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'user.effective-roles.tooltip' | translate}} + +
    +
    +
    +
    + +
    + +
    + + +
    + + +
    +
    +
    + + {{:: 'user.available-roles.tooltip' | translate}} + + +
    +
    + + {{:: 'user.assigned-roles-client.tooltip' | translate}} + + +
    +
    + + {{:: 'user.effective-roles-client.tooltip' | translate}} + +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/server-info-providers.html b/keycloak-themes/base/admin/resources/partials/server-info-providers.html new file mode 100644 index 0000000..be741c1 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/server-info-providers.html @@ -0,0 +1,55 @@ +
    +

    + {{:: 'server-info' | translate}} + +

    + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +
    +
    +
    {{:: 'spi' | translate}}{{:: 'providers' | translate}}
    {{spi.name}} +
    + {{providerName}} + + + + + + + +
    {{key}}{{value}}
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/server-info.html b/keycloak-themes/base/admin/resources/partials/server-info.html new file mode 100644 index 0000000..6d24419 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/server-info.html @@ -0,0 +1,135 @@ +
    +

    + {{:: 'server-info' | translate}} + +

    + + + + + + + + + + + + + + + + +
    {{:: 'server-version' | translate}}{{serverInfo.systemInfo.version}}
    {{:: 'server-time' | translate}}{{serverInfo.systemInfo.serverTime}}
    {{:: 'server-uptime' | translate}}{{serverInfo.systemInfo.uptime}}
    + + + {{:: 'profile' | translate}} + + + + + + + + + + + + + + + + + + +
    {{:: 'server-profile' | translate}}{{serverInfo.profileInfo.name | capitalize}}
    + {{:: 'server-disabled' | translate}} + {{:: 'server-disabled.tooltip' | translate}} + {{serverInfo.profileInfo.disabledFeatures.sort().join(', ')}}
    + {{:: 'server-preview' | translate}} + {{:: 'server-preview.tooltip' | translate}} + {{serverInfo.profileInfo.previewFeatures.sort().join(', ')}}
    + {{:: 'server-experimental' | translate}} + {{:: 'server-experimental.tooltip' | translate}} + {{serverInfo.profileInfo.experimentalFeatures.sort().join(', ')}}
    + +
    + {{:: 'memory' | translate}} + + + + + + + + + + + + + +
    {{:: 'total-memory' | translate}}{{serverInfo.memoryInfo.totalFormated}}
    {{:: 'free-memory' | translate}}{{serverInfo.memoryInfo.freeFormated}} ({{serverInfo.memoryInfo.freePercentage}}%)
    {{:: 'used-memory' | translate}}{{serverInfo.memoryInfo.usedFormated}}
    +
    + +
    + {{:: 'system' | translate}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{:: 'current-working-directory' | translate}}{{serverInfo.systemInfo.userDir}}
    {{:: 'java-version' | translate}}{{serverInfo.systemInfo.javaVersion}}
    {{:: 'java-vendor' | translate}}{{serverInfo.systemInfo.javaVendor}}
    {{:: 'java-runtime' | translate}}{{serverInfo.systemInfo.javaRuntime}}
    {{:: 'java-vm' | translate}}{{serverInfo.systemInfo.javaVm}}
    {{:: 'java-vm-version' | translate}}{{serverInfo.systemInfo.javaVmVersion}}
    {{:: 'java-home' | translate}}{{serverInfo.systemInfo.javaHome}}
    {{:: 'user-name' | translate}}{{serverInfo.systemInfo.userName}}
    {{:: 'user-timezone' | translate}}{{serverInfo.systemInfo.userTimezone}}
    {{:: 'user-locale' | translate}}{{serverInfo.systemInfo.userLocale}}
    {{:: 'system-encoding' | translate}}{{serverInfo.systemInfo.fileEncoding}}
    {{:: 'operating-system' | translate}}{{serverInfo.systemInfo.osName}} {{serverInfo.systemInfo.osVersion}}
    {{:: 'os-architecture' | translate}}{{serverInfo.systemInfo.osArchitecture}}
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/session-realm.html b/keycloak-themes/base/admin/resources/partials/session-realm.html new file mode 100644 index 0000000..79232a0 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/session-realm.html @@ -0,0 +1,34 @@ +
    +

    {{:: 'sessions' | translate}}

    + + + + + + + + + + + + + + + + + + + + + +
    + +
    {{:: 'client' | translate}}{{:: 'active-sessions' | translate}}{{:: 'offline-sessions' | translate}}
    {{data.clientId}}{{data.active}}{{data.offline}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/session-revocation.html b/keycloak-themes/base/admin/resources/partials/session-revocation.html new file mode 100644 index 0000000..03c6864 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/session-revocation.html @@ -0,0 +1,30 @@ +
    +

    {{:: 'sessions' | translate}}

    + + + +
    +
    +
    + +
    + +
    + {{:: 'not-before.tooltip' | translate}} +
    +
    + +
    +
    + + + +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/user-attributes.html b/keycloak-themes/base/admin/resources/partials/user-attributes.html new file mode 100644 index 0000000..10e3d8f --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-attributes.html @@ -0,0 +1,41 @@ +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + +
    {{:: 'key' | translate}}{{:: 'value' | translate}}{{:: 'actions' | translate}}
    {{key}}{{:: 'delete' | translate}}
    {{:: 'add' | translate}}
    + +
    +
    + + +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/user-consents.html b/keycloak-themes/base/admin/resources/partials/user-consents.html new file mode 100644 index 0000000..76eb0a8 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-consents.html @@ -0,0 +1,41 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{:: 'client' | translate}}{{:: 'granted-client-scopes' | translate}}{{:: 'additional-grants' | translate}}{{:: 'consent-created-date' | translate}}{{:: 'consent-last-updated-date' | translate}}{{:: 'action' | translate}}
    {{consent.clientId}} + + , {{clientScope}} + + + + , {{additionalGrant.key}} + + {{consent.createdDate | date :'short'}}{{consent.lastUpdatedDate | date :'short'}}{{:: 'revoke' | translate}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/user-credentials.html b/keycloak-themes/base/admin/resources/partials/user-credentials.html new file mode 100644 index 0000000..737b4b1 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-credentials.html @@ -0,0 +1,173 @@ +
    + + + + +
    + +
    + + {{:: 'supported-user-storage-credential-types' | translate}} + {{:: 'supported-user-storage-credential-types.tooltip' | translate}} + + + + + + + + + + + + + +
    + +
    + + {{:: 'manage-credentials' | translate}} + {{:: 'manage-credentials.tooltip' | translate}} + + + {{:: 'manage-credentials' | translate}} + + + + + + + + + + + + + + + + + + + + +
    + +
    + {{ (hasPassword ? 'reset-password' : 'set-password') | translate }} +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    + {{:: 'credentials.temporary.tooltip' | translate}} +
    + +
    +
    + +
    +
    +
    + +
    + {{:: 'disable-credentials' | translate}} +
    + + +
    + +
    + {{:: 'credentials.disableable.tooltip' | translate}} +
    +
    + + +
    + +
    + {{:: 'credentials.disable.tooltip' | translate}} +
    +
    + +
    + {{:: 'credential-reset-actions' | translate}} +
    + + +
    + +
    + {{:: 'credentials.reset-actions.tooltip' | translate}} +
    +
    + + +
    + + +
    + {{:: 'credential-reset-actions-timeout.tooltip' | translate}} +
    +
    + + +
    + +
    + {{:: 'credentials.reset-actions-email.tooltip' | translate}} +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/user-detail.html b/keycloak-themes/base/admin/resources/partials/user-detail.html new file mode 100644 index 0000000..10ca22c --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-detail.html @@ -0,0 +1,186 @@ +
    + + + + +
    + +
    +
    + +
    + +
    +
    + +
    + +
    + {{user.createdTimestamp|date:('dateFormat' | translate)}} {{user.createdTimestamp|date:('timeFormat' | translate)}} +
    +
    + +
    + +
    + + +
    +
    + + +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    + +
    + +
    + +
    + {{:: 'user-enabled.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'user-temporarily-locked.tooltip' | translate}} +
    + +
    +
    +
    + + + {{:: 'user-link.tooltip' | translate}} +
    +
    + + + {{:: 'user-origin.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'email-verified.tooltip' | translate}} +
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +
    +
    +
    {{:: 'groups-joining-path' | translate}}{{:: 'actions' | translate}}
    {{group.path}} + {{:: 'remove' | translate}} +
    {{:: 'groups-joining-no-selected' | translate}}
    +
    + {{:: 'groups-joining.tooltip' | translate}} +
    +
    + + +
    + +
    + {{:: 'required-user-actions.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    +
    + +
    + + +
    + +
    + {{:: 'impersonate-user.tooltip' | translate}} +
    + +
    + +
    +
    + + +
    + +
    + + +
    +
    + +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/user-federated-identity-detail.html b/keycloak-themes/base/admin/resources/partials/user-federated-identity-detail.html new file mode 100644 index 0000000..aa5d049 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-federated-identity-detail.html @@ -0,0 +1,53 @@ +
    + + +

    {{:: 'add-identity-provider-link' | translate}}

    + + + +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    + +
    + {{:: 'identity-provider-user-id.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'identity-provider-username.tooltip' | translate}} +
    + +
    + + +
    +
    + + +
    +
    + +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/user-federated-identity-list.html b/keycloak-themes/base/admin/resources/partials/user-federated-identity-list.html new file mode 100644 index 0000000..82f96f6 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-federated-identity-list.html @@ -0,0 +1,41 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    {{:: 'identity-provider-alias' | translate}}{{:: 'provider-user-id' | translate}}{{:: 'provider-username' | translate}}{{:: 'action' | translate}}
    {{identity.identityProvider}}{{identity.userId}}{{identity.userName}}{{:: 'remove' | translate}}
    {{:: 'no-identity-provider-links-available' | translate}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/user-federation.html b/keycloak-themes/base/admin/resources/partials/user-federation.html new file mode 100644 index 0000000..3e702f3 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-federation.html @@ -0,0 +1,69 @@ +
    +

    + {{:: 'user-federation' | translate}} +

    + +
    +
    + +
    +

    + {{:: 'user-federation' | translate}} +

    +

    Keycloak can federate external user databases. Out of the box we have support for LDAP and Active Directory.

    +

    To get started select a provider from the dropdown below:

    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + +
    +
    +
    {{:: 'id' | translate}}{{:: 'enabled' | translate}}{{:: 'provider-name' | translate}}{{:: 'priority' | translate}}{{:: 'actions' | translate}}
    {{getInstanceName(instance)}}{{isProviderEnabled(instance)}}{{getInstanceProvider(instance) | capitalize}}{{getInstancePriority(instance)}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    {{:: 'no-user-federation-providers-configured' | translate}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/user-group-membership.html b/keycloak-themes/base/admin/resources/partials/user-group-membership.html new file mode 100644 index 0000000..abfb237 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-group-membership.html @@ -0,0 +1,114 @@ +
    + + + + +
    +
    + + +
    +
    +
    + + + + + + + + + + + +
    +
    +
    + + {{:: 'group-membership.tooltip' | translate}} +
    +
    +
    + +
    + +
    +
    +
    +   + +
    + +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    + + + + + + + + + + + +
    + +
    +
    + + {{:: 'membership.available-groups.tooltip' | translate}} +
    +
    +
    + +
    + +
    +
    +
    +   + +
    + +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/user-list.html b/keycloak-themes/base/admin/resources/partials/user-list.html new file mode 100644 index 0000000..687936c --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-list.html @@ -0,0 +1,69 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    + + +
    + + {{:: 'add-user' | translate}} +
    +
    +
    {{:: 'id' | translate}}{{:: 'username' | translate}}{{:: 'email' | translate}}{{:: 'last-name' | translate}}{{:: 'first-name' | translate}}{{:: 'actions' | translate}}
    +
    + + + +
    +
    {{user.id}}{{user.username}}{{user.email}}{{user.lastName}}{{user.firstName}}{{:: 'edit' | translate}}{{:: 'impersonate' | translate}}{{:: 'delete' | translate}}
    {{:: 'users.instruction' | translate}}{{:: 'no-results' | translate}}{{:: 'no-users-available' | translate}}
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/user-offline-sessions.html b/keycloak-themes/base/admin/resources/partials/user-offline-sessions.html new file mode 100644 index 0000000..0194bca --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-offline-sessions.html @@ -0,0 +1,35 @@ +
    + + + + + + + + + + + + + + + + + + + +
    {{:: 'ip-address' | translate}}{{:: 'started' | translate}}{{:: 'last-refresh' | translate}}
    {{session.ipAddress}}{{session.start | date:'medium'}}{{session.lastAccess | date:'medium'}}
    + +
    +
    + +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/user-sessions.html b/keycloak-themes/base/admin/resources/partials/user-sessions.html new file mode 100644 index 0000000..02c1959 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-sessions.html @@ -0,0 +1,43 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    {{:: 'ip-address' | translate}}{{:: 'started' | translate}}{{:: 'last-access' | translate}}{{:: 'clients' | translate}}{{:: 'action' | translate}}
    {{session.ipAddress}}{{session.start | date:'medium'}}{{session.lastAccess | date:'medium'}} + + + {{:: 'logout' | translate}}
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/user-storage-generic.html b/keycloak-themes/base/admin/resources/partials/user-storage-generic.html new file mode 100644 index 0000000..2b2456c --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-storage-generic.html @@ -0,0 +1,246 @@ +
    + + + + +
    +
    + {{:: 'required-settings' | translate}} +
    + +
    + +
    +
    +
    + +
    + +
    + {{:: 'user-storage.enabled.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'console-display-name.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'priority.tooltip' | translate}} +
    + + + +
    + +
    + {{:: 'sync-settings' | translate}} +
    + +
    + +
    + {{:: 'periodic-full-sync.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'full-sync-period.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'periodic-changed-users-sync.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'changed-users-sync-period.tooltip' | translate}} +
    +
    + + +
    + {{:: 'user-storage-cache-policy' | translate}} +
    + +
    +
    + +
    +
    + {{:: 'userStorage.cachePolicy.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'userStorage.cachePolicy.evictionDay.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'userStorage.cachePolicy.evictionHour.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'userStorage.cachePolicy.evictionMinute.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'userStorage.cachePolicy.maxLifespan.tooltip' | translate}} +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + + + + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/user-storage-kerberos.html b/keycloak-themes/base/admin/resources/partials/user-storage-kerberos.html new file mode 100644 index 0000000..b7fa6ef --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-storage-kerberos.html @@ -0,0 +1,264 @@ +
    + + + + +
    +
    + {{:: 'required-settings' | translate}} +
    + +
    + +
    +
    +
    + +
    + +
    + {{:: 'user-storage.enabled.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'console-display-name.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'priority.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'kerberos-realm.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'server-principal.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'keytab.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'debug.tooltip' | translate}} +
    + +
    + +
    + +
    + {{:: 'allow-password-authentication.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'edit-mode.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'update-profile-first-login.tooltip' | translate}} +
    + +
    + +
    + {{:: 'user-storage-cache-policy' | translate}} +
    + +
    +
    + +
    +
    + {{:: 'userStorage.cachePolicy.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'userStorage.cachePolicy.evictionDay.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'userStorage.cachePolicy.evictionHour.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'userStorage.cachePolicy.evictionMinute.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'userStorage.cachePolicy.maxLifespan.tooltip' | translate}} +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/user-storage-ldap-mapper-detail.html b/keycloak-themes/base/admin/resources/partials/user-storage-ldap-mapper-detail.html new file mode 100644 index 0000000..88de0ff --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-storage-ldap-mapper-detail.html @@ -0,0 +1,64 @@ +
    + + +

    {{mapper.name|capitalize}}

    +

    {{:: 'add-user-federation-mapper' | translate}}

    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    + {{:: 'mapper.name.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{mapperType.helpText}} +
    +
    + +
    + +
    + {{mapperType.helpText}} +
    + + + +
    + +
    +
    + + + + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/user-storage-ldap-mappers.html b/keycloak-themes/base/admin/resources/partials/user-storage-ldap-mappers.html new file mode 100644 index 0000000..794e83e --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-storage-ldap-mappers.html @@ -0,0 +1,46 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    {{:: 'name' | translate}}{{:: 'type' | translate}}
    {{mapper.name}}{{mapper.providerId}}
    {{:: 'no-mappers-available' | translate}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/user-storage-ldap.html b/keycloak-themes/base/admin/resources/partials/user-storage-ldap.html new file mode 100644 index 0000000..98f058e --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-storage-ldap.html @@ -0,0 +1,568 @@ +
    + + + + +
    +
    + {{:: 'required-settings' | translate}} +
    + +
    + +
    +
    +
    + +
    + +
    + {{:: 'user-storage.enabled.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'console-display-name.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'priority.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.import-enabled.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'ldap.edit-mode.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.sync-registrations.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + +
    +
    + {{:: 'ldap.vendor.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'username-ldap-attribute.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'rdn-ldap-attribute.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'uuid-ldap-attribute.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.user-object-classes.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.connection-url.tooltip' | translate}} + +
    +
    + +
    + +
    + {{:: 'ldap.users-dn.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.custom-user-ldap-filter.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'ldap.search-scope.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'ldap.authentication-type.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.bind-dn.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.bind-credential.tooltip' | translate}} + +
    +
    + +
    + {{:: 'advanced-ldap-settings' | translate}} +
    + +
    + +
    + {{:: 'ldap.startTls.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.usePasswordModifyExtendedOp.tooltip' | translate}} +
    + + {{:: 'ldap-query-supported-extensions.tooltip' | translate}} +
    +
    +
    + +
    + +
    + {{:: 'ldap.validate-password-policy.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'trust-email.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'ldap.use-truststore-spi.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.connection-timeout.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.read-timeout.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.pagination.tooltip' | translate}} +
    +
    + +
    + {{:: 'connection-pooling' | translate}} +
    + +
    + +
    + {{:: 'ldap.connection-pooling.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.connection-pooling.authentication.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.connection-pooling.debug.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.connection-pooling.initsize.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.connection-pooling.maxsize.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.connection-pooling.prefsize.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.connection-pooling.protocol.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.connection-pooling.timeout.tooltip' | translate}} +
    +
    + +
    + {{:: 'kerberos-integration' | translate}} +
    + +
    + +
    + {{:: 'ldap.allow-kerberos-authentication.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'kerberos-realm.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'server-principal.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'keytab.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'debug.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.use-kerberos-for-password-authentication.tooltip' | translate}} +
    +
    + +
    + {{:: 'sync-settings' | translate}} +
    + +
    + +
    + {{:: 'ldap.batch-size.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.periodic-full-sync.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'full-sync-period.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.periodic-changed-users-sync.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'ldap.changed-users-sync-period.tooltip' | translate}} +
    +
    + +
    + {{:: 'user-storage-cache-policy' | translate}} +
    + +
    +
    + +
    +
    + {{:: 'userStorage.cachePolicy.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'userStorage.cachePolicy.evictionDay.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'userStorage.cachePolicy.evictionHour.tooltip' | translate}} +
    +
    + +
    +
    + +
    +
    + {{:: 'userStorage.cachePolicy.evictionMinute.tooltip' | translate}} +
    +
    + +
    + +
    + {{:: 'userStorage.cachePolicy.maxLifespan.tooltip' | translate}} +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + + + + + +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/admin/resources/partials/user-storage.html b/keycloak-themes/base/admin/resources/partials/user-storage.html new file mode 100644 index 0000000..93ca5a9 --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/user-storage.html @@ -0,0 +1,45 @@ +
    +

    + {{:: 'user-storage' | translate}} +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + +
    +
    +
    {{:: 'id' | translate}}{{:: 'provider-name' | translate}}{{:: 'enabled' | translate}}{{:: 'priority' | translate}}{{:: 'actions' | translate}}
    {{instance.name}}{{instance.providerId|capitalize}}{{instance.config['enabled'][0]}}{{instance.config['priority'][0]}}{{:: 'edit' | translate}}{{:: 'delete' | translate}}
    {{:: 'no-user-storage-providers-configured' | translate}}
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/partials/webauthn-policy-passwordless.html b/keycloak-themes/base/admin/resources/partials/webauthn-policy-passwordless.html new file mode 100644 index 0000000..b15dfec --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/webauthn-policy-passwordless.html @@ -0,0 +1,177 @@ + + +
    +

    {{:: 'authentication' | translate}}

    + + + + +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-rp-entity-name.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-signature-algorithms.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-rp-id.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-attestation-conveyance-preference.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-authenticator-attachment.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-require-resident-key.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-user-verification-requirement.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-create-timeout.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-avoid-same-authenticator-register.tooltip' | translate}} +
    + +
    + +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + {{:: 'webauthn-acceptable-aaguids.tooltip' | translate}} +
    + +
    +
    + + +
    +
    +
    + +
    + + + diff --git a/keycloak-themes/base/admin/resources/partials/webauthn-policy.html b/keycloak-themes/base/admin/resources/partials/webauthn-policy.html new file mode 100644 index 0000000..e8f785f --- /dev/null +++ b/keycloak-themes/base/admin/resources/partials/webauthn-policy.html @@ -0,0 +1,159 @@ +
    +

    {{:: 'authentication' | translate}}

    + + + + +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-rp-entity-name.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-signature-algorithms.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-rp-id.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-attestation-conveyance-preference.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-authenticator-attachment.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-require-resident-key.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-user-verification-requirement.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-create-timeout.tooltip' | translate}} +
    + +
    + +
    +
    + +
    +
    + {{:: 'webauthn-avoid-same-authenticator-register.tooltip' | translate}} +
    + +
    + +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + {{:: 'webauthn-acceptable-aaguids.tooltip' | translate}} +
    + +
    +
    + + +
    +
    +
    + +
    + + + diff --git a/keycloak-themes/base/admin/resources/templates/authz/kc-authz-modal.html b/keycloak-themes/base/admin/resources/templates/authz/kc-authz-modal.html new file mode 100644 index 0000000..18acf86 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/authz/kc-authz-modal.html @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/authz/kc-tabs-resource-server.html b/keycloak-themes/base/admin/resources/templates/authz/kc-tabs-resource-server.html new file mode 100644 index 0000000..bd20270 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/authz/kc-tabs-resource-server.html @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-component-config.html b/keycloak-themes/base/admin/resources/templates/kc-component-config.html new file mode 100644 index 0000000..840ab1e --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-component-config.html @@ -0,0 +1,67 @@ +
    +
    + + +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + + +
    + +
    +
    + + + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    + +
    +
    + +
    + + {{:: option.helpText | translate}} +
    +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-copy.html b/keycloak-themes/base/admin/resources/templates/kc-copy.html new file mode 100644 index 0000000..d92b2d4 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-copy.html @@ -0,0 +1,18 @@ + + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-dropdown.html b/keycloak-themes/base/admin/resources/templates/kc-dropdown.html new file mode 100644 index 0000000..13874ca --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-dropdown.html @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-edit.html b/keycloak-themes/base/admin/resources/templates/kc-edit.html new file mode 100644 index 0000000..0b98b29 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-edit.html @@ -0,0 +1,22 @@ + + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-menu.html b/keycloak-themes/base/admin/resources/templates/kc-menu.html new file mode 100644 index 0000000..4edc768 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-menu.html @@ -0,0 +1,65 @@ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-modal-message.html b/keycloak-themes/base/admin/resources/templates/kc-modal-message.html new file mode 100644 index 0000000..fc32708 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-modal-message.html @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-modal.html b/keycloak-themes/base/admin/resources/templates/kc-modal.html new file mode 100644 index 0000000..25eee96 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-modal.html @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-paging.html b/keycloak-themes/base/admin/resources/templates/kc-paging.html new file mode 100644 index 0000000..653e4a5 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-paging.html @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-provider-config.html b/keycloak-themes/base/admin/resources/templates/kc-provider-config.html new file mode 100644 index 0000000..88bf771 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-provider-config.html @@ -0,0 +1,104 @@ +
    +
    + + +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + + +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + +
    {{:: 'key' | translate}}{{:: 'value' | translate}}{{:: 'actions' | translate}}
    {{mapEntry['key']}}{{:: 'delete' | translate}} +
    {{:: 'add' | translate}} +
    +
    + + {{:: option.helpText | translate}} +
    +
    diff --git a/keycloak-themes/base/admin/resources/templates/kc-switch.html b/keycloak-themes/base/admin/resources/templates/kc-switch.html new file mode 100644 index 0000000..7f28598 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-switch.html @@ -0,0 +1,12 @@ + +
    + + +
    +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-tabs-authentication.html b/keycloak-themes/base/admin/resources/templates/kc-tabs-authentication.html new file mode 100644 index 0000000..98ad23f --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-tabs-authentication.html @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-tabs-client-role.html b/keycloak-themes/base/admin/resources/templates/kc-tabs-client-role.html new file mode 100644 index 0000000..20f05a9 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-tabs-client-role.html @@ -0,0 +1,17 @@ +
    +

    {{:: 'add-role' | translate}}

    +

    {{role.name|capitalize}}

    + + +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-tabs-client-scope.html b/keycloak-themes/base/admin/resources/templates/kc-tabs-client-scope.html new file mode 100644 index 0000000..72f59e9 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-tabs-client-scope.html @@ -0,0 +1,20 @@ +
    + +

    {{:: 'add-client-scope' | translate}}

    +

    + {{clientScope.name|capitalize}} + +

    + + +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-tabs-client.html b/keycloak-themes/base/admin/resources/templates/kc-tabs-client.html new file mode 100644 index 0000000..4148687 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-tabs-client.html @@ -0,0 +1,65 @@ +
    + +

    {{:: 'add-client' | translate}}

    +

    + {{client.clientId|capitalize}} + +

    + + +
    diff --git a/keycloak-themes/base/admin/resources/templates/kc-tabs-clients.html b/keycloak-themes/base/admin/resources/templates/kc-tabs-clients.html new file mode 100644 index 0000000..8cf318a --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-tabs-clients.html @@ -0,0 +1,16 @@ +
    +

    + {{:: 'clients' | translate}} +

    + + +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-tabs-group-list.html b/keycloak-themes/base/admin/resources/templates/kc-tabs-group-list.html new file mode 100644 index 0000000..5b67035 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-tabs-group-list.html @@ -0,0 +1,11 @@ +
    +

    + {{:: 'user-groups' | translate}} +

    + + +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-tabs-group.html b/keycloak-themes/base/admin/resources/templates/kc-tabs-group.html new file mode 100644 index 0000000..da08252 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-tabs-group.html @@ -0,0 +1,17 @@ +
    +

    + {{group.name|capitalize}} + +

    + + +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-tabs-identity-provider.html b/keycloak-themes/base/admin/resources/templates/kc-tabs-identity-provider.html new file mode 100644 index 0000000..94b2604 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-tabs-identity-provider.html @@ -0,0 +1,16 @@ +
    +

    + {{identityProvider.displayName}} + {{provider.name}} + {{identityProvider.alias}} + + +

    +

    {{:: 'add-identity-provider' | translate}}

    + + +
    diff --git a/keycloak-themes/base/admin/resources/templates/kc-tabs-ldap.html b/keycloak-themes/base/admin/resources/templates/kc-tabs-ldap.html new file mode 100644 index 0000000..a4f17a8 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-tabs-ldap.html @@ -0,0 +1,12 @@ +
    +

    + {{instance.name|capitalize}} + +

    +

    {{:: 'add-user-federation-provider' | translate}}

    + + +
    diff --git a/keycloak-themes/base/admin/resources/templates/kc-tabs-realm.html b/keycloak-themes/base/admin/resources/templates/kc-tabs-realm.html new file mode 100644 index 0000000..e0608aa --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-tabs-realm.html @@ -0,0 +1,24 @@ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-tabs-role.html b/keycloak-themes/base/admin/resources/templates/kc-tabs-role.html new file mode 100644 index 0000000..f00515b --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-tabs-role.html @@ -0,0 +1,16 @@ +
    +

    {{role.name|capitalize}}

    +

    {{:: 'add-role' | translate}}

    + + +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-tabs-user-storage.html b/keycloak-themes/base/admin/resources/templates/kc-tabs-user-storage.html new file mode 100644 index 0000000..03e1ddc --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-tabs-user-storage.html @@ -0,0 +1,11 @@ +
    +

    + {{instance.name|capitalize}} + +

    +

    {{:: 'add-user-storage-provider' | translate}}

    + + +
    diff --git a/keycloak-themes/base/admin/resources/templates/kc-tabs-user.html b/keycloak-themes/base/admin/resources/templates/kc-tabs-user.html new file mode 100644 index 0000000..9c372e3 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-tabs-user.html @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/keycloak-themes/base/admin/resources/templates/kc-tabs-users.html b/keycloak-themes/base/admin/resources/templates/kc-tabs-users.html new file mode 100644 index 0000000..e5771a0 --- /dev/null +++ b/keycloak-themes/base/admin/resources/templates/kc-tabs-users.html @@ -0,0 +1,11 @@ +
    +

    {{:: 'users' | translate}}

    + + +
    \ No newline at end of file diff --git a/keycloak-themes/base/admin/theme.properties b/keycloak-themes/base/admin/theme.properties new file mode 100644 index 0000000..0058af3 --- /dev/null +++ b/keycloak-themes/base/admin/theme.properties @@ -0,0 +1 @@ +locales=ca,de,en,es,fr,fi,it,ja,lt,lv,nl,no,pl,pt-BR,ru,sv,zh-CN diff --git a/keycloak-themes/base/email/html/email-test.ftl b/keycloak-themes/base/email/html/email-test.ftl new file mode 100644 index 0000000..3a52272 --- /dev/null +++ b/keycloak-themes/base/email/html/email-test.ftl @@ -0,0 +1,5 @@ + + +${kcSanitize(msg("emailTestBodyHtml",realmName))?no_esc} + + diff --git a/keycloak-themes/base/email/html/email-verification-with-code.ftl b/keycloak-themes/base/email/html/email-verification-with-code.ftl new file mode 100644 index 0000000..66e8925 --- /dev/null +++ b/keycloak-themes/base/email/html/email-verification-with-code.ftl @@ -0,0 +1,5 @@ + + +${kcSanitize(msg("emailVerificationBodyCodeHtml",code))?no_esc} + + diff --git a/keycloak-themes/base/email/html/email-verification.ftl b/keycloak-themes/base/email/html/email-verification.ftl new file mode 100644 index 0000000..dacabd2 --- /dev/null +++ b/keycloak-themes/base/email/html/email-verification.ftl @@ -0,0 +1,5 @@ + + +${kcSanitize(msg("emailVerificationBodyHtml",link, linkExpiration, realmName, linkExpirationFormatter(linkExpiration)))?no_esc} + + diff --git a/keycloak-themes/base/email/html/event-login_error.ftl b/keycloak-themes/base/email/html/event-login_error.ftl new file mode 100644 index 0000000..022c024 --- /dev/null +++ b/keycloak-themes/base/email/html/event-login_error.ftl @@ -0,0 +1,5 @@ + + +${kcSanitize(msg("eventLoginErrorBodyHtml",event.date,event.ipAddress))?no_esc} + + diff --git a/keycloak-themes/base/email/html/event-remove_totp.ftl b/keycloak-themes/base/email/html/event-remove_totp.ftl new file mode 100644 index 0000000..9a56ed3 --- /dev/null +++ b/keycloak-themes/base/email/html/event-remove_totp.ftl @@ -0,0 +1,5 @@ + + +${kcSanitize(msg("eventRemoveTotpBodyHtml",event.date, event.ipAddress))?no_esc} + + diff --git a/keycloak-themes/base/email/html/event-update_password.ftl b/keycloak-themes/base/email/html/event-update_password.ftl new file mode 100644 index 0000000..27825c7 --- /dev/null +++ b/keycloak-themes/base/email/html/event-update_password.ftl @@ -0,0 +1,5 @@ + + +${kcSanitize(msg("eventUpdatePasswordBodyHtml",event.date, event.ipAddress))?no_esc} + + diff --git a/keycloak-themes/base/email/html/event-update_totp.ftl b/keycloak-themes/base/email/html/event-update_totp.ftl new file mode 100644 index 0000000..3ed37c3 --- /dev/null +++ b/keycloak-themes/base/email/html/event-update_totp.ftl @@ -0,0 +1,5 @@ + + +${kcSanitize(msg("eventUpdateTotpBodyHtml",event.date, event.ipAddress))?no_esc} + + diff --git a/keycloak-themes/base/email/html/executeActions.ftl b/keycloak-themes/base/email/html/executeActions.ftl new file mode 100644 index 0000000..4c837bc --- /dev/null +++ b/keycloak-themes/base/email/html/executeActions.ftl @@ -0,0 +1,9 @@ +<#outputformat "plainText"> +<#assign requiredActionsText><#if requiredActions??><#list requiredActions><#items as reqActionItem>${msg("requiredAction.${reqActionItem}")}<#sep>, + + + + +${kcSanitize(msg("executeActionsBodyHtml",link, linkExpiration, realmName, requiredActionsText, linkExpirationFormatter(linkExpiration)))?no_esc} + + diff --git a/keycloak-themes/base/email/html/identity-provider-link.ftl b/keycloak-themes/base/email/html/identity-provider-link.ftl new file mode 100644 index 0000000..8b67968 --- /dev/null +++ b/keycloak-themes/base/email/html/identity-provider-link.ftl @@ -0,0 +1,5 @@ + + +${kcSanitize(msg("identityProviderLinkBodyHtml", identityProviderAlias, realmName, identityProviderContext.username, link, linkExpiration, linkExpirationFormatter(linkExpiration)))?no_esc} + + \ No newline at end of file diff --git a/keycloak-themes/base/email/html/password-reset.ftl b/keycloak-themes/base/email/html/password-reset.ftl new file mode 100644 index 0000000..b2840b6 --- /dev/null +++ b/keycloak-themes/base/email/html/password-reset.ftl @@ -0,0 +1,5 @@ + + +${kcSanitize(msg("passwordResetBodyHtml",link, linkExpiration, realmName, linkExpirationFormatter(linkExpiration)))?no_esc} + + \ No newline at end of file diff --git a/keycloak-themes/base/email/messages/messages_ca.properties b/keycloak-themes/base/email/messages/messages_ca.properties new file mode 100644 index 0000000..03e0254 --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_ca.properties @@ -0,0 +1,21 @@ +emailVerificationSubject=Verificaci\u00F3 d''email +emailVerificationBody=Alg\u00FA ha creat un compte de {2} amb aquesta adre\u00E7a de correu electr\u00F2nic. Si has estat tu, fes clic a l''enlla\u00E7 seg\u00FCent per verificar la teva adre\u00E7a de correu electr\u00F2nic.\n\n{0}\n\nAquest enlla\u00E7 expirar\u00E0 en {1} minuts.\n\nSi tu no has creat aquest compte, simplement ignora aquest missatge. +emailVerificationBodyHtml=

    Alg\u00FA ha creat un compte de {2} amb aquesta adre\u00E7a de correu electr\u00F2nic. Si has estat tu, fes clic a l''enlla\u00E7 seg\u00FCent per verificar la teva adre\u00E7a de correu electr\u00F2nic.

    {0}

    Aquest enlla\u00E7 expirar\u00E0 en {1} minuts.

    Si tu no has creat aquest compte, simplement ignora aquest missatge.

    +passwordResetSubject=Reinicia contrasenya +passwordResetBody=Alg\u00FA ha demanat de canviar les credencials del teu compte de {2}. Si has estat tu, fes clic a l''enlla\u00E7 seg\u00FCent per a reiniciar-les.\n\n{0}\n\nAquest enlla\u00E7 expirar\u00E0 en {1} minuts.\n\nSi no vols reiniciar les teves credencials, simplement ignora aquest missatge i no es realitzar\u00E0 cap canvi. +passwordResetBodyHtml=

    Alg\u00FA ha demanat de canviar les credencials del teu compte de {2}. Si has estat tu, fes clic a l''enlla\u00E7 seg\u00FCent per a reiniciar-les.

    {0}

    Aquest enlla\u00E7 expirar\u00E0 en {1} minuts.

    Si no vols reiniciar les teves credencials, simplement ignora aquest missatge i no es realitzar\u00E0 cap canvi.

    +executeActionsSubject=Actualitza el teu compte +executeActionsBody=L''administrador ha sol\u00B7licitat que actualitzis el teu compte de {2}. Fes clic a l''enlla\u00E7 inferior per iniciar aquest proc\u00E9s.\n\n{0}\n\nAquest enlla\u00E7 expirar\u00E0 en {1} minutes.\n\nSi no est\u00E0s al tant que l''administrador hagi sol\u00B7licitat aix\u00F2, simplement ignora aquest missatge i no es realitzar\u00E0 cap canvi. +executeActionsBodyHtml=

    L''administrador ha sol\u00B7licitat que actualitzis el teu compte de {2}. Fes clic a l''enlla\u00E7 inferior per iniciar aquest proc\u00E9s.

    {0}

    Aquest enlla\u00E7 expirar\u00E0 en {1} minutes.

    Si no est\u00E0s al tant que l''administrador hagi sol\u00B7licitat aix\u00F2, simplement ignora aquest missatge i no es realitzar\u00E0 cap canvi.

    +eventLoginErrorSubject=Fallada en l''inici de sessi\u00F3 +eventLoginErrorBody=S''ha detectat un intent d''acc\u00E9s fallit al teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l''administrador. +eventLoginErrorBodyHtml=

    S''ha detectat un intent d''acc\u00E9s fallit al teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l''administrador.

    +eventRemoveTotpSubject=Esborrat OTP +eventRemoveTotpBody=OTP s''ha eliminat del teu compte el {0} des de {1}. Si no has estat tu, per favor contacta amb l''administrador. +eventRemoveTotpBodyHtml=

    OTP s''ha eliminat del teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l''administrador. +eventUpdatePasswordSubject=Actualitzaci\u00F3 de contrasenya +eventUpdatePasswordBody=La teva contrasenya s''ha actualitzat el {0} des de {1}. Si no has estat tu, si us plau contacta amb l''administrador. +eventUpdatePasswordBodyHtml=

    La teva contrasenya s''ha actualitzat el {0} des de {1}. Si no has estat tu, si us plau contacta amb l''administrador.

    +eventUpdateTotpSubject=Actualitzaci\u00F3 de OTP +eventUpdateTotpBody=OTP s''ha actualitzat al teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l''administrador. +eventUpdateTotpBodyHtml=

    OTP s''ha actualitzat al teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l''administrador.

    diff --git a/keycloak-themes/base/email/messages/messages_cs.properties b/keycloak-themes/base/email/messages/messages_cs.properties new file mode 100644 index 0000000..2e4fab5 --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_cs.properties @@ -0,0 +1,60 @@ +# encoding: utf-8 +emailVerificationSubject=Ověření e-mailu +emailVerificationBody=Někdo vytvořil účet {2} s touto e-mailovou adresou. Pokud jste to vy, klikněte na níže uvedený odkaz a ověřte svou e-mailovou adresu \n\n{0}\n\nTento odkaz vyprší za {3}.\n\nPokud jste tento účet nevytvořili, tuto zprávu ignorujte. +emailVerificationBodyHtml=

    Někdo vytvořil účet {2} s touto e-mailovou adresou. Pokud jste to vy, klikněte na níže uvedený odkaz a ověřte svou e-mailovou adresu.

    Odkaz na ověření e-mailové adresy

    Platnost odkazu vyprší za {3}.

    Pokud jste tento účet nevytvořili, tuto zprávu ignorujte.

    +emailTestSubject=[KEYCLOAK] - testovací zpráva +emailTestBody=Toto je testovací zpráva +emailTestBodyHtml=

    Toto je testovací zpráva

    +identityProviderLinkSubject=Odkaz {0} +identityProviderLinkBody=Někdo chce propojit váš účet "{1}" s účtem "{0}" uživatele {2}. Pokud jste to vy, klikněte na níže uvedený odkaz a propojte účty. \n\n{3}\n\nPlatnost tohoto odkazu je {5}.\n\nPokud nechcete propojit účet, tuto zprávu ignorujte. Pokud propojíte účty, budete se moci přihlásit jako {1} pomocí {0}. +identityProviderLinkBodyHtml=

    Někdo chce propojit váš účet {1} s účtem {0} uživatele {2}. Pokud jste to vy, klikněte na níže uvedený odkaz a propojte účty.

    Odkaz na propojení účtů.

    Platnost tohoto odkazu je {5}.

    Pokud nechcete propojit účet, tuto zprávu ignorujte. Pokud propojíte účty, budete se moci přihlásit jako {1} pomocí {0}.

    +passwordResetSubject=Zapomenuté heslo +passwordResetBody=Někdo právě požádal o změnu hesla u vašeho účtu {2}. Pokud jste to vy, pro jeho změnu klikněte na odkaz níže.\n\n{0}\n\nPlatnost tohoto odkazu je {3}.\n\nPokud heslo změnit nechcete, tuto zprávu ignorujte a nic se nezmění. +passwordResetBodyHtml=

    Někdo právě požádal o změnu pověření vašeho účtu {2}. Pokud jste to vy, klikněte na odkaz níže, abyste je resetovali.

    Odkaz na obnovení pověření

    Platnost tohoto odkazu vyprší během {3}.

    Pokud nechcete obnovit vaše pověření, ignorujte tuto zprávu a nic se nezmění.

    +executeActionsSubject=Aktualizujte svůj účet +executeActionsBody=Váš administrátor vás požádal o provedení následujících akcí u účtu {2}: {3}. Začněte kliknutím na níže uvedený odkaz.\n\n{0}\n\nPlatnost tohoto odkazu je {4}.\n\nPokud si nejste jisti, zda je tento požadavek v pořádku, ignorujte tuto zprávu. +executeActionsBodyHtml=

    Váš administrátor vás požádal o provedení následujících akcí u účtu {2}: {3}. Začněte kliknutím na níže uvedený odkaz.

    Odkaz na aktualizaci účtu.

    Platnost tohoto odkazu je {4}.

    Pokud si nejste jisti, zda je tento požadavek v pořádku, ignorujte tuto zprávu.

    +eventLoginErrorSubject=Chyba přihlášení +eventLoginErrorBody=Někdo se neúspěšně pokusil přihlásit k účtu {0} z {1}. Pokud jste to nebyli vy, kontaktujte administrátora. +eventLoginErrorBodyHtml=

    Někdo se neúspěšně pokusil přihlásit k účtu {0} z {1}. Pokud jste to nebyli vy, kontaktujte administrátora.

    +eventRemoveTotpSubject=Odebrat TOTP +eventRemoveTotpBody=V účtu {0} bylo odebráno nastavení OTP z {1}. Pokud jste to nebyli vy, kontaktujte administrátora. +eventRemoveTotpBodyHtml=

    V účtu {0} bylo odebráno nastavení OTP z {1}. Pokud jste to nebyli vy, kontaktujte administrátora.

    +eventUpdatePasswordSubject=Aktualizace hesla +eventUpdatePasswordBody=V účtu {0} bylo změněno heslo z {1}. Pokud jste to nebyli vy, kontaktujte administrátora. +eventUpdatePasswordBodyHtml=

    V účtu {0} bylo změněno heslo z {1}. Pokud jste to nebyli vy, kontaktujte administrátora.

    +eventUpdateTotpSubject=Aktualizace OTP +eventUpdateTotpBody=V účtu {0} bylo změněno nastavení OTP z {1}. Pokud jste to nebyli vy, kontaktujte administrátora. +eventUpdateTotpBodyHtml=

    V účtu {0} bylo změněno nastavení OTP z {1}. Pokud jste to nebyli vy, kontaktujte administrátora.

    + +requiredAction.CONFIGURE_TOTP=Konfigurace OTP +requiredAction.terms_and_conditions=Smluvní podmínky +requiredAction.UPDATE_PASSWORD=Aktualizace hesla +requiredAction.UPDATE_PROFILE=Aktualizace profilu +requiredAction.VERIFY_EMAIL=Ověření e-mailu + +# units for link expiration timeout formatting +linkExpirationFormatter.timePeriodUnit.seconds=sekund +linkExpirationFormatter.timePeriodUnit.seconds.1=sekunda +linkExpirationFormatter.timePeriodUnit.seconds.2=sekundy +linkExpirationFormatter.timePeriodUnit.seconds.3=sekundy +linkExpirationFormatter.timePeriodUnit.seconds.4=sekundy +linkExpirationFormatter.timePeriodUnit.minutes=minut +linkExpirationFormatter.timePeriodUnit.minutes.1=minuta +linkExpirationFormatter.timePeriodUnit.minutes.2=minuty +linkExpirationFormatter.timePeriodUnit.minutes.3=minuty +linkExpirationFormatter.timePeriodUnit.minutes.4=minuty +linkExpirationFormatter.timePeriodUnit.hours=hodin +linkExpirationFormatter.timePeriodUnit.hours.1=hodina +linkExpirationFormatter.timePeriodUnit.hours.2=hodiny +linkExpirationFormatter.timePeriodUnit.hours.3=hodiny +linkExpirationFormatter.timePeriodUnit.hours.4=hodiny +linkExpirationFormatter.timePeriodUnit.days=dní +linkExpirationFormatter.timePeriodUnit.days.1=den +linkExpirationFormatter.timePeriodUnit.days.2=dny +linkExpirationFormatter.timePeriodUnit.days.3=dny +linkExpirationFormatter.timePeriodUnit.days.4=dny + +emailVerificationBodyCode=Ověřte prosím svou e-mailovou adresu zadáním následujícího kódu.\n\n{0}\n\n. +emailVerificationBodyCodeHtml=

    Ověřte prosím svou e-mailovou adresu zadáním následujícího kódu.

    {0}

    + diff --git a/keycloak-themes/base/email/messages/messages_da.properties b/keycloak-themes/base/email/messages/messages_da.properties new file mode 100644 index 0000000..5f013f2 --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_da.properties @@ -0,0 +1,47 @@ +# encoding: UTF-8 +emailVerificationSubject=Verificer email +emailVerificationBody=Nogen har oprettet en {2} konto med denne email adresse. Hvis dette var dig, bedes du trykke på forbindet herunder for at verificere din email adresse \n\n{0}\n\nDette link vil udløbe inden for {3}.\n\nHvis det var dig der har oprettet denne konto, bedes du se bort fra denne mail. +emailVerificationBodyHtml=

    Nogen har oprettet en {2} konto med denne email adresse. Hvis dette var dig, bedes du trykke på forbindet herunder for at verificere din email adresse

    Link til email verificering

    Dette link vil udløbe inden for {3}.

    Hvis det var dig der har oprettet denne konto, bedes du se bort fra denne mail.

    +emailTestSubject=[KEYCLOAK] - SMTP test besked +emailTestBody=Dette er en test besked +emailTestBodyHtml=

    Dette er en test besked

    +identityProviderLinkSubject=Link {0} +identityProviderLinkBody=Nogen vil forbinde din "{1}" konto med "{0}" kontoen som er tilknyttet brugeren {2}. Hvis dette var dig, bedes du klikke på forbindet herunder for at forbinde de to konti\n\n{3}\n\nDette link vil udløbe efter {5}.\n\nHvis du ikke vil forbinde disse konti, kan du bare ignore denne besked. Hvis du vælger at forbinde de to konti, kan du logge ind som {1} via {0}. +identityProviderLinkBodyHtml=

    Someone wants to link your {1} account with {0} account of user {2} . Hvis dette var dig, bedes du klikke på forbindet herunder for at forbinde de to konti

    Bekræft

    Dette link vil udløbe efter {5}.

    nHvis du ikke vil forbinde disse konti, kan du bare ignore denne besked. Hvis du vælger at forbinde de to konti, kan du logge ind som {1} via {0}. +passwordResetSubject=Gendan adgangskode +passwordResetBody=Nogen har forsøgt at nulstille adgangskoden til {2}. Hvis dette var dig, bedes du klikke på linket herunder for at nulstille adgangskoden.\n\n{0}\n\nDette link og kode vil udløbe efter {3}.\n\nHvis du ikke ønsker at nulstille din adgangskode, kan du se bort fra denne besked. +passwordResetBodyHtml=

    Nogen har forsøgt at nulstille adgangskoden til {2}. Hvis dette var dig, bedes du klikke på linket herunder for at nulstille adgangskoden.

    Nulstil adgangskode

    Dette link og kode vil udløbe efter {3}.

    Hvis du ikke ønsker at nulstille din adgangskode, kan du se bort fra denne besked.

    +executeActionsSubject=Opdater din konto +executeActionsBody=Din administrator beder dig opdatere din {2} konto ved at udføre følgende handling(er): {3}. Klik på linket herunder for at starte processen.\n\n{0}\n\nDette link udløber efter {4}.\n\nHvis du ikke mener at din administrator har efterspurgt dette, kan du blot se bort fra denne besked. +executeActionsBodyHtml=

    Din administrator beder dig opdatere din {2} konto ved at udføre følgende handling(er): {3}. Klik på linket herunder for at starte processen.

    Opdater konto

    Dette link udløber efter {4}.

    Hvis du ikke mener at din administrator har efterspurgt dette, kan du blot se bort fra denne besked.

    +eventLoginErrorSubject=Logind fejl +eventLoginErrorBody=Et fejlet logind forsøg er blevet registreret på din konto d. {0} fra {1}. Hvis dette ikke var dig, bedes du kontakte din administrator omgående. +eventLoginErrorBodyHtml=

    Et fejlet logind forsøg er blevet registreret på din konto d. {0} fra {1}. Hvis dette ikke var dig, bedes du kontakte din administrator omgående.

    +eventRemoveTotpSubject=Fjern OTP +eventRemoveTotpBody=OTP er blevet fjernet fra din konto d. {0} fra {1}. Hvis dette ikke var dig, bedes du kontakte din administrator omgående. +eventRemoveTotpBodyHtml=

    OTP er blevet fjernet fra din konto d. {0} fra {1}. Hvis dette ikke var dig, bedes du kontakte din administrator omgående.

    +eventUpdatePasswordSubject=Opdater adgangskode +eventUpdatePasswordBody=Din adgangskode er blevet opdateret d. {0} fra {1}. Hvis dette ikke var dig, bedes du kontakte din administrator omgående. +eventUpdatePasswordBodyHtml=

    Din adgangskode er blevet opdateret d. {0} fra {1}. Hvis dette ikke var dig, bedes du kontakte din administrator omgående.

    +eventUpdateTotpSubject=Opdater OTP +eventUpdateTotpBody=OTP blev opdateret på din konto d. {0} fra {1}. Hvis dette ikke var dig, bedes du kontakte din administrator omgående. +eventUpdateTotpBodyHtml=

    OTP blev opdateret på din konto d. {0} fra {1}. Hvis dette ikke var dig, bedes du kontakte din administrator omgående.

    + +requiredAction.CONFIGURE_TOTP=Konfigurer OTP +requiredAction.terms_and_conditions=Vilkår og Betingelser +requiredAction.UPDATE_PASSWORD=Opdater Adgangskode +requiredAction.UPDATE_PROFILE=Opdater Profil +requiredAction.VERIFY_EMAIL=Verificer Email + +# units for link expiration timeout formatting +forbindexpirationFormatter.timePeriodUnit.seconds=sekunder +forbindexpirationFormatter.timePeriodUnit.seconds.1=sekund +forbindexpirationFormatter.timePeriodUnit.minutes=minutter +forbindexpirationFormatter.timePeriodUnit.minutes.1=minut +forbindexpirationFormatter.timePeriodUnit.hours=timer +forbindexpirationFormatter.timePeriodUnit.hours.1=time +forbindexpirationFormatter.timePeriodUnit.days=dage +forbindexpirationFormatter.timePeriodUnit.days.1=dag + +emailVerificationBodyCode=Verificer din email adresse ved at indtaste følgende kode.\n\n{0}\n\n. +emailVerificationBodyCodeHtml=

    Verificer din email adresse ved at indtaste følgende kode.

    {0}

    diff --git a/keycloak-themes/base/email/messages/messages_de.properties b/keycloak-themes/base/email/messages/messages_de.properties new file mode 100644 index 0000000..d79a3b1 --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_de.properties @@ -0,0 +1,43 @@ +emailVerificationSubject=E-Mail verifizieren +emailVerificationBody=Jemand hat ein {2} Konto mit dieser E-Mail-Adresse erstellt. Falls Sie das waren, dann klicken Sie auf den Link, um die E-Mail-Adresse zu verifizieren.\n\n{0}\n\nDieser Link wird in {1} Minuten ablaufen.\n\nFalls Sie dieses Konto nicht erstellt haben, dann k\u00F6nnen sie diese Nachricht ignorieren. +emailVerificationBodyHtml=

    Jemand hat ein {2} Konto mit dieser E-Mail-Adresse erstellt. Falls das Sie waren, klicken Sie auf den Link, um die E-Mail-Adresse zu verifizieren.

    Link zur Best\u00E4tigung der E-Mail-Adresse

    Dieser Link wird in {1} Minuten ablaufen.

    Falls Sie dieses Konto nicht erstellt haben, dann k\u00F6nnen sie diese Nachricht ignorieren.

    +identityProviderLinkSubject=Link {0} +identityProviderLinkBody=Es wurde beantragt Ihren Account {1} mit dem Account {0} von Benutzer {2} zu verlinken. Sollten Sie dies beantragt haben, klicken Sie auf den unten stehenden Link.\n\n{3}\n\n Die G\u00FCltigkeit des Links wird in {4} Minuten verfallen.\n\nSollten Sie Ihren Account nicht verlinken wollen, ignorieren Sie diese Nachricht. Wenn Sie die Accounts verlinken wird ein Login auf {1} \u00FCber {0} erm\u00F6glicht. +identityProviderLinkBodyHtml=

    Es wurde beantragt Ihren Account {1} mit dem Account {0} von Benutzer {2} zu verlinken. Sollten Sie dies beantragt haben, klicken Sie auf den unten stehenden Link.

    Link zur Best\u00E4tigung der Kontoverkn\u00FCpfung

    Die G\u00FCltigkeit des Links wird in {4} Minuten verfallen.

    Sollten Sie Ihren Account nicht verlinken wollen, ignorieren Sie diese Nachricht. Wenn Sie die Accounts verlinken wird ein Login auf {1} \u00FCber {0} erm\u00F6glicht.

    +passwordResetSubject=Passwort zur\u00FCcksetzen +passwordResetBody=Es wurde eine \u00C4nderung der Anmeldeinformationen f\u00FCr Ihren Account {2} angefordert. Wenn Sie diese \u00C4nderung beantragt haben, klicken Sie auf den unten stehenden Link.\n\n{0}\n\nDie G\u00FCltigkeit des Links wird in {1} Minuten verfallen.\n\nSollten Sie keine \u00C4nderung vollziehen wollen k\u00F6nnen Sie diese Nachricht ignorieren und an Ihrem Account wird nichts ge\u00E4ndert. +passwordResetBodyHtml=

    Es wurde eine \u00C4nderung der Anmeldeinformationen f\u00FCr Ihren Account {2} angefordert. Wenn Sie diese \u00C4nderung beantragt haben, klicken Sie auf den unten stehenden Link.

    Link zum Zur\u00FCcksetzen von Anmeldeinformationen

    Die G\u00FCltigkeit des Links wird in {1} Minuten verfallen.

    Sollten Sie keine \u00C4nderung vollziehen wollen k\u00F6nnen Sie diese Nachricht ignorieren und an Ihrem Account wird nichts ge\u00E4ndert.

    +executeActionsSubject=Aktualisieren Sie Ihr Konto +executeActionsBody=Ihr Administrator hat Sie aufgefordert Ihren Account {2} zu aktualisieren. Klicken Sie auf den unten stehenden Link um den Prozess zu starten.\n\n{0}\n\nDie G\u00FCltigkeit des Links wird in {1} Minuten verfallen.\n\nSollten Sie sich dieser Aufforderung nicht bewusst sein, ignorieren Sie diese Nachricht und Ihr Account bleibt unver\u00E4ndert. +executeActionsBodyHtml=

    Ihr Administrator hat Sie aufgefordert Ihren Account {2} zu aktualisieren. Klicken Sie auf den unten stehenden Link um den Prozess zu starten.

    Link zum Account-Update

    Die G\u00FCltigkeit des Links wird in {1} Minuten verfallen.

    Sollten Sie sich dieser Aufforderung nicht bewusst sein, ignorieren Sie diese Nachricht und Ihr Account bleibt unver\u00E4ndert.

    +eventLoginErrorSubject=Fehlgeschlagene Anmeldung +eventLoginErrorBody=Jemand hat um {0} von {1} versucht, sich mit Ihrem Konto anzumelden. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin. +eventLoginErrorBodyHtml=

    Jemand hat um {0} von {1} versucht, sich mit Ihrem Konto anzumelden. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.

    +eventRemoveTotpSubject=OTP Entfernt +eventRemoveTotpBody=OTP wurde von Ihrem Konto am {0} von {1} entfernt. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin. +eventRemoveTotpBodyHtml=

    OTP wurde von Ihrem Konto am {0} von {1} entfernt. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.

    +eventUpdatePasswordSubject=Passwort Aktualisiert +eventUpdatePasswordBody=Ihr Passwort wurde am {0} von {1} ge\u00E4ndert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin. +eventUpdatePasswordBodyHtml=

    Ihr Passwort wurde am {0} von {1} ge\u00E4ndert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.

    +eventUpdateTotpSubject=OTP Aktualisiert +eventUpdateTotpBody=OTP wurde am {0} von {1} ge\u00E4ndert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin. +eventUpdateTotpBodyHtml=

    OTP wurde am {0} von {1} ge\u00E4ndert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.

    + +requiredAction.CONFIGURE_TOTP=Mehrfachauthentifizierung konfigurieren +requiredAction.terms_and_conditions=Bedingungen und Konditionen +requiredAction.UPDATE_PASSWORD=Passwort aktualisieren +requiredAction.UPDATE_PROFILE=Profil aktualisieren +requiredAction.VERIFY_EMAIL=E-Mail-Adresse verifizieren + +# units for link expiration timeout formatting +linkExpirationFormatter.timePeriodUnit.seconds=Sekunden +linkExpirationFormatter.timePeriodUnit.seconds.1=Sekunde +linkExpirationFormatter.timePeriodUnit.minutes=Minuten +linkExpirationFormatter.timePeriodUnit.minutes.1=Minute +linkExpirationFormatter.timePeriodUnit.hours=Stunden +linkExpirationFormatter.timePeriodUnit.hours.1=Stunde +linkExpirationFormatter.timePeriodUnit.days=Tage +linkExpirationFormatter.timePeriodUnit.days.1=Tag + +emailVerificationBodyCode=Bitte verifizieren Sie Ihre E-Mail-Adresse, indem Sie den folgenden Code eingeben.\n\n{0}\n\n. +emailVerificationBodyCodeHtml=

    Bitte verifizieren Sie Ihre E-Mail-Adresse, indem Sie den folgenden Code eingeben.

    {0}

    diff --git a/keycloak-themes/base/email/messages/messages_en.properties b/keycloak-themes/base/email/messages/messages_en.properties new file mode 100644 index 0000000..132fe25 --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_en.properties @@ -0,0 +1,52 @@ +emailVerificationSubject=Verify email +emailVerificationBody=Someone has created a {2} account with this email address. If this was you, click the link below to verify your email address\n\n{0}\n\nThis link will expire within {3}.\n\nIf you didn''t create this account, just ignore this message. +emailVerificationBodyHtml=

    Someone has created a {2} account with this email address. If this was you, click the link below to verify your email address

    Link to e-mail address verification

    This link will expire within {3}.

    If you didn''t create this account, just ignore this message.

    +emailTestSubject=[KEYCLOAK] - SMTP test message +emailTestBody=This is a test message +emailTestBodyHtml=

    This is a test message

    +identityProviderLinkSubject=Link {0} +identityProviderLinkBody=Someone wants to link your "{1}" account with "{0}" account of user {2} . If this was you, click the link below to link accounts\n\n{3}\n\nThis link will expire within {5}.\n\nIf you don''t want to link account, just ignore this message. If you link accounts, you will be able to login to {1} through {0}. +identityProviderLinkBodyHtml=

    Someone wants to link your {1} account with {0} account of user {2}. If this was you, click the link below to link accounts

    Link to confirm account linking

    This link will expire within {5}.

    If you don''t want to link account, just ignore this message. If you link accounts, you will be able to login to {1} through {0}.

    +passwordResetSubject=Reset password +passwordResetBody=Someone just requested to change your {2} account''s credentials. If this was you, click on the link below to reset them.\n\n{0}\n\nThis link and code will expire within {3}.\n\nIf you don''t want to reset your credentials, just ignore this message and nothing will be changed. +passwordResetBodyHtml=

    Someone just requested to change your {2} account''s credentials. If this was you, click on the link below to reset them.

    Link to reset credentials

    This link will expire within {3}.

    If you don''t want to reset your credentials, just ignore this message and nothing will be changed.

    +executeActionsSubject=Update Your Account +executeActionsBody=Your administrator has just requested that you update your {2} account by performing the following action(s): {3}. Click on the link below to start this process.\n\n{0}\n\nThis link will expire within {4}.\n\nIf you are unaware that your administrator has requested this, just ignore this message and nothing will be changed. +executeActionsBodyHtml=

    Your administrator has just requested that you update your {2} account by performing the following action(s): {3}. Click on the link below to start this process.

    Link to account update

    This link will expire within {4}.

    If you are unaware that your administrator has requested this, just ignore this message and nothing will be changed.

    +eventLoginErrorSubject=Login error +eventLoginErrorBody=A failed login attempt was detected to your account on {0} from {1}. If this was not you, please contact an administrator. +eventLoginErrorBodyHtml=

    A failed login attempt was detected to your account on {0} from {1}. If this was not you, please contact an administrator.

    +eventRemoveTotpSubject=Remove OTP +eventRemoveTotpBody=OTP was removed from your account on {0} from {1}. If this was not you, please contact an administrator. +eventRemoveTotpBodyHtml=

    OTP was removed from your account on {0} from {1}. If this was not you, please contact an administrator.

    +eventUpdatePasswordSubject=Update password +eventUpdatePasswordBody=Your password was changed on {0} from {1}. If this was not you, please contact an administrator. +eventUpdatePasswordBodyHtml=

    Your password was changed on {0} from {1}. If this was not you, please contact an administrator.

    +eventUpdateTotpSubject=Update OTP +eventUpdateTotpBody=OTP was updated for your account on {0} from {1}. If this was not you, please contact an administrator. +eventUpdateTotpBodyHtml=

    OTP was updated for your account on {0} from {1}. If this was not you, please contact an administrator.

    + +requiredAction.CONFIGURE_TOTP=Configure OTP +requiredAction.terms_and_conditions=Terms and Conditions +requiredAction.UPDATE_PASSWORD=Update Password +requiredAction.UPDATE_PROFILE=Update Profile +requiredAction.VERIFY_EMAIL=Verify Email +requiredAction.CONFIGURE_RECOVERY_AUTHN_CODES=Generate Recovery Codes + +# units for link expiration timeout formatting +linkExpirationFormatter.timePeriodUnit.seconds=seconds +linkExpirationFormatter.timePeriodUnit.seconds.1=second +linkExpirationFormatter.timePeriodUnit.minutes=minutes +linkExpirationFormatter.timePeriodUnit.minutes.1=minute +#for language which have more unit plural forms depending on the value (eg. Czech and other Slavic langs) you can override unit text for some other values like this: +#linkExpirationFormatter.timePeriodUnit.minutes.2=minuty +#linkExpirationFormatter.timePeriodUnit.minutes.3=minuty +#linkExpirationFormatter.timePeriodUnit.minutes.4=minuty +linkExpirationFormatter.timePeriodUnit.hours=hours +linkExpirationFormatter.timePeriodUnit.hours.1=hour +linkExpirationFormatter.timePeriodUnit.days=days +linkExpirationFormatter.timePeriodUnit.days.1=day + +emailVerificationBodyCode=Please verify your email address by entering in the following code.\n\n{0}\n\n. +emailVerificationBodyCodeHtml=

    Please verify your email address by entering in the following code.

    {0}

    + diff --git a/keycloak-themes/base/email/messages/messages_es.properties b/keycloak-themes/base/email/messages/messages_es.properties new file mode 100644 index 0000000..024bc3d --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_es.properties @@ -0,0 +1,21 @@ +emailVerificationSubject=Verificaci\u00F3n de email +emailVerificationBody=Alguien ha creado una cuenta de {2} con esta direcci\u00F3n de email. Si has sido t\u00FA, haz click en el enlace siguiente para verificar tu direcci\u00F3n de email.\n\n{0}\n\nEste enlace expirar\u00E1 en {1} minutos.\n\nSi t\u00FA no has creado esta cuenta, simplemente ignora este mensaje. +emailVerificationBodyHtml=

    Alguien ha creado una cuenta de {2} con esta direcci\u00F3n de email. Si has sido t\u00FA, haz click en el enlace siguiente para verificar tu direcci\u00F3n de email.

    Enlace de verficaci\u00F3n de direcci\u00F3n de email

    Este enlace expirar\u00E1 en {1} minutos.

    Si t\u00FA no has creado esta cuenta, simplemente ignora este mensaje.

    +passwordResetSubject=Reiniciar contrase\u00F1a +passwordResetBody=Alguien ha solicitado cambiar las credenciales de tu cuenta de {2}. Si has sido t\u00FA, haz clic en el enlace siguiente para reiniciarlas.\n\n{0}\n\nEste enlace expirar\u00E1 en {1} minutos.\n\nSi no quieres reiniciar tus credenciales, simplemente ignora este mensaje y no se realizar\u00E1 ning\u00FAn cambio. +passwordResetBodyHtml=

    Alguien ha solicitado cambiar las credenciales de tu cuenta de {2}. Si has sido t\u00FA, haz clic en el enlace siguiente para reiniciarlas.

    {0}

    Este enlace expirar\u00E1 en {1} minutos.

    Si no quieres reiniciar tus credenciales, simplemente ignora este mensaje y no se realizar\u00E1 ning\u00FAn cambio.

    +executeActionsSubject=Actualiza tu cuenta +executeActionsBody=El administrador ha solicitado que actualices tu cuenta de {2}. Haz clic en el enlace inferior para iniciar este proceso.\n\n{0}\n\nEste enlace expirar\u00E1 en {1} minutos.\n\nSi no est\u00E1s al tanto de que el administrador haya solicitado esto, simplemente ignora este mensaje y no se realizar\u00E1 ning\u00FAn cambio. +executeActionsBodyHtml=

    El administrador ha solicitado que actualices tu cuenta de {2}. Haz clic en el enlace inferior para iniciar este proceso.

    {0}

    Este enlace expirar\u00E1 en {1} minutos.

    Si no est\u00E1s al tanto de que el administrador haya solicitado esto, simplemente ignora este mensaje y no se realizar\u00E1 ning\u00FAn cambio.

    +eventLoginErrorSubject=Fallo en el inicio de sesi\u00F3n +eventLoginErrorBody=Se ha detectado un intento de acceso fallido a tu cuenta el {0} desde {1}. Si no has sido t\u00FA, por favor contacta con el administrador. +eventLoginErrorBodyHtml=

    Se ha detectado un intento de acceso fallido a tu cuenta el {0} desde {1}. Si no has sido t\u00FA, por favor contacta con el administrador.

    +eventRemoveTotpSubject=Borrado OTP +eventRemoveTotpBody=OTP fue eliminado de tu cuenta el {0} desde {1}. Si no has sido t\u00FA, por favor contacta con el administrador. +eventRemoveTotpBodyHtml=

    OTP fue eliminado de tu cuenta el {0} desde {1}. Si no has sido t\u00FA, por favor contacta con el administrador.

    +eventUpdatePasswordSubject=Actualizaci\u00F3n de contrase\u00F1a +eventUpdatePasswordBody=Tu contrase\u00F1a se ha actualizado el {0} desde {1}. Si no has sido t\u00FA, por favor contacta con el administrador. +eventUpdatePasswordBodyHtml=

    Tu contrase\u00F1a se ha actualizado el {0} desde {1}. Si no has sido t\u00FA, por favor contacta con el administrador.

    +eventUpdateTotpSubject=Actualizaci\u00F3n de OTP +eventUpdateTotpBody=OTP se ha actualizado en tu cuenta el {0} desde {1}. Si no has sido t\u00FA, por favor contacta con el administrador. +eventUpdateTotpBodyHtml=

    OTP se ha actualizado en tu cuenta el {0} desde {1}. Si no has sido t\u00FA, por favor contacta con el administrador.

    diff --git a/keycloak-themes/base/email/messages/messages_fi.properties b/keycloak-themes/base/email/messages/messages_fi.properties new file mode 100644 index 0000000..111ff6f --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_fi.properties @@ -0,0 +1,46 @@ +# encoding: UTF-8 +emailVerificationSubject=Vahvista sähköposti +emailVerificationBody=Tällä sähköpostiosoitteella on luotu {2}-tili. Jos loit tilin itse, klikkaa alla olevaa linkkiä vahvistaaksesi sähköpostiosoitteesi\n\n{0}\n\nLinkin vanhenemisaika: {3}.\n\nJos et luonut tätä tiliä, jätä viesti huomiotta. +emailVerificationBodyHtml=

    Tällä sähköpostiosoitteella on luotu {2}-tili. Jos loit tilin itse, klikkaa alla olevaa linkkiä vahvistaaksesi sähköpostiosoitteesi

    Linkki vahvistamiseen

    Linkin vanhenemisaika: {3}.

    Jos et luonut tätä tiliä, jätä viesti huomiotta.

    +emailTestSubject=[KEYCLOAK] - SMTP testiviesti +emailTestBody=Tämä on testiviesti +emailTestBodyHtml=

    Tämä on testiviesti

    +identityProviderLinkSubject=Linkki {0} +identityProviderLinkBody=Saimme pyynnön linkittää "{1}"-tilin "{0}"-tiliin käyttäjälle {2}. Jos teit tämän pyynnön, klikkaa alla olevaa linkkiä tilien linkittämiseksi\n\n{3}\n\nLinkin vanhenemisaika: {5}.\n\nJos et halua linkittää tilejä, jätä tämä viesti huomiotta. Jos linkität tilit, voit jatkossa kirjautua tilille {1}, tilin {0} kautta. +identityProviderLinkBodyHtml=

    Saimme pyynnön linkittää {1}-tilin {0}-tiliin käyttäjälle {2}. Jos teit tämän pyynnön, klikkaa alla olevaa linkkiä tilien linkittämiseksi

    Vahvista tilien linkitys

    Linkin vanhenemisaika: {5}.

    Jos et halua linkittää tilejä, jätä tämä viesti huomiotta. Jos linkität tilit, voit jatkossa kirjautua tilille {1}, tilin {0} kautta.

    +passwordResetSubject=Salasanan nollaus +passwordResetBody=Saimme pyynnön vaihtaa {2}-tilisi salasanan. Jos pyysit itse salasanan vaihtoa, pääset tästä linkistä vaihtamaan salasanasi:\n\n{0}\n\nLinkin vanhenemisaika: {3} .\n\nJos et halua vaihtaa salasanaasi tai et ole pyytänyt salasanan vaihtoa itse, jätä tämän viesti huomiotta. +passwordResetBodyHtml=

    Saimme pyynnön vaihtaa {2}-tilisi salasanan. Jos pyysit itse salasanan vaihtoa, pääset tästä linkistä vaihtamaan salasanasi:

    Linkki salasanan vaihtoon

    Linkin vanhenemisaika: {3}.

    Jos et halua vaihtaa salasanaasi tai et ole pyytänyt salasanan vaihtoa itse, jätä tämän viesti huomiotta.

    +executeActionsSubject=Päivitä tilisi +executeActionsBody=Järjestelmänvalvoja on pyytänyt sinua päivittämään {2}-tilisi tekemällä seuraavat toimenpiteet: {3}. Aloita prosessi klikkaamalla alla olevaa linkkiä.\n\n{0}\n\nLinkin vanhenemisaika: {4}.\n\nJos et ole tietoinen tästä järjestelmänvalvojan pyynnöstä, jätä tämän viesti huomiotta. +executeActionsBodyHtml=

    Järjestelmänvalvoja on pyytänyt sinua päivittämään {2}-tilisi tekemällä seuraavat toimenpiteet: {3}. Aloita prosessi klikkaamalla alla olevaa linkkiä.

    Linkki tilin päivittämiseen

    Linkin vanhenemisaika: {4}.

    Jos et ole tietoinen tästä järjestelmänvalvojan pyynnöstä, jätä tämän viesti huomiotta.

    +eventLoginErrorSubject=Kirjautuminen epäonnistui +eventLoginErrorBody=Tilillänne on havaittu epäonnistunut kirjautumisyritys {0} osoitteesta {1}. Jos et itse yrittänyt kirjautua tilillesi, ota yhteyttä järjestelmänvalvojaan. +eventLoginErrorBodyHtml=

    Tilillänne on havaittu epäonnistunut kirjautumisyritys {0} osoitteesta {1}. Jos et itse yrittänyt kirjautua tilillesi, ota yhteyttä järjestelmänvalvojaan.

    +eventRemoveTotpSubject=Poista OTP +eventRemoveTotpBody=OTP on poistettu tililtäsi {0} osoitteesta {1}. Jos et itse tehnyt tätä, ota yhteyttä järjestelmänvalvojaan. +eventRemoveTotpBodyHtml=

    OTP on poistettu tililtäsi {0} osoitteesta {1}. Jos et itse tehnyt tätä, ota yhteyttä järjestelmänvalvojaan.

    +eventUpdatePasswordSubject=Päivitä salasana +eventUpdatePasswordBody=Tilisi salasana on vaihdettu {0} osoitteesta {1}. Jos et itse tehnyt tätä, ota yhteyttä järjestelmänvalvojaan.. +eventUpdatePasswordBodyHtml=

    Tilisi salasana on vaihdettu {0} osoitteesta {1}. Jos et itse tehnyt tätä, ota yhteyttä järjestelmänvalvojaan.

    +eventUpdateTotpSubject=Päivitä OTP +eventUpdateTotpBody=OTP on päivitetty tilillesi {0} osoitteesta {1}. Jos et itse tehnyt tätä, ota yhteyttä järjestelmänvalvojaan. +eventUpdateTotpBodyHtml=

    OTP on päivitetty tilillesi {0} osoitteesta {1}. Jos et itse tehnyt tätä, ota yhteyttä järjestelmänvalvojaan.

    +requiredAction.CONFIGURE_TOTP=Konfiguroi OTP +requiredAction.terms_and_conditions=Käyttöehdot +requiredAction.UPDATE_PASSWORD=Päivitä salasana +requiredAction.UPDATE_PROFILE=Päivitä profiili +requiredAction.VERIFY_EMAIL=Vahvista sähköposti + +# units for link expiration timeout formatting +linkExpirationFormatter.timePeriodUnit.seconds=sekuntia +linkExpirationFormatter.timePeriodUnit.seconds.1=sekunti +linkExpirationFormatter.timePeriodUnit.minutes=minuuttia +linkExpirationFormatter.timePeriodUnit.minutes.1=minuutti +linkExpirationFormatter.timePeriodUnit.hours=tuntia +linkExpirationFormatter.timePeriodUnit.hours.1=tunti +linkExpirationFormatter.timePeriodUnit.days=päivää +linkExpirationFormatter.timePeriodUnit.days.1=päivä + +emailVerificationBodyCode=Ole hyvä ja vahvista sähköpostiosoitteesi alla olevalla koodilla.\n\n{0}\n\n. +emailVerificationBodyCodeHtml=

    Ole hyvä ja vahvista sähköpostiosoitteesi alla olevalla koodilla.

    {0}

    \ No newline at end of file diff --git a/keycloak-themes/base/email/messages/messages_fr.properties b/keycloak-themes/base/email/messages/messages_fr.properties new file mode 100644 index 0000000..6a21384 --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_fr.properties @@ -0,0 +1,37 @@ +emailVerificationSubject=V\u00e9rification du courriel +emailVerificationBody=Quelqu''un vient de cr\u00e9er un compte "{2}" avec votre courriel. Si vous \u00eates \u00e0 l''origine de cette requ\u00eate, veuillez cliquer sur le lien ci-dessous afin de v\u00e9rifier votre adresse de courriel\n\n{0}\n\nCe lien expire dans {3}.\n\nSinon, veuillez ignorer ce message. +emailVerificationBodyHtml=

    Quelqu''un vient de cr\u00e9er un compte "{2}" avec votre courriel. Si vous \u00eates \u00e0 l''origine de cette requ\u00eate, veuillez cliquer sur le lien ci-dessous afin de v\u00e9rifier votre adresse de courriel

    {0}

    Ce lien expire dans {3}.

    Sinon, veuillez ignorer ce message.

    +passwordResetSubject=R\u00e9initialiser le mot de passe +passwordResetBody=Quelqu''un vient de demander une r\u00e9initialisation de mot de passe pour votre compte {2}. Si vous \u00eates \u00e0 l''origine de cette requ\u00eate, veuillez cliquer sur le lien ci-dessous pour le mettre \u00e0 jour.\n\n{0}\n\nCe lien expire dans {3}.\n\nSinon, veuillez ignorer ce message ; aucun changement ne sera effectu\u00e9 sur votre compte. +passwordResetBodyHtml=

    Quelqu''un vient de demander une r\u00e9initialisation de mot de passe pour votre compte {2}. Si vous \u00eates \u00e0 l''origine de cette requ\u00eate, veuillez cliquer sur le lien ci-dessous pour le mettre \u00e0 jour.

    Lien pour r\u00e9initialiser votre mot de passe

    Ce lien expire dans {3}.

    Sinon, veuillez ignorer ce message ; aucun changement ne sera effectu\u00e9 sur votre compte.

    +executeActionsSubject=Mettre \u00e0 jour votre compte +executeActionsBody=Votre administrateur vient de demander une mise \u00e0 jour de votre compte {2} pour r\u00e9aliser les actions suivantes : {3}. Veuillez cliquer sur le lien ci-dessous afin de commencer le processus.\n\n{0}\n\nCe lien expire dans {4}.\n\nSi vous n''\u00eates pas \u00e0 l''origine de cette requ\u00eate, veuillez ignorer ce message ; aucun changement ne sera effectu\u00e9 sur votre compte. +executeActionsBodyHtml=

    Votre administrateur vient de demander une mise \u00e0 jour de votre compte {2} pour r\u00e9aliser les actions suivantes : {3}. Veuillez cliquer sur le lien ci-dessous afin de commencer le processus.

    {0}

    Ce lien expire dans {4}.

    Si vous n''\u00eates pas \u00e0 l''origine de cette requ\u00eate, veuillez ignorer ce message ; aucun changement ne sera effectu\u00e9 sur votre compte.

    +eventLoginErrorSubject=Erreur de connexion +eventLoginErrorBody=Une tentative de connexion a \u00e9t\u00e9 d\u00e9tect\u00e9e sur votre compte {0} depuis {1}. Si vous n''\u00eates pas \u00e0 l''origine de cette requ\u00eate, veuillez contacter votre administrateur. +eventLoginErrorBodyHtml=

    Une tentative de connexion a \u00e9t\u00e9 d\u00e9tect\u00e9e sur votre compte {0} depuis {1}. Si vous n''\u00eates pas \u00e0 l''origine de cette requ\u00eate, veuillez contacter votre administrateur.

    +eventRemoveTotpSubject=Suppression du OTP +eventRemoveTotpBody=Le OTP a \u00e9t\u00e9 supprim\u00e9 de votre compte {0} depuis {1}. Si vous n''\u00e9tiez pas \u00e0 l''origine de cette requ\u00eate, veuillez contacter votre administrateur. +eventRemoveTotpBodyHtml=

    Le OTP a \u00e9t\u00e9 supprim\u00e9 de votre compte {0} depuis {1}. Si vous n''\u00e9tiez pas \u00e0 l''origine de cette requ\u00eate, veuillez contacter votre administrateur.

    +eventUpdatePasswordSubject=Mise \u00e0 jour du mot de passe +eventUpdatePasswordBody=Votre mot de passe pour votre compte {0} a \u00e9t\u00e9 modifi\u00e9 depuis {1}. Si vous n''\u00e9tiez pas \u00e0 l''origine de cette requ\u00eate, veuillez contacter votre administrateur. +eventUpdatePasswordBodyHtml=

    Votre mot de passe pour votre compte {0} a \u00e9t\u00e9 modifi\u00e9 depuis {1}. Si vous n''\u00e9tiez pas \u00e0 l''origine de cette requ\u00eate, veuillez contacter votre administrateur.

    +eventUpdateTotpSubject=Mise \u00e0 jour du OTP +eventUpdateTotpBody=Le OTP a \u00e9t\u00e9 mis \u00e0 jour pour votre compte {0} depuis {1}. Si vous n''\u00e9tiez pas \u00e0 l''origine de cette requ\u00eate, veuillez contacter votre administrateur. +eventUpdateTotpBodyHtml=

    Le OTP a \u00e9t\u00e9 mis \u00e0 jour pour votre compte {0} depuis {1}. Si vous n''\u00e9tiez pas \u00e0 l''origine de cette requ\u00eate, veuillez contacter votre administrateur.

    + +requiredAction.CONFIGURE_TOTP=Configurer un OTP +requiredAction.terms_and_conditions=Conditions g\u00e9n\u00e9rale d''utilisation +requiredAction.UPDATE_PASSWORD=Mise \u00e0 jour du mot de passe +requiredAction.UPDATE_PROFILE=Mise \u00e0 jour du profile +requiredAction.VERIFY_EMAIL=V\u00e9rification de l''adresse courriel + +# units for link expiration timeout formatting +linkExpirationFormatter.timePeriodUnit.seconds=secondes +linkExpirationFormatter.timePeriodUnit.seconds.1=seconde +linkExpirationFormatter.timePeriodUnit.minutes=minutes +linkExpirationFormatter.timePeriodUnit.minutes.1=minute +linkExpirationFormatter.timePeriodUnit.hours=heures +linkExpirationFormatter.timePeriodUnit.hours.1=heure +linkExpirationFormatter.timePeriodUnit.days=jours +linkExpirationFormatter.timePeriodUnit.days.1=jour diff --git a/keycloak-themes/base/email/messages/messages_hu.properties b/keycloak-themes/base/email/messages/messages_hu.properties new file mode 100644 index 0000000..65f5ac0 --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_hu.properties @@ -0,0 +1,47 @@ +# encoding: utf-8 +emailVerificationSubject=Email cím megerősítése +emailVerificationBody=Ezzel az email címmel valaki létrehozott egy {2} tartomány felhasználói fiókot. Amennyiben a fiókot Ön hozta létre, kérem kattintson a lenti hivatkozásra, hogy megerősítse fiókját és ezt az email címet.\n\n{0}\n\nA hivatkozás érvényét veszti {3} múlva.\n\nHa nem ön hozta létre a felhasználói fiókot, akkor kérem hagyja figyelmen kívül ezt az üzenetet. +emailVerificationBodyHtml=

    Ezzel az email címmel valaki létrehozott egy {2} tartomány felhasználói fiókot. Amennyiben a fiókot Ön hozta létre, kérem kattintson a lenti hivatkozásra, hogy megerősítse fiókját és ezt az email címet.

    Hivatkozás a fiók és az email cím megerősítéséhez

    A hivatkozás érvényét veszti {3} múlva.

    Ha nem ön hozta létre a felhasználói fiókot, akkor kérem hagyja figyelmen kívül ezt az üzenetet.

    +emailTestSubject=[KEYCLOAK] - SMTP teszt üzenet +emailTestBody=Ez egy KEYCLOAK teszt üzenet. +emailTestBodyHtml=

    Ez egy KEYCLOAK teszt üzenet.

    +identityProviderLinkSubject={0} összekötés +identityProviderLinkBody=Valaki össze kívánja kötni az Ön "{1}" tartományi fiókját a(z) "{0}" személyazonosság-kezelő {2} felhasználói fiókjával. Amennyiben az összekötést Ön kezdeményezte kérem kattintson a lenti hivatkozásra, hogy összekösse fiókjait.\n\n{3}\n\nA hivatkozás érvényét veszti {5} múlva.\n\nHa nem ön kezdeményezte a felhasználói fiókok összekötését, akkor kérem hagyja figyelmen kívül ezt az üzenetet.\n\nHa összeköti a fiókjait, akkor beléphet a(z) {1} tartományba a(z) {0} szolgáltatón keresztül. +identityProviderLinkBodyHtml=

    Valaki össze kívánja kötni az Ön {1} tartomány fiókját a(z) {0} személyazonosság-kezelő {2} felhasználói fiókjával. Amennyiben az összekötést Ön kezdeményezte kérem kattintson a lenti hivatkozásra, hogy összekösse fiókjait.

    Hivatkozás a fiók összekötés megerősítéshez

    A hivatkozás érvényét veszti {5} múlva.

    Ha nem ön kezdeményezte a felhasználói fiókok összekötését, akkor kérem hagyja figyelmen kívül ezt az üzenetet.

    Ha összeköti a fiókjait, akkor beléphet a(z) {1} tartományba a(z) {0} szolgáltatón keresztül.

    +passwordResetSubject=Jelszó visszaállítás +passwordResetBody=Valaki vissza kívánja állítani az Ön "{2}" tartományi fiókjának jelszavát. Amennyiben a jelszó visszaállítást Ön kezdeményezte, kérem kattintson a lenti hivatkozásra a jelszava megváltoztatásához.\n\n{0}\n\nA hivatkozás érvényét veszti {3} múlva.\n\nHa nem ön kérte a jelszó visszaállítást, akkor kérem hagyja figyelmen kívül ezt az üzenetet, a jelszava nem fog megváltozni. +passwordResetBodyHtml=

    Valaki vissza kívánja állítani az Ön "{2}" tartományi fiókjának jelszavát. Amennyiben a jelszó visszaállítást Ön kezdeményezte, kérem kattintson a lenti hivatkozásra a jelszava megváltoztatásához.

    Hivatkozás a jelszó visszaállításhoz

    A hivatkozás érvényét veszti {3} múlva.

    Ha nem ön kérte a jelszó visszaállítást, akkor kérem hagyja figyelmen kívül ezt az üzenetet, a jelszava nem fog megváltozni.

    +executeActionsSubject=Felhasználói fiók adatok módosítása +executeActionsBody=Az alkalmazás adminisztrátora kezdeményezte az Ön "{2}" tartományi felhasználói fiók adatainak módosítását a következő műveletekkel: {3}. Kérem kattintson a lenti hivatkozásra, hogy megkezdhesse a kért módosításokat.\n\n{0}\n\nA hivatkozás érvényét veszti {4} múlva.\n\nHa nincs tudomása arról, hogy az adminisztrátora módosításokat kért Öntől, akkor kérem hagyja figyelmen kívül ezt az üzenetet, az adatai nem fognak megváltozni. +executeActionsBodyHtml=

    Az alkalmazás adminisztrátora kezdeményezte az Ön "{2}" tartományi felhasználói fiók adatainak módosítását a következő műveletekkel: {3}. Kérem kattintson a lenti hivatkozásra, hogy megkezdhesse a kért módosításokat.

    Hivatkozás a felhasználói fiók adatok módosításához

    A hivatkozás érvényét veszti {4} múlva.

    Ha nincs tudomása arról, hogy az adminisztrátora módosításokat kért Öntől, akkor kérem hagyja figyelmen kívül ezt az üzenetet, az adatai nem fognak megváltozni.

    +eventLoginErrorSubject=Belépési hiba +eventLoginErrorBody=Sikertelen belépési kísérlet történt {0} időpontban a(z) {1} címről. Kérem lépjen kapcsolatba az alkalmazás adminisztrátorral amennyiben nem ön próbált meg belépni. +eventLoginErrorBodyHtml=

    Sikertelen belépési kísérlet történt {0} időpontban a(z) {1} címről. Kérem lépjen kapcsolatba az alkalmazás adminisztrátorral amennyiben nem ön próbált meg belépni.

    +eventRemoveTotpSubject=Egyszer használatos jelszó (OTP) eltávolítása +eventRemoveTotpBody=Az egyszer használatos jelszó (OTP) funkciót {0} időpontban a(z) {1} címről érkező kérés értelmében eltávolítottuk a fiókjáról. Kérem haladéktalanul lépjen kapcsolatba az alkalmazás adminisztrátorral amennyiben nem ön igényelte az OTP eltávolítását. +eventRemoveTotpBodyHtml=

    Az egyszer használatos jelszó (OTP) funkciót {0} időpontban a(z) {1} címről érkező kérés értelmében eltávolítottuk a fiókjáról. Kérem haladéktalanul lépjen kapcsolatba az alkalmazás adminisztrátorral amennyiben nem ön igényelte az OTP eltávolítását.

    +eventUpdatePasswordSubject=Jelszó csere +eventUpdatePasswordBody=Jelszavát {0} időpontban a(z) {1} címről érkező kérés értelmében lecseréltük. Kérem haladéktalanul lépjen kapcsolatba az alkalmazás adminisztrátorral amennyiben nem ön igényelte a jelszó cserét. +eventUpdatePasswordBodyHtml=

    Jelszavát {0} időpontban a(z) {1} címről érkező kérés értelmében lecseréltük. Kérem haladéktalanul lépjen kapcsolatba az alkalmazás adminisztrátorral amennyiben nem ön igényelte a jelszó cserét.

    +eventUpdateTotpSubject=Egyszer használatos jelszó (OTP) csere +eventUpdateTotpBody=Az egyszer használatos jelszó (OTP) beállításait {0} időpontban a(z) {1} címről érkező kérés értelmében módosítottuk a fiókján. Kérem haladéktalanul lépjen kapcsolatba az alkalmazás adminisztrátorral amennyiben nem ön igényelte az OTP beállítások módosítását. +eventUpdateTotpBodyHtml=

    Az egyszer használatos jelszó (OTP) beállításait {0} időpontban a(z) {1} címről érkező kérés értelmében módosítottuk a fiókján. Kérem haladéktalanul lépjen kapcsolatba az alkalmazás adminisztrátorral amennyiben nem ön igényelte az OTP beállítások módosítását.

    + +requiredAction.CONFIGURE_TOTP=Egyszer használatos jelszó (OTP) beállítása +requiredAction.terms_and_conditions=Felhasználási feltételek +requiredAction.UPDATE_PASSWORD=Jelszó csere +requiredAction.UPDATE_PROFILE=Fiók adatok módosítása +requiredAction.VERIFY_EMAIL=Email cím megerősítése + +# units for link expiration timeout formatting +linkExpirationFormatter.timePeriodUnit.seconds=másodperc +linkExpirationFormatter.timePeriodUnit.seconds.1=másodperc +linkExpirationFormatter.timePeriodUnit.minutes=perc +linkExpirationFormatter.timePeriodUnit.minutes.1=perc +linkExpirationFormatter.timePeriodUnit.hours=óra +linkExpirationFormatter.timePeriodUnit.hours.1=óra +linkExpirationFormatter.timePeriodUnit.days=nap +linkExpirationFormatter.timePeriodUnit.days.1=nap + +emailVerificationBodyCode=Kérem erősítse meg az email címét a következő kód megadásával.\n\n{0}\n\n. +emailVerificationBodyCodeHtml=

    Kérem erősítse meg az email címét a következő kód megadásával.

    {0}

    diff --git a/keycloak-themes/base/email/messages/messages_it.properties b/keycloak-themes/base/email/messages/messages_it.properties new file mode 100644 index 0000000..a866bf2 --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_it.properties @@ -0,0 +1,50 @@ +emailVerificationSubject=Verifica l''email +emailVerificationBody=Qualcuno ha creato un account {2} con questo indirizzo email. Se sei stato tu, fai clic sul link seguente per verificare il tuo indirizzo email\n\n{0}\n\nQuesto link scadr\u00e0 in {3}.\n\nSe non sei stato tu a creare questo account, ignora questo messaggio. +emailVerificationBodyHtml=

    Qualcuno ha creato un account {2} con questo indirizzo email. Se sei stato tu, fai clic sul link seguente per verificare il tuo indirizzo email

    {0}

    Questo link scadr\u00e0 in {3}.

    Se non sei stato tu a creare questo account, ignora questo messaggio.

    +emailTestSubject=[KEYCLOAK] - messaggio di test SMTP +emailTestBody=Questo \u00e8 un messaggio di test +emailTestBodyHtml=

    Questo \u00e8 un messaggio di test

    +identityProviderLinkSubject=Link {0} +identityProviderLinkBody=Qualcuno vuole associare il tuo account "{1}" con l''account "{0}" dell''utente {2}. Se sei stato tu, fai clic sul link seguente per associare gli account\n\n{3}\n\nQuesto link scadr\u00e0 in {5}.\n\nSe non vuoi associare l''account, ignora questo messaggio. Se associ gli account, potrai accedere a {1} attraverso {0}. +identityProviderLinkBodyHtml=

    Qualcuno vuole associare il tuo account {1} con l''account {0} dell''utente {2}. Se sei stato tu, fai clic sul link seguente per associare gli account

    {3}

    Questo link scadr\u00e0 in {5}.

    Se non vuoi associare l''account, ignora questo messaggio. Se associ gli account, potrai accedere a {1} attraverso {0}.

    +passwordResetSubject=Reimposta la password +passwordResetBody=Qualcuno ha appena richiesto di cambiare le credenziali di accesso al tuo account {2}. Se sei stato tu, fai clic sul link seguente per reimpostarle.\n\n{0}\n\nQuesto link e codice scadranno in {3}.\n\nSe non vuoi reimpostare le tue credenziali di accesso, ignora questo messaggio e non verr\u00e0 effettuato nessun cambio. +passwordResetBodyHtml=

    Qualcuno ha appena richiesto di cambiare le credenziali di accesso al tuo account {2}. Se sei stato tu, fai clic sul link seguente per reimpostarle.

    {0}

    Questo link scadr\u00e0 in {3}.

    Se non vuoi reimpostare le tue credenziali di accesso, ignora questo messaggio e non verr\u00e0 effettuato nessun cambio.

    +executeActionsSubject=Aggiorna il tuo account +executeActionsBody=Il tuo amministratore ha appena richiesto un aggiornamento del tuo account {2} ed \u00e8 necessario che tu esegua la/le seguente/i azione/i: {3}. Fai clic sul link seguente per iniziare questo processo.\n\n{0}\n\nQuesto link scadr\u00e0 in {4}.\n\nSe non sei a conoscenza della richiesta del tuo amministratore, ignora questo messaggio e non verr\u00e0 effettuato nessun cambio. +executeActionsBodyHtml=

    Il tuo amministratore ha appena richiesto un aggiornamento del tuo account {2} ed \u00e8 necessario che tu esegua la/le seguente/i azione/i: {3}. Fai clic sul link seguente per iniziare questo processo.

    Link to account update

    Questo link scadr\u00e0 in {4}.

    Se non sei a conoscenza della richiesta del tuo amministratore, ignora questo messaggio e non verr\u00e0 effettuato nessun cambio.

    +eventLoginErrorSubject=Errore di accesso +eventLoginErrorBody=\u00c8 stato rilevato un tentativo fallito di accesso al tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore. +eventLoginErrorBodyHtml=

    \u00c8 stato rilevato un tentativo fallito di accesso al tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore.

    +eventRemoveTotpSubject=Rimozione OTP (password temporanea valida una volta sola) +eventRemoveTotpBody=La OTP (password temporanea valida una volta sola) \u00e8 stata rimossa dal tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore. +eventRemoveTotpBodyHtml=

    La OTP (password temporanea valida una volta sola) \u00e8 stata rimossa dal tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore.

    +eventUpdatePasswordSubject=Aggiornamento password +eventUpdatePasswordBody=La tua password \u00e8 stata cambiata il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore. +eventUpdatePasswordBodyHtml=

    La tua password \u00e8 stata cambiata il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore.

    +eventUpdateTotpSubject=Aggiornamento OTP (password temporanea valida una volta sola) +eventUpdateTotpBody=La OTP (password temporanea valida una volta sola) \u00e8 stata aggiornata per il tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore. +eventUpdateTotpBodyHtml=

    La OTP (password temporanea valida una volta sola) \u00e8 stata aggiornata per il tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore.

    + +requiredAction.CONFIGURE_TOTP=Configurazione OTP +requiredAction.terms_and_conditions=Termini e condizioni +requiredAction.UPDATE_PASSWORD=Aggiornamento password +requiredAction.UPDATE_PROFILE=Aggiornamento profilo +requiredAction.VERIFY_EMAIL=Verifica dell''indirizzo email + +# units for link expiration timeout formatting +linkExpirationFormatter.timePeriodUnit.seconds=secondi +linkExpirationFormatter.timePeriodUnit.seconds.1=secondo +linkExpirationFormatter.timePeriodUnit.minutes=minuti +linkExpirationFormatter.timePeriodUnit.minutes.1=minuto +#for language which have more unit plural forms depending on the value (eg. Czech and other Slavic langs) you can override unit text for some other values like this: +#linkExpirationFormatter.timePeriodUnit.minutes.2=minuty +#linkExpirationFormatter.timePeriodUnit.minutes.3=minuty +#linkExpirationFormatter.timePeriodUnit.minutes.4=minuty +linkExpirationFormatter.timePeriodUnit.hours=ore +linkExpirationFormatter.timePeriodUnit.hours.1=ora +linkExpirationFormatter.timePeriodUnit.days=giorni +linkExpirationFormatter.timePeriodUnit.days.1=giorno + +emailVerificationBodyCode=Per favore verifica il tuo indirizzo email inserendo il codice seguente.\n\n{0}\n\n. +emailVerificationBodyCodeHtml=

    Per favore verifica il tuo indirizzo email inserendo il codice seguente.

    {0}

    diff --git a/keycloak-themes/base/email/messages/messages_ja.properties b/keycloak-themes/base/email/messages/messages_ja.properties new file mode 100644 index 0000000..fb5c728 --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_ja.properties @@ -0,0 +1,52 @@ +# encoding: utf-8 +emailVerificationSubject=Eメールの確認 +emailVerificationBody=このメールアドレスで{2}アカウントが作成されました。以下のリンクをクリックしてメールアドレスの確認を完了してください。\n\n{0}\n\nこのリンクは{3}だけ有効です。\n\nもしこのアカウントの作成に心当たりがない場合は、このメールを無視してください。 +emailVerificationBodyHtml=

    このメールアドレスで{2}アカウントが作成されました。以下のリンクをクリックしてメールアドレスの確認を完了してください。

    メールアドレスの確認

    このリンクは{3}だけ有効です。

    もしこのアカウントの作成に心当たりがない場合は、このメールを無視してください。

    +emailTestSubject=[KEYCLOAK] - SMTPテストメッセージ +emailTestBody=これはテストメッセージです +emailTestBodyHtml=

    これはテストメッセージです

    +identityProviderLinkSubject=リンク {0} +identityProviderLinkBody=あなたの"{1}"アカウントと{2}ユーザーの"{0}"アカウントのリンクが要求されました。以下のリンクをクリックしてアカウントのリンクを行ってください。\n\n{3}\n\nこのリンクは{5}だけ有効です。\n\nもしアカウントのリンクを行わない場合は、このメッセージを無視してください。アカウントのリンクを行うことで、{0}経由で{1}にログインすることができるようになります。 +identityProviderLinkBodyHtml=

    あなたの{1}アカウントと{2}ユーザーの{0}アカウントのリンクが要求されました。以下のリンクをクリックしてアカウントのリンクを行ってください。

    アカウントリンクの確認

    このリンクは{5}だけ有効です。

    もしアカウントのリンクを行わない場合は、このメッセージを無視してください。アカウントのリンクを行うことで、{0}経由で{1}にログインすることができるようになります。

    +passwordResetSubject=パスワードのリセット +passwordResetBody=あなたの{2}アカウントのパスワードの変更が要求されています。以下のリンクをクリックしてパスワードのリセットを行ってください。\n\n{0}\n\nこのリンクは{3}だけ有効です。\n\nもしパスワードのリセットを行わない場合は、このメッセージを無視してください。何も変更されません。 +passwordResetBodyHtml=

    あなたの{2}アカウントのパスワードの変更が要求されています。以下のリンクをクリックしてパスワードのリセットを行ってください。

    パスワードのリセット

    このリンクは{3}だけ有効です。

    もしパスワードのリセットを行わない場合は、このメッセージを無視してください。何も変更されません。

    +executeActionsSubject=アカウントの更新 +executeActionsBody=次のアクションを実行することにより、管理者よりあなたの{2}アカウントの更新が要求されています: {3}。以下のリンクをクリックしてこのプロセスを開始してください。\n\n{0}\n\nこのリンクは{4}だけ有効です。\n\n管理者からのこの変更要求についてご存知ない場合は、このメッセージを無視してください。何も変更されません。 +executeActionsBodyHtml=

    次のアクションを実行することにより、管理者よりあなたの{2}アカウントの更新が要求されています: {3}。以下のリンクをクリックしてこのプロセスを開始してください。

    アカウントの更新

    このリンクは{4}だけ有効です。

    管理者からのこの変更要求についてご存知ない場合は、このメッセージを無視してください。何も変更されません。

    +eventLoginErrorSubject=ログインエラー +eventLoginErrorBody={0}に{1}からのログイン失敗があなたのアカウントで検出されました。心当たりがない場合は、管理者に連絡してください。 +eventLoginErrorBodyHtml=

    {0}に{1}からのログイン失敗があなたのアカウントで検出されました。心当たりがない場合は管理者に連絡してください。

    +eventRemoveTotpSubject=OTPの削除 +eventRemoveTotpBody={0}に{1}からの操作でOTPが削除されました。心当たりがない場合は、管理者に連絡してください。 +eventRemoveTotpBodyHtml=

    {0}に{1}からの操作でOTPが削除されました。心当たりがない場合は、管理者に連絡してください。

    +eventUpdatePasswordSubject=パスワードの更新 +eventUpdatePasswordBody={0}に{1}からの操作であなたのパスワードが変更されました。心当たりがない場合は、管理者に連絡してください。 +eventUpdatePasswordBodyHtml=

    {0}に{1}からの操作であなたのパスワードが変更されました。心当たりがない場合は、管理者に連絡してください。

    +eventUpdateTotpSubject=OTPの更新 +eventUpdateTotpBody={0}に{1}からの操作でOTPが更新されました。心当たりがない場合は、管理者に連絡してください。 +eventUpdateTotpBodyHtml=

    {0}に{1}からの操作でOTPが更新されました。心当たりがない場合は、管理者に連絡してください。

    + +requiredAction.CONFIGURE_TOTP=OTPの設定 +requiredAction.terms_and_conditions=利用規約 +requiredAction.UPDATE_PASSWORD=パスワードの更新 +requiredAction.UPDATE_PROFILE=プロファイルの更新 +requiredAction.VERIFY_EMAIL=Eメールの確認 + +# units for link expiration timeout formatting +linkExpirationFormatter.timePeriodUnit.seconds=秒 +linkExpirationFormatter.timePeriodUnit.seconds.1=秒 +linkExpirationFormatter.timePeriodUnit.minutes=分 +linkExpirationFormatter.timePeriodUnit.minutes.1=分 +#for language which have more unit plural forms depending on the value (eg. Czech and other Slavic langs) you can override unit text for some other values like this: +#linkExpirationFormatter.timePeriodUnit.minutes.2=minuty +#linkExpirationFormatter.timePeriodUnit.minutes.3=minuty +#linkExpirationFormatter.timePeriodUnit.minutes.4=minuty +linkExpirationFormatter.timePeriodUnit.hours=時間 +linkExpirationFormatter.timePeriodUnit.hours.1=時間 +linkExpirationFormatter.timePeriodUnit.days=日 +linkExpirationFormatter.timePeriodUnit.days.1=日 + +emailVerificationBodyCode=次のコードを入力してメールアドレスを確認してください。\n\n{0}\n\n. +emailVerificationBodyCodeHtml=

    次のコードを入力してメールアドレスを確認してください。

    {0}

    + diff --git a/keycloak-themes/base/email/messages/messages_lt.properties b/keycloak-themes/base/email/messages/messages_lt.properties new file mode 100644 index 0000000..abf1659 --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_lt.properties @@ -0,0 +1,25 @@ +# encoding: utf-8 +emailVerificationSubject=El. pašto patvirtinimas +emailVerificationBody=Paskyra {2} sukurta naudojant šį el. pašto adresą. Jei tai buvote Jūs, tuomet paspauskite žemiau esančią nuorodą\n\n{0}\n\nŠi nuoroda galioja {1} min.\n\nJei paskyros nekūrėte, tuomet ignuoruokite šį laišką. +emailVerificationBodyHtml=

    Paskyra {2} sukurta naudojant šį el. pašto adresą. Jei tao buvote Jūs, tuomet paspauskite žemiau esančią nuorodą

    {0}

    Ši nuoroda galioja {1} min.

    nJei paskyros nekūrėte, tuomet ignuoruokite šį laišką.

    +identityProviderLinkSubject=Sąsaja {0} +identityProviderLinkBody=Kažas pageidauja susieti Jūsų "{1}" paskyrą su "{0}" {2} naudotojo paskyrą. Jei tai buvote Jūs, tuomet paspauskite žemiau esančią nuorodą norėdami susieti paskyras\n\n{3}\n\nŠi nuoroda galioja {4} min.\n\nJei paskyrų susieti nenorite, tuomet ignoruokite šį laišką. Jei paskyras susiesite, tuomet prie {1} galėsiste prisijungti per {0}. +identityProviderLinkBodyHtml=

    žas pageidauja susieti Jūsų {1} paskyrą su {0} {2} naudotojo paskyrą. Jei tai buvote Jūs, tuomet paspauskite žemiau esančią nuorodą norėdami susieti paskyras

    {3}

    Ši nuoroda galioja {4} min.

    Jei paskyrų susieti nenorite, tuomet ignoruokite šį laišką. Jei paskyras susiesite, tuomet prie {1} galėsiste prisijungti per {0}.

    +passwordResetSubject=Slaptažodžio atkūrimas +passwordResetBody=Kažkas pageidauja pakeisti Jūsų paskyros {2} slaptažodį. Jei tai buvote Jūs, tuomet paspauskite žemiau esančią nuorodą slaptažodžio pakeitimui.\n\n{0}\n\nŠi nuoroda ir kodas galioja {1} min.\n\nJei nepageidajate keisti slaptažodžio, tuomet ignoruokite šį laišką ir niekas nebus pakeista. +passwordResetBodyHtml=

    Kažkas pageidauja pakeisti Jūsų paskyros {2} slaptažodį. Jei tai buvote Jūs, tuomet paspauskite žemiau esančią nuorodą slaptažodžio pakeitimui.

    {0}

    Ši nuoroda ir kodas galioja {1} min.

    Jei nepageidajate keisti slaptažodžio, tuomet ignoruokite šį laišką ir niekas nebus pakeista.

    +executeActionsSubject=Atnaujinkite savo paskyrą +executeActionsBody=Sistemos administratorius pageidauja, kad Jūs atnaujintumėte savo {2} paskyrą. Paspauskite žemiau esančią nuorodą paskyros duomenų atnaujinimui.\n\n{0}\n\nŠi nuoroda galioja {1} min.\n\nJei Jūs neasate tikri, kad tai administratoriaus pageidavimas, tuomet ignoruokite šį laišką ir niekas nebus pakeista. +executeActionsBodyHtml=

    Sistemos administratorius pageidauja, kad Jūs atnaujintumėte savo {2} paskyrą. Paspauskite žemiau esančią nuorodą paskyros duomenų atnaujinimui.

    {0}

    Ši nuoroda galioja {1} min.

    Jei Jūs neasate tikri, kad tai administratoriaus pageidavimas, tuomet ignoruokite šį laišką ir niekas nebus pakeista.

    +eventLoginErrorSubject=Nesėkmingas bandymas prisijungti prie jūsų paskyros +eventLoginErrorBody=Bandymas prisijungti prie jūsų paskyros {0} iš {1} nesėkmingas. Jei tai nebuvote jūs, tuomet susisiekite su administratoriumi +eventLoginErrorBodyHtml=

    Bandymas prisijungti prie jūsų paskyros {0} iš {1} nesėkmingas. Jei tai nebuvote jūs, tuomet susisiekite su administratoriumi

    +eventRemoveTotpSubject=OTP pašalinimas +eventRemoveTotpBody=Kažkas pageidauja atsieti TOPT Jūsų {1} paskyroje su {0}. Jei tai nebuvote Jūs, tuomet susisiekite su administratoriumi +eventRemoveTotpBodyHtml=

    Kažkas pageidauja atsieti TOPT Jūsų {1} paskyroje su {0}. Jei tai nebuvote Jūs, tuomet susisiekite su administratoriumi

    +eventUpdatePasswordSubject=Slaptažodžio atnaujinimas +eventUpdatePasswordBody={1} paskyroje {0} pakeisas jūsų slaptažodis. Jei Jūs nekeitėte, tuomet susisiekite su administratoriumi +eventUpdatePasswordBodyHtml=

    {1} paskyroje {0} pakeisas jūsų slaptažodis. Jei Jūs nekeitėte, tuomet susisiekite su administratoriumi

    +eventUpdateTotpSubject=OTP atnaujinimas +eventUpdateTotpBody=OTP Jūsų {1} paskyroje su {0} buvo atnaujintas. Jei tai nebuvote Jūs, tuomet susisiekite su administratoriumi +eventUpdateTotpBodyHtml=

    OTP Jūsų {1} paskyroje su {0} buvo atnaujintas. Jei tai nebuvote Jūs, tuomet susisiekite su administratoriumi

    \ No newline at end of file diff --git a/keycloak-themes/base/email/messages/messages_nl.properties b/keycloak-themes/base/email/messages/messages_nl.properties new file mode 100644 index 0000000..9e6efbe --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_nl.properties @@ -0,0 +1,38 @@ +emailVerificationSubject=Bevestig e-mailadres +emailVerificationBody=Iemand heeft een {2} account aangemaakt met dit e-mailadres. Als u dit was, klikt u op de onderstaande koppeling om uw e-mailadres te bevestigen \n\n{0}\n\nDeze koppeling zal binnen {3} vervallen.\n\nU kunt dit bericht negeren indien u dit account niet heeft aangemaakt. +emailVerificationBodyHtml=

    Iemand heeft een {2} account aangemaakt met dit e-mailadres. Als u dit was, klikt u op de onderstaande koppeling om uw e-mailadres te bevestigen

    Koppeling naar e-mailadres bevestiging

    Deze koppeling zal binnen {3} vervallen.U kunt dit bericht negeren indien u dit account niet heeft aangemaakt.

    +emailTestSubject=[KEYCLOAK] - SMTP testbericht +emailTestBody=Dit is een testbericht +emailTestBodyHtml=

    Dit is een testbericht

    +identityProviderLinkSubject=Koppel {0} +identityProviderLinkBody=Iemand wil uw "{1}" account koppelen met "{0}" account van gebruiker {2}. Als u dit was, klik dan op de onderstaande link om de accounts te koppelen\n\n{3}\n\nDeze link zal over {5} vervallen.\n\nAls u de accounts niet wilt koppelen, negeer dan dit bericht. Als u accounts koppelt, dan kunt u bij {1} inloggen via {0}. +identityProviderLinkBodyHtml=

    Iemand wil uw "{1}" account koppelen met "{0}" account van gebruiker {2}. Als u dit was, klik dan op de onderstaande link om de accounts te koppelen

    Link om accounts te koppelen

    Deze link zal over {5} vervallen.

    Als u de accounts niet wilt koppelen, negeer dan dit bericht. Als u accounts koppelt, dan kunt u bij {1} inloggen via {0}.

    +passwordResetSubject=Wijzig wachtwoord +passwordResetBody=Iemand verzocht de aanmeldgegevens van uw {2} account te wijzigen. Als u dit was, klik dan op de onderstaande koppeling om ze te wijzigen.\n\n{0}\n\nDe link en de code zullen binnen {3} vervallen.\n\nAls u uw aanmeldgegevens niet wilt wijzigen, negeer dan dit bericht en er zal niets gewijzigd worden. +passwordResetBodyHtml=

    Iemand verzocht de aanmeldgegevens van uw {2} account te wijzigen. Als u dit was, klik dan op de onderstaande koppeling om ze te wijzigen.

    Wijzig aanmeldgegevens

    De link en de code zullen binnen {3} vervallen.

    Als u uw aanmeldgegevens niet wilt wijzigen, negeer dan dit bericht en er zal niets gewijzigd worden.

    +executeActionsSubject=Wijzig uw account +executeActionsBody=Uw beheerder heeft u verzocht uw {2} account te wijzigen. Klik op de onderstaande koppeling om dit proces te starten. \n\n{0}\n\nDeze link zal over {4} vervallen. \n\nAls u niet over dit verzoek op de hoogte was, negeer dan dit bericht om uw account ongewijzigd te laten. +executeActionsBodyHtml=

    Uw beheerder heeft u verzocht uw {2} account te wijzigen. Klik op de onderstaande koppeling om dit proces te starten.

    Link naar account wijziging

    Deze link zal over {4} vervallen.

    Als u niet over dit verzoek op de hoogte was, negeer dan dit bericht om uw account ongewijzigd te laten.

    +eventLoginErrorSubject=Inlogfout +eventLoginErrorBody=Er is een foutieve inlogpoging gedetecteerd op uw account om {0} vanuit {1}. Als u dit niet was, neem dan contact op met de beheerder. +eventLoginErrorBodyHtml=

    Er is een foutieve inlogpoging gedetecteerd op uw account om {0} vanuit {1}. Als u dit niet was, neem dan contact op met de beheerder.

    +eventRemoveTotpSubject=OTP verwijderd +eventRemoveTotpBody=OTP is verwijderd van uw account om {0} vanuit {1}. Als u dit niet was, neem dan contact op met uw beheerder. +eventRemoveTotpBodyHtml=

    OTP is verwijderd van uw account om {0} vanuit {1}. Als u dit niet was, neem dan contact op met uw beheerder.

    +eventUpdatePasswordSubject=Wachtwoord gewijzigd +eventUpdatePasswordBody=Uw wachtwoord is gewijzigd om {0} door {1}. Als u dit niet was, neem dan contact op met uw beheerder. +eventUpdatePasswordBodyHtml=

    Uw wachtwoord is gewijzigd om {0} door {1}. Als u dit niet was, neem dan contact op met uw beheerder.

    +eventUpdateTotpSubject=OTP gewijzigd +eventUpdateTotpBody=OTP is gewijzigd voor uw account om {0} door {1}. Als u dit niet was, neem dan contact op met uw beheerder. +eventUpdateTotpBodyHtml=

    OTP is gewijzigd voor uw account om {0} door {1}. Als u dit niet was, neem dan contact op met uw beheerder.

    + + +# units for link expiration timeout formatting +linkExpirationFormatter.timePeriodUnit.seconds=seconden +linkExpirationFormatter.timePeriodUnit.seconds.1=seconde +linkExpirationFormatter.timePeriodUnit.minutes=minuten +linkExpirationFormatter.timePeriodUnit.minutes.1=minuut +linkExpirationFormatter.timePeriodUnit.hours=uur +linkExpirationFormatter.timePeriodUnit.hours.1=uur +linkExpirationFormatter.timePeriodUnit.days=dagen +linkExpirationFormatter.timePeriodUnit.days.1=dag diff --git a/keycloak-themes/base/email/messages/messages_no.properties b/keycloak-themes/base/email/messages/messages_no.properties new file mode 100644 index 0000000..32334e9 --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_no.properties @@ -0,0 +1,24 @@ +emailVerificationSubject=Bekreft e-postadresse +emailVerificationBody=Noen har opprettet en {2} konto med denne e-postadressen. Hvis dette var deg, klikk p\u00E5 lenken nedenfor for \u00E5 bekrefte e-postadressen din\n\n{0}\n\nDenne lenken vil utl\u00F8pe om {1} minutter.\n\nHvis du ikke opprettet denne kontoen, vennligst ignorer denne meldingen. +emailVerificationBodyHtml=

    Noen har opprettet en {2} konto med denne e-postadressen. Hvis dette var deg, klikk p\u00E5 lenken nedenfor for \u00E5 bekrefte e-postadressen din

    {0}

    Denne lenken vil utl\u00F8pe om {1} minutter.

    Hvis du ikke opprettet denne kontoen, vennligst ignorer denne meldingen.

    +identityProviderLinkSubject=Lenke {0} +identityProviderLinkBody=Noen vil koble din {1} konto med {0} konto til bruker {2}. Hvis dette var deg, klikk p\u00E5 lenken nedenfor for \u00E5 koble kontoene\n\n{3}\n\nDenne lenken vil utl\u00F8pe om {4} minutter\n\nHvis du ikke vil koble kontoene, vennligst ignorer denne meldingen. Hvis du kobler kontoene sammen vil du kunne logge inn til {1} gjennom {0}. +identityProviderLinkBodyHtml=

    Noen vil koble din {1} konto med {0} konto til bruker {2}. Hvis dette var deg, klikk p\u00E5 lenken nedenfor for \u00E5 koble kontoene.

    {3}

    Denne lenken vil utl\u00F8pe om {4} minutter.

    Hvis du ikke vil koble kontoene, vennligst ignorer denne meldingen. Hvis du kobler kontoene sammen vil du kunne logge inn til {1} gjennom {0}.

    +passwordResetSubject=Tilbakestill passord +passwordResetBody=Noen har bedt om \u00E5 endre innloggingsdetaljene til din konto {2}. Hvis dette var deg, klikk p\u00E5 lenken nedenfor for \u00E5 tilbakestille dem.\n\n{0}\n\nDenne lenken vil utl\u00F8pe om {1} minutter.\n\nHvis du ikke vil tilbakestille din innloggingsdata, vennligst ignorer denne meldingen og ingenting vil bli endret. +passwordResetBodyHtml=

    Noen har bedt om \u00E5 endre innloggingsdetaljene til din konto {2}. Hvis dette var deg, klikk p\u00E5 lenken nedenfor for \u00E5 tilbakestille dem.

    {0}

    Denne lenken vil utl\u00F8pe om {1} minutter.

    Hvis du ikke vil tilbakestille din innloggingsdata, vennligst ignorer denne meldingen og ingenting vil bli endret.

    +executeActionsSubject=Oppdater kontoen din +executeActionsBody=Administrator har anmodet at du oppdaterer din {2} konto. Klikk p\u00E5 lenken nedenfor for \u00E5 starte denne prosessen\n\n{0}\n\nDenne lenken vil utl\u00F8pe om {1} minutter.\n\nHvis du ikke var klar over at administrator har bedt om dette, vennligst ignorer denne meldingen og ingenting vil bli endret. +executeActionsBodyHtml=

    Administrator har anmodet at du oppdaterer din {2} konto. Klikk p\u00E5 linken nedenfor for \u00E5 starte denne prosessen.

    {0}

    Denne lenken vil utl\u00F8pe om {1} minutter.

    Hvis du ikke var klar over at administrator har bedt om dette, ignorer denne meldingen og ingenting vil bli endret.

    +eventLoginErrorSubject=Innlogging feilet +eventLoginErrorBody=Et mislykket innloggingsfors\u00F8k ble oppdaget p\u00E5 din konto p\u00E5 {0} fra {1}. Hvis dette ikke var deg, vennligst kontakt administrator. +eventLoginErrorBodyHtml=

    Et mislykket innloggingsfors\u00F8k ble oppdaget p\u00E5 din konto p\u00E5 {0} fra {1}. Hvis dette ikke var deg, vennligst kontakt administrator.

    +eventRemoveTotpSubject=Fjern engangskode +eventRemoveTotpBody=Engangskode ble fjernet fra kontoen din p\u00E5 {0} fra {1}. Hvis dette ikke var deg, vennligst kontakt administrator. +eventRemoveTotpBodyHtml=

    Engangskode ble fjernet fra kontoen din p\u00E5 {0} fra {1}. Hvis dette ikke var deg, vennligst kontakt administrator.

    +eventUpdatePasswordSubject=Oppdater passord +eventUpdatePasswordBody=Ditt passord ble endret i {0} fra {1}. Hvis dette ikke var deg, vennligst kontakt administrator. +eventUpdatePasswordBodyHtml=

    Ditt passord ble endret i {0} fra {1}. Hvis dette ikke var deg, vennligst kontakt administrator.

    +eventUpdateTotpSubject=Oppdater engangskode +eventUpdateTotpBody=Engangskode ble oppdatert for kontoen din p\u00E5 {0} fra {1}. Hvis dette ikke var deg, vennligst kontakt administrator. +eventUpdateTotpBodyHtml=

    Engangskode ble oppdatert for kontoen din p\u00E5 {0} fra {1}. Hvis dette ikke var deg, vennligst kontakt administrator.

    diff --git a/keycloak-themes/base/email/messages/messages_pl.properties b/keycloak-themes/base/email/messages/messages_pl.properties new file mode 100644 index 0000000..757f1bd --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_pl.properties @@ -0,0 +1,56 @@ +# encoding: UTF-8 +emailVerificationSubject=Zweryfikuj email +emailVerificationBody=Ktoś utworzył już konto {2} z tym adresem e-mail. Jeśli to Ty, kliknij poniższy link, aby zweryfikować swój adres e-mail \n\n{0}\n\nLink ten wygaśnie w ciągu {3}.\n\nJeśli nie utworzyłeś tego konta, po prostu zignoruj tę wiadomość. +emailVerificationBodyHtml=

    Ktoś utworzył już konto {2} z tym adresem e-mail. Jeśli to Ty, kliknij ten link aby zweryfikować swój adres e-mail

    Link ten wygaśnie w ciągu {3}

    Jeśli nie utworzyłeś tego konta, po prostu zignoruj tę wiadomość.

    +emailTestSubject=[KEYCLOAK] - wiadomość testowa SMTP +emailTestBody=To jest wiadomość testowa +emailTestBodyHtml=

    To jest wiadomość testowa

    +identityProviderLinkSubject=Link {0} +identityProviderLinkBody=Ktoś chce połączyć Twoje konto "{1}" z kontem "{0}" użytkownika {2}. Jeśli to Ty, kliknij poniższy link by połączyć konta\n\n{3}\n\nTen link wygaśnie w ciągu {5}.\n\nJeśli nie chcesz połączyć konta to zignoruj tę wiadomość. Jeśli połączysz konta, będziesz mógł się zalogować na {1} przez {0}. +identityProviderLinkBodyHtml=

    Ktoś chce połączyć Twoje konto {1} z kontem {0} użytkownika {2}. Jeśli to Ty, kliknij ten link by połączyć konta.

    Ten link wygaśnie w ciągu {5}.

    Jeśli nie chcesz połączyć konta to zignoruj tę wiadomość. Jeśli połączysz konta, będziesz mógł się zalogować na {1} przez {0}.

    +passwordResetSubject=Zresetuj hasło +passwordResetBody=Ktoś właśnie poprosił o zmianę danych logowania Twojego konta {2}. Jeśli to Ty, kliknij poniższy link, aby je zresetować.\n\n{0}\n\nTen link i kod stracą ważność w ciągu {3}.\n\nJeśli nie chcesz zresetować swoich danych logowania, po prostu zignoruj tę wiadomość i nic się nie zmieni. +passwordResetBodyHtml=

    Ktoś właśnie poprosił o zmianę poświadczeń Twojego konta {2}. Jeśli to Ty, kliknij poniższy link, aby je zresetować.

    Link do resetowania poświadczeń

    Ten link wygaśnie w ciągu {3}.

    Jeśli nie chcesz resetować swoich poświadczeń, po prostu zignoruj tę wiadomość i nic się nie zmieni.

    +executeActionsSubject=Zaktualizuj swoje konto +executeActionsBody=Administrator właśnie zażądał aktualizacji konta {2} poprzez wykonanie następujących działań: {3}. Kliknij poniższy link, aby rozpocząć ten proces.\n\n{0}\n\nTen link wygaśnie w ciągu {4}.\n\nJeśli nie masz pewności, że administrator tego zażądał, po prostu zignoruj tę wiadomość i nic się nie zmieni. +executeActionsBodyHtml=

    Administrator właśnie zażądał aktualizacji konta {2} poprzez wykonanie następujących działań: {3}. Kliknij ten link, aby rozpocząć proces.

    Link ten wygaśnie w ciągu {4}.

    Jeśli nie masz pewności, że administrator tego zażądał, po prostu zignoruj tę wiadomość i nic się nie zmieni.

    +eventLoginErrorSubject=Błąd logowania +eventLoginErrorBody=Nieudana próba logowania została wykryta na Twoim koncie {0} z {1}. Jeśli to nie Ty, skontaktuj się z administratorem. +eventLoginErrorBodyHtml=

    Nieudana próba logowania została wykryta na Twoim koncie {0} z {1}. Jeśli to nie Ty, skontaktuj się z administratorem.

    +eventRemoveTotpSubject=Usuń hasło jednorazowe (OTP) +eventRemoveTotpBody=Hasło jednorazowe (OTP) zostało usunięte z Twojego konta w {0} z {1}. Jeśli to nie Ty, skontaktuj się z administratorem. +eventRemoveTotpBodyHtml=

    Hasło jednorazowe (OTP) zostało usunięte z Twojego konta w {0} z {1}. Jeśli to nie Ty, skontaktuj się z administratorem.

    +eventUpdatePasswordSubject=Aktualizuj hasło +eventUpdatePasswordBody=Twoje hasło zostało zmienione {0} z {1}. Jeśli to nie Ty, skontaktuj się z administratorem. +eventUpdatePasswordBodyHtml=

    Twoje hasło zostało zmienione {0} z {1}. Jeśli to nie Ty, skontaktuj się z administratorem.

    +eventUpdateTotpSubject=Aktualizuj hasło jednorazowe (OTP) +eventUpdateTotpBody=Hasło jednorazowe (OTP) zostało zaktualizowane na Twoim koncie {0} z {1}. Jeśli to nie Ty, skontaktuj się z administratorem. +eventUpdateTotpBodyHtml=

    Hasło jednorazowe (OTP) zostało zaktualizowane na Twoim koncie {0} z {1}. Jeśli to nie Ty, skontaktuj się z administratorem.

    + +requiredAction.CONFIGURE_TOTP=Konfiguracja hasła jednorazowego (OTP) +requiredAction.terms_and_conditions=Regulamin +requiredAction.UPDATE_PASSWORD=Aktualizacja hasła +requiredAction.UPDATE_PROFILE=Aktualizacja profilu +requiredAction.VERIFY_EMAIL=Weryfikacja adresu e-mail + +# units for link expiration timeout formatting +linkExpirationFormatter.timePeriodUnit.seconds=sekund +linkExpirationFormatter.timePeriodUnit.seconds.1=sekunda +linkExpirationFormatter.timePeriodUnit.seconds.2=sekundy +linkExpirationFormatter.timePeriodUnit.seconds.3=sekundy +linkExpirationFormatter.timePeriodUnit.seconds.4=sekundy +linkExpirationFormatter.timePeriodUnit.minutes=minut +linkExpirationFormatter.timePeriodUnit.minutes.1=minuta +linkExpirationFormatter.timePeriodUnit.minutes.2=minuty +linkExpirationFormatter.timePeriodUnit.minutes.3=minuty +linkExpirationFormatter.timePeriodUnit.minutes.4=minuty +linkExpirationFormatter.timePeriodUnit.hours=godzin +linkExpirationFormatter.timePeriodUnit.hours.1=godzina +linkExpirationFormatter.timePeriodUnit.hours.2=godziny +linkExpirationFormatter.timePeriodUnit.hours.3=godziny +linkExpirationFormatter.timePeriodUnit.hours.4=godziny +linkExpirationFormatter.timePeriodUnit.days=dni +linkExpirationFormatter.timePeriodUnit.days.1=dzień + +emailVerificationBodyCode=Potwierdź swój adres e-mail wprowadzając następujący kod.\n\n{0}\n\n. +emailVerificationBodyCodeHtml=

    Potwierdź swój adres e-mail, wprowadzając następujący kod.

    {0}

    diff --git a/keycloak-themes/base/email/messages/messages_pt_BR.properties b/keycloak-themes/base/email/messages/messages_pt_BR.properties new file mode 100644 index 0000000..d8fa214 --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_pt_BR.properties @@ -0,0 +1,51 @@ +emailVerificationSubject=Verifica\u00E7\u00E3o de endere\u00e7o de e-mail +emailVerificationBody=Algu\u00E9m criou uma conta {2} com este endere\u00E7o de e-mail. Se foi voc\u00EA, clique no link abaixo para verificar o seu endere\u00E7o de email.\n\n{0}\n\nEste link ir\u00E1 expirar dentro de {3}.\n\nSe n\u00E3o foi voc\u00EA quem criou esta conta, basta ignorar esta mensagem. +emailVerificationBodyHtml=

    Algu\u00E9m criou uma conta {2} com este endere\u00E7o de e-mail. Se foi voc\u00EA, clique no link abaixo para verificar o seu endere\u00E7o de email.

    Link para verifica\u00e7\u00e3o de endere\u00e7o de e-mail

    Este link ir\u00E1 expirar dentro de {3}.

    Se n\u00E3o foi voc\u00EA quem criou esta conta, basta ignorar esta mensagem.

    +emailTestSubject=[KEYCLOAK] - Mensagem de teste SMTP +emailTestBody=Esta \u00E9 uma mensagem de teste +emailTestBodyHtml=

    Esta \u00E9 uma mensagem de teste

    +identityProviderLinkSubject=Vincular {0} +identityProviderLinkBody=Algu\u00E9m quer vincular a sua conta "{1}" com a conta "{0}" do usu\u00E1rio {2} . Se foi voc\u00EA, clique no link abaixo para vincular as contas.\n\n{3}\n\nEste link ir\u00E1 expirar em {5}.\n\nSe voc\u00EA n\u00E3o quer vincular a conta, apenas ignore esta mensagem. Se voc\u00EA vincular as contas, voc\u00EA ser\u00E1 capaz de logar em {1} fazendo login em {0}. +identityProviderLinkBodyHtml=

    Algu\u00E9m quer vincular a sua conta {1} com a conta {0} do usu\u00E1rio {2} . Se foi voc\u00EA, clique no link abaixo para vincular as contas.

    Link para confirmar vincula\u00e7\u00e3o de contas

    Este link ir\u00E1 expirar em {5}.

    Se voc\u00EA n\u00E3o quer vincular a conta, apenas ignore esta mensagem. Se voc\u00EA vincular as contas, voc\u00EA ser\u00E1 capaz de logar em {1} fazendo login em {0}.

    +passwordResetSubject=Redefini\u00E7\u00E3o de senha +passwordResetBody=Algu\u00E9m solicitou uma altera\u00E7\u00E3o de senha da sua conta {2}. Se foi voc\u00EA, clique no link abaixo para redefini-la.\n\n{0}\n\nEste link e c\u00F3digo expiram em {3}.\n\nSe voc\u00EA n\u00E3o deseja redefinir sua senha, apenas ignore esta mensagem e nada ser\u00E1 alterado. +passwordResetBodyHtml=

    Algu\u00E9m solicitou uma altera\u00E7\u00E3o de senha da sua conta {2}. Se foi voc\u00EA, clique no link abaixo para redefini-la.

    Link para redefinir a senha

    Este link ir\u00E1 expirar em {3}.

    Se voc\u00EA n\u00E3o deseja redefinir sua senha, apenas ignore esta mensagem e nada ser\u00E1 alterado.

    +executeActionsSubject=Atualiza\u00E7\u00E3o de conta +executeActionsBody=Um administrador solicitou que voc\u00EA atualize sua conta {2} com a(s) seguinte(s) etapa(s): {3}. Clique no link abaixo para iniciar o processo.\n\n{0}\n\nEste link ir\u00E1 expirar em {4}.\n\nSe voc\u00EA n\u00E3o tem conhecimento de que o administrador solicitou isso, basta ignorar esta mensagem e nada ser\u00E1 alterado. +executeActionsBodyHtml=

    Um administrador solicitou que voc\u00EA atualize sua conta {2} com a(s) seguinte(s) etapa(s): {3}. Clique no link abaixo para iniciar o processo.

    Link para atualizar a conta

    Este link ir\u00E1 expirar em {4}.

    Se voc\u00EA n\u00E3o tem conhecimento de que o administrador solicitou isso, basta ignorar esta mensagem e nada ser\u00E1 alterado.

    +eventLoginErrorSubject=Erro de login +eventLoginErrorBody=Uma tentativa de login malsucedida da sua conta foi detectada em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador. +eventLoginErrorBodyHtml=

    Uma tentativa de login malsucedida da sua conta foi detectada em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador.

    +eventRemoveTotpSubject=Remover autentica\u00e7\u00e3o de dois fatores +eventRemoveTotpBody=A autentica\u00e7\u00e3o de dois fatores foi removida da sua conta em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador. +eventRemoveTotpBodyHtml=

    A autentica\u00e7\u00e3o de dois fatores foi removida da sua conta em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador.

    +eventUpdatePasswordSubject=Atualiza\u00E7\u00E3o de senha +eventUpdatePasswordBody=Sua senha foi alterada em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador. +eventUpdatePasswordBodyHtml=

    Sua senha foi alterada em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador.

    +eventUpdateTotpSubject=Atualiza\u00E7\u00E3o de autentica\u00e7\u00e3o de dois fatores +eventUpdateTotpBody=A autentica\u00e7\u00e3o de dois fatores foi atualizada para a sua conta em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador. +eventUpdateTotpBodyHtml=

    A autentica\u00e7\u00e3o de dois fatores foi atualizada para a sua conta em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador.

    + +requiredAction.CONFIGURE_TOTP=Configurar Autentica\u00e7\u00e3o de Dois Fatores +requiredAction.terms_and_conditions=Termos e Condi\u00E7\u00F5es +requiredAction.UPDATE_PASSWORD=Atualizar Senha +requiredAction.UPDATE_PROFILE=Atualizar Perfil +requiredAction.VERIFY_EMAIL=Verificar Endere\u00e7o de E-mail + +# units for link expiration timeout formatting +linkExpirationFormatter.timePeriodUnit.seconds=segundos +linkExpirationFormatter.timePeriodUnit.seconds.1=segundo +linkExpirationFormatter.timePeriodUnit.minutes=minutos +linkExpirationFormatter.timePeriodUnit.minutes.1=minuto +#for language which have more unit plural forms depending on the value (eg. Czech and other Slavic langs) you can override unit text for some other values like this: +#linkExpirationFormatter.timePeriodUnit.minutes.2=minuty +#linkExpirationFormatter.timePeriodUnit.minutes.3=minuty +#linkExpirationFormatter.timePeriodUnit.minutes.4=minuty +linkExpirationFormatter.timePeriodUnit.hours=horas +linkExpirationFormatter.timePeriodUnit.hours.1=hora +linkExpirationFormatter.timePeriodUnit.days=dias +linkExpirationFormatter.timePeriodUnit.days.1=dia + +emailVerificationBodyCode=Verifique o seu endere\u00E7o de e-mail inserindo o seguinte c\u00F3digo.\n\n{0}\n\n. +emailVerificationBodyCodeHtml=

    Verifique o seu endere\u00E7o de e-mail inserindo o seguinte c\u00F3digo.

    {0}

    + diff --git a/keycloak-themes/base/email/messages/messages_ru.properties b/keycloak-themes/base/email/messages/messages_ru.properties new file mode 100644 index 0000000..7f6886b --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_ru.properties @@ -0,0 +1,25 @@ +# encoding: utf-8 +emailVerificationSubject=Подтверждение E-mail +emailVerificationBody=Кто-то создал учетную запись {2} с этим E-mail. Если это были Вы, нажмите на следующую ссылку для подтверждения вашего email\n\n{0}\n\nЭта ссылка устареет через {1} минут.\n\nЕсли Вы не создавали учетную запись, просто проигнорируйте это письмо. +emailVerificationBodyHtml=

    Кто-то создал учетную запись {2} с этим E-mail. Если это были Вы, нажмите по ссылке для подтверждения вашего E-mail

    {0}

    Эта ссылка устареет через {1} минут.

    Если Вы не создавали учетную запись, просто проигнорируйте это письмо.

    +identityProviderLinkSubject=Ссылка {0} +identityProviderLinkBody=Кто-то хочет связать вашу учетную запись "{1}" с "{0}" учетной записью пользователя {2} . Если это были Вы, нажмите по следующей ссылке, чтобы связать учетные записи\n\n{3}\n\nЭта ссылка устареет через {4} минут.\n\nЕсли это не хотите объединять учетные записи, просто проигнориуйте это письмо. После объединения учетных записей Вы можете войти в {1} через {0}. +identityProviderLinkBodyHtml=

    Кто-то хочет связать вашу учетную запись {1} с {0} учетной записью пользователя {2} . Если это были Вы, нажмите по следующей ссылке, чтобы связать учетные записи

    {3}

    Эта ссылка устареет через {4} минут.

    Если это не хотите объединять учетные записи, просто проигнориуйте это письмо. После объединения учетных записей Вы можете войти в {1} через {0}.

    +passwordResetSubject=Сброс пароля +passwordResetBody=Кто-то только что запросил изменение пароля от Вашей учетной записи {2}. Если это были Вы, нажмите на следующую ссылку, чтобы сбросить его.\n\n{0}\n\nЭта ссылка устареет через {1} минут.\n\nЕсли Вы не хотите сбрасывать пароль, просто проигнорируйте это письмо. +passwordResetBodyHtml=

    Кто-то только что запросил изменение пароля от Вашей учетной записи {2}. Если это были Вы, нажмите на следующую ссылку, чтобы сбросить его.

    {0}

    Эта ссылка устареет через {1} минут.

    Если Вы не хотите сбрасывать пароль, просто проигнорируйте это письмо и ничего не изменится.

    +executeActionsSubject=Обновление Вашей учетной записи +executeActionsBody=Администратор просит Вас обновить данные Вашей учетной записи {2}. Нажмите по следующей ссылке чтобы начать этот процесс.\n\n{0}\n\nЭта ссылка устареет через {1} минут.\n\nЕсли у вас есть подозрения, что администратор не мог сделать такой запрос, просто проигнорируйте это письмо. +executeActionsBodyHtml=

    Администратор просит Вас обновить данные Вашей учетной записи {2}. Нажмите по следующей ссылке чтобы начать этот процесс.

    {0}

    Эта ссылка устареет через {1} минут.

    Если у вас есть подозрения, что администратор не мог сделать такой запрос, просто проигнорируйте это письмо.

    +eventLoginErrorSubject=Ошибка входа +eventLoginErrorBody=Была зафиксирована неудачная попытка входа в Вашу учетную запись {0} с {1}. Если это были не Вы, пожалуйста, свяжитесь с администратором. +eventLoginErrorBodyHtml=

    Была зафиксирована неудачная попытка входа в Вашу учетную запись {0} с {1}. Если это были не Вы, пожалуйста, свяжитесь с администратором.

    +eventRemoveTotpSubject=Удалить OTP +eventRemoveTotpBody=OTP был удален из вашей учетной записи {0} c {1}. Если это были не Вы, пожалуйста, свяжитесь с администратором. +eventRemoveTotpBodyHtml=

    OTP был удален из вашей учетной записи {0} c {1}. Если это были не Вы, пожалуйста, свяжитесь с администратором.

    +eventUpdatePasswordSubject=Обновление пароля +eventUpdatePasswordBody=Ваш пароль был изменен в {0} с {1}. Если это были не Вы, пожалуйста, свяжитесь с администратором. +eventUpdatePasswordBodyHtml=

    Ваш пароль был изменен в {0} с {1}. Если это были не Вы, пожалуйста, свяжитесь с администратором.

    +eventUpdateTotpSubject=Обновление OTP +eventUpdateTotpBody=OTP был обновлен в вашей учетной записи {0} с {1}. Если это были не Вы, пожалуйста, свяжитесь с администратором. +eventUpdateTotpBodyHtml=

    OTP был обновлен в вашей учетной записи {0} с {1}. Если это были не Вы, пожалуйста, свяжитесь с администратором.

    diff --git a/keycloak-themes/base/email/messages/messages_sk.properties b/keycloak-themes/base/email/messages/messages_sk.properties new file mode 100644 index 0000000..a87972c --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_sk.properties @@ -0,0 +1,48 @@ +# encoding: utf-8 +emailVerificationSubject=Overenie e-mailu +emailVerificationBody=Niekto vytvoril účet {2} s touto e-mailovou adresou. Ak ste to vy, kliknite na nižšie uvedený odkaz a overte svoju e-mailovú adresu \n\n{0}\n\nTento odkaz uplynie do {1} minút.\n\nAk ste tento účet nevytvorili, ignorujte túto správu. +emailVerificationBodyHtml=

    Niekto vytvoril účet {2} s touto e-mailovou adresou. Ak ste to vy, kliknite na nižšie uvedený odkaz na overenie svojej e-mailovej adresy.

    Odkaz na overenie e-mailovej adresy

    Platnosť odkazu vyprší za {1} minút.

    Ak ste tento účet nevytvorili, ignorujte túto správu.

    +emailTestSubject=[KEYCLOAK] - Testovacia správa SMTP +emailTestBody=Toto je skúšobná správa +emailTestBodyHtml=

    Toto je skúšobná správa

    +identityProviderLinkSubject=Odkaz {0} +identityProviderLinkBody=Niekto chce prepojiť váš účet "{1}" s účtom {0}"používateľa {2}. Ak ste to vy, kliknutím na odkaz nižšie prepojte účty. \n\n{3}\n\nTento odkaz uplynie do {4} minút.\n\nAk nechcete prepojiť účet, jednoducho ignorujte túto správu , Ak prepájate účty, budete sa môcť prihlásiť do {1} až {0}. +identityProviderLinkBodyHtml=

    Niekto chce prepojiť váš účet {1} s účtom {0} používateľa {2}. Ak ste to vy, kliknutím na odkaz nižšie prepojte účty

    Odkaz na potvrdenie prepojenia účtu

    Platnosť tohto odkazu vyprší v rámci {4} minút.

    Ak nechcete prepojiť účet, ignorujte túto správu. Ak prepojujete účty, budete sa môcť prihlásiť do {1} až {0}.

    +passwordResetSubject=Obnovenie hesla +passwordResetBody=Niekto požiadal, aby ste zmenili svoje poverenia účtu {2}. Ak ste to vy, kliknite na odkaz uvedený nižšie, aby ste ich vynulovali.\n\n{0}\n\nTento odkaz a kód uplynie do {1} minút.\n\nAk nechcete obnoviť svoje poverenia , ignorujte túto správu a nič sa nezmení. +passwordResetBodyHtml=

    Niekto požiadal, aby ste zmenili svoje poverenia účtu {2}. Ak ste to vy, kliknutím na odkaz nižšie ich resetujte.

    Odkaz na obnovenie poverení

    Platnosť tohto odkazu vyprší v priebehu {1} minút.

    Ak nechcete obnoviť svoje poverenia, ignorujte túto správu a nič sa nezmení.

    +executeActionsSubject=Aktualizujte svoj účet +executeActionsBody=Váš administrátor práve požiadal o aktualizáciu vášho účtu {2} vykonaním nasledujúcich akcií: {3}. Kliknutím na odkaz uvedený nižšie spustíte tento proces.\n\n{0}\n\nTento odkaz vyprší za {1} minúty.\n\nAk si nie ste vedomý, že váš adminstrátor o toto požiadal, ignorujte túto správu a nič bude zmenené. +executeActionsBodyHtml=

    Váš správca práve požiadal o aktualizáciu vášho účtu {2} vykonaním nasledujúcich akcií: {3}. Kliknutím na odkaz uvedený nižšie spustíte tento proces.

    Odkaz na aktualizáciu účtu

    Platnosť tohto odkazu uplynie do {1} minúty.

    Ak si nie ste vedomí, že váš adminstrátor o toto požiadal, ignorujte túto správu a nič sa nezmení.

    +eventLoginErrorSubject=Chyba prihlásenia +eventLoginErrorBody=Bol zistený neúspešný pokus o prihlásenie do vášho účtu v {0} z {1}. Ak ste to neboli vy, obráťte sa na administrátora. +eventLoginErrorBodyHtml=

    Bol zistený neúspešný pokus o prihlásenie vášho účtu na {0} z {1}. Ak ste to neboli vy, kontaktujte administrátora.

    +eventRemoveTotpSubject=Odstrániť TOTP +eventRemoveTotpBody=OTP bol odstránený z vášho účtu dňa {0} z {1}. Ak ste to neboli vy, obráťte sa na administrátora. +eventRemoveTotpBodyHtml=

    OTP bol odstránený z vášho účtu dňa {0} z {1}. Ak ste to neboli vy, kontaktujte administrátora.

    +eventUpdatePasswordSubject=Aktualizovať heslo +eventUpdatePasswordBody=Vaše heslo bolo zmenené na {0} z {1}. Ak ste to neboli vy, obráťte sa na administrátora. +eventUpdatePasswordBodyHtml=

    Vaše heslo bolo zmenené na {0} z {1}. Ak ste to neboli vy, kontaktujte administrátora.

    +eventUpdateTotpSubject=Aktualizácia TOTP +eventUpdateTotpBody=TOTP bol aktualizovaný pre váš účet na {0} z {1}. Ak ste to neboli vy, obráťte sa na administrátora. +eventUpdateTotpBodyHtml=

    TOTP bol aktualizovaný pre váš účet dňa {0} z {1}. Ak ste to neboli vy, kontaktujte administrátora.

    + +requiredAction.CONFIGURE_TOTP=Konfigurácia OTP +requiredAction.terms_and_conditions=Zmluvné podmienky +requiredAction.UPDATE_PASSWORD=Aktualizovať heslo +requiredAction.UPDATE_PROFILE=Aktualizovať profil +requiredAction.VERIFY_EMAIL=Overiť e-mail + +# units for link expiration timeout formatting +linkExpirationFormatter.timePeriodUnit.seconds=sekundy +linkExpirationFormatter.timePeriodUnit.seconds.1=sekunda +linkExpirationFormatter.timePeriodUnit.minutes=minuty +linkExpirationFormatter.timePeriodUnit.minutes.1=minúta +#for language which have more unit plural forms depending on the value (eg. Czech and other Slavic langs) you can override unit text for some other values like this: +#linkExpirationFormatter.timePeriodUnit.minutes.2=minuty +#linkExpirationFormatter.timePeriodUnit.minutes.3=minuty +#linkExpirationFormatter.timePeriodUnit.minutes.4=minutu +linkExpirationFormatter.timePeriodUnit.hours=hodiny +linkExpirationFormatter.timePeriodUnit.hours.1=hodina +linkExpirationFormatter.timePeriodUnit.days=dni +linkExpirationFormatter.timePeriodUnit.days.1=deň diff --git a/keycloak-themes/base/email/messages/messages_sv.properties b/keycloak-themes/base/email/messages/messages_sv.properties new file mode 100644 index 0000000..15199c1 --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_sv.properties @@ -0,0 +1,25 @@ +# encoding: utf-8 +emailVerificationSubject=Verifiera e-post +emailVerificationBody=Någon har skapat ett {2} konto med den här e-postadressen. Om det var du, klicka då på länken nedan för att verifiera din e-postadress\n\n{0}\n\nDen här länken kommer att upphöra inom {1} minuter.\n\nOm det inte var du som skapade det här kontot, ignorera i så fall det här meddelandet. +emailVerificationBodyHtml=

    Någon har skapat ett {2} konto med den här e-postadressen. Om det var du, klicka då på länken nedan för att verifiera din e-postadress

    {0}

    Den här länken kommer att upphöra inom {1} minuter.

    Om det inte var du som skapade det här kontot, ignorera i så fall det här meddelandet.

    +identityProviderLinkSubject=Länk {0} +identityProviderLinkBody=Någon vill länka ditt "{1}" konto med "{0}" kontot tillhörande användaren {2} . Om det var du, klicka då på länken nedan för att länka kontona\n\n{3}\n\nDen här länken kommer att upphöra inom {4} minuter.\n\nOm du inte vill länka kontot, ignorera i så fall det här meddelandet. Om du länkar kontona, så kan du logga in till {1} genom {0}. +identityProviderLinkBodyHtml=

    Någon vill länka ditt {1} konto med {0} kontot tillhörande användaren {2} . Om det var du, klicka då på länken nedan för att länka kontona

    {3}

    Den här länken kommer att upphöra inom {4} minuter.

    Om du inte vill länka kontot, ignorera i så fall det här meddelandet. Om du länkar kontona, så kan du logga in till {1} genom {0}.

    +passwordResetSubject=Återställ lösenord +passwordResetBody=Någon har precis bett om att ändra användaruppgifter för ditt konto {2}. Om det var du, klicka då på länken nedan för att återställa dem.\n\n{0}\n\nDen här länken och koden kommer att upphöra inom {1} minuter.\n\nOm du inte vill återställa dina kontouppgifter, ignorera i så fall det här meddelandet så kommer inget att ändras. +passwordResetBodyHtml=

    Någon har precis bett om att ändra användaruppgifter för ditt konto {2}. Om det var du, klicka då på länken nedan för att återställa dem.

    {0}

    Den här länken och koden kommer att upphöra inom {1} minuter.

    Om du inte vill återställa dina kontouppgifter, ignorera i så fall det här meddelandet så kommer inget att ändras.

    +executeActionsSubject=Uppdatera ditt konto +executeActionsBody=Din administratör har precis bett om att du skall uppdatera ditt {2} konto. Klicka på länken för att påbörja processen.\n\n{0}\n\nDen här länken kommer att upphöra inom {1} minuter.\n\nOm du är omedveten om att din administratör har bett om detta, ignorera i så fall det här meddelandet så kommer inget att ändras. +executeActionsBodyHtml=

    Din administratör har precis bett om att du skall uppdatera ditt {2} konto. Klicka på länken för att påbörja processen.

    {0}

    Den här länken kommer att upphöra inom {1} minuter.

    Om du är omedveten om att din administratör har bett om detta, ignorera i så fall det här meddelandet så kommer inget att ändras.

    +eventLoginErrorSubject=Inloggningsfel +eventLoginErrorBody=Ett misslyckat inloggningsförsök har upptäckts på ditt konto på {0} från {1}. Om det inte var du, vänligen kontakta i så fall en administratör. +eventLoginErrorBodyHtml=

    Ett misslyckat inloggningsförsök har upptäckts på ditt konto den {0} från {1}. Om det inte var du, vänligen kontakta i så fall en administratör.

    +eventRemoveTotpSubject=Ta bort OTP +eventRemoveTotpBody=OTP togs bort från ditt konto den {0} från {1}. Om det inte var du, vänligen kontakta i så fall en administratör. +eventRemoveTotpBodyHtml=

    OTP togs bort från ditt konto den {0} från {1}. Om det inte var du, vänligen kontakta i så fall en administratör.

    +eventUpdatePasswordSubject=Uppdatera lösenord +eventUpdatePasswordBody=Ditt lösenord ändrades den {0} från {1}. Om det inte var du, vänligen kontakta i så fall en administratör. +eventUpdatePasswordBodyHtml=

    Ditt lösenord ändrades den {0} från {1}. Om det inte var du, vänligen kontakta i så fall en administratör.

    +eventUpdateTotpSubject=Uppdatera OTP +eventUpdateTotpBody=OTP uppdaterades för ditt konto den {0} från {1}. Om det inte var du, vänligen kontakta i så fall en administratör. +eventUpdateTotpBodyHtml=

    OTP uppdaterades för ditt konto den {0} från {1}. Om det inte var du, vänligen kontakta i så fall en administratör.

    \ No newline at end of file diff --git a/keycloak-themes/base/email/messages/messages_tr.properties b/keycloak-themes/base/email/messages/messages_tr.properties new file mode 100644 index 0000000..a260ef1 --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_tr.properties @@ -0,0 +1,51 @@ +emailVerificationSubject=E-postay\u0131 do\u011Frula +emailVerificationBody=Birisi bu e-posta adresiyle bir {2} hesap olu\u015Fturdu. Bu sizseniz, e-posta adresinizi do\u011Frulamak i\u00E7in a\u015Fa\u011F\u0131daki ba\u011Flant\u0131ya t\u0131klay\u0131n\n\n{0}\n\nBu ba\u011Flant\u0131 {3} i\u00E7inde sona erecek.\n\nBu hesab\u0131 olu\u015Fturmad\u0131ysan\u0131z, sadece bu iletiyi yoksay\u0131n\u0131z. +emailVerificationBodyHtml=

    Birisi bu e-posta adresiyle bir {2} hesap olu\u015Fturdu. Bu sizseniz, e-posta adresinizi do\u011Frulamak i\u00E7in a\u015Fa\u011F\u0131daki ba\u011Flant\u0131y\u0131 t\u0131klay\u0131n.

    E-posta adresi do\u011Frulama adresi

    Bu ba\u011Flant\u0131n\u0131n s\u00FCresi {3} i\u00E7erisinde sona erecek.

    Bu hesab\u0131 siz olu\u015Fturmad\u0131ysan\u0131z, bu mesaj\u0131 g\u00F6z ard\u0131 edin.

    +emailTestSubject=[KEYCLOAK] - SMTP test mesaj\u0131 +emailTestBody=Bu bir test mesaj\u0131 +emailTestBodyHtml=

    Bu bir test mesaj\u0131

    +identityProviderLinkSubject=Link {0} +identityProviderLinkBody=Birisi "{1}" hesab\u0131n\u0131z\u0131 "{0}" kullan\u0131c\u0131 hesab\u0131 {2} ile ba\u011Flamak istiyor. Bu sizseniz, hesaplar\u0131 ba\u011Flamak i\u00E7in a\u015Fa\u011F\u0131daki ba\u011Flant\u0131y\u0131 t\u0131klay\u0131n:\n\n{3}\n\nBu ba\u011Flant\u0131 {5} i\u00E7inde sona erecek.\n\nHesab\u0131n\u0131z\u0131 ba\u011Flamak istemiyorsan\u0131z bu mesaj\u0131 g\u00F6z ard\u0131 edin. Hesaplar\u0131 ba\u011Flarsan\u0131z, {1} ile {0} aras\u0131nda oturum a\u00E7abilirsiniz. +identityProviderLinkBodyHtml=

    Birisi {1} hesab\u0131n\u0131z\u0131 {2} kullan\u0131c\u0131s\u0131 {0} hesab\u0131na ba\u011Flamak istiyor. Bu sizseniz, ba\u011Flant\u0131 vermek i\u00E7in a\u015Fa\u011F\u0131daki ba\u011Flant\u0131y\u0131 t\u0131klay\u0131n

    Hesap ba\u011Flant\u0131s\u0131n\u0131 onaylamak i\u00E7in ba\u011Flant\u0131

    Bu ba\u011Flant\u0131n\u0131n s\u00FCresi {5} i\u00E7erisinde sona erecek.

    Hesab\u0131 ba\u011Flamak istemiyorsan\u0131z, bu mesaj\u0131 g\u00F6z ard\u0131 edin. Hesaplar\u0131 ba\u011Flarsan\u0131z, {1} ile {0} aras\u0131nda oturum a\u00E7abilirsiniz.

    +passwordResetSubject=\u015Eifreyi s\u0131f\u0131rla +passwordResetBody=Birisi, {2} hesab\u0131n\u0131z\u0131n kimlik bilgilerini de\u011Fi\u015Ftirmeyi istedi.Bu sizseniz, s\u0131f\u0131rlamak i\u00E7in a\u015Fa\u011F\u0131daki ba\u011Flant\u0131y\u0131 t\u0131klay\u0131n.\n\n{0}\n\nBu ba\u011Flant\u0131 ve kod {3} i\u00E7inde sona erecek.\n\nFakat bilgilerinizi s\u0131f\u0131rlamak istemiyorsan\u0131z, Sadece bu mesaj\u0131 g\u00F6rmezden gelin ve hi\u00E7bir \u015Fey de\u011Fi\u015Fmeyecek. +passwordResetBodyHtml=

    Birisi, {2} hesab\u0131n\u0131z\u0131n kimlik bilgilerini de\u011Fi\u015Ftirmeyi istedi. Sizseniz, s\u0131f\u0131rlamak i\u00E7in a\u015Fa\u011F\u0131daki linke t\u0131klay\u0131n\u0131z.

    Kimlik bilgilerini s\u0131f\u0131rlamak i\u00E7in ba\u011Flant\u0131

    Bu ba\u011Flant\u0131n\u0131n s\u00FCresi {3} i\u00E7erisinde sona erecek.

    Kimlik bilgilerinizi s\u0131f\u0131rlamak istemiyorsan\u0131z, bu mesaj\u0131 g\u00F6z ard\u0131 edin.

    +executeActionsSubject=Hesab\u0131n\u0131z\u0131 G\u00FCncelleyin +executeActionsBody=Y\u00F6neticiniz a\u015Fa\u011F\u0131daki i\u015Flemleri ger\u00E7ekle\u015Ftirerek {2} hesab\u0131n\u0131z\u0131 g\u00FCncelledi: {3}. Bu i\u015Flemi ba\u015Flatmak i\u00E7in a\u015Fa\u011F\u0131daki linke t\u0131klay\u0131n.\n\n{0}\n\nBu ba\u011Flant\u0131n\u0131n s\u00FCresi {4} i\u00E7erisinde sona erecek.\n\nY\u00F6neticinizin bunu istedi\u011Finden habersizseniz, bu mesaj\u0131 g\u00F6z ard\u0131 edin ve hi\u00E7bir \u015Fey de\u011Fi\u015Fmez. +executeActionsBodyHtml=

    Y\u00F6neticiniz a\u015Fa\u011F\u0131daki i\u015Flemleri ger\u00E7ekle\u015Ftirerek {2} hesab\u0131n\u0131z\u0131 g\u00FCncelledi: {3}. Bu i\u015Flemi ba\u015Flatmak i\u00E7in a\u015Fa\u011F\u0131daki linke t\u0131klay\u0131n.

    Hesap g\u00FCncelleme ba\u011Flant\u0131s\u0131

    Bu ba\u011Flant\u0131n\u0131n s\u00FCresi {4} i\u00E7erisinde sona erecek.

    Y\u00F6neticinizin bunu istedi\u011Finden habersizseniz, bu mesaj\u0131 g\u00F6z ard\u0131 edin ve hi\u00E7bir \u015Fey de\u011Fi\u015Fmez.

    +eventLoginErrorSubject=Giri\u015F hatas\u0131 +eventLoginErrorBody={1} ''den {0} tarihinde ba\u015Far\u0131s\u0131z bir giri\u015F denemesi yap\u0131ld\u0131. Bu siz de\u011Filseniz, l\u00FCtfen y\u00F6neticiyle ileti\u015Fime ge\u00E7in. +eventLoginErrorBodyHtml=

    {1} ''den {0} tarihinde ba\u015Far\u0131s\u0131z bir giri\u015F denemesi yap\u0131ld\u0131. Bu siz de\u011Filseniz, l\u00FCtfen y\u00F6neticiyle ileti\u015Fime ge\u00E7in.

    +eventRemoveTotpSubject=OTP''yi kald\u0131r +eventRemoveTotpBody=OTP, {0} tarihinden {1} tarihinde hesab\u0131n\u0131zdan kald\u0131r\u0131ld\u0131. Bu siz de\u011Filseniz, l\u00FCtfen y\u00F6neticiyle ileti\u015Fime ge\u00E7in. +eventRemoveTotpBodyHtml=

    OTP, {0} tarihinden {1} tarihinde hesab\u0131n\u0131zdan kald\u0131r\u0131ld\u0131. Bu siz de\u011Filseniz, l\u00FCtfen y\u00F6neticiyle ileti\u015Fime ge\u00E7in.

    +eventUpdatePasswordSubject=\u015Eifreyi g\u00FCncelle +eventUpdatePasswordBody=\u015Eifreniz {0} tarihinde {0} tarihinde de\u011Fi\u015Ftirildi. Bu siz de\u011Filseniz, l\u00FCtfen y\u00F6neticiyle ileti\u015Fime ge\u00E7in. +eventUpdatePasswordBodyHtml=

    \u015Eifreniz {0} tarihinde {0} tarihinde de\u011Fi\u015Ftirildi. Bu siz de\u011Filseniz, l\u00FCtfen y\u00F6neticiyle ileti\u015Fime ge\u00E7in.

    +eventUpdateTotpSubject=OTP''yi G\u00FCncelle +eventUpdateTotpBody=OTP, {0} tarihinden {1} tarihinde hesab\u0131n\u0131z i\u00E7in g\u00FCncellendi. Bu siz de\u011Filseniz, l\u00FCtfen y\u00F6neticiyle ileti\u015Fime ge\u00E7in. +eventUpdateTotpBodyHtml=

    OTP, {0} tarihinden {1} tarihinde hesab\u0131n\u0131z i\u00E7in g\u00FCncellendi. Bu siz de\u011Filseniz, l\u00FCtfen y\u00F6neticiyle ileti\u015Fime ge\u00E7in.

    + +requiredAction.CONFIGURE_TOTP=OTP''yi yap\u0131land\u0131r +requiredAction.terms_and_conditions=\u015Eartlar ve Ko\u015Fullar +requiredAction.UPDATE_PASSWORD=\u015Eifre G\u00FCncelleme +requiredAction.UPDATE_PROFILE=Profilleri g\u00FCncelle +requiredAction.VERIFY_EMAIL=E-mail do\u011Frula + +# units for link expiration timeout formatting +linkExpirationFormatter.timePeriodUnit.seconds=saniye +linkExpirationFormatter.timePeriodUnit.seconds.1=saniye +linkExpirationFormatter.timePeriodUnit.minutes=dakika +linkExpirationFormatter.timePeriodUnit.minutes.1=dakika +#for language which have more unit plural forms depending on the value (eg. Czech and other Slavic langs) you can override unit text for some other values like this: +#linkExpirationFormatter.timePeriodUnit.minutes.2=minuty +#linkExpirationFormatter.timePeriodUnit.minutes.3=minuty +#linkExpirationFormatter.timePeriodUnit.minutes.4=minuty +linkExpirationFormatter.timePeriodUnit.hours=saat +linkExpirationFormatter.timePeriodUnit.hours.1=saat +linkExpirationFormatter.timePeriodUnit.days=g\u00FCn +linkExpirationFormatter.timePeriodUnit.days.1=g\u00FCn + +emailVerificationBodyCode=L\u00FCtfen a\u015Fa\u011F\u0131daki kodu girerek e-posta adresinizi do\u011Frulay\u0131n.\n\n{0}\n\n. +emailVerificationBodyCodeHtml=

    L\u00FCtfen a\u015Fa\u011F\u0131daki kodu girerek e-posta adresinizi do\u011Frulay\u0131n.

    {0}

    + diff --git a/keycloak-themes/base/email/messages/messages_zh_CN.properties b/keycloak-themes/base/email/messages/messages_zh_CN.properties new file mode 100644 index 0000000..42f59f8 --- /dev/null +++ b/keycloak-themes/base/email/messages/messages_zh_CN.properties @@ -0,0 +1,25 @@ +# encoding: utf-8 +emailVerificationSubject=验证电子邮件 +emailVerificationBody=用户使用当前电子邮件注册 {2} 账户。如是本人操作,请点击以下链接完成邮箱验证\n\n{0}\n\n这个链接会在 {1} 分钟后过期.\n\n如果您没有注册用户,请忽略这条消息。 +emailVerificationBodyHtml=

    用户使用当前电子邮件注册 {2} 账户。如是本人操作,请点击以下链接完成邮箱验证

    {0}

    这个链接会在 {1} 分钟后过期.

    如果您没有注册用户,请忽略这条消息。

    +identityProviderLinkSubject=链接 {0} +identityProviderLinkBody=有用户想要将账户 "{1}" 与用户{2}的账户"{0}" 做链接 . 如果是本人操作,请点击以下链接完成链接请求\n\n{3}\n\n这个链接会在 {4} 分钟后过期.\n\n如非本人操作,请忽略这条消息。如果您链接账户,您将可以通过{0}登录账户 {1}. +identityProviderLinkBodyHtml=

    有用户想要将账户 {1} 与用户{2} 的账户{0} 做链接 . 如果是本人操作,请点击以下链接完成链接请求

    {3}

    这个链接会在 {4} 分钟后过期。

    如非本人操作,请忽略这条消息。如果您链接账户,您将可以通过{0}登录账户 {1}.

    +passwordResetSubject=重置密码 +passwordResetBody=有用户要求修改账户 {2} 的密码.如是本人操作,请点击下面链接进行重置.\n\n{0}\n\n这个链接会在 {1} 分钟后过期.\n\n如果您不想重置您的密码,请忽略这条消息,密码不会改变。 +passwordResetBodyHtml=

    有用户要求修改账户 {2} 的密码如是本人操作,请点击下面链接进行重置.

    {0}

    这个链接会在 {1} 分钟后过期

    如果您不想重置您的密码,请忽略这条消息,密码不会改变。

    +executeActionsSubject=更新您的账户 +executeActionsBody=您的管理员要求您更新账户 {2}. 点击以下链接开始更新\n\n{0}\n\n这个链接会在 {1} 分钟后失效.\n\n如果您不知道管理员要求更新账户信息,请忽略这条消息。账户信息不会修改。 +executeActionsBodyHtml=

    您的管理员要求您更新账户{2}. 点击以下链接开始更新.

    {0}

    这个链接会在 {1} 分钟后失效.

    如果您不知道管理员要求更新账户信息,请忽略这条消息。账户信息不会修改。

    +eventLoginErrorSubject=登录错误 +eventLoginErrorBody=在{0} 由 {1}使用您的账户登录失败. 如果这不是您本人操作,请联系管理员. +eventLoginErrorBodyHtml=

    在{0} 由 {1}使用您的账户登录失败. 如果这不是您本人操作,请联系管理员.

    +eventRemoveTotpSubject=删除 OTP +eventRemoveTotpBody=OTP在 {0} 由{1} 从您的账户中删除.如果这不是您本人操作,请联系管理员 +eventRemoveTotpBodyHtml=

    OTP在 {0} 由{1} 从您的账户中删除.如果这不是您本人操作,请联系管理员。

    +eventUpdatePasswordSubject=更新密码 +eventUpdatePasswordBody=您的密码在{0} 由 {1}更改. 如非本人操作,请联系管理员 +eventUpdatePasswordBodyHtml=

    您的密码在{0} 由 {1}更改. 如非本人操作,请联系管理员

    +eventUpdateTotpSubject=更新 OTP +eventUpdateTotpBody=您账户的OTP 配置在{0} 由 {1}更改. 如非本人操作,请联系管理员。 +eventUpdateTotpBodyHtml=

    您账户的OTP 配置在{0} 由 {1}更改. 如非本人操作,请联系管理员。

    diff --git a/keycloak-themes/base/email/text/email-test.ftl b/keycloak-themes/base/email/text/email-test.ftl new file mode 100644 index 0000000..f1becdd --- /dev/null +++ b/keycloak-themes/base/email/text/email-test.ftl @@ -0,0 +1,2 @@ +<#ftl output_format="plainText"> +${msg("emailTestBody", realmName)} \ No newline at end of file diff --git a/keycloak-themes/base/email/text/email-verification-with-code.ftl b/keycloak-themes/base/email/text/email-verification-with-code.ftl new file mode 100644 index 0000000..4ffb7d8 --- /dev/null +++ b/keycloak-themes/base/email/text/email-verification-with-code.ftl @@ -0,0 +1,2 @@ +<#ftl output_format="plainText"> +${msg("emailVerificationBodyCode",code)} \ No newline at end of file diff --git a/keycloak-themes/base/email/text/email-verification.ftl b/keycloak-themes/base/email/text/email-verification.ftl new file mode 100644 index 0000000..9e39696 --- /dev/null +++ b/keycloak-themes/base/email/text/email-verification.ftl @@ -0,0 +1,2 @@ +<#ftl output_format="plainText"> +${msg("emailVerificationBody",link, linkExpiration, realmName, linkExpirationFormatter(linkExpiration))} \ No newline at end of file diff --git a/keycloak-themes/base/email/text/event-login_error.ftl b/keycloak-themes/base/email/text/event-login_error.ftl new file mode 100644 index 0000000..bfb4036 --- /dev/null +++ b/keycloak-themes/base/email/text/event-login_error.ftl @@ -0,0 +1,2 @@ +<#ftl output_format="plainText"> +${msg("eventLoginErrorBody",event.date,event.ipAddress)} \ No newline at end of file diff --git a/keycloak-themes/base/email/text/event-remove_totp.ftl b/keycloak-themes/base/email/text/event-remove_totp.ftl new file mode 100644 index 0000000..a7e3b68 --- /dev/null +++ b/keycloak-themes/base/email/text/event-remove_totp.ftl @@ -0,0 +1,2 @@ +<#ftl output_format="plainText"> +${msg("eventRemoveTotpBody",event.date, event.ipAddress)} \ No newline at end of file diff --git a/keycloak-themes/base/email/text/event-update_password.ftl b/keycloak-themes/base/email/text/event-update_password.ftl new file mode 100644 index 0000000..2ec7ea0 --- /dev/null +++ b/keycloak-themes/base/email/text/event-update_password.ftl @@ -0,0 +1,2 @@ +<#ftl output_format="plainText"> +${msg("eventUpdatePasswordBody",event.date, event.ipAddress)} \ No newline at end of file diff --git a/keycloak-themes/base/email/text/event-update_totp.ftl b/keycloak-themes/base/email/text/event-update_totp.ftl new file mode 100644 index 0000000..14778b5 --- /dev/null +++ b/keycloak-themes/base/email/text/event-update_totp.ftl @@ -0,0 +1,2 @@ +<#ftl output_format="plainText"> +${msg("eventUpdateTotpBody",event.date, event.ipAddress)} \ No newline at end of file diff --git a/keycloak-themes/base/email/text/executeActions.ftl b/keycloak-themes/base/email/text/executeActions.ftl new file mode 100644 index 0000000..6610c7a --- /dev/null +++ b/keycloak-themes/base/email/text/executeActions.ftl @@ -0,0 +1,4 @@ +<#ftl output_format="plainText"> +<#assign requiredActionsText><#if requiredActions??><#list requiredActions><#items as reqActionItem>${msg("requiredAction.${reqActionItem}")}<#sep>, <#else> + +${msg("executeActionsBody",link, linkExpiration, realmName, requiredActionsText, linkExpirationFormatter(linkExpiration))} \ No newline at end of file diff --git a/keycloak-themes/base/email/text/identity-provider-link.ftl b/keycloak-themes/base/email/text/identity-provider-link.ftl new file mode 100644 index 0000000..ed9d246 --- /dev/null +++ b/keycloak-themes/base/email/text/identity-provider-link.ftl @@ -0,0 +1,2 @@ +<#ftl output_format="plainText"> +${msg("identityProviderLinkBody", identityProviderAlias, realmName, identityProviderContext.username, link, linkExpiration, linkExpirationFormatter(linkExpiration))} \ No newline at end of file diff --git a/keycloak-themes/base/email/text/password-reset.ftl b/keycloak-themes/base/email/text/password-reset.ftl new file mode 100644 index 0000000..27405c9 --- /dev/null +++ b/keycloak-themes/base/email/text/password-reset.ftl @@ -0,0 +1,2 @@ +<#ftl output_format="plainText"> +${msg("passwordResetBody",link, linkExpiration, realmName, linkExpirationFormatter(linkExpiration))} \ No newline at end of file diff --git a/keycloak-themes/base/email/theme.properties b/keycloak-themes/base/email/theme.properties new file mode 100644 index 0000000..d8b7627 --- /dev/null +++ b/keycloak-themes/base/email/theme.properties @@ -0,0 +1 @@ +locales=ca,cs,da,de,en,es,fr,fi,hu,it,ja,lt,nl,no,pl,pt-BR,ru,sk,sv,tr,zh-CN diff --git a/keycloak-themes/base/login/cli_splash.ftl b/keycloak-themes/base/login/cli_splash.ftl new file mode 100644 index 0000000..cd9ebbb --- /dev/null +++ b/keycloak-themes/base/login/cli_splash.ftl @@ -0,0 +1,7 @@ + _ __ _ _ +| |/ /___ _ _ ___| | ___ __ _| | __ +| ' // _ \ | | |/ __| |/ _ \ / _` | |/ / +| . \ __/ |_| | (__| | (_) | (_| | < +|_|\_\___|\__, |\___|_|\___/ \__,_|_|\_\ + |___/ + diff --git a/keycloak-themes/base/login/code.ftl b/keycloak-themes/base/login/code.ftl new file mode 100644 index 0000000..6830fc4 --- /dev/null +++ b/keycloak-themes/base/login/code.ftl @@ -0,0 +1,19 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout; section> + <#if section = "header"> + <#if code.success> + ${msg("codeSuccessTitle")} + <#else> + ${msg("codeErrorTitle", code.error)} + + <#elseif section = "form"> +
    + <#if code.success> +

    ${msg("copyCodeInstruction")}

    + + <#else> +

    ${code.error}

    + +
    + + diff --git a/keycloak-themes/base/login/delete-account-confirm.ftl b/keycloak-themes/base/login/delete-account-confirm.ftl new file mode 100644 index 0000000..6aa93f0 --- /dev/null +++ b/keycloak-themes/base/login/delete-account-confirm.ftl @@ -0,0 +1,33 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout; section> + + <#if section = "header"> + ${msg("deleteAccountConfirm")} + + <#elseif section = "form"> + +
    + +
    + + ${msg("irreversibleAction")} +
    + +

    ${msg("deletingImplies")}

    +
      +
    • ${msg("loggingOutImmediately")}
    • +
    • ${msg("errasingData")}
    • +
    + + + +
    + + <#if triggered_from_aia> + + +
    +
    + + + \ No newline at end of file diff --git a/keycloak-themes/base/login/error.ftl b/keycloak-themes/base/login/error.ftl new file mode 100644 index 0000000..112ded3 --- /dev/null +++ b/keycloak-themes/base/login/error.ftl @@ -0,0 +1,16 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout displayMessage=false; section> + <#if section = "header"> + ${kcSanitize(msg("errorTitle"))?no_esc} + <#elseif section = "form"> +
    +

    ${kcSanitize(message.summary)?no_esc}

    + <#if skipLink??> + <#else> + <#if client?? && client.baseUrl?has_content> +

    ${kcSanitize(msg("backToApplication"))?no_esc}

    + + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/login/frontchannel-logout.ftl b/keycloak-themes/base/login/frontchannel-logout.ftl new file mode 100644 index 0000000..3de7d25 --- /dev/null +++ b/keycloak-themes/base/login/frontchannel-logout.ftl @@ -0,0 +1,30 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout; section> + <#if section = "header"> + + ${msg("frontchannel-logout.title")} + <#elseif section = "form"> +

    ${msg("frontchannel-logout.message")}

    +
      + <#list logout.clients as client> +
    • + ${client.name} + +
    • + +
    + <#if logout.logoutRedirectUri?has_content> + + ${msg("doContinue")} + + + diff --git a/keycloak-themes/base/login/idp-review-user-profile.ftl b/keycloak-themes/base/login/idp-review-user-profile.ftl new file mode 100644 index 0000000..1b70aec --- /dev/null +++ b/keycloak-themes/base/login/idp-review-user-profile.ftl @@ -0,0 +1,23 @@ +<#import "template.ftl" as layout> +<#import "user-profile-commons.ftl" as userProfileCommons> +<@layout.registrationLayout displayMessage=messagesPerField.exists('global') displayRequiredFields=true; section> + <#if section = "header"> + ${msg("loginIdpReviewProfileTitle")} + <#elseif section = "form"> +
    + + <@userProfileCommons.userProfileFormFields/> + +
    +
    +
    +
    +
    + +
    + +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/login/info.ftl b/keycloak-themes/base/login/info.ftl new file mode 100644 index 0000000..8da0cb7 --- /dev/null +++ b/keycloak-themes/base/login/info.ftl @@ -0,0 +1,24 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout displayMessage=false; section> + <#if section = "header"> + <#if messageHeader??> + ${messageHeader} + <#else> + ${message.summary} + + <#elseif section = "form"> +
    +

    ${message.summary}<#if requiredActions??><#list requiredActions>: <#items as reqActionItem>${msg("requiredAction.${reqActionItem}")}<#sep>, <#else>

    + <#if skipLink??> + <#else> + <#if pageRedirectUri?has_content> +

    ${kcSanitize(msg("backToApplication"))?no_esc}

    + <#elseif actionUri?has_content> +

    ${kcSanitize(msg("proceedWithAction"))?no_esc}

    + <#elseif (client.baseUrl)?has_content> +

    ${kcSanitize(msg("backToApplication"))?no_esc}

    + + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/login/login-config-totp-text.ftl b/keycloak-themes/base/login/login-config-totp-text.ftl new file mode 100644 index 0000000..d609182 --- /dev/null +++ b/keycloak-themes/base/login/login-config-totp-text.ftl @@ -0,0 +1,31 @@ +<#ftl output_format="plainText"> +${msg("loginTotpIntro")} + +${msg("loginTotpStep1")} + +<#list totp.policy.supportedApplications as app> +* ${app} + + +${msg("loginTotpManualStep2")} + + ${totp.totpSecretEncoded} + + +${msg("loginTotpManualStep3")} + +- ${msg("loginTotpType")}: ${msg("loginTotp." + totp.policy.type)} +- ${msg("loginTotpAlgorithm")}: ${totp.policy.getAlgorithmKey()} +- ${msg("loginTotpDigits")}: ${totp.policy.digits} +<#if totp.policy.type = "totp"> +- ${msg("loginTotpInterval")}: ${totp.policy.period} + +<#elseif totp.policy.type = "hotp"> +- ${msg("loginTotpCounter")}: ${totp.policy.initialCounter} + + + +Enter in your one time password so we can verify you have installed it correctly. + + + diff --git a/keycloak-themes/base/login/login-config-totp.ftl b/keycloak-themes/base/login/login-config-totp.ftl new file mode 100644 index 0000000..c82948d --- /dev/null +++ b/keycloak-themes/base/login/login-config-totp.ftl @@ -0,0 +1,108 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout displayRequiredFields=false displayMessage=!messagesPerField.existsError('totp','userLabel'); section> + + <#if section = "header"> + ${msg("loginTotpTitle")} + <#elseif section = "form"> +
      +
    1. +

      ${msg("loginTotpStep1")}

      + +
        + <#list totp.policy.supportedApplications as app> +
      • ${app}
      • + +
      +
    2. + + <#if mode?? && mode = "manual"> +
    3. +

      ${msg("loginTotpManualStep2")}

      +

      ${totp.totpSecretEncoded}

      +

      ${msg("loginTotpScanBarcode")}

      +
    4. +
    5. +

      ${msg("loginTotpManualStep3")}

      +

      +

        +
      • ${msg("loginTotpType")}: ${msg("loginTotp." + totp.policy.type)}
      • +
      • ${msg("loginTotpAlgorithm")}: ${totp.policy.getAlgorithmKey()}
      • +
      • ${msg("loginTotpDigits")}: ${totp.policy.digits}
      • + <#if totp.policy.type = "totp"> +
      • ${msg("loginTotpInterval")}: ${totp.policy.period}
      • + <#elseif totp.policy.type = "hotp"> +
      • ${msg("loginTotpCounter")}: ${totp.policy.initialCounter}
      • + +
      +

      +
    6. + <#else> +
    7. +

      ${msg("loginTotpStep2")}

      + Figure: Barcode
      +

      ${msg("loginTotpUnableToScan")}

      +
    8. + +
    9. +

      ${msg("loginTotpStep3")}

      +

      ${msg("loginTotpStep3DeviceName")}

      +
    10. +
    + +
    +
    +
    + * +
    +
    + + + <#if messagesPerField.existsError('totp')> + + ${kcSanitize(messagesPerField.get('totp'))?no_esc} + + + +
    + + <#if mode??> +
    + +
    +
    + <#if totp.otpCredentials?size gte 1>* +
    + +
    + + + <#if messagesPerField.existsError('userLabel')> + + ${kcSanitize(messagesPerField.get('userLabel'))?no_esc} + + +
    +
    + + <#if isAppInitiatedAction??> + + + <#else> + + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/login/login-idp-link-confirm.ftl b/keycloak-themes/base/login/login-idp-link-confirm.ftl new file mode 100644 index 0000000..c3537c5 --- /dev/null +++ b/keycloak-themes/base/login/login-idp-link-confirm.ftl @@ -0,0 +1,13 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout; section> + <#if section = "header"> + ${msg("confirmLinkIdpTitle")} + <#elseif section = "form"> +
    +
    + + +
    +
    + + diff --git a/keycloak-themes/base/login/login-idp-link-email.ftl b/keycloak-themes/base/login/login-idp-link-email.ftl new file mode 100644 index 0000000..0020178 --- /dev/null +++ b/keycloak-themes/base/login/login-idp-link-email.ftl @@ -0,0 +1,16 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout; section> + <#if section = "header"> + ${msg("emailLinkIdpTitle", idpDisplayName)} + <#elseif section = "form"> +

    + ${msg("emailLinkIdp1", idpDisplayName, brokerContext.username, realm.displayName)} +

    +

    + ${msg("emailLinkIdp2")} ${msg("doClickHere")} ${msg("emailLinkIdp3")} +

    +

    + ${msg("emailLinkIdp4")} ${msg("doClickHere")} ${msg("emailLinkIdp5")} +

    + + \ No newline at end of file diff --git a/keycloak-themes/base/login/login-oauth-grant.ftl b/keycloak-themes/base/login/login-oauth-grant.ftl new file mode 100644 index 0000000..d5cfc4a --- /dev/null +++ b/keycloak-themes/base/login/login-oauth-grant.ftl @@ -0,0 +1,68 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout bodyClass="oauth"; section> + <#if section = "header"> + <#if client.attributes.logoUri??> + + +

    + <#if client.name?has_content> + ${msg("oauthGrantTitle",advancedMsg(client.name))} + <#else> + ${msg("oauthGrantTitle",client.clientId)} + +

    + <#elseif section = "form"> +
    +

    ${msg("oauthGrantRequest")}

    +
      + <#if oauth.clientScopesRequested??> + <#list oauth.clientScopesRequested as clientScope> +
    • + <#if !clientScope.dynamicScopeParameter??> + ${advancedMsg(clientScope.consentScreenText)} + <#else> + ${advancedMsg(clientScope.consentScreenText)}: ${clientScope.dynamicScopeParameter} + + +
    • + + +
    + <#if client.attributes.policyUri?? || client.attributes.tosUri??> +

    + <#if client.name?has_content> + ${msg("oauthGrantInformation",advancedMsg(client.name))} + <#else> + ${msg("oauthGrantInformation",client.clientId)} + + <#if client.attributes.tosUri??> + ${msg("oauthGrantReview")} + ${msg("oauthGrantTos")} + + <#if client.attributes.policyUri??> + ${msg("oauthGrantReview")} + ${msg("oauthGrantPolicy")} + +

    + + +
    + +
    +
    +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    + + diff --git a/keycloak-themes/base/login/login-oauth2-device-verify-user-code.ftl b/keycloak-themes/base/login/login-oauth2-device-verify-user-code.ftl new file mode 100644 index 0000000..dfb625f --- /dev/null +++ b/keycloak-themes/base/login/login-oauth2-device-verify-user-code.ftl @@ -0,0 +1,31 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout; section> + <#if section = "header"> + ${msg("oauth2DeviceVerificationTitle")} + <#elseif section = "form"> +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/login/login-otp.ftl b/keycloak-themes/base/login/login-otp.ftl new file mode 100644 index 0000000..a43778d --- /dev/null +++ b/keycloak-themes/base/login/login-otp.ftl @@ -0,0 +1,58 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout displayMessage=!messagesPerField.existsError('totp'); section> + <#if section="header"> + ${msg("doLogIn")} + <#elseif section="form"> +
    + <#if otpLogin.userOtpCredentials?size gt 1> +
    +
    + <#list otpLogin.userOtpCredentials as otpCredential> + checked="checked"> + + +
    +
    + + +
    +
    + +
    + +
    + + + <#if messagesPerField.existsError('totp')> + + ${kcSanitize(messagesPerField.get('totp'))?no_esc} + + +
    +
    + +
    +
    +
    +
    +
    + +
    + +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/login/login-page-expired.ftl b/keycloak-themes/base/login/login-page-expired.ftl new file mode 100644 index 0000000..2b470e0 --- /dev/null +++ b/keycloak-themes/base/login/login-page-expired.ftl @@ -0,0 +1,11 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout; section> + <#if section = "header"> + ${msg("pageExpiredTitle")} + <#elseif section = "form"> +

    + ${msg("pageExpiredMsg1")} ${msg("doClickHere")} .
    + ${msg("pageExpiredMsg2")} ${msg("doClickHere")} . +

    + + diff --git a/keycloak-themes/base/login/login-password.ftl b/keycloak-themes/base/login/login-password.ftl new file mode 100644 index 0000000..e9a7211 --- /dev/null +++ b/keycloak-themes/base/login/login-password.ftl @@ -0,0 +1,43 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout displayMessage=!messagesPerField.existsError('password'); section> + <#if section = "header"> + ${msg("doLogIn")} + <#elseif section = "form"> +
    +
    +
    +
    +
    + + + <#if messagesPerField.existsError('password')> + + ${kcSanitize(messagesPerField.get('password'))?no_esc} + + +
    + +
    +
    +
    +
    + <#if realm.resetPasswordAllowed> + ${msg("doForgotPassword")} + +
    +
    + +
    + +
    +
    +
    +
    + + + diff --git a/keycloak-themes/base/login/login-recovery-authn-code-config.ftl b/keycloak-themes/base/login/login-recovery-authn-code-config.ftl new file mode 100644 index 0000000..5bd3559 --- /dev/null +++ b/keycloak-themes/base/login/login-recovery-authn-code-config.ftl @@ -0,0 +1,184 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout; section> + +<#if section = "header"> + ${msg("recovery-code-config-header")} +<#elseif section = "form"> + +
    +
    + +
    +

    + Warning alert: + ${msg("recovery-code-config-warning-title")} +

    +
    +

    ${msg("recovery-code-config-warning-message")}

    +
    +
    + +
      + <#list recoveryAuthnCodesConfigBean.generatedRecoveryAuthnCodesList as code> +
    1. ${code?counter}: ${code[0..3]}-${code[4..7]}-${code[8..]}
    2. + +
    + + +
    + + + +
    + + +
    + + +
    + +
    + + + + + <#if isAppInitiatedAction??> + + + <#else> + + +
    + + + + diff --git a/keycloak-themes/base/login/login-recovery-authn-code-input.ftl b/keycloak-themes/base/login/login-recovery-authn-code-input.ftl new file mode 100644 index 0000000..f6cad67 --- /dev/null +++ b/keycloak-themes/base/login/login-recovery-authn-code-input.ftl @@ -0,0 +1,32 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout; section> + + <#if section = "header"> + ${msg("auth-recovery-code-header")} + <#elseif section = "form"> +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    +
    +
    + +
    + +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/login/login-reset-password.ftl b/keycloak-themes/base/login/login-reset-password.ftl new file mode 100644 index 0000000..800faea --- /dev/null +++ b/keycloak-themes/base/login/login-reset-password.ftl @@ -0,0 +1,39 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout displayInfo=true displayMessage=!messagesPerField.existsError('username'); section> + <#if section = "header"> + ${msg("emailForgotTitle")} + <#elseif section = "form"> +
    +
    +
    + +
    +
    + + <#if messagesPerField.existsError('username')> + + ${kcSanitize(messagesPerField.get('username'))?no_esc} + + +
    +
    + +
    + <#elseif section = "info" > + <#if realm.duplicateEmailsAllowed> + ${msg("emailInstructionUsername")} + <#else> + ${msg("emailInstruction")} + + + diff --git a/keycloak-themes/base/login/login-update-password.ftl b/keycloak-themes/base/login/login-update-password.ftl new file mode 100644 index 0000000..b884d75 --- /dev/null +++ b/keycloak-themes/base/login/login-update-password.ftl @@ -0,0 +1,71 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout displayMessage=!messagesPerField.existsError('password','password-confirm'); section> + <#if section = "header"> + ${msg("updatePasswordTitle")} + <#elseif section = "form"> +
    + + + +
    +
    + +
    +
    + + + <#if messagesPerField.existsError('password')> + + ${kcSanitize(messagesPerField.get('password'))?no_esc} + + +
    +
    + +
    +
    + +
    +
    + + + <#if messagesPerField.existsError('password-confirm')> + + ${kcSanitize(messagesPerField.get('password-confirm'))?no_esc} + + + +
    +
    + +
    +
    +
    + <#if isAppInitiatedAction??> +
    + +
    + +
    +
    + +
    + <#if isAppInitiatedAction??> + + + <#else> + + +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/login/login-update-profile.ftl b/keycloak-themes/base/login/login-update-profile.ftl new file mode 100644 index 0000000..3a8610a --- /dev/null +++ b/keycloak-themes/base/login/login-update-profile.ftl @@ -0,0 +1,97 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout displayMessage=!messagesPerField.existsError('username','email','firstName','lastName'); section> + <#if section = "header"> + ${msg("loginProfileTitle")} + <#elseif section = "form"> +
    + <#if user.editUsernameAllowed> +
    +
    + +
    +
    + + + <#if messagesPerField.existsError('username')> + + ${kcSanitize(messagesPerField.get('username'))?no_esc} + + +
    +
    + +
    +
    + +
    +
    + + + <#if messagesPerField.existsError('email')> + + ${kcSanitize(messagesPerField.get('email'))?no_esc} + + +
    +
    + +
    +
    + +
    +
    + + + <#if messagesPerField.existsError('firstName')> + + ${kcSanitize(messagesPerField.get('firstName'))?no_esc} + + +
    +
    + +
    +
    + +
    +
    + + + <#if messagesPerField.existsError('lastName')> + + ${kcSanitize(messagesPerField.get('lastName'))?no_esc} + + +
    +
    + +
    +
    +
    +
    +
    + +
    + <#if isAppInitiatedAction??> + + + <#else> + + +
    +
    +
    + + diff --git a/keycloak-themes/base/login/login-username.ftl b/keycloak-themes/base/login/login-username.ftl new file mode 100644 index 0000000..02ced45 --- /dev/null +++ b/keycloak-themes/base/login/login-username.ftl @@ -0,0 +1,87 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout displayMessage=!messagesPerField.existsError('username') displayInfo=(realm.password && realm.registrationAllowed && !registrationDisabled??); section> + <#if section = "header"> + ${msg("loginAccountTitle")} + <#elseif section = "form"> +
    +
    + <#if realm.password> +
    + <#if !usernameHidden??> +
    + + + + + <#if messagesPerField.existsError('username')> + + ${kcSanitize(messagesPerField.get('username'))?no_esc} + + +
    + + +
    +
    + <#if realm.rememberMe && !usernameHidden??> +
    + +
    + +
    +
    + +
    + +
    +
    + +
    +
    + + <#elseif section = "info" > + <#if realm.password && realm.registrationAllowed && !registrationDisabled??> +
    + ${msg("noAccount")} ${msg("doRegister")} +
    + + <#elseif section = "socialProviders" > + <#if realm.password && social.providers??> +
    +
    +

    ${msg("identity-provider-login-label")}

    + + +
    + + + + diff --git a/keycloak-themes/base/login/login-verify-email-code-text.ftl b/keycloak-themes/base/login/login-verify-email-code-text.ftl new file mode 100644 index 0000000..87abcd7 --- /dev/null +++ b/keycloak-themes/base/login/login-verify-email-code-text.ftl @@ -0,0 +1,2 @@ +<#ftl output_format="plainText"> +${msg("console-verify-email",email, code)} \ No newline at end of file diff --git a/keycloak-themes/base/login/login-verify-email.ftl b/keycloak-themes/base/login/login-verify-email.ftl new file mode 100644 index 0000000..b47d8ca --- /dev/null +++ b/keycloak-themes/base/login/login-verify-email.ftl @@ -0,0 +1,14 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout displayInfo=true; section> + <#if section = "header"> + ${msg("emailVerifyTitle")} + <#elseif section = "form"> +

    ${msg("emailVerifyInstruction1",user.email)}

    + <#elseif section = "info"> +

    + ${msg("emailVerifyInstruction2")} +
    + ${msg("doClickHere")} ${msg("emailVerifyInstruction3")} +

    + + diff --git a/keycloak-themes/base/login/login-x509-info.ftl b/keycloak-themes/base/login/login-x509-info.ftl new file mode 100644 index 0000000..0228b06 --- /dev/null +++ b/keycloak-themes/base/login/login-x509-info.ftl @@ -0,0 +1,55 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout; section> + <#if section = "header"> + ${msg("doLogIn")} + <#elseif section = "form"> + +
    +
    + +
    + +
    + <#if x509.formData.subjectDN??> +
    + +
    + <#else> +
    + +
    + +
    + +
    + + <#if x509.formData.isUserEnabled??> +
    + +
    +
    + +
    + + +
    + +
    +
    +
    +
    +
    + +
    +
    + + <#if x509.formData.isUserEnabled??> + + +
    +
    +
    +
    + + + diff --git a/keycloak-themes/base/login/login.ftl b/keycloak-themes/base/login/login.ftl new file mode 100644 index 0000000..21f3f95 --- /dev/null +++ b/keycloak-themes/base/login/login.ftl @@ -0,0 +1,105 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout displayMessage=!messagesPerField.existsError('username','password') displayInfo=realm.password && realm.registrationAllowed && !registrationDisabled??; section> + <#if section = "header"> + ${msg("loginAccountTitle")} + <#elseif section = "form"> +
    +
    + <#if realm.password> +
    + <#if !usernameHidden??> +
    + + + + + <#if messagesPerField.existsError('username','password')> + + ${kcSanitize(messagesPerField.getFirstError('username','password'))?no_esc} + + + +
    + + +
    + + + + + <#if usernameHidden?? && messagesPerField.existsError('username','password')> + + ${kcSanitize(messagesPerField.getFirstError('username','password'))?no_esc} + + + +
    + +
    +
    + <#if realm.rememberMe && !usernameHidden??> +
    + +
    + +
    +
    + <#if realm.resetPasswordAllowed> + ${msg("doForgotPassword")} + +
    + +
    + +
    + value="${auth.selectedCredential}"/> + +
    +
    + +
    + +
    + <#elseif section = "info" > + <#if realm.password && realm.registrationAllowed && !registrationDisabled??> +
    +
    + ${msg("noAccount")} ${msg("doRegister")} +
    +
    + + <#elseif section = "socialProviders" > + <#if realm.password && social.providers??> +
    +
    +

    ${msg("identity-provider-login-label")}

    + + +
    + + + + diff --git a/keycloak-themes/base/login/logout-confirm.ftl b/keycloak-themes/base/login/logout-confirm.ftl new file mode 100644 index 0000000..6c0b4e9 --- /dev/null +++ b/keycloak-themes/base/login/logout-confirm.ftl @@ -0,0 +1,38 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout; section> + <#if section = "header"> + ${msg("logoutConfirmTitle")} + <#elseif section = "form"> +
    +

    ${msg("logoutConfirmHeader")}

    + +
    + +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + +
    + <#if logoutConfirm.skipLink> + <#else> + <#if (client.baseUrl)?has_content> +

    ${kcSanitize(msg("backToApplication"))?no_esc}

    + + +
    + +
    +
    + + diff --git a/keycloak-themes/base/login/messages/messages_ca.properties b/keycloak-themes/base/login/messages/messages_ca.properties new file mode 100644 index 0000000..5d13328 --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_ca.properties @@ -0,0 +1,200 @@ +doLogIn=Inicia sessi\u00F3 +doRegister=Registra''t +doCancel=Cancel\u00B7lar +doSubmit=Envia +doYes=S\u00ED +doNo=No +doContinue=Continua +doAccept=Accepta +doDecline=Rebutja +doForgotPassword=Has oblidat la teva contrasenya? +doClickHere=Fes clic aqu\u00ED +doImpersonate=Personifica +kerberosNotConfigured=Kerberos no configurat +kerberosNotConfiguredTitle=Kerberos no configurat +bypassKerberosDetail=O b\u00E9 no est\u00E0s identificat mitjan\u00E7ant Kerberos o el teu navegador no est\u00E0 configurat per identificar-se mitjan\u00E7ant Kerberos. Si us plau fes clic per identificar-te per un altre mitj\u00E0. +kerberosNotSetUp=Kerberos no est\u00E0 configurat. No pots identificar-te. +registerWithTitle=Registra''t amb {0} +registerWithTitleHtml={0} +loginTitle=Inicia sessi\u00F3 a {0} +loginTitleHtml={0} +impersonateTitle={0}\u00A0Personifica Usuari +impersonateTitleHtml={0} Personifica Usuari +realmChoice=Domini +unknownUser=Usuari desconegut +loginTotpTitle=Configura la teva aplicaci\u00F3 d''identificaci\u00F3 m\u00F2bil +loginProfileTitle=Actualitza la informaci\u00F3 del teu compte +loginTimeout=Has trigat massa a identificar-te. Inicia de nou la identificaci\u00F3. +oauthGrantTitle=Concessi\u00F3 OAuth +oauthGrantTitleHtml={0} +errorTitle=Ho sentim... +errorTitleHtml=Ho sentim... +emailVerifyTitle=Verificaci\u00F3 de l''email +emailForgotTitle=Has oblidat la teva contrasenya? +updatePasswordTitle=Modificaci\u00F3 de contrasenya +codeSuccessTitle=Codi d''\u00E8xit +codeErrorTitle=Codi d''error: {0} + +termsTitle=Termes i Condicions +termsTitleHtml=Termes i Condicions +termsText=

    Termes i condicions a definir

    + +recaptchaFailed=Reconeixement de text inv\u00E0lid +recaptchaNotConfigured=El reconeixement de text \u00E9s obligatori per\u00F2 no est\u00E0 configurat +consentDenied=Consentiment rebutjat. + +noAccount=Usuari nou? +username=Usuari +usernameOrEmail=Usuari o email +firstName=Nom +givenName=Nom de pila +fullName=Nom complet +lastName=Cognoms +familyName=Cognoms +email=Email +password=Contrasenya +passwordConfirm=Confirma la contrasenya +passwordNew=Nova contrasenya +passwordNewConfirm=Confirma la nova contrasenya +rememberMe=Seguir connectat +authenticatorCode=Codi d''identificaci\u00F3 +address=Adre\u00E7a +street=Carrer +locality=Ciutat o Municipi +region=Estat, Prov\u00EDncia, o Regi\u00F3 +postal_code=Codi Postal +country=Pa\u00EDs +emailVerified=Email verificat +gssDelegationCredential=GSS Delegation Credential + +loginTotpStep1=Instal\u00B7la FreeOTP o Google Authenticator al teu tel\u00E8fon m\u00F2bil. Les dues aplicacions estan disponibles a Google Play i en l''App Store d''Apple. +loginTotpStep2=Obre l''aplicaci\u00F3 i escaneja el codi o introdueix la clau. +loginTotpStep3=Introdueix el codi \u00FAnic que et mostra l''aplicaci\u00F3 d''autenticaci\u00F3 i fes clic a Envia per finalitzar la configuraci\u00F3 +loginOtpOneTime=Codi d''un sol \u00FAs + +oauthGrantRequest=Vols permetre aquests privilegis d''acc\u00E9s? +inResource=a + +emailVerifyInstruction1=T''hem enviat un email amb instruccions per verificar el teu email. +emailVerifyInstruction2=No has rebut un codi de verificaci\u00F3 al teu email? +emailVerifyInstruction3=per reenviar l''email. + +backToLogin=« Torna a la identificaci\u00F3 + +emailInstruction=Indica el teu usuari o email i t''enviarem instruccions indicant com generar una nova contrasenya. + +copyCodeInstruction=Si us plau, copia i enganxa aquest codi a la teva aplicaci\u00F3: + +personalInfo=Informaci\u00F3 personal: +role_admin=Admin +role_realm-admin=Administrador del domini +role_create-realm=Crear domini +role_create-client=Crear client +role_view-realm=Veure domini +role_view-users=Veure usuaris +role_view-applications=Veure aplicacions +role_view-clients=Veure clients +role_view-events=Veure events +role_view-identity-providers=Veure prove\u00EFdors d''identitat +role_manage-realm=Gestionar domini +role_manage-users=Gestionar usuaris +role_manage-applications=Gestionar aplicacions +role_manage-identity-providers=Gestionar prove\u00EFdors d''identitat +role_manage-clients=Gestionar clients +role_manage-events=Gestionar events +role_view-profile=Veure perfil +role_manage-account=Gestionar compte +role_read-token=Llegir token +role_offline-access=Acc\u00E9s sense connexi\u00F3 +client_account=Compte +client_security-admin-console=Consola d''Administraci\u00F3 de Seguretat +client_realm-management=Gesti\u00F3 del domini +client_broker=Broker + +invalidUserMessage=Usuari o contrasenya incorrectes. +invalidEmailMessage=Email no v\u00E0lid +accountDisabledMessage=El compte est\u00E0 desactivat, contacta amb l''administrador. +accountTemporarilyDisabledMessage=El compte est\u00E0 temporalment desactivat, contacta amb l''administrador o intenta-ho de nou m\u00E9s tard. +expiredCodeMessage=S''ha esgotat el temps m\u00E0xim per a la identificaci\u00F3. Si us plau identifica''t de nou. + +missingFirstNameMessage=Si us plau indica el teu nom. +missingLastNameMessage=Si us plau indica els teus cognoms. +missingEmailMessage=Si us plau indica el teu email. +missingUsernameMessage=Si us plau indica el teu usuari. +missingPasswordMessage=Si us plau indica la teva contrasenya. +missingTotpMessage=Si us plau indica el teu codi d''autenticaci\u00F3 +notMatchPasswordMessage=Les contrasenyes no coincideixen. + +invalidPasswordExistingMessage=La contrasenya actual no \u00E9s correcta. +invalidPasswordConfirmMessage=La confirmaci\u00F3 de contrasenya no coincideix. +invalidTotpMessage=El codi d''autenticaci\u00F3 no \u00E9s v\u00E0lid. + +usernameExistsMessage=El nom d''usuari ja existeix +emailExistsMessage=L''email ja existeix + +federatedIdentityEmailExistsMessage=Ja existeix un usuari amb aquest email. Si us plau accedeix a la gesti\u00F3 del teu compte per enlla\u00E7ar-lo. +federatedIdentityUsernameExistsMessage=Ja existeix un usuari amb aquest nom d''usuari. Si us plau accedeix a la gesti\u00F3 del teu compte per enlla\u00E7ar-lo. + +configureTotpMessage=Has de configurar l''aplicaci\u00F3 m\u00F2bil 'd'identificaci\u00F3 per activar el teu compte. +updateProfileMessage=Has d''actualitzar el teu perfil d''usuari per activar el teu compte. +updatePasswordMessage=Has de canviar la contrasenya per activar el teu compte. +verifyEmailMessage=Has de verificar el teu email per activar el teu compte. + +emailSentMessage=En breu hauries de rebre un missatge amb m\u00E9s instruccions +emailSendErrorMessage=Ha fallat l''enviament de l''email, si us plau intenta-ho de nou m\u00E9s tard. + +accountUpdatedMessage=El teu compte s''ha actualitzat. +accountPasswordUpdatedMessage=La contrasenya s''ha actualitzat. + +noAccessMessage=Sense acc\u00E9s + +invalidPasswordMinLengthMessage=Contrasenya incorrecta: longitud m\u00EDnima {0}. +invalidPasswordMinDigitsMessage=Contrasenya incorrecta: ha de contenir almenys {0} car\u00E0cters num\u00E8rics. +invalidPasswordMinLowerCaseCharsMessage=Contrasenya incorrecta: ha de contenir almenys {0} lletres min\u00FAscules. +invalidPasswordMinUpperCaseCharsMessage=Contrasenya incorrecta: ha de contenir almenys {0} lletres maj\u00FAscules. +invalidPasswordMinSpecialCharsMessage=Contrasenya incorrecta: ha de contenir almenys {0} car\u00E0cters especials. +invalidPasswordNotUsernameMessage=Contrasenya incorrecta: no pot ser igual al nom d''usuari. +invalidPasswordRegexPatternMessage=Contrasenya incorrecta: no compleix l''expressi\u00F3 regular. +invalidPasswordHistoryMessage=Contrasenya incorrecta: no pot ser igual a cap de les \u00FAltimes {0} contrasenyes. + +failedToProcessResponseMessage=Fallada en processar la resposta +httpsRequiredMessage=HTTPS obligatori +realmNotEnabledMessage=El domini no est\u00E0 activat +invalidRequestMessage=Petici\u00F3 incorrecta +failedLogout=Ha fallat la desconnexi\u00F3. +unknownLoginRequesterMessage=Sol\u00B7licitant d''identificaci\u00F3 desconegut +loginRequesterNotEnabledMessage=El sol\u00B7licitant d''inici de sessi\u00F3 est\u00E0 desactivat +bearerOnlyMessage=Les aplicacions Bearer-only no poden iniciar sessi\u00F3 des del navegador. +directGrantsOnlyMessage=Els clients de tipus Direct-grants-only no poden iniciar sessi\u00F3 des del navegador. +invalidRedirectUriMessage=L''URI de redirecci\u00F3 no \u00E9s correcta +unsupportedNameIdFormatMessage=NameIDFormat no suportat +invalidRequesterMessage=Sol\u00B7licitant no v\u00E0lid +registrationNotAllowedMessage=El registre no est\u00E0 perm\u00E8s +resetCredentialNotAllowedMessage=El reinici de les credencials no est\u00E0 perm\u00E8s + +permissionNotApprovedMessage=Perm\u00EDs no aprovat. +noRelayStateInResponseMessage=Sense estat de retransmissi\u00F3 en la resposta del prove\u00EFdor d''identitat. +identityProviderAlreadyLinkedMessage=La identitat retornada pel prove\u00EFdor d''identitat ja est\u00E0 associada a un altre usuari. +insufficientPermissionMessage=Permisos insuficients per enlla\u00E7ar identitats. +couldNotProceedWithAuthenticationRequestMessage=No s''ha pogut continuar amb la petici\u00F3 d''autenticaci\u00F3 al prove\u00EFdor d''identitat. +couldNotObtainTokenMessage=No s''ha pogut obtenir el codi del prove\u00EFdor d''identitat. +unexpectedErrorRetrievingTokenMessage=Error inesperat obtenint el token del prove\u00EFdor d''identitat +unexpectedErrorHandlingResponseMessage=Error inesperat processant la resposta del prove\u00EFdor d''identitat. +identityProviderAuthenticationFailedMessage=Ha fallat l''autenticaci\u00F3. No ha estat possible autenticar-se en el prove\u00EFdor d''identitat. +couldNotSendAuthenticationRequestMessage=No s''ha pogut enviar la petici\u00F3 d''identificaci\u00F3 al prove\u00EFdor d''identitat. +unexpectedErrorHandlingRequestMessage=Error inesperat durant la petici\u00F3 d''identificaci\u00F3 al prove\u00EFdor d''identitat. +invalidAccessCodeMessage=Codi d''acc\u00E9s no v\u00E0lid. +sessionNotActiveMessage=La sessi\u00F3 no est\u00E0 activa +invalidCodeMessage=Hi ha hagut un error, si us plau identifica''t de nou des de la teva aplicaci\u00F3. +identityProviderUnexpectedErrorMessage=Error no esperat intentant autenticar en el prove\u00EFdor d''identitat. +identityProviderNotFoundMessage=No s''ha trobat cap prove\u00EFdor d''identitat. +realmSupportsNoCredentialsMessage=El domini no suporta cap tipus de credencials. +identityProviderNotUniqueMessage=El domini suporta m\u00FAltiples prove\u00EFdors d''identitat. No s''ha pogut determinar el prove\u00EFdor d''identitat que hauria de ser utilitzat per identificar-se. +emailVerifiedMessage=El teu email ha estat verificat. + +backToApplication=« Torna a l''aplicaci\u00F3 +missingParameterMessage=Par\u00E0metres que falten: {0} +clientNotFoundMessage=Client no trobat +invalidParameterMessage=Par\u00E0metre no v\u00E0lid: {0} +alreadyLoggedIn=You are already logged in. + diff --git a/keycloak-themes/base/login/messages/messages_cs.properties b/keycloak-themes/base/login/messages/messages_cs.properties new file mode 100644 index 0000000..11a3c7e --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_cs.properties @@ -0,0 +1,423 @@ +# encoding: utf-8 +doLogIn=Přihlásit se +doRegister=Registrovat se +doCancel=Zrušit +doSubmit=Odeslat +doBack=Zpět +doYes=Ano +doNo=Ne +doContinue=Pokračovat +doIgnore=Ignorovat +doAccept=Potvrdit +doDecline=Zamítnout +doForgotPassword=Zapomenuté heslo? +doClickHere=Klikněte zde +doImpersonate=Zosobnit +doTryAgain=Zkusit znovu +doTryAnotherWay=Zkusit jiným způsobem +doConfirmDelete=Potvrdit odstranění +errorDeletingAccount=Nastala chyba při odstraňování účtu +deletingAccountForbidden=Nemáte dostatečná oprávnění k odstranění vašeho vlastního účtu, kontaktujte administrátora. +kerberosNotConfigured=Kerberos není nakonfigurován +kerberosNotConfiguredTitle=Kerberos není nakonfigurován +bypassKerberosDetail=Buď nejste přihlášeni přes Kerberos nebo váš prohlížeč není nastaven pro přihlášení Kerberos. Klepnutím na tlačítko pokračujte k přihlášení jinými způsoby +kerberosNotSetUp=Kerberos není nastaven. Nemůžete se přihlásit. +registerTitle=Registrovat +loginAccountTitle=Přihlásit k vašemu účtu +loginTitle=Přihlásit do {0} +loginTitleHtml={0} +impersonateTitle={0} Zosobnit uživatele +impersonateTitleHtml={0} Zosobnit uživatele +realmChoice=Realm +unknownUser=Neznámý uživatel +loginTotpTitle=Nastavení autentikátoru OTP +loginProfileTitle=Aktualizovat informace o účtu +loginIdpReviewProfileTitle=Aktualizovat informace o účtu +loginTimeout=Přihlašování trvalo příliš dlouho. Přihlašovací proces začíná od začátku. +oauthGrantTitle=Poskytnout přístup +oauthGrantTitleHtml={0} +errorTitle=Je nám líto ... +errorTitleHtml=Omlouváme se ... +emailVerifyTitle=Ověření e-mailu +emailForgotTitle=Zapomněli jste heslo? +updatePasswordTitle=Aktualizace hesla +codeSuccessTitle=Kód úspěchu +codeErrorTitle=Kód chyby\: {0} +displayUnsupported=Požadovaný typ zobrazení není podporovaný +browserRequired=Pro přihlášení je vyžadován prohlížeč +browserContinue=Pro dokončení přihlášení je vyžadován prohlížeč +internal=Interní +unknown=Neznámé + +termsTitle=Smluvní podmínky +termsTitleHtml=Smluvní podmínky +termsText=

    Smluvní podmínky k odsouhlasení

    +termsPlainText=Smluvní podmínky k odsouhlasení. + +recaptchaFailed=Neplatná Recaptcha +recaptchaNotConfigured=Recaptcha je vyžadována, ale není nakonfigurována +consentDenied=Souhlas byl zamítnut. + +noAccount=Nový uživatel? +username=Přihlašovací jméno +usernameOrEmail=Přihlašovací jméno nebo e-mail +firstName=Křestní jméno +givenName=Křestní jména +fullName=Celé jméno +lastName=Příjmení +familyName=Příjmení +email=E-mail +password=Heslo +passwordConfirm=Potvrdit heslo +passwordNew=Nové heslo +passwordNewConfirm=Potvrdit nové heslo +rememberMe=Pamatovat si mě +authenticatorCode=Jednorázový kód +address=Adresa +street=Ulice +locality=Město +region=Kraj +postal_code=PSČ +country=Stát +emailVerified=E-mail ověřen +website=Webová stránka +phoneNumber=Telefonní číslo +phoneNumberVerified=Telefonní číslo ověřeno +gender=Pohlaví +birthday=Datum narození +zoneinfo=Časová zóna +gssDelegationCredential=GSS Delegované Oprávnění +logoutOtherSessions=Odhlásit se z ostatních zařízení + +profileScopeConsentText=Uživatelský profil +emailScopeConsentText=E-mailová adresa +addressScopeConsentText=Adresa +phoneScopeConsentText=Telefonní číslo +offlineAccessScopeConsentText=Přístup offline +samlRoleListScopeConsentText=Moje role +rolesScopeConsentText=Uživatelské role + +restartLoginTooltip=Restart login + +loginTotpIntro=Musíte si nakonfigurovat generátor jednorázových kódů (OTP) pro přístup k účtu +loginTotpStep1=Nainstalujte do mobilu jednu z následujících aplikací +loginTotpStep2=Otevřete aplikaci a naskenujte čárový kód +loginTotpStep3=Zadejte jednorázový kód poskytnutý aplikací a klepnutím na tlačítko Odeslat dokončete nastavení +loginTotpStep3DeviceName=Zadejte název zařízení pro jednodušší správu jednorázových kódů (OTP) zařízení. +loginTotpManualStep2=Otevřete aplikaci a zadejte klíč +loginTotpManualStep3=Použijte následující hodnoty konfigurace, pokud aplikace umožňuje jejich nastavení +loginTotpUnableToScan=Nelze skenovat? +loginTotpScanBarcode=Skenovat čárový kód? +loginOtpOneTime=Jednorázový kód +loginTotpType=Typ +loginTotpAlgorithm=Algoritmus +loginTotpDigits=Číslice +loginTotpInterval=Interval +loginTotpCounter=Počítadlo +loginTotpDeviceName=Název zařízení + +loginTotp.totp=Založeno na čase +loginTotp.hotp=Založeno na počítadle + +loginChooseAuthenticator=Vyberte metodu přihlášení + +oauthGrantRequest=Poskytujete tyto přístupová oprávnění? +inResource=v + +verifyOAuth2DeviceUserCode=Zadejte kód z vašeho zařízení a klikněte na Odeslat +oauth2DeviceInvalidUserCodeMessage=Nesprávný kód, zkuste to prosím znovu. +oauth2DeviceExpiredUserCodeMessage=Platnost kódu vypršela. Vraťte se prosím do vašeho zařízení a zkuste se připojit znovu. +oauth2DeviceVerificationCompleteHeader=Úspěšné přihlášení v zařízení +oauth2DeviceVerificationCompleteMessage=Můžete zavřít toto okno prohlížeče a vrátit se do vašeho zařízení. +oauth2DeviceVerificationFailedHeader=Selhalo přihlášení v zařízení +oauth2DeviceVerificationFailedMessage=Můžete zavřít toto okno prohlížeče a vrátit se do vašeho zařízení a zkusit se znovu připojit. +oauth2DeviceConsentDeniedMessage=Připojení zařízení odmítnuto. +oauth2DeviceAuthorizationGrantDisabledMessage=Klient nemá povoleno iniciovat OAuth 2.0 Device Authorization Grant. Flow je pro klienta zakázáno. + +emailVerifyInstruction1=Byl Vám zaslán e-mail s pokyny k ověření vaší e-mailové adresy. +emailVerifyInstruction2=Nezískali jste v e-mailu ověřovací kód? +emailVerifyInstruction3=znovu odeslat e-mail. + +emailLinkIdpTitle=Odkaz {0} +emailLinkIdp1=Byl vám zaslán e-mail s pokyny k propojení {0} účtu {1} s vaším účtem {2}. +emailLinkIdp2=Nezískali jste v e-mailu ověřovací kód? +emailLinkIdp3=znovu odeslat e-mail. +emailLinkIdp4=Pokud jste již ověřili e-mail v jiném prohlížeči +emailLinkIdp5=pokračovat. + +backToLogin=« Zpět k přihlášení + +emailInstruction=Zadejte své uživatelské jméno nebo e-mailovou adresu a my vám zašleme pokyny k vytvoření nového hesla. +emailInstructionUsername=Zadejte své uživatelské jméno a my vám zašleme pokyny k vytvoření nového hesla. + +copyCodeInstruction=Zkopírujte tento kód a vložte jej do své aplikace: + +pageExpiredTitle=Vypršela platnost stránky +pageExpiredMsg1=Pro restart procesu přihlášení +pageExpiredMsg2=Pokračovat v procesu přihlášení + +personalInfo=Osobní údaje: +role_admin=Administrátor realmu +role_realm-admin=Administrátor realmu +role_create-realm=Vytvořit realm +role_create-client=Vytvořit klienta +role_view-realm=Zobrazit realm +role_view-users=Zobrazit uživatele +role_view-applications=Zobrazit aplikace +role_view-clients=Zobrazit klienty +role_view-events=Zobrazit události +role_view-identity-providers=Zobrazit poskytovatele identity +role_manage-realm=Spravovat realm +role_manage-users=Spravovat uživatele +role_manage-applications=Spravovat aplikace +role_manage-identity-providers=Spravovat poskytovatele identity +role_manage-clients=Spravovat klienty +role_manage-events=Spravovat události +role_view-profile=Zobrazit profil +role_manage-account=Spravovat účet +role_manage-account-links=Spravovat odkazy na účet +role_read-token=Číst token +role_offline-access=Přístup offline +client_account=Účet +client_account-console=Uživatelská konzola +client_security-admin-console=Security Admin Console +client_admin-cli=Admin CLI +client_realm-management=Spravovat Realm +client_broker=Broker + +requiredFields=Vyžadované položky + +invalidUserMessage=Neplatné jméno nebo heslo. +invalidUsernameMessage=Neplatné jméno. +invalidUsernameOrEmailMessage=Neplatné jméno nebo e-mail. +invalidPasswordMessage=Neplatné heslo. +invalidEmailMessage=Neplatný e-mail. +accountDisabledMessage=Účet je neplatný, kontaktujte administrátora. +accountTemporarilyDisabledMessage=Účet je dočasně deaktivován, kontaktujte administrátora nebo zkuste později. +expiredCodeMessage=Platnost přihlášení vypršela. Přihlaste se znovu. +expiredActionMessage=Akce vypršela. Pokračujte přihlášením. +expiredActionTokenNoSessionMessage=Akce vypršela. +expiredActionTokenSessionExistsMessage=Akce vypršela. Začněte znovu + +missingFirstNameMessage=Zadejte prosím jméno. +missingLastNameMessage=Zadejte prosím příjmení. +missingEmailMessage=Zadejte prosím e-mail. +missingUsernameMessage=Zadejte prosím uživatelské jméno. +missingPasswordMessage=Zadejte prosím heslo. +missingTotpMessage=Zadejte prosím kód ověřovatele. +missingTotpDeviceNameMessage=Zadejte prosím jméno zařízení. +notMatchPasswordMessage=Hesla se neshodují. + +error-invalid-value=Nesprávná hodnota. +error-invalid-blank=Zadejte prosím hodnotu. +error-empty=Zadejte prosím hodnotu. +error-invalid-length=Délka musí být mezi {1} a {2}. +error-invalid-length-too-short=Minimální délka je {1}. +error-invalid-length-too-long=Maximální délka je {2}. +error-invalid-email=Nesprávná e-mailová adresa. +error-invalid-number=Nesprávné číslo. +error-number-out-of-range=Číslo musí být mezi {1} a {2}. +error-number-out-of-range-too-small=Minimální hodnota čísla je {1}. +error-number-out-of-range-too-big=Maximální hodnota čísla je {2}. +error-pattern-no-match=Nesprávná hodnota. +error-invalid-uri=Nesprávná URL adresa. +error-invalid-uri-scheme=Nesprávné URL schema. +error-invalid-uri-fragment=Nesprávný fragment URL. +error-user-attribute-required=Zadejte prosím tuto položku. +error-invalid-date=Nesprávné datum. +error-user-attribute-read-only=Tato položka je jen ke čtení. +error-username-invalid-character=Hodnota obsahuje nevalidní znak. +error-person-name-invalid-character=Hodnota obsahuje nevalidní znak. + +invalidPasswordExistingMessage=Neplatné existující heslo. +invalidPasswordBlacklistedMessage=Neplatné heslo: heslo je na černé listině. +invalidPasswordConfirmMessage=Potvrzení hesla se neshoduje. +invalidTotpMessage=Neplatný kód ověřování. + +usernameExistsMessage=Uživatelské jméno již existuje. +emailExistsMessage=E-mail již existuje. + +federatedIdentityExistsMessage=Uživatel s {0} {1} již existuje. Přihlaste se ke správě účtu a propojte účet. +federatedIdentityUnavailableMessage=Uživatel {0} přihlášený poskytovatelem identit {1} neexistuje. Kontaktujte prosím administrátora. + +confirmLinkIdpTitle=Účet již existuje +federatedIdentityConfirmLinkMessage=Uživatel s {0} {1} již existuje. Jak chcete pokračovat? +federatedIdentityConfirmReauthenticateMessage=Ověřte jako {0} k propojení účtu {1} +nestedFirstBrokerFlowMessage={0} uživatel {1} není propojen s žádným známým uživatelem. +confirmLinkIdpReviewProfile=Zkontrolujte profil +confirmLinkIdpContinue=Přidat do existujícího účtu + +configureTotpMessage=Chcete-li aktivovat účet, musíte nastavit službu Mobile Authenticator. +updateProfileMessage=Pro aktivaci účtu potřebujete aktualizovat svůj uživatelský profil. +updatePasswordMessage=Pro aktivaci účtu musíte provést aktualizaci hesla. +resetPasswordMessage=Je třeba změnit heslo. +verifyEmailMessage=Pro aktivaci účtu potřebujete ověřit vaši e-mailovou adresu. +linkIdpMessage=Potřebujete-li ověřit vaši e-mailovou adresu, propojte svůj účet s {0}. + +emailSentMessage=Měli byste brzy obdržet e-mail s dalšími pokyny. +emailSendErrorMessage=Nepodařilo se odeslat e-mail, zkuste to prosím později. + +accountUpdatedMessage=Váš účet byl aktualizován. +accountPasswordUpdatedMessage=Vaše heslo bylo aktualizováno. + +delegationCompleteHeader=Přihlášení úspěšné +delegationCompleteMessage=Můžete zavřít toto okno prohlížeče a vrátit se do aplikace. +delegationFailedHeader=Přihlášení selhalo +delegationFailedMessage=Můžete zavřít toto okno prohlížeče a vrátit se do aplikace a zkusit se znovu přihlásit. + +noAccessMessage=Žádný přístup + +invalidPasswordMinLengthMessage=Neplatné heslo: minimální délka {0}. +invalidPasswordMaxLengthMessage=Neplatné heslo: maximální délka {0}. +invalidPasswordMinDigitsMessage=Neplatné heslo: musí obsahovat nejméně {0} číslic. +invalidPasswordMinLowerCaseCharsMessage=Neplatné heslo: musí obsahovat minimálně {0} malé znaky. +invalidPasswordMinUpperCaseCharsMessage=Neplatné heslo: musí obsahovat nejméně {0} velká písmena. +invalidPasswordMinSpecialCharsMessage=Neplatné heslo: musí obsahovat nejméně {0} speciální znaky. +invalidPasswordNotUsernameMessage=Neplatné heslo: nesmí být totožné s uživatelským jménem. +invalidPasswordNotEmailMessage=Neplatné heslo: nesmí být totožné s e-mailovou adresou. +invalidPasswordRegexPatternMessage=Neplatné heslo: neshoduje se vzorem regulérního výrazu. +invalidPasswordHistoryMessage=Neplatné heslo: Nesmí se rovnat žádnému z posledních {0} hesel. +invalidPasswordGenericMessage=Neplatné heslo: nové heslo neodpovídá pravidlům hesla. + +failedToProcessResponseMessage=Nepodařilo se zpracovat odpověď +httpsRequiredMessage=Požadováno HTTPS +realmNotEnabledMessage=Realm není povolen +invalidRequestMessage=Neplatná žádost +successLogout=Odhlášení bylo úspěšné +failedLogout=Odhlášení se nezdařilo +unknownLoginRequesterMessage=Neznámý žadatel o přihlášení +loginRequesterNotEnabledMessage=Žadatel o přihlášení není povolen +bearerOnlyMessage=Aplikace bearer-only nemohou iniciovat přihlašování pomocí prohlížeče +standardFlowDisabledMessage=Klient nesmí iniciovat přihlašování prohlížeče s daným typem odpovědi. Standardní tok je pro klienta zakázán. +implicitFlowDisabledMessage=Klient nesmí iniciovat přihlašování prohlížeče s daným typem odpovědi. Implicitní tok je pro klienta zakázán. +invalidRedirectUriMessage=Neplatná adresa přesměrování +unsupportedNameIdFormatMessage=Nepodporovaný NameIDFormat +invalidRequesterMessage=Neplatný žadatel +registrationNotAllowedMessage=Registrace není povolena +resetCredentialNotAllowedMessage=Reset Credential není povoleno + +permissionNotApprovedMessage=Oprávnění nebylo schváleno. +noRelayStateInResponseMessage=Chybí relay state v odpovědi od poskytovatele identity. +insufficientPermissionMessage=Nedostatečná oprávnění k propojení identit. +couldNotProceedWithAuthenticationRequestMessage=Nemohu pokračovat s žádostí o ověření poskytovateli identity. +couldNotObtainTokenMessage=Nelze získat token od poskytovatele identity. +unexpectedErrorRetrievingTokenMessage=Neočekávaná chyba při načítání tokenu od poskytovatele identity. +unexpectedErrorHandlingResponseMessage=Neočekávaná chyba při zpracování odpovědi od poskytovatele identity. +identityProviderAuthenticationFailedMessage=Ověření selhalo. Nelze ověřit s poskytovatelem identity. +couldNotSendAuthenticationRequestMessage=Nelze odeslat žádost o ověření poskytovateli identity. +unexpectedErrorHandlingRequestMessage=Neočekávaná chyba při zpracování požadavku na ověření poskytovateli identity. +invalidAccessCodeMessage=Neplatný přístupový kód. +sessionNotActiveMessage=Session není aktivní. +invalidCodeMessage=Došlo k chybě, přihlaste se znovu prostřednictvím své aplikace. +cookieNotFoundMessage=Soubor cookie nenalezen. Ujistěte se prosím, že máte v prohlížeči povolené cookies. +identityProviderUnexpectedErrorMessage=Neočekávaná chyba při ověřování s poskytovatelem identity +identityProviderMissingStateMessage=V odpovědi od poskytovatele identit chybí parametr state. +identityProviderNotFoundMessage=Nelze najít poskytovatele identity s identifikátorem. +identityProviderLinkSuccess=Úspěšně jste ověřili svůj e-mail. Vraťte se prosím zpět do původního prohlížeče a pokračujte tam s přihlašovacími údaji. +staleCodeMessage=Tato stránka již není platná. Vraťte se zpět do aplikace a přihlaste se znovu +realmSupportsNoCredentialsMessage=Realm nepodporuje žádný typ pověření. +credentialSetupRequired=Není možné se přihlásit, je vyžadována konfigurace přístupových údajů. +identityProviderNotUniqueMessage=Realm podporuje více poskytovatelů identity. Nelze určit, s jakým zprostředkovatelem identity se má ověřit. +emailVerifiedMessage=Vaše e-mailová adresa byla ověřena. +staleEmailVerificationLink=Odkaz, na který jste klikli, je starý odkaz a již není platný. Možná jste již ověřili svůj e-mail? +identityProviderAlreadyLinkedMessage=Federovaná identita vrácená {0} je již propojena s jiným uživatelem. +confirmAccountLinking=Potvrďte propojení účtu {0} poskytovatele identity {1} s vaším účtem. +confirmEmailAddressVerification=Potvrďte platnost e-mailové adresy {0}. +confirmExecutionOfActions=Proveďte následující akce + +backToApplication=« Zpět na aplikaci +missingParameterMessage=Chybějící parametry \: {0} +clientNotFoundMessage=Klient nebyl nalezen. +clientDisabledMessage=Klient byl zneplatněn. +invalidParameterMessage=Neplatný parametr : {0} +alreadyLoggedIn=Jste již přihlášeni. +differentUserAuthenticated=Jste již v této relaci ověřeni jako jiný uživatel '' {0} ''. Nejdříve se odhlašte. +brokerLinkingSessionExpired=Požadované propojení účtu brokerů, ale aktuální relace již není platná. +proceedWithAction=» Klikněte zde pro pokračování + +requiredAction.CONFIGURE_TOTP=Konfigurovat OTP +requiredAction.terms_and_conditions=Smluvní podmínky +requiredAction.UPDATE_PASSWORD=Aktualizace hesla +requiredAction.UPDATE_PROFILE=Aktualizovat profil +requiredAction.VERIFY_EMAIL=Ověřit e-mail + +doX509Login=Budete přihlášeni jako\: +clientCertificate=Klientský X509 certifikát\: +noCertificate=[Žádný certifikát] + + +pageNotFound=Stránka nenalezena +internalServerError=Nastala interní chyba serveru + +console-username=Jméno: +console-password=Heslo: +console-otp=Jednorázové heslo: +console-new-password=Nové heslo: +console-confirm-password=Potvrzení hesla: +console-update-password=Je vyžadována změna hesla. +console-verify-email=Musíte ověřit svou emailovou adresu. Odeslali jsme e-mail na {0}, který obsahuje ověřovací kód. Zadejte prosím tento kód do pole níže. +console-email-code=Kód z e-mailu: + +# Openshift messages +openshift.scope.user_info=Informace o uživateli +openshift.scope.user_check-access=Informace o přístupu uživatele +openshift.scope.user_full=Plný přístup +openshift.scope.list-projects=Seznam projektů + +# SAML authentication +saml.post-form.title=Přesměrování přihlášení +saml.post-form.message=Přesměrovávám, čekejte prosím. +saml.post-form.js-disabled=JavaScript není povolený. Důrazně doporučujeme jej povolit. Pro pokračování stiskněte tlačítko níže. + +#authenticators +otp-display-name=Authenticator Application +otp-help-text=Zadejte ověřovací kód z aplikace. +password-display-name=Heslo +password-help-text=Přihlaste se pomocí hesla. +auth-username-form-display-name=Jméno +auth-username-form-help-text=Začněte přihlášení zadáním svého uživatelského jména +auth-username-password-form-display-name=Jméno a heslo +auth-username-password-form-help-text=Přihlaste se pomocí jména a hesla. + +# WebAuthn +webauthn-display-name=Bezpečnostní klíč +webauthn-help-text=Použijte k přihlášení bezpečnostní klíč. +webauthn-passwordless-display-name=Bezpečnostní klíč +webauthn-passwordless-help-text=Použijte bezpečnostní klíč k přihlášení bez hesla. +webauthn-login-title=Přihlášení bezpečnostním klíčem +webauthn-registration-title=Registrace bezpečnostního klíče +webauthn-available-authenticators=Dostupné bezpečnostní klíče +webauthn-unsupported-browser-text=WebAuthn není v tomto prohlížeči podporováno. Zkuste jiný prohlížeč nebo kontaktujte svého administrátora. +webauthn-doAuthenticate=Přihlášení bezpečnostním klíčem +webauthn-createdAt-label=Vytvořeno + +# WebAuthn Error +webauthn-error-title=Chyba bezpečnostního klíče +webauthn-error-registration=Selhala registrace vašeho bezpečnostního klíče.
    {0} +webauthn-error-api-get=Selhalo přihlášení pomocí bezpečnostního klíče.
    {0} +webauthn-error-different-user=První přihlášený uživatel není totožný s uživatelem přihlášeným pomocí bezpečnostního klíče. +webauthn-error-auth-verification=Nevalidní výsledek přihlášení pomocí bezpečnostního klíče.
    {0} +webauthn-error-register-verification=Nevalidní výsledek registrace bezpečnostního klíče.
    {0} +webauthn-error-user-not-found=Neznámý uživatel přihlášen pomocí bezpečnostního klíče. + +# Identity provider +identity-provider-redirector=Propojit s jiným poskytovatelem identit +identity-provider-login-label=Nebo se přihlaste pomocí + +finalDeletionConfirmation=Pokud svůj účet odstraníte, nemůže být obnoven. Pro zachování účtu klikněte na tlačítko Zrušit. +irreversibleAction=Tuto akci nelze vzít zpět +deleteAccountConfirm=Potvrzení odstranění účtu + +deletingImplies=Odstranění vašeho účtu znamená: +errasingData=Smazání všech vašich dat +loggingOutImmediately=Okamžité odhlášení +accountUnusable=Další použití aplikace s tímto účtem nebude možné +userDeletedSuccessfully=Uživatel úspěšně odstraněn + +access-denied=Přístup odepřen + +frontchannel-logout.title=Odhlášení +frontchannel-logout.message=Odhlašujete se z následujících aplikací +logoutConfirmTitle=Odhlašování +logoutConfirmHeader=Chcete se odhlásit? +doLogout=Odhlásit diff --git a/keycloak-themes/base/login/messages/messages_da.properties b/keycloak-themes/base/login/messages/messages_da.properties new file mode 100644 index 0000000..1eba02d --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_da.properties @@ -0,0 +1,361 @@ +# encoding: UTF-8 +doLogIn=Log ind +doRegister=Registrer +doCancel=Annuller +doSubmit=Indsend +doYes=Ja +doNo=Nej +doContinue=Fortsæt +doIgnore=Ignorer +doAccept=Accepter +doDecline=Afslå +doForgotPassword=Glemt adgangskode? +doClickHere=Klik her +doImpersonate=Efterlign +kerberosNotConfigured=Kerberos er ikke konfigureret +kerberosNotConfiguredTitle=Kerberos er ikke konfigureret +bypassKerberosDetail=Enten er du ikke logget ind via Kerberos eller også er din browser ikke sat op til Kerberos login. Tryk fortsæt for at logge ind på anden vis +kerberosNotSetUp=Kerberos er ikke sat op. Du kan ikke logge ind. +registerTitle=Registrer +loginTitle=Log ind i {0} +loginTitleHtml={0} +impersonateTitle={0} Efterlign bruger +impersonateTitleHtml={0} Efterlign bruger +realmChoice=Rige +unknownUser=Ukendt bruger +loginTotpTitle=Mobil Godkendelses Opsætning +loginProfileTitle=Opdater brugerinformationer +loginTimeout=Dit login tog for lang tid. Login processen vil nu begynde forfra. +oauthGrantTitle=Giv adgang til {0} +oauthGrantTitleHtml={0} +errorTitle=Vi beklager... +errorTitleHtml=Vi beklager ... +emailVerifyTitle=Email verificering +emailForgotTitle=Glemt din adgangskode? +updatePasswordTitle=Opdater adgangskode +codeSuccessTitle=Success kode +codeErrorTitle=Fejl kode\: {0} +displayUnsupported=Den ønskede skærmtype understøttes ikke +browserRequired=Brwoseren skal logges ind +browserContinue=Browser påkrævet for at kunne gennemføre login +browserContinuePrompt=Åben browser for at fortsætte login? [j/n]: +browserContinueAnswer=j + +termsTitle=Vilkår og betingelser +termsText=

    Vilkår og betingelser mangler at blive beskrevet

    +termsPlainText=Vilkår og betingelser mangler at blive beskrevet. + +recaptchaFailed=Ugyldig Recaptcha +recaptchaNotConfigured=Recaptcha er påkrævet, men ikke konfigureret +consentDenied=Samtykke afslået. + +noAccount=Ny bruger? +username=Brugernavn +usernameOrEmail=Brugernavn eller email +firstName=Fornavn +givenName=Fornavn +fullName=Fulde navn +lastName=Efternavn +familyName=Efternavn +email=Email +password=Adgangskode +passwordConfirm=Bekræft adgangskode +passwordNew=Ny Adgangskode +passwordNewConfirm=Bekræft ny adgangskode +rememberMe=Husk mig +authenticatorCode=Engangskode +address=Adresse +street=Vej +locality=By +region=Region +postal_code=Postnummer +country=Land +emailVerified=Email verificeret +gssDelegationCredential=GSS Delegation Credential + +profileScopeConsentText=Brugerprofil +emailScopeConsentText=Email adresse +addressScopeConsentText=Adresse +phoneScopeConsentText=Telefonnummer +offlineAccessScopeConsentText=Offline Adgang +samlRoleListScopeConsentText=Mine roller + +loginTotpIntro=Du skal opsætte en Engangskodegenerator for at kunne tilgå denne konto. +loginTotpStep1=Installer en af følgende applikationer på din mobil +loginTotpStep2=Åben applikationen og skan stregkoden +loginTotpStep3=Indtast engangskoden fra applikationen og tryk Indsend for at gennemføre opsætningen +loginTotpManualStep2=Åben applikationen og indtast nøglen +loginTotpManualStep3=Brug følgende konfigurations værdier hvis applikationen tillader det +loginTotpUnableToScan=Kan du ikke skanne? +loginTotpScanBarcode=Skan stregkode? +loginOtpOneTime=Engangskode +loginTotpType=Type +loginTotpAlgorithm=Algoritme +loginTotpDigits=Cifre +loginTotpInterval=Interval +loginTotpCounter=Tæller + +loginTotp.totp=Tidsbaseret +loginTotp.hotp=Tællerbaseret + +oauthGrantRequest=Bevilger du disse adgangs privilegier? +inResource=ind +emailVerifyInstruction1=En email med instruktioner til, hvordan du verificerer din mail adresse er blevet sendt til dig. +emailVerifyInstruction2=Har du ikke modtaget en verificerings kode i din inbox? +emailVerifyInstruction3=for at gensende emailen. + +emailLinkIdpTitle=Link {0} +emailLinkIdp1=En email med instruktioner til hvordan du linker {0} konto {1} med din {2} konto er blevet sendt til dig. +emailLinkIdp2=Har du ikke modtaget en verificerings kode i din inbox? +emailLinkIdp3=for at gensende emailen. +emailLinkIdp4=Hvis du allerede har verificeret din email i en anden browser +emailLinkIdp5=for at fortsætte. + +backToLogin=« Tilbage til log ind + +emailInstruction=Indtast dit brugernavn eller email adresse, så sender vi instruktioner til dig om hvordan du angiver en ny adgangskode. + +copyCodeInstruction=Kopier denne kode og indsæt den i din applikation: + +pageExpiredTitle=Siden er udløbet +pageExpiredMsg1=For at genstarte login processen +pageExpiredMsg2=For at fortsætte login processen + +personalInfo=Personlig information: +role_admin=Admin +role_realm-admin=Rige Admin +role_create-realm=Opret rige +role_create-client=Opret klient +role_view-realm=Se rige +role_view-users=Se brugere +role_view-applications=Se applikationer +role_view-clients=Se klienter +role_view-events=Se hændelser +role_view-identity-providers=Se identitetsudbydere +role_manage-realm=Administrer rige +role_manage-users=Administrer brugere +role_manage-applications=Administrer applikationer +role_manage-identity-providers=Administrer identitetsudbydere +role_manage-clients=Administrer klienter +role_manage-events=Administrer hændelser +role_view-profile=Se profil +role_manage-account=Administrer konto +role_manage-account-links=Administrer konto links +role_read-token=Se token +role_offline-access=Offline adgang +client_account=Konto +client_account-console=Kontokonsol +client_security-admin-console=Sikkerhefds Admin Konsol +client_admin-cli=Admin CLI +client_realm-management=Rige administration +client_broker=Broker + +invalidUserMessage=Ugyldig brugernavn eller adgangskode. +invalidEmailMessage=Ugyldig email adresse. +accountDisabledMessage=Kontoen er deaktiveret, kontakt en administrator. +accountTemporarilyDisabledMessage=Kontoen er midlertidigt deaktiveret, kontakt en administrator eller prøv igen senere. +expiredCodeMessage=Log ind tog for lang tid. Prøv igen. +expiredActionMessage=Handlingen er udløbet. Fortsæt med log ind nu. +expiredActionTokenNoSessionMessage=Handling udløbet. +expiredActionTokenSessionExistsMessage=Handlingen er udløbet. Start venligst forfra. + +missingFirstNameMessage=Angiv fornavn. +missingLastNameMessage=Angiv efternavn. +missingEmailMessage=Angiv email adressse. +missingUsernameMessage=Angiv brugernavn. +missingPasswordMessage=Angiv password. +missingTotpMessage=Angiv autentificerings kode. +notMatchPasswordMessage=Passwords er ikke ens. + +invalidPasswordExistingMessage=Ugyldig eksisterende adgangskode. +invalidPasswordBlacklistedMessage=Ugyldig adgangskode: Adgangskoden er sortlisted. +invalidPasswordConfirmMessage=Adgangskoderne er ikke ens +invalidTotpMessage=Ugyldig autentificerings kode. + +usernameExistsMessage=Brugernavnet eksisterer allerede. +emailExistsMessage=Email adressen eksisterer allerede. + +federatedIdentityExistsMessage=Bruger med {0} {1} eksisterer allerede. Log ind i konto administration for at linke kontoen. + +confirmLinkIdpTitle=Kontoen eksisterer allerede +federatedIdentityConfirmLinkMessage=Bruger med {0} {1} eksisterer allerede. Hvordan vil du fortsætte? +federatedIdentityConfirmReauthenticateMessage=Log ind som {0} for at linke din konto med {1} +confirmLinkIdpReviewProfile=Se profil +confirmLinkIdpContinue=Tilføj til eksisterende konto + +configureTotpMessage=Du skal opsætte en Mobile Authenticator for at kunne aktivere din konto. +updateProfileMessage=Du skal opdatere din brugerprofil for at kunne aktivere din konto. +updatePasswordMessage=Du skal ændre din adgangskode for at kunne aktivere din konto. +resetPasswordMessage=Du skal ændre din adgangskode. +verifyEmailMessage=Du skal verificere din email adresse for at kunne aktivere din konto. +linkIdpMessage=Du skal verificere din email adresse for at kunne kontoen med {0}. + +emailSentMessage=Du vil snarest modtage en email med yderligere instruktioner. +emailSendErrorMessage=Kunne ikke sende email, prøv igen senere. + +accountUpdatedMessage=Din konto er blevet opdateret. +accountPasswordUpdatedMessage=Din adgangskode er blevet opdateret. + +delegationCompleteHeader=Login lykkedes +delegationCompleteMessage=Du kan nu lukke dette browser vindue og gå tilbage til din konsol applikation. +delegationFailedHeader=Log ind fejlede +delegationFailedMessage=Du kan nu lukke dette browser vindue og gå tilbage til din konsol applikation for at forsøge at logge ind igen. + +noAccessMessage=Ingen adgang + +invalidPasswordMinLengthMessage=Ugyldig adgangskode: minimum længde {0}. +invalidPasswordMinDigitsMessage=Ugyldig adgangskode: skal minimum indeholde {0} tal. +invalidPasswordMinLowerCaseCharsMessage=Ugyldig adgangskode: skal minimum indeholde {0} små bogstaver. +invalidPasswordMinUpperCaseCharsMessage=Ugyldig adgangskode: skal minimum indeholde {0} store bogstaver. +invalidPasswordMinSpecialCharsMessage=Ugyldig adgangskode: skal minimum indeholde {0} specialtegn. +invalidPasswordNotUsernameMessage=Ugyldig adgangskode: må ikke være identisk med brugernavnet. +invalidPasswordRegexPatternMessage=Ugyldig adgangskode: Ikke i stand til at matche regex mønstre. +invalidPasswordHistoryMessage=Ugyldig adgangskode: må ikke være identisk med nogle af de seneste {0} adgangskoder. +invalidPasswordGenericMessage=Ugyldig adgangskode: ny adgangskode matcher ikke vores adgangskode politikker. + +failedToProcessResponseMessage=Ude af stand til at processere svaret +httpsRequiredMessage=HTTPS påkrævet +realmNotEnabledMessage=Riget er ikke aktiveret +invalidRequestMessage=Ugyldig Forespørgsel +failedLogout=Logud fejlede +unknownLoginRequesterMessage=Ukendt log ind forespørger +loginRequesterNotEnabledMessage=Log ind forespørgeren er ikke aktiveret +bearerOnlyMessage=Bearer-only applikationer må ikke foretage browser login +standardFlowDisabledMessage=Klienten må ikke foretage browser login med den givne response_type. Standard flowet er deaktiveret for klienten. +implicitFlowDisabledMessage=Klienten må ikke foretage browser login med den givne response_type. Implicit flowet er deaktiveret for klienten. + +invalidRedirectUriMessage=Ugyldig redirect uri +unsupportedNameIdFormatMessage=Ikke understøttet NameIDFormat +invalidRequesterMessage=Ugyldig forespørger +registrationNotAllowedMessage=Registrering er ikke tilladt +resetCredentialNotAllowedMessage=Reset Credential er ikke tilladt + +permissionNotApprovedMessage=Tilladelse ikke godkendt. +noRelayStateInResponseMessage=Ingen relæ tilstand i svaret fra identitetsudbyderen. +insufficientPermissionMessage=Utilstrækkelig tilladelse for at kunne linke identiter. +couldNotProceedWithAuthenticationRequestMessage=Kunne ikke fortsætte med godkendelsesanmodning til identitetsudbyderen. +couldNotObtainTokenMessage=Kunne ikke opnå token fra identitetsudbyder. +unexpectedErrorRetrievingTokenMessage=Uventet fejl i forsøget på at hente token fra identitetsudbyder. +unexpectedErrorHandlingResponseMessage=Uventet fejl i forsøget på at behandle svaret fra identitetsudbyder. +identityProviderAuthenticationFailedMessage=Log ind fejlede. Kunne ikke logge ind ved identitetsudbyder. +couldNotSendAuthenticationRequestMessage=Kunne ikke sende log ind forespørgsel til identitetsudbyder. +unexpectedErrorHandlingRequestMessage=Uventet fejl under håndteringen af forespørgsel til identitetsudbyder. +invalidAccessCodeMessage=Ugyldig adgangskode. +sessionNotActiveMessage=Sessionen er ikke aktiv. +invalidCodeMessage=Der opstod en fejl, log ind igen via din applikation. +identityProviderUnexpectedErrorMessage=Uventet fejl under log ind ved identitetsudbyder +identityProviderNotFoundMessage=Kunne ikke finde en identitetsudbyder med det angivede id. +identityProviderLinkSuccess=Din email er nu verificeret. Gå tilbage til din oprindelige browser og fortsæt log ind derfra. +staleCodeMessage=Siden er ikke længere gyldig, gå tilbage til din applikation og login igen +realmSupportsNoCredentialsMessage=Riget understøtter ikke nogen legimatitionstype. +credentialSetupRequired=Kan ikke logge ind. Legimatitionstype skal konfigureres. +identityProviderNotUniqueMessage=Riget understøtter flere forskellige identitetsudbydere. Kunne ikke beslutte hvilken identitetsudbyder der skulle bruges til at logge ind med. +emailVerifiedMessage=Din email adresse er verificeret. +staleEmailVerificationLink=Linket du har klikket på er et gammelt udløbet link. Måske har du allerede verificeret din mailadresse? +identityProviderAlreadyLinkedMessage=Forbundsidentitet returneret af {0} er allerede linket til en anden bruger. +confirmAccountLinking=Bekræft sammenkobling af konto {0} fra identitetsudbyder {1} med din konto. +confirmEmailAddressVerification=Bekræft gyldigheden af email adresse {0}. +confirmExecutionOfActions=Udfør følgende handling(er) + +locale_ca=Catal\u00E0 +locale_da=Dansk +locale_de=Deutsch +locale_en=English +locale_es=Espa\u00F1ol +locale_fr=Fran\u00e7ais +locale_it=Italiano +locale_ja=\u65E5\u672C\u8A9E +locale_nl=Nederlands +locale_no=Norsk +locale_pt_BR=Portugu\u00EAs (Brasil) +locale_pt-BR=Portugu\u00EAs (Brasil) +locale_ru=\u0420\u0443\u0441\u0441\u043A\u0438\u0439 +locale_lt=Lietuvi\u0173 +locale_zh-CN=\u4e2d\u6587\u7b80\u4f53 +locale_sk=Sloven\u010Dina +locale_sv=Svenska + +backToApplication=« Tilbage til applikation +missingParameterMessage=Manglende parametre\: {0} +clientNotFoundMessage=Klienten kunne ikke findes. +clientDisabledMessage=Klienten er deaktiveret. +invalidParameterMessage=Ugyldig parameter\: {0} +alreadyLoggedIn=Du er allerede logget ind. +differentUserAuthenticated=Du er allerede logget ind som en anden bruger ''{0}'' i denne session. Log venligst ud først. +brokerLinkingSessionExpired=Har forespørgt kobling mellem mæglerkonti, men den nuværende session er ikke længere gyldig. + +proceedWithAction=» Tryk her for at fortsætte + +requiredAction.CONFIGURE_TOTP=Konfigurer OTP +requiredAction.terms_and_conditions=Vilkår og betingelser +requiredAction.UPDATE_PASSWORD=Opdater Adgangskode +requiredAction.UPDATE_PROFILE=Opdater Profil +requiredAction.VERIFY_EMAIL=Verificer email adresse + +doX509Login=Du vil blive logget ind som\: +clientCertificate=X509 client certificate\: +noCertificate=[No Certificate] + +pageNotFound=Siden kunne ikke findes +internalServerError=Der opstod en intern server fejl. + +console-username=Brugernavn: +console-password=Adgangskode: +console-otp=Engangskode: +console-new-password=Ny Adgangskode: +console-confirm-password=Bekræft Adgangskode: +console-update-password=Du skal opdatere din adgangskode. +console-verify-email=Du skal verificere din email adresse. En email er blevet sendt til {0} som indeholder en verificerings kode. Indtast koden i input feltet herunder. + +console-email-code=Email Kode: +console-accept-terms=Accepter Vilkår? [j/n]: +console-accept=j + +auth-username-form-display-name=Brugernavn +auth-username-form-help-text=Start log ind ved at indtaste dit brugernavn +auth-username-password-form-display-name=Brugernavn og adgangskode +auth-username-password-form-help-text=Log ind ved at indtaste dit brugernavn og adgangskode + +doBack=Tilbage +doTryAgain=Prøv igen +doTryAnotherWay=Prøv på en anden måde +rolesScopeConsentText=Brugerroller +restartLoginTooltip=Start log ind forfra +loginTotpStep3DeviceName=Angiv et udstyrsnavn for at kunne holde rede på udstyr med engangskode. +loginCredential=Credential +loginTotpDeviceName=Udstyrsnavn +loginChooseAuthenticator=Vælg metode til log ind +requiredFields=Nødvendige felter +invalidUsernameMessage=Ugyldigt brugernavn. +invalidUsernameOrEmailMessage=Ugyldigt brugernavn eller email. +invalidPasswordMessage=Ugyldig adangskode. +missingTotpDeviceNameMessage=Angiv venligst et udstyrsnavn. +nestedFirstBrokerFlowMessage={0} brugeren {1} er ikke forbundet til nogen kendt bruger. +locale_cs=\u010Ce\u0161tina +locale_pl=Polish +openshift.scope.user_info=Brugerinformation +openshift.scope.user_check-access=Brugeradgangsinformation +openshift.scope.user_full=Fuld adgang +openshift.scope.list-projects=Vis liste af projekter +saml.post-form.title=Log ind Redirect +saml.post-form.message=Redirigerer, vent venligst. +saml.post-form.js-disabled=JavaScript er disabled. Vi anbefaler stærkt at enbable det. Klik på knappen nedenfor for at fortsætte. +otp-display-name=Engangskodegenerator +otp-help-text=Indtast en godkendelseskode fra engangskodegeneratoren. +password-display-name=Adgangskode +password-help-text=Log ind ved at indtaste din adgangskode. +webauthn-display-name=Sikkerhedsnøgle +webauthn-help-text=Brug din sikkerhedsnøgle for at logge ind. +webauthn-passwordless-display-name=Sikkerhedsnøgle +webauthn-passwordless-help-text=Brug din sikkerhedsnøgle for at logge ind uden adgangskode. +webauthn-login-title=Log ind med sikkerhedsnøgle +webauthn-registration-title=Registrering af Sikkerhedsnøgle +webauthn-available-authenticators=Tilgængelige log ind måder +webauthn-error-title=Sikkerhedsnøglefejl +webauthn-error-registration=Det lykkedes ikke at registrere din sikkerhedsnøgle. +webauthn-error-api-get=Det lykkedes ikke at logge ind med din sikkerhedsnøgle. +webauthn-error-different-user=Den første authenticatede bruger er ikke den der er authenticated med sikkerhedsnøglen. +webauthn-error-auth-verification=Resultatet fra log ind med sikkerhedsnøgle er ugyldigt. +webauthn-error-register-verification=Resultatet fra registrering med sikkerhedsnøglen er ugyldigt. +webauthn-error-user-not-found=Ukendt bruger authenticated med sikkerhedsnøglen. +identity-provider-redirector=Forbind med en anden Identitetsudbyder \ No newline at end of file diff --git a/keycloak-themes/base/login/messages/messages_de.properties b/keycloak-themes/base/login/messages/messages_de.properties new file mode 100644 index 0000000..b12fe1c --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_de.properties @@ -0,0 +1,380 @@ +doLogIn=Anmelden +doRegister=Registrieren +doCancel=Abbrechen +doSubmit=Absenden +doBack=Zur\u00FCck +doYes=Ja +doNo=Nein +doContinue=Weiter +doIgnore=Ignorieren +doAccept=Annehmen +doDecline=Ablehnen +doForgotPassword=Passwort vergessen? +doClickHere=Hier klicken +doImpersonate=Identit\u00E4tswechsel +doTryAgain=Erneut versuchen +doTryAnotherWay=Einen anderen Weg versuchen +doConfirmDelete=L\u00F6schung best\u00E4tigen +errorDeletingAccount=Beim L\u00F6schen des Kontos ist ein Fehler aufgetreten +deletingAccountForbidden=Sie haben nicht gen\u00FCgend Berechtigungen, um Ihr eigenes Konto zu l\u00F6schen, wenden Sie sich an einen Administrator. +kerberosNotConfigured=Kerberos ist nicht konfiguriert. +kerberosNotConfiguredTitle=Kerberos nicht konfiguriert +bypassKerberosDetail=Sie sind entweder nicht mit Kerberos angemeldet, oder Ihr Browser ist nicht f\u00FCr eine Anmeldung mit Kerberos konfiguriert. Bitte klicken Sie auf Weiter, damit Sie sich auf eine andere Art anmelden k\u00F6nnen +kerberosNotSetUp=Kerberos ist nicht konfiguriert. Sie k\u00F6nnen sich damit nicht anmelden. +registerTitle=Registrierung +loginAccountTitle=Bei Ihrem Konto anmelden +loginTitle=Anmeldung bei {0} +loginTitleHtml={0} +impersonateTitle={0} Identit\u00E4tswechsel +impersonateTitleHtml={0} Identit\u00E4tswechsel +realmChoice=Realm +unknownUser=Unbekannter Benutzer +loginTotpTitle=Mehrfachauthentifizierung konfigurieren +loginProfileTitle=Benutzerkonto Informationen aktualisieren +loginTimeout=Sie haben zu lange gebraucht, um sich anzumelden. Bitte versuchen Sie es erneut. +oauthGrantTitle=OAuth gew\u00E4hren +oauthGrantTitleHtml={0} +errorTitle=Es ist ein Fehler aufgetreten. +errorTitleHtml=Es ist ein Fehler aufgetreten. +emailVerifyTitle=E-Mail verifizieren +emailForgotTitle=Passwort vergessen? +updatePasswordTitle=Passwort aktualisieren +codeSuccessTitle=Erfolgreicher Code +codeErrorTitle=Fehlercode\: {0} +displayUnsupported=Angeforderter Anzeigetyp wird nicht unterst\u00FCtzt +browserRequired=Browser f\u00FCr die Anmeldung erforderlich +browserContinue=Browser erforderlich, um die Anmeldung abzuschlie\u00DFen +browserContinuePrompt=Browser \u00F6ffnen und Anmeldung fortsetzen? [y/n]: +browserContinueAnswer=y + + +termsTitle=Bedingungen und Konditionen +termsTitleHtml=Bedingungen und Konditionen +termsText=

    Zu definierende Bedingungen und Konditionen

    + +recaptchaFailed=Ung\u00FCltiges Recaptcha +recaptchaNotConfigured=Recaptcha Eingabe ist erforderlich, jedoch noch nicht konfiguriert. +consentDenied=Zustimmung verweigert. + +noAccount=Neuer Benutzer? +username=Benutzername +usernameOrEmail=Benutzername oder E-Mail +firstName=Vorname +givenName=Vorname +fullName=Voller Name +lastName=Nachname +familyName=Nachname +email=E-Mail +password=Passwort +passwordConfirm=Passwort best\u00E4tigen +passwordNew=Neues Passwort +passwordNewConfirm=Neues Passwort best\u00E4tigen +rememberMe=Angemeldet bleiben +authenticatorCode=One-time Code +address=Adresse +street=Stra\u00DFe +locality=Stadt oder Ortschaft +region=Staat, Provinz, Region +postal_code=PLZ +country=Land +emailVerified=E-Mail verifiziert +website=Website +phoneNumber=Telefonnummer +phoneNumberVerified=Telefonnummer verifiziert +gender=Geschlecht +birthday=Geburtsdatum +zoneinfo=Zeitzone +gssDelegationCredential=GSS delegierte Berechtigung +logoutOtherSessions=Von anderen Ger\u00E4ten abmelden + +profileScopeConsentText=Nutzerkonto +emailScopeConsentText=E-Mail Adresse +addressScopeConsentText=Adresse +phoneScopeConsentText=Telefonnummer +offlineAccessScopeConsentText=Offline Zugriff +samlRoleListScopeConsentText=Meine Rollen +rolesScopeConsentText=Nutzerrollen + +restartLoginTooltip=Login neustarten + +loginTotpIntro=Sie m\u00FCssen einen One Time Passwort-Generator einrichten, um auf dieses Konto zugreifen zu k\u00F6nnen. +loginTotpStep1=Installieren Sie eine der folgenden Applikationen auf Ihrem Smartphone: +loginTotpStep2=\u00D6ffnen Sie die Applikation und scannen Sie den Barcode. +loginTotpStep3=Geben Sie den von der Applikation generierten One-time Code ein und klicken Sie auf Speichern. +loginTotpStep3DeviceName=Geben Sie einen Ger\u00E4tenamen an, um die Verwaltung Ihrer OTP-Ger\u00E4te zu erleichtern. +loginTotpManualStep2=\u00D6ffnen Sie die Applikation und geben Sie den folgenden Schl\u00FCssel ein. +loginTotpManualStep3=Verwenden Sie die folgenden Konfigurationswerte, falls Sie diese f\u00FCr die Applikation anpassen k\u00F6nnen: +loginTotpUnableToScan=Sie k\u00F6nnen den Barcode nicht scannen? +loginTotpScanBarcode=Barcode scannen? +loginCredential=Anmeldeinformation +loginOtpOneTime=One-time code +loginTotpType=Typ +loginTotpAlgorithm=Algorithmus +loginTotpDigits=Ziffern +loginTotpInterval=Intervall +loginTotpCounter=Z\u00E4hler +loginTotpDeviceName=Ger\u00E4tename + +loginTotp.totp=zeitbasiert (time-based) +loginTotp.hotp=z\u00E4hlerbasiert (counter-based) + +loginChooseAuthenticator=Login Methode ausw\u00E4hlen + +oauthGrantRequest=Wollen Sie diese Zugriffsrechte gew\u00E4hren? +inResource=in + +emailVerifyInstruction1=Eine E-Mail mit weiteren Anweisungen wurde an Sie versendet. +emailVerifyInstruction2=Falls Sie keine E-Mail erhalten haben, dann k\u00F6nnen Sie +emailVerifyInstruction3=um eine neue E-Mail versenden zu lassen. + +emailLinkIdpTitle={0} verkn\u00FCpfen +emailLinkIdp1=Eine E-Mail mit weiteren Anweisungen um {0} Konto {1} mit Ihrem {2} Konto zu verkn\u00FCpfen wurde an Sie versendet. +emailLinkIdp2=Sie haben keinen Code in Ihrer E-Mail erhalten? +emailLinkIdp3=um eine neue E-Mail versenden zu lassen. +emailLinkIdp4=Wenn Sie die E-Mail bereits in einem anderen Browser verifiziert haben +emailLinkIdp5=um fortzufahren. + +backToLogin=« Zur\u00FCck zur Anmeldung + +emailInstruction=Geben Sie Ihren Benutzernamen oder Ihre E-Mail Adresse ein und klicken Sie auf Absenden. Danach werden wir Ihnen eine E-Mail mit weiteren Instruktionen zusenden. + +copyCodeInstruction=Bitte kopieren Sie den folgenden Code und f\u00FCgen ihn in die Applikation ein\: + +pageExpiredTitle=Diese Seite ist nicht mehr g\u00FCltig. +pageExpiredMsg1=Um den Anmeldevorgang neu zu starten +pageExpiredMsg2=Um den Anmeldevorgang fortzusetzen + +personalInfo=Pers\u00F6nliche Informationen: +role_admin=Admin +role_realm-admin=Realm Admin +role_create-realm=Realm erstellen +role_create-client=Client erstellen +role_view-realm=Realm ansehen +role_view-users=Benutzer ansehen +role_view-applications=Applikationen ansehen +role_view-clients=Clients ansehen +role_view-events=Events ansehen +role_view-identity-providers=Identity Provider ansehen +role_manage-realm=Realm verwalten +role_manage-users=Benutzer verwalten +role_manage-applications=Applikationen verwalten +role_manage-identity-providers=Identity Provider verwalten +role_manage-clients=Clients verwalten +role_manage-events=Events verwalten +role_view-profile=Profile ansehen +role_manage-account=Profile verwalten +role_manage-account-links=Profil-Links verwalten +role_read-token=Token lesen +role_offline-access=Offline-Zugriff +client_account=Clientkonto +client_account-console=Accountkonsole +client_security-admin-console=Security Adminkonsole +client_admin-cli=Admin CLI +client_realm-management=Realm-Management +client_broker=Broker + +requiredFields=Ben\u00F6tigte Felder + +invalidUserMessage=Ung\u00FCltiger Benutzername oder Passwort. +invalidUsernameMessage=Ung\u00FCltiger Benutzername. +invalidUsernameOrEmailMessage=Ung\u00FCltiger Benutzername oder E-Mail. +invalidPasswordMessage=Ung\u00FCltiges Passwort. +invalidEmailMessage=Ung\u00FCltige E-Mail-Adresse. +accountDisabledMessage=Ihr Benutzerkonto ist gesperrt, bitte kontaktieren Sie den Admin. +accountTemporarilyDisabledMessage=Ihr Benutzerkonto ist tempor\u00E4r gesperrt. Bitte kontaktieren Sie den Admin oder versuchen Sie es sp\u00E4ter noch einmal. +expiredCodeMessage=Zeit\u00FCberschreitung bei der Anmeldung. Bitte melden Sie sich erneut an. +expiredActionMessage=Die Aktion ist nicht mehr g\u00FCltig. Bitte fahren Sie nun mit der Anmeldung fort. +expiredActionTokenNoSessionMessage=Die Aktion ist nicht mehr g\u00FCltig. +expiredActionTokenSessionExistsMessage=Die Aktion ist nicht mehr g\u00FCltig. Bitte fangen Sie noch einmal an. + +missingFirstNameMessage=Bitte geben Sie einen Vornamen ein. +missingLastNameMessage=Bitte geben Sie einen Nachnamen ein. +missingEmailMessage=Bitte geben Sie eine E-Mail-Adresse ein. +missingUsernameMessage=Bitte geben Sie einen Benutzernamen ein. +missingPasswordMessage=Bitte geben Sie ein Passwort ein. +missingTotpMessage=Bitte geben Sie den One-time Code ein. +missingTotpDeviceNameMessage=Bitte geben Sie einen Ger\u00E4tenamen ein. +notMatchPasswordMessage=Passw\u00F6rter sind nicht identisch. + +invalidPasswordExistingMessage=Das aktuelle Passwort ist ung\u00FCltig. +invalidPasswordBlacklistedMessage=Ung\u00FCltiges Passwort: Das Passwort steht auf der Blockliste (schwarzen Liste). +invalidPasswordConfirmMessage=Die Passwortbest\u00E4tigung ist nicht identisch. +invalidTotpMessage=Ung\u00FCltiger One-time Code. + +usernameExistsMessage=Benutzername existiert bereits. +emailExistsMessage=E-Mail existiert bereits. + +federatedIdentityExistsMessage=Ein Benutzer mit {0} {1} existiert bereits. Bitte melden Sie sich an der Benutzerkontoverwaltung an um den Benutzer zu verkn\u00FCpfen. + +confirmLinkIdpTitle=Das Benutzerkonto existiert bereits. +federatedIdentityConfirmLinkMessage=Ein Benutzer mit {0} {1} existiert bereits. Wie m\u00F6chten Sie fortfahren? +federatedIdentityConfirmReauthenticateMessage=Anmelden um das Benutzerkonto mit {0} zu verkn\u00FCpfen +nestedFirstBrokerFlowMessage=Der {0} Benutzer {1} ist mit keinem bekannten Benutzer verkn\u00FCpfen. +confirmLinkIdpReviewProfile=Benutzerkonto \u00FCberpr\u00FCfen +confirmLinkIdpContinue=Zu einem bestehenden Benutzerkonto hinzuf\u00FCgen + +configureTotpMessage=Sie m\u00FCssen eine Mehrfachauthentifizierung einrichten, um das Benutzerkonto zu aktivieren. +updateProfileMessage=Sie m\u00FCssen Ihr Benutzerkonto aktualisieren, um das Benutzerkonto zu aktivieren. +updatePasswordMessage=Sie m\u00FCssen Ihr Passwort \u00E4ndern, um das Benutzerkonto zu aktivieren. +resetPasswordMessage=Sie m\u00FCssen Ihr Passwort \u00E4ndern. +verifyEmailMessage=Sie m\u00FCssen Ihre E-Mail-Adresse verifizieren, um das Benutzerkonto zu aktivieren. +linkIdpMessage=Sie m\u00FCssen Ihre E-Mail-Adresse verifizieren, um Ihr Benutzerkonto mit {0} zu verkn\u00FCpfen. + +emailSentMessage=Sie sollten in K\u00FCrze eine E-Mail mit weiteren Instruktionen erhalten. +emailSendErrorMessage=Die E-Mail konnte nicht versendet werden. Bitte versuchen Sie es sp\u00E4ter nochmal einmal. + +accountUpdatedMessage=Ihr Benutzerkonto wurde aktualisiert. +accountPasswordUpdatedMessage=Ihr Passwort wurde aktualisiert. + +delegationCompleteHeader=Login Erfolgreich +delegationCompleteMessage=Sie k\u00F6nnen dieses Browserfenster schlie\u00DFen und zu Ihrer Konsolenanwendung zur\u00FCckkehren. +delegationFailedHeader=Login Fehlgeschlagen +delegationFailedMessage=Sie k\u00F6nnen dieses Browserfenster schlie\u00DFen und zu Ihrer Konsolenanwendung zur\u00FCckkehren und versuchen, sich erneut anzumelden. + +noAccessMessage=Kein Zugriff + +invalidPasswordMinLengthMessage=Ung\u00FCltiges Passwort: Es muss mindestens {0} Zeichen lang sein. +invalidPasswordMinDigitsMessage=Ung\u00FCltiges Passwort: Es muss mindestens {0} Zahl(en) beinhalten. +invalidPasswordMinLowerCaseCharsMessage=Ung\u00FCltiges Passwort\: Es muss mindestens {0} Kleinbuchstaben beinhalten. +invalidPasswordMinUpperCaseCharsMessage=Ung\u00FCltiges Passwort: Es muss mindestens {0} Gro\u00DFbuchstaben beinhalten. +invalidPasswordMinSpecialCharsMessage=Ung\u00FCltiges Passwort: Es muss mindestens {0} Sonderzeichen beinhalten. +invalidPasswordNotUsernameMessage=Ung\u00FCltiges Passwort: Es darf nicht gleich sein wie der Benutzername. +invalidPasswordNotEmailMessage=Ung\u00FCltiges Passwort: darf nicht identisch mit der E-Mail-Adresse sein. +invalidPasswordRegexPatternMessage=Ung\u00FCltiges Passwort: Es entspricht nicht dem Regex-Muster. +invalidPasswordHistoryMessage=Ung\u00FCltiges Passwort: Es darf nicht einem der letzten {0} Passw\u00F6rter entsprechen. +invalidPasswordGenericMessage=Ung\u00FCltiges Passwort: Es verletzt die Passwort-Richtlinien. + +failedToProcessResponseMessage=Konnte Antwort nicht verarbeiten. +httpsRequiredMessage=HTTPS erforderlich. +realmNotEnabledMessage=Realm nicht aktiviert. +invalidRequestMessage=Ung\u00FCltiger Request. +failedLogout=Logout fehlgeschlagen. +unknownLoginRequesterMessage=Ung\u00FCltiger Login Requester. +loginRequesterNotEnabledMessage=Login Requester nicht aktiviert. +bearerOnlyMessage=Bearer-only Clients k\u00F6nnen sich nicht via Browser anmelden. +standardFlowDisabledMessage=Client darf sich mit diesem response_type nicht via Browser anmelden. Standard Flow ist f\u00FCr diesen Client deaktiviert. +implicitFlowDisabledMessage=Client darf sich mit diesem response_type nicht via Browser anmelden. Implicit Flow ist f\u00FCr diesen Client deaktiviert. +invalidRedirectUriMessage=Ung\u00FCltige Redirect Uri. +unsupportedNameIdFormatMessage=Nicht unterst\u00FCtztes NameIDFormat. +invalidRequesterMessage=Ung\u00FCltiger Requester. +registrationNotAllowedMessage=Registrierung nicht erlaubt. +resetCredentialNotAllowedMessage=Reset Credential nicht erlaubt. + +permissionNotApprovedMessage=Berechtigung nicht best\u00E4tigt. +noRelayStateInResponseMessage=Kein Relay State in der Antwort von Identity Provider. +insufficientPermissionMessage=Nicht gen\u00FCgend Rechte, um die Identit\u00E4t zu verkn\u00FCpfen. +couldNotProceedWithAuthenticationRequestMessage=Konnte die Authentifizierungsanfrage nicht weiter verarbeiten. +couldNotObtainTokenMessage=Konnte kein Token vom Identity Provider erhalten. +unexpectedErrorRetrievingTokenMessage=Unerwarteter Fehler w\u00E4hrend dem Empfang des Tokens vom Identity Provider. +unexpectedErrorHandlingResponseMessage=Unerwarteter Fehler w\u00E4hrend der Bearbeitung der Antwort vom Identity Provider. +identityProviderAuthenticationFailedMessage=Authentifizierung fehlgeschlagen. Authentifizierung mit dem Identity Provider nicht m\u00F6glich. +couldNotSendAuthenticationRequestMessage=Konnte Authentifizierungsanfrage nicht an den Identity Provider senden. +unexpectedErrorHandlingRequestMessage=Unerwarteter Fehler w\u00E4hrend der Bearbeitung der Anfrage an den Identity Provider. +invalidAccessCodeMessage=Ung\u00FCltiger Access-Code. +sessionNotActiveMessage=Session nicht aktiv. +invalidCodeMessage=Ung\u00FCltiger Code, bitte melden Sie sich erneut \u00FCber die Applikation an. +cookieNotFoundMessage=Cookie konnte nicht gefunden werden. Bitte stellen Sie sicher, dass Cookies in Ihrem Browser aktiviert sind. +identityProviderUnexpectedErrorMessage=Unerwarteter Fehler w\u00E4hrend der Authentifizierung mit dem Identity Provider. +identityProviderMissingStateMessage=Fehlender state Parameter in der Antwort vom Identit\u00E4tsanbieter. +identityProviderNotFoundMessage=Konnte keinen Identity Provider zu der Identit\u00E4t finden. +identityProviderLinkSuccess=Sie haben Ihre E-Mail-Adresse erfolgreich verifiziert. Bitte kehren Sie zu Ihrem urspr\u00FCnglichen Browser zur\u00FCck und fahren Sie dort mit der Anmeldung fort. +staleCodeMessage=Diese Seite ist nicht mehr g\u00FCltig, bitte kehren Sie zu Ihrer Applikation zur\u00FCk und melden Sie sich erneut an. +realmSupportsNoCredentialsMessage=Realm unterst\u00FCtzt keine Credential Typen. +credentialSetupRequired=Anmeldung nicht m\u00F6glich, Einrichtung der Anmeldeinformationen erforderlich. +identityProviderNotUniqueMessage=Der Realm unterst\u00FCtzt mehrere Identity Provider. Es konnte kein eindeutiger Identity Provider zum Authentifizieren gew\u00E4hlt werden. +emailVerifiedMessage=Ihre E-Mail-Adresse wurde erfolgreich verifiziert. +staleEmailVerificationLink=Der von Ihnen angeklickte Link ist nicht mehr g\u00FCltig. Haben Sie Ihre E-Mail-Adresse eventuell bereits verifiziert? +identityProviderAlreadyLinkedMessage=Die Identit\u00E4t welche von dem Identity Provider zur\u00FCckgegeben wurde ist bereits mit einem anderen Benutzer verkn\u00FCpft. +confirmAccountLinking=Best\u00E4tigen Sie den Account {0} des Identity Provider {1} mit Ihrem Account zu verkn\u00FCpfen. +confirmEmailAddressVerification=Best\u00E4tigen Sie, dass die E-Mail-Adresse {0} g\u00FCltig ist. +confirmExecutionOfActions=F\u00FChren Sie die folgende(n) Aktion(en) aus + +backToApplication=« Zur\u00FCck zur Applikation +missingParameterMessage=Fehlender Parameter\: {0} +clientNotFoundMessage=Client nicht gefunden. +clientDisabledMessage=Client deaktiviert. +invalidParameterMessage=Ung\u00FCltiger Parameter\: {0} +alreadyLoggedIn=Sie sind bereits angemeldet. +differentUserAuthenticated=Sie sind in dieser Session bereits mit einem anderen Benutzer ''{0}'' angemeldet. Bitte melden Sie sich zuerst ab. +brokerLinkingSessionExpired=Broker Account Linking angefordert; Ihre Session ist allerdings nicht mehr g\u00FCltig. +proceedWithAction=» Klicken Sie hier um fortzufahren + +requiredAction.CONFIGURE_TOTP=Mehrfachauthentifizierung konfigurieren +requiredAction.terms_and_conditions=Bedingungen und Konditionen +requiredAction.UPDATE_PASSWORD=Passwort aktualisieren +requiredAction.UPDATE_PROFILE=Profil aktualisieren +requiredAction.VERIFY_EMAIL=E-Mail-Adresse verifizieren + +doX509Login=Sie werden angemeldet als\: +clientCertificate=X509 Client Zertifikat\: +noCertificate=[Kein Zertifikat] + + +pageNotFound=Seite nicht gefunden +internalServerError=Es ist ein interner Server-Fehler aufgetreten + +console-username=Benutzername: +console-password=Passwort: +console-otp=One Time Passwort: +console-new-password=Neues Passwort: +console-confirm-password=Passwort best\u00E4tigen: +console-update-password=Eine Aktualisierung Ihres Passworts ist erforderlich. +console-verify-email=Sie m\u00FCssen Ihre E-Mail-Adresse verifizieren. Wir haben eine E-Mail an {0} gesendet, die einen Verifizierungscode enth\u00E4lt. Bitte geben Sie diesen Code in das untenstehende Eingabefeld ein. +console-email-code=E-Mail Code: +console-accept-terms=Nutzungsbedingungen akzeptieren? [y/n]: +console-accept=y + +# Openshift messages +openshift.scope.user_info=Nutzerinformation +openshift.scope.user_check-access=Benutzerzugriffsinformationen +openshift.scope.user_full=Voller Zugriff +openshift.scope.list-projects=Projekte auflisten + +# SAML authentication +saml.post-form.title=Authentifizierungsumleitung +saml.post-form.message=Sie werden weitergeleitet, bitte warten. +saml.post-form.js-disabled=JavaScript ist deaktiviert. Wir empfehlen dringend, es zu aktivieren. Klicken Sie auf die Schaltfl\u00E4che unten, um fortzufahren. + +#authenticators +otp-display-name=Authenticator-Anwendung +otp-help-text=Eingabe eines Verifizierungscodes aus der Authenticator-Anwendung. +password-display-name=Passwort +password-help-text=Melden Sie sich an, indem Sie Ihr Passwort eingeben. +auth-username-form-display-name=Benutzername +auth-username-form-help-text=Anmelden durch Eingabe des Benutzernamens +auth-username-password-form-display-name=Benutzername und Passwort +auth-username-password-form-help-text=Anmelden, indem Sie Ihren Benutzernamen und Ihr Passwort eingeben. + +# WebAuthn +webauthn-display-name=Security-Token +webauthn-help-text=Verwenden Sie Ihr Security-Token zur Anmeldung. +webauthn-passwordless-display-name=Security-Token +webauthn-passwordless-help-text=Verwenden Sie Ihr Security-Token zur kennwortlosen Anmeldung. +webauthn-login-title=Security-Token Anmeldung +webauthn-registration-title=Security-Token Registrierung +webauthn-available-authenticators=Verf\u00FCgbare Authentifikatoren +webauthn-unsupported-browser-text=WebAuthn wird von diesem Browser nicht unterst\u00FCtzt. Versuchen Sie es mit einem anderen oder wenden Sie sich an Ihren Administrator. +webauthn-doAuthenticate=Anmelden mit Security-Token + +# WebAuthn Error +webauthn-error-title=Security-Token Fehler +webauthn-error-registration=Fehler beim Registrieren Ihres Security-Tokens.
    {0} +webauthn-error-api-get=Fehler beim Authentifizieren mit dem Security-Token.
    {0} +webauthn-error-different-user=Der erste authentifizierte Benutzer ist nicht derjenige, der durch das Security-Token authentifiziert wurde. +webauthn-error-auth-verification=Das Ergebnis der Security-Token Authentifizierung ist ung\u00FCltig.
    {0} +webauthn-error-register-verification=Das Ergebnis der Security-Token Registrierung ist ung\u00FCltig.
    {0} +webauthn-error-user-not-found=Unbekannter Benutzer, der mit dem Security-Token authentifiziert wurde. + +# Identity provider +identity-provider-redirector=Mit einem anderen Indentit\u00E4tsprovider verbinden +identity-provider-login-label=Oder anmelden mit + +finalDeletionConfirmation=Wenn Sie Ihr Konto l\u00F6schen, kann es nicht wiederhergestellt werden. Um Ihr Konto zu behalten, klicken Sie auf Abbrechen. +irreversibleAction=Diese Aktion ist unwiderruflich +deleteAccountConfirm=L\u00F6schung des Kontos best\u00E4tigen + +deletingImplies=Die L\u00F6schung Ihres Kontos bedeutet: +errasingData=L\u00F6schen aller Ihrer Daten +loggingOutImmediately=Sofortige Abmeldung +accountUnusable=Eine sp\u00E4tere Nutzung der Anwendung ist mit diesem Konto nicht mehr m\u00F6glich +userDeletedSuccessfully=Nutzer erfolgreich gel\u00F6scht diff --git a/keycloak-themes/base/login/messages/messages_en.properties b/keycloak-themes/base/login/messages/messages_en.properties new file mode 100644 index 0000000..b22c647 --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_en.properties @@ -0,0 +1,489 @@ +doLogIn=Sign In +doRegister=Register +doCancel=Cancel +doSubmit=Submit +doBack=Back +doYes=Yes +doNo=No +doContinue=Continue +doIgnore=Ignore +doAccept=Accept +doDecline=Decline +doForgotPassword=Forgot Password? +doClickHere=Click here +doImpersonate=Impersonate +doTryAgain=Try again +doTryAnotherWay=Try Another Way +doConfirmDelete=Confirm deletion +errorDeletingAccount=Error happened while deleting account +deletingAccountForbidden=You do not have enough permissions to delete your own account, contact admin. +kerberosNotConfigured=Kerberos Not Configured +kerberosNotConfiguredTitle=Kerberos Not Configured +bypassKerberosDetail=Either you are not logged in by Kerberos or your browser is not set up for Kerberos login. Please click continue to login in through other means +kerberosNotSetUp=Kerberos is not set up. You cannot login. +registerTitle=Register +loginAccountTitle=Sign in to your account +loginTitle=Sign in to {0} +loginTitleHtml={0} +impersonateTitle={0} Impersonate User +impersonateTitleHtml={0} Impersonate User +realmChoice=Realm +unknownUser=Unknown user +loginTotpTitle=Mobile Authenticator Setup +loginProfileTitle=Update Account Information +loginIdpReviewProfileTitle=Update Account Information +loginTimeout=Your login attempt timed out. Login will start from the beginning. +reauthenticate=Please re-authenticate to continue +oauthGrantTitle=Grant Access to {0} +oauthGrantTitleHtml={0} +oauthGrantInformation=Make sure you trust {0} by learning how {0} will handle your data. +oauthGrantReview=You could review the +oauthGrantTos=terms of service. +oauthGrantPolicy=privacy policy. +errorTitle=We are sorry... +errorTitleHtml=We are sorry ... +emailVerifyTitle=Email verification +emailForgotTitle=Forgot Your Password? +updatePasswordTitle=Update password +codeSuccessTitle=Success code +codeErrorTitle=Error code\: {0} +displayUnsupported=Requested display type unsupported +browserRequired=Browser required to login +browserContinue=Browser required to complete login +browserContinuePrompt=Open browser and continue login? [y/n]: +browserContinueAnswer=y + +# Transports +usb=USB +nfc=NFC +bluetooth=Bluetooth +internal=Internal +unknown=Unknown + +termsTitle=Terms and Conditions +termsText=

    Terms and conditions to be defined

    +termsPlainText=Terms and conditions to be defined. + +recaptchaFailed=Invalid Recaptcha +recaptchaNotConfigured=Recaptcha is required, but not configured +consentDenied=Consent denied. + +noAccount=New user? +username=Username +usernameOrEmail=Username or email +firstName=First name +givenName=Given name +fullName=Full name +lastName=Last name +familyName=Family name +email=Email +password=Password +passwordConfirm=Confirm password +passwordNew=New Password +passwordNewConfirm=New Password confirmation +rememberMe=Remember me +authenticatorCode=One-time code +address=Address +street=Street +locality=City or Locality +region=State, Province, or Region +postal_code=Zip or Postal code +country=Country +emailVerified=Email verified +website=Web page +phoneNumber=Phone number +phoneNumberVerified=Phone number verified +gender=Gender +birthday=Birthdate +zoneinfo=Time zone +gssDelegationCredential=GSS Delegation Credential +logoutOtherSessions=Sign out from other devices + +profileScopeConsentText=User profile +emailScopeConsentText=Email address +addressScopeConsentText=Address +phoneScopeConsentText=Phone number +offlineAccessScopeConsentText=Offline Access +samlRoleListScopeConsentText=My Roles +rolesScopeConsentText=User roles + +restartLoginTooltip=Restart login + +loginTotpIntro=You need to set up a One Time Password generator to access this account +loginTotpStep1=Install one of the following applications on your mobile: +loginTotpStep2=Open the application and scan the barcode: +loginTotpStep3=Enter the one-time code provided by the application and click Submit to finish the setup. +loginTotpStep3DeviceName=Provide a Device Name to help you manage your OTP devices. +loginTotpManualStep2=Open the application and enter the key: +loginTotpManualStep3=Use the following configuration values if the application allows setting them: +loginTotpUnableToScan=Unable to scan? +loginTotpScanBarcode=Scan barcode? +loginCredential=Credential +loginOtpOneTime=One-time code +loginTotpType=Type +loginTotpAlgorithm=Algorithm +loginTotpDigits=Digits +loginTotpInterval=Interval +loginTotpCounter=Counter +loginTotpDeviceName=Device Name + +loginTotp.totp=Time-based +loginTotp.hotp=Counter-based + +loginChooseAuthenticator=Select login method + +oauthGrantRequest=Do you grant these access privileges? +inResource=in + +oauth2DeviceVerificationTitle=Device Login +verifyOAuth2DeviceUserCode=Enter the code provided by your device and click Submit +oauth2DeviceInvalidUserCodeMessage=Invalid code, please try again. +oauth2DeviceExpiredUserCodeMessage=The code has expired. Please go back to your device and try connecting again. +oauth2DeviceVerificationCompleteHeader=Device Login Successful +oauth2DeviceVerificationCompleteMessage=You may close this browser window and go back to your device. +oauth2DeviceVerificationFailedHeader=Device Login Failed +oauth2DeviceVerificationFailedMessage=You may close this browser window and go back to your device and try connecting again. +oauth2DeviceConsentDeniedMessage=Consent denied for connecting the device. +oauth2DeviceAuthorizationGrantDisabledMessage=Client is not allowed to initiate OAuth 2.0 Device Authorization Grant. The flow is disabled for the client. + +emailVerifyInstruction1=An email with instructions to verify your email address has been sent to your address {0}. +emailVerifyInstruction2=Haven''t received a verification code in your email? +emailVerifyInstruction3=to re-send the email. + +emailLinkIdpTitle=Link {0} +emailLinkIdp1=An email with instructions to link {0} account {1} with your {2} account has been sent to you. +emailLinkIdp2=Haven''t received a verification code in your email? +emailLinkIdp3=to re-send the email. +emailLinkIdp4=If you already verified the email in different browser +emailLinkIdp5=to continue. + +backToLogin=« Back to Login + +emailInstruction=Enter your username or email address and we will send you instructions on how to create a new password. +emailInstructionUsername=Enter your username and we will send you instructions on how to create a new password. + +copyCodeInstruction=Please copy this code and paste it into your application: + +pageExpiredTitle=Page has expired +pageExpiredMsg1=To restart the login process +pageExpiredMsg2=To continue the login process + +personalInfo=Personal Info: +role_admin=Admin +role_realm-admin=Realm Admin +role_create-realm=Create realm +role_create-client=Create client +role_view-realm=View realm +role_view-users=View users +role_view-applications=View applications +role_view-clients=View clients +role_view-events=View events +role_view-identity-providers=View identity providers +role_manage-realm=Manage realm +role_manage-users=Manage users +role_manage-applications=Manage applications +role_manage-identity-providers=Manage identity providers +role_manage-clients=Manage clients +role_manage-events=Manage events +role_view-profile=View profile +role_manage-account=Manage account +role_manage-account-links=Manage account links +role_read-token=Read token +role_offline-access=Offline access +client_account=Account +client_account-console=Account Console +client_security-admin-console=Security Admin Console +client_admin-cli=Admin CLI +client_realm-management=Realm Management +client_broker=Broker + +requiredFields=Required fields + +invalidUserMessage=Invalid username or password. +invalidUsernameMessage=Invalid username. +invalidUsernameOrEmailMessage=Invalid username or email. +invalidPasswordMessage=Invalid password. +invalidEmailMessage=Invalid email address. +accountDisabledMessage=Account is disabled, contact your administrator. +accountTemporarilyDisabledMessage=Account is temporarily disabled; contact your administrator or retry later. +expiredCodeMessage=Login timeout. Please sign in again. +expiredActionMessage=Action expired. Please continue with login now. +expiredActionTokenNoSessionMessage=Action expired. +expiredActionTokenSessionExistsMessage=Action expired. Please start again. +sessionLimitExceeded=There are too many sessions + +missingFirstNameMessage=Please specify first name. +missingLastNameMessage=Please specify last name. +missingEmailMessage=Please specify email. +missingUsernameMessage=Please specify username. +missingPasswordMessage=Please specify password. +missingTotpMessage=Please specify authenticator code. +missingTotpDeviceNameMessage=Please specify device name. +notMatchPasswordMessage=Passwords don''t match. + +error-invalid-value=Invalid value. +error-invalid-blank=Please specify value. +error-empty=Please specify value. +error-invalid-length=Length must be between {1} and {2}. +error-invalid-length-too-short=Minimal length is {1}. +error-invalid-length-too-long=Maximal length is {2}. +error-invalid-email=Invalid email address. +error-invalid-number=Invalid number. +error-number-out-of-range=Number must be between {1} and {2}. +error-number-out-of-range-too-small=Number must have minimal value of {1}. +error-number-out-of-range-too-big=Number must have maximal value of {2}. +error-pattern-no-match=Invalid value. +error-invalid-uri=Invalid URL. +error-invalid-uri-scheme=Invalid URL scheme. +error-invalid-uri-fragment=Invalid URL fragment. +error-user-attribute-required=Please specify this field. +error-invalid-date=Invalid date. +error-user-attribute-read-only=This field is read only. +error-username-invalid-character=Value contains invalid character. +error-person-name-invalid-character=Value contains invalid character. + +invalidPasswordExistingMessage=Invalid existing password. +invalidPasswordBlacklistedMessage=Invalid password: password is blacklisted. +invalidPasswordConfirmMessage=Password confirmation doesn''t match. +invalidTotpMessage=Invalid authenticator code. + +usernameExistsMessage=Username already exists. +emailExistsMessage=Email already exists. + +federatedIdentityExistsMessage=User with {0} {1} already exists. Please login to account management to link the account. +federatedIdentityUnavailableMessage=User {0} authenticated with identity provider {1} does not exist. Please contact your administrator. + +confirmLinkIdpTitle=Account already exists +federatedIdentityConfirmLinkMessage=User with {0} {1} already exists. How do you want to continue? +federatedIdentityConfirmReauthenticateMessage=Authenticate to link your account with {0} +nestedFirstBrokerFlowMessage=The {0} user {1} is not linked to any known user. +confirmLinkIdpReviewProfile=Review profile +confirmLinkIdpContinue=Add to existing account + +configureTotpMessage=You need to set up Mobile Authenticator to activate your account. +configureBackupCodesMessage=You need to set up Backup Codes to activate your account. +updateProfileMessage=You need to update your user profile to activate your account. +updatePasswordMessage=You need to change your password to activate your account. +resetPasswordMessage=You need to change your password. +verifyEmailMessage=You need to verify your email address to activate your account. +linkIdpMessage=You need to verify your email address to link your account with {0}. + +emailSentMessage=You should receive an email shortly with further instructions. +emailSendErrorMessage=Failed to send email, please try again later. + +accountUpdatedMessage=Your account has been updated. +accountPasswordUpdatedMessage=Your password has been updated. + +delegationCompleteHeader=Login Successful +delegationCompleteMessage=You may close this browser window and go back to your console application. +delegationFailedHeader=Login Failed +delegationFailedMessage=You may close this browser window and go back to your console application and try logging in again. + +noAccessMessage=No access + +invalidPasswordMinLengthMessage=Invalid password: minimum length {0}. +invalidPasswordMaxLengthMessage=Invalid password: maximum length {0}. +invalidPasswordMinDigitsMessage=Invalid password: must contain at least {0} numerical digits. +invalidPasswordMinLowerCaseCharsMessage=Invalid password: must contain at least {0} lower case characters. +invalidPasswordMinUpperCaseCharsMessage=Invalid password: must contain at least {0} upper case characters. +invalidPasswordMinSpecialCharsMessage=Invalid password: must contain at least {0} special characters. +invalidPasswordNotUsernameMessage=Invalid password: must not be equal to the username. +invalidPasswordNotEmailMessage=Invalid password: must not be equal to the email. +invalidPasswordRegexPatternMessage=Invalid password: fails to match regex pattern(s). +invalidPasswordHistoryMessage=Invalid password: must not be equal to any of last {0} passwords. +invalidPasswordGenericMessage=Invalid password: new password doesn''t match password policies. + +failedToProcessResponseMessage=Failed to process response +httpsRequiredMessage=HTTPS required +realmNotEnabledMessage=Realm not enabled +invalidRequestMessage=Invalid Request +successLogout=You are logged out +failedLogout=Logout failed +unknownLoginRequesterMessage=Unknown login requester +loginRequesterNotEnabledMessage=Login requester not enabled +bearerOnlyMessage=Bearer-only applications are not allowed to initiate browser login +standardFlowDisabledMessage=Client is not allowed to initiate browser login with given response_type. Standard flow is disabled for the client. +implicitFlowDisabledMessage=Client is not allowed to initiate browser login with given response_type. Implicit flow is disabled for the client. +invalidRedirectUriMessage=Invalid redirect uri +unsupportedNameIdFormatMessage=Unsupported NameIDFormat +invalidRequesterMessage=Invalid requester +registrationNotAllowedMessage=Registration not allowed +resetCredentialNotAllowedMessage=Reset Credential not allowed + +permissionNotApprovedMessage=Permission not approved. +noRelayStateInResponseMessage=No relay state in response from identity provider. +insufficientPermissionMessage=Insufficient permissions to link identities. +couldNotProceedWithAuthenticationRequestMessage=Could not proceed with authentication request to identity provider. +couldNotObtainTokenMessage=Could not obtain token from identity provider. +unexpectedErrorRetrievingTokenMessage=Unexpected error when retrieving token from identity provider. +unexpectedErrorHandlingResponseMessage=Unexpected error when handling response from identity provider. +identityProviderAuthenticationFailedMessage=Authentication failed. Could not authenticate with identity provider. +couldNotSendAuthenticationRequestMessage=Could not send authentication request to identity provider. +unexpectedErrorHandlingRequestMessage=Unexpected error when handling authentication request to identity provider. +invalidAccessCodeMessage=Invalid access code. +sessionNotActiveMessage=Session not active. +invalidCodeMessage=An error occurred, please login again through your application. +cookieNotFoundMessage=Cookie not found. Please make sure cookies are enabled in your browser. +insufficientLevelOfAuthentication=The requested level of authentication has not been satisfied. +identityProviderUnexpectedErrorMessage=Unexpected error when authenticating with identity provider +identityProviderMissingStateMessage=Missing state parameter in response from identity provider. +identityProviderNotFoundMessage=Could not find an identity provider with the identifier. +identityProviderLinkSuccess=You successfully verified your email. Please go back to your original browser and continue there with the login. +staleCodeMessage=This page is no longer valid, please go back to your application and sign in again +realmSupportsNoCredentialsMessage=Realm does not support any credential type. +credentialSetupRequired=Cannot login, credential setup required. +identityProviderNotUniqueMessage=Realm supports multiple identity providers. Could not determine which identity provider should be used to authenticate with. +emailVerifiedMessage=Your email address has been verified. +staleEmailVerificationLink=The link you clicked is an old stale link and is no longer valid. Maybe you have already verified your email. +identityProviderAlreadyLinkedMessage=Federated identity returned by {0} is already linked to another user. +confirmAccountLinking=Confirm linking the account {0} of identity provider {1} with your account. +confirmEmailAddressVerification=Confirm validity of e-mail address {0}. +confirmExecutionOfActions=Perform the following action(s) + +locale_ca=Catal\u00E0 +locale_cs=\u010Ce\u0161tina +locale_da=Dansk +locale_de=Deutsch +locale_en=English +locale_es=Espa\u00F1ol +locale_fr=Fran\u00E7ais +locale_hu=Magyar +locale_it=Italiano +locale_ja=\u65E5\u672C\u8A9E +locale_lt=Lietuvi\u0173 +locale_nl=Nederlands +locale_no=Norsk +locale_pl=Polski +locale_pt_BR=Portugu\u00EAs (Brasil) +locale_pt-BR=Portugu\u00EAs (Brasil) +locale_ru=\u0420\u0443\u0441\u0441\u043A\u0438\u0439 +locale_sk=Sloven\u010Dina +locale_sv=Svenska +locale_tr=T\u00FCrk\u00E7e +locale_zh-CN=\u4E2D\u6587\u7B80\u4F53 +locale_fi=Suomi + +backToApplication=« Back to Application +missingParameterMessage=Missing parameters\: {0} +clientNotFoundMessage=Client not found. +clientDisabledMessage=Client disabled. +invalidParameterMessage=Invalid parameter\: {0} +alreadyLoggedIn=You are already logged in. +differentUserAuthenticated=You are already authenticated as different user ''{0}'' in this session. Please sign out first. +brokerLinkingSessionExpired=Requested broker account linking, but current session is no longer valid. +proceedWithAction=» Click here to proceed +acrNotFulfilled=Authentication requirements not fulfilled + +requiredAction.CONFIGURE_TOTP=Configure OTP +requiredAction.terms_and_conditions=Terms and Conditions +requiredAction.UPDATE_PASSWORD=Update Password +requiredAction.UPDATE_PROFILE=Update Profile +requiredAction.VERIFY_EMAIL=Verify Email +requiredAction.CONFIGURE_RECOVERY_AUTHN_CODES=Generate Recovery Codes + +doX509Login=You will be logged in as\: +clientCertificate=X509 client certificate\: +noCertificate=[No Certificate] + + +pageNotFound=Page not found +internalServerError=An internal server error has occurred + +console-username=Username: +console-password=Password: +console-otp=One Time Password: +console-new-password=New Password: +console-confirm-password=Confirm Password: +console-update-password=Update of your password is required. +console-verify-email=You need to verify your email address. We sent an email to {0} that contains a verification code. Please enter this code into the input below. +console-email-code=Email Code: +console-accept-terms=Accept Terms? [y/n]: +console-accept=y + +# Openshift messages +openshift.scope.user_info=User information +openshift.scope.user_check-access=User access information +openshift.scope.user_full=Full Access +openshift.scope.list-projects=List projects + +# SAML authentication +saml.post-form.title=Authentication Redirect +saml.post-form.message=Redirecting, please wait. +saml.post-form.js-disabled=JavaScript is disabled. We strongly recommend to enable it. Click the button below to continue. +saml.artifactResolutionServiceInvalidResponse=Unable to resolve artifact. + +#authenticators +otp-display-name=Authenticator Application +otp-help-text=Enter a verification code from authenticator application. +password-display-name=Password +password-help-text=Sign in by entering your password. +auth-username-form-display-name=Username +auth-username-form-help-text=Start sign in by entering your username +auth-username-password-form-display-name=Username and password +auth-username-password-form-help-text=Sign in by entering your username and password. + +# Recovery Codes +auth-recovery-authn-code-form-display-name=Recovery Authentication Code +auth-recovery-authn-code-form-help-text=Enter a recovery authentication code from a previously generated list. +auth-recovery-code-info-message=Enter the specified recovery code. +auth-recovery-code-prompt=Recovery code #{0} +auth-recovery-code-header=Login with a recovery authentication code +recovery-codes-error-invalid=Invalid recovery authentication code +recovery-code-config-header=Recovery Authentication Codes +recovery-code-config-warning-title=These recovery codes won't appear again after leaving this page +recovery-code-config-warning-message=Make sure to print, download, or copy them to a password manager and keep them save. Canceling this setup will remove these recovery codes from your account. +recovery-codes-print=Print +recovery-codes-download=Download +recovery-codes-copy=Copy +recovery-codes-copied=Copied +recovery-codes-confirmation-message=I have saved these codes somewhere safe +recovery-codes-action-complete=Complete setup +recovery-codes-action-cancel=Cancel setup +recovery-codes-download-file-header=Keep these recovery codes somewhere safe. +recovery-codes-download-file-description=Recovery codes are single-use passcodes that allow you to log in to your account if you do not have access to your authenticator. +recovery-codes-download-file-date= These codes were generated on +recovery-codes-label-default=Recovery codes + +# WebAuthn +webauthn-display-name=Security Key +webauthn-help-text=Use your security key to sign in. +webauthn-passwordless-display-name=Security Key +webauthn-passwordless-help-text=Use your security key for passwordless sign in. +webauthn-login-title=Security Key login +webauthn-registration-title=Security Key Registration +webauthn-available-authenticators=Available Security Keys +webauthn-unsupported-browser-text=WebAuthn is not supported by this browser. Try another one or contact your administrator. +webauthn-doAuthenticate=Sign in with Security Key +webauthn-createdAt-label=Created + +# WebAuthn Error +webauthn-error-title=Security Key Error +webauthn-error-registration=Failed to register your Security key.
    {0} +webauthn-error-api-get=Failed to authenticate by the Security key.
    {0} +webauthn-error-different-user=First authenticated user is not the one authenticated by the Security key. +webauthn-error-auth-verification=Security key authentication result is invalid.
    {0} +webauthn-error-register-verification=Security key registration result is invalid.
    {0} +webauthn-error-user-not-found=Unknown user authenticated by the Security key. + +# Identity provider +identity-provider-redirector=Connect with another Identity Provider +identity-provider-login-label=Or sign in with + +finalDeletionConfirmation=If you delete your account, it cannot be restored. To keep your account, click Cancel. +irreversibleAction=This action is irreversible +deleteAccountConfirm=Delete account confirmation + +deletingImplies=Deleting your account implies: +errasingData=Erasing all your data +loggingOutImmediately=Logging you out immediately +accountUnusable=Any subsequent use of the application will not be possible with this account +userDeletedSuccessfully=User deleted successfully + +access-denied=Access denied + +frontchannel-logout.title=Logging out +frontchannel-logout.message=You are logging out from following apps +logoutConfirmTitle=Logging out +logoutConfirmHeader=Do you want to logout? +doLogout=Logout + diff --git a/keycloak-themes/base/login/messages/messages_es.properties b/keycloak-themes/base/login/messages/messages_es.properties new file mode 100644 index 0000000..27e8723 --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_es.properties @@ -0,0 +1,201 @@ +doLogIn=Iniciar sesi\u00F3n +doRegister=Reg\u00EDstrate +doCancel=Cancelar +doSubmit=Enviar +doYes=S\u00ED +doNo=No +doContinue=Continuar +doAccept=Aceptar +doDecline=Declinar +doForgotPassword=\u00BFHas olvidado tu contrase\u00F1a? +doClickHere=Haz clic aqu\u00ED +doImpersonate=Personificar +kerberosNotConfigured=Kerberos no configurado +kerberosNotConfiguredTitle=Kerberos no configurado +bypassKerberosDetail=O bien no est\u00E1s identificado mediante Kerberos o tu navegador no est\u00E1 configurado para identificarse mediante Kerberos. Por favor haz clic para identificarte por otro medio. +kerberosNotSetUp=Kerberos no est\u00E1 configurado. No puedes identificarte. +registerWithTitle=Reg\u00EDstrate con {0} +registerWithTitleHtml={0} +loginAccountTitle=Acceder a tu cuenta +loginTitle=Inicia sesi\u00F3n en {0} +loginTitleHtml={0} +impersonateTitle={0}\u00A0Personificar Usuario +impersonateTitleHtml={0} Personificar Usuario +realmChoice=Dominio +unknownUser=Usuario desconocido +loginTotpTitle=Configura tu aplicaci\u00F3n de identificaci\u00F3n m\u00F3vil +loginProfileTitle=Actualiza la informaci\u00F3n de tu cuenta +loginTimeout=Has tardado demasiado en identificarte. Inicia de nuevo la identificaci\u00F3n. +oauthGrantTitle=Concesi\u00F3n OAuth +oauthGrantTitleHtml={0} +errorTitle=Lo sentimos... +errorTitleHtml=Lo sentimos... +emailVerifyTitle=Verificaci\u00F3n del email +emailForgotTitle=\u00BFHas olvidado tu contrase\u00F1a? +updatePasswordTitle=Modificaci\u00F3n de contrase\u00F1a +codeSuccessTitle=C\u00F3digo de \u00E9xito +codeErrorTitle=C\u00F3digo de error: {0} + +termsTitle=T\u00E9rminos y Condiciones +termsTitleHtml=T\u00E9rminos y Condiciones +termsText=

    T\u00E9rmines y condiciones a definir

    + +recaptchaFailed=Reconocimiento de texto inv\u00E1lido +recaptchaNotConfigured=El reconocimiento de texto es obligatorio pero no est\u00E1 configurado +consentDenied=Consentimiento rechazado. + +noAccount=\u00BFUsuario nuevo? +username=Usuario +usernameOrEmail=Usuario o email +firstName=Nombre +givenName=Nombre de pila +fullName=Nombre completo +lastName=Apellidos +familyName=Apellidos +email=Email +password=Contrase\u00F1a +passwordConfirm=Confirma la contrase\u00F1a +passwordNew=Nueva contrase\u00F1a +passwordNewConfirm=Confirma la nueva contrase\u00F1a +rememberMe=Seguir conectado +authenticatorCode=C\u00F3digo de identificaci\u00F3n +address=Direcci\u00F3n +street=Calle +locality=Ciudad o Municipio +region=Estado, Provincia, o Regi\u00F3n +postal_code=C\u00F3digo Postal +country=Pa\u00EDs +emailVerified=Email verificado +gssDelegationCredential=GSS Delegation Credential + +loginTotpStep1=Instala FreeOTP o Google Authenticator en tu tel\u00E9fono m\u00F3vil. Ambas aplicaciones est\u00E1n disponibles en Google Play y en la App Store de Apple. +loginTotpStep2=Abre la aplicaci\u00F3n y escanea el c\u00F3digo o introduce la clave. +loginTotpStep3=Introduce el c\u00F3digo \u00FAnico que te muestra la aplicaci\u00F3n de autenticaci\u00F3n y haz clic en Enviar para finalizar la configuraci\u00F3n +loginOtpOneTime=C\u00F3digo de un solo uso + +oauthGrantRequest=\u00BFQuieres permitir estos privilegios de acceso? +inResource=en + +emailVerifyInstruction1=Te hemos enviado un email con instrucciones para verificar tu email. +emailVerifyInstruction2=\u00BFNo has recibido un c\u00F3digo de verificaci\u00F3n en tu email? +emailVerifyInstruction3=para reenviar el email. + +backToLogin=« Volver a la identificaci\u00F3n + +emailInstruction=Indica tu usuario o email y te enviaremos instrucciones indicando c\u00F3mo generar una nueva contrase\u00F1a. + +copyCodeInstruction=Por favor, copia y pega este c\u00F3digo en tu aplicaci\u00F3n: + +personalInfo=Informaci\u00F3n personal: +role_admin=Admin +role_realm-admin=Administrador del dominio +role_create-realm=Crear dominio +role_create-client=Crear cliente +role_view-realm=Ver dominio +role_view-users=Ver usuarios +role_view-applications=Ver aplicaciones +role_view-clients=Ver clientes +role_view-events=Ver eventos +role_view-identity-providers=Ver proveedores de identidad +role_manage-realm=Gestionar dominio +role_manage-users=Gestionar usuarios +role_manage-applications=Gestionar aplicaciones +role_manage-identity-providers=Gestionar proveedores de identidad +role_manage-clients=Gestionar clientes +role_manage-events=Gestionar eventos +role_view-profile=Ver perfil +role_manage-account=Gestionar cuenta +role_read-token=Leer token +role_offline-access=Acceso sin conexi\u00F3n +client_account=Cuenta +client_security-admin-console=Consola de Administraci\u00F3n de Seguridad +client_realm-management=Gesti\u00F3n del dominio +client_broker=Broker + +invalidUserMessage=Usuario o contrase\u00F1a incorrectos. +invalidEmailMessage=Email no v\u00E1lido +accountDisabledMessage=La cuenta est\u00E1 desactivada, contacta con el administrador. +accountTemporarilyDisabledMessage=La cuenta est\u00E1 temporalmente desactivada, contacta con el administrador o int\u00E9ntalo de nuevo m\u00E1s tarde. +expiredCodeMessage=Se agot\u00F3 el tiempo m\u00E1ximo para la identificaci\u00F3n. Por favor identificate de nuevo. + +missingFirstNameMessage=Por favor indica tu nombre. +missingLastNameMessage=Por favor indica tus apellidos. +missingEmailMessage=Por favor indica tu email. +missingUsernameMessage=Por favor indica tu usuario. +missingPasswordMessage=Por favor indica tu contrase\u00F1a. +missingTotpMessage=Por favor indica tu c\u00F3digo de autenticaci\u00F3n +notMatchPasswordMessage=Las contrase\u00F1as no coinciden. + +invalidPasswordExistingMessage=La contrase\u00F1a actual no es correcta. +invalidPasswordConfirmMessage=La confirmaci\u00F3n de contrase\u00F1a no coincide. +invalidTotpMessage=El c\u00F3digo de autenticaci\u00F3n no es v\u00E1lido. + +usernameExistsMessage=El nombre de usuario ya existe +emailExistsMessage=El email ya existe + +federatedIdentityEmailExistsMessage=Ya existe un usuario con este email. Por favor accede a la gesti\u00F3n de tu cuenta para enlazarlo. +federatedIdentityUsernameExistsMessage=Ya existe un usuario con este nombre de usuario. Por favor accede a la gesti\u00F3n de tu cuenta para enlazarlo. + +configureTotpMessage=Tienes que configurar la aplicaci\u00F3n m\u00F3vil de identificaci\u00F3n para activar tu cuenta. +updateProfileMessage=Tienes que actualizar tu perfil de usuario para activar tu cuenta. +updatePasswordMessage=Tienes que cambiar tu contrase\u00F1a para activar tu cuenta. +verifyEmailMessage=Tienes que verificar tu email para activar tu cuenta. + +emailSentMessage=En breve deber\u00EDas recibir un mensaje con m\u00E1s instrucciones +emailSendErrorMessage=Fall\u00F3 el env\u00EDo del email, por favor int\u00E9ntalo de nuevo m\u00E1s tarde. + +accountUpdatedMessage=Tu cuenta se ha actualizado. +accountPasswordUpdatedMessage=Tu contrase\u00F1a se ha actualizado. + +noAccessMessage=Sin acceso + +invalidPasswordMinLengthMessage=Contrase\u00F1a incorrecta: longitud m\u00EDnima {0}. +invalidPasswordMinDigitsMessage=Contrase\u00F1a incorrecta: debe contaner al menos {0} caracteres num\u00E9ricos. +invalidPasswordMinLowerCaseCharsMessage=Contrase\u00F1a incorrecta: debe contener al menos {0} letras min\u00FAsculas. +invalidPasswordMinUpperCaseCharsMessage=Contrase\u00F1a incorrecta: debe contener al menos {0} letras may\u00FAsculas. +invalidPasswordMinSpecialCharsMessage=Contrase\u00F1a incorrecta: debe contener al menos {0} caracteres especiales. +invalidPasswordNotUsernameMessage=Contrase\u00F1a incorrecta: no puede ser igual al nombre de usuario. +invalidPasswordRegexPatternMessage=Contrase\u00F1a incorrecta: no cumple la expresi\u00F3n regular. +invalidPasswordHistoryMessage=Contrase\u00F1a incorrecta: no puede ser igual a ninguna de las \u00FAltimas {0} contrase\u00F1as. + +failedToProcessResponseMessage=Fallo al procesar la respuesta +httpsRequiredMessage=HTTPS obligatorio +realmNotEnabledMessage=El dominio no est\u00E1 activado +invalidRequestMessage=Petici\u00F3n incorrecta +failedLogout=Fall\u00F3 la desconexi\u00F3n. +unknownLoginRequesterMessage=Solicitante de identificaci\u00F3n desconocido +loginRequesterNotEnabledMessage=El solicitante de inicio de sesi\u00F3n est\u00E1 desactivado +bearerOnlyMessage=Las aplicaciones Bearer-only no pueden iniciar sesi\u00F3n desde el navegador. +directGrantsOnlyMessage=Los clientes de tipo Direct-grants-only no pueden iniciar sesi\u00F3n desde el navegador. +invalidRedirectUriMessage=La URI de redirecci\u00F3n no es correcta +unsupportedNameIdFormatMessage=NameIDFormat no soportado +invalidRequesterMessage=Solicitante no v\u00E1lido +registrationNotAllowedMessage=El registro no est\u00E1 permitido +resetCredentialNotAllowedMessage=El reinicio de las credenciales no est\u00E1 permitido + +permissionNotApprovedMessage=Permiso no aprobado. +noRelayStateInResponseMessage=Sin estado de retransmisi\u00F3n en la respuesta del proveedor de identidad. +identityProviderAlreadyLinkedMessage=La identidad devuelta por el proveedor de identidad ya est\u00E1 asociada a otro usuario. +insufficientPermissionMessage=Permisos insuficientes para enlazar identidades. +couldNotProceedWithAuthenticationRequestMessage=No se pudo continuar con la petici\u00F3n de autenticaci\u00F3n al proveedor de identidad. +couldNotObtainTokenMessage=.No se pudo obtener el c\u00F3digo del proveedor de identidad +unexpectedErrorRetrievingTokenMessage=Error inesperado obteniendo el token del proveedor de identidad +unexpectedErrorHandlingResponseMessage=Error inesperado procesando la respuesta del proveedor de identidad. +identityProviderAuthenticationFailedMessage=Fall\u00F3 la autenticaci\u00F3n. No fue posible autenticarse en el proveedor de identidad. +couldNotSendAuthenticationRequestMessage=No se pudo enviar la petici\u00F3n de identificaci\u00F3n al proveedor de identidad. +unexpectedErrorHandlingRequestMessage=Error inesperado durante la petici\u00F3n de identificaci\u00F3n al proveedor de identidad. +invalidAccessCodeMessage=C\u00F3digo de acceso no v\u00E1lido. +sessionNotActiveMessage=La sesi\u00F3n no est\u00E1 activa +invalidCodeMessage=Ha ocurrido un error, por favor identificate de nuevo desde tu aplicaci\u00F3n. +identityProviderUnexpectedErrorMessage=Error no esperado intentado autenticar en el proveedor de identidad. +identityProviderNotFoundMessage=No se encontr\u00F3 un proveedor de identidad. +realmSupportsNoCredentialsMessage=El dominio no soporta ning\u00FAn tipo de credenciales. +identityProviderNotUniqueMessage=El dominio soporta m\u00FAltiples proveedores de identidad. No se pudo determinar el proveedor de identidad que deber\u00EDa ser utilizado para identificarse. +emailVerifiedMessage=Tu email ha sido verificado. + +backToApplication=« Volver a la aplicaci\u00F3n +missingParameterMessage=Par\u00E1metros que faltan: {0} +clientNotFoundMessage=Cliente no encontrado +invalidParameterMessage=Par\u00E1metro no v\u00E1lido: {0} +alreadyLoggedIn=You are already logged in. + diff --git a/keycloak-themes/base/login/messages/messages_fi.properties b/keycloak-themes/base/login/messages/messages_fi.properties new file mode 100644 index 0000000..f22eb3d --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_fi.properties @@ -0,0 +1,441 @@ +# encoding: UTF-8 +doLogIn=Kirjaudu +doRegister=Rekisteröidy +doCancel=Peruuta +doSubmit=Lähetä +doBack=Takaisin +doYes=Kyllä +doNo=Ei +doContinue=Jatka +doIgnore=Sivuuta +doAccept=Hyväksy +doDecline=En hyväksy +doForgotPassword=Unohditko salasanan? +doClickHere=Klikkaa tästä +doImpersonate=Edusta +doTryAgain=Yritä uudelleen +doTryAnotherWay=Yritä toista tapaa +doConfirmDelete=Vahvista poisto +errorDeletingAccount=Tilin poistossa tapahtui virhe +deletingAccountForbidden=Sinulla ei ole riittäviä oikeuksia poistaakseesi omaa tiliä, ota yhteyttä järjestelmänvalvojaan. +kerberosNotConfigured=Kerberosta ei ole konfiguroitu +kerberosNotConfiguredTitle=Kerberosta ei ole konfiguroitu +bypassKerberosDetail=Joko et ole kirjautunut Kerberoksen kautta tai selaintasi ei ole asetettu käyttämään Kerberosta kirjautumiseen. Klikkaa jatkaaksesi kirjautumista jollain toisella tavalla +kerberosNotSetUp=Kerberosta ei ole asennettu. Et voi kirjautua sisään. +registerTitle=Rekisteröidy +loginAccountTitle=Kirjaudu sisään +loginTitle=Kirjaudu {0} +loginTitleHtml={0} +impersonateTitle={0} Edusta käyttäjää +impersonateTitleHtml={0} Edusta käyttäjää +realmChoice=Realm +unknownUser=Tuntematon käyttäjä +loginTotpTitle=Mobiili-todentajan asetukset +loginProfileTitle=Päivitä käyttäjätilin tiedot +loginIdpReviewProfileTitle=Päivitä käyttäjätilin tiedot +loginTimeout=Kirjautumisyritys kesti liian kauan. Kirjautuminen aloitetaan alusta. +oauthGrantTitle=Myönnä pääsy {0} +oauthGrantTitleHtml={0} +errorTitle=Pahoittelut... +errorTitleHtml=Olemme pahoillamme ... +emailVerifyTitle=Sähköpostiosoitteen varmistus +emailForgotTitle=Unohditko salasanasi? +updatePasswordTitle=Päivitä salasana +codeSuccessTitle=Success-koodi +codeErrorTitle=Virhekoodi: {0} +displayUnsupported=Pyydetty näyttötyyppi ei ole tuettu +browserRequired=Selain vaatii sisäänkirjautumista +browserContinue=Selain vaatii sisäänkirjautumisen viimeistelyä +browserContinuePrompt=Avaa selain ja jatka kirjautumista? [k/e]: +browserContinueAnswer=k + + +termsTitle=Käyttöehdot +termsText=

    Käyttöehdot ja niiden määrittely

    +termsPlainText=Käyttöehdot ja niiden määrittely. + +recaptchaFailed=Virheellinen Recaptcha +recaptchaNotConfigured=Recaptcha vaaditaan, mutta sitä ei ole konfiguroitu +consentDenied=Suostumus kielletty. + +noAccount=Uusi käyttäjä? +username=Käyttäjätunnus +usernameOrEmail=Käyttäjätunnus tai sähköpostiosoite +firstName=Etunimi +givenName=Sukunimi +fullName=Koko nimi +lastName=Sukunimi +familyName=Sukunimi +email=Sähköposti +password=Salasana +passwordConfirm=Salasana uudelleen +passwordNew=Uusi salasana +passwordNewConfirm=Uusi salasana uudelleen +rememberMe=Muista minut +authenticatorCode=Kertakäyttökoodi +address=Osoite +street=Katu +locality=Kaupunki +region=Osavaltio, Provinssi, tai Alue +postal_code=Postinumero +country=Maa +emailVerified=Sähköposti vahvistettu +website=Verkkosivu +phoneNumber=Puhelinnumero +phoneNumberVerified=Puhelinnumero varmennettu +gender=Sukupuoli +birthday=Syntymäpäivä +zoneinfo=Aikavyöhyke +gssDelegationCredential=GSS Delegation Credential +logoutOtherSessions=Kirjaudu ulos muilta laitteilta + +profileScopeConsentText=Käyttäjän profiili +emailScopeConsentText=Sähköpostiosoite +addressScopeConsentText=Osoite +phoneScopeConsentText=Puhelinnumero +offlineAccessScopeConsentText=Offline-käyttö +samlRoleListScopeConsentText=Omat roolit +rolesScopeConsentText=Käyttäjäroolit + +restartLoginTooltip=Aloita kirjautuminen alusta + +loginTotpIntro=Sinun täytyy asentaa OTP (One Time Password) luontityökalu päästäksesi tälle tilille +loginTotpStep1=Asenna yksi seuraavista sovelluksista puhelimeesi: +loginTotpStep2=Avaa sovellus ja skannaa viivakoodi +loginTotpStep3=Liitä sovelluksesta saatu kertaluontoinen koodi ja paina Lähetä viimeistelläksesi asennuksen +loginTotpStep3DeviceName=Anna laitteelle nimi, jotta voit hallinnoida OTP-laitteitasi. +loginTotpManualStep2=Avaa sovellus ja liitä avain +loginTotpManualStep3=Käytä seuraavia konfiguraatioarvoja jos sovellus antaa asettaa ne: +loginTotpUnableToScan=Ongelmia skannauksessa? +loginTotpScanBarcode=Skannaa viivakoodi? +loginCredential=Kirjautumistieto +loginTotpOneTime=Kertaluontoinen koodi +loginTotpType=Tyyppi +loginTotpAlgorithm=Algoritmi +loginTotpDigits=Numerot +loginTotpInterval=Intervalli +loginTotpCounter=Laskuri +loginTotpDeviceName=Laitteen nimi + +loginTotp.totp=Aikapohjainen +loginTotp.hotp=Laskuripohjainen + +loginChooseAuthenticator=Valitse kirjautumistapa + +oauthGrantRequest=Myönnätkö nämä käyttöoikeudet? +inResource=in + +oauth2DeviceVerificationTitle=Laitekirjautuminen +verifyOAuth2DeviceUserCode=Liitä laitteeltasi saamasi kertaluontoinen koodi ja paina Lähetä +oauth2DeviceInvalidUserCodeMessage=Virheellinen koodi. yritä uudelleen. +oauth2DeviceExpiredUserCodeMessage=Koodi on vanhentunut. Ole hyvä ja mene takaisin laitteellesi ja yritä yhdistämistä uudellleen. +oauth2DeviceVerificationCompleteHeader=Laitekirjautuminen onnistui +oauth2DeviceVerificationCompleteMessage=Voit sulkea tämän ikkunan ja mennä takaisin laitteellesi. +oauth2DeviceVerificationFailedHeader=Laitekirjautuminen epäonnistui +oauth2DeviceVerificationFailedMessage=Voit sulkea tämän ikkunan, mennä takaisin laitteellesi ja yrittää kirjautumista uudelleen. +oauth2DeviceConsentDeniedMessage=Laitteen kirjautumisen suostumus evätty. +oauth2DeviceAuthorizationGrantDisabledMessage=Client is not allowed to initiate OAuth 2.0 Device Authorization Grant. The flow is disabled for the client. + +emailVerifyInstruction1=Sähköpostin vahvistamisohjeet sisältävä viesti on lähetetty sähköpostiisi. +emailVerifyInstruction2=Etkö ole saanut vahvistuskoodia sähköpostiisi? +emailVerifyInstruction3=saadaksesi uuden sähköpostiviestin. + +emailLinkIdpTitle=Linkitä {0} +emailLinkIdp1=Sinulle on lähetetty ohjeet tunnuksen linkittämiseen palvelun {0} kanssa. +emailLinkIdp2=Etkö saanut vahvistuskoodia sähköpostiisi? +emailLinkIdp3=saadaksesi uuden sähköpostiviestin. +emailLinkIdp4=Jos olet jo vahvistanut sähköpostisi toisella selaimella, +emailLinkIdp5=jatkaaksesi. + +backToLogin=« Takaisin kirjautumiseen + +emailInstruction=Syötä käyttäjätunnuksesi tai sähköpostiosoitteesi niin lähetämme sinulle ohjeet salasanan palauttamista varten. +emailInstructionUsername=Syötä käyttäjänimesi niin lähetämme sinulle ohjeet uuden salasanan luomiseksi. + +copyCodeInstruction=Ole hyvä ja kopioi tämä koodi ja liitä se sovellukseesi: + +pageExpiredTitle=Sivu on vanhentunut +pageExpiredMsg1=Aloita kirjautuminen alusta +pageExpiredMsg2=Jatka kirjautumista + +personalInfo=Henkilökohtaiset tiedot: +role_admin=Järjestelmänvalvoja +role_realm-admin=Realm Järjestelmänvalvoja +role_create-realm=Luo realm +role_create-client=Luo asiakas +role_view-realm=Näytä realm +role_view-users=Näytä käyttäjät +role_view-applications=Näytä sovellukset +role_view-clients=Näytä asiakkaat +role_view-events=Näytä tapahtumat +role_view-identity-providers=Näytä henkilöllisyyden tarjoajat +role_manage-realm=Hallinnoi realmia +role_manage-users=Hallinnoi käyttäjiä +role_manage-applications=Hallinnoi sovelluksia +role_manage-identity-providers=Hallinnoi henkilöllisyyden tarjoajia +role_manage-clients=Hallinnoi asiakkaita +role_manage-events=Hallinnoi tapahtumia +role_view-profile=Näytä profiili +role_manage-account=Hallitse tiliä +role_manage-account-links=Hallitse tilin linkkejä +role_read-token=Lue token +role_offline-access=Offline-pääsy +client_account=Tili +client_account-console=Tilin konsoli +client_security-admin-console=Turvallisuus-hallintapaneeli +client_admin-cli=Admin CLI +client_realm-management=Realm Hallinta +client_broker=Broker + +requiredFields=Vaaditut kentät + +invalidUserMessage=Virheellinen käyttäjätunnus tai salasana. +invalidUsernameMessage=Väärä salasana. +invalidUsernameOrEmailMessage=Väärä salasana tai sähköposti. +invalidPasswordMessage=Väärä salasana. +invalidEmailMessage=Virheellinen sähköpostiosoite. +accountDisabledMessage=Tili on poistettu käytöstä, ota yhteyttä järjestelmänvalvojaan. +accountTemporarilyDisabledMessage=Tili on väliaikaisesti poissa käytöstä, ota yhteyttä järjestelmänvalvojaan tai yritä myöhemmin uudelleen. +expiredCodeMessage=Kirjautuminen kesti liian kauan. Ole hyvä ja kirjaudu uudestaan. +expiredActionMessage=Toiminto kesti liian kauan. Ole hyvä ja jatka kirjautumiseen. +expiredActionTokenNoSessionMessage=Toiminto vanhentui. +expiredActionTokenSessionExistsMessage=Toiminto vanhentui. Aloita alusta. + +missingFirstNameMessage=Anna etunimi. +missingLastNameMessage=Anna sukunimi. +missingEmailMessage=Anna sähköpostiosoite. +missingUsernameMessage=Anna käyttäjätunnus. +missingPasswordMessage=Anna salasana. +missingTotpMessage=Ole hyvä ja määrittele todentajan koodi. +missingTotpDeviceNameMessage=Ole hyvä ja määrittele laitteen nimi. +notMatchPasswordMessage=Salasanat eivät täsmää. + +error-invalid-value=Väärä arvo. +error-invalid-blank=Ole hyvä ja määritä arvo. +error-empty=Ole hyvä ja määritä arvo. +error-invalid-length=Ominaisuudella {0} täytyy olla pituus väliltä {1} ja {2}. +error-invalid-length-too-short=Ominaisuudella {0} täytyy olla minimipituus {1}. +error-invalid-length-too-long=Ominaisuudella {0} täytyy olla maksimipituus {2}. +error-invalid-email=Väärä sähköpostiosoite. +error-invalid-number=Väärä numero. +error-number-out-of-range=Ominaisuuden {0} täytyy olla numero väliltä {1} ja {2}. +error-number-out-of-range-too-small=Ominaisuudella {0} täytyy olla minimiarvona {1}. +error-number-out-of-range-too-big=Ominaisuudella {0} täytyy olla maksimiarvona {2}. +error-pattern-no-match=Väärä arvo. +error-invalid-uri=Väärä URL. +error-invalid-uri-scheme=Väärä URL:n malli. +error-invalid-uri-fragment=Väärä URL:n osa. +error-user-attribute-required=Ole hyvä ja määritä ominaisuus {0}. +error-invalid-date=Väärä päivämäärä. +error-user-attribute-read-only=Kenttä {0} on "vain luku"-tilassa. +error-username-invalid-character=Käyttäjänimi sisältää vääriä merkkejä. +error-person-name-invalid-character=Nimi sisältää vääriä merkkejä. + +invalidPasswordExistingMessage=Vanha salasana on virheellinen. +invalidPasswordBlacklistedMessage=Väärä salasana: salasana on lisätty mustalle listalle. +invalidPasswordConfirmMessage=Salasanan vahvistus ei täsmää. +invalidTotpMessage=Väärä todentaja-koodi. + +usernameExistsMessage=Käyttäjänimi on varattu. +emailExistsMessage=Sähköpostiosoite on jo käytössä. + +federatedIdentityExistsMessage=Käyttäjä {0} {1} on jo olemassa. Kirjaudu tilihallintaan linkittääksesi tilin. +federatedIdentityUnavailableMessage=Käyttäjä {0} joka on tunnistettu henkilöllisyyden tarjoajalla {1} ei ole olemassa. Ota yhteyttä järjestelmänvalvojaan. + +confirmLinkIdpTitle=Käyttäjätunnus on jo olemassa +federatedIdentityConfirmLinkMessage=Käyttäjätunnus, jolla {0} on {1} on jo olemassa. Kuinka haluat jatkaa? +federatedIdentityConfirmReauthenticateMessage=Tunnistaudu linkittääksesi {0}-tilin. +nestedFirstBrokerFlowMessage={0} käyttäjä {1} ei ole linkitetty tunnettuun käyttäjään. +confirmLinkIdpReviewProfile=Tarkastele profiilia +confirmLinkIdpContinue=Lisää olemassa olevaan tiliin + +configureTotpMessage=Sinun täytyy asentaa mobiili-todentaja aktivoidaksesi tilin. +updateProfileMessage=Sinun tulee päivittää profiilisi aktivoidaksesi tilisi. +updatePasswordMessage=Sinun tulee vaihtaa salasanasi aktivoidaksesi tilisi. +resetPasswordMessage=Sinun tulee päivittää salasanasi. +verifyEmailMessage=Sinun tulee vahvistaa sähköpostiosoitteesi aktivoidaksesi tilisi. +linkIdpMessage=Sinun tulee vahvistaa sähköpostiosoitteesi linkittääksesi tilin palvelun {0} kanssa. + +emailSentMessage=Sinun pitäisi saada sähköpostiisi lisäohjeita hetken kuluttua. +emailSendErrorMessage=Sähköpostin lähettäminen epäonnistui. Yritä hetken kuluttua uudelleen. + +accountUpdatedMessage=Käyttäjätiedot päivitetty. +accountPasswordUpdatedMessage=Salasana vaihdettu. + +delegationCompleteHeader=Kirjautuminen onnistui +delegationCompleteMessage=Voit sulkea tämän ikkunan ja siirtyä takaisin konsolisovellukseen. +delegationFailedHeader=Kirjautuminen epäonnistui +delegationFailedMessage=Voit sulkea tämän selaimen, siirtyä takaisin konsolisovellukseen ja yrittää kirjautumista uudelleen. + +noAccessMessage=Ei pääsyä + +invalidPasswordMinLengthMessage=Virheellinen salasana: vähimmäispituus {0}. +invalidPasswordMaxLengthMessage=Virheellinen salasana: maksimipituus {0}. +invalidPasswordMinDigitsMessage=Virheellinen salasana: salasanassa tulee olla vähintään {0} numeroa. +invalidPasswordMinLowerCaseCharsMessage=Virheellinen salasana: salasanassa tulee olla vähintään {0} pientä kirjainta. +invalidPasswordMinUpperCaseCharsMessage=Virheellinen salasana: salasanassa tulee olla vähintään {0} isoa kirjainta. +invalidPasswordMinSpecialCharsMessage=Virheellinen salasana: salasanassa tulee olla vähintään {0} erikoismerkkiä. +invalidPasswordNotUsernameMessage=Virheellinen salasana: salasana ei saa olla sama kuin käyttäjätunnus. +invalidPasswordNotEmailMessage=Virheellinen salasana: ei voi olla sama kuin sähköposti. +invalidPasswordRegexPatternMessage=Virheellinen salasana: ei vastaa "regex pattern(s)". +invalidPasswordHistoryMessage=Virheellinen salasana: salasana ei saa olla sama kuin {0} edellistä salasanaasi. +invalidPasswordGenericMessage=Virheellinen salasana: uusi salasana ei täytä salasanavaatimuksia. + +failedToProcessResponseMessage=Vastauksen käsittely epäonnistui +httpsRequiredMessage=HTTPS vaaditaan +realmNotEnabledMessage=Realm ei otettu käyttöön +invalidRequestMessage=Virheellinen pyyntö +failedLogout=Uloskirjautuminen epäonnistui +unknownLoginRequesterMessage=Tuntematon kirjautumispyynnön tekijä +loginRequesterNotEnabledMessage=kirjautumispyynnön tekijää ei ole otettu käyttöön +bearerOnlyMessage="Bearer-only" sovellusten ei ole sallittua aloittaa selainkirjautumista +standardFlowDisabledMessage=Asiakas ei saa aloittaa selainkirjautumista annetulla vastaustyypillä ("response_type"). "Standard flow" on poistettu käytöstä asiakkaalla. +implicitFlowDisabledMessage=Asiakas ei saa aloittaa selainkirjautumista annetulla vastaustyypillä ("response_type"). "Implicit flow" on poistettu käytöstä asiakkaalla. +invalidRedirectUriMessage=Virheellinen uudelleenohjaus-uri +unsupportedNameIdFormatMessage=Ei-tuettu "NameIDFormat" +invalidRequesterMessage=Virheellinen pyynnön tekijä +registrationNotAllowedMessage=Rekisteröinti ei ole sallittu +resetCredentialNotAllowedMessage=Kirjautumistietojen nollaus ei ole sallittu + +permissionNotApprovedMessage=Lupaa ei myönnetty +noRelayStateInResponseMessage="relay state" puuttuu henkilöllisyyden tarjoajan vastauksesta. +insufficientPermissionMessage=Riittämättömät oikeudet henkilöllisyyksien linkittämiseksi. +couldNotProceedWithAuthenticationRequestMessage=Tunnistuspyyntöä henkilöllisyyden tarjoajalle ei voitu jatkaa. +couldNotObtainTokenMessage=Ei voitu saada tokenia henkilöllisyyden tarjoajalta. +unexpectedErrorRetrievingTokenMessage=Odottamaton virhe hankkiessa tokenia henkilöllisyyden tarjoajalta. +unexpectedErrorHandlingResponseMessage=Odottamaton virhe käsiteltäessä vastausta henkilöllisyyden tarjoajalta. +identityProviderAuthenticationFailedMessage=Tunnistautuminen epäonnistui. Ei voitu tunnistautua henkilöllisyyden tarjoajan kautta. +identityProviderDifferentUserMessage=Tunnistautunut {0}, vaikka pitäisi olla tunnistautunut {1} +couldNotSendAuthenticationRequestMessage=Ei voitu lähettää tunnistautumispyyntö henkilöllisyyden tarjoajalle. +unexpectedErrorHandlingRequestMessage=Odottamaton virhe käsiteltäessä tunnistautumispyyntö henkilöllisyyden tarjoajalle. +invalidAccessCodeMessage=Virheellinen pääsykoodi +sessionNotActiveMessage=Istunto ei ole aktiivinen. +invalidCodeMessage=Tapahtui virhe, ole hyvä ja kirjaudu uudelleen sovelluksesi kautta. +identityProviderUnexpectedErrorMessage=Tunnistautumisen yhteydessä tapahtui virhe tunnistetietojen tarjoajan kanssa. +identityProviderNotFoundMessage=Tunnisteella ei löytynyt henkilöllisyyden tarjoajaa. +identityProviderLinkSuccess=Sähköpostin vahvistus onnistui Ole hyvä ja palaa alkuperäiseen selainikkunaan jatkaaksesi kirjautumista. +staleCodeMessage=Tämä sivu ei ole enää voimassa, ole hyvä ja palaa sovellukseesi ja kirjaudu uudelleen +realmSupportsNoCredentialsMessage=Realm ei tue mitään kirjautumistiedon tyyppiä. +credentialSetupRequired=Ei voida kirjautua, kirjautumistietojen asetukset vaaditaan. +identityProviderNotUniqueMessage=Realm tukee useita henkilöllisyyden tarjoajia. Ei voitu määrittää, mitä henkilöllisyyden tarjoajaa pitäisi käyttää tunnistautumiseen. +emailVerifiedMessage=Sähköpostisi on vahvistettu. +staleEmailVerificationLink=Klikkaamasi linkki on vanhentunut eikä enää toimi. Oletko jo vahvistanut sähköpostisi? +identityProviderAlreadyLinkedMessage=Yhdistetty henkilöllisyys, minkä {0} palautti, on jo linkitetty toiseen käyttäjään. +confirmAccountLinking=Vahvista tilin {0} linkitys, henkilöllisyyden tarjoajalta {1}, tiliisi. +confirmEmailAddressVerification=Vahvista sähköpostiosoitteen {0} voimassaolo. +confirmExecutionOfActions=Suorita seuraavat toiminnot + +locale_ca=Català +locale_cs=Čeština +locale_da=Dansk +locale_de=Deutsch +locale_en=English +locale_es=Español +locale_fr=Français +locale_hu=Magyar +locale_it=Italiano +locale_ja=日本語 +locale_lt=Lietuvių +locale_nl=Nederlands +locale_no=Norsk +locale_pl=Polski +locale_pt_BR=Portugu\u00EAs (Brasil) +locale_pt-BR=Portugu\u00EAs (Brasil) +locale_ru=Русский +locale_zh-CN=中文简体 +locale_sk=Slovenčina +locale_sv=Svenska +locale_fi=Suomi +locale_tr=Türkçe + +backToApplication=« Takaisin sovellukseen +missingParameterMessage=Puuttuva parametri\: {0} +clientNotFoundMessage=Asiakasta ei löytynyt. +clientDisabledMessage=Asiakas ei ole käytössä. +invalidParameterMessage=Epäkelpo parametri\: {0} +alreadyLoggedIn=Olet jo kirjautunut sisään +differentUserAuthenticated=Olet kirjautunut sisään tilillä ''{0}''. Ole hyvä ja kirjaudu ulos ensin. +brokerLinkingSessionExpired=Pyysit tilin yhdistämistä mutta sessio on vanhentunut. +proceedWithAction=» Klikkaa tästä jatkaaksesi + +requiredAction.CONFIGURE_TOTP=Konfiguroi OTP +requiredAction.terms_and_conditions=Käyttöehdot +requiredAction.UPDATE_PASSWORD=Päivitä salasana +requiredAction.UPDATE_PROFILE=Päivitä profiili +requiredAction.VERIFY_EMAIL=Vahvista sähköposti + +doX509Login=Kirjaudut sisään nimellä\: +clientCertificate=X509 asiakas-varmenne\: +noCertificate=[No Certificate] + + +pageNotFound=Sivua ei löytynyt +internalServerError=Tapahtui sisäinen virhe palvelimella. + +console-username=Käyttäjänimi: +console-password=Salasana: +console-otp=One Time Password: +console-new-password=Uusi salasana: +console-confirm-password=Vahvista salana: +console-update-password=Salasanan päivitys vaaditaan. +console-verify-email=Sinun täytyy vahvistaa sähköpostiosoitteesi. Sähköposti, mikä sisältää vahvistuskoodin, on lähetetty osoitteeseen {0}. Ole hyvä ja kirjoita tämä koodi alapuolella olevaan kenttään. +console-email-code=Sähköposti-koodi: +console-accept-terms=Hyväksy käyttöehdot? [k/e]: +console-accept=k + +# Openshift messages +openshift.scope.user_info=Käyttäjän tiedot +openshift.scope.user_check-access=Käyttäjän käyttöoikeustiedot +openshift.scope.user_full=Täysi käyttöoikeus +openshift.scope.list-projects=Listaa projektit +# SAML authentication +saml.post-form.title=Tunnistautumisen uudelleenohjaus +saml.post-form.message=Uudelleenohjataan, odota hetki.. +saml.post-form.js-disabled=JavaScript on pois käytöstä. Suosittelemme vahvasti sen käyttöönottoa. Klikkaa alla olevaa nappia jatkaaksesi. +saml.artifactResolutionServiceInvalidResponse=Unable to resolve artifact. + +#authenticators +otp-display-name=Todentajasovellus +otp-help-text=Syötä todentajasovelluksen tarjoama vahvistuskoodi. +password-display-name=Salasana +password-help-text=Kirjaudu sisään syöttämällä salasanasi. +auth-username-form-display-name=Käyttäjänimi +auth-username-form-help-text=Aloita kirjautuminen syöttämällä käyttäjänimesi +auth-username-password-form-display-name=käyttäjänimi ja salasana +auth-username-password-form-help-text=Kirjaudu sisään syöttämällä käyttäjänimi ja salasana. + +# WebAuthn +webauthn-display-name=Turva-avain +webauthn-help-text=Käytä Turva-avaintasi kirjatuaksesi sisään. +webauthn-passwordless-display-name=Turva-avain +webauthn-passwordless-help-text=Käytä Turva-avaintasi kirjatuaksesi sisään ilman salasanaa. +webauthn-login-title=Turva-avain kirjautuminen +webauthn-registration-title=Turva-avain rekisteröinti +webauthn-available-authenticators=Saatavilla olevat todentajat +webauthn-unsupported-browser-text="WebAuthn" ei ole tuettu tällä selaimella. Kokeile jotain toista tai ota yhteyttä järjestelmänvalvojaan. +webauthn-doAuthenticate=Kirjaudu sisään Turva-avaimella + +# WebAuthn Error +webauthn-error-title=Turva-avain virhe +webauthn-error-registration=Turva-avaimen rekisteröinti epäonnistui.
    {0} +webauthn-error-api-get=Tunnistautuminen Turva-avaimella epäonnistui.
    {0} +webauthn-error-different-user=Ensiksi tunnistautunut käyttäjä ei ole sama kuin Turva-avaimella tunnistaunut. +webauthn-error-auth-verification=Turva-avain -tunnistautumisen tulos on virheellinen.
    {0} +webauthn-error-register-verification=Turva-avaimen rekisteröinnin tulos on virheellinen.
    {0} +webauthn-error-user-not-found=Tuntematon käyttäjä tunnistautui Turva-avaimella. + +# Identity provider +identity-provider-redirector=Yhdistä käyttämällä toista henkilöllisyyden tarjoajaa +identity-provider-login-label=Tai kirjaudu jollain näistä: + +finalDeletionConfirmation=Jos poistat tilisi, sitä ei voida enää palauttaa. Säilyttääksesi tilisi, paina Peruuta. +irreversibleAction=Tätä toimintoa ei voi peruuttaa +deleteAccountConfirm=Tilin poistamisen vahvistus + +deletingImplies=Tilin poisto tarkoittaa sitä, että: +errasingData=Kaikki tietosi poistetaan +loggingOutImmediately=Sinut kirjataan ulos välittömästi +accountUnusable=Tämän sovelluksen käyttö ei myöhemmin enää ole mahdollista tällä käyttäjätilillä +userDeletedSuccessfully=Käyttäjä poistettu onnistuneesti + +access-denied=Pääsy evätty \ No newline at end of file diff --git a/keycloak-themes/base/login/messages/messages_fr.properties b/keycloak-themes/base/login/messages/messages_fr.properties new file mode 100644 index 0000000..5f577b4 --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_fr.properties @@ -0,0 +1,277 @@ +doLogIn=Connexion +doRegister=Enregistrement +doCancel=Annuler +doSubmit=Soumettre +doYes=Oui +doNo=Non +doContinue=Continuer +doIgnore=Ignorer +doAccept=Accepter +doDecline=D\u00e9cliner +doForgotPassword=Mot de passe oubli\u00e9 ? +doClickHere=Cliquez ici +doImpersonate=Usurper l'identit\u00e9 +kerberosNotConfigured=Kerberos non configur\u00e9 +kerberosNotConfiguredTitle=Kerberos non configur\u00e9 +bypassKerberosDetail=Si vous n''\u00eates pas connect\u00e9 via Kerberos ou bien que votre navigateur n''est pas configur\u00e9 pour la connexion via Kerberos. Veuillez cliquer pour vous connecter via un autre moyen. +kerberosNotSetUp=Kerberos n''est pas configur\u00e9. Connexion impossible. +registerTitle=S''enregistrer +loginAccountTitle=Connectez-vous \u00e0 votre compte +registerWithTitle=Enregistrement avec {0} +registerWithTitleHtml={0} +loginTitle=Se connecter \u00e0 {0} +loginTitleHtml={0} +impersonateTitle={0} utilisateur usurp\u00e9 +impersonateTitleHtml={0} utilisateur usurp\u00e9 +realmChoice=Domaine +unknownUser=Utilisateur inconnu +loginTotpTitle=Configuration de l''authentification par mobile +loginProfileTitle=Mise \u00e0 jour du compte +loginTimeout=Le temps imparti pour la connexion est \u00e9coul\u00e9. Le processus de connexion red\u00e9marre depuis le d\u00e9but. +oauthGrantTitle=OAuth Grant +oauthGrantTitleHtml={0} +errorTitle=Nous sommes d\u00e9sol\u00e9s... +errorTitleHtml=Nous sommes d\u00e9sol\u00e9s... +emailVerifyTitle=V\u00e9rification du courriel +emailForgotTitle=Mot de passe oubli\u00e9 ? +updatePasswordTitle=Mise \u00e0 jour du mot de passe +codeSuccessTitle=Code succ\u00e8s +codeErrorTitle=Code d''erreur \: {0} +displayUnsupported=Type d''affichage demand\u00e9 non support\u00e9 +browserRequired=Navigateur requis pour se connecter +browserContinue=Navigateur requis pour continuer la connexion +browserContinuePrompt=Ouvrir le navigateur et continuer la connexion? [y/n]: +browserContinueAnswer=y + +termsTitle=Termes et Conditions +termsTitleHtml=Termes et Conditions +termsText=

    Termes et conditions \u00e0 d\u00e9finir

    +termsPlainText=Termes et conditions \u00e0 d\u00e9finir + +recaptchaFailed=Re-captcha invalide +recaptchaNotConfigured=Re-captcha est requis, mais il n''est pas configur\u00e9 +consentDenied=Consentement refus\u00e9. + +noAccount=Nouvel utilisateur ? +username=Nom d''utilisateur +usernameOrEmail=Nom d''utilisateur ou courriel +firstName=Pr\u00e9nom +givenName=Pr\u00e9nom +fullName=Nom complet +lastName=Nom +familyName=Nom de famille +email=Courriel +password=Mot de passe +passwordConfirm=Confirmation du mot de passe +passwordNew=Nouveau mot de passe +passwordNewConfirm=Confirmation du nouveau mot de passe +rememberMe=Se souvenir de moi +authenticatorCode=Code \u00e0 usage unique +address=Adresse +street=Rue +locality=Ville ou Localit\u00e9 +region=\u00c9tat, Province ou R\u00e9gion +postal_code=Code postal +country=Pays +emailVerified=Courriel v\u00e9rifi\u00e9 +gssDelegationCredential=Accr\u00e9ditation de d\u00e9l\u00e9gation GSS + +loginTotpIntro=Il est n\u00e9cessaire de configurer un g\u00e9n\u00e9rateur One Time Password pour acc\u00e9der \u00e0 ce compte +loginTotpStep1=Installez une des applications suivantes sur votre mobile: +loginTotpStep2=Ouvrez l''application et scannez le code-barres ou entrez la clef. +loginTotpStep3=Entrez le code \u00e0 usage unique fourni par l''application et cliquez sur Sauvegarder pour terminer. +loginTotpManualStep2=Ouvrez l''application et saisissez la cl\u00e9 +loginTotpManualStep3=Utilisez la configuration de valeur suivante si l''application permet son \u00e9dition +loginTotpUnableToScan=Impossible de scanner? +loginTotpScanBarcode=Scanner le code barre ? +loginOtpOneTime=Code \u00e0 usage unique +loginTotpType=Type +loginTotpAlgorithm=Algorithme +loginTotpDigits=Chiffres +loginTotpInterval=Intervalle +loginTotpCounter=Compteur + +loginTotp.totp=Bas\u00e9 sur le temps +loginTotp.hotp=Bas\u00e9 sur les compteurs + +oauthGrantRequest=Voulez-vous accorder ces privil\u00e8ges d''acc\u00e8s ? +inResource=dans + +emailVerifyInstruction1=Un courriel avec des instructions \u00e0 suivre vous a \u00e9t\u00e9 envoy\u00e9. +emailVerifyInstruction2=Vous n''avez pas re\u00e7u de code dans le courriel ? +emailVerifyInstruction3=pour renvoyer le courriel. + +emailLinkIdpTitle=Association avec {0} +emailLinkIdp1=Un courriel avec des instructions pour associer le compte {1} sur {0} avec votre compte {2} vous a \u00e9t\u00e9 envoy\u00e9. +emailLinkIdp2=Vous n''avez pas re\u00e7u de code dans le courriel ? +emailLinkIdp3=pour renvoyer le courriel. +emailLinkIdp4=Si vous avez d\u00e9j\u00e0 v\u00e9rifi\u00e9 votre courriel dans un autre navigateur +emailLinkIdp5=pour continuer. + +backToLogin=« Retour \u00e0 la connexion + +emailInstruction=Entrez votre nom d''utilisateur ou votre courriel ; un courriel va vous \u00eatre envoy\u00e9 vous permettant de cr\u00e9er un nouveau mot de passe. +emailInstructionUsername=Entrez votre nom d''utilisateur ; un courriel va vous \u00eatre envoy\u00e9 vous permettant de cr\u00e9er un nouveau mot de passe. + +copyCodeInstruction=Copiez le code et recopiez le dans votre application : + +pageExpiredTitle=La page a expir\u00e9 +pageExpiredMsg1=Pour recommencer le processus d''authentification +pageExpiredMsg2=Pour continuer le processus d''authentification + +personalInfo=Information personnelle : +role_admin=Administrateur +role_realm-admin=Administrateur du domaine +role_create-realm=Cr\u00e9er un domaine +role_create-client=Cr\u00e9er un client +role_view-realm=Voir un domaine +role_view-users=Voir les utilisateurs +role_view-applications=Voir les applications +role_view-clients=Voir les clients +role_view-events=Voir les \u00e9v\u00e9nements +role_view-identity-providers=Voir les fournisseurs d''identit\u00e9 +role_manage-realm=G\u00e9rer le domaine +role_manage-users=G\u00e9rer les utilisateurs +role_manage-applications=G\u00e9rer les applications +role_manage-identity-providers=G\u00e9rer les fournisseurs d''identit\u00e9 +role_manage-clients=G\u00e9rer les clients +role_manage-events=G\u00e9rer les \u00e9v\u00e9nements +role_view-profile=Voir le profil +role_manage-account=G\u00e9rer le compte +role_manage-account-links=G\u00e9rer les liens de compte +role_read-token=Lire le jeton d''authentification +role_offline-access=Acc\u00e8s hors-ligne +client_account=Compte +client_security-admin-console=Console d''administration de la s\u00e9curit\u00e9 +client_admin-cli=Admin CLI +client_realm-management=Gestion du domaine +client_broker=Broker + +invalidUserMessage=Nom d''utilisateur ou mot de passe invalide. +invalidEmailMessage=Courriel invalide. +accountDisabledMessage=Compte d\u00e9sactiv\u00e9, contactez votre administrateur. +accountTemporarilyDisabledMessage=Ce compte est temporairement d\u00e9sactiv\u00e9, contactez votre administrateur ou bien r\u00e9essayez plus tard. +expiredCodeMessage=Connexion expir\u00e9e. Veuillez vous reconnecter. +expiredActionMessage=Action expir\u00e9e. Merci de continuer la connexion. +expiredActionTokenNoSessionMessage=Action expir\u00e9e. +expiredActionTokenSessionExistsMessage=Action expir\u00e9e. Merci de recommencer. + +missingFirstNameMessage=Veuillez entrer votre pr\u00e9nom. +missingLastNameMessage=Veuillez entrer votre nom. +missingEmailMessage=Veuillez entrer votre courriel. +missingUsernameMessage=Veuillez entrer votre nom d''utilisateur. +missingPasswordMessage=Veuillez entrer votre mot de passe. +missingTotpMessage=Veuillez entrer votre code d''authentification. +notMatchPasswordMessage=Les mots de passe ne sont pas identiques. + +invalidPasswordExistingMessage=Mot de passe existant invalide. +invalidPasswordBlacklistedMessage=Mot de passe invalide : ce mot de passe est blacklist\u00e9. +invalidPasswordConfirmMessage=Le mot de passe de confirmation ne correspond pas. +invalidTotpMessage=Le code d''authentification est invalide. + +usernameExistsMessage=Le nom d''utilisateur existe d\u00e9j\u00e0. +emailExistsMessage=Le courriel existe d\u00e9j\u00e0. + +federatedIdentityExistsMessage=L''utilisateur avec {0} {1} existe d\u00e9j\u00e0. Veuillez acc\u00e9der \u00e0 au gestionnaire de compte pour lier le compte. +federatedIdentityEmailExistsMessage=Cet utilisateur avec ce courriel existe d\u00e9j\u00e0. Veuillez vous connecter au gestionnaire de compte pour lier le compte. + +confirmLinkIdpTitle=Ce compte existe d\u00e9j\u00e0 +federatedIdentityConfirmLinkMessage=L''utilisateur {0} {1} existe d\u00e9j\u00e0. Que souhaitez-vous faire ? +federatedIdentityConfirmReauthenticateMessage=Identifiez vous afin de lier votre compte avec {0} +confirmLinkIdpReviewProfile=V\u00e9rifiez vos informations de profil +confirmLinkIdpContinue=Souhaitez-vous lier {0} \u00e0 votre compte existant + +configureTotpMessage=Vous devez configurer l''authentification par mobile pour activer votre compte. +updateProfileMessage=Vous devez mettre \u00e0 jour votre profil pour activer votre compte. +updatePasswordMessage=Vous devez changer votre mot de passe pour activer votre compte. +resetPasswordMessage=Vous devez changer votre mot de passe. +verifyEmailMessage=Vous devez v\u00e9rifier votre courriel pour activer votre compte. +linkIdpMessage=Vous devez v\u00e9rifier votre courriel pour lier votre compte avec {0}. + +emailSentMessage=Vous devriez recevoir rapidement un courriel avec de plus amples instructions. +emailSendErrorMessage=Erreur lors de l''envoi du courriel, veuillez essayer plus tard. + +accountUpdatedMessage=Votre compte a \u00e9t\u00e9 mis \u00e0 jour. +accountPasswordUpdatedMessage=Votre mot de passe a \u00e9t\u00e9 mis \u00e0 jour. + +noAccessMessage=Aucun acc\u00e8s + +invalidPasswordMinLengthMessage=Mot de passe invalide : longueur minimale requise de {0}. +invalidPasswordMinDigitsMessage=Mot de passe invalide : doit contenir au moins {0} chiffre(s). +invalidPasswordMinLowerCaseCharsMessage=Mot de passe invalide : doit contenir au moins {0} lettre(s) en minuscule. +invalidPasswordMinUpperCaseCharsMessage=Mot de passe invalide : doit contenir au moins {0} lettre(s) en majuscule. +invalidPasswordMinSpecialCharsMessage=Mot de passe invalide : doit contenir au moins {0} caract\u00e8re(s) sp\u00e9ciaux. +invalidPasswordNotUsernameMessage=Mot de passe invalide : ne doit pas \u00eatre identique au nom d''utilisateur. +invalidPasswordRegexPatternMessage=Mot de passe invalide : ne valide pas l''expression rationnelle. +invalidPasswordHistoryMessage=Mot de passe invalide : ne doit pas \u00eatre \u00e9gal aux {0} derniers mots de passe. +invalidPasswordGenericMessage=Mot de passe invalide : le nouveau mot de passe ne r\u00e9pond pas \u00e0 la politique de mot de passe. + +failedToProcessResponseMessage=Erreur lors du traitement de la r\u00e9ponse +httpsRequiredMessage=Le protocole HTTPS est requis +realmNotEnabledMessage=Le domaine n''est pas activ\u00e9 +invalidRequestMessage=Requ\u00eate invalide +failedLogout=La d\u00e9connexion a \u00e9chou\u00e9e +unknownLoginRequesterMessage=Compte inconnu du demandeur +loginRequesterNotEnabledMessage=La connexion du demandeur n''est pas active +bearerOnlyMessage=Les applications Bearer-only ne sont pas autoris\u00e9es \u00e0 initier la connexion par navigateur. +standardFlowDisabledMessage=Le client n''est pas autoris\u00e9 \u00e0 initier une connexion avec le navigateur avec ce response_type. Le flux standard est d\u00e9sactiv\u00e9 pour le client. +implicitFlowDisabledMessage=Le client n''est pas autoris\u00e9 \u00e0 initier une connexion avec le navigateur avec ce response_type. Le flux implicite est d\u00e9sactiv\u00e9 pour le client. +invalidRedirectUriMessage=L''URI de redirection est invalide +unsupportedNameIdFormatMessage=NameIDFormat non support\u00e9 +invalidRequesterMessage=Demandeur invalide +registrationNotAllowedMessage=L''enregistrement n''est pas autoris\u00e9 +resetCredentialNotAllowedMessage=La remise \u00e0 z\u00e9ro n''est pas autoris\u00e9e + +permissionNotApprovedMessage=La permission n''est pas approuv\u00e9e. +noRelayStateInResponseMessage=Aucun \u00e9tat de relais dans la r\u00e9ponse du fournisseur d''identit\u00e9. +insufficientPermissionMessage=Permissions insuffisantes pour lier les identit\u00e9s. +couldNotProceedWithAuthenticationRequestMessage=Impossible de continuer avec la requ\u00eate d''authentification vers le fournisseur d''identit\u00e9. +couldNotObtainTokenMessage=Impossible de r\u00e9cup\u00e9rer le jeton du fournisseur d''identit\u00e9. +unexpectedErrorRetrievingTokenMessage=Erreur inattendue lors de la r\u00e9cup\u00e9ration du jeton provenant du fournisseur d''identit\u00e9. +unexpectedErrorHandlingResponseMessage=Erreur inattendue lors du traitement de la r\u00e9ponse provenant du fournisseur d''identit\u00e9. +identityProviderAuthenticationFailedMessage=L''authentification a \u00e9chou\u00e9e. Impossible de s''authentifier avec le fournisseur d''identit\u00e9. +couldNotSendAuthenticationRequestMessage=Impossible d''envoyer la requ\u00eate d''authentification vers le fournisseur d''identit\u00e9. +unexpectedErrorHandlingRequestMessage=Erreur inattendue lors du traitement de la requ\u00eate vers le fournisseur d''identit\u00e9. +invalidAccessCodeMessage=Code d''acc\u00e8s invalide. +sessionNotActiveMessage=La session n''est pas active. +invalidCodeMessage=Une erreur est survenue, veuillez vous reconnecter \u00e0 votre application. +identityProviderUnexpectedErrorMessage=Erreur inattendue lors de l''authentification avec fournisseur d''identit\u00e9. +identityProviderNotFoundMessage=Impossible de trouver le fournisseur d''identit\u00e9 avec cet identifiant. +identityProviderLinkSuccess=Votre compte a \u00e9t\u00e9 correctement li\u00e9 avec {0} compte {1} . +staleCodeMessage=Cette page n''est plus valide, merci de retourner \u00e0 votre application et de vous connecter \u00e0 nouveau. +realmSupportsNoCredentialsMessage=Ce domaine ne supporte aucun type d''accr\u00e9ditation. +identityProviderNotUniqueMessage=Ce domaine autorise plusieurs fournisseurs d''identit\u00e9. Impossible de d\u00e9terminer le fournisseur d''identit\u00e9 avec lequel s''authentifier. +emailVerifiedMessage=Votre courriel a \u00e9t\u00e9 v\u00e9rifi\u00e9. + +staleEmailVerificationLink=Le lien que vous avez cliqu\u00e9 est p\u00e9rim\u00e9 et n''est plus valide. Peut-\u00eatre avez vous d\u00e9j\u00e0 v\u00e9rifi\u00e9 votre mot de passe ? +identityProviderAlreadyLinkedMessage=L''identit\u00e9 f\u00e9d\u00e9r\u00e9e retourn\u00e9e par {0} est d\u00e9j\u00e0 li\u00e9e \u00e0 un autre utilisateur. +confirmAccountLinking=Confirmez la liaison du compte {0} du fournisseur d''entit\u00e9 {1} avec votre compte. +confirmEmailAddressVerification=Confirmez la validit\u00e9 de l''adresse courriel {0}. +confirmExecutionOfActions=Suivez les instructions suivantes + + +backToApplication=« Revenir \u00e0 l''application +missingParameterMessage=Param\u00e8tres manquants \: {0} +clientNotFoundMessage=Client inconnu. +clientDisabledMessage=Client d\u00e9sactiv\u00e9. +invalidParameterMessage=Param\u00e8tre invalide \: {0} +alreadyLoggedIn=Vous \u00eates d\u00e9j\u00e0 connect\u00e9. + +differentUserAuthenticated=Vous \u00eates d\u00e9j\u00e0 authentifi\u00e9 avec un autre utilisateur ''{0}'' dans cette session. Merci de vous d\u00e9connecter. +proceedWithAction=» Cliquez ici + + +requiredAction.CONFIGURE_TOTP=Configurer OTP +requiredAction.terms_and_conditions=Termes et conditions +requiredAction.UPDATE_PASSWORD=Mettre \u00e0 jour votre mot de passe +requiredAction.UPDATE_PROFILE=Mettre \u00e0 jour votre profil +requiredAction.VERIFY_EMAIL=Valider votre adresse email + + +doX509Login=Vous allez \u00eatre connect\u00e9 en tant que\: +clientCertificate=X509 certificat client\: +noCertificate=[Pas de certificat] + + +pageNotFound=Page non trouv\u00e9e +internalServerError=Une erreur interne du serveur s''est produite diff --git a/keycloak-themes/base/login/messages/messages_hu.properties b/keycloak-themes/base/login/messages/messages_hu.properties new file mode 100644 index 0000000..e2d7f3d --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_hu.properties @@ -0,0 +1,354 @@ +# encoding: utf-8 +doLogIn=Belépés +doRegister=Regisztráció +doCancel=Mégsem +doSubmit=Elküld +doBack=Vissza +doYes=Igen +doNo=Nem +doContinue=Folytat +doIgnore=Mellőz +doAccept=Elfogad +doDecline=Elutasít +doForgotPassword=Elfelejtette a jelszavát? +doClickHere=Kattintson ide +doImpersonate=Megszemélyesítés +doTryAgain=Próbálja újra +doTryAnotherWay=Pórbálja máshogyan +kerberosNotConfigured=Nincs beállítva Kerberos +kerberosNotConfiguredTitle=Nincs beállítva Kerberos +bypassKerberosDetail=Vagy nem Kerberosszal lépett be, vagy a böngészője nem kezeli a Kerberos alapú belépést. Kérem kattintson a Folytat gombra, egy másik belépési módhoz. +kerberosNotSetUp=Nincs beállítva Kerberos, nem lehet belépni. +registerTitle=Regisztráció +loginAccountTitle=Jelentkezzen be a fiókjába +loginTitle=Belépés ide: {0} +loginTitleHtml={0} +impersonateTitle={0} megszemélyesített felhasználó +impersonateTitleHtml={0} megszemélyesített felhasználó +realmChoice=Tartomány +unknownUser=Ismeretlen felhasználó +loginTotpTitle=Mobil hitelesítő eszköz beállítása +loginProfileTitle=Felhasználói fiók adatok módosítása +loginTimeout=Belépési kísérlete időtúllépés miatt meghiúsult, a belépési eljárás újraindul. +oauthGrantTitle=Hozzáférés engedélyezése {0}-nak/nek +oauthGrantTitleHtml={0} +errorTitle=Nagyon sajnáljuk... +errorTitleHtml=Nagyon sajnáljuk ... +emailVerifyTitle=Email ellenőrzés +emailForgotTitle=Elfelejtette a jelszavát? +updatePasswordTitle=Jelszó módosítása +codeSuccessTitle=Sikeres kérés kódja +codeErrorTitle=Hibakód\: {0} +displayUnsupported=A kért megjelenítési mód nem támogatott +browserRequired=A belépéshez böngésző szükséges +browserContinue=A belépés befejezéséhez böngésző szükséges +browserContinuePrompt=Megnyitja a böngészőt és folytatja a belépést? [i/n]: +browserContinueAnswer=i + + +termsTitle=Felhasználási feltételek +termsText=

    Felhasználási feltételek helye

    +termsPlainText=Felhasználási feltételek helye + +recaptchaFailed=Érvénytelen Recaptcha +recaptchaNotConfigured=Recaptcha szükséges, de nincsen beállítva +consentDenied=Jóváhagyó nyilatkozat elutasítva. + +noAccount=Új felhasználó? +username=Felhasználó név +usernameOrEmail=Felhasználó név vagy email +firstName=Keresztnév +givenName=Keresztnév +fullName=Teljes név +lastName=Vezetéknév +familyName=Vezetéknév +password=Jelszó +email=Email cím +passwordConfirm=Jelszó megerősítése +passwordNew=Új jelszó +passwordNewConfirm=Új jelszó megerősítése +rememberMe=Automatikus bejelentkezés +authenticatorCode=Egyszer használatos hitelesítő kód +address=Cím +street=Közterület +locality=Település +region=Állam, Tartomány, Megye, Régió +postal_code=Irányítószám +country=Ország +emailVerified=Ellenőrzött email cím +gssDelegationCredential=GSS Delegation Credential + +profileScopeConsentText=Felhasználói fiók +emailScopeConsentText=Email cím +addressScopeConsentText=Cím +phoneScopeConsentText=Telefonszám +offlineAccessScopeConsentText=Offline hozzáférés +samlRoleListScopeConsentText=Szerepköreim +rolesScopeConsentText=Felhasználói szerepkörök +restartLoginTooltip=Belépés újrakezdése +loginTotpIntro=A felhasználói fiók hozzáféréshez be kell állítania egy egyszer használatos jelszót (OTP) generáló alkalmazást. +loginTotpStep1=Kérem telepítse az itt felsorolt alkalmazások egyikét a mobil eszközére: +loginTotpStep2=Indítsa el az alkalmazást a mobil eszközén és olvassa be ezt a (QR) kódot: +loginTotpStep3=Adja meg az alkalmazás által generált egyszer használatos kódot majd kattintson az Elküld gombra a beállítás befejezéséhez. +loginTotpStep3DeviceName=Adja meg a mobil eszköz nevét. Ez a későbbiekben segíthet az eszköz azonosításában. +loginTotpManualStep2=Indítsa el az alkalmazást és adja meg a következő kulcsot: +loginTotpManualStep3=Használja a következő beállításokat, ha az alkalmazása támogatja ezeket: +loginTotpUnableToScan=Nem tud (QR) kódot beolvasni? +loginTotpScanBarcode=Inkább (QR) kódot olvasna be? +loginCredential=Jelszó +loginOtpOneTime=Egyszer használatos kód +loginTotpType=Típus +loginTotpAlgorithm=Algoritmus +loginTotpDigits=Számjegyek +loginTotpInterval=Intervallum +loginTotpCounter=Számláló +loginTotpDeviceName=Eszköz neve + +loginTotp.totp=Idő alapú +loginTotp.hotp=Számláló alapú +loginChooseAuthenticator=Válasszon egy belépési módszert + +oauthGrantRequest=Engedélyezi a következő hozzáférés jogosultságokat? +inResource=Itt: + +emailVerifyInstruction1=A megadott email címre elküldtük az email cím megerősítéséhez szükséges lépéseket tartalmazó üzenetet. +emailVerifyInstruction2=Nem kapott megerősítő kódot tartalmazó email üzenetet? +emailVerifyInstruction3=az ellenőrző kód ismételt kiküldéséhez. + +emailLinkIdpTitle={0} összekötés +emailLinkIdp1=A(z) {1} {0} fiók és a(z) {2} fiókjának összekötéséhez szükséges tudnivalókat email üzenetben elküldtük Önnek. +emailLinkIdp2=Nem kapott megerősítő kódot tartalmazó email üzenetet? +emailLinkIdp3=az ellenőrző kód ismételt kiküldéséhez. +emailLinkIdp4=Ha egy másik böngészőben már jóváhagyta az email címét +emailLinkIdp5=a folytatáshoz. + +backToLogin=« Vissza a belépéshez + +emailInstruction=Adja meg a felhasználó nevét vagy email címét, hogy az új jelszó beállításához szükséges tudnivalókat elküldhessük Önnek. + +copyCodeInstruction=Kérem másolja ki ezt a kódot és illessze be az alkalmazásába: + +pageExpiredTitle=A lap érvényessége lejárt +pageExpiredMsg1=Ahhoz, hogy újrakezdje a belépési eljárást +pageExpiredMsg2=Ahhoz, hogy folytassa a belépési eljárást + +personalInfo=Személyes adatok: +role_admin=Adminisztrátor +role_realm-admin=Tartomány Adminisztrátor +role_create-realm=Tartomány létrehozása +role_create-client=Kliens létrehozása +role_view-realm=Tartományok megtekintése +role_view-users=Felhasználók megtekintése +role_view-applications=Alkalmazások megtekintése +role_view-clients=Kliensek megtekintése +role_view-events=Események megtekintése +role_view-identity-providers=Személyazonosság-kezelők megtekintése +role_view-consent=Jóváhagyó nyilatkozatok megtekintése +role_manage-realm=Tartományok kezelése +role_manage-users=Felhasználók kezelése +role_manage-applications=Alkalmazások kezelése +role_manage-identity-providers=Személyazonosság-kezelők karbantartása +role_manage-clients=Kliensek kezelése +role_manage-events=Események kezelése +role_view-profile=Fiók megtekintése +role_manage-account=Fiók kezelése +role_manage-account-links=Fiók összekötések kezelése +role_manage-consent=Jóváhagyó nyilatkozatok kezelése +role_read-token=Olvasási token +role_offline-access=Offline hozzáférés +role_uma_authorization=Hozzáférés jogosultságokhoz (UMA) +client_account=Fiók +client_account-console=Fiók kezelés +client_security-admin-console=Biztonsági, adminisztrátor fiók kezelés +client_admin-cli=Admin CLI +client_realm-management=Tartomány kezelés +client_broker=Ügynök + +requiredFields=Kötelezően kitöltendő mezők + +invalidUserMessage=Érvénytelen felhasználó név vagy jelszó. +invalidUsernameMessage=Érvénytelen felhasználó név. +invalidUsernameOrEmailMessage=Érvénytelen felhasználó név vagy email cím. +invalidPasswordMessage=Érvénytelen jelszó. +invalidEmailMessage=Érvénytelen email cím. +accountDisabledMessage=Felhasználói fiókja inaktív, kérem vegye fel a kapcsolatot az alkalmazás adminisztrátorral. +accountTemporarilyDisabledMessage=Felhasználói fiókja átmenetileg inaktív, kérem vegye fel a kapcsolatot az alkalmazás adminisztrátorral, vagy próbálkozzon később. +expiredCodeMessage=Belépési időtúllépés, kérem lépjen be újra. +expiredActionMessage=A művelet érvényességi ideje lejárt. Kérem lépjen be újra. +expiredActionTokenNoSessionMessage=A művelet érvényességi ideje lejárt. +expiredActionTokenSessionExistsMessage=A művelet érvényességi ideje lejárt. Kérem ismételje meg a műveletet. + +missingUsernameMessage=Kérem adja meg a felhasználó nevét. +missingFirstNameMessage=Kérem adja meg a keresztnevet. +missingLastNameMessage=Kérem adja meg a vezetéknevet. +missingEmailMessage=Kérem adja meg az email címet. +missingPasswordMessage=Kérem adja meg a jelszót. +missingTotpMessage=Kérem adja meg a hitelesítő kódot. +missingTotpDeviceNameMessage=Kérem adja meg az eszköz nevét. +notMatchPasswordMessage=A jelszavak nem egyeznek meg. + +invalidPasswordExistingMessage=Érvénytelen jelenlegi jelszó. +invalidPasswordBlacklistedMessage=Érvénytelen jelszó: a jelszó tiltó listán szerepel. +invalidPasswordConfirmMessage=A jelszavak nem egyeznek meg. +invalidTotpMessage=Érvénytelen hitelesítő kód. + +usernameExistsMessage=Ez a felhasználó név már foglalt. +emailExistsMessage=Ez az email cím már foglalt. + +federatedIdentityExistsMessage=A megadott {0} {1} felhasználó már létezik. Kérem lépjen be a Keycloak Fiók Kezelőbe, hogy összeköthesse a fiókokat. + +confirmLinkIdpTitle=A felhasználói fiók már létezik +federatedIdentityConfirmLinkMessage=A megadott {0} {1} felhasználó már létezik. Hogyan tovább? +federatedIdentityConfirmReauthenticateMessage=Azonosítsa magát, hogy összeköthesse a felhasználói fiókját a(z) {0}-val/vel. +nestedFirstBrokerFlowMessage=A {0} {1} felhasználó nincs összekötve egyetlen ismert felhasználóval sem. +confirmLinkIdpReviewProfile=Fiók áttekintése +confirmLinkIdpContinue=Hozzáadás meglévő fiókhoz + +configureTotpMessage=Fiókja aktiválásához előbb be kell állítania egy mobil hitelesítő eszközt. +updateProfileMessage=Fiókja aktiválásához előbb módosítania kell a felhasználói adatait. +updatePasswordMessage=Fiókja aktiválásához előbb le kell cserélnie a jelszavát. +resetPasswordMessage=Cserélje le jelszavát! +verifyEmailMessage=Fiókja aktiválásához előbb erősítse meg email címét. +linkIdpMessage=Fiókja összekötéséhez előbb erősítse meg email címét a(z) {0}-val/vel. + +emailSentMessage=Hamarosan email üzenetet küldünk a további tudnivalókról. +emailSendErrorMessage=Az email üzenetet nem tudtuk elküldeni, kérem próbálja meg később. + +accountUpdatedMessage=A felhasználói fiók adatai megváltoztak. +accountPasswordUpdatedMessage=A jelszava megváltozott. + +delegationCompleteHeader=Sikeres belépés +delegationCompleteMessage=Becsukhatja a böngésző ablakot és visszatérhet a konzolos alkalmazásához. +delegationFailedHeader=Sikertelen belépés +delegationFailedMessage=Becsukhatja a böngésző ablakot és visszatérhet a konzolos alkalmazásához, ahol újból megpróbálhat a belépni. + +noAccessMessage=Nincs hozzáférés + +invalidPasswordMinLengthMessage=Érvénytelen jelszó: minimum hossz {0}. +invalidPasswordMinLowerCaseCharsMessage=Érvénytelen jelszó: legalább {0} darab kisbetűt kell tartalmaznia. +invalidPasswordMinDigitsMessage=Érvénytelen jelszó: legalább {0} darab számjegyet kell tartalmaznia. +invalidPasswordMinUpperCaseCharsMessage=Érvénytelen jelszó: legalább {0} darab nagybetűt kell tartalmaznia. +invalidPasswordMinSpecialCharsMessage=Érvénytelen jelszó: legalább {0} darab speciális karaktert (pl. #!$@ stb.) kell tartalmaznia. +invalidPasswordNotUsernameMessage=Érvénytelen jelszó: nem lehet azonos a felhasználó névvel. +invalidPasswordRegexPatternMessage=Érvénytelen jelszó: a jelszó nem illeszkedik a megadott reguláris kifejezés mintára. +invalidPasswordHistoryMessage=Érvénytelen jelszó: nem lehet azonos az utolsó {0} darab, korábban alkalmazott jelszóval. +invalidPasswordGenericMessage=Érvénytelen jelszó: az új jelszó nem felel meg a jelszó házirendnek. + +failedToProcessResponseMessage=A válasz üzenet feldolgozása nem sikerült. +httpsRequiredMessage=HTTPS protokoll használata kötelező. +realmNotEnabledMessage=A tartomány inaktív. +invalidRequestMessage=Érvénytelen kérés. +failedLogout=A kilépés sikertelen. +unknownLoginRequesterMessage=A belépést kérelmező ismeretlen. +loginRequesterNotEnabledMessage=A belépést kérelmező inaktív. +bearerOnlyMessage=Bearer-only alkalmazások nem kezdeményezhetnek böngésző alapú beléptetést. +standardFlowDisabledMessage=Ez a kliens nem kezdeményezhet böngésző alapú beléptetést a megadott válasz típussal. A standard belépési eljárás (flow) tiltott a kliensen. +implicitFlowDisabledMessage=Ez a kliens nem kezdeményezhet böngésző alapú beléptetést a megadott válasz típussal. Az implicit belépési eljárás (flow) tiltott a kliensen. +invalidRedirectUriMessage=Érvénytelen átirányítási cím (URI) +unsupportedNameIdFormatMessage=Nem támogatott NameIDFormat +invalidRequesterMessage=Érvénytelen kérelmező +registrationNotAllowedMessage=A felhasználó regisztráció tiltott. +resetCredentialNotAllowedMessage=A jelszó visszaállítás tiltott. + +permissionNotApprovedMessage=A jogosultság nincsen jóváhagyva. +noRelayStateInResponseMessage=Nincsen "relay state" a személyazonosság-kezelő válaszüzenetében. +insufficientPermissionMessage=Nincs elég jogosultság a fiókok összekötéséhez. +couldNotProceedWithAuthenticationRequestMessage=A személyazonosság-kezelő felé indított hitelesítési kérés sikertelen. +couldNotObtainTokenMessage=Nem sikerült tokent igényelni a személyazonosság-kezelőtől. +unexpectedErrorRetrievingTokenMessage=Váratlan hiba történt a személyazonosság-kezelő token igénylése közben. +unexpectedErrorHandlingResponseMessage=Váratlan hiba történt a személyazonosság-kezelő válaszüzenetének feldolgozása közben. +identityProviderAuthenticationFailedMessage=Nem sikerült a személyazonosság-kezelőn keresztül intézett hitelesítés. +couldNotSendAuthenticationRequestMessage=Nem sikerült a személyazonosság-kezelőhöz intézett hitelesítés kérés elküldése. +unexpectedErrorHandlingRequestMessage=Váratlan hiba történt a személyazonosság-kezelő hitelesítés kérés feldolgozása közben. +invalidAccessCodeMessage=Érvénytelen hozzáférési kód. +sessionNotActiveMessage=A munkamenet inaktív. +invalidCodeMessage=Hiba történt, kérem lépjen be újra az alkalmazásán keresztül. +identityProviderUnexpectedErrorMessage=Váratlan hiba történt a személyazonosság-kezelőn keresztül intézett hitelesítés során. +identityProviderNotFoundMessage=A megadott azonosítóval személyazonosság-kezelő nem található. +identityProviderLinkSuccess=Sikeresen megerősítette email címét. Kérem térjen vissza az eredeti böngészőjébe, és onnan folytassa a belépési eljárást. +staleCodeMessage=Ez a lap már nem érvényes, kérem térjen vissza az alkalmazásába és lépjen be ismét. +realmSupportsNoCredentialsMessage=Ez a tartomány nem támogat jelszó alapú azonosítást. +credentialSetupRequired=Belépés sikertelen, jelszó beállítás szükséges. +identityProviderNotUniqueMessage=Ez a tartomány több személyazonosság-kezelőt támogat. Nem sikerült meghatározni, hogy melyik személyazonosság-kezelőt kellene a hitelesítéshez alkalmazni. +emailVerifiedMessage=Az email címét megerősítettük. +staleEmailVerificationLink=Az a hivatkozás, amelyikre rákattintott elévült és érvényét vesztette. Talán már korábban megerősítette az email címét? +identityProviderAlreadyLinkedMessage=A(z) {0}-tól/től visszakapott összekapcsolt személyazonosság már össze van kötve egy másik felhasználói fiókkal. +confirmAccountLinking=Erősítse meg a(z) {0} személyazonosság-kezelő {1} fiókjának összekötését a felhasználói fiókjával. +confirmEmailAddressVerification=Erősítse meg a(z) {0} email cím érvényességét. +confirmExecutionOfActions=Hajtsa végre a következő művelet(ek)et + +backToApplication=« Vissza az alkalmazásba +missingParameterMessage=Hiányzó paraméterek\: {0} +clientNotFoundMessage=A kliens nem található. +clientDisabledMessage=A kliens inaktív. +invalidParameterMessage=Érvénytelen paraméter\: {0} +alreadyLoggedIn=Már korábban belépett. +differentUserAuthenticated=Ebben a munkamenetben már korábban belépett ''{0}'' felhasználó névvel. Kérem előbb lépjen ki a munkamenetből. +brokerLinkingSessionExpired=Ügynök fiók összekötést kezdeményezett, de az aktuális munkamenete már érvénytelen. +proceedWithAction=» Kattintson ide a folytatáshoz + +requiredAction.CONFIGURE_TOTP=Egyszer használatos jelszó (OTP) beállítása +requiredAction.terms_and_conditions=Felhasználási feltételek +requiredAction.UPDATE_PASSWORD=Jelszó csere +requiredAction.UPDATE_PROFILE=Fiók adatok módosítása +requiredAction.VERIFY_EMAIL=Email cím megerősítése + +doX509Login=Beléptetés mint\: +clientCertificate=X509 kliens tanúsítvány\: +noCertificate=[Nincs tanúsítvány] + +pageNotFound=A kért lap nem található +internalServerError=Belső hiba történt + +console-username=Felhasználó név: +console-password=Jelszó: +console-otp=Egyszer használatos jelszó (OTP): +console-new-password=Új jelszó: +console-confirm-password=Jelszó megerősítés: +console-update-password=Cserélje le jelszavát. +console-verify-email=Meg kell erősítenie az email címét. Email üzenetet küldtünk a(z) {0} email címre amely egy ellenőrző, megerősítő, kódot tartalmaz. Kérem írja be a kapott kódot a lenti beviteli mezőbe. +console-email-code=Email üzenetben kapott ellenőrző kód: +console-accept-terms=Elfogadja a felhasználási feltételeket? [i/n]: +console-accept=i + +# Openshift messages +openshift.scope.user_info=Felhasználó adatok +openshift.scope.user_check-access=Felhasználó hozzáférés adatok +openshift.scope.user_full=Teljes hozzáférés +openshift.scope.list-projects=Projektek listája + +# SAML authentication +saml.post-form.title=Hitelesítés átirányítás +saml.post-form.message=Átirányítás folyamatban, kérem várjon. +saml.post-form.js-disabled=A JavaScript nincs engedélyezve. A folytatás előtt ajánlott bekapcsolni a JavaScript támogatást. Kattintson a lenti gombra a folytatáshoz. + +#authenticators +otp-display-name=Hitelesítő alkalmazás +otp-help-text=Adja meg az ellenőrző kódot a hitelesítő alkalmazásból +password-display-name=Jelszó +password-help-text=Lépjen be a jelszava megadásával +auth-username-form-display-name=Felhasználó név +auth-username-form-help-text=Kezdje meg a belépést a felhasználó nevének megadásával +auth-username-password-form-display-name=Felhasználó név és jelszó +auth-username-password-form-help-text=Lépjen be a felhasználó neve és jelszava megadásával. + +# WebAuthn +webauthn-display-name=Biztonsági kulcs +webauthn-help-text=Használja a biztonsági kulcsát a belépéshez. +webauthn-passwordless-display-name=Biztonsági kulcs +webauthn-passwordless-help-text=Használja a biztonsági kulcsát a jelszómentes belépéshez. +webauthn-login-title=Biztonsági kulcs alapú belépés +webauthn-registration-title=Biztonsági kulcs regisztráció +webauthn-available-authenticators=Elérhető hitelesítő alkalmazások + +# WebAuthn Error +webauthn-error-title=Biztonsági kulcs hiba +webauthn-error-registration=Nem sikerült regisztrálni a biztonsági kulcsot. +webauthn-error-api-get=Nem sikerült a hitelesítés a biztonsági kulccsal. +webauthn-error-different-user=Az először hitelesített felhasználó nem az, akit a biztonsági kulccsal azonosítottunk. +webauthn-error-auth-verification=A biztonsági kulcs alapú hitelesítés eredménye érvénytelen. +webauthn-error-register-verification=A biztonsági kulcs alapú regisztráció eredménye érvénytelen. +webauthn-error-user-not-found=Ismeretlen felhasználót hitelesítettünk a biztonsági kulcs alapján. + +identity-provider-redirector=Összekötés másik személyazonosság-kezelővel +identity-provider-login-label=Egyéb bejelentkezési módok diff --git a/keycloak-themes/base/login/messages/messages_it.properties b/keycloak-themes/base/login/messages/messages_it.properties new file mode 100644 index 0000000..ca2cbdb --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_it.properties @@ -0,0 +1,352 @@ +doLogIn=Accedi +doRegister=Registrati +doCancel=Annulla +doSubmit=Invia +doBack=Indietro +doYes=S\u00ec +doNo=No +doContinue=Continua +doIgnore=Ignora +doAccept=Accetta +doDecline=Nega +doForgotPassword=Password dimenticata? +doClickHere=Clicca qui +doImpersonate=Impersona +doTryAgain=Prova ancora +doTryAnotherWay=Prova in un altro modo +kerberosNotConfigured=Kerberos non configurato +kerberosNotConfiguredTitle=Kerberos non configurato +bypassKerberosDetail=Non sei connesso via Kerberos o il tuo browser non supporta l''autenticazione a Kerberos. Fai clic su Continua per accedere in modo alternativo. +kerberosNotSetUp=Kerberos non \u00e8 configurato. Non puoi effettuare l''accesso. +registerTitle=Registrati +loginTitle=Accedi a {0} +loginTitleHtml={0} +impersonateTitle={0} Impersona utente +impersonateTitleHtml={0} Impersona utente +realmChoice=Realm +unknownUser=Utente sconosciuto +loginTotpTitle=Configura autenticazione mobile +loginProfileTitle=Aggiorna profilo +loginTimeout=Stai impiegando troppo tempo per accedere. Il processo di autenticazione verr\u00e0 riavviato. +oauthGrantTitle=Autenticazione concessa +oauthGrantTitleHtml={0} +errorTitle=Siamo spiacenti\u2026 +errorTitleHtml=Siamo spiacenti... +emailVerifyTitle=Verifica l''email +emailForgotTitle=Password dimenticata? +updatePasswordTitle=Aggiorna password +codeSuccessTitle=Codice di successo +codeErrorTitle=Codice di errore\: {0} +displayUnsupported=Tipo display richiesto non supportato +browserRequired=\u00c8 richiesto il browser per il login +browserContinue=\u00c8 richiesto il browser per continuare il login +browserContinuePrompt=Aprire il browser per continuare il login? [y/n]: +browserContinueAnswer=y + + +termsTitle=Termini e condizioni +termsText=

    Termini e condizioni da definire

    +termsPlainText=Termini e condizioni da definire. + +recaptchaFailed=Recaptcha non valido +recaptchaNotConfigured=Il Recaptcha \u00e8 obbligatorio, ma non configurato +consentDenied=Permesso negato. + +noAccount=Nuovo utente? +username=Username +usernameOrEmail=Username o email +firstName=Nome +givenName=Nome +fullName=Nome completo +lastName=Cognome +familyName=Cognome +email=Email +password=Password +passwordConfirm=Conferma password +passwordNew=Nuova Password +passwordNewConfirm=Conferma nuova password +rememberMe=Ricordami +authenticatorCode=Codice One-time +address=Indirizzo +locality=Citt\u00E0 o Localit\u00e0 +street=Via +region=Stato, Provincia, o Regione +postal_code=CAP +country=Paese +emailVerified=Email verificata +gssDelegationCredential=Credenziali delega GSS + +profileScopeConsentText=Profilo utente +emailScopeConsentText=Indirizzo email +addressScopeConsentText=Indirizzo +phoneScopeConsentText=Numero di telefono +offlineAccessScopeConsentText=Accesso offline +samlRoleListScopeConsentText=I miei ruoli +rolesScopeConsentText=Ruoli utente + +restartLoginTooltip=Riavvia login + +loginTotpIntro=Devi impostare un generatore di OTP (password temporanea valida una volta sola) per accedere a questo account +loginTotpStep1=Installa una delle seguenti applicazioni sul tuo dispositivo mobile +loginTotpStep2=Apri l''applicazione e scansiona il codice QR +loginTotpStep3=Scrivi il codice monouso fornito dall''applicazione e premi Invia per completare il setup +loginTotpStep3DeviceName=Fornisci il nome del dispositivo per aiutarti a gestire i dispositivi di autenticazione. +loginTotpManualStep2=Apri l''applicazione e scrivi la chiave +loginTotpManualStep3=Usa le seguenti impostazioni se l''applicazione lo consente +loginTotpUnableToScan=Non riesci a scansionare il codice QR? +loginTotpScanBarcode=Vuoi scansionare il codice QR? +loginCredential=Credenziali +loginOtpOneTime=Codice monouso +loginTotpType=Tipo +loginTotpAlgorithm=Algoritmo +loginTotpDigits=Cifre +loginTotpInterval=Intervallo +loginTotpCounter=Contatore +loginTotpDeviceName=Nome del dispositivo di autenticazione + +loginTotp.totp=Basato sull''ora +loginTotp.hotp=Basato sul contatore + +loginChooseAuthenticator=Seleziona il tuo metodo di autenticazione + +oauthGrantRequest=Vuoi assegnare questi privilegi di accesso? +inResource=per + +emailVerifyInstruction1=Ti \u00e8 stata inviata una email con le istruzioni per la verifica della tua email. +emailVerifyInstruction2=Non hai ricevuto un codice di verifica nella tua email? +emailVerifyInstruction3=per rinviare la email. + +emailLinkIdpTitle=Collega {0} +emailLinkIdp1=Ti \u00e8 stata inviata una email con le istruzioni per collegare l''account {0} {1} con il tuo account {2}. +emailLinkIdp2=Non hai ricevuto un codice di verifica nella tua email? +emailLinkIdp3=Per rinviare la email. +emailLinkIdp4=Se hai gi\u00e0 verificato l''indirizzo email in un altro browser +emailLinkIdp5=per continuare. + +backToLogin=« Torna al Login + +emailInstruction=Inserisci la tua username o l''indirizzo email e ti manderemo le istruzioni per creare una nuova password. + +copyCodeInstruction=Copia questo codice e incollalo nella tua applicazione: + +pageExpiredTitle=La pagina \u00e8 scaduta +pageExpiredMsg1=Per ripetere il login +pageExpiredMsg2=Per continuare con il login + +personalInfo=Informazioni personali: +role_admin=Admin +role_realm-admin=Realm Admin +role_create-realm=Crea realm +role_create-client=Crea client +role_view-realm=Visualizza realm +role_view-users=Visualizza utenti +role_view-applications=Visualizza applicazioni +role_view-clients=Visualizza client +role_view-events=Visualizza eventi +role_view-identity-providers=Visualizza identity provider +role_manage-realm=Gestisci realm +role_manage-users=Gestisci utenti +role_manage-applications=Gestisci applicazioni +role_manage-identity-providers=Gestisci identity provider +role_manage-clients=Gestisci client +role_manage-events=Gestisci eventi +role_view-profile=Visualizza profilo +role_manage-account=Gestisci account +role_manage-account-links=Gestisci i link per l''account +role_read-token=Leggi il token +role_offline-access=Accesso offline +client_account=Account +client_account-console=Console account +client_security-admin-console=Console di amministrazione di sicurezza +client_admin-cli=Admin CLI +client_realm-management=Gestione realm +client_broker=Broker + +requiredFields=Campi obbligatori + +invalidUserMessage=Username o password non validi. +invalidUsernameMessage=Username non valido. +invalidUsernameOrEmailMessage=Username o email non validi. +invalidPasswordMessage=Password non valida. +invalidEmailMessage=Indirizzo email non valido. +accountDisabledMessage=L''account \u00e8 disabilitato, contatta il tuo amministratore. +accountTemporarilyDisabledMessage=L''account \u00e8 temporaneamente disabilitato; contatta il tuo amministratore o prova pi\u00f9 tardi. +expiredCodeMessage=Login scaduto. Riprovare. +expiredActionMessage=Azione scaduta. Continuare adesso con in login. +expiredActionTokenNoSessionMessage=Azione scaduta. +expiredActionTokenSessionExistsMessage=Azione scaduta. Ricominciare. + +missingFirstNameMessage=Inserisci il nome. +missingLastNameMessage=Inserisci il cognome. +missingEmailMessage=Inserisci l''email. +missingUsernameMessage=Inserisci l''username. +missingPasswordMessage=Inserisci la password. +missingTotpMessage=Inserisci il codice di autenticazione. +missingTotpDeviceNameMessage=Inserisci il nome del dispositivo di autenticazione. +notMatchPasswordMessage=Le password non coincidono. + +invalidPasswordExistingMessage=Password esistente non valida. +invalidPasswordBlacklistedMessage=Password non valida: la password non \u00e8 consentita. +invalidPasswordConfirmMessage=La password di conferma non coincide. +invalidTotpMessage=Codice di autenticazione non valido. + +usernameExistsMessage=Username gi\u00e0 esistente. +emailExistsMessage=Email gi\u00e0 esistente. + +federatedIdentityExistsMessage=L''utente con {0} {1} esiste gi\u00e0. Effettua il login nella gestione account per associare l''account. + +confirmLinkIdpTitle=Account gi\u00e0 esistente +federatedIdentityConfirmLinkMessage=L''utente con {0} {1} esiste gi\u00e0. Come vuoi procedere? +federatedIdentityConfirmReauthenticateMessage=Autenticati per associare il tuo account con {0} +confirmLinkIdpReviewProfile=Rivedi profilo +confirmLinkIdpContinue=Aggiungi all''account esistente + +configureTotpMessage=Devi impostare un autenticatore per attivare il tuo account. +updateProfileMessage=Devi aggiornare il tuo profilo utente per attivare il tuo account. +updatePasswordMessage=Devi cambiare la password per attivare il tuo account. +resetPasswordMessage=Devi cambiare la password. +verifyEmailMessage=Devi verificare il tuo indirizzo email per attivare il tuo account. +linkIdpMessage=Devi verificare il tuo indirizzo email per associare il tuo account con {0}. + +emailSentMessage=Riceverai a breve una email con maggiori istruzioni. +emailSendErrorMessage=Invio email fallito, riprova pi\u00f9 tardi. + +accountUpdatedMessage=Il tuo account \u00e8 stato aggiornato. +accountPasswordUpdatedMessage=La tua password \u00e8 stata aggiornata. + +delegationCompleteHeader=Login completato +delegationCompleteMessage=Puoi chiudere questa finestra del browser e tornare alla tua applicazione. +delegationFailedHeader=Login fallito +delegationFailedMessage=Puoi chiudere questa finestra del browser e tornare alla tua applicazione per provare ad accedere nuovamente. + +noAccessMessage=Nessun accesso + +invalidPasswordMinLengthMessage=Password non valida: lunghezza minima {0}. +invalidPasswordMinDigitsMessage=Password non valida: deve contenere almeno {0} numeri. +invalidPasswordMinLowerCaseCharsMessage=Password non valida: deve contenere almeno {0} caratteri minuscoli. +invalidPasswordMinUpperCaseCharsMessage= Password non valida: deve contenere almeno {0} caratteri maiuscoli. +invalidPasswordMinSpecialCharsMessage= Password non valida: deve contenere almeno {0} caratteri speciali. +invalidPasswordNotUsernameMessage=Password non valida: non deve essere uguale alla username. +invalidPasswordRegexPatternMessage=Password non valida: fallito il match con una o pi\u00f9 espressioni regolari. +invalidPasswordHistoryMessage=Password non valida: non deve essere uguale ad una delle ultime {0} password. +invalidPasswordGenericMessage=Password non valida: la nuova password non rispetta le indicazioni previste. + +failedToProcessResponseMessage=Fallimento nell''elaborazione della risposta +httpsRequiredMessage=HTTPS richiesto +realmNotEnabledMessage=Realm non abilitato +invalidRequestMessage=Richiesta non valida +failedLogout=Logout fallito +unknownLoginRequesterMessage=Richiedente di Login non riconosciuto +loginRequesterNotEnabledMessage=Richiedente di Login non abilitato +bearerOnlyMessage=Alle applicazioni di tipo Bearer-only non \u00e8 consentito di effettuare il login tramite browser +standardFlowDisabledMessage=Al client non \u00e8 consentito di effettuare il login tramite browser con questo response_type. Standard flow \u00e8 stato disabilitato per il client. +implicitFlowDisabledMessage=Al client non \u00e8 consentito di effettuare il login tramite browser con questo response_type. Implicit flow \u00e8 stato disabilitato per il client. +invalidRedirectUriMessage=Redirect uri non valido +unsupportedNameIdFormatMessage=NameIDFormat non supportato +invalidRequesterMessage=Richiedente non valido +registrationNotAllowedMessage=Registrazione non permessa +resetCredentialNotAllowedMessage=Reimpostazione della credenziale non permessa + +permissionNotApprovedMessage=Permesso non approvato. +noRelayStateInResponseMessage=Nessun relay state in risposta dall''identity provider. +insufficientPermissionMessage=Permessi insufficienti per associare le identit\u00e0. +couldNotProceedWithAuthenticationRequestMessage=Impossibile procedere con la richiesta di autenticazione all''identity provider +couldNotObtainTokenMessage=Non posso ottenere un token dall''identity provider. +unexpectedErrorRetrievingTokenMessage=Errore inaspettato nel recupero del token dall''identity provider. +unexpectedErrorHandlingResponseMessage=Errore inaspettato nella gestione della risposta dall''identity provider. +identityProviderAuthenticationFailedMessage=Autenticazione fallita. Non posso effettuare l''autenticazione con l''identity provider. +couldNotSendAuthenticationRequestMessage=Impossibile inviare la richiesta di autenticazione all''identity provider. +unexpectedErrorHandlingRequestMessage=Errore inaspettato nella gestione della richiesta di autenticazione all''identity provider. +invalidAccessCodeMessage=Codice di accesso non valido. +sessionNotActiveMessage=Sessione non attiva. +invalidCodeMessage=Si \u00e8 verificato un errore, effettua di nuovo il login nella tua applicazione. +identityProviderUnexpectedErrorMessage=Errore imprevisto durante l''autenticazione con identity provider +identityProviderNotFoundMessage=Non posso trovare un identity provider con l''identificativo. +identityProviderLinkSuccess=Hai verificato con successo la tua email. Torna al tuo browser iniziale e continua da l\u00ec con il login. +staleCodeMessage=Questa pagina non \u00e8 pi\u00f9 valida, torna alla tua applicazione ed effettua nuovamente l''accesso +realmSupportsNoCredentialsMessage=Il realm non supporta nessun tipo di credenziali. +credentialSetupRequired=Impossibile effettuare il login, \u00e8 richiesto il setup delle credenziali. +identityProviderNotUniqueMessage=Il realm supporta pi\u00f9 di un identity provider. Impossibile determinare quale identity provider deve essere utilizzato per autenticarti. +emailVerifiedMessage=Il tuo indirizzo email \u00e8 stato verificato. +staleEmailVerificationLink=Il link che hai cliccato \u00e8 un link scaduto e non \u00e8 pi\u00f9 valido. Forse hai gi\u00e0 verificato la tua email? +identityProviderAlreadyLinkedMessage=L''identit\u00e0 federata restituita dall''identity provider {0} \u00e8 gi\u00e0 associata ad un altro utente. +confirmAccountLinking=Conferma il collegamento per l''account {0} dell''identity provider {1} con il tuo account. +confirmEmailAddressVerification=Conferma la validit\u00e0 dell''indirizzo email {0}. +confirmExecutionOfActions=Esegui la/le seguenti azione/i +locale_it=Italiano + +backToApplication=« Torna all''applicazione +missingParameterMessage=Parametri mancanti\: {0} +clientNotFoundMessage=Client non trovato. +clientDisabledMessage=Client disabilitato. +invalidParameterMessage=Parametro non valido\: {0} +alreadyLoggedIn=Sei gi\u00e0 connesso. +differentUserAuthenticated=Se gi\u00e0 autenticato con l''utente ''{0}'' in questa sessione. Per favore, fai prima il logout. +brokerLinkingSessionExpired=\u00c8 stato richiesta un''associazione a un account broker, ma la sessione corrente non \u00e8 pi\u00f9 valida. +proceedWithAction=» Clicca qui per continuare + +requiredAction.CONFIGURE_TOTP=Configura OTP +requiredAction.terms_and_conditions=Termini e condizioni +requiredAction.UPDATE_PASSWORD=Aggiornamento password +requiredAction.UPDATE_PROFILE=Aggiornamento profilo +requiredAction.VERIFY_EMAIL=Verifica dell''indirizzo email + +doX509Login=Sarai connesso come\: +clientCertificate=Certificato client X509\: +noCertificate=[Nessun certificato] + + +pageNotFound=Pagina non trovata +internalServerError=Si \u00e8 verificato un errore interno del server + +console-username=Username: +console-password=Password: +console-otp=One-time password: +console-new-password=Nuova password: +console-confirm-password=Conferma password: +console-update-password=\u00c8 richiesto l''aggiornamento della tua password. +console-verify-email=Devi verificare il tuo indirizzo email. \u00c8 stata inviata una email a {0} che contiene un codice di verifica. Per favore inserisci il codice nella casella di testo seguente. +console-email-code=Codice email: +console-accept-terms=Accetti i termini? [y/n]: +console-accept=y + +# Openshift messages +openshift.scope.user_info=Informazioni utente +openshift.scope.user_check-access=Informazioni di accesso per l''utente +openshift.scope.user_full=Accesso completo +openshift.scope.list-projects=Elenca i progetti + +# SAML authentication +saml.post-form.title=Reindirizzamento per l''autenticazione +saml.post-form.message=Reindirizzamento, attendere per favore. +saml.post-form.js-disabled=JavaScript \u00e8 disabilitato. \u00c8 fortemente consigliato abilitarlo. Clicca sul bottone seguente per continuare. + +#authenticators +otp-display-name=Applicazione di autenticazione +otp-help-text=Inserire un codice di verifica fornito dall''applicazione di autenticazione. +password-display-name=Password +password-help-text=Accedi inserendo la tua password. +auth-username-form-display-name=Username +auth-username-form-help-text=Inizia il login inserendo la tua username +auth-username-password-form-display-name=Username e password +auth-username-password-form-help-text=Accedi inserendo la tua username e la password. + +# WebAuthn +webauthn-display-name=Chiave di sicurezza +webauthn-help-text=Utilizza la tua chiave di sicurezza per accedere. +webauthn-passwordless-display-name=Chiave di sicurezza +webauthn-passwordless-help-text=Utilizza la tua chiave di sicurezza per l''accesso senza password. +webauthn-login-title=Login con chiave di sicurezza +webauthn-registration-title=Registrazione chiave di sicurezza +webauthn-available-authenticators=Autenticatori disponibili + +# WebAuthn Error +webauthn-error-title=Errore della chiave di sicurezza +webauthn-error-registration=Impossibile registrare la tua chiave di sicurezza. +webauthn-error-api-get=Autenticazione con la chiave di sicurezza fallita. +webauthn-error-different-user=Il primo utente autenticato non \u00e8 quello autenticato tramite la chiave di sicurezza. +webauthn-error-auth-verification=Il risultato dell''autenticazione con la chiave di sicurezza non \u00e8 valido. +webauthn-error-register-verification=Il risultato della registrazione della chiave di sicurezza non \u00e8 valido. +webauthn-error-user-not-found=Utente sconosciuto autenticato con la chiave di sicurezza. + +identity-provider-redirector=Connettiti con un altro identity provider. diff --git a/keycloak-themes/base/login/messages/messages_ja.properties b/keycloak-themes/base/login/messages/messages_ja.properties new file mode 100644 index 0000000..eef9925 --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_ja.properties @@ -0,0 +1,354 @@ +# encoding: utf-8 +doLogIn=ログイン +doRegister=登録 +doCancel=キャンセル +doSubmit=送信 +doBack=戻る +doYes=はい +doNo=いいえ +doContinue=続ける +doIgnore=無視 +doAccept=承諾 +doDecline=却下 +doForgotPassword=パスワードをお忘れですか? +doClickHere=クリックしてください +doImpersonate=代理ログイン +doTryAgain=再試行してください +doTryAnotherWay=別の方法を試してください +kerberosNotConfigured=Kerberosは設定されていません +kerberosNotConfiguredTitle=Kerberosは設定されていません +bypassKerberosDetail=Kerberosでログインしていないか、ブラウザーでKerberosログインの設定がされていません。他の手段でログインするには「続ける」をクリックしてください。 +kerberosNotSetUp=Kerberosが設定されていません。ログインできません。 +registerTitle=登録 +loginAccountTitle=アカウントにログイン +loginTitle={0}にログイン +loginTitleHtml={0} +impersonateTitle={0}ユーザーの代理 +impersonateTitleHtml={0}ユーザーの代理 +realmChoice=レルム +unknownUser=不明なユーザー +loginTotpTitle=モバイル・オーセンティケーターのセットアップ +loginProfileTitle=アカウント情報の更新 +loginTimeout=ログイン試行がタイムアウトしました。ログインは最初から開始されます。 +oauthGrantTitle={0}へのアクセスを許可 +oauthGrantTitleHtml={0} +errorTitle=申し訳ございません +errorTitleHtml=申し訳ございません +emailVerifyTitle=Eメール確認 +emailForgotTitle=パスワードをお忘れですか? +updatePasswordTitle=パスワードの更新 +codeSuccessTitle=成功コード +codeErrorTitle=エラーコード\: {0} +displayUnsupported=要求された表示タイプがサポートされていません +browserRequired=ログインに必要なブラウザー +browserContinue=ログインを完了するために必要なブラウザー +browserContinuePrompt=ブラウザーを開いてログインを続行しますか? [y/n]: +browserContinueAnswer=y + + +termsTitle=利用規約 +termsText=

    利用規約はここで設定する必要があります

    +termsPlainText=定義される利用規約。 + +recaptchaFailed=無効なreCAPTCHA +recaptchaNotConfigured=reCAPTCHAが必須ですが、設定されていません +consentDenied=同意が拒否されました。 + +noAccount=新規ユーザーですか? +username=ユーザー名 +usernameOrEmail=ユーザー名またはメールアドレス +firstName=名 +givenName=名 +fullName=氏名 +lastName=姓 +familyName=姓 +email=Eメール +password=パスワード +passwordConfirm=パスワード(確認) +passwordNew=新しいパスワード +passwordNewConfirm=新しいパスワード(確認) +rememberMe=ログイン状態の保存 +authenticatorCode=ワンタイムコード +address=住所 +street=番地 +locality=市区町村 +region=都道府県 +postal_code=郵便番号 +country=国 +emailVerified=確認済みEメール +gssDelegationCredential=GSS委譲クレデンシャル + +profileScopeConsentText=ユーザー・プロファイル +emailScopeConsentText=メールアドレス +addressScopeConsentText=アドレス +phoneScopeConsentText=電話番号 +offlineAccessScopeConsentText=オフライン・アクセス +samlRoleListScopeConsentText=ロール +rolesScopeConsentText=ユーザーロール + +restartLoginTooltip=ログインを再開 + +loginTotpIntro=このアカウントにアクセスするには、ワンタイム・パスワード・ジェネレーターを設定する必要があります +loginTotpStep1=次のいずれかのアプリケーションをモバイルにインストールします。 +loginTotpStep2=アプリケーションを開き、バーコードをスキャンします。 +loginTotpStep3=アプリケーションから提供されたワンタイムコードを入力し、送信をクリックしてセットアップを終了します。 +loginTotpStep3DeviceName=OTPデバイスの管理に役立つデバイス名を指定します。 +loginTotpManualStep2=アプリケーションを開き、キーを入力します: +loginTotpManualStep3=アプリケーションで設定できる場合は、次の設定値を使用します。 +loginTotpUnableToScan=スキャンできませんか? +loginTotpScanBarcode=バーコードをスキャンしますか? +loginCredential=クレデンシャル +loginOtpOneTime=ワンタイムコード +loginTotpType=タイプ +loginTotpAlgorithm=アルゴリズム +loginTotpDigits=桁 +loginTotpInterval=間隔 +loginTotpCounter=カウンター +loginTotpDeviceName=デバイス名 + +loginTotp.totp=時間ベース +loginTotp.hotp=カウンターベース + +loginChooseAuthenticator=ログイン方法を選択してください + +oauthGrantRequest=これらのアクセス権限を付与しますか? +inResource=in + +emailVerifyInstruction1=メールアドレスを確認する手順を記載したEメールを送信しました。 +emailVerifyInstruction2=Eメールで確認コードを受け取っていませんか? +emailVerifyInstruction3=Eメールを再送信します。 + +emailLinkIdpTitle=リンク {0} +emailLinkIdp1={0}の{1}アカウントをあなたの{2}アカウントとリンクするための手順を記載したEメールを送信しました。 +emailLinkIdp2=Eメールで確認コードを受け取っていませんか? +emailLinkIdp3=Eメールを再送信します。 +emailLinkIdp4=別のブラウザーでメールを確認済みの場合 +emailLinkIdp5=続けるには + +backToLogin=« ログインに戻る + +emailInstruction=ユーザー名またメールアドレスを入力してください。新しいパスワードの設定方法をご案内いたします。 + +copyCodeInstruction=このコードをコピーし、あなたのアプリケーションにペーストしてください: + +pageExpiredTitle=ページの有効期限が切れています +pageExpiredMsg1=ログインプロセスを再開するには +pageExpiredMsg2=ログイン処理を続行するには + +personalInfo=個人情報: +role_admin=管理者 +role_realm-admin=レルム管理者 +role_create-realm=レルムの作成 +role_create-client=クライアントの作成 +role_view-realm=レルムの参照 +role_view-users=ユーザーの参照 +role_view-applications=アプリケーションの参照 +role_view-clients=クライアントの参照 +role_view-events=イベントの参照 +role_view-identity-providers=アイデンティティー・プロバイダーの参照 +role_manage-realm=レルムの管理 +role_manage-users=ユーザーの管理 +role_manage-applications=アプリケーションの管理 +role_manage-identity-providers=アイデンティティー・プロバイダーの管理 +role_manage-clients=クライアントの管理 +role_manage-events=イベントの管理 +role_view-profile=プロファイルの参照 +role_manage-account=アカウントの管理 +role_manage-account-links=アカウントリンクの管理 +role_read-token=トークンの参照 +role_offline-access=オフライン・アクセス +client_account=アカウント +client_account-console=アカウント・コンソール +client_security-admin-console=セキュリティー管理コンソール +client_admin-cli=管理CLI +client_realm-management=レルム管理 +client_broker=ブローカー + +requiredFields=必須フィールド + +invalidUserMessage=無効なユーザー名またはパスワードです。 +invalidUsernameMessage=ユーザー名が無効です。 +invalidUsernameOrEmailMessage=ユーザー名またはメールアドレスが無効です。 +invalidPasswordMessage=パスワードが無効です。 +invalidEmailMessage=無効なメールアドレスです。 +accountDisabledMessage=アカウントが無効です。管理者に連絡してください。 +accountTemporarilyDisabledMessage=アカウントが一時的に無効です。管理者に連絡するか、しばらく時間をおいてから再度お試しください。 +expiredCodeMessage=ログイン・タイムアウトが発生しました。再度ログインしてください。 +expiredActionMessage=アクションは期限切れです。今すぐログインしてください。 +expiredActionTokenNoSessionMessage=アクションは期限切れです。 +expiredActionTokenSessionExistsMessage=アクションは期限切れです。もう一度やり直してください。 + +missingFirstNameMessage=名を指定してください。 +missingLastNameMessage=姓を指定してください。 +missingEmailMessage=Eメールを指定してください。 +missingUsernameMessage=ユーザー名を指定してください。 +missingPasswordMessage=パスワードを指定してください。 +missingTotpMessage=オーセンティケーター・コードを指定してください。 +missingTotpDeviceNameMessage=デバイス名を指定してください。 +notMatchPasswordMessage=パスワードが一致していません。 + +invalidPasswordExistingMessage=既存のパスワードが不正です。 +invalidPasswordBlacklistedMessage=無効なパスワード: パスワードがブラックリストに含まれています。 +invalidPasswordConfirmMessage=パスワード確認が一致していません。 +invalidTotpMessage=無効なオーセンティケーター・コードです。 + +usernameExistsMessage=既に存在するユーザー名です。 +emailExistsMessage=既に存在するEメールです。 + +federatedIdentityExistsMessage={0}{1}のユーザーは既に存在します。そのアカウントをリンクするにはアカウント管理にログインしてください。 + +confirmLinkIdpTitle=既に存在するアカウントです。 +federatedIdentityConfirmLinkMessage={0}{1}のユーザーは既に存在します。継続しますか? +federatedIdentityConfirmReauthenticateMessage={1}でアカウントをリンクするために{0}として認証します +nestedFirstBrokerFlowMessage={0}ユーザー{1}は既知のユーザーにリンクされていません。 +confirmLinkIdpReviewProfile=プロファイルの確認 +confirmLinkIdpContinue=既存のアカウントに追加する + +configureTotpMessage=アカウントを有効にするにはモバイル・オーセンティケーターのセットアップが必要です。 +updateProfileMessage=アカウントを有効にするにはユーザー・プロファイルの更新が必要です。 +updatePasswordMessage=アカウントを有効にするにはパスワードの更新が必要です。 +resetPasswordMessage=パスワードを変更する必要があります。 +verifyEmailMessage=アカウントを有効にするにはメールアドレスの確認が必要です。 +linkIdpMessage=アカウントを{0}とリンクするにはメールアドレスの確認が必要です。 + +emailSentMessage=詳細な手順を記載したEメールをすぐに受信してください。 +emailSendErrorMessage=Eメールの送信に失敗しました。しばらく時間をおいてから再度お試しください。 + +accountUpdatedMessage=アカウントが更新されました。 +accountPasswordUpdatedMessage=パスワードが更新されました。 + +delegationCompleteHeader=ログインに成功しました +delegationCompleteMessage=このブラウザーのウィンドウを閉じて、コンソール・アプリケーションに戻ることができます。 +delegationFailedHeader=ログインに失敗しました +delegationFailedMessage=このブラウザー・ウィンドウを閉じてコンソール・アプリケーションに戻り、再度ログインを試みることができます。 + +noAccessMessage=アクセスがありません + +invalidPasswordMinLengthMessage=無効なパスワード: 最小{0}の長さが必要です。 +invalidPasswordMinDigitsMessage=無効なパスワード: 少なくとも{0}文字の数字を含む必要があります。 +invalidPasswordMinLowerCaseCharsMessage=無効なパスワード: 少なくとも{0}文字の小文字を含む必要があります。 +invalidPasswordMinUpperCaseCharsMessage=無効なパスワード: 少なくとも{0}文字の大文字を含む必要があります。 +invalidPasswordMinSpecialCharsMessage=無効なパスワード: 少なくとも{0}文字の特殊文字を含む必要があります。 +invalidPasswordNotUsernameMessage=無効なパスワード: ユーザー名と同じパスワードは禁止されています。 +invalidPasswordRegexPatternMessage=無効なパスワード: 正規表現パターンと一致しません。 +invalidPasswordHistoryMessage=無効なパスワード: 最近の{0}パスワードのいずれかと同じパスワードは禁止されています。 +invalidPasswordGenericMessage=無効なパスワード: 新しいパスワードはパスワード・ポリシーと一致しません。 + +failedToProcessResponseMessage=応答を処理できませんでした +httpsRequiredMessage=HTTPSが必須です +realmNotEnabledMessage=レルムが有効ではありません +invalidRequestMessage=無効なリクエストです +failedLogout=ログアウトに失敗しました +unknownLoginRequesterMessage=不明なログイン要求元です +loginRequesterNotEnabledMessage=ログイン要求元は有効ではありません +bearerOnlyMessage=bearer-onlyのアプリケーションはブラウザー・ログインを開始することが許可されていません +standardFlowDisabledMessage=与えられたresponse_typeでクライアントはブラウザー・ログインを開始することが許可されていません。標準フローは無効です。 +implicitFlowDisabledMessage=与えられたresponse_typeでクライアントはブラウザー・ログインを開始することが許可されていません。インプリシット・フローは無効です。 +invalidRedirectUriMessage=無効なリダイレクトURIです +unsupportedNameIdFormatMessage=サポートされていないNameID Formatです +invalidRequesterMessage=無効な要求元です +registrationNotAllowedMessage=登録は許可されていません +resetCredentialNotAllowedMessage=クレデンシャルのリセットは許可されていません + +permissionNotApprovedMessage=パーミッションは承認されていません。 +noRelayStateInResponseMessage=アイデンティティー・プロバイダーからの応答にRelayStateがありません。 +insufficientPermissionMessage=アイデンティティーにリンクするには不十分なパーミッションです。 +couldNotProceedWithAuthenticationRequestMessage=アイデンティティー・プロバイダーへの認証リクエストを続行できませんでした。 +couldNotObtainTokenMessage=アイデンティティー・プロバイダーからトークンを取得できませんでした。 +unexpectedErrorRetrievingTokenMessage=アイデンティティー・プロバイダーからのトークン取得で予期せぬエラーが発生しました。 +unexpectedErrorHandlingResponseMessage=アイデンティティー・プロバイダーからの応答を処理する際に予期せぬエラーが発生しました。 +identityProviderAuthenticationFailedMessage=認証に失敗しました。アイデンティティー・プロバイダーを使用して認証できませんでした。 +couldNotSendAuthenticationRequestMessage=アイデンティティー・プロバイダーに認証リクエストを送信することができませんでした。 +unexpectedErrorHandlingRequestMessage=アイデンティティー・プロバイダーへの認証リクエストを処理する際に予期せぬエラーが発生しました。 +invalidAccessCodeMessage=無効なアクセスコードです。 +sessionNotActiveMessage=セッションが有効ではありません。 +invalidCodeMessage=エラーが発生しました。アプリケーションを介して再度ログインしてください。 +identityProviderUnexpectedErrorMessage=アイデンティティー・プロバイダーによる認証の際に予期せぬエラーが発生しました +identityProviderNotFoundMessage=該当の識別子を持つアイデンティティー・プロバイダーが見つかりませんでした。 +identityProviderLinkSuccess=Eメールを正常に確認しました。元のブラウザーに戻ってログインしてください。 +staleCodeMessage=このページはもはや有効ではありませんので、アプリケーションに戻り再度ログインしてください +realmSupportsNoCredentialsMessage=レルムはクレデンシャル・タイプをサポートしていません。 +credentialSetupRequired=ログインできません。クレデンシャルのセットアップが必要です。 +identityProviderNotUniqueMessage=レルムは複数のアイデンティティー・プロバイダーをサポートしています。どのアイデンティティー・プロバイダーが認証に使用されるべきか判断できませんでした。 +emailVerifiedMessage=メールアドレスが確認できました。 +staleEmailVerificationLink=クリックしたリンクは古いリンクであり、有効ではありません。おそらく、すでにメールを確認しています。 +identityProviderAlreadyLinkedMessage={0}によって返された連携済みアイデンティティーは、すでに別のユーザーにリンクされています。 +confirmAccountLinking=アイデンティティー・プロバイダー{1}のアカウント{0}とあなたのアカウントとのリンクを確認してください。 +confirmEmailAddressVerification=Eメールアドレス{0}の有効性を確認してください。 +confirmExecutionOfActions=次の操作を実行します。 + +backToApplication=« アプリケーションに戻る +missingParameterMessage=不足パラメーター\: {0} +clientNotFoundMessage=クライアントが見つかりません。 +clientDisabledMessage=クライアントが無効になっています。 +invalidParameterMessage=無効なパラメーター\: {0} +alreadyLoggedIn=既にログインしています。 +differentUserAuthenticated=すでにこのセッションで異なるユーザー''{0}''として認証されています。まずログアウトしてください。 +brokerLinkingSessionExpired=要求されたブローカー・アカウントのリンクは、現在のセッションでは有効ではありません。 +proceedWithAction=» 続行するにはここをクリックしてください + +requiredAction.CONFIGURE_TOTP=OTPの設定 +requiredAction.terms_and_conditions=利用規約 +requiredAction.UPDATE_PASSWORD=パスワードの更新 +requiredAction.UPDATE_PROFILE=プロファイルの更新 +requiredAction.VERIFY_EMAIL=Eメールの確認 + +doX509Login=次のユーザーとしてログインします\: +clientCertificate=X509クライアント証明書\: +noCertificate=[証明書なし] + + +pageNotFound=ページが見つかりません +internalServerError=内部サーバーエラーが発生しました + +console-username=ユーザー名: +console-password=パスワード: +console-otp=ワンタイム・パスワード: +console-new-password=新しいパスワード: +console-confirm-password=パスワードの確認: +console-update-password=パスワードの更新が必要です。 +console-verify-email=メールアドレスを確認する必要があります。確認コードを含むメールを{0}に送信しました。このコードを以下に入力してください。 +console-email-code=Eメールコード: +console-accept-terms=利用規約に同意しますか? [y/n]: +console-accept=y + +# Openshift messages +openshift.scope.user_info=ユーザー情報 +openshift.scope.user_check-access=ユーザーアクセス情報 +openshift.scope.user_full=フルアクセス +openshift.scope.list-projects=プロジェクトの一覧表示 + +# SAML authentication +saml.post-form.title=認証リダイレクト +saml.post-form.message=リダイレクトしています。お待ちください。 +saml.post-form.js-disabled=JavaScriptが無効になっています。有効にすることを強くお勧めします。継続するには、下のボタンをクリックしてください。 + +#authenticators +otp-display-name=オーセンティケーター・アプリケーション +otp-help-text=オーセンティケーター・アプリケーションから取得した確認コードを入力してください。 +password-display-name=パスワード +password-help-text=パスワードを入力してログインします。 +auth-username-form-display-name=ユーザー名 +auth-username-form-help-text=ユーザー名を入力してログインを開始します +auth-username-password-form-display-name=ユーザー名とパスワード +auth-username-password-form-help-text=ユーザー名とパスワードを入力してログインしてください。 + +# WebAuthn +webauthn-display-name=セキュリティーキー +webauthn-help-text=セキュリティーキーを使用してログインしてください。 +webauthn-passwordless-display-name=セキュリティーキー +webauthn-passwordless-help-text=パスワードレス・ログインにセキュリティーキーを使用します。 +webauthn-login-title=セキュリティーキー・ログイン +webauthn-registration-title=セキュリティーキーの登録 +webauthn-available-authenticators=利用可能なオーセンティケーター + +# WebAuthn Error +webauthn-error-title=セキュリティーキー・エラー +webauthn-error-registration=セキュリティーキーを登録できませんでした。 +webauthn-error-api-get=セキュリティーキーによる認証に失敗しました。 +webauthn-error-different-user=最初に認証されたユーザーは、セキュリティーキーによって認証されたユーザーではありません。 +webauthn-error-auth-verification=セキュリティーキーの認証結果が無効です。 +webauthn-error-register-verification=セキュリティーキーの登録結果が無効です。 +webauthn-error-user-not-found=セキュリティーキーで認証された不明なユーザー。 + +identity-provider-redirector=別のアイデンティティー・プロバイダーと接続する \ No newline at end of file diff --git a/keycloak-themes/base/login/messages/messages_lt.properties b/keycloak-themes/base/login/messages/messages_lt.properties new file mode 100644 index 0000000..9181b8e --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_lt.properties @@ -0,0 +1,216 @@ +# encoding: utf-8 +doLogIn=Prisijungti +doRegister=Registruotis +doCancel=Atšaukti +doSubmit=Patvirtinti +doYes=Taip +doNo=Ne +doContinue=Tęsti +doAccept=Patvirtinti +doDecline=Atšaukti +doForgotPassword=Pamiršote slaptažodį? +doClickHere=Spauskite čia +doImpersonate=Apsimesti kaip +kerberosNotConfigured=Kerberos nesukonfigūruotas +kerberosNotConfiguredTitle=Kerberos nesukonfigūruotas +bypassKerberosDetail=Jūs neprisijungęs per Kerberos arba Jūsų naršyklė nesukonfigūruota Kerberos prisijungimui. Tęskite ir pasirinkite kitą prisijungimo būdą +kerberosNotSetUp=Kerberos nesukonfigūruotas. Jūs negalite prisijungti. +registerWithTitle=Registruotis su {0} +registerWithTitleHtml={0} +loginTitle=Prisijungti su {0} +loginTitleHtml={0} +impersonateTitle=Apsimesti kaip naudotojas {0} +impersonateTitleHtml=Apsimesti kaip {0} +realmChoice=Sritis +unknownUser=Nežinomas naudotojas +loginTotpTitle=Mobilaus autentifikatoriaus nustatymas +loginProfileTitle=Atnaujinti paskyros informaciją +loginTimeout=Užtrukote per ilgai. Prisijungimo procesas pradedamas iš naujo. +oauthGrantTitle=Suteitikti prieigą +oauthGrantTitleHtml={0} +errorTitle=Atsiprašome ... +errorTitleHtml=Atsiprašome ... +emailVerifyTitle=El. pašto adreso patvirtinimas +emailForgotTitle=Pamiršote slaptažodį? +updatePasswordTitle=Atnaujinti slaptažodį +codeSuccessTitle=Sėkmė +codeErrorTitle=Klaidos kodas\: {0} + +termsTitle=Naudojimo sąlygos +termsTitleHtml=Naudojimo sąlygos +termsText=

    Naudojimo sąlygos nenurodytos

    + +recaptchaFailed=Recaptcha neteisingas +recaptchaNotConfigured=Reikalingas Recaptcha nesukonfigūruotas +consentDenied=Prieiga draudžiama. + +noAccount=Dar neturite paskyros? +username=Naudotojo vardas +usernameOrEmail=Naudotojo vardas arba el. pašto adresas +firstName=Vardas +givenName=Vardas +fullName=Pavardė +lastName=Pavardė +familyName=Pavardė +email=El. paštas +password=Slaptažodis +passwordConfirm=Pakartotas slaptažodis +passwordNew=Naujas slaptažodis +passwordNewConfirm=Pakartotas naujas slaptažodis +rememberMe=Prisiminti mane +authenticatorCode=Vienkartinis kodas +address=Adresas +street=Gatvė +locality=Miestas arba vietovė +region=Rajonas +postal_code=Pašto kodas +country=Šalis +emailVerified=El. pašto adresas patvirtintas +gssDelegationCredential=GSS prisijungimo duomenų delegavimas + +loginTotpStep1=Įdiekite FreeOTP arba Google Authenticator savo įrenginyje. Programėlės prieinamos Google Play ir Apple App Store. +loginTotpStep2=Atidarykite programėlę ir nuskenuokite barkodą arba įveskite kodą. +loginTotpStep3=Įveskite programėlėje sugeneruotą vieną kartą galiojantį kodą ir paspauskite Saugoti norėdami prisijungti. +loginOtpOneTime=Vienkartinis kodas + +oauthGrantRequest=Ar Jūs suteikiate šias prieigos teises? +inResource=į + +emailVerifyInstruction1=El. paštas su instrukcijomis ir patvirtinimo nuoroda nusiųsti į Jūsų el. paštą. +emailVerifyInstruction2=El. paštu negavote patvirtinimo kodo? +emailVerifyInstruction3=pakartotoinai siųsti el. laišką. + +emailLinkIdpTitle=Susieti {0} +emailLinkIdp1=El. pašto laiškas su instrukcijomis susieti {0} paskyrą {1} su {2} buvo nusiųstas. +emailLinkIdp2=Negavote patvirtinimo kodo el. paštu? +emailLinkIdp3=pakartotoinai siųsti el. laišką. + +backToLogin=« Grįžti į prisijungimo langą + +emailInstruction=Įveskite naudotojo vardą arba slaptažodį ir slaptažodžio pakeitimo instrukcijos bus atsiųstos Jums el. paštu + +copyCodeInstruction=Nukopijuokite šį kodą į Jūsų programą: + +personalInfo=Asmeninė informacija: +role_admin=Administratorius +role_realm-admin=Srities administravimas +role_create-realm=Kurti sritį +role_create-client=Kurti programą +role_view-realm=Peržiūrėti sritį +role_view-users=Peržiūrėti naudotojus +role_view-applications=Peržiūrėti programas +role_view-clients=Peržiūrėti klientines programas +role_view-events=Peržiūrėti įvykių žurnalą +role_view-identity-providers=Peržiūrėti tapatybės teikėjus +role_manage-realm=Valdyti sritis +role_manage-users=Valdyti naudotojus +role_manage-applications=Valdyti programas +role_manage-identity-providers=Valdyti tapatybės teikėjus +role_manage-clients=Valdyti programas +role_manage-events=Valdyti įvykius +role_view-profile=Peržiūrėti paskyrą +role_manage-account=Valdyti paskyrą +role_read-token=Skaityti prieigos rakšą +role_offline-access=Darbas neprisijungus +client_account=Paskyra +client_security-admin-console=Saugumo administravimo konsolė +client_admin-cli=Administravimo CLI +client_realm-management=Srities valdymas +client_broker=Tarpininkas + +invalidUserMessage=Neteisingas naudotojo vardas arba slaptažodis. +invalidEmailMessage=Neteisingas el. pašto adresas. +accountDisabledMessage=Paskyros galiojimas sustabdytas, kreipkitės į administratorių. +accountTemporarilyDisabledMessage=Paskyros galiojimas laikinai sustabdytas. Kreipkitės į administratorių arba pabandykite vėliau. +expiredCodeMessage=Prisijungimo laikas baigėsi. Bandykite dar kartą. + +missingFirstNameMessage=Prašome įvesti vardą. +missingLastNameMessage=Prašome įvesti pavardę. +missingEmailMessage=Prašome įvesti el. pašto adresą. +missingUsernameMessage=Prašome įvesti naudotojo vardą. +missingPasswordMessage=Prašome įvesti slaptažodį. +missingTotpMessage=Prašome įvesti autentifikacijos kodą. +notMatchPasswordMessage=Slaptažodžiai nesutampa. + +invalidPasswordExistingMessage=Neteisingas dabartinis slaptažodis. +invalidPasswordConfirmMessage=Pakartotas slaptažodis nesutampa. +invalidTotpMessage=Neteisingas autentifikacijos kodas. + +usernameExistsMessage=Toks naudotojas jau egzistuoja. +emailExistsMessage=El. pašto adresas jau egzistuoja. + +federatedIdentityExistsMessage=Naudotojas {0} {1} jau egzistuoja. Prašome prsijungti prie naudotojų valdymo posistemės paskyrų susiejimui. + +confirmLinkIdpTitle=Paskyra jau egzistuoja +federatedIdentityConfirmLinkMessage=Naudotojas {0} {1} jau egzistuoja. Ar tęsti? +federatedIdentityConfirmReauthenticateMessage=Prisijunkite norėdami susieti paskyrą su {0} +confirmLinkIdpReviewProfile=Peržiūrėti naudotojo profilio informaciją +confirmLinkIdpContinue=Susieti su egzistuojančia paskyra + +configureTotpMessage=Paskyros aktyvavimui Jums reikalingas Mobilus autentifikatorius. +updateProfileMessage=Paskyros aktyvavimui Jums reikia atnaujinti profilio informaciją. +updatePasswordMessage=Paskyros aktyvavimui Jums reikia pakeisti slaptažodį. +verifyEmailMessage=Paskyros aktyvavimui Jums reikia patvirtinti el. pašto adresą. +linkIdpMessage=El. pašto adreso susiejimui su Jūsu paskyra {0} reikalingas patvirtinimas. + +emailSentMessage=Netrukus turėtumėte gauti el. pašto adresą su instrukcijomis. +emailSendErrorMessage=Klaida siunčiant el. paštą, bandykite vėliau. + +accountUpdatedMessage=Jųsų paskyros informacija atnaujinta. +accountPasswordUpdatedMessage=Jūsų slaptažodis pakeistas. + +noAccessMessage=Prieiga negalima + +invalidPasswordMinLengthMessage=Neteisingas slaptažodis: privalomi bent {0} simboliai. +invalidPasswordMinDigitsMessage=Neteisingas slaptažodis: privalomi bent {0} skaitmenys. +invalidPasswordMinLowerCaseCharsMessage=Neteisingas slaptažodis: privalomos bent {0} mažosios raidės. +invalidPasswordMinUpperCaseCharsMessage=Neteisingas slaptažodis: privalomos bent {0} didžiosios raidės. +invalidPasswordMinSpecialCharsMessage=Neteisingas slaptažodis: privalomi bent {0} specialūs simboliai. +invalidPasswordNotUsernameMessage=Neteisingas slaptažodis: negali sutapti su naudotojo vardu. +invalidPasswordRegexPatternMessage=Neteisingas slaptažodis: neatitinka regexp taisyklės. +invalidPasswordHistoryMessage=Neteisingas slaptažodis: negali sutapti su prieš tai naudotais {0} slaptažodžiais. + +failedToProcessResponseMessage=Klaida apdorojant atsakymą +httpsRequiredMessage=Privalomas HTTPS +realmNotEnabledMessage=Srities galiojimas išjungtas +invalidRequestMessage=Neteisinga užklausa +failedLogout=Nepavyko užbaigti sesijos +unknownLoginRequesterMessage=Nežinomas prisijungimo prašytojas +loginRequesterNotEnabledMessage=Prisijungimo prašytojo galiojimas išjungtas +bearerOnlyMessage=Programos, sukonfigūruotos tik kaip perdavėjai, negali inicijuoti prisijungimą per naršyklę. +standardFlowDisabledMessage=Su pateiktu atsakymo tipu prisijungimas per naršyklę šiam klientui negalimas. Šiam klientui neįgalinta standartinė seka. +implicitFlowDisabledMessage=Su pateiktu atsakymo tipu prisijungimas per naršyklę šiam klientui negalimas. Šiam klientui neįgalinta išreikštinė seka. +invalidRedirectUriMessage=Neteisinga nukreipimo nuoroda +unsupportedNameIdFormatMessage=Nepalaikomas NameIDFormat +invalidRequesterMessage=Neteisingas prašytojas +registrationNotAllowedMessage=Registracija negalima +resetCredentialNotAllowedMessage=Prisijungimo duomenų atkūrimas negalimas + +permissionNotApprovedMessage=Teisį nepatvirtinta. +noRelayStateInResponseMessage=Tapatybės teikėjo atsakyme trūksta perdavimo būsenos. +insufficientPermissionMessage=Trūksta teisių tapatybių susiejimui. +couldNotProceedWithAuthenticationRequestMessage=Nepavyksta pradėti tapatybės teikėjo autentifikacijos užklausos. +couldNotObtainTokenMessage=Negaunamas prieigos raktas iš tapatybės teikėjo. +unexpectedErrorRetrievingTokenMessage=Prieigos rakšo gavimo iš tapatybės teikėjo metu įvyko netikėta klaida. +unexpectedErrorHandlingResponseMessage=Tapatybės teikėjo atsakymo apdorojimo metu įvyko netikėta klaida. +identityProviderAuthenticationFailedMessage=Autentifikacijos klaida. Nepavyksta autentifikacija su tapatybės teikėju. +couldNotSendAuthenticationRequestMessage=Tapatybės teikėjui nepavyksta nusiųsti autentifikacijos užklausos. +unexpectedErrorHandlingRequestMessage=Užklausos tapatybės teikėjui formavimo metu įvyko netikėta klaida. +invalidAccessCodeMessage=Neteisingas prieigos kodas. +sessionNotActiveMessage=Sesija neaktyvi. +invalidCodeMessage=Įvyko klaida. Prašome bandyti prisijungti dar kartą. +identityProviderUnexpectedErrorMessage=Autentifikavimo su išoriniu tapatybės teikėju metu įvyko netikėta klaida. +identityProviderNotFoundMessage=Su nurodytu identifikatoriumi nerastas tapatybės teikėjas. +identityProviderLinkSuccess=Jūsų naudotojo paskyra buvo sėkmingai susieta su {0} paskyra {1} . +staleCodeMessage=Šis puslapis nebegalioja. Prašome grįžti į programą ir bandyti prisijungti iš naujo. +realmSupportsNoCredentialsMessage=Sritis nepalaiko prisijungimų naudojant prisijungimo duomenis. +identityProviderNotUniqueMessage=Sritis palaiko daugiau nei vieną tapatybės teikėją. Negalima nustatyti kuris tapatybės teikėjas turi būti naudojamas autentifikacijai. +emailVerifiedMessage=Jūsų el. pašto adresas patvirtintas. +staleEmailVerificationLink=Nuoroda, kurią paspaudėte nebegalioja? Galbūt Jūs jau patvirtinote el. pašto adresą? + +backToApplication=« Grįžti į programą +missingParameterMessage=Nenurodytas parametras\: {0} +clientNotFoundMessage=Nenurodytas klientas. +clientDisabledMessage=Kliento galiojimas išjungtas. +invalidParameterMessage=Neteisingas parametras\: {0} +alreadyLoggedIn=Jūs jau esate prisijungę. diff --git a/keycloak-themes/base/login/messages/messages_lv.properties b/keycloak-themes/base/login/messages/messages_lv.properties new file mode 100644 index 0000000..4520e62 --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_lv.properties @@ -0,0 +1,254 @@ +# encoding: utf-8 +doLogIn=Pieslēgties +doRegister=Reģistrēties +doCancel=Atcelt +doSubmit=Iesniegt +doBack=Atpakaļ +doYes=Jā +doNo=Nē +doContinue=Turpināt +doIgnore=Ignorēt +doAccept=Pieņemt +doDecline=Atteikties +doForgotPassword=Aizmirsāt paroli? +doClickHere=Spiediet šeit +doImpersonate=Uzdoties +doTryAgain=Mēģināt vēlreiz +doTryAnotherWay=Mēģināt citā veidā +doConfirmDelete=Apstiprināt dzēšanu +errorDeletingAccount=Kļūda dzēšot kontu +deletingAccountForbidden=Jums nav piešķirtas atļaujas sava konta dzēšanai, sazinieties ar administratoru. +kerberosNotConfigured=Kerberos nav konfigurēts +kerberosNotConfiguredTitle=Kerberos nav konfigurēts +bypassKerberosDetail=Jūs neesat pieslēdzies izmantojot Kerberos vai jūsu pārlūks nav iestatīts Kerberos autentifikācijai. Spiediet turpināt, lai pieslēgtos citā veidā +kerberosNotSetUp=Kerberos nav uzstādīts. Jūs nevarat pieslēgties. +registerTitle=Reģistrācija +loginAccountTitle=Pieslēgties savam kontam +loginTitle=Pieslēgties {0} +loginTitleHtml={0} +impersonateTitle={0} uzdoties par lietotāju +impersonateTitleHtml={0} uzdoties par lietotāju +realmChoice=Realm +unknownUser=Nezināms lietotājs +loginTotpTitle=Mobilā autentifikatora uzstādīšana +loginProfileTitle=Atjaunot profila informāciju +loginIdpReviewProfileTitle=Atjaunot konta informācija +loginTimeout=Jūs pārāk ilgi pieslēdzaties. Pieslēgšanās process tiks sākts no jauna. +oauthGrantTitle=Piešķirt atļauju {0} +oauthGrantTitleHtml={0} +errorTitle=Notikusi kļūme... +errorTitleHtml=Notikusi kļūme ... +emailVerifyTitle=E-pasta apstiprināšana +emailForgotTitle=Aizmirsāt paroli? +updatePasswordTitle=Atjaunot paroli +codeSuccessTitle=Kods +codeErrorTitle=Kļūdas kods\: {0} +displayUnsupported=Pieprasītais attēlošanas veids netiek atbalstīts +browserRequired=Nepieciešama pieslēgšanās caur pārlūku +browserContinue=Nepieciešama pieslēgšanās caur pārlūku, lai turpinātu autentifikāciju +browserContinuePrompt=Vai atvērt pārlūku lai turpinātu pieslēgšanos? [y/n]: +browserContinueAnswer=y + + +termsTitle=Noteikumi un nosacījumi +termsText=

    Noteikumi un nosacījumi jānosaka

    +termsPlainText=Noteikumi un nosacījumi jānosaka + +recaptchaFailed=Nekorekts Recaptcha +recaptchaNotConfigured=Recaptcha ir obligāts, bet nav uzstādīts +consentDenied=Piekrišana liegta. + +noAccount=Jauns lietotājs? +username=Lietotājvārds +usernameOrEmail=Lietotājvārds vai e-pasts +firstName=Vārds +givenName=Vārds +fullName=Pilns vārds +lastName=Uzvārds +familyName=Uzvārds +email=E-pasts +password=Parole +passwordConfirm=Parole atkārtoti +passwordNew=Jauna parole +passwordNewConfirm=Jauna parole atkārtoti +rememberMe=Atcerēties mani +authenticatorCode=Vienreizējā parole +address=Adrese +street=Iela +locality=Pilsēta +region=Novads vai reģions +postal_code=Pasta indegs +country=Valsts +emailVerified=E-pasts apstiprināts +website=Tīmekļa vietne +phoneNumber=Tālruņa numurs +phoneNumberVerified=Tālruņa numurs apstiprināts +gender=Dzimums +birthday=Dzimšanas datums +zoneinfo=Laika josla +gssDelegationCredential=GSS delegācijas atslēga +logoutOtherSessions=Atteikties no visām ierīcēm + +profileScopeConsentText=Lietotāja profils +emailScopeConsentText=E-pasta adrese +addressScopeConsentText=Adrese +phoneScopeConsentText=Tālrunis +offlineAccessScopeConsentText=Bezsaustes piekļuve +samlRoleListScopeConsentText=Manas lomas +rolesScopeConsentText=Lietotāju lomas + +restartLoginTooltip=Atkārtot pieslēgšanos + + +emailVerifyInstruction1=E-pasts ar instrukcijām e-pasta apstiprināšanai ir nosūtīts +emailVerifyInstruction2=Nesaņēmāt apsiptināšanas kodu savā e-pastā? +emailVerifyInstruction3=lai atkārtoti nosūtītu e-pastu. + +emailLinkIdpTitle=Saistīt {0} +emailLinkIdp1=E-pasts ar instrukcijām, lai saistītu {0} kontu {1} ar savu {2} kontu ir nosūtīts. +emailLinkIdp2=Nesaņēmāt apsiptināšanas kodu savā e-pastā? +emailLinkIdp3=lai atkārtoti nosūtītu e-pastu. +emailLinkIdp4=Ja jūs jau apstiprinājāt e-pastu citā pārlūkā +emailLinkIdp5=lai turpinātu. + +backToLogin=« Atpakaļ uz pieslēgšanos + +emailInstruction=Ievadiet lietotājvārdu vai e-pasta adresi un mēs nosūtīsim jums instrukcijas kā izveidot jaunu paroli. + +copyCodeInstruction=Lūdzu nokopējiet šo kodu un ielīmējiet savā lietojumprogrammā: + +pageExpiredTitle=Lapa ir beigusies +pageExpiredMsg1=Lai atsāktu pieslēgšanās procesu +pageExpiredMsg2=Lai turpinātu pieslēgšanās procesu + +personalInfo=Personiskā informācija: +role_admin=Administrators +role_realm-admin=Realm administrators +role_create-realm=Izveidot realm +role_view-realm=Skatīt realm +role_view-users=Skatīt lietoājus +role_view-applications=Skatīt lietojumprogrammas +role_view-clients=Skatīt klientus +role_view-events=Skatīt notikumus +role_view-identity-providers=Skatīt identitātes sniedzējus +role_manage-realm=Pārvaldīt realm +role_manage-users=Pārvaldīt lietotājus +role_manage-applications=Pārvaldīt lietojumprogrammas +role_manage-identity-providers=Pārvaldīt identitātes sniedzējus +role_manage-clients=Pārvaldīt klientus +role_manage-events=Pārvaldīt notikumus +role_view-profile=Skatīt profilu +role_manage-account=Pārvaldīt kontu +role_manage-account-links=Pārvaldīt konta saites +role_read-token=Lasīt talonu (token) +role_offline-access=Bezsaistes piekļuve +role_uma_authorization=Iegūt atļaujas +client_account=Konts +client_security-admin-console=Drošības administrācijas konsole +client_admin-cli=Administrācijas CLI +client_realm-management=Realm pārvaldība +client_broker=Brokeris + +invalidUserMessage=Nekorekts lietotājvārds vai parole. +invalidEmailMessage=Nekorekta e-pasta adrese. +accountDisabledMessage=Konts ir atspējots, sazinieties ar administratoru. +accountTemporarilyDisabledMessage=Konts ir uz laiku atspējots, sazinieties ar administratoru vai mēģiniet vēlāk. +expiredCodeMessage=Pieslēgšanās noilgums. Lūdzu pieslēdzieties atkārtoti. +expiredActionMessage=Darbība noilgusi. Lūdzu turpiniet ar pieslēgšanos. +expiredActionTokenNoSessionMessage=Darbība noilgusi. +expiredActionTokenSessionExistsMessage=Darbība noilgusi. Lūdzu uzsāciet to no jauna. + +missingFirstNameMessage=Lūdzu norādi vārdu. +missingLastNameMessage=Lūdzu norādi uzvārdu. +missingEmailMessage=Lūdzu norādi e-pastu. +missingUsernameMessage=Lūdzu norādi lietotājvārdu. +missingPasswordMessage=Lūdzu norādi paroli. + +notMatchPasswordMessage=Paroles nesakrīt. + +invalidPasswordExistingMessage=Nekorekta pašreizējā parole. +invalidPasswordBlacklistedMessage=Nekorekta parole: parole ir melnajā sarakstā. +invalidPasswordConfirmMessage=Paroles apstiprinājums nav pareizs. + +usernameExistsMessage=Lietotājvārds jau eksistē. +emailExistsMessage=E-pasts jau eksistē. + +federatedIdentityExistsMessage=Lietotājvārds ar {0} {1} jau eksistē. Lūdzu pieslēdzieties konta pārvaldniekam lai savienotu kontus. + +confirmLinkIdpTitle=Konts jau eksistē +federatedIdentityConfirmLinkMessage=Konts ar {0} {1} jau eksistē. Kā vēlies turpināt? +federatedIdentityConfirmReauthenticateMessage=Pieslēdzieties ar {0}, lai savienotu kontu ar {1} +confirmLinkIdpReviewProfile=Pārskatīt profilu +confirmLinkIdpContinue=Pievienot eksistējošam kontam + +accountUpdatedMessage=Jūsu konts ir atjaunots. +accountPasswordUpdatedMessage=Jūsu parole ir atjaunota. + +delegationCompleteHeader=Pieslēgšanās veiksmīga +delegationCompleteMessage=Jūs varat aizvērt šo pārlūka logu un doties atpakaļ uz konsoles lietojumprogrammu. +delegationFailedHeader=Pieslēgšanās neizdevās +delegationFailedMessage=Jūs varat aizvērt šo pārlūka logu un doties atpakaļ uz konsoles lietojumprogrammu un mēģināt pieslēgties atkārtoti. + +noAccessMessage=Nav piekļuves + +invalidPasswordMinLengthMessage=Nekorekta parole: minimālais paroles garums {0}. +invalidPasswordMinDigitsMessage=Nekorekta parole: tai jāsatur vismaz {0} cipari. +invalidPasswordMinLowerCaseCharsMessage=Nekorekta parole: tai jāsatur vismaz {0} mazie burti. +invalidPasswordMinUpperCaseCharsMessage=Nekorekta parole: tai jāsatur vismaz {0} lielie burti. +invalidPasswordMinSpecialCharsMessage=Nekorekta parole: tai jāsatur vismaz {0} speciālie simboli. +invalidPasswordNotUsernameMessage=Nekorekta parole: tā nedrīkst sakrist ar lietotājvārdu. +invalidPasswordRegexPatternMessage=Nekorekta parole: netabilst regex šablonam(iem). +invalidPasswordHistoryMessage=Nekorekta parole: nedrīkst būt vienāda ar iepriekšējām {0} parolēm. +invalidPasswordGenericMessage=Nekorekta parole: jaunā parole neatbilst paroles noteikumiem. + +locale_ca=Català +locale_cs=Čeština +locale_da=Dansk +locale_de=Deutsch +locale_en=English +locale_es=Español +locale_fr=Français +locale_hu=Magyar +locale_it=Italiano +locale_ja=日本語 +locale_lv=Latviešu +locale_lt=Lietuvių +locale_nl=Nederlands +locale_no=Norsk +locale_pl=Polski +locale_pt_BR=Português (Brasil) +locale_pt-BR=Português (Brasil) +locale_ru=Русский +locale_sk=Slovenčina +locale_sv=Svenska +locale_tr=Türkçe +locale_zh-CN=中文简体 + +backToApplication=« Atpakaļ uz lietojumprogrammu +missingParameterMessage=Trūkst parametru\: {0} +clientNotFoundMessage=Klients nav atrasts. +clientDisabledMessage=Klients atspējos. +invalidParameterMessage=Nekorekts parametrs\: {0} +alreadyLoggedIn=Tu jau esi pieslēdzies. +differentUserAuthenticated=Jūs jau esat pieslēdzies ar citu lietotāju ''{0}'' šajā sesijā. Lūdzu vispirms atslēgties. +proceedWithAction=» Spiediet šeit lai turpinātu + +requiredAction.CONFIGURE_TOTP=Konfigurēt OTP +requiredAction.terms_and_conditions=Noteikumi un nosacījumi +requiredAction.UPDATE_PASSWORD=Atjaunot paroli +requiredAction.UPDATE_PROFILE=Atjaunot profilu +requiredAction.VERIFY_EMAIL=Apstiprināt e-pastu + +pageNotFound=Lapa nav atrasta +internalServerError=Notikusi servera kļūme + +console-username=Lietotājvārds: +console-password=Parole: +console-otp=Vienreizējā parole: +console-new-password=Jauna parole: +console-confirm-password=Parole atkārtoti: +console-update-password=Jums ir jāatjauno parole. +console-verify-email=Jums ir jāapstiprina e-pasta adrese. E-pasts tika nosūtīts uz {0}, kas satur apstiprinājuma kodu. Lūdzu ievadiet šo kodu ievadlaukā zemāk. +console-email-code=E-pasta kods: +console-accept-terms=Piekrist noteikumiem? [y/n]: +console-accept=y \ No newline at end of file diff --git a/keycloak-themes/base/login/messages/messages_nl.properties b/keycloak-themes/base/login/messages/messages_nl.properties new file mode 100644 index 0000000..46c2c02 --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_nl.properties @@ -0,0 +1,294 @@ +# encoding: utf-8 +doLogIn=Inloggen +doRegister=Registreer +doCancel=Annuleer +doSubmit=Verzenden +doYes=Ja +doNo=Nee +doContinue=Doorgaan +doIgnore=Negeer +doAccept=Accepteren +doDecline=Afwijzen +doForgotPassword=Wachtwoord vergeten? +doClickHere=Klik hier +doImpersonate=Identiteit overnemen +kerberosNotConfigured=Kerberos is niet geconfigureerd +kerberosNotConfiguredTitle=Kerberos is niet geconfigureerd +bypassKerberosDetail=U bent niet ingelogd via Kerberos of uw browser kan niet met Kerberos inloggen. Klik op 'doorgaan' om via een andere manier in te loggen +kerberosNotSetUp=Kerberos is onjuist geconfigureerd. U kunt niet inloggen. +registerTitle=Registreer +loginTitle=Log in met {0} +loginTitleHtml={0} +impersonateTitle={0} Identiteit overnemen +impersonateTitleHtml={0} Identiteit overnemen +realmChoice=Realm +unknownUser=Onbekende gebruiker +loginTotpTitle=Mobile Authenticator Setup +loginProfileTitle=Update accountinformatie +loginTimeout=U bent te lang bezig geweest met inloggen. Het inlogproces begint opnieuw. +oauthGrantTitle=Verleen Toegang +oauthGrantTitleHtml={0} +errorTitle=Er is een fout opgetreden... +errorTitleHtml=Er is een fout opgetreden... +emailVerifyTitle=E-mailadres-verificatie +emailForgotTitle=Wachtwoord vergeten? +updatePasswordTitle=Wachtwoord updaten +codeSuccessTitle=Succescode +codeErrorTitle=Foutcode: {0} +displayUnsupported=Opgevraagde weergave type is niet ondersteund +browserRequired=Om in te loggen is een browser vereist +browserContinue=Om het loginproces af te ronden is een browser vereist +browserContinuePrompt=Open een browser en ga door met inloggen? [y/n]: +browserContinueAnswer=y + + +termsTitle=Voorwaarden +termsText=

    Gedefinieerde voorwaarden

    +termsPlainText=Voorwaarden + +recaptchaFailed=Ongeldige Recaptcha +recaptchaNotConfigured=Recaptcha is verplicht, maar niet geconfigureerd +consentDenied=Toestemming geweigerd. + +noAccount=Nieuwe gebruiker? +username=Gebruikersnaam +usernameOrEmail=Gebruikersnaam of e-mailadres +firstName=Voornaam +givenName=Voornaam +fullName=Volledige naam +lastName=Achternaam +familyName=Familienaam +email=E-mailadres +password=Wachtwoord +passwordConfirm=Bevestig wachtwoord +passwordNew=Nieuw wachtwoord +passwordNewConfirm=Bevestiging nieuwe wachtwoord +rememberMe=Ingelogd blijven +authenticatorCode=Authenticatiecode +address=Adres +street=Straat +locality=Woonplaats +region=Provincie of regio +postal_code=Postcode +country=Land +emailVerified=E-mailadres geverifieerd +gssDelegationCredential=GSS delegatie Credential + +profileScopeConsentText=Gebruikersprofiel +emailScopeConsentText=E-mailadres +addressScopeConsentText=Adres +phoneScopeConsentText=Telefoonnummer +offlineAccessScopeConsentText=Offline toegang +samlRoleListScopeConsentText=Mijn rollen +rolesScopeConsentText=Gebruikersrollen + +loginTotpIntro=U bent verplicht om tweefactor-authenticatie in te stellen om dit account te kunnen gebruiken +loginTotpStep1=Installeer een van de volgende applicaties op uw mobile telefoon +loginTotpStep2=Open de applicatie en scan de barcode +loginTotpStep3=Voer de eenmalige code die door de applicatie is aangeleverd in en klik op 'Verzenden' om de setup te voltooien +loginTotpManualStep2=Open de applicatie en voer de sleutel in +loginTotpManualStep3=Gebruik de volgende configuratiewaarden (als de applicatie dit ondersteund) +loginTotpUnableToScan=Lukt het scannen niet? +loginTotpScanBarcode=Scan barcode? +loginOtpOneTime=Eenmalige code +loginTotpType=Type +loginTotpAlgorithm=Algoritme +loginTotpDigits=Cijfers +loginTotpInterval=Interval +loginTotpCounter=Teller + +loginTotp.totp=Time-based +loginTotp.hotp=Counter-based + + +oauthGrantRequest=Wilt u deze toegangsrechten verlenen? +inResource=in + +emailVerifyInstruction1=Een e-mail met instructies om uw e-mailadres te verifiëren is zojuist verzonden. +emailVerifyInstruction2=Heeft u geen verificatiecode ontvangen in uw e-mail? +emailVerifyInstruction3=om opnieuw een e-mail te versturen. + +emailLinkIdpTitle=Link {0} +emailLinkIdp1=Er is een e-mail met instructies verzonden om {0} account {1} te koppelen met uw {2} account. +emailLinkIdp2=Heeft u geen verificatiecode in uw e-mail ontvangen? +emailLinkIdp3=om opnieuw een e-mail te versturen. +emailLinkIdp4=Als u deze mail al geverifieerd hebt in een andere browser +emailLinkIdp5=om door te gaan. + +backToLogin=« Terug naar Inloggen + +emailInstruction=Voer uw gebruikersnaam of e-mailadres in en wij sturen u een e-mailbericht met instructies voor het aanmaken van een nieuw wachtwoord. + +copyCodeInstruction=Kopieer deze code en plak deze in uw applicatie: + +pageExpiredTitle=Sessie is verlopen +pageExpiredMsg1=Om het loginproces opnieuw te doen +pageExpiredMsg2=Om door te gaan met het loginproces + +personalInfo=Persoonlijke informatie: +role_admin=Admin +role_realm-admin=Realm beheren +role_create-realm=Realm aanmaken +role_create-client=Client aanmaken +role_view-realm=Bekijk realm +role_view-users=Bekijk gebruikers +role_view-applications=Bekijk applicaties +role_view-clients=Bekijk clients +role_view-events=Bekijk gebeurtenissen +role_view-identity-providers=Bekijk identity providers +role_manage-realm=Beheer realm +role_manage-users=Gebruikers beheren +role_manage-applications=Beheer applicaties +role_manage-identity-providers=Beheer identity providers +role_manage-clients=Beheer clients +role_manage-events=Beheer gebeurtenissen +role_view-profile=Profiel bekijken +role_manage-account=Beheer account +role_manage-account-links=Beheer accountlinks +role_read-token=Token lezen +role_offline-access=Offline toegang +client_account=Account +client_security-admin-console=Security Admin Console +client_admin-cli=Admin CLI +client_realm-management=Realm-beheer +client_broker=Broker + +invalidUserMessage=Ongeldige gebruikersnaam of wachtwoord. +invalidEmailMessage=Ongeldig e-mailadres. +accountDisabledMessage=Account is uitgeschakeld, neem contact op met beheer. +accountTemporarilyDisabledMessage=Account is tijdelijk uitgeschakeld, neem contact op met beheer of probeer het later opnieuw. +expiredCodeMessage=Logintijd verlopen. Gelieve opnieuw in te loggen. +expiredActionMessage=Actietijd verlopen. Log daarom opnieuw in. +expiredActionTokenNoSessionMessage=Actietijd verlopen. +expiredActionTokenSessionExistsMessage=Actietijd verlopen. Gelieve de actie opnieuw doen. + +missingFirstNameMessage=Voer uw voornaam in. +missingLastNameMessage=Voer uw achternaam in. +missingEmailMessage=Voer uw e-mailadres in. +missingUsernameMessage=Voer uw gebruikersnaam in. +missingPasswordMessage=Voer uw wachtwoord in. +missingTotpMessage=Voer uw authenticatiecode in. +notMatchPasswordMessage=Wachtwoorden komen niet overeen. + +invalidPasswordExistingMessage=Ongeldig bestaand wachtwoord. +invalidPasswordBlacklistedMessage=Ongeldig wachtwoord: wachtwoord is geblacklist. +invalidPasswordConfirmMessage=Wachtwoord komt niet overeen met wachtwoordbevestiging. +invalidTotpMessage=Ongeldige authenticatiecode. + +usernameExistsMessage=Gebruikersnaam bestaat al. +emailExistsMessage=E-mailadres bestaat al. + +federatedIdentityExistsMessage=Gebruiker met {0} {1} bestaat al. Log in met het beheerdersaccount om het account te koppelen. + +confirmLinkIdpTitle=Account bestaat al +federatedIdentityConfirmLinkMessage=Gebruiker met {0} {1} bestaat al. Hoe wilt u doorgaan? +federatedIdentityConfirmReauthenticateMessage=Authenticeer om uw account te koppelen {0} +confirmLinkIdpReviewProfile=Nalopen profiel +confirmLinkIdpContinue=Voeg toe aan bestaande account + +configureTotpMessage=U moet de Mobile Authenticator configuren om uw account te activeren. +updateProfileMessage=U moet uw gebruikersprofiel bijwerken om uw account te activeren. +updatePasswordMessage=U moet uw wachtwoord wijzigen om uw account te activeren. +resetPasswordMessage=U moet uw wachtwoord wijzigen. +verifyEmailMessage=U moet uw e-mailadres verifiëren om uw account te activeren. +linkIdpMessage=U moet uw e-mailadres verifiëren om uw account te koppelen aan {0}. + +emailSentMessage=U ontvangt binnenkort een e-mail met verdere instructies. +emailSendErrorMessage=Het versturen van de e-mail is mislukt, probeer het later opnieuw. + +accountUpdatedMessage=Uw account is gewijzigd. +accountPasswordUpdatedMessage=Uw wachtwoord is gewijzigd. + +delegationCompleteHeader=Login gelukt +delegationCompleteMessage=U mag uw browser sluiten en terug gaan naar uw console applicatie +delegationFailedHeader=Login mislukt +delegationFailedMessage=U mag uw browser sluiten en terug gaan naar uw console applicatie om daar het loginproces nogmaalt te proberen. + +noAccessMessage=Geen toegang + +invalidPasswordMinLengthMessage=Ongeldig wachtwoord, de minimumlengte is {0} karakters. +invalidPasswordMinDigitsMessage=Ongeldig wachtwoord, deze moet minstens {0} cijfers bevatten. +invalidPasswordMinLowerCaseCharsMessage=Ongeldig wachtwoord, deze moet minstens {0} kleine letters bevatten. +invalidPasswordMinUpperCaseCharsMessage=Ongeldig wachtwoord, deze moet minstens {0} hoofdletters bevatten. +invalidPasswordMinSpecialCharsMessage=Ongeldig wachtwoord, deze moet minstens {0} speciale tekens bevatten. +invalidPasswordNotUsernameMessage=Ongeldig wachtwoord, deze mag niet overeen komen met de gebruikersnaam. +invalidPasswordRegexPatternMessage=Ongeldig wachtwoord, deze komt niet overeen met opgegeven reguliere expressie(s). +invalidPasswordHistoryMessage=Ongeldig wachtwoord, deze mag niet overeen komen met een van de laatste {0} wachtwoorden. +invalidPasswordGenericMessage=Ongeldig wachtwoord: het nieuwe wachtwoord voldoet niet aan de opgestelde eisen. + +failedToProcessResponseMessage=Het verwerken van de respons is mislukt +httpsRequiredMessage=HTTPS vereist +realmNotEnabledMessage=Realm niet geactiveerd +invalidRequestMessage=Ongeldige request +failedLogout=Afmelden is mislukt +unknownLoginRequesterMessage=De login requester is onbekend +loginRequesterNotEnabledMessage=De login requester is niet geactiveerd +bearerOnlyMessage=Bearer-only applicaties mogen geen browserlogin initiëren +standardFlowDisabledMessage=Client mag geen browserlogin starten met het opgegeven response_type. Standard flow is uitgeschakeld voor de client. +implicitFlowDisabledMessage=Client mag geen browserlogin starten met opgegeven response_type. Implicit flow is uitgeschakeld voor de klant. +invalidRedirectUriMessage=Ongeldige redirect-URI +unsupportedNameIdFormatMessage=Niet-ondersteunde NameIDFormat +invalidRequesterMessage=Ongeldige requester +registrationNotAllowedMessage=Registratie is niet toegestaan +resetCredentialNotAllowedMessage=Het opnieuw instellen van de aanmeldgegevens is niet toegestaan + +permissionNotApprovedMessage=Recht verworpen. +noRelayStateInResponseMessage=Geen relay state in antwoord van de identity provider. +insufficientPermissionMessage=Onvoldoende rechten om identiteiten te koppelen. +couldNotProceedWithAuthenticationRequestMessage=Het authenticatieverzoek naar de identity provider wordt afgebroken. +couldNotObtainTokenMessage=Kon geen token bemachtigen van de identity provider. +unexpectedErrorRetrievingTokenMessage=Onverwachte fout bij het ophalen van de token van de identity provider. +unexpectedErrorHandlingResponseMessage=Onverwachte fout bij het verwerken van de respons van de identity provider. +identityProviderAuthenticationFailedMessage=Verificatie mislukt. Er kon niet worden geauthenticeerd met de identity provider. +couldNotSendAuthenticationRequestMessage=Kan het authenticatieverzoek niet verzenden naar de identity provider. +unexpectedErrorHandlingRequestMessage=Onverwachte fout bij het verwerken van het authenticatieverzoek naar de identity provider. +invalidAccessCodeMessage=Ongeldige toegangscode. +sessionNotActiveMessage=Sessie inactief. +invalidCodeMessage=Er is een fout opgetreden, probeer nogmaals in te loggen. +identityProviderUnexpectedErrorMessage=Onverwachte fout tijdens de authenticatie met de identity provider +identityProviderNotFoundMessage=Geen identity provider gevonden met deze naam. +identityProviderLinkSuccess=Uw account is met succes gekoppeld aan {0} account {1}. +staleCodeMessage=Deze pagina is verlopen. Keer terug naar uw applicatie om opnieuw in te loggen. +realmSupportsNoCredentialsMessage=Realm ondersteunt geen enkel soort aanmeldgegeven. +identityProviderNotUniqueMessage=Realm ondersteunt meerdere identity providers. Er kon niet bepaald worden welke identity provider er gebruikt zou moeten worden tijdens de authenticatie. +emailVerifiedMessage=Uw e-mailadres is geverifieerd. +staleEmailVerificationLink=De link die u gebruikt is verlopen, wellicht omdat u uw e-mailadres al eerder geverifieerd heeft. +identityProviderAlreadyLinkedMessage=De door {0} teruggegeven gefedereerde identiteit is al aan een andere gebruiker gekoppeld. +confirmAccountLinking=Bevestig dat het account {0} van identity provider {1} overeenkomt met uw account. +confirmEmailAddressVerification=Bevestig dat e-mailadres {0} valide is. +confirmExecutionOfActions=Voer de volgende actie(s) uit + +backToApplication=« Terug naar de applicatie +missingParameterMessage=Missende parameters: {0} +clientNotFoundMessage=Client niet gevonden. +clientDisabledMessage=Client is inactief. +invalidParameterMessage=Ongeldige parameter: {0} +alreadyLoggedIn=U bent al ingelogd. +differentUserAuthenticated=U bent in deze sessie al als de gebruiker "{0}" aangemeld. Log eerst uit. +brokerLinkingSessionExpired=Broker account linking aangevraagd, maar de huidige sessie in verlopen. +proceedWithAction=» Klik hier om verder te gaan + +requiredAction.CONFIGURE_TOTP=Configureer OTP +requiredAction.terms_and_conditions=Voorwaarden +requiredAction.UPDATE_PASSWORD=Update wachtwoord +requiredAction.UPDATE_PROFILE=Update profiel +requiredAction.VERIFY_EMAIL=Verifieer e-mail + +doX509Login=U wordt ingelogd als\: +clientCertificate=X509 client certificate\: +noCertificate=[No Certificate] + + +pageNotFound=Pagina niet gevonden +internalServerError=Er is een interne serverfout opgetreden + +console-username=Gebruikersnaam: +console-password=Wachtwoord: +console-otp=Eenmalige code: +console-new-password=Nieuw wachtwoord: +console-confirm-password=Bevestig wachtwoord: +console-update-password=Een update van uw wachtwoord is verplicht. +console-verify-email=U bent verplicht om uw e-mailadres te verifiëren. Een e-mail met de verificatiecode is naar {0} gestuurd. Voer deze code hieronder in. +console-email-code=E-mail Code: +console-accept-terms=Accepteert u de voorwaarden? [y/n]: +console-accept=y diff --git a/keycloak-themes/base/login/messages/messages_no.properties b/keycloak-themes/base/login/messages/messages_no.properties new file mode 100644 index 0000000..8f1d4d4 --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_no.properties @@ -0,0 +1,214 @@ +doLogIn=Logg inn +doRegister=Registrer deg +doCancel=Avbryt +doSubmit=Send inn +doYes=Ja +doNo=Nei +doContinue=Fortsett +doAccept=Aksepter +doDecline=Avsl\u00E5 +doForgotPassword=Glemt passord? +doClickHere=Klikk her +doImpersonate=Utgi deg for \u00E5 v\u00E6re en annen bruker +kerberosNotConfigured=Kerberos er ikke konfigurert +kerberosNotConfiguredTitle=Kerberos er ikke konfigurert +bypassKerberosDetail=Enten er du ikke logget inn via Kerberos eller s\u00E5 st\u00F8tter ikke nettleseren innlogging med Kerberos. Vennligst klikk Fortsett for \u00E5 logge inn p\u00E5 andre m\u00E5ter +kerberosNotSetUp=Kerberos er ikke konfigurert. Du kan ikke logge inn. +registerWithTitle=Registrer deg med {0} +registerWithTitleHtml={0} +loginTitle=Logg inn p\u00E5 {0} +loginTitleHtml={0} +impersonateTitle={0} Gi deg ut for \u00E5 v\u00E6re en annen bruker +impersonateTitleHtml={0} Gi deg ut for \u00E5 v\u00E6re en annen bruker +realmChoice=Sikkerhetsdomene +unknownUser=Ukjent bruker +loginTotpTitle=Konfigurer autentifikator for mobil +loginProfileTitle=Oppdater konto +loginTimeout=Du brukte for lang tid p\u00E5 \u00E5 logge inn. Vennligst pr\u00F8v igjen. +oauthGrantTitle=Gi tilgang +oauthGrantTitleHtml={0} +errorTitle=Vi beklager... +errorTitleHtml=Vi beklager ... +emailVerifyTitle=E-postbekreftelse +emailForgotTitle=Glemt passord? +updatePasswordTitle=Oppdater passord +codeSuccessTitle=Suksesskode +codeErrorTitle=Feilkode\: {0} + +termsTitle=Vilk\u00E5r og betingelser +termsTitleHtml=Vilk\u00E5r og betingelser +termsText=

    Vilk\u00E5r og betingelser kommer

    + +recaptchaFailed=Ugyldig Bildebekreftelse +recaptchaNotConfigured=Bildebekreftelse er p\u00E5krevet, men er ikke konfigurert +consentDenied=Samtykke avsl\u00E5tt. + +noAccount=Ny bruker? +username=Brukernavn +usernameOrEmail=Brukernavn eller e-postadresse +firstName=Fornavn +givenName=Fornavn +fullName=Fullstendig navn +lastName=Etternavn +familyName=Etternavn +email=E-postadresse +password=Passord +passwordConfirm=Bekreft passord +passwordNew=Nytt passord +passwordNewConfirm=Bekreft nytt Passord +rememberMe=Husk meg +authenticatorCode=Engangskode +address=Adresse +street=Gate-/veinavn + husnummer +locality=By +region=Fylke +postal_code=Postnummer +country=Land +emailVerified=E-postadresse bekreftet +gssDelegationCredential=GSS legitimasjons-delegering + +loginTotpStep1=Installer FreeOTP eller Google Authenticator p\u00E5 din mobiltelefon. Begge applikasjoner er tilgjengelige p\u00E5 Google Play og Apple App Store. +loginTotpStep2=\u00C5pne applikasjonen og skann strekkoden eller skriv inn koden +loginTotpStep3=Skriv inn engangskoden fra applikasjonen og klikk send inn for \u00E5 fullf\u00F8re +loginOtpOneTime=Engangskode + +oauthGrantRequest=Vil du gi disse tilgangsrettighetene? +inResource=i + +emailVerifyInstruction1=En e-post med instruksjoner for \u00E5 bekrefte din e-postadresse har blitt sendt til deg. +emailVerifyInstruction2=Ikke mottatt en bekreftelseskode i e-posten vi sendte til deg? +emailVerifyInstruction3=for \u00E5 sende e-post p\u00E5 nytt. + +emailLinkIdpTitle=Lenke {0} +emailLinkIdp1=En e-post med instruksjoner for \u00E5 koble {0} konto med din {2} konto har blitt sendt til deg. +emailLinkIdp2=Ikke mottatt en bekreftelseskode i e-posten vi sendte til deg? +emailLinkIdp3=for \u00E5 sende e-post p\u00E5 nytt. + +backToLogin=« Tilbake til innlogging +emailInstruction=Skriv inn e-postadressen din og vi vil sende deg instruksjoner for hvordan du oppretter et nytt passord. + +copyCodeInstruction=Vennligst kopier denne koden og lim den inn i applikasjonen din: + +personalInfo=Personlig informasjon: +role_admin=Administrator +role_realm-admin=Administrator for sikkerhetsdomene +role_create-realm=Opprette sikkerhetsdomene +role_create-client=Opprette klient +role_view-realm=Se sikkerhetsdomene +role_view-users=Se brukere +role_view-applications=Se applikasjoner +role_view-clients=Se klienter +role_view-events=Se hendelser +role_view-identity-providers=Se identitetsleverand\u00F8rer +role_manage-realm=Administrere sikkerhetsdomene +role_manage-users=Administrere brukere +role_manage-applications=Administrere applikasjoner +role_manage-identity-providers=Administrere identitetsleverand\u00F8rer +role_manage-clients=Administrere klienter +role_manage-events=Administrere hendelser +role_view-profile=Se profil +role_manage-account=Administrere konto +role_read-token=Lese token +role_offline-access=Frakoblet tilgang +role_uma_authorization=Skaffe tillatelser +client_account=Konto +client_security-admin-console=Sikkerthetsadministrasjonskonsoll +client_realm-management=Sikkerhetsdomene-administrasjon +client_broker=Broker + +invalidUserMessage=Ugyldig brukernavn eller passord. +invalidEmailMessage=Ugyldig e-postadresse. +accountDisabledMessage=Konto er deaktivert, kontakt administrator. +accountTemporarilyDisabledMessage=Konto er midlertidig deaktivert, kontakt administrator eller pr\u00F8v p\u00E5 nytt senere. +expiredCodeMessage=Login ble tidsavbrutt. Vennligst logg inn p\u00E5 nytt. + +missingFirstNameMessage=Vennligst oppgi fornavn. +missingLastNameMessage=Vennligst oppgi etternavn. +missingEmailMessage=Vennligst oppgi e-postadresse. +missingUsernameMessage=Vennligst oppgi brukernavn. +missingPasswordMessage=Vennligst oppgi passord. +missingTotpMessage=Vennligst oppgi autentiseringskode. +notMatchPasswordMessage=Passordene er ikke like. + +invalidPasswordExistingMessage=Ugyldig eksisterende passord. +invalidPasswordConfirmMessage=Passord er ikke like. +invalidTotpMessage=Ugyldig engangskode. + +usernameExistsMessage=Brukernavnet finnes allerede. +emailExistsMessage=E-post finnes allerede. + +federatedIdentityExistsMessage=Bruker med {0} {1} finnes allerede. Vennligst logg inn p\u00E5 kontoadministratsjon for \u00E5 koble sammen kontoene. + +confirmLinkIdpTitle=Kontoen finnes allerede +federatedIdentityConfirmLinkMessage=Bruker med {0} {1} finnes allerede. Hvordan vil du fortsette? +#federatedIdentityConfirmReauthenticateMessage=Bekreft at du er {0} for \u00E5 koble din konto med {1} +confirmLinkIdpReviewProfile=Se over og bekreft profil +confirmLinkIdpContinue=Legg til eksisterende konto + +configureTotpMessage=Du m\u00E5 sette opp en engangskode-generator for \u00E5 aktivere konto. +updateProfileMessage=Du m\u00E5 oppdatere brukerprofilen din for \u00E5 aktivere konto. +updatePasswordMessage=Du m\u00E5 skifte passord for \u00E5 aktivere kontoen din. +verifyEmailMessage=Du m\u00E5 bekrefte e-postadressen din for \u00E5 aktivere konto. +linkIdpMessage=You need to verify your email address to link your account with {0}. + +emailSentMessage=Du vil straks motta en e-post med ytterlige instruksjoner. +emailSendErrorMessage=Mislyktes \u00E5 sende e-post, vennligst pr\u00F8v igjen senere. + +accountUpdatedMessage=Din konto har blitt oppdatert. +accountPasswordUpdatedMessage=Ditt passord har blitt oppdatert. + +noAccessMessage=Ingen tilgang + +invalidPasswordMinLengthMessage=Ugyldig passord: minimum lengde {0}. +invalidPasswordMinDigitsMessage=Ugyldig passord: m\u00E5 inneholde minimum {0} sifre. +invalidPasswordMinLowerCaseCharsMessage=Ugyldig passord: m\u00E5 inneholde minimum {0} sm\u00E5 bokstaver. +invalidPasswordMinUpperCaseCharsMessage=Ugyldig passord: m\u00E5 inneholde minimum {0} store bokstaver. +invalidPasswordMinSpecialCharsMessage=Ugyldig passord: m\u00E5 inneholde minimum {0} spesialtegn. +invalidPasswordNotUsernameMessage=Ugyldig passord: kan ikke v\u00E6re likt brukernavn. +invalidPasswordRegexPatternMessage=Ugyldig passord: tilfredsstiller ikke kravene for passord-m\u00F8nster. +invalidPasswordHistoryMessage=Ugyldig passord: kan ikke v\u00E6re likt noen av de {0} foreg\u00E5ende passordene. + +failedToProcessResponseMessage=Kunne ikke behandle svar +httpsRequiredMessage=HTTPS p\u00E5krevd +realmNotEnabledMessage=Sikkerhetsdomene er ikke aktivert +invalidRequestMessage=Ugyldig foresp\u00F8rsel +failedLogout=Utlogging feilet +unknownLoginRequesterMessage=Ukjent anmoder for innlogging +loginRequesterNotEnabledMessage=Anmoder for innlogging er ikke aktivert +bearerOnlyMessage=Bearer-only applikasjoner har ikke lov til \u00E5 initiere innlogging via nettleser +standardFlowDisabledMessage=Klienten har ikke lov til \u00E5 initiere innlogging via nettleser med gitt response_type. Standard flow er deaktivert for denne klienten. +implicitFlowDisabledMessage=Klienten har ikke lov til \u00E5 initiere innlogging via nettleser med gitt response_type. Implicit flow er deaktivert for denne klienten. +invalidRedirectUriMessage=Ugyldig redirect uri +unsupportedNameIdFormatMessage=NameIDFormat er ikke st\u00F8ttet +invalidRequesterMessage=Ugyldig sender av foresp\u00F8rsel +registrationNotAllowedMessage=Registrering er ikke lov +resetCredentialNotAllowedMessage=Tilbakestilling av innloggingsdata er ikke lov + +permissionNotApprovedMessage=Tillatelse ikke godkjent. +noRelayStateInResponseMessage=Ingen relay state i svar fra identitetsleverand\u00F8r. +insufficientPermissionMessage=Utilstrekkelige rettigheter for \u00E5 koble identiteter. +couldNotProceedWithAuthenticationRequestMessage=Kunne ikke g\u00E5 videre med autentiseringsforesp\u00F8rsel til identitetsleverand\u00F8r. +couldNotObtainTokenMessage=Klarte ikke \u00E5 innhente token fra identitetsleverand\u00F8r. +unexpectedErrorRetrievingTokenMessage=Uventet feil ved henting av token fra identitetsleverand\u00F8r. +unexpectedErrorHandlingResponseMessage=Uventet feil ved h\u00E5ndtering av svar fra identitetsleverand\u00F8r. +identityProviderAuthenticationFailedMessage=Autentisering feilet. Kunne ikke autentisere med identitetsleverand\u00F8r. +couldNotSendAuthenticationRequestMessage=Kunne ikke sende autentiseringsforesp\u00F8rsel til identitetsleverand\u00F8r. +unexpectedErrorHandlingRequestMessage=Uventet feil ved h\u00E5ndtering av autentiseringsforesp\u00F8rsel til identitetsleverand\u00F8r. +invalidAccessCodeMessage=Ugyldig tilgangskode. +sessionNotActiveMessage=Sesjonen er ikke aktiv. +invalidCodeMessage=En feil oppstod, vennligst logg inn p\u00E5 nytt i din applikasjon. +identityProviderUnexpectedErrorMessage=Uventet feil ved autentisering med identitetsleverand\u00F8r +identityProviderNotFoundMessage=Kunne ikke finne en identitetsleverand\u00F8r med identifikatoren. +identityProviderLinkSuccess=Din konto ble suksessfullt koblet med {0} konto {1}. +staleCodeMessage=Denne siden er ikke lenger gyldig. Vennligst g\u00E5 tilbake til applikasjonen din og logg inn p\u00E5 nytt. +realmSupportsNoCredentialsMessage=Sikkerhetsdomene st\u00F8tter ingen legitimasjonstyper. +identityProviderNotUniqueMessage=Sikkerhetsdomene st\u00F8tter flere identitetsleverand\u00F8rer. Kunne ikke avgj\u00F8re hvilken identitetsleverand\u00F8r som burde brukes for autentisering. +emailVerifiedMessage=Din e-postadresse har blitt verifisert. +staleEmailVerificationLink=Lenken du klikket er utg\u00E5tt og er ikke lenger gyldig. Har du kanskje allerede bekreftet e-postadressen din? + +backToApplication=« Tilbake til applikasjonen +missingParameterMessage=Manglende parameter\: {0} +clientNotFoundMessage=Klient ikke funnet. +clientDisabledMessage=Klient deaktivert. +invalidParameterMessage=Ugyldig parameter\: {0} +alreadyLoggedIn=Du er allerede innlogget. diff --git a/keycloak-themes/base/login/messages/messages_pl.properties b/keycloak-themes/base/login/messages/messages_pl.properties new file mode 100644 index 0000000..a754996 --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_pl.properties @@ -0,0 +1,316 @@ +# encoding: UTF-8 +doLogIn=Logowanie +doRegister=Rejestracja +doCancel=Anuluj +doSubmit=Zatwierdź +doBack=Cofnij +doYes=Tak +doNo=Nie +doContinue=Kontynuuj +doIgnore=Ignoruj +doAccept=Akceptuj +doDecline=Odrzuć +doForgotPassword=Nie pamiętasz hasła? +doClickHere=Kliknij tutaj +doImpersonate=Wciel się +doTryAgain=Spróbuj ponownie +doTryAnotherWay=Spróbuj inną metodą +kerberosNotConfigured=Kerberos nie jest skonfigurowany +kerberosNotConfiguredTitle=Kerberos nie jest skonfigurowany +bypassKerberosDetail=Albo nie jesteś zalogowany przez Kerberos albo twoja przeglądarka nie jest skonfigurowana do logowania Kerberos. Kliknij kontynuuj by zalogować się w inny sposób. +kerberosNotSetUp=Kerberos nie jest skonfigurowany. Nie można się zalogować. +registerTitle=Rejestracja +loginTitle=Zaloguj się do {0} +loginTitleHtml={0} +impersonateTitle=Wcielenie {0} +impersonateTitleHtml=Wcielenie {0} +realmChoice=Strefa +unknownUser=Nieznany użytkownik +loginTotpTitle=Konfiguracja dla Mobile Authenticator +loginProfileTitle=Zaktualizuj informacje konta +loginTimeout=Zbyt dużo czasu zajęło logowanie. Proces logowania rozpocznie się od nowa. +oauthGrantTitle=Przydziel dostęp dla {0} +oauthGrantTitleHtml={0} +errorTitle=Przykro nam... +errorTitleHtml=Przykro nam... +emailVerifyTitle=Weryfikacja e-maila +emailForgotTitle=Nie pamiętasz hasła? +updatePasswordTitle=Aktualizacja hasła +codeSuccessTitle=Kod sukcesu +codeErrorTitle=Kod błędu\: {0} +displayUnsupported=Żądany typ wyświetlania jest nieobsługiwany +browserRequired=Do zalogowania wymagana jest przeglądarka +browserContinue=Przeglądarka jest wymagana by dokończyć logowanie +browserContinuePrompt=Otworzyć przeglądarkę i kontynuować logowanie? [t/n]\: +browserContinueAnswer=t + + +termsTitle=Regulamin +termsText=

    Regulamin, który należy zdefiniować

    +termsPlainText=Regulamin, który należy zdefiniować. + +recaptchaFailed=Błędna Recaptcha +recaptchaNotConfigured=Recaptcha jest wymagana, ale nie skonfigurowana +consentDenied=Zgoda odrzucona. + +noAccount=Nie masz konta? +username=Nazwa użytkownika (login) +usernameOrEmail=Nazwa użytkownika lub e-mail (login) +firstName=Imię +givenName=Nadane imię +fullName=Pełne imię i nazwisko +lastName=Nazwisko +familyName=Nazwisko rodowe +email=E-mail +password=Hasło +passwordConfirm=Potwierdź hasło +passwordNew=Nowe hasło +passwordNewConfirm=Potwierdzenie nowego hasła +rememberMe=Zapamiętaj mnie +authenticatorCode=Kod jednorazowy +address=Adres +street=Ulica +locality=Miejscowość +region=Województwo +postal_code=Kod pocztowy +country=Państwo +emailVerified=Email zweryfikowany +website=Strona internetowa +phoneNumber=Nr telefonu +phoneNumberVerified=Nr telefonu zweryfikowany +gender=Płeć +birthday=Data urodzenia +zoneinfo=Strefa czasowa +gssDelegationCredential=Świadectwo przekazania uprawnień GSS + +profileScopeConsentText=Profil użytkownika +emailScopeConsentText=Adres email +addressScopeConsentText=Adres +phoneScopeConsentText=Numer telefonu +offlineAccessScopeConsentText=Dostęp offline +samlRoleListScopeConsentText=Moje role +rolesScopeConsentText=Role użytkownika + +restartLoginTooltip=Restart logowania + +loginTotpIntro=Aby uzyskać dostęp do tego konta, musisz skonfigurować generator haseł jednorazowych +loginTotpStep1=Zainstaluj jedną z następujących aplikacji na telefonie komórkowym +loginTotpStep2=Otwórz aplikację i zeskanuj kod kreskowy +loginTotpStep3=Wprowadź jednorazowy kod podany przez aplikację i kliknij Prześlij aby zakończyć konfigurację +loginTotpManualStep2=Otwórz aplikację i wprowadź klucz +loginTotpManualStep3=Użyj poniższych wartości konfiguracji, jeśli aplikacja pozwala na ich ustawienie +loginTotpUnableToScan=Nie można skanować? +loginTotpScanBarcode=Zeskanować kod paskowy? +loginCredential=Poświadczenia +loginOtpOneTime=Kod jednorazowy +loginTotpType=Typ +loginTotpAlgorithm=Algorytm +loginTotpDigits=Cyfry +loginTotpInterval=Interwał +loginTotpCounter=Licznik +loginTotpDeviceName=Nazwa urządzenia + +loginTotp.totp=Oparte o czas +loginTotp.hotp=Oparte o licznik + +loginChooseAuthenticator=Wybierz metodę logowania + +oauthGrantRequest=Czy przyznajesz te uprawnienia dostępu? +inResource=w + +emailVerifyInstruction1=Została wysłana do Ciebie wiadomość e-mail z instrukcjami jak zweryfikować swój adres e-mail. +emailVerifyInstruction2=Nie otrzymałem kodu weryfikacyjnego w wiadomości e-mail? +emailVerifyInstruction3=aby ponownie wysłać wiadomość e-mail. + +emailLinkIdpTitle=Link {0} +emailLinkIdp1=Wiadomość e-mail z instrukcjami, aby powiązać konto {0} {1} z kontem {2} została wysłana do Ciebie. +emailLinkIdp2=Nie otrzymałem kodu weryfikacyjnego w wiadomości e-mail? +emailLinkIdp3=aby ponownie wysłać wiadomość e-mail. +emailLinkIdp4=Jeśli już zweryfikowana e-mail w innej przeglądarce +emailLinkIdp5=aby kontynuować. + +backToLogin=« Powrót do logowania + +emailInstruction=Wpisz swój adres e-mail lub nazwę użytkownika a wyślemy do Ciebie instrukcje, jak utworzyć nowe hasło. + +copyCodeInstruction=Proszę skopiować ten kod i wklej go do aplikacji\: + +pageExpiredTitle=Strona wygasła +pageExpiredMsg1=Aby ponownie uruchomić proces logowania +pageExpiredMsg2=Aby kontynuować proces logowania + +personalInfo=Informacje osobiste\: +role_admin=Admin +role_realm-admin=Strefa Admin +role_create-realm=Utwórz strefę +role_create-client=Utwórz klienta +role_view-realm=Wyświetl strefę +role_view-users=Wyświetl użytkowników +role_view-applications=Wyświetl aplikacje +role_view-clients=Wyświetl klientów +role_view-events=Wyświetl zdarzenia +role_view-identity-providers=Wyświetl dostawców tożsamości +role_manage-realm=Zarządzaj strefą +role_manage-users=Zarządzaj użytkownikami +role_manage-applications=Zarządzaj aplikacjami +role_manage-identity-providers=Zarządzaj dostawcami tożsamości +role_manage-clients=Zarządzaj klientami +role_manage-events=Zarządzaj zdarzeniami +role_view-profile=Zobacz profil +role_manage-account=Zarządzaj kontem +role_manage-account-links=Zarządzanie łączami konta +role_read-token=Odczytu tokenu +role_offline-access=Dostęp offline +client_account=Konto +client_account-console=Konsola konta +client_security-admin-console=Konsola administratora bezpieczeństwa +client_admin-cli=Admin CLI +client_realm-management=Zarządzanie strefą +client_broker=Broker + +requiredFields=Wymagane pola + +invalidUserMessage=Nieprawidłowa nazwa użytkownika lub hasło. +invalidUsernameMessage=Nieprawidłowa nazwa użytkownika. +invalidUsernameOrEmailMessage=Nieprawidłowa nazwa użytkownika lub hasło. +invalidPasswordMessage=Nieprawidłowe hasło. +invalidEmailMessage=Nieprawidłowy adres e-mail. +accountDisabledMessage=Konto jest wyłączone, skontaktuj się z administratorem. +accountTemporarilyDisabledMessage=Konto jest tymczasowo wyłączone, skontaktuj się z administratorem lub spróbuj ponownie później. +expiredCodeMessage=Przekroczono limit czasu logowania. Proszę Zaloguj się ponownie. +expiredActionMessage=Akcja wygasła. Proszę kontynuować logowanie. +expiredActionTokenNoSessionMessage=Akcja wygasła. +expiredActionTokenSessionExistsMessage=Akcja wygasła. Proszę uruchomić ponownie. + +missingFirstNameMessage=Proszę podać imię. +missingLastNameMessage=Proszę podać nazwisko. +missingEmailMessage=Proszę podać e-mail. +missingUsernameMessage=Proszę podać nazwę użytkownika. +missingPasswordMessage=Proszę podać hasło. +missingTotpMessage=Proszę podać kod uwierzytelniający. +missingTotpDeviceNameMessage=Proszę podać nazwę urządzenia. +notMatchPasswordMessage=Hasła nie są zgodne. + +invalidPasswordExistingMessage=Nieprawidłowe istniejące hasło. +invalidPasswordBlacklistedMessage=Nieprawidłowe hasło\: hasło jest na czarnej liście. +invalidPasswordConfirmMessage=Potwierdzenie hasła nie pasuje. +invalidTotpMessage=Nieprawidłowy kod uwierzytelnienia. + +usernameExistsMessage=Nazwa użytkownika już istnieje. +emailExistsMessage=Email już istnieje. + +federatedIdentityExistsMessage=Użytkownik z {0} {1} już istnieje. Zaloguj się do zarządzania kontem aby połączyć konto. + +confirmLinkIdpTitle=Konto już istnieje +federatedIdentityConfirmLinkMessage=Użytkownik z {0} {1} już istnieje. Co chcesz zrobić? +federatedIdentityConfirmReauthenticateMessage=Uwierzytelnij się aby połączyć swoje konto z {0} +nestedFirstBrokerFlowMessage=Użytkownik {0} {1} nie jest powiązany z żadnym znanym użytkownikiem. +confirmLinkIdpReviewProfile=Przejrzyj profil +confirmLinkIdpContinue=Dodaj do istniejącego konta + +configureTotpMessage=Musisz skonfigurować Mobile Authenticator aby aktywować swoje konto. +updateProfileMessage=Musisz zaktualizować profilu użytkownika aby aktywować swoje konto. +updatePasswordMessage=Musisz zmienić swoje hasło aby aktywować swoje konto. +resetPasswordMessage=Musisz zmienić swoje hasło. +verifyEmailMessage=Musisz zweryfikować swój adres e-mail aby aktywować swoje konto. +linkIdpMessage=Musisz zweryfikować swój adres e-mail, aby połączyć swoje konto z {0}. + +emailSentMessage=Powinieneś otrzymywać wkrótce pocztę z dalszymi instrukcjami. +emailSendErrorMessage=Nie można wysłać wiadomości e-mail, proszę spróbować ponownie później. + +accountUpdatedMessage=Twoje konto zostało zaktualizowane. +accountPasswordUpdatedMessage=Twoje hasło zostało zaktualizowane. + +delegationCompleteHeader=Logowanie udane +delegationCompleteMessage=Możesz zamknąć okno przeglądarki i przejść wstecz do aplikacji konsoli. +delegationFailedHeader=Logowanie nie powiodło się +delegationFailedMessage=Możesz zamknąć okno przeglądarki, wrócić do aplikacji konsoli i spróbować zalogować się ponownie. + +noAccessMessage=Brak dostępu + +invalidPasswordMinLengthMessage=Nieprawidłowe hasło\: minimalna długość {0}. +invalidPasswordMinDigitsMessage=Nieprawidłowe hasło\: musi zawierać przynajmniej {0} cyfr. +invalidPasswordMinLowerCaseCharsMessage=Nieprawidłowe hasło\: musi zawierać co najmniej {0} małych liter. +invalidPasswordMinUpperCaseCharsMessage=Nieprawidłowe hasło\: musi zawierać co najmniej {0} wielkich liter. +invalidPasswordMinSpecialCharsMessage=Nieprawidłowe hasło\: musi zawierać przynajmniej {0} znaków specjalnych. +invalidPasswordNotUsernameMessage=Nieprawidłowe hasło\: nie może być nazwą użytkownika. +invalidPasswordRegexPatternMessage=Nieprawidłowe hasło\: brak zgodności z wyrażeniem regularnym. +invalidPasswordHistoryMessage=Nieprawidłowe hasło\: nie może być takie jak {0} ostatnich haseł. +invalidPasswordGenericMessage=Nieprawidłowe hasło\: nowe hasło nie jest zgodne z zasadami haseł. + +failedToProcessResponseMessage=Nie można przetworzyć odpowiedzi +httpsRequiredMessage=Wymagany HTTPS +realmNotEnabledMessage=Strefa nie jest aktywna +invalidRequestMessage=Nieprawidłowe żądanie +failedLogout=Wylogowanie nie powiodło się +unknownLoginRequesterMessage=Nieznany żądający logowania +loginRequesterNotEnabledMessage=Żądający logowania nie jest aktywny +bearerOnlyMessage=Klienci bearer-only nie mogą inicjować logowania przez przeglądarkę +standardFlowDisabledMessage=Klient nie może zainicjować logowania przez przeglądarkę z podanym response_type. Standardowy przepływ jest wyłączony dla klienta. +implicitFlowDisabledMessage=Klient nie może zainicjować logowania przez przeglądarkę z podanym response_type. Niejawny przepływ jest wyłączony dla klienta. +invalidRedirectUriMessage=Nieprawidłowy uri przekierowania +unsupportedNameIdFormatMessage=Nieobsługiwany NameIDFormat +invalidRequesterMessage=Nieprawidłowy żądający +registrationNotAllowedMessage=Rejestracja nie jest dozwolona +resetCredentialNotAllowedMessage=Zresetowanie poświadczeń nie jest dozwolone + +permissionNotApprovedMessage=Uprawnienie nie zatwierdzone. +noRelayStateInResponseMessage=Brak przekazanego stanu w odpowiedzi dostawcy tożsamości. +insufficientPermissionMessage=Niewystarczające uprawnienia do łączenia tożsamości. +couldNotProceedWithAuthenticationRequestMessage=Nie można kontynuować żądania uwierzytelnienia do dostawcy tożsamości. +couldNotObtainTokenMessage=Nie można uzyskać tokenu od dostawcy tożsamości. +unexpectedErrorRetrievingTokenMessage=Nieoczekiwany błąd podczas pobierania tokenu od dostawcy tożsamości. +unexpectedErrorHandlingResponseMessage=Nieoczekiwany błąd podczas obsługi odpowiedzi od dostawcy tożsamości. +identityProviderAuthenticationFailedMessage=Uwierzytelnianie nie powiodło się. Nie można uwierzytelnić za pomocą dostawcy tożsamości. +couldNotSendAuthenticationRequestMessage=Nie może wysyłać żądania uwierzytelniania do dostawcy tożsamości. +unexpectedErrorHandlingRequestMessage=Nieoczekiwany błąd podczas obsługi żądania uwierzytelnienia do dostawcy tożsamości. +invalidAccessCodeMessage=Nieprawidłowy kod dostępu. +sessionNotActiveMessage=Sesja nie jest aktywna. +invalidCodeMessage=Wystąpił błąd, zaloguj się ponownie za pośrednictwem aplikacji. +identityProviderUnexpectedErrorMessage=Nieoczekiwany błąd podczas uwierzytelniania u dostawcy tożsamości +identityProviderNotFoundMessage=Nie można odnaleźć dostawcy tożsamości z tym identyfikatorem. +identityProviderLinkSuccess=Pomyślnie zweryfikowano e-mail. Wróć do oryginalnej przeglądarki i tam kontynuuj logowanie. +staleCodeMessage=Ta strona nie jest już ważna, proszę wrócić do aplikacji i zalogować się ponownie +realmSupportsNoCredentialsMessage=Strefa nie obsługuje dowolnego typu poświadczeń. +identityProviderNotUniqueMessage=Strefa obsługuje wielu dostawców tożsamości. Nie można określić dostawcy tożsamości, który powinien być używany do uwierzytelniania. +emailVerifiedMessage=Twój adres e-mail został zweryfikowany. +staleEmailVerificationLink=Użyto nieaktualny link stanu, który stracił ważność. Może e-mail został już zweryfikowany? +identityProviderAlreadyLinkedMessage=Stowarzyszona tożsamość, zwrócona przez {0} jest już połączona z innym użytkownikiem. +confirmAccountLinking=Potwierdź powiązanie konta {0} dostawcy tożsamości {1} z twoim kontem. +confirmEmailAddressVerification=Potwierdź ważność adresu e-mail {0}. +confirmExecutionOfActions=Wykonaj następujące akcje + +backToApplication=« Powrót do aplikacji +missingParameterMessage=Brakujące parametry\: {0} +clientNotFoundMessage=Klient nie znaleziony. +clientDisabledMessage=Klient nieaktywny. +invalidParameterMessage=Nieprawidłowy parametr\: {0} +alreadyLoggedIn=Jesteś już zalogowany. +differentUserAuthenticated=Jesteś już uwierzytelniona/y jako inny użytkownik ''{0}'' w tej sesji. Najpierw się wyloguj. +brokerLinkingSessionExpired=Żądano łączenia kont brokera, ale bieżąca sesja już jest nieważna. +proceedWithAction=» kliknij tutaj, aby przejść + +requiredAction.CONFIGURE_TOTP=Skonfiguruj OTP +requiredAction.terms_and_conditions=Regulamin +requiredAction.UPDATE_PASSWORD=Zaktualizuj hasło +requiredAction.UPDATE_PROFILE=Zaktualizuj profil +requiredAction.VERIFY_EMAIL=Zweryfikuj adres e-mail + +doX509Login=Użytkownik będzie zalogowany jako\: +clientCertificate=X509 certyfikat klienta\: +noCertificate=[brak certyfikatu] + + +pageNotFound=Nie znaleziono strony +internalServerError=Wystąpił błąd wewnętrzny serwera + +console-username=Nazwa użytkownika\: +console-password=Hasło\: +console-otp=Hasło jednorazowe\: +console-new-password=Nowe hasło\: +console-confirm-password=Potwierdź hasło\: +console-update-password=Aktualizacja hasła jest wymagana. +console-verify-email=Musisz zweryfikować swój adres e-mail. Wiadomość e-mail z kodem weryfikacyjnym została wysłana do {0}. Podaj ten kod poniżej. +console-email-code=Kod z e-mail\: +console-accept-terms=Akceptujesz warunki? [t/n]\: +console-accept=t diff --git a/keycloak-themes/base/login/messages/messages_pt_BR.properties b/keycloak-themes/base/login/messages/messages_pt_BR.properties new file mode 100644 index 0000000..796bf29 --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_pt_BR.properties @@ -0,0 +1,380 @@ +doLogIn=Entrar +doRegister=Cadastre-se +doCancel=Cancelar +doSubmit=Ok +doBack=Voltar +doYes=Sim +doNo=N\u00E3o +doContinue=Continuar +doIgnore=Ignorar +doAccept=Aceitar +doDecline=Rejeitar +doForgotPassword=Esqueceu sua senha? +doClickHere=Clique aqui +doImpersonate=Personificar +doTryAgain=Tente novamente +doTryAnotherWay=Tente outra forma +doConfirmDelete=Confirmar descadastramento +errorDeletingAccount=Falha ao apagar conta +deletingAccountForbidden=Voc\u00ea n\u00e3o tem permiss\u00f5es para apagar a sua pr\u00f3pria conta, entre em contato com um administrador. +kerberosNotConfigured=Kerberos N\u00E3o Configurado +kerberosNotConfiguredTitle=Kerberos N\u00E3o Configurado +bypassKerberosDetail=Ou voc\u00EA n\u00E3o possui uma sess\u00e3o Kerberos ou o seu navegador n\u00E3o est\u00E1 configurado para usar o acesso do Kerberos. Por favor, clique em continuar para fazer o login no atrav\u00E9s de outros meios +kerberosNotSetUp=Kerberos n\u00E3o est\u00E1 configurado. Voc\u00EA n\u00E3o pode acessar a aplica\u00e7\u00e3o. +registerTitle=Registre-se +loginAccountTitle=Entrar na sua conta +loginTitle=Entrar em {0} +loginTitleHtml={0} +impersonateTitle={0} Personificar Usu\u00E1rio +impersonateTitleHtml={0} Personificar Usu\u00E1rio +realmChoice=Dom\u00EDnio +unknownUser=Usu\u00E1rio desconhecido +loginTotpTitle=Configura\u00E7\u00E3o do autenticador m\u00f3vel +loginProfileTitle=Atualizar Informa\u00E7\u00F5es da Conta +loginTimeout=Voc\u00EA demorou muito para entrar. Por favor, recomece o processo de login. +oauthGrantTitle=Conceder acesso a {0} +oauthGrantTitleHtml={0} +errorTitle=Sentimos muito... +errorTitleHtml=Sentimos muito ... +emailVerifyTitle=Verifica\u00E7\u00E3o de endere\u00e7o de e-mail +emailForgotTitle=Esqueceu sua senha? +updatePasswordTitle=Atualizar senha +codeSuccessTitle=C\u00F3digo de sucesso +codeErrorTitle=C\u00F3digo de erro\: {0} +displayUnsupported=Tipo de exibi\u00E7\u00E3o solicitado n\u00E3o suportado +browserRequired=Navegador necess\u00E1rio para realizar acesso +browserContinue=Navegador necess\u00E1rio para concluir o login +browserContinuePrompt=Abrir navegador e continuar o login? [s/n]: +browserContinueAnswer=s + + +termsTitle=Termos e Condi\u00E7\u00F5es +termsText=

    Termos e condi\u00E7\u00F5es a serem definidos

    +termsPlainText=Termos e condi\u00E7\u00F5es a serem definidos. + +recaptchaFailed=Recaptcha Inv\u00E1lido +recaptchaNotConfigured=O recaptcha \u00E9 necess\u00e1rio, mas n\u00E3o foi configurado +consentDenied=Consentimento negado. + +noAccount=Novo usu\u00E1rio? +username=Nome de usu\u00E1rio +usernameOrEmail=Nome de usu\u00E1rio ou e-mail +firstName=Primeiro nome +givenName=Primeiro nome +fullName=Nome completo +lastName=Sobrenome +familyName=Sobrenome +email=Endere\u00e7o de e-mail +password=Senha +passwordConfirm=Confirme a senha +passwordNew=Nova senha +passwordNewConfirm=Confirma\u00E7\u00E3o de Nova Senha +rememberMe=Mantenha-me conectado +authenticatorCode=C\u00F3digo autenticador +address=Endere\u00E7o +street=Logradouro +locality=Cidade ou localidade +region=Estado +postal_code=CEP +country=Pa\u00EDs +emailVerified=Endere\u00e7o de e-mail verificado +website=P\u00e1gina da web +phoneNumber=N\u00famero de telefone +phoneNumberVerified=N\u00famero de telefone verificado +gender=G\u00eanero +birthday=Data de nascimento +zoneinfo=Zona hor\u00e1ria +gssDelegationCredential=Delega\u00E7\u00E3o de Credenciais GSS +logoutOtherSessions=Sair dos outros dispositivos + +profileScopeConsentText=Perfil de usu\u00E1rio +emailScopeConsentText=Endere\u00E7o de e-mail +addressScopeConsentText=Endere\u00E7o +phoneScopeConsentText=N\u00FAmero de telefone +offlineAccessScopeConsentText=Acesso Offline +samlRoleListScopeConsentText=Meus Perfis de Acesso +rolesScopeConsentText=Perfis de acesso do usu\u00E1rio + +restartLoginTooltip=Reiniciar o login + +loginTotpIntro=Voc\u00EA precisa configurar um gerador de c\u00F3digo de uso \u00FAnico para acessar esta conta +loginTotpStep1=Instale um dos seguintes aplicativos no seu celular: +loginTotpStep2=Abra o aplicativo e escaneie o c\u00f3digo QR: +loginTotpStep3=Digite o c\u00F3digo de uso \u00FAnico fornecido pelo aplicativo e clique em Ok para concluir a configura\u00E7\u00E3o. +loginTotpStep3DeviceName=Forne\u00E7a um nome de dispositivo para ajud\u00E1-lo a gerenciar seus dispositivos de autentica\u00e7\u00e3o de dois fatores. +loginTotpManualStep2=Abra o aplicativo e digite a chave: +loginTotpManualStep3=Use os seguintes valores de configura\u00E7\u00E3o se o aplicativo permitir defini-los: +loginTotpUnableToScan=N\u00E3o foi poss\u00EDvel ler o c\u00f3digo QR? +loginTotpScanBarcode=Escanear c\u00f3digo QR? +loginCredential=Credencial +loginOtpOneTime=C\u00F3digo de uso \u00fanico +loginTotpType=Tipo +loginTotpAlgorithm=Algoritmo +loginTotpDigits=D\u00EDgitos +loginTotpInterval=Intervalo +loginTotpCounter=Contador +loginTotpDeviceName=Nome do dispositivo + +loginTotp.totp=Baseado em tempo +loginTotp.hotp=Baseado em contador + +loginChooseAuthenticator=Selecione o m\u00E9todo de login + +oauthGrantRequest=Voc\u00EA concede esses privil\u00E9gios de acesso? +inResource=em + +emailVerifyInstruction1=Um e-mail com instru\u00E7\u00F5es para verificar o seu endere\u00E7o de e-mail foi enviado para voc\u00EA. +emailVerifyInstruction2=N\u00E3o recebeu um c\u00F3digo de verifica\u00E7\u00E3o em seu e-mail? +emailVerifyInstruction3=para reenviar o e-mail. + +emailLinkIdpTitle=Vincular {0} +emailLinkIdp1=Um e-mail com instru\u00E7\u00F5es para vincular a conta {0} {1} com sua conta {2} foi enviado para voc\u00EA. +emailLinkIdp2=N\u00E3o recebeu um c\u00F3digo de verifica\u00E7\u00E3o no e-mail? +emailLinkIdp3=para reenviar o e-mail. +emailLinkIdp4=Se voc\u00EA j\u00E1 verificou o email em outro navegador +emailLinkIdp5=para continuar. + +backToLogin=« Voltar ao Login + +emailInstruction=Digite seu nome de usu\u00E1rio ou endere\u00E7o de e-mail e n\u00F3s lhe enviaremos instru\u00E7\u00F5es sobre como criar uma nova senha. + +copyCodeInstruction=Por favor, copie o c\u00F3digo e cole-o em seu aplicativo: + +pageExpiredTitle=A p\u00E1gina expirou +pageExpiredMsg1=Para reiniciar o processo de login +pageExpiredMsg2=Para continuar o processo de login + +personalInfo=Informa\u00E7\u00F5es Pessoais: +role_admin=Admininstrador +role_realm-admin=Admininstrador do Dom\u00EDnio +role_create-realm=Criar dom\u00EDnio +role_create-client=Criar cliente +role_view-realm=Visualizar dom\u00EDnio +role_view-users=Visualizar usu\u00E1rios +role_view-applications=Visualizar aplicativos +role_view-clients=Visualizar clientes +role_view-events=Visualizar eventos +role_view-identity-providers=Visualizar provedores de identidade +role_manage-realm=Gerenciar dom\u00EDnio +role_manage-users=Gerenciar usu\u00E1rios +role_manage-applications=Gerenciar aplicativos +role_manage-identity-providers=Gerenciar provedores de identidade +role_manage-clients=Gerenciar clientes +role_manage-events=Gerenciar eventos +role_view-profile=Visualizar perfil +role_manage-account=Gerenciar conta +role_manage-account-links=Gerenciar vincula\u00e7\u00f5es de conta +role_read-token=Ler token +role_offline-access=Acesso offline +client_account=Conta +client_account-console=Console da Conta +client_security-admin-console=Console de Administra\u00E7\u00E3o de Seguran\u00E7a +client_admin-cli=CLI de Administra\u00e7\u00e3o +client_realm-management=Gerenciamento de Dom\u00EDnio +client_broker=Provedor de Identidade + +requiredFields=Campos obrigat\u00F3rios + +invalidUserMessage=Nome de usu\u00E1rio ou senha inv\u00E1lida. +invalidUsernameMessage=Nome de usu\u00E1rio inv\u00E1lido. +invalidUsernameOrEmailMessage=Nome de usu\u00E1rio ou endere\u00e7o de e-mail inv\u00E1lido. +invalidPasswordMessage=Senha inv\u00E1lida. +invalidEmailMessage=Endere\u00e7o de e-mail inv\u00E1lido. +accountDisabledMessage=Conta desativada, por favor, contate um administrador. +accountTemporarilyDisabledMessage=Conta temporariamente indispon\u00EDvel, por favor, contate um administrador ou tente novamente mais tarde. +expiredCodeMessage=Tempo de login expirado. Por favor, fa\u00E7a login novamente. +expiredActionMessage=A\u00E7\u00E3o expirada. Por favor, continue com o login agora. +expiredActionTokenNoSessionMessage=A\u00E7\u00E3o expirada. +expiredActionTokenSessionExistsMessage=A\u00E7\u00E3o expirada. Por favor, comece novamente. + +missingFirstNameMessage=Por favor, informe o primeiro nome. +missingLastNameMessage=Por favor, informe o sobrenome. +missingEmailMessage=Por favor, informe o endere\u00e7o de e-mail. +missingUsernameMessage=Por favor, informe o nome de usu\u00E1rio. +missingPasswordMessage=Por favor, informe a senha. +missingTotpMessage=Por favor, informe o c\u00F3digo de uso \u00fanico. +missingTotpDeviceNameMessage=Por favor, informe o nome do dispositivo. +notMatchPasswordMessage=As senhas n\u00E3o coincidem. + +invalidPasswordExistingMessage=Senha atual inv\u00E1lida. +invalidPasswordBlacklistedMessage=Senha inv\u00E1lida, devido a lista de exclus\u00e3o. +invalidPasswordConfirmMessage=Senha de confirma\u00E7\u00E3o n\u00E3o coincide. +invalidTotpMessage=C\u00F3digo de uso \u00fanico inv\u00E1lido. + +usernameExistsMessage=Nome de usu\u00E1rio j\u00E1 existe. +emailExistsMessage=Endere\u00e7o de e-mail j\u00E1 existe. + +federatedIdentityExistsMessage=Usu\u00E1rio com {0} {1} j\u00E1 existe. Por favor, entre no gerenciamento de conta para vincular a conta. +federatedIdentityUnavailableMessage=Usu\u00e1rio {0} autenticado com o provedor de identidade {1} n\u00e3o existe. Por favor, entre em contato com um administrador. + +confirmLinkIdpTitle=Conta j\u00E1 existente +federatedIdentityConfirmLinkMessage=Usu\u00E1rio com {0} {1} j\u00E1 existe. Como voc\u00EA quer continuar? +federatedIdentityConfirmReauthenticateMessage=Autenticar para vincular sua conta com {0} +nestedFirstBrokerFlowMessage=O usu\u00e1rio {0} {1} n\u00e3o est\u00e1 vinculado a nenhum usu\u00e1rio conhecido. +confirmLinkIdpReviewProfile=Revisar informa\u00E7\u00F5es do perfil +confirmLinkIdpContinue=Vincular \u00E0 conta existente + +configureTotpMessage=Voc\u00EA precisa configurar seu celular com o autenticador Mobile para ativar sua conta. +updateProfileMessage=Voc\u00EA precisa atualizar o seu perfil de usu\u00E1rio para ativar sua conta. +updatePasswordMessage=Voc\u00EA precisa mudar sua senha para ativar sua conta. +resetPasswordMessage=Voc\u00EA precisa mudar sua senha. +verifyEmailMessage=Voc\u00EA precisa verificar o seu endere\u00E7o de e-mail para ativar sua conta. +linkIdpMessage=Voc\u00EA precisa confirmar o seu endere\u00E7o de e-mail para vincular sua conta com {0}. + +emailSentMessage=Voc\u00EA dever\u00E1 receber um e-mail em breve com mais instru\u00E7\u00F5es. +emailSendErrorMessage=Falha ao enviar e-mail, por favor, tente novamente mais tarde. + +accountUpdatedMessage=Sua conta foi atualizada. +accountPasswordUpdatedMessage=Sua senha foi atualizada. + +delegationCompleteHeader=Autentica\u00E7\u00E3o Bem Sucedida +delegationCompleteMessage=Voc\u00ea pode fechar esta janela do navegador e voltar ao seu aplicativo. +delegationFailedHeader=Falha na Autentica\u00E7\u00E3o +delegationFailedMessage=Voc\u00EA pode fechar esta janela do navegador e voltar ao aplicativo e tentar fazer login novamente. + +noAccessMessage=Sem acesso + +invalidPasswordMinLengthMessage=Senha inv\u00E1lida\: deve ter pelo menos {0} caracteres. +invalidPasswordMinDigitsMessage=Senha inv\u00E1lida\: deve conter pelo menos {0} n\u00FAmero(s). +invalidPasswordMinLowerCaseCharsMessage=Senha inv\u00E1lida\: deve conter pelo menos {0} letra(s) min\u00FAscula(s). +invalidPasswordMinUpperCaseCharsMessage=Senha inv\u00E1lida\: deve conter pelo menos {0} letra(s) mai\u00FAscula(s). +invalidPasswordMinSpecialCharsMessage=Senha inv\u00E1lida\: deve conter pelo menos {0} caractere(s) especial(is). +invalidPasswordNotUsernameMessage=Senha inv\u00E1lida\: n\u00E3o pode ser igual ao nome de usu\u00E1rio +invalidPasswordNotEmailMessage=Senha inv\u00e1lida: n\u00e3o pode ser igual ao endere\u00e7o de e-mail. +invalidPasswordRegexPatternMessage=Senha inv\u00E1lida\: n\u00E3o corresponde ao(s) padr\u00e3o(\u00f5es) de express\u00E3o regular. +invalidPasswordHistoryMessage=Senha inv\u00E1lida\: n\u00E3o pode ser igual a qualquer uma da(s) \u00FAltima(s) {0} senha(s). +invalidPasswordGenericMessage=Senha inv\u00E1lida: a nova senha n\u00E3o cumpre as pol\u00EDticas de senha. + +failedToProcessResponseMessage=Falha ao processar a resposta +httpsRequiredMessage=HTTPS necess\u00e1rio +realmNotEnabledMessage=Dom\u00EDnio desativado +invalidRequestMessage=Solicita\u00e7\u00e3o inv\u00E1lida +failedLogout=Falha ao sair +unknownLoginRequesterMessage=Solicitante de login desconhecido +loginRequesterNotEnabledMessage=Solicitante de login desativado +bearerOnlyMessage=Aplicativos configurados como Bearer-Only n\u00E3o t\u00eam permiss\u00E3o para iniciar o login pelo navegador +standardFlowDisabledMessage=O cliente n\u00E3o tem permiss\u00E3o para iniciar o login com o response_type informado. O fluxo padr\u00E3o est\u00E1 desabilitado para o cliente. +implicitFlowDisabledMessage=O cliente n\u00E3o tem permiss\u00E3o para iniciar o login com o response_type informado. O fluxo impl\u00EDcito est\u00E1 desabilitado para o cliente. +invalidRedirectUriMessage=URI de redirecionamento inv\u00E1lido +unsupportedNameIdFormatMessage=NameIDFormat n\u00E3o suportado +invalidRequesterMessage=Solicitante inv\u00E1lido +registrationNotAllowedMessage=Cadastro n\u00E3o \u00e9 permitido +resetCredentialNotAllowedMessage=Sem permiss\u00e3o de redefini\u00e7\u00e3o de credenciais + +permissionNotApprovedMessage=Permiss\u00E3o n\u00E3o aprovada. +noRelayStateInResponseMessage=Sem estado de retransmiss\u00E3o na resposta do provedor de identidade. +insufficientPermissionMessage=Permiss\u00F5es insuficientes para vincular identidades. +couldNotProceedWithAuthenticationRequestMessage=N\u00E3o foi poss\u00EDvel proceder com a solicita\u00E7\u00E3o de autentica\u00E7\u00E3o ao provedor de identidade. +couldNotObtainTokenMessage=N\u00E3o foi poss\u00EDvel obter token do provedor de identidade. +unexpectedErrorRetrievingTokenMessage=Erro inesperado ao recuperar token do provedor de identidade. +unexpectedErrorHandlingResponseMessage=Erro inesperado ao tratar a resposta do provedor de identidade. +identityProviderAuthenticationFailedMessage=Falha na autentica\u00E7\u00E3o. N\u00E3o foi poss\u00EDvel autenticar com o provedor de identidade. +couldNotSendAuthenticationRequestMessage=N\u00E3o foi poss\u00EDvel enviar a solicita\u00E7\u00E3o de autentica\u00E7\u00E3o ao provedor de identidade. +unexpectedErrorHandlingRequestMessage=Erro inesperado ao tratar o pedido de autentica\u00E7\u00E3o ao provedor de identidade. +invalidAccessCodeMessage=C\u00F3digo de acesso inv\u00E1lido. +sessionNotActiveMessage=Sess\u00E3o inativa. +invalidCodeMessage=Um erro correu, por favor, fa\u00E7a login novamente atrav\u00E9s da aplica\u00E7\u00E3o. +identityProviderUnexpectedErrorMessage=Erro inesperado durante a autentica\u00E7\u00E3o com o provedor de identidade +identityProviderMissingStateMessage=Par\u00e2metro de estado ausente da resposta do provedor de identidades. +identityProviderNotFoundMessage=N\u00E3o foi poss\u00EDvel encontrar um provedor de identidade com o identificador. +identityProviderLinkSuccess=O seu endere\u00e7o de e-mail foi confirmado com sucesso. Por favor, retorne \u00e0 aba original e continue com o login. +staleCodeMessage=Esta p\u00E1gina n\u00E3o \u00E9 mais v\u00E1lida. Por favor, volte \u00e0 aplica\u00e7\u00e3o e fa\u00E7a login novamente +realmSupportsNoCredentialsMessage=O dom\u00EDnio n\u00E3o suporta qualquer tipo de credencial. +credentialSetupRequired=N\u00E3o \u00E9 poss\u00EDvel fazer o login, a configura\u00E7\u00E3o de credencial \u00e9 necess\u00e1ria. +identityProviderNotUniqueMessage=O dom\u00EDnio suporta m\u00FAltiplos provedores de identidade. N\u00E3o foi poss\u00EDvel determinar qual o provedor de identidade deve ser usado para autentica\u00e7\u00e3o. +emailVerifiedMessage=O seu endere\u00E7o de e-mail foi confirmado. +staleEmailVerificationLink=O link em que voc\u00EA clicou \u00E9 um link antigo e n\u00E3o \u00E9 mais v\u00E1lido. Talvez voc\u00EA j\u00E1 tenha confirmado o seu endere\u00e7o de e-mail. +identityProviderAlreadyLinkedMessage=A conta retornada do {0} j\u00E1 est\u00E1 vinculada a outro usu\u00E1rio. +confirmAccountLinking=Confirme o vincula\u00e7\u00e3o da conta {0} do provedor de identidade {1} \u00E0 sua conta. +confirmEmailAddressVerification=Confirme a validade do endere\u00E7o de e-mail {0}. +confirmExecutionOfActions=Execute a(s) seguinte(s) a\u00E7\u00E3o(\u00F5es) + +backToApplication=« Voltar para o aplicativo +missingParameterMessage=Par\u00E2metros ausentes\: {0} +clientNotFoundMessage=Cliente n\u00E3o encontrado. +clientDisabledMessage=Cliente desativado. +invalidParameterMessage=Par\u00E2mentro inv\u00E1lido\: {0} +alreadyLoggedIn=Voc\u00EA j\u00E1 est\u00E1 logado. +differentUserAuthenticated=Voc\u00EA j\u00E1 est\u00E1 autenticado como outro usu\u00E1rio ''{0}'' nesta sess\u00E3o. Por favor, finalize a sess\u00e3o primeiro. +brokerLinkingSessionExpired=A vincul\u00e7\u00e3o de conta do provedor de identidade foi solicitado, mas a sess\u00E3o atual n\u00E3o \u00E9 mais v\u00E1lida. +proceedWithAction=» Clique aqui para continuar + +requiredAction.CONFIGURE_TOTP=Configurar Autentica\u00e7\u00e3o de Dois Fatores +requiredAction.terms_and_conditions=Termos e Condi\u00E7\u00F5es +requiredAction.UPDATE_PASSWORD=Atualizar Senha +requiredAction.UPDATE_PROFILE=Atualizar Perfil +requiredAction.VERIFY_EMAIL=Verificar Endere\u00e7o de E-mail + +doX509Login=Voc\u00EA ser\u00E1 logado como\: +clientCertificate=Certificado X509 do cliente\: +noCertificate=[Sem Certificado] + + +pageNotFound=P\u00E1gina n\u00E3o encontrada +internalServerError=Ocorreu um erro interno no servidor + +console-username=Nome de usu\u00E1rio: +console-password=Senha: +console-otp=C\u00F3digo de uso \u00FAnico: +console-new-password=Nova Senha: +console-confirm-password=Confirma\u00E7\u00E3o de Senha: +console-update-password=Voc\u00ea precisa atualizar a sua senha. +console-verify-email=Voc\u00EA precisa verificar o seu endere\u00E7o de e-mail. Enviamos um e-mail para {0} que cont\u00E9m um c\u00F3digo de verifica\u00E7\u00E3o. Digite o c\u00F3digo enviado no campo abaixo. +console-email-code=C\u00F3digo do e-mail: +console-accept-terms=Aceita os Termos? [s/n]: +console-accept=s + +# Openshift messages +openshift.scope.user_info=Informa\u00e7\u00f5es do usu\u00E1rio +openshift.scope.user_check-access=Informa\u00e7\u00f5es de acesso do usu\u00E1rio +openshift.scope.user_full=Acesso Completo +openshift.scope.list-projects=Listar projetos + +# SAML authentication +saml.post-form.title=Redirecionamento de Autentica\u00E7\u00E3o +saml.post-form.message=Redirecionando... Por favor, aguarde. +saml.post-form.js-disabled=O JavaScript est\u00E1 desabilitado. \u00C9 altamente recomend\u00E1vel habilit\u00E1-lo. Clique no bot\u00E3o abaixo para continuar. + +#authenticators +otp-display-name=Aplicativo Autenticador +otp-help-text=Insira o c\u00F3digo de verifica\u00E7\u00E3o do aplicativo autenticador. +password-display-name=Senha +password-help-text=Fa\u00E7a o login digitando sua senha. +auth-username-form-display-name=Nome de usu\u00E1rio +auth-username-form-help-text=Fa\u00E7a o login digitando seu nome de usu\u00E1rio. +auth-username-password-form-display-name=Nome de usu\u00E1rio e senha +auth-username-password-form-help-text=Fa\u00E7a o login digitando seu nome de usu\u00E1rio e senha. + +# WebAuthn +webauthn-display-name=Chave de Seguran\u00E7a +webauthn-help-text=Use sua chave de seguran\u00E7a para fazer login. +webauthn-passwordless-display-name=Chave de Seguran\u00E7a +webauthn-passwordless-help-text=Use sua chave de seguran\u00E7a para fazer login sem senha. +webauthn-login-title=Login com Chave de Seguran\u00E7a +webauthn-registration-title=Registrar Chave de Seguran\u00E7a +webauthn-available-authenticators=Autenticadores dispon\u00EDveis +webauthn-unsupported-browser-text=WebAuthn n\u00e3o \u00e9 suportada pelo seu navegador. Tente outro navegador ou entre em contato com um administrador. + +# WebAuthn Error +webauthn-error-title=Erro de Chave de Seguran\u00E7a +webauthn-error-registration=Falha ao registrar sua Chave de Seguran\u00E7a. +webauthn-error-api-get=Falha ao autenticar usando a Chave de Seguran\u00E7a. +webauthn-error-different-user=O primeiro usu\u00E1rio autenticado n\u00E3o corresponde \u00e0quele autenticado pela Chave de Seguran\u00E7a. +webauthn-error-auth-verification=O resultado da autentica\u00E7\u00E3o da Chave de Seguran\u00E7a \u00E9 inv\u00E1lido.
    {0} +webauthn-error-register-verification=O resultado do registro da Chave de Seguran\u00E7a \u00E9 inv\u00E1lido.
    {0} +webauthn-error-user-not-found=Usu\u00E1rio desconhecido autenticado pela Chave de Seguran\u00E7a. + +# Identity provider +identity-provider-redirector=Conecte-se com outro Provedor de Identidade +identity-provider-login-label=Ou entre com + +finalDeletionConfirmation=Se voc\u00ea apagar a sua conta, ela n\u00e3o poder\u00e1 ser recuperada. Para manter a sua conta, clique em Cancelar. +irreversibleAction=Esta a\u00e7\u00e3o \u00e9 irrevers\u00edvel +deleteAccountConfirm=Confirma\u00e7\u00e3o de descadastramento + +deletingImplies=Apagar a sua conta implica em: +errasingData=Remover todos os seus dados +loggingOutImmediately=Sair da aplica\u00e7\u00e3o imediatamente +accountUnusable=Qualquer uso subsequente da aplica\u00e7\u00e3o n\u00e3o ser\u00e1 poss\u00edvel com esta conta +userDeletedSuccessfully=Usu\u00e1rio exclu\u00eddo com sucesso + diff --git a/keycloak-themes/base/login/messages/messages_ru.properties b/keycloak-themes/base/login/messages/messages_ru.properties new file mode 100644 index 0000000..4ca80bf --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_ru.properties @@ -0,0 +1,217 @@ +# encoding: utf-8 +doLogIn=Вход +doRegister=Регистрация +doCancel=Отмена +doSubmit=Подтвердить +doYes=Да +doNo=Нет +doContinue=Продолжить +doAccept=Подтвердить +doDecline=Отменить +doForgotPassword=Забыли пароль? +doClickHere=Нажмите сюда +doImpersonate=Имперсонализироваться +kerberosNotConfigured=Kerberos не сконфигурирован +kerberosNotConfiguredTitle=Kerberos не сконфигурирован +bypassKerberosDetail=Либо вы не вошли в систему с помощью Kerberos, либо ваш браузер не настроен для входа в систему Kerberos. Пожалуйста, нажмите кнопку 'Продолжить' для входа в с помощью других средств +kerberosNotSetUp=Kerberos не настроен. Вы не можете войти. +registerWithTitle=Зарегистрироваться с {0} +registerWithTitleHtml={0} +loginTitle=Log in to {0} +loginTitleHtml={0} +impersonateTitle={0} Имперсонализация пользователя +impersonateTitleHtml={0} Имперсонализация пользователя +realmChoice=Realm +unknownUser=Неизвестный пользователь +loginTotpTitle=Настройка мобильного аутентификатора +loginProfileTitle=Обновление информации учетной записи +loginTimeout=Вы слишком долго бездействовали. Процесс аутентификации начнется с начала. +oauthGrantTitle=Согласовать доступ +oauthGrantTitleHtml={0} +errorTitle=Мы сожалеем... +errorTitleHtml=Мы сожалеем ... +emailVerifyTitle=Подтверждение адреса E-mail +emailForgotTitle=Забыли пароль? +updatePasswordTitle=Обновление пароля +codeSuccessTitle=Успешный код +codeErrorTitle=Ошибочный код\: {0} + +termsTitle=Условия и положения +termsTitleHtml=Условия и положения +termsText=

    Условия и положения должны быть определены

    + +recaptchaFailed=Некорректная Recaptcha +recaptchaNotConfigured=Recaptcha требуется, но не сконфигурирована +consentDenied=В согласовании отказано. + +noAccount=Новый пользователь? +username=Имя пользователя +usernameOrEmail=Имя пользователя или E-mail +firstName=Имя +givenName=Выданное имя +fullName=Полное имя +lastName=Фамилия +familyName=Фамилия +email=E-mail +password=Пароль +passwordConfirm=Подтверждение пароля +passwordNew=Новый пароль +passwordNewConfirm=Подтверждение нового пароля +rememberMe=Запомнить меня +authenticatorCode=Одноразовый код +address=Адрес +street=Улица +locality=Город +region=Регион +postal_code=Почтовый индекс +country=Страна +emailVerified=E-mail подтвержден +gssDelegationCredential=Делегирование учетных данных GSS + +loginTotpStep1=Установите FreeOTP или Google Authenticator. Оба приложения доступны в Google Play и Apple App Store. +loginTotpStep2=Откройте приложение и просканируйте баркод, либо введите ключ +loginTotpStep3=Введите одноразовый пароль, выданный приложением, и нажмите сохранить для завершения установки +loginOtpOneTime=Одноразовый пароль + +oauthGrantRequest=Вы согласуете доступ к этим привилегиям? +inResource=в + +emailVerifyInstruction1=Вам было отправлено письмо с инструкциями для подтверждения адреса E-mail. +emailVerifyInstruction2=Не получили письмо с кодом подтверждения? +emailVerifyInstruction3=для повторной отправки письма. + +emailLinkIdpTitle=Связать {0} +emailLinkIdp1=Вам было отправлено письмо с инструкциями по объединению {0} учетной записи {1} с вашей учетной записью {2}. +emailLinkIdp2=Не получили код подтверждения на ваш E-mail? +emailLinkIdp3=для повторной отправки письма. + +backToLogin=« Назад ко входу + +emailInstruction=Введите Ваше имя пользователя или E-mail и мы вышлем Вам инструкции по получению нового пароля. + +copyCodeInstruction=Пожалуйста, скопируйте этот код в приложение: + +personalInfo=Персональная информация: +role_admin=Администратор +role_realm-admin=Администратор realm +role_create-realm=Создание realm +role_create-client=Создание клиента +role_view-realm=Просмотр realm +role_view-users=Просмотр пользователей +role_view-applications=Просмотр приложений +role_view-clients=Просмотр клиентов +role_view-events=Просмотр событий +role_view-identity-providers=Просмотр провайдеров учетных записей +role_manage-realm=Управление realm +role_manage-users=Управление пользователями +role_manage-applications=Управление приложениями +role_manage-identity-providers=Управление провайдерами учетных записей +role_manage-clients=Управление клиентами +role_manage-events=Управление событиями +role_view-profile=Просмотр профиля +role_manage-account=Управление учетной записью +role_read-token=Чтение токена +role_offline-access=Оффлайн доступ +client_account=Учетная запись +client_security-admin-console=Консоль администратора безопасности +client_admin-cli=Командный интерфейс администратора +client_realm-management=Управление realm +client_broker=Брокер + +invalidUserMessage=Неправильное имя пользователя или пароль. +invalidEmailMessage=Неправильный E-mail. +accountDisabledMessage=Учетная запись заблокирована, свяжитесь с администратором. +accountTemporarilyDisabledMessage=Учетная запись временно заблокирована, свяжитесь с администратором или попробуйте позже. +expiredCodeMessage=Вход просрочен по таймауту. Пожалуйста, войдите снова. + +missingFirstNameMessage=Пожалуйста введите имя. +missingLastNameMessage=Пожалуйста введите фамилию. +missingEmailMessage=Пожалуйста введите E-mail. +missingUsernameMessage=Пожалуйста введите имя пользователя. +missingPasswordMessage=Пожалуйста введите пароль. +missingTotpMessage=Пожалуйста введите код аутентификатора. +notMatchPasswordMessage=Пароли не совпадают. + +invalidPasswordExistingMessage=Неверный существующий пароль. +invalidPasswordConfirmMessage=Подтверждение пароля не совпадает. +invalidTotpMessage=Неверный код аутентификатора. + +usernameExistsMessage=Имя пользователя уже занято. +emailExistsMessage=E-mail уже существует. + +federatedIdentityExistsMessage=Пользователь с {0} {1} уже существует. Пожалуйста войдите в управление учетными записями, чтобы связать эту учетную запись. + +confirmLinkIdpTitle=Учетная запись уже существует +federatedIdentityConfirmLinkMessage=Пользователь с {0} {1} уже сущестует. Хотите продолжить? +federatedIdentityConfirmReauthenticateMessage=Аутентифицируйтесь, чтобы связать Вашу учетную запись с {0} +confirmLinkIdpReviewProfile=Обзор профиля +confirmLinkIdpContinue=Добавить в существующую учетную запись + +configureTotpMessage=Вам необходимо настроить аутентификатор в мобильном устройстве, чтобы активировать учетную запись. +updateProfileMessage=Вам необходимо обновить свой профиль, чтобы активировать Вашу учетную запись. +updatePasswordMessage=Вам необходимо изменить пароль, чтобы активировать Вашу учетную запись. +verifyEmailMessage=Вам необходимо подтвердить Ваш E-mail, чтобы активировать Вашу учетную запись. +linkIdpMessage=Вам необходимо подтвердить Ваш E-mail, чтобы связать Вашу учетную запись с {0}. + +emailSentMessage=В ближайшее время Вы должны получить письмо с дальнейшими инструкциями. +emailSendErrorMessage=Не получается отправить письмо. Пожалуйста, повторите позже. + +accountUpdatedMessage=Ваша учетная запись успешно обновлена. +accountPasswordUpdatedMessage=Ваш пароль успешно обновлен. + +noAccessMessage=Нет доступа + +invalidPasswordMinLengthMessage=Некорректный пароль: длина пароля должна быть не менее {0} символов(а). +invalidPasswordMinDigitsMessage=Некорректный пароль: пароль должен содержать не менее {0} цифр(ы). +invalidPasswordMinLowerCaseCharsMessage=Некорректный пароль: пароль должен содержать не менее {0} символов(а) в нижнем регистре. +invalidPasswordMinUpperCaseCharsMessage=Некорректный пароль: пароль должен содержать не менее {0} символов(а) в верхнем регистре. +invalidPasswordMinSpecialCharsMessage=Некорректный пароль: пароль должен содержать не менее {0} спецсимволов(а). +invalidPasswordNotUsernameMessage=Некорректный пароль: пароль не должен совпадать с именем пользователя. +invalidPasswordRegexPatternMessage=Некорректный пароль: пароль не прошел проверку по регулярному выражению. +invalidPasswordHistoryMessage=Некорректный пароль: пароль не должен совпадать с последним(и) {0} паролем(ями). +invalidPasswordGenericMessage=Некорректный пароль: новый пароль не соответствует правилам пароля. + +failedToProcessResponseMessage=Не удалось обработать ответ +httpsRequiredMessage=Требуется HTTPS +realmNotEnabledMessage=Realm не включен +invalidRequestMessage=Неверный запрос +failedLogout=Выйти не удалось +unknownLoginRequesterMessage=Неизвестный клиент +loginRequesterNotEnabledMessage=Клиент отключен +bearerOnlyMessage=Bearer-only приложениям не разрешается инициализация входа через браузер +standardFlowDisabledMessage=Клиенту не разрешается инициировать вход через браузер с данным response_type. Standard flow отключен для этого клиента. +implicitFlowDisabledMessage=Клиенту не разрешается инициировать вход через браузер с данным response_type. Implicit flow отключен для этого клиента. +invalidRedirectUriMessage=Неверный uri для переадресации +unsupportedNameIdFormatMessage=Неподдерживаемый NameIDFormat +invalidRequesterMessage=Неверный запрашивающий +registrationNotAllowedMessage=Регистрация не разрешена +resetCredentialNotAllowedMessage=Сброс идентификационных данных не разрешен + +permissionNotApprovedMessage=Разрешение не подтверждено. +noRelayStateInResponseMessage=Нет изменения состояния в ответе от провайдера учетных записей. +insufficientPermissionMessage=Недостаточно полномочий для связывания идентификаторов. +couldNotProceedWithAuthenticationRequestMessage=Невозможно обработать аутентификационный запрос в провайдере учетных записей. +couldNotObtainTokenMessage=Не удалось получить токен от провайдера учетных записей. +unexpectedErrorRetrievingTokenMessage=Непредвиденная ошибка при получении токена от провайдера учетных записей. +unexpectedErrorHandlingResponseMessage=Непредвиденная ошибка при обработке ответа от провайдера учетных записей. +identityProviderAuthenticationFailedMessage=Аутентификация провалена. Невозможно аутентифицировать с поставщиком учетных записей. +couldNotSendAuthenticationRequestMessage=Не получается выполнить запрос аутентификации к поставщику учетных записей. +unexpectedErrorHandlingRequestMessage=Непредвиденная ошибка при обработке запроса аутентификации поставщика учетных записей. +invalidAccessCodeMessage=Неверный код доступа. +sessionNotActiveMessage=Сессия не активна. +invalidCodeMessage=Произошла ошибка. Пожалуйста, войдите в систему снова через ваше приложение. +identityProviderUnexpectedErrorMessage=Непредвиденная ошибка при проверке подлинности поставщика учетных записей. +identityProviderNotFoundMessage=Не удалось найти поставщика учетных записей с данным идентификатором. +identityProviderLinkSuccess=Ваша учетная запись была успешно соединена с {0} учетной записью {1} . +staleCodeMessage=Эта страница больше не действительна, пожалуйста, вернитесь в приложение и снова войдите в систему. +realmSupportsNoCredentialsMessage=Realm не поддерживает никакой тип учетных данных. +identityProviderNotUniqueMessage=Realm поддерживает несколько поставщиков учетных записей. Не удалось определить, какой именно поставщик должен использоваться для аутентификации. +emailVerifiedMessage=Ваш E-mail был подтвержден. +staleEmailVerificationLink=Ссылка, по которой Вы перешли, устарела и больше не действует. Может быть, вы уже подтвердили свой E-mail? + +backToApplication=« Назад в приложение +missingParameterMessage=Пропущенные параметры\: {0} +clientNotFoundMessage=Клиент не найден. +clientDisabledMessage=Клиент отключен. +invalidParameterMessage=Неверный параметр\: {0} +alreadyLoggedIn=Вы уже вошли. diff --git a/keycloak-themes/base/login/messages/messages_sk.properties b/keycloak-themes/base/login/messages/messages_sk.properties new file mode 100644 index 0000000..7734b5b --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_sk.properties @@ -0,0 +1,263 @@ +# encoding: utf-8 +doLogIn=Prihlásenie +doRegister=Registrácia +doCancel=Zrušiť +doSubmit=Odoslať +doYes=Áno +doNo=Nie +doContinue=Pokračovať +doAccept=Potvrdiť +doDecline=Odmietnuť +doForgotPassword=Zabudli ste heslo? +doClickHere=Kliknite tu +doImpersonate=Prevteliť +kerberosNotConfigured=Kerberos nie je nakonfigurovaný +kerberosNotConfiguredTitle=Kerberos nie je nakonfigurovaný +bypassKerberosDetail=Buď nie ste prihlásený cez Kerberos, alebo váš prehliadač nie je nastavený na prihlásenie do Kerberos. Kliknutím na tlačidlo Pokračovať sa prihláste iným spôsobom +kerberosNotSetUp=Kerberos nie je nastavený. Nemôžete sa prihlásiť. +registerWithTitle=Registrácia s {0} +registerWithTitleHtml={0} +loginTitle=Prihlásenie do {0} +loginTitleHtml={0} +impersonateTitle={0} prevteliť sa +impersonateTitleHtml={0} Prevteliť sa
    +realmChoice=Realm +unknownUser=Neznámy používateľ +loginTotpTitle=Nastavenie mobilného autentifikátora +loginProfileTitle=Aktualizácia informácií o účte +loginTimeout=Prihlasovanie trvalo príliš dlho. Prihlasovací proces začína od začiatku. +oauthGrantTitle=Poskytnúť prístup +oauthGrantTitleHtml={0} +errorTitle=Je nám ľúto ... +errorTitleHtml=Ospravedlňujeme sa ... +emailVerifyTitle=Overenie e-mailom +emailForgotTitle=Zabudli ste heslo? +updatePasswordTitle=Aktualizácia hesla +codeSuccessTitle=Kód úspechu +codeErrorTitle=Kód chyby\: {0} + +termsTitle=Zmluvné podmienky +termsTitleHtml=Zmluvné podmienky +termsText=

    Zmluvné podmienky, ktoré sa majú definovať

    + +recaptchaFailed=Neplatné Recaptcha +recaptchaNotConfigured=Recaptcha sa vyžaduje, ale nie je nakonfigurovaná +consentDenied=Súhlas bol zamietnutý. + +noAccount=Nový používateľ? +username=Prihlasovacie meno +usernameOrEmail=Prihlasovacie meno alebo e-mail +firstName=Meno +givenName=Meno pri narodení +fullName=Celé meno +lastName=Priezvisko +familyName=Rodné meno +email=E-mail +password=Heslo +passwordConfirm=Potvrdenie hesla +passwordNew=Nové heslo +passwordNewConfirm=Potvrdenie nového hesla +rememberMe=Zapamätať si ma +authenticatorCode=Jednorazový kód +address=Adresa +street=Ulica +locality=Mesto alebo lokalita +region=Kraj +postal_code=PSČ +country=Štát +emailVerified=E-mail overený +gssDelegationCredential=GSS delegované oprávnenie + +loginTotpStep1=Nainštalujte FreeOTP alebo Google Authenticator na mobil. Obidve aplikácie sú k dispozícii v Google Play a Apple App Store. +loginTotpStep2=Otvorte aplikáciu a skenujte čiarový kód alebo zadajte kľúč +loginTotpStep3=Zadajte jednorazový kód poskytnutý aplikáciou a kliknutím na tlačidlo Odoslať dokončite nastavenie +loginTotpManualStep2=Otvorte aplikáciu a zadajte kľúč +loginTotpManualStep3=Používajte nasledujúce hodnoty konfigurácie, ak aplikácia umožňuje ich nastavenie +loginTotpUnableToScan=Nemožno skenovať? +loginTotpScanBarcode=Skenovať čiarový kód? +loginOtpOneTime=Jednorázový kód +loginTotpType=Typ +loginTotpAlgorithm=Algoritmus +loginTotpDigits=Číslica +loginTotpInterval=Interval +loginTotpCounter=Počítadlo + +loginTotp.totp=Založené na čase +loginTotp.hotp=Založené na počítadle + +oauthGrantRequest=Udeľujete tieto prístupové oprávnenia? +inResource=v + +emailVerifyInstruction1=Bol Vám odoslaný e-mail s pokynmi na overenie vašej e-mailovej adresy. +emailVerifyInstruction2=Nezískali ste v e-maili overovací kód? +emailVerifyInstruction3=opätovne odoslať e-mail. + +emailLinkIdpTitle=Odkaz {0} +emailLinkIdp1=Bol vám odoslaný e-mail s pokynmi na prepojenie účtu {0} {1} s vaším účtom {2}. +emailLinkIdp2=Nezískali ste v e-maili verifikačný kód? +emailLinkIdp3=opätovne poslať e-mail. +emailLinkIdp4=Ak ste už overili e-mail v inom prehliadači +emailLinkIdp5=pokračovať. + +backToLogin=« Späť na prihlásenie + +emailInstruction=Zadajte svoje používateľské meno alebo e-mailovú adresu a my vám zašleme pokyny na vytvorenie nového hesla. +emailInstructionUsername=Zadajte svoje používateľské meno a my vám zašleme pokyny na vytvorenie nového hesla. + +copyCodeInstruction=Prosím skopírujte tento kód a vložte ho do vašej aplikácie: + +pageExpiredTitle=Platnosť stránky vypršala +pageExpiredMsg1=Pre reštartovanie prihlasovacieho procesu +pageExpiredMsg2=Pokračovanie prihlasovacieho procesu + +personalInfo=Osobné informácie: +role_admin=Administrátor +role_realm-admin=Realm administrátor +role_create-realm=Vytvoriť realm +role_create-client=Vytvoriť klienta +role_view-realm=Zobraziť realm +role_view-users=Zobraziť používateľov +role_view-applications=Zobraziť aplikácie +role_view-clients=Zobrazenie klientov +role_view-events=Zobraziť udalosti +role_view-identity-providers=Zobrazenie poskytovateľov identity +role_manage-realm=Spravovať realm +role_manage-users=Spravovať používateľov +role_manage-applications=Spravovať aplikácie +role_manage-identity-providers=Spravovať poskytovateľov identity +role_manage-clients=Spravovať klientov +role_manage-events=Spravovať udalosti +role_view-profile=Zobraziť profil +role_manage-account=Spravovať účty +role_manage-account-links=Spravovať odkazy na účty +role_read-token=Čítať token +role_offline-access=Offline prístup +client_account=Účet klienta +client_security-admin-console=Administrátorská bezpečnostná konzola klienta +client_admin-cli=Správca CLI +client_realm-management=Správa realmov klienta +client_broker=Broker + +invalidUserMessage=Neplatné používateľské meno alebo heslo. +invalidEmailMessage=Neplatná e-mailová adresa. +accountDisabledMessage=Účet je zakázaný, kontaktujte administrátora. +accountTemporarilyDisabledMessage=Účet je dočasne zakázaný, kontaktujte administrátora alebo skúste neskôr. +expiredCodeMessage=Platnosť prihlásenia vypršala. Prihláste sa znova. +expiredActionMessage=Akcia vypršala. Pokračujte prihlásením. +expiredActionTokenNoSessionMessage=Akcia vypršala. +expiredActionTokenSessionExistsMessage=Platnosť vypršala. Začnite znova. + +missingFirstNameMessage=Zadajte krstné meno. +missingLastNameMessage=Zadajte priezvisko. +missingEmailMessage=Zadajte e-mail. +missingUsernameMessage=Zadajte používateľské meno. +missingPasswordMessage=Zadajte prosím heslo. +missingTotpMessage=Prosím, zadajte kód autentifikátora. +notMatchPasswordMessage=Heslá sa nezhodujú. + +invalidPasswordExistingMessage=Neplatné existujúce heslo. +invalidPasswordBlacklistedMessage=Neplatné heslo: heslo je na čiernej listine. +invalidPasswordConfirmMessage=Potvrdenie hesla sa nezhoduje. +invalidTotpMessage=Neplatný kód autentifikátora. + +usernameExistsMessage=Užívateľské meno už existuje. +emailExistsMessage=E-mail už existuje. + +federatedIdentityExistsMessage=Používateľ s {0} {1} už existuje. Ak chcete prepojiť účet, prihláste sa na správu účtov. + +confirmLinkIdpTitle=Účet už existuje +federatedIdentityConfirmLinkMessage=Používateľ s {0} {1} už existuje. Ako chcete pokračovať? +federatedIdentityConfirmReauthenticateMessage=Overiť prepojiť váš účet s {0} +confirmLinkIdpReviewProfile=Skontrolujte profil +confirmLinkIdpContinue=Pridať do existujúceho účtu + +configureTotpMessage=Na aktiváciu vášho účtu musíte nastaviť aplikáciu Mobile Authenticator. +updateProfileMessage=Ak chcete aktivovať svoj účet, musíte aktualizovať svoj užívateľský profil. +updatePasswordMessage=Ak chcete aktivovať svoj účet, musíte zmeniť heslo. +resetPasswordMessage=Potrebujete zmeniť svoje heslo. +verifyEmailMessage=Ak chcete aktivovať svoj účet, musíte overiť svoju e-mailovú adresu. +linkIdpMessage=Potrebujete si overiť svoju e-mailovú adresu a prepojiť svoj účet s {0}. + +emailSentMessage=Zakrátko by ste mali dostať e-mail s ďalšími pokynmi. +emailSendErrorMessage=Nepodarilo sa odoslať e-mail, skúste to znova neskôr. + +accountUpdatedMessage=Váš účet bol aktualizovaný. +accountPasswordUpdatedMessage=Vaše heslo bolo aktualizované. + +noAccessMessage=Žiadny prístup + +invalidPasswordMinLengthMessage=Neplatné heslo: minimálna dĺžka {0}. +invalidPasswordMinDigitsMessage=Neplatné heslo: musí obsahovať aspoň {0} číslic. +invalidPasswordMinLowerCaseCharsMessage=Neplatné heslo: musí obsahovať minimálne {0} malé písmená. +invalidPasswordMinUpperCaseCharsMessage=Neplatné heslo: musí obsahovať aspoň {0} veľké písmená. +invalidPasswordMinSpecialCharsMessage=Neplatné heslo: musí obsahovať aspoň {0} špeciálne znaky. +invalidPasswordNotUsernameMessage=Neplatné heslo: nesmie byť rovnaké ako používateľské meno. +invalidPasswordRegexPatternMessage=Neplatné heslo: nezhoduje sa vzormi regulérneho výrazu. +invalidPasswordHistoryMessage=Neplatné heslo: nesmie sa rovnať žiadnemu z posledných {0} hesiel. +invalidPasswordGenericMessage=Neplatné heslo: nové heslo nezodpovedá pravidlám hesiel. + +failedToProcessResponseMessage=Nepodarilo sa spracovať odpoveď +httpsRequiredMessage=Vyžaduje sa HTTPS +realmNotEnabledMessage=Realm nie je povolený +invalidRequestMessage=Neplatná požiadavka +failedLogout=Odhlásenie zlyhalo +unknownLoginRequesterMessage=Neznámy žiadateľ o prihlásenie +loginRequesterNotEnabledMessage=Žiadateľ o prihlásenie nie je povolený +bearerOnlyMessage=Aplikácie bearer-only nesmú inicializovať prihlásenie pomocou prehliadača +standardFlowDisabledMessage=Klient nesmie iniciovať prihlásenie do prehliadača s daným typom odpovede. Štandardný tok je pre klienta zakázaný. +implicitFlowDisabledMessage=Klient nemôže iniciovať prihlásenie do prehliadača s daným typom odpovede. Implicitný tok je pre klienta zakázaný. +invalidRedirectUriMessage=Neplatné redirect uri +unsupportedNameIdFormatMessage=Nepodporovaný NameIDFormat +invalidRequesterMessage=Neplatný žiadateľ +registrationNotAllowedMessage=Registrácia nie je povolená +resetCredentialNotAllowedMessage=Obnovenie poverenia nie je povolené + +permissionNotApprovedMessage=Povolenie nie je schválené. +noRelayStateInResponseMessage=Neexistuje relay state v odpovedi od poskytovateľa identity. +insufficientPermissionMessage=Nedostatočné povolenia na prepojenie identít. +couldNotProceedWithAuthenticationRequestMessage=Nemožno pokračovať s požiadavkou na autentifikáciu poskytovateľa identity. +couldNotObtainTokenMessage=Nemožno získať token od poskytovateľa identity. +unexpectedErrorRetrievingTokenMessage=Neočakávaná chyba pri získavaní tokenu od poskytovateľa identity. +unexpectedErrorHandlingResponseMessage=Neočakávaná chyba pri spracovaní odpovede od poskytovateľa identity. +identityProviderAuthenticationFailedMessage=Overenie zlyhalo. Nepodarilo sa autentizovať s poskytovateľom identity. +couldNotSendAuthenticationRequestMessage=Nemožno odoslať žiadosť o autentifikáciu poskytovateľovi identity. +unexpectedErrorHandlingRequestMessage=Neočakávaná chyba pri spracovaní žiadosti o autentifikáciu poskytovateľovi identity. +invalidAccessCodeMessage=Neplatný prístupový kód. +sessionNotActiveMessage=Session nie je aktívna. +invalidCodeMessage=Vyskytla sa chyba, prihláste sa znova prostredníctvom svojej aplikácie. +identityProviderUnexpectedErrorMessage=Neočakávaná chyba pri autentifikácii s poskytovateľom identity +identityProviderNotFoundMessage=Nepodarilo sa nájsť poskytovateľa identity s identifikátorom. +identityProviderLinkSuccess=Svoj e-mail ste úspešne overili. Vráťte sa späť do pôvodného prehliadača a pokračujte tam s prihlasovacími údajmi. +staleCodeMessage=Táto stránka už nie je platná, vráťte sa späť do aplikácie a znova sa prihláste +realmSupportsNoCredentialsMessage=Realm nepodporuje žiadny typ poverenia. +identityProviderNotUniqueMessage=Realm podporuje viacerých poskytovateľov identity. Nepodarilo sa určiť, ktorý poskytovateľ totožnosti sa má používať na autentifikáciu. +emailVerifiedMessage=Vaša e-mailová adresa bola overená. +staleEmailVerificationLink=Odkaz, na ktorý ste klikli, je starý starý odkaz a už nie je platný. Možno ste už overili svoj e-mail? +identityProviderAlreadyLinkedMessage=Federatívna identita vrátená {0} je už prepojená s iným používateľom. +confirmAccountLinking=Potvrďte prepojenie účtu {0} poskytovateľa totožnosti {1} s vaším účtom. +confirmEmailAddressVerification=Potvrďte platnosť e-mailovej adresy {0}. +confirmExecutionOfActions=Vykonajte nasledujúce akcie + +backToApplication=« Späť na aplikáciu +missingParameterMessage=Chýbajúce parametre : {0} +clientNotFoundMessage=Klient sa nenašiel. +clientDisabledMessage=Klient bol zneplatnený. +invalidParameterMessage=Neplatný parameter : {0} +alreadyLoggedIn=Už ste prihlásený. +differentUserAuthenticated=V tejto relácii ste už boli overení ako iný používateľ '' {0} ''. Najskôr sa odhláste. +brokerLinkingSessionExpired=Požadované prepojenie s účtom brokera, ale aktuálna relácia už nie je platná. +proceedWithAction=» Ak chcete pokračovať, kliknite sem + +requiredAction.CONFIGURE_TOTP=Konfigurácia OTP +requiredAction.terms_and_conditions=Zmluvné podmienky +requiredAction.UPDATE_PASSWORD=Aktualizovať heslo +requiredAction.UPDATE_PROFILE=Aktualizovať profil +requiredAction.VERIFY_EMAIL=Overiť e-mail + +doX509Login=Budete prihlásení ako\: +clientCertificate=certifikát klienta X509\: +noCertificate=[Bez certifikátu] + + +pageNotFound=Stránka nebola nájdená +internalServerError=Vyskytla sa interná chyba servera diff --git a/keycloak-themes/base/login/messages/messages_sv.properties b/keycloak-themes/base/login/messages/messages_sv.properties new file mode 100644 index 0000000..70b1d51 --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_sv.properties @@ -0,0 +1,214 @@ +# encoding: utf-8 +doLogIn=Logga in +doRegister=Registrera +doCancel=Avbryt +doSubmit=Skicka +doYes=Ja +doNo=Nej +doContinue=Fortsätt +doAccept=Acceptera +doDecline=Avböj +doForgotPassword=Glömt lösenord? +doClickHere=Klicka här +doImpersonate=Imitera +kerberosNotConfigured=Kerberos är inte konfigurerat +kerberosNotConfiguredTitle=Kerberos är inte konfigurerat +bypassKerberosDetail=Antingen så är du inte inloggad via Kerberos eller så är inte din webbläsare inställd för Kerberosinloggning. Vänligen klicka på fortsätt för att logga in på annat sätt. +kerberosNotSetUp=Kerberos är inte inställt. Du kan inte logga in. +registerWithTitle=Registrera med {0} +registerWithTitleHtml={0} +loginTitle=Logga in till {0} +loginTitleHtml={0} +impersonateTitle={0} Imitera användare +impersonateTitleHtml={0} Imitera användare +realmChoice=Realm +unknownUser=Okänd användare +loginTotpTitle=Inställning av mobilautentiserare +loginProfileTitle=Uppdatera kontoinformation +loginTimeout=Det tog för lång tid att logga in. Inloggningsprocessen börjar om. +oauthGrantTitle=Bevilja åtkomst +oauthGrantTitleHtml={0} +errorTitle=Vi ber om ursäkt... +errorTitleHtml=Vi ber om ursäkt ... +emailVerifyTitle=E-postverifiering +emailForgotTitle=Glömt ditt lösenord? +updatePasswordTitle=Uppdatera lösenord +codeSuccessTitle=Rätt kod +codeErrorTitle=Felkod\: {0} + +termsTitle=Användarvillkor +termsTitleHtml=Användarvillkor +termsText=

    Användarvillkoren har ännu inte definierats

    + +recaptchaFailed=Ogiltig Recaptcha +recaptchaNotConfigured=Recaptcha krävs, men är inte inställd +consentDenied=Samtycke förnekat. + +noAccount=Ny användare? +username=Användarnamn +usernameOrEmail=Användarnamn eller e-post +firstName=Förnamn +lastName=Efternamn +email=E-post +password=Lösenord +passwordConfirm=Bekräfta lösenord +passwordNew=Nytt lösenord +passwordNewConfirm=Bekräftelse av nytt lösenord +rememberMe=Kom ihåg mig +authenticatorCode=Engångskod +address=Adress +street=Gata +locality=Postort +region=Stat, Provins eller Region +postal_code=Postnummer +country=Land +emailVerified=E-post verifierad +gssDelegationCredential=GSS Delegation Credential + +loginTotpStep1=Installera FreeOTP eller Google Authenticator på din mobil. Båda applikationerna finns tillgängliga hos Google Play och Apple App Store. +loginTotpStep2=Öppna applikationen och skanna streckkoden eller skriv i nyckeln +loginTotpStep3=Fyll i engångskoden som tillhandahålls av applikationen och klicka på Spara för att avsluta inställningarna +loginOtpOneTime=Engångskod + +oauthGrantRequest=Godkänner du tillgång till de här rättigheterna? +inResource=i + +emailVerifyInstruction1=Ett e-postmeddelande med instruktioner om hur du verifierar din e-postadress har skickats till dig. +emailVerifyInstruction2=Har du inte fått en verifikationskod i din e-post? +emailVerifyInstruction3=för att skicka e-postmeddelandet igen. + +emailLinkIdpTitle=Länkning {0} +emailLinkIdp1=Ett e-postmeddelande med instruktioner om hur du länkar {0} kontot {1} med ditt {2} konto har skickats till dig. +emailLinkIdp2=Har du inte fått en verifikationskod i din e-post? +emailLinkIdp3=för att skicka e-postmeddelandet igen. + +backToLogin=« Tillbaka till inloggningen + +emailInstruction=Fyll i ditt användarnamn eller din e-postadress, så kommer vi att skicka instruktioner för hur du skapar ett nytt lösenord. + +copyCodeInstruction=Vänligen kopiera den här koden och klistra in den i din applikation: + +personalInfo=Personlig information: +role_admin=Administratör +role_realm-admin=Realm-administratör +role_create-realm=Skapa realm +role_create-client=Skapa klient +role_view-realm=Visa realm +role_view-users=Visa användare +role_view-applications=Visa applikationer +role_view-clients=Visa klienter +role_view-events=Visa event +role_view-identity-providers=Visa identitetsleverantörer +role_manage-realm=Hantera realm +role_manage-users=Hantera användare +role_manage-applications=Hantera applikationer +role_manage-identity-providers=Hantera identitetsleverantörer +role_manage-clients=Hantera klienter +role_manage-events=Hantera event +role_view-profile=Visa profil +role_manage-account=Hantera konto +role_read-token=Läs element +role_offline-access=Åtkomst offline +client_account=Konto +client_security-admin-console=Säkerhetsadministratörskonsol +client_admin-cli=Administratörs-CLI +client_realm-management=Realmhantering + +invalidUserMessage=Ogiltigt användarnamn eller lösenord. +invalidEmailMessage=Ogiltig e-postadress. +accountDisabledMessage=Kontot är inaktiverat, kontakta administratör. +accountTemporarilyDisabledMessage=Kontot är tillfälligt inaktiverat, kontakta administratör eller försök igen senare. +expiredCodeMessage=Inloggningen nådde en maxtidsgräns. Vänligen försök igen. + +missingFirstNameMessage=Vänligen ange förnamn. +missingLastNameMessage=Vänligen ange efternamn. +missingEmailMessage=Vänligen ange e-post. +missingUsernameMessage=Vänligen ange användarnamn. +missingPasswordMessage=Vänligen ange lösenord. +missingTotpMessage=Vänligen ange autentiseringskod. +notMatchPasswordMessage=Lösenorden matchar inte. + +invalidPasswordExistingMessage=Det nuvarande lösenordet är ogiltigt. +invalidPasswordConfirmMessage=Lösenordsbekräftelsen matchar inte. +invalidTotpMessage=Autentiseringskoden är ogiltig. + +usernameExistsMessage=Användarnamnet finns redan. +emailExistsMessage=E-postadressen finns redan. + +federatedIdentityExistsMessage=Användare med {0} {1} finns redan. Vänligen logga in till kontohanteringen för att länka kontot. + +confirmLinkIdpTitle=Kontot finns redan +federatedIdentityConfirmLinkMessage=Användare med {0} {1} finns redan, Hur vill du fortsätta? +federatedIdentityConfirmReauthenticateMessage=Autentisera för att länka ditt konto med {0} +confirmLinkIdpReviewProfile=Granska profil +confirmLinkIdpContinue=Lägg till i existerande konto + +configureTotpMessage=Du behöver konfigurera mobilautentiseraren för att aktivera ditt konto. +updateProfileMessage=Du behöver uppdatera din användarprofil för att aktivera ditt konto. +updatePasswordMessage=Du behöver byta ditt lösenord för att aktivera ditt konto. +verifyEmailMessage=Du behöver verifiera din e-postadress för att aktivera ditt konto. +linkIdpMessage=Du behöver verifiera din e-postadress för att länka ditt konto med {0}. + +emailSentMessage=Du bör inom kort motta ett e-postmeddelande med ytterligare instruktioner. +emailSendErrorMessage=E-postmeddelandet kunde inte skickas, försök igen senare. + +accountUpdatedMessage=Ditt konto har uppdaterats. +accountPasswordUpdatedMessage=Ditt lösenord har uppdaterats. + +noAccessMessage=Ingen åtkomst + +invalidPasswordMinLengthMessage=Ogiltigt lösenord. Minsta längd är {0}. +invalidPasswordMinDigitsMessage=Ogiltigt lösenord: måste innehålla minst {0} siffror. +invalidPasswordMinLowerCaseCharsMessage=Ogiltigt lösenord: måste innehålla minst {0} små bokstäver. +invalidPasswordMinUpperCaseCharsMessage=Ogiltigt lösenord: måste innehålla minst {0} stora bokstäver. +invalidPasswordMinSpecialCharsMessage=Ogiltigt lösenord: måste innehålla minst {0} specialtecken. +invalidPasswordNotUsernameMessage=Ogiltigt lösenord: Får inte vara samma som användarnamnet. +invalidPasswordRegexPatternMessage=Ogiltigt lösenord: matchar inte regex mönstret(en). +invalidPasswordHistoryMessage=Ogiltigt lösenord: Får inte vara samma som de senaste {0} lösenorden. +invalidPasswordGenericMessage=Ogiltigt lösenord: Det nya lösenordet stämmer inte med lösenordspolicyn. + +failedToProcessResponseMessage=Misslyckades med att behandla svaret +httpsRequiredMessage=HTTPS krävs +realmNotEnabledMessage=Realm är inte aktiverad +invalidRequestMessage=Ogiltig förfrågan +failedLogout=Utloggning misslyckades +unknownLoginRequesterMessage=Okänd inloggningsförfrågan +loginRequesterNotEnabledMessage=Inloggningsförfrågaren är inte aktiverad +bearerOnlyMessage=Bearer-only-applikationer tillåts inte att initiera inloggning genom webbläsare +standardFlowDisabledMessage=Klienten tillåts inte att initiera inloggning genom webbläsare med det givna response_type. Standardflödet är inaktiverat för klienten. +implicitFlowDisabledMessage=Klienten tillåts inte att initiera inloggning genom webbläsare med det givna response_type. Villkorslöst flöde är inaktiverat för klienten. +invalidRedirectUriMessage=Ogiltig omdirigeringsadress +unsupportedNameIdFormatMessage=NameIDFormat stöds ej +invalidRequesterMessage=Ogiltig förfrågare +registrationNotAllowedMessage=Registrering tillåts ej +resetCredentialNotAllowedMessage=Återställning av uppgifter tillåts ej + +permissionNotApprovedMessage=Rättigheten ej godkänd. +noRelayStateInResponseMessage=Inget vidarebefordrat tillstånd i svaret från identitetsleverantör. +insufficientPermissionMessage=Otillräckliga tillstånd för att länka identiteter. +couldNotProceedWithAuthenticationRequestMessage=Kunde inte fortsätta med autentiseringsförfrågan till identitetsleverantör. +couldNotObtainTokenMessage=Kunde inte motta element från identitetsleverantör. +unexpectedErrorRetrievingTokenMessage=Oväntat fel när element hämtas från identitetsleverantör. +unexpectedErrorHandlingResponseMessage=Oväntat fel under hantering av svar från från identitetsleverantör. +identityProviderAuthenticationFailedMessage=Autentiseringen misslyckades. Kunde inte autentisera med identitetsleverantör. +couldNotSendAuthenticationRequestMessage=Kunde inte skicka autentiseringsförfrågan till identitetsleverantör. +unexpectedErrorHandlingRequestMessage=Oväntat fel under hantering av autentiseringsförfrågan till identitetsleverantör. +invalidAccessCodeMessage=Ogiltig tillträdeskod. +sessionNotActiveMessage=Sessionen ej aktiv. +invalidCodeMessage=Ett fel uppstod, vänligen logga in igen genom din applikation. +identityProviderUnexpectedErrorMessage=Oväntat fel under autentiseringen med identitetsleverantör +identityProviderNotFoundMessage=Kunde inte hitta en identitetsleverantör med identifikatorn. +identityProviderLinkSuccess=Ditt konto lyckades med att länka {0} med kontot {1}. +staleCodeMessage=Den här sidan är inte längre giltig, vänligen gå tillbaka till din applikation och logga in igen +realmSupportsNoCredentialsMessage=Realmen stödjer inga inloggningstyper. +identityProviderNotUniqueMessage=Realmen stödjer flera identitetsleverantör. Kunde inte avgöra vilken identitetsleverantör som skall användas för autentisering. +emailVerifiedMessage=Din e-postadress har blivit verifierad. +staleEmailVerificationLink=Länken du klickade på är en gammal, inaktuell länk som inte längre är giltig. Kanske har du redan verifierat din e-post? + +backToApplication=« Tillbaka till applikationen +missingParameterMessage=Parametrar som saknas\: {0} +clientNotFoundMessage=Klienten hittades ej. +clientDisabledMessage=Klienten är inaktiverad. +invalidParameterMessage=Ogiltig parameter\: {0} +alreadyLoggedIn=Du är redan inloggad. +loginAccountTitle=Logga in till ditt konto \ No newline at end of file diff --git a/keycloak-themes/base/login/messages/messages_tr.properties b/keycloak-themes/base/login/messages/messages_tr.properties new file mode 100644 index 0000000..7d6c7a0 --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_tr.properties @@ -0,0 +1,294 @@ +doLogIn=Oturum a\u00E7 +doRegister=Kay\u0131t ol +doCancel=\u0130ptal et +doSubmit=G\u00F6nder +doYes=Evet +doNo=Hay\u0131r +doContinue=Devam et +doIgnore=Yoksay +doAccept=Kabul Et +doDecline=Reddet +doForgotPassword=Parolan\u0131z\u0131 m\u0131 unuttunuz? +doClickHere=Buraya T\u0131klay\u0131n +doImpersonate=Ki\u015Fiselle\u015Ftir +kerberosNotConfigured=Kerberos Tan\u0131mlanmam\u0131\u015F +kerberosNotConfiguredTitle=Kerberos Tan\u0131mlanmam\u0131\u015F +bypassKerberosDetail=Ya Kerberos ile giri\u015F yapmad\u0131n\u0131z veya taray\u0131c\u0131n\u0131z Kerberos giri\u015F i\u00E7in ayarlanmam\u0131\u015F. Di\u011Fer yollarla giri\u015F yapmak i\u00E7in l\u00FCtfen devam''a t\u0131klay\u0131n +kerberosNotSetUp=Kerberos kurulmad\u0131. Giri\u015F yapamazs\u0131n. +registerTitle=Kay\u0131t ol +loginTitle={0} adresinde oturum a\u00E7\u0131n +loginTitleHtml={0} +impersonateTitle={0} Kullan\u0131c\u0131 kimli\u011Fine b\u00FCr\u00FCn +impersonateTitleHtml={0} Kullan\u0131c\u0131 kimli\u011Fine b\u00FCr\u00FCn +realmChoice=Realm +unknownUser=Bilinmeyen kullan\u0131c\u0131 +loginTotpTitle=Mobil Kimlik Do\u011Frulama Kurulumu +loginProfileTitle=Hesap bilgilerini G\u00FCncelle +loginTimeout=Giri\u015F yapmak \u00E7ok uzun s\u00FCrd\u00FC. Giri\u015F s\u00FCreci ba\u015Ftan ba\u015Flayacak. +oauthGrantTitle={0} adresine Eri\u015Fim Ver +oauthGrantTitleHtml={0} +errorTitle=\u00DCzg\u00FCn\u00FCz... +errorTitleHtml=\u00DCzg\u00FCn\u00FCz ... +emailVerifyTitle=Eposta Do\u011Frulama +emailForgotTitle=Parolan\u0131z\u0131 m\u0131 unuttunuz? +updatePasswordTitle=\u015Eifre g\u00FCncelle +codeSuccessTitle=Ba\u015Far\u0131l\u0131 i\u015Flem kodu +codeErrorTitle=Hatal\u0131 i\u015Flem kodu\: {0} +displayUnsupported=\u0130stenen g\u00F6sterim t\u00FCr\u00FC desteklenmiyor +browserRequired=Giri\u015F i\u00E7in tary\u0131c\u0131 gerekli +browserContinue=Giri\u015Fe devam etmek i\u00E7in taray\u0131c\u0131 gerekli +browserContinuePrompt=Taray\u0131c\u0131 a\u00E7 ve giri\u015Fe devam et? [e/h]: +browserContinueAnswer=h + + +termsTitle=\u015Eartlar ve ko\u015Fullar +termsText=

    Tan\u0131mlanacak \u015Fartlar ve ko\u015Fullar

    +termsPlainText=Tan\u0131mlanacak \u015Fartlar ve ko\u015Fullar. + +recaptchaFailed=Ge\u00E7ersiz Recaptcha +recaptchaNotConfigured=Recaptcha gerekli, ancak yap\u0131land\u0131r\u0131lmam\u0131\u015F +consentDenied=Onay reddedildi. + +noAccount=Yeni kullan\u0131c\u0131? +username=Kullan\u0131c\u0131 Ad\u0131 +usernameOrEmail=Kullan\u0131c\u0131 ad\u0131 veya E-mail +firstName=Ad +givenName=Ad +fullName=Ad Soyad +lastName=Soyad +familyName=Soyad +email=E-Mail +password=\u015Eifre +passwordConfirm=\u015Eifre Do\u011Frulama +passwordNew=Yeni \u015Eifre +passwordNewConfirm=eni \u015Eifre Do\u011Frulama +rememberMe=Beni Hat\u0131rla +authenticatorCode=Kimlik Do\u011Frulama Kodu +address=Adres +street=Cadde +locality=Semt +region=B\u00F6lge +postal_code=Posta Kodu +country=\u00DClke +emailVerified=E-Mail Do\u011Fruland\u0131 +gssDelegationCredential=GSS Yetki Bilgisi + + +profileScopeConsentText=Kullan\u0131c\u0131 profili +emailScopeConsentText=E-Mai Adresi +addressScopeConsentText=Adres +phoneScopeConsentText=Telefon Numaras\u0131 +offlineAccessScopeConsentText=\u00C7evrimd\u0131\u015F\u0131 Eri\u015Fim +samlRoleListScopeConsentText=Rollerim +rolesScopeConsentText=Kullan\u0131c\u0131 rolleri + +loginTotpIntro=Bu hesaba eri\u015Fmek i\u00E7in bir Tek Kullan\u0131ml\u0131k \u015Eifre olu\u015Fturmal\u0131s\u0131n\u0131z. +loginTotpStep1=Cep telefonunuzda a\u015Fa\u011F\u0131daki uygulamalardan birini y\u00FCkleyin +loginTotpStep2=Uygulamay\u0131 a\u00E7\u0131n ve barkodu taray\u0131n +loginTotpStep3=Uygulama taraf\u0131ndan sa\u011Flanan tek seferlik kodu girin ve kurulumu tamamlamak i\u00E7in G\u00F6nder''i t\u0131klay\u0131n. +loginTotpManualStep2=Uygulamay\u0131 a\u00E7\u0131n ve anahtar\u0131 girin +loginTotpManualStep3=Uygulama bunlar\u0131 ayarlamaya izin veriyorsa a\u015Fa\u011F\u0131daki yap\u0131land\u0131rma de\u011Ferlerini kullan\u0131n. +loginTotpUnableToScan=Taranam\u0131yor? +loginTotpScanBarcode=Barkod tara? +loginOtpOneTime=Tek seferlik kod +loginTotpType=Tip +loginTotpAlgorithm=Algoritma +loginTotpDigits=Basamak +loginTotpInterval=Aral\u0131k +loginTotpCounter=Saya\u00E7 + +loginTotp.totp=Zaman Tabanl\u0131 +loginTotp.hotp=Saya\u00E7 Tabanl\u0131 + + +oauthGrantRequest=Bu eri\u015Fim ayr\u0131cal\u0131klar\u0131 veriyor musunuz? +inResource=i\u00E7inde + +emailVerifyInstruction1=E-posta adresinizi do\u011Frulamak i\u00E7in talimatlar\u0131 i\u00E7eren bir e-posta size g\u00F6nderildi. +emailVerifyInstruction2=E-postan\u0131zda do\u011Frulama kodu almad\u0131n\u0131z m\u0131? +emailVerifyInstruction3=e-postay\u0131 yeniden g\u00F6ndermek i\u00E7in. + +emailLinkIdpTitle=Ba\u011Flant\u0131 {0} +emailLinkIdp1={1} hesab\u0131n\u0131 {2} hesab\u0131n\u0131za ba\u011Flayan talimatlar\u0131 i\u00E7eren bir e-posta size g\u00F6nderildi. +emailLinkIdp2=E-postan\u0131zda do\u011Frulama kodu almad\u0131n\u0131z m\u0131? +emailLinkIdp3=e-postay\u0131 yeniden g\u00F6ndermek i\u00E7in. +emailLinkIdp4=E-postay\u0131 farkl\u0131 taray\u0131c\u0131da zaten do\u011Frulad\u0131ysan\u0131z +emailLinkIdp5=devam etmek. + +backToLogin=« Giri\u015F''e geri d\u00F6n + +emailInstruction=Kullan\u0131c\u0131 ad\u0131n\u0131z\u0131 veya e-posta adresinizi girin ve yeni bir \u015Fifre olu\u015Fturmaya ili\u015Fkin talimatlar\u0131 size g\u00F6nderece\u011Fiz. + +copyCodeInstruction=L\u00FCtfen bu kodu kopyalay\u0131n ve uygulaman\u0131za yap\u0131\u015Ft\u0131r\u0131n: + +pageExpiredTitle=Sayfan\u0131n S\u00FCresi Doldu +pageExpiredMsg1=Giri\u015F i\u015Flemini yeniden ba\u015Flatmak i\u00E7in +pageExpiredMsg2=Giri\u015F i\u015Flemine devam etmek i\u00E7in + +personalInfo=Ki\u015Fisel bilgi: +role_admin=Admin +role_realm-admin=Realm Admin +role_create-realm=Realm Olu\u015Ftur +role_create-client=Create client +role_view-realm=Realm g\u00F6r\u00FCnt\u00FCle +role_view-users=Kullan\u0131c\u0131 g\u00F6r\u00FCnt\u00FCle +role_view-applications=Uygulamar\u0131 g\u00F6r +role_view-clients=Clients g\u00F6r\u00FCnt\u00FCle +role_view-events=Events g\u00F6r\u00FCnt\u00FCle +role_view-identity-providers=Kimlik sa\u011Flay\u0131c\u0131lar\u0131n\u0131 g\u00F6r\u00FCnt\u00FCle +role_manage-realm=Realm Y\u00F6net +role_manage-users=Kullan\u0131c\u0131lar\u0131 Y\u00F6net +role_manage-applications=Uygulamalar\u0131 Y\u00F6net +role_manage-identity-providers=Kimlik Sa\u011Flay\u0131c\u0131lar\u0131n\u0131 Y\u00F6net +role_manage-clients=Clients Y\u00F6net +role_manage-events=Events Y\u00F6net +role_view-profile=Profil g\u00F6r\u00FCnt\u00FCle +role_manage-account=Hesap Y\u00F6net +role_manage-account-links=Hesap ba\u011Flant\u0131lar\u0131n\u0131 y\u00F6net +role_read-token=Token oku +role_offline-access=\u00C7evrimd\u0131\u015F\u0131 eri\u015Fim +client_account=Hesap +client_security-admin-console=G\u00FCvenlik Y\u00F6netici Konsolu +client_admin-cli=Admin CLI +client_realm-management=Realm Y\u00F6net +client_broker=Broker + +invalidUserMessage=Ge\u00E7ersiz kullan\u0131c\u0131 ad\u0131 veya \u015Fifre. +invalidEmailMessage=Ge\u00E7ersiz e-posta adresi. +accountDisabledMessage=Hesap devre d\u0131\u015F\u0131, y\u00F6netici ile ileti\u015Fime ge\u00E7in. +accountTemporarilyDisabledMessage=Hesab\u0131n\u0131z ge\u00E7ici olarak kilitlendi, l\u00FCtfen y\u00F6neticiyle ileti\u015Fime ge\u00E7in veya daha sonra tekrar deneyin. +expiredCodeMessage=Oturum zaman a\u015F\u0131m\u0131na u\u011Frad\u0131. L\u00FCtfen tekrar giri\u015F yap\u0131n. +expiredActionMessage=Eylem s\u00FCresi doldu. L\u00FCtfen \u015Fimdi giri\u015F yapmaya devam edin. +expiredActionTokenNoSessionMessage=Eylemin s\u00FCresi doldu. +expiredActionTokenSessionExistsMessage=Eylem s\u00FCresi doldu. L\u00FCtfen tekrar ba\u015Flay\u0131n. + +missingFirstNameMessage=L\u00FCtfen ilk ad\u0131 belirtin. +missingLastNameMessage=L\u00FCtfen soyad\u0131 belirtin. +missingEmailMessage=L\u00FCtfen email belirtin. +missingUsernameMessage=L\u00FCtfen kullan\u0131c\u0131 ad\u0131n\u0131 belirtin. +missingPasswordMessage=L\u00FCtfen \u015Fifre belirtin. +missingTotpMessage=L\u00FCtfen kimlik do\u011Frulama kodunu belirtin. +notMatchPasswordMessage=\u015Eifreler e\u015Fle\u015Fmiyor. + +invalidPasswordExistingMessage=Mevcut \u015Fifre ge\u00E7ersiz. +invalidPasswordBlacklistedMessage=Ge\u00E7ersiz \u015Fifre: \u015Fifre kara listeye al\u0131nd\u0131. +invalidPasswordConfirmMessage=\u015Eifre onay\u0131 e\u015Fle\u015Fmiyor. +invalidTotpMessage=Ge\u00E7ersiz kimlik do\u011Frulama kodu. + +usernameExistsMessage=Kullan\u0131c\u0131 ad\u0131 zaten var. +emailExistsMessage=Bu e-posta zaten var. + +federatedIdentityExistsMessage={0} {1} kullan\u0131c\u0131 zaten var. Hesab\u0131 ba\u011Flamak i\u00E7in l\u00FCtfen hesap y\u00F6netimine giri\u015F yap\u0131n. + +confirmLinkIdpTitle=Bu Hesap Zaten Mevcut +federatedIdentityConfirmLinkMessage={0} {1} kullan\u0131c\u0131 zaten var. Nas\u0131l devam etmek istersin? +#federatedIdentityConfirmReauthenticateMessage=Hesab\u0131n\u0131z\u0131 {1} ile ba\u011Flamak i\u00E7in {0} olarak do\u011Frulay\u0131n +confirmLinkIdpReviewProfile=Profili g\u00F6zden ge\u00E7ir +confirmLinkIdpContinue=Mevcut hesaba ekle + +configureTotpMessage=Hesab\u0131n\u0131z\u0131 etkinle\u015Ftirmek i\u00E7in Mobil Kimlik Do\u011Frulama''y\u0131 ayarlaman\u0131z gerekiyor. +updateProfileMessage=Hesab\u0131n\u0131z\u0131 etkinle\u015Ftirmek i\u00E7in kullan\u0131c\u0131 profilinizi g\u00FCncellemeniz gerekiyor. +updatePasswordMessage=Hesab\u0131n\u0131z\u0131 etkinle\u015Ftirmek i\u00E7in \u015Fifrenizi de\u011Fi\u015Ftirmeniz gerekiyor. +resetPasswordMessage=\u015Eifreni de\u011Fi\u015Ftirmelisin. +verifyEmailMessage=Hesab\u0131n\u0131z\u0131 etkinle\u015Ftirmek i\u00E7in e-posta adresinizi do\u011Frulaman\u0131z gerekiyor. +linkIdpMessage=Hesab\u0131n\u0131z\u0131 {0} ile ba\u011Flamak i\u00E7in e-posta adresinizi do\u011Frulaman\u0131z gerekiyor. + +emailSentMessage=Daha fazla talimatla k\u0131sa s\u00FCrede bir e-posta almal\u0131s\u0131n\u0131z. +emailSendErrorMessage=E-posta g\u00F6nderilemedi, l\u00FCtfen daha sonra tekrar deneyin. + +accountUpdatedMessage=Hesab\u0131n g\u00FCncellendi. +accountPasswordUpdatedMessage=\u015Eifreniz g\u00FCncellenmi\u015Ftir. + +delegationCompleteHeader=Giri\u015F ba\u015Far\u0131l\u0131 +delegationCompleteMessage=Bu taray\u0131c\u0131 penceresini kapatabilir ve konsol uygulaman\u0131za geri d\u00F6nebilirsiniz. +delegationFailedHeader=Giri\u015F ba\u015Far\u0131s\u0131z +delegationFailedMessage=Bu taray\u0131c\u0131 penceresini kapatabilir ve konsol uygulaman\u0131za geri d\u00F6n\u00FCp tekrar giri\u015F yapmay\u0131 deneyebilirsiniz.. + +noAccessMessage=Eri\u015Fim yok + +invalidPasswordMinLengthMessage=Ge\u00E7ersiz \u015Eifre: En az {0} karakter uzunlu\u011Funda olmal\u0131. +invalidPasswordMinDigitsMessage=Ge\u00E7ersiz \u015Eifre: En az {0} say\u0131(lar) i\u00E7ermelidir. +invalidPasswordMinLowerCaseCharsMessage=Ge\u00E7ersiz \u015Eifre \: En az {0} k\u00FC\u00E7\u00FCk harf i\u00E7ermelidir. +invalidPasswordMinUpperCaseCharsMessage=Ge\u00E7ersiz \u015Eifre: En az {0} b\u00FCy\u00FCk harf i\u00E7ermelidir. +invalidPasswordMinSpecialCharsMessage=Ge\u00E7ersiz \u015Eifre: En az {0} \u00F6zel karakter i\u00E7ermelidir. +invalidPasswordNotUsernameMessage=Ge\u00E7ersiz \u015Eifre: Kullan\u0131c\u0131 ad\u0131yla ayn\u0131 olamaz. +invalidPasswordRegexPatternMessage=Ge\u00E7ersiz \u015Eifre: Regex Patternine uygun de\u011Fil. +invalidPasswordHistoryMessage=Ge\u00E7ersiz \u015Eifre: Son {0} \u015Fifreden biri olamaz. +invalidPasswordGenericMessage=Ge\u00E7ersiz \u015Eifre: yeni \u015Fifre \u015Fifre politikalar\u0131yla e\u015Fle\u015Fmiyor. + +failedToProcessResponseMessage=Yan\u0131t i\u015Flenemedi +httpsRequiredMessage=HTTPS zorunlu +realmNotEnabledMessage=Realm aktif de\u011Fil +invalidRequestMessage=Ge\u00E7ersiz \u0130stek +failedLogout=\u00C7\u0131k\u0131\u015F ba\u015Far\u0131s\u0131z +unknownLoginRequesterMessage=Bilinmeyen giri\u015F iste\u011Fi +loginRequesterNotEnabledMessage=Giri\u015F istemi etkin de\u011Fil +bearerOnlyMessage=Yaln\u0131zca ta\u015F\u0131y\u0131c\u0131 uygulamalar\u0131 taray\u0131c\u0131 giri\u015Fini ba\u015Flatmaya izinli de\u011Fil +standardFlowDisabledMessage=Client is not allowed to initiate browser login with given response_type. Standard flow is disabled for the client. +implicitFlowDisabledMessage=Client is not allowed to initiate browser login with given response_type. Implicit flow is disabled for the client. +invalidRedirectUriMessage=Ge\u00E7ersiz y\u00F6nlendirme url''i +unsupportedNameIdFormatMessage=Desteklenmeyen NameIDFormat +invalidRequesterMessage=Ge\u00E7ersiz istek +registrationNotAllowedMessage=Kay\u0131t yap\u0131lamaz +resetCredentialNotAllowedMessage=S\u0131f\u0131rlamas\u0131na izin verilmiyor + +permissionNotApprovedMessage=\u0130zin onaylanmad\u0131. +noRelayStateInResponseMessage=Kimlik sa\u011Flay\u0131c\u0131dan yan\u0131t olarak ge\u00E7i\u015F durumu yok. +insufficientPermissionMessage=Kimliklerin ba\u011Flanmas\u0131 i\u00E7in yetersiz izinler. +couldNotProceedWithAuthenticationRequestMessage=Kimlik sa\u011Flay\u0131c\u0131ya kimlik do\u011Frulama iste\u011Fi ile devam edilemedi. +couldNotObtainTokenMessage=Kimlik sa\u011Flay\u0131c\u0131dan token al\u0131namad\u0131. +unexpectedErrorRetrievingTokenMessage=Kimlik sa\u011Flay\u0131c\u0131dan token al\u0131rken beklenmeyen bir hata olu\u015Ftu. +unexpectedErrorHandlingResponseMessage=Kimlik sa\u011Flay\u0131c\u0131dan yan\u0131t al\u0131n\u0131rken beklenmeyen bir hata olu\u015Ftu. +identityProviderAuthenticationFailedMessage=Kimlik do\u011Frulama ba\u015Far\u0131s\u0131z oldu. Kimlik sa\u011Flay\u0131c\u0131yla kimlik do\u011Frulamas\u0131 yap\u0131lamad\u0131. +couldNotSendAuthenticationRequestMessage=Kimlik sa\u011Flay\u0131c\u0131ya kimlik do\u011Frulama iste\u011Fi g\u00F6nderilemedi. +unexpectedErrorHandlingRequestMessage=Kimlik sa\u011Flay\u0131c\u0131ya kimlik do\u011Frulama iste\u011Fi i\u015Flenirken beklenmeyen bir hata olu\u015Ftu. +invalidAccessCodeMessage=Ge\u00E7ersiz giri\u015F kodu. +sessionNotActiveMessage=Oturum etkin de\u011Fil. +invalidCodeMessage=Bir hata olu\u015Ftu, l\u00FCtfen ba\u015Fvurunuz arac\u0131l\u0131\u011F\u0131yla tekrar giri\u015F yap\u0131n. +identityProviderUnexpectedErrorMessage=Kimlik sa\u011Flay\u0131c\u0131yla kimlik do\u011Frulamas\u0131 yap\u0131l\u0131rken beklenmeyen bir hata olu\u015Ftu +identityProviderNotFoundMessage=Tan\u0131mlay\u0131c\u0131 ile kimlik sa\u011Flay\u0131c\u0131 bulunamad\u0131. +identityProviderLinkSuccess=E-postan\u0131z\u0131 ba\u015Far\u0131yla do\u011Frulad\u0131n\u0131z. L\u00FCtfen orijinal taray\u0131c\u0131n\u0131za geri d\u00F6n\u00FCn ve giri\u015F yap\u0131n. +staleCodeMessage=Bu sayfa art\u0131k ge\u00E7erli de\u011Fil, l\u00FCtfen uygulaman\u0131za geri d\u00F6n\u00FCn ve tekrar giri\u015F yap\u0131n +realmSupportsNoCredentialsMessage=Realm herhangi bir kimlik bilgisi t\u00FCr\u00FCn\u00FC desteklemiyor. +identityProviderNotUniqueMessage=Realm \u00E7oklu kimlik sa\u011Flay\u0131c\u0131lar\u0131n\u0131 destekler. Kimlik do\u011Frulamak i\u00E7in hangi kimlik sa\u011Flay\u0131c\u0131s\u0131n\u0131n kullan\u0131lmas\u0131 gerekti\u011Fini belirleyemedi. +emailVerifiedMessage=E-posta adresiniz do\u011Fruland\u0131. +staleEmailVerificationLink=T\u0131klad\u0131\u011F\u0131n\u0131z ba\u011Flant\u0131 eski bir ba\u011Flant\u0131d\u0131r ve art\u0131k ge\u00E7erli de\u011Fil. Belki de e-postan\u0131z\u0131 zaten do\u011Frulad\u0131n\u0131z. +identityProviderAlreadyLinkedMessage={0} taraf\u0131ndan d\u00F6nd\u00FCr\u00FClen birle\u015Fik kimlik, ba\u015Fka bir kullan\u0131c\u0131yla zaten ba\u011Flant\u0131l\u0131. +confirmAccountLinking={1} kimlik sa\u011Flay\u0131c\u0131s\u0131n\u0131n hesab\u0131n\u0131 {0} hesab\u0131n\u0131zla ili\u015Fkilendirmeyi onaylay\u0131n. +confirmEmailAddressVerification={0} e-posta adresinin ge\u00E7erlili\u011Fini onaylay\u0131n. +confirmExecutionOfActions=A\u015Fa\u011F\u0131daki eylemleri ger\u00E7ekle\u015Ftirin + +backToApplication=« Uygulamaya D\u00F6n +missingParameterMessage=Eksik parametreler\: {0} +clientNotFoundMessage=\u0130stemci Bulunamad\u0131. +clientDisabledMessage=\u0130stemci engelli. +invalidParameterMessage=Ge\u00E7ersiz Paremetreler\: {0} +alreadyLoggedIn=Zaten giri\u015F yapt\u0131n\u0131z. +differentUserAuthenticated=Bu oturumda zaten farkl\u0131 kullan\u0131c\u0131 '' {0} '' olarak do\u011Frulanm\u0131\u015Fs\u0131n\u0131z. L\u00FCtfen \u00F6nce \u00E7\u0131k\u0131\u015F yap\u0131n\u0131z. +brokerLinkingSessionExpired=\u0130stenen broker hesab\u0131 ba\u011Flan\u0131yor, ancak mevcut oturum art\u0131k ge\u00E7erli de\u011Fil. +proceedWithAction=» Devam etmek i\u00E7in buraya t\u0131klay\u0131n + +requiredAction.CONFIGURE_TOTP=OTP Ayarla +requiredAction.terms_and_conditions=\u015Eartlar ve Ko\u015Fullar +requiredAction.UPDATE_PASSWORD=\u015Eifre g\u00FCncelle +requiredAction.UPDATE_PROFILE=Profili G\u00FCncelle +requiredAction.VERIFY_EMAIL=E-mail''i do\u011Frula + +doX509Login=Olarak giri\u015F yapacaks\u0131n\u0131z\: +clientCertificate=X509 istemci sertifikas\u0131\: +noCertificate=[Sertifika Yok] + + +pageNotFound=Sayfa Bulunamad\u0131 +internalServerError=Bir i\u00E7 sunucu hatas\u0131 olu\u015Ftu + +console-username=Kullan\u0131c\u0131 ad\u0131: +console-password=Parola: +console-otp=Tek seferlik \u015Fifre: +console-new-password=Yeni \u015Fifre: +console-confirm-password=\u015Eifreyi Onayla: +console-update-password=\u015Eifrenizin g\u00FCncellenmesi gerekiyor. +console-verify-email=E-posta adresinizi do\u011Frulaman\u0131z gerekiyor. Bir do\u011Frulama kodu i\u00E7eren {0} adresine bir e-posta g\u00F6nderildi. L\u00FCtfen bu kodu a\u015Fa\u011F\u0131daki girdiye giriniz. +console-email-code=E-posta Kodu: +console-accept-terms=\u015Eartlar\u0131 kabul et? [e/h]: +console-accept=e diff --git a/keycloak-themes/base/login/messages/messages_zh_CN.properties b/keycloak-themes/base/login/messages/messages_zh_CN.properties new file mode 100644 index 0000000..b669f21 --- /dev/null +++ b/keycloak-themes/base/login/messages/messages_zh_CN.properties @@ -0,0 +1,216 @@ +# encoding: utf-8 +doLogIn=登录 +doRegister=注册 +doCancel=取消 +doSubmit=提交 +doYes=是 +doNo=否 +doContinue=继续 +doAccept=接受 +doDecline=拒绝 +doForgotPassword=忘记密码? +doClickHere=点击这里 +doImpersonate=模拟 +kerberosNotConfigured=Kerberos 没有配置 +kerberosNotConfiguredTitle=Kerberos 没有配置 +bypassKerberosDetail=您没有通过Kerberos登录 或者您的浏览器没有设置Kerberos登录. 请点击继续通过其他途径登录。 +kerberosNotSetUp=Kerberos没有配置,您不可以登录 +registerWithTitle=用 {0} 注册 +registerWithTitleHtml={0} +loginTitle=登录到 {0} +loginTitleHtml={0} +impersonateTitle={0} 模拟用户 +impersonateTitleHtml={0}模拟用户 +realmChoice=域 +unknownUser=未知用户 +loginTotpTitle=手机验证者配置 +loginProfileTitle=更新账户信息 +loginTimeout=登录超时,请重新开始登录 +oauthGrantTitle=授权 +oauthGrantTitleHtml={0} +errorTitle=很抱歉... +errorTitleHtml=我们很抱歉 ... +emailVerifyTitle=验证电子邮件地址 +emailForgotTitle=忘记密码? +updatePasswordTitle=更新密码 +codeSuccessTitle=成功码 +codeErrorTitle=错误码\: {0} + +termsTitle=条款 +termsTitleHtml=条款 +termsText=

    需要确定的条款

    + +recaptchaFailed=无效的验证码 +recaptchaNotConfigured=需要验证码,但是没有配置 +consentDenied=许可被拒绝。 + +noAccount=新用户? +username=用户名 +usernameOrEmail=用户名 或 电子邮箱地址 +firstName=名 +givenName=姓 +fullName=全名 +lastName=姓 +familyName=姓 +email=Email +password=密码 +passwordConfirm=确认密码 +passwordNew=新密码 +passwordNewConfirm=新密码确认 +rememberMe=记住我 +authenticatorCode=一次性验证码 +address=地址 +street=街道 +locality=市 +region=省,自治区,直辖市 +postal_code=邮政编码 +country=国家 +emailVerified=电子邮件已验证 +gssDelegationCredential=GSS Delegation Credential + +loginTotpStep1=在手机安装 FreeOTP 或 Google Authenticator. 这两个应用可以在 Google Play 和 Apple App Store找到. +loginTotpStep2=打开应用扫描二维码或者输入一次性码 +loginTotpStep3=输入应用提供的一次性码点击提交完成设置 +loginOtpOneTime=一次性验证码 + +oauthGrantRequest=您是否想要授予下列权限? +inResource=in + +emailVerifyInstruction1=一封包含验证邮箱具体步骤的邮件已经发送到您的邮箱。 +emailVerifyInstruction2=邮箱没有收到验证码? +emailVerifyInstruction3=重新发送电子邮件 + +emailLinkIdpTitle=链接 {0} +emailLinkIdp1=一封包含链接账户 {0} 和账户 {1} 到账户 {2} 的邮件已经发送到您的邮箱。 +emailLinkIdp2=邮箱没有收到验证码邮件? +emailLinkIdp3=重新发送电子邮件 + +backToLogin=« 回到登录 + +emailInstruction=输入您的用户名和邮箱,我们会发送一封带有设置新密码步骤的邮件到您的邮箱。 + +copyCodeInstruction=请复制这段验证码并粘贴到应用: + +personalInfo=个人信息\: +role_admin=管理员 +role_realm-admin=域管理员 +role_create-realm=创建域 +role_create-client=创建客户 +role_view-realm=查看域 +role_view-users=查看用户 +role_view-applications=查看应用 +role_view-clients=查看客户 +role_view-events=查看时间 +role_view-identity-providers=查看身份提供者 +role_manage-realm=管理域 +role_manage-users=管理用户 +role_manage-applications=管理应用 +role_manage-identity-providers=管理身份提供者 +role_manage-clients=管理客户 +role_manage-events=管理事件 +role_view-profile=查看用户信息 +role_manage-account=管理账户 +role_read-token=读取 token +role_offline-access=离线访问 +client_account=账户 +client_security-admin-console=安全管理控制台 +client_admin-cli=管理命令行工具 +client_realm-management=域管理 +client_broker=代理 + +invalidUserMessage=无效的用户名或密码。 +invalidEmailMessage=无效的电子邮件地址 +accountDisabledMessage=账户被禁用,请联系管理员。 +accountTemporarilyDisabledMessage=账户被暂时禁用,请稍后再试或联系管理员。 +expiredCodeMessage=登录超时,请重新登录。 + +missingFirstNameMessage=请输入名 +missingLastNameMessage=请输入姓 +missingEmailMessage=请输入email. +missingUsernameMessage=请输入用户名 +missingPasswordMessage=请输入密码 +missingTotpMessage=请输入验证码 +notMatchPasswordMessage=密码不匹配。 + +invalidPasswordExistingMessage=无效的旧密码 +invalidPasswordConfirmMessage=确认密码不相同 +invalidTotpMessage=无效的验证码 + +usernameExistsMessage=用户名已被占用 +emailExistsMessage=电子邮件已存在。 + +federatedIdentityExistsMessage=用户 {0} {1} 已存在. 请登录账户管理界面链接账户. + +confirmLinkIdpTitle=账户已存在 +federatedIdentityConfirmLinkMessage=用户{0} {1} 已存在. 怎么继续? +#federatedIdentityConfirmReauthenticateMessage=以 {0} 登录来将 {1} 连接到您的账户 +confirmLinkIdpReviewProfile=审查您的信息 +confirmLinkIdpContinue=添加到已知账户 + +configureTotpMessage=您需要设置验证码模块来激活您的账户 +updateProfileMessage=您需要更新您的简介来激活您的账户 +updatePasswordMessage=您需要更新您的密码来激活您的账户 +verifyEmailMessage=您需要验证您的电子邮箱来激活您的账户 +linkIdpMessage=您需要验证您的电子邮箱来连接到账户{0}. + +emailSentMessage=您很快会收到一封关于接下来操作的邮件。 +emailSendErrorMessage=无法发送邮件,请稍后再试 + +accountUpdatedMessage=您的账户已经更新。 +accountPasswordUpdatedMessage=您的密码已经更新 + +noAccessMessage=无权限 + +invalidPasswordMinLengthMessage=无效的密码:最短长度 {0}. +invalidPasswordMinDigitsMessage=无效的密码: 至少包含{0} 个数字 +invalidPasswordMinLowerCaseCharsMessage=无效的密码:至少包含 {0} 小写字母. +invalidPasswordMinUpperCaseCharsMessage=无效的密码:至少包含 {0} 大写字母. +invalidPasswordMinSpecialCharsMessage=无效的密码:至少包含 {0} 特殊字符. +invalidPasswordNotUsernameMessage=无效的密码: 不能与用户名相同. +invalidPasswordRegexPatternMessage=无效的密码: 无法与正则表达式匹配. +invalidPasswordHistoryMessage=无效的密码: 不能与前 {0} 个旧密码相同. + +failedToProcessResponseMessage=无法处理回复 +httpsRequiredMessage=需要HTTPS +realmNotEnabledMessage=域未启用 +invalidRequestMessage=非法的请求 +failedLogout=无法登出 +unknownLoginRequesterMessage=未知的登录请求发起方 +loginRequesterNotEnabledMessage=登录请求发起方为启用 +bearerOnlyMessage=Bearer-only 的应用不允许通过浏览器登录 +standardFlowDisabledMessage=客户程序不允许发起指定返回类型的浏览器登录. 标准的登录流程已禁用。 +implicitFlowDisabledMessage=客户程序不允许发起指定返回类型的浏览器登录. 隐式的登录流程已禁用。 +invalidRedirectUriMessage=无效的跳转链接 +unsupportedNameIdFormatMessage=不支持的 nameID格式 +invalidRequesterMessage=无效的发起者 +registrationNotAllowedMessage=注册不允许 +resetCredentialNotAllowedMessage=不允许重置密码 + +permissionNotApprovedMessage=许可没有批准 +noRelayStateInResponseMessage=身份提供者没有返回中继状态信息 +insufficientPermissionMessage=权限不足以链接新的身份 +couldNotProceedWithAuthenticationRequestMessage=无法与身份提供者处理认证请求 +couldNotObtainTokenMessage=未从身份提供者获得token +unexpectedErrorRetrievingTokenMessage=从身份提供者获得Token时遇到未知错误 +unexpectedErrorHandlingResponseMessage=从身份提供者获得回复时遇到未知错误 +identityProviderAuthenticationFailedMessage=认证失败,无法通过身份提供者认证 +couldNotSendAuthenticationRequestMessage=无法向身份提供方发送认证请求 +unexpectedErrorHandlingRequestMessage=在处理发向认证提供方的请求时,出现未知错误。 +invalidAccessCodeMessage=无效的验证码 +sessionNotActiveMessage=会话不在活动状态 +invalidCodeMessage=发生错误,请重新通过应用登录 +identityProviderUnexpectedErrorMessage=在与认证提供者认证过程中发生未知错误 +identityProviderNotFoundMessage=无法找到认证提供方 +identityProviderLinkSuccess=您的账户已经将账户{0} 与账户 {1} 链接. +staleCodeMessage=当前页面已无效,请到登录界面重新登录 +realmSupportsNoCredentialsMessage=域不支持特定类型密码 +identityProviderNotUniqueMessage=域支持通过多个身份提供者登录,不知道应用哪一种方式登录 +emailVerifiedMessage=您的电子邮箱已经验证。 +staleEmailVerificationLink=您点击的链接已无效。可能您已经验证过您的电子邮箱? + +backToApplication=« 回到应用 +missingParameterMessage=缺少参数 \: {0} +clientNotFoundMessage=客户端未找到 +clientDisabledMessage=客户端已禁用 +invalidParameterMessage=无效的参数 \: {0} +alreadyLoggedIn=您已经登录 diff --git a/keycloak-themes/base/login/register-user-profile.ftl b/keycloak-themes/base/login/register-user-profile.ftl new file mode 100644 index 0000000..e0d533b --- /dev/null +++ b/keycloak-themes/base/login/register-user-profile.ftl @@ -0,0 +1,74 @@ +<#import "template.ftl" as layout> +<#import "user-profile-commons.ftl" as userProfileCommons> +<@layout.registrationLayout displayMessage=messagesPerField.exists('global') displayRequiredFields=true; section> + <#if section = "header"> + ${msg("registerTitle")} + <#elseif section = "form"> +
    + + <@userProfileCommons.userProfileFormFields; callback, attribute> + <#if callback = "afterField"> + <#-- render password fields just under the username or email (if used as username) --> + <#if passwordRequired?? && (attribute.name == 'username' || (attribute.name == 'email' && realm.registrationEmailAsUsername))> +
    +
    + * +
    +
    + + + <#if messagesPerField.existsError('password')> + + ${kcSanitize(messagesPerField.get('password'))?no_esc} + + +
    +
    + +
    +
    + * +
    +
    + + + <#if messagesPerField.existsError('password-confirm')> + + ${kcSanitize(messagesPerField.get('password-confirm'))?no_esc} + + +
    +
    + + + + + <#if recaptchaRequired??> +
    +
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/login/register.ftl b/keycloak-themes/base/login/register.ftl new file mode 100644 index 0000000..db50984 --- /dev/null +++ b/keycloak-themes/base/login/register.ftl @@ -0,0 +1,141 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout displayMessage=!messagesPerField.existsError('firstName','lastName','email','username','password','password-confirm'); section> + <#if section = "header"> + ${msg("registerTitle")} + <#elseif section = "form"> +
    +
    +
    + +
    +
    + + + <#if messagesPerField.existsError('firstName')> + + ${kcSanitize(messagesPerField.get('firstName'))?no_esc} + + +
    +
    + +
    +
    + +
    +
    + + + <#if messagesPerField.existsError('lastName')> + + ${kcSanitize(messagesPerField.get('lastName'))?no_esc} + + +
    +
    + +
    +
    + +
    +
    + + + <#if messagesPerField.existsError('email')> + + ${kcSanitize(messagesPerField.get('email'))?no_esc} + + +
    +
    + + <#if !realm.registrationEmailAsUsername> +
    +
    + +
    +
    + + + <#if messagesPerField.existsError('username')> + + ${kcSanitize(messagesPerField.get('username'))?no_esc} + + +
    +
    + + + <#if passwordRequired??> +
    +
    + +
    +
    + + + <#if messagesPerField.existsError('password')> + + ${kcSanitize(messagesPerField.get('password'))?no_esc} + + +
    +
    + +
    +
    + +
    +
    + + + <#if messagesPerField.existsError('password-confirm')> + + ${kcSanitize(messagesPerField.get('password-confirm'))?no_esc} + + +
    +
    + + + <#if recaptchaRequired??> +
    +
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/login/resources/js/base64url.js b/keycloak-themes/base/login/resources/js/base64url.js new file mode 100644 index 0000000..64555bf --- /dev/null +++ b/keycloak-themes/base/login/resources/js/base64url.js @@ -0,0 +1,114 @@ +// for embedded scripts, quoted and modified from https://github.com/swansontec/rfc4648.js by William Swanson +'use strict'; +var base64url = base64url || {}; +(function(base64url) { + + function parse (string, encoding, opts = {}) { + // Build the character lookup table: + if (!encoding.codes) { + encoding.codes = {}; + for (let i = 0; i < encoding.chars.length; ++i) { + encoding.codes[encoding.chars[i]] = i; + } + } + + // The string must have a whole number of bytes: + if (!opts.loose && (string.length * encoding.bits) & 7) { + throw new SyntaxError('Invalid padding'); + } + + // Count the padding bytes: + let end = string.length; + while (string[end - 1] === '=') { + --end; + + // If we get a whole number of bytes, there is too much padding: + if (!opts.loose && !(((string.length - end) * encoding.bits) & 7)) { + throw new SyntaxError('Invalid padding'); + } + } + + // Allocate the output: + const out = new (opts.out || Uint8Array)(((end * encoding.bits) / 8) | 0); + + // Parse the data: + let bits = 0; // Number of bits currently in the buffer + let buffer = 0; // Bits waiting to be written out, MSB first + let written = 0; // Next byte to write + for (let i = 0; i < end; ++i) { + // Read one character from the string: + const value = encoding.codes[string[i]]; + if (value === void 0) { + throw new SyntaxError('Invalid character ' + string[i]); + } + + // Append the bits to the buffer: + buffer = (buffer << encoding.bits) | value; + bits += encoding.bits; + + // Write out some bits if the buffer has a byte's worth: + if (bits >= 8) { + bits -= 8; + out[written++] = 0xff & (buffer >> bits); + } + } + + // Verify that we have received just enough bits: + if (bits >= encoding.bits || 0xff & (buffer << (8 - bits))) { + throw new SyntaxError('Unexpected end of data'); + } + + return out + } + + function stringify (data, encoding, opts = {}) { + const { pad = true } = opts; + const mask = (1 << encoding.bits) - 1; + let out = ''; + + let bits = 0; // Number of bits currently in the buffer + let buffer = 0; // Bits waiting to be written out, MSB first + for (let i = 0; i < data.length; ++i) { + // Slurp data into the buffer: + buffer = (buffer << 8) | (0xff & data[i]); + bits += 8; + + // Write out as much as we can: + while (bits > encoding.bits) { + bits -= encoding.bits; + out += encoding.chars[mask & (buffer >> bits)]; + } + } + + // Partial character: + if (bits) { + out += encoding.chars[mask & (buffer << (encoding.bits - bits))]; + } + + // Add padding characters until we hit a byte boundary: + if (pad) { + while ((out.length * encoding.bits) & 7) { + out += '='; + } + } + + return out + } + + const encoding = { + chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', + bits: 6 + } + + base64url.decode = function (string, opts) { + return parse(string, encoding, opts); + } + + base64url.encode = function (data, opts) { + return stringify(data, encoding, opts) + } + + return base64url; +}(base64url)); + + diff --git a/keycloak-themes/base/login/saml-post-form.ftl b/keycloak-themes/base/login/saml-post-form.ftl new file mode 100644 index 0000000..94b0c30 --- /dev/null +++ b/keycloak-themes/base/login/saml-post-form.ftl @@ -0,0 +1,25 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout; section> + <#if section = "header"> + ${msg("saml.post-form.title")} + <#elseif section = "form"> + +

    ${msg("saml.post-form.message")}

    +
    + <#if samlPost.SAMLRequest??> + + + <#if samlPost.SAMLResponse??> + + + <#if samlPost.relayState??> + + + + +
    + + diff --git a/keycloak-themes/base/login/select-authenticator.ftl b/keycloak-themes/base/login/select-authenticator.ftl new file mode 100644 index 0000000..3a73174 --- /dev/null +++ b/keycloak-themes/base/login/select-authenticator.ftl @@ -0,0 +1,43 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout displayInfo=false; section> + <#if section = "header" || section = "show-username"> + + <#if section = "header"> + ${msg("loginChooseAuthenticator")} + + <#elseif section = "form"> + +
    +
    + <#list auth.authenticationSelections as authenticationSelection> +
    + +
    + +
    +
    +
    + ${msg('${authenticationSelection.displayName}')} +
    +
    + ${msg('${authenticationSelection.helpText}')} +
    +
    +
    +
    + +
    +
    + + +
    +
    + + + + diff --git a/keycloak-themes/base/login/template.ftl b/keycloak-themes/base/login/template.ftl new file mode 100644 index 0000000..f21e6cb --- /dev/null +++ b/keycloak-themes/base/login/template.ftl @@ -0,0 +1,154 @@ +<#macro registrationLayout bodyClass="" displayInfo=false displayMessage=true displayRequiredFields=false> + + + + + + + + + <#if properties.meta?has_content> + <#list properties.meta?split(' ') as meta> + + + + ${msg("loginTitle",(realm.displayName!''))} + + <#if properties.stylesCommon?has_content> + <#list properties.stylesCommon?split(' ') as style> + + + + <#if properties.styles?has_content> + <#list properties.styles?split(' ') as style> + + + + <#if properties.scripts?has_content> + <#list properties.scripts?split(' ') as script> + + + + <#if scripts??> + <#list scripts as script> + + + + + + +
    +
    +
    ${kcSanitize(msg("loginTitleHtml",(realm.displayNameHtml!'')))?no_esc}
    +
    +
    +
    + <#if realm.internationalizationEnabled && locale.supported?size gt 1> +
    +
    +
    + ${locale.current} +
      + <#list locale.supported as l> +
    • + ${l.label} +
    • + +
    +
    +
    +
    + + <#if !(auth?has_content && auth.showUsername() && !auth.showResetCredentials())> + <#if displayRequiredFields> +
    +
    + * ${msg("requiredFields")} +
    +
    +

    <#nested "header">

    +
    +
    + <#else> +

    <#nested "header">

    + + <#else> + <#if displayRequiredFields> +
    +
    + * ${msg("requiredFields")} +
    +
    + <#nested "show-username"> +
    + + + + +
    +
    +
    + <#else> + <#nested "show-username"> +
    + + + + +
    + + +
    +
    +
    + + <#-- App-initiated actions should not see warning messages about the need to complete the action --> + <#-- during login. --> + <#if displayMessage && message?has_content && (message.type != 'warning' || !isAppInitiatedAction??)> +
    +
    + <#if message.type = 'success'> + <#if message.type = 'warning'> + <#if message.type = 'error'> + <#if message.type = 'info'> +
    + ${kcSanitize(message.summary)?no_esc} +
    + + + <#nested "form"> + + <#if auth?has_content && auth.showTryAnotherWayLink()> +
    + +
    + + + <#nested "socialProviders"> + + <#if displayInfo> +
    +
    + <#nested "info"> +
    +
    + +
    +
    + +
    +
    + + + diff --git a/keycloak-themes/base/login/terms.ftl b/keycloak-themes/base/login/terms.ftl new file mode 100644 index 0000000..687b192 --- /dev/null +++ b/keycloak-themes/base/login/terms.ftl @@ -0,0 +1,15 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout displayMessage=false; section> + <#if section = "header"> + ${msg("termsTitle")} + <#elseif section = "form"> +
    + ${kcSanitize(msg("termsText"))?no_esc} +
    +
    + + +
    +
    + + diff --git a/keycloak-themes/base/login/theme.properties b/keycloak-themes/base/login/theme.properties new file mode 100644 index 0000000..d8b7627 --- /dev/null +++ b/keycloak-themes/base/login/theme.properties @@ -0,0 +1 @@ +locales=ca,cs,da,de,en,es,fr,fi,hu,it,ja,lt,nl,no,pl,pt-BR,ru,sk,sv,tr,zh-CN diff --git a/keycloak-themes/base/login/update-user-profile.ftl b/keycloak-themes/base/login/update-user-profile.ftl new file mode 100644 index 0000000..e09f5c3 --- /dev/null +++ b/keycloak-themes/base/login/update-user-profile.ftl @@ -0,0 +1,28 @@ +<#import "template.ftl" as layout> +<#import "user-profile-commons.ftl" as userProfileCommons> +<@layout.registrationLayout displayMessage=messagesPerField.exists('global') displayRequiredFields=true; section> + <#if section = "header"> + ${msg("loginProfileTitle")} + <#elseif section = "form"> +
    + + <@userProfileCommons.userProfileFormFields/> + +
    +
    +
    +
    +
    + +
    + <#if isAppInitiatedAction??> + + + <#else> + + +
    +
    +
    + + \ No newline at end of file diff --git a/keycloak-themes/base/login/user-profile-commons.ftl b/keycloak-themes/base/login/user-profile-commons.ftl new file mode 100644 index 0000000..140eea3 --- /dev/null +++ b/keycloak-themes/base/login/user-profile-commons.ftl @@ -0,0 +1,187 @@ +<#macro userProfileFormFields> + <#assign currentGroup=""> + + <#list profile.attributes as attribute> + + <#assign groupName = attribute.group!""> + <#if groupName != currentGroup> + <#assign currentGroup=groupName> + <#if currentGroup != "" > +
    + + <#assign groupDisplayHeader=attribute.groupDisplayHeader!""> + <#if groupDisplayHeader != ""> + <#assign groupHeaderText=advancedMsg(attribute.groupDisplayHeader)!groupName> + <#else> + <#assign groupHeaderText=groupName> + +
    + +
    + + <#assign groupDisplayDescription=attribute.groupDisplayDescription!""> + <#if groupDisplayDescription != ""> + <#assign groupDescriptionText=advancedMsg(attribute.groupDisplayDescription)!""> +
    + +
    + +
    + + + + <#nested "beforeField" attribute> +
    +
    + + <#if attribute.required>* +
    +
    + <#if attribute.annotations.inputHelperTextBefore??> +
    ${kcSanitize(advancedMsg(attribute.annotations.inputHelperTextBefore))?no_esc}
    + + <@inputFieldByType attribute=attribute/> + <#if messagesPerField.existsError('${attribute.name}')> + + ${kcSanitize(messagesPerField.get('${attribute.name}'))?no_esc} + + + <#if attribute.annotations.inputHelperTextAfter??> +
    ${kcSanitize(advancedMsg(attribute.annotations.inputHelperTextAfter))?no_esc}
    + +
    +
    + <#nested "afterField" attribute> + + + +<#macro inputFieldByType attribute> + <#switch attribute.annotations.inputType!''> + <#case 'textarea'> + <@textareaTag attribute=attribute/> + <#break> + <#case 'select'> + <#case 'multiselect'> + <@selectTag attribute=attribute/> + <#break> + <#case 'select-radiobuttons'> + <#case 'multiselect-checkboxes'> + <@inputTagSelects attribute=attribute/> + <#break> + <#default> + <@inputTag attribute=attribute/> + + + +<#macro inputTag attribute> + disabled + <#if attribute.autocomplete??>autocomplete="${attribute.autocomplete}" + <#if attribute.annotations.inputTypePlaceholder??>placeholder="${attribute.annotations.inputTypePlaceholder}" + <#if attribute.annotations.inputTypePattern??>pattern="${attribute.annotations.inputTypePattern}" + <#if attribute.annotations.inputTypeSize??>size="${attribute.annotations.inputTypeSize}" + <#if attribute.annotations.inputTypeMaxlength??>maxlength="${attribute.annotations.inputTypeMaxlength}" + <#if attribute.annotations.inputTypeMinlength??>minlength="${attribute.annotations.inputTypeMinlength}" + <#if attribute.annotations.inputTypeMax??>max="${attribute.annotations.inputTypeMax}" + <#if attribute.annotations.inputTypeMin??>min="${attribute.annotations.inputTypeMin}" + <#if attribute.annotations.inputTypeStep??>step="${attribute.annotations.inputTypeStep}" + /> + + +<#macro inputTagType attribute> + <#compress> + <#if attribute.annotations.inputType??> + <#if attribute.annotations.inputType?starts_with("html5-")> + ${attribute.annotations.inputType[6..]} + <#else> + ${attribute.annotations.inputType} + + <#else> + text + + + + +<#macro textareaTag attribute> + + + +<#macro selectTag attribute> + + + +<#macro inputTagSelects attribute> + <#if attribute.annotations.inputType=='select-radiobuttons'> + <#assign inputType='radio'> + <#assign classDiv=properties.kcInputClassRadio!> + <#assign classInput=properties.kcInputClassRadioInput!> + <#assign classLabel=properties.kcInputClassRadioLabel!> + <#else> + <#assign inputType='checkbox'> + <#assign classDiv=properties.kcInputClassCheckbox!> + <#assign classInput=properties.kcInputClassCheckboxInput!> + <#assign classLabel=properties.kcInputClassCheckboxLabel!> + + + <#if attribute.annotations.inputOptionsFromValidation?? && attribute.validators[attribute.annotations.inputOptionsFromValidation]?? && attribute.validators[attribute.annotations.inputOptionsFromValidation].options??> + <#assign options=attribute.validators[attribute.annotations.inputOptionsFromValidation].options> + <#elseif attribute.validators.options?? && attribute.validators.options.options??> + <#assign options=attribute.validators.options.options> + + + <#if options??> + <#list options as option> +
    + disabled + <#if attribute.values?seq_contains(option)>checked + /> + +
    + + + + + +<#macro selectOptionLabelText attribute option> + <#compress> + <#if attribute.annotations.inputOptionLabels??> + ${advancedMsg(attribute.annotations.inputOptionLabels[option]!option)} + <#else> + <#if attribute.annotations.inputOptionLabelsI18nPrefix??> + ${msg(attribute.annotations.inputOptionLabelsI18nPrefix + '.' + option)} + <#else> + ${option} + + + + \ No newline at end of file diff --git a/keycloak-themes/base/login/webauthn-authenticate.ftl b/keycloak-themes/base/login/webauthn-authenticate.ftl new file mode 100644 index 0000000..a07f750 --- /dev/null +++ b/keycloak-themes/base/login/webauthn-authenticate.ftl @@ -0,0 +1,168 @@ + <#import "template.ftl" as layout> + <@layout.registrationLayout; section> + <#if section = "title"> + title + <#elseif section = "header"> + ${kcSanitize(msg("webauthn-login-title"))?no_esc} + <#elseif section = "form"> +
    +
    + + + + + + +
    + +
    + <#if authenticators??> +
    + <#list authenticators.authenticators as authenticator> + + +
    + + <#if shouldDisplayAuthenticators?? && shouldDisplayAuthenticators> + <#if authenticators.authenticators?size gt 1> +

    ${kcSanitize(msg("webauthn-available-authenticators"))?no_esc}

    + + +
    + <#list authenticators.authenticators as authenticator> +
    +
    + +
    +
    +
    + ${kcSanitize(msg('${authenticator.label}'))?no_esc} +
    + + <#if authenticator.transports?? && authenticator.transports.displayNameProperties?has_content> +
    + <#list authenticator.transports.displayNameProperties as nameProperty> + ${kcSanitize(msg('${nameProperty!}'))?no_esc} + <#if nameProperty?has_next> + , + + +
    + + +
    + + ${kcSanitize(msg('webauthn-createdAt-label'))?no_esc} + + + ${kcSanitize(authenticator.createdAt)?no_esc} + +
    +
    +
    +
    + +
    + + + +
    + +
    +
    +
    + + + + + <#elseif section = "info"> + + + diff --git a/keycloak-themes/base/login/webauthn-error.ftl b/keycloak-themes/base/login/webauthn-error.ftl new file mode 100644 index 0000000..2474a3f --- /dev/null +++ b/keycloak-themes/base/login/webauthn-error.ftl @@ -0,0 +1,36 @@ +<#import "template.ftl" as layout> +<@layout.registrationLayout displayMessage=true; section> + <#if section = "header"> + ${kcSanitize(msg("webauthn-error-title"))?no_esc} + <#elseif section = "form"> + + + +
    + + +
    + + + + <#if isAppInitiatedAction??> +
    + +
    + + + + \ No newline at end of file diff --git a/keycloak-themes/base/login/webauthn-register.ftl b/keycloak-themes/base/login/webauthn-register.ftl new file mode 100644 index 0000000..1b339a7 --- /dev/null +++ b/keycloak-themes/base/login/webauthn-register.ftl @@ -0,0 +1,192 @@ + <#import "template.ftl" as layout> + <@layout.registrationLayout; section> + <#if section = "title"> + title + <#elseif section = "header"> + + ${kcSanitize(msg("webauthn-registration-title"))?no_esc} + <#elseif section = "form"> + +
    +
    + + + + + + +
    +
    + + + + + + + + <#if !isSetRetry?has_content && isAppInitiatedAction?has_content> +
    + +
    + + + + \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/index.ftl b/keycloak-themes/keycloak.v2/account/index.ftl new file mode 100644 index 0000000..76d65c6 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/index.ftl @@ -0,0 +1,293 @@ + + + + ${msg("accountManagementTitle")} + + + + + + + + + <#if properties.favIcon?has_content> + + <#else> + + + + + + <#if properties.developmentMode?has_content && properties.developmentMode == "true"> + + + + + + + <#if properties.extensions?has_content> + <#list properties.extensions?split(' ') as script> + <#if properties.developmentMode?has_content && properties.developmentMode == "true"> + + <#else> + + + + + + <#if properties.scripts?has_content> + <#list properties.scripts?split(' ') as script> + + + + + + + <#if properties.styles?has_content> + <#list properties.styles?split(' ') as style> + + + + + + + + + + + + + + + + + +
    +
    + <#if properties.logo?has_content> + Logo + <#else> + Logo + +

    ${msg("loadingMessage")}

    +
    + + + + + +
    +
    +
    + + + + + + + diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_ca.properties b/keycloak-themes/keycloak.v2/account/messages/messages_ca.properties new file mode 100644 index 0000000..2e929f2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_ca.properties @@ -0,0 +1 @@ +fullName={0} {1} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_cs.properties b/keycloak-themes/keycloak.v2/account/messages/messages_cs.properties new file mode 100644 index 0000000..2e929f2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_cs.properties @@ -0,0 +1 @@ +fullName={0} {1} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_da.properties b/keycloak-themes/keycloak.v2/account/messages/messages_da.properties new file mode 100644 index 0000000..2e929f2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_da.properties @@ -0,0 +1 @@ +fullName={0} {1} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_de.properties b/keycloak-themes/keycloak.v2/account/messages/messages_de.properties new file mode 100644 index 0000000..a651492 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_de.properties @@ -0,0 +1,122 @@ +# Put new messages for Account Console Here +# Feel free to use any existing messages from the base theme +pageNotFound=Seite nicht gefunden +forbidden=Verboten +needAccessRights=Sie haben keine Zugriffsrechte auf diese Anfrage. Wenden Sie sich an Ihren Administrator. +invalidRoute={0} ist keine valide Route. +actionRequiresIDP=Diese Aktion erfordert eine Umleitung zu Ihrem Identit\u00E4tsanbieter. +actionNotDefined=Keine Aktion festgelegt +continue=Fortfahren +refreshPage=Aktualisiere die Seite +done=Fertig +cancel=Abbrechen +remove=Entfernen +update=Aktualisieren +status=Status +loadingMessage=Accountkonsole l\u00E4dt ... +unknownUser=Unbekannter Nutzer +fullName={0} {1} + +selectLocale=Sprache ausw\u00E4hlen +doSignIn=Anmelden + +# Device Activity Page +signedInDevices=Angemeldete Ger\u00E4te +signedInDevicesExplanation=Melde ein unbekanntes Ger\u00E4t ab. +signOutWarning=Session abmelden? +signOutAllDevices=Alle Ger\u00E4te abmelden +signOutAllDevicesWarning=Diese Aktion meldet alle Ger\u00E4te ab, die sich bei Ihrem Konto angemeldet haben, einschlie\u00DFlich des aktuellen Ger\u00E4ts, das Sie verwenden. +recentlyUsedDevices=K\u00FCrzlich verwendete Ger\u00E4te +recentlyUsedDevicesExplanation=Ger\u00E4te die im letzten Monat verwendet wurden, aber derzeit nicht angemeldet sind. +lastAccess=Letzter Zugriff +unknownOperatingSystem=Unbekanntes Betriebssystem +currentDevice=Aktuelles Ger\u00E4t +currentSession=Aktuelle Sitzung +signedOutSession=Abgemeldet {0}/{1} +lastAccessedOn=Zuletzt zugegriffen am +clients=Clients +startedAt=Gestartet am +expiresAt=L\u00E4uft ab am +ipAddress=IP Adresse + +# Resources Page +resourceName=Ressourcenname +nextPage=N\u00E4chste +previousPage=Vorherige +firstPage=Erste Seite +resourceSharedWith=Ressource ist freigegeben mit {0} +and=\ und {0} anderen Nutzern +add=Hinzuf\u00FCgen +share=Freigeben +edit=Editieren +close=Schlie\u00DFen +unShare=Alle Freigaben aufheben +shareSuccess=Ressource erfolgreich freigegeben. +unShareSuccess=Freigabe erfolgreich aufgehoben. +updateSuccess=Ressource erfolgreich aktualisiert. +resourceAlreadyShared=Ressource ist bereits an diesen Nutzer freigegeben. +resourceNotShared=Diese Ressource ist nicht freigegeben. +permissionRequests=Zugriffsanfragen +permissions=Zugriffsrechte +unShareAllConfirm=Wollen Sie wirklich alle Freigaben aufheben? +userNotFound=Kein Nutzer mit dem Namen oder E-Mail gefunden {0} + +# Linked Accounts Page +linkedAccountsTitle=Verbundene Konten +linkedAccountsIntroMessage=Verwalten Sie Anmeldungen \u00FCber Konten von Drittanbietern. +linkedLoginProviders=Verbundene Login Anbieter +unlinkedLoginProviders=Getrennte Login Anbieter +linkedEmpty=Keine verbundenen Anbieter +unlinkedEmpty=Keine getrennten Anbieter +socialLogin=Social Login +systemDefined=Systemdefiniert +link=Account verbinden +unLink=Account trennen + +# Signing In Page +signingIn=Anmeldung +signingInSubMessage=Konfigurieren Sie die Anmeldem\u00F6glichkeiten. +credentialCreatedAt=Erstellt +successRemovedMessage={0} wurde entfernt. +stopUsingCred={0} nicht mehr verwenden? +removeCred={0} entfernen +setUpNew={0} einrichten +notSetUp={0} ist nicht eingerichtet. +two-factor=Zwei-Faktor Authentifizierung +passwordless=Kennwortlos +unknown=Unbekannt +password-display-name=Passwort +password-help-text=Mit einem Passwort anmelden. +password=Mein Passwort +otp-display-name=Authenticator-Anwendung +otp-help-text=Geben Sie einen Verifizierungscode aus der Authenticator-Anwendung ein. +webauthn-display-name=Security-Token +webauthn-help-text=Verwenden Sie Ihr Security-Token zur Anmeldung. +webauthn-passwordless-display-name=Security-Token +webauthn-passwordless-help-text=Verwenden Sie Ihr Security-Token zur kennwortlosen Anmeldung. +basic-authentication=Standardauthentifizierung +invalidRequestMessage=Ung\u00FCltige Anfrage + +# Applications page +applicationsPageTitle=Anwendungen +internalApp=Intern +thirdPartyApp=Drittanbieter +offlineAccess=Offline Zugriff +inUse=In Benutzung +notInUse=Nicht in Benutzung +applicationDetails=Anwendungsdetails +client=Client +description=Beschreibung +baseUrl=URL +accessGrantedOn=Zugriff gew\u00E4hrt am +removeButton=Zugriff entfernen +removeModalTitle=Zugriff entfernen +removeModalMessage=Dadurch wird die aktuell gew\u00E4hrte Zugriffsberechtigung f\u00FCr {0} entfernt. Sie m\u00FCssen den Zugriff erneut gew\u00E4hren, wenn Sie diese Anwendung verwenden m\u00F6chten. +confirmButton=Best\u00E4tigen +infoMessage=Indem Sie auf "Zugriff entfernen" klicken, entfernen Sie gew\u00E4hrte Berechtigungen dieser Anwendung. Diese Anwendung wird Ihre Informationen nicht mehr verwenden. + +#Delete Account page +doDelete=L\u00F6schen +deleteAccountSummary=Wenn Sie Ihr Konto l\u00F6schen, werden alle Ihre Daten gel\u00F6scht und Sie werden sofort abgemeldet. +deleteAccount=Konto l\u00F6schen +deleteAccountWarning=Dies ist unwiderruflich. Alle Ihre Daten werden dauerhaft gel\u00F6scht und k\u00F6nnen nicht wiederhergestellt werden. diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_en.properties b/keycloak-themes/keycloak.v2/account/messages/messages_en.properties new file mode 100644 index 0000000..f1b31e7 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_en.properties @@ -0,0 +1,164 @@ +# Put new messages for Account Console Here +# Feel free to use any existing messages from the base theme +pageNotFound=Page not found +forbidden=Forbidden +needAccessRights=You do not have access rights to this request. Contact your administrator. +invalidRoute={0} is not a valid route. +actionRequiresIDP=This action requires redirection to your identity provider. +actionNotDefined=No action defined +continue=Continue +refreshPage=Refresh the page +refresh=Refresh +done=Done +cancel=Cancel +remove=Remove +update=Update +loadingMessage=Account Console loading ... +unknownUser=Anonymous +fullName={0} {1} +allFieldsRequired=All fields are required. + +selectLocale=Select a locale +doSignIn=Sign in + +backToAdminConsole=Back to admin console +accountManagementWelcomeMessage=Welcome to Keycloak account management + +# Personal info page +personalInfoHtmlTitle=Personal info + +# Device activity page +signedInDevices=Signed in devices +signedInDevicesExplanation=Sign out of any unfamiliar devices. +signOutWarning=Sign out the session? +signOutAllDevices=Sign out all devices +signOutAllDevicesWarning=This action will sign out all the devices that have signed in to your account, including the current device you are using. +recentlyUsedDevices=Recently used devices +recentlyUsedDevicesExplanation=Devices used in the last month, but not currently logged in. +lastAccess=Last access +unknownOperatingSystem=Unknown operating system +currentDevice=Current device +currentSession=Current session +signedOutSession=Signed out {0}/{1} +lastAccessedOn=Last accessed +clients=Clients +started=Started +expires=Expires +ipAddress=IP address + +# Resources page +resourceName=Resource name +nextPage=Next +previousPage=Previous +firstPage=First page +resourceSharedWith=Resource is shared with {0} +and=\ and {0} other users +add=Add +share=Share +shareWith=Share with +edit=Edit +close=Close +unShare=Unshare all +shareSuccess=Resource successfully shared. +unShareSuccess=Resource successfully un-shared. +updateSuccess=Resource successfully updated. +resourceAlreadyShared=Resource is already shared with this user. +resourceNotShared=This resource is not shared. +permissionRequests=Permission requests +permissions=Permissions +selectPermissions=Select the permissions +unShareAllConfirm=Are you sure you want to completely remove all shares? +userNotFound=No user found with name or email {0} + +# Linked accounts page +linkedAccountsTitle=Linked accounts +linkedAccountsIntroMessage=Manage logins through third-party accounts. +linkedLoginProviders=Linked login providers +unlinkedLoginProviders=Unlinked login providers +linkedEmpty=No linked providers +unlinkedEmpty=No unlinked providers +socialLogin=Social login +systemDefined=System defined +link=Link account +unLink=Unlink account + +# Signing in page +signingIn=Signing in +signingInSubMessage=Configure ways to sign in. +credentialCreatedAt=Created +successRemovedMessage={0} was removed. +stopUsingCred=Stop using {0}? +changePassword=Change password +removeCred=Remove {0} +setUpNew=Set up {0} +removeCredAriaLabel=Remove credential +updateCredAriaLabel=Update credential +notSetUp={0} is not set up. +two-factor=Two-factor authentication +passwordless=Passwordless +unknown=Unknown +password-display-name=Password +password-help-text=Log in by entering your password. +password=My password +otp-display-name=authenticator application +otp-help-text=Enter a verification code from authenticator application. +recovery-authn-code=My recovery authentication codes +recovery-authn-codes-display-name=Recovery authentication codes +recovery-authn-codes-help-text=These codes can be used to regain your access in case your other 2FA means are not available. +recovery-codes-number-used={0} recovery codes used +recovery-codes-number-remaining={0} recovery codes remaining +recovery-codes-generate-new-codes=Generate new codes to ensure access to your account +webauthn-display-name=Security key +webauthn-help-text=Use your security key to sign in. +webauthn-passwordless-display-name=Security key +webauthn-passwordless-help-text=Use your security key for passwordless sign in. +basic-authentication=Basic authentication +invalidRequestMessage=Invalid request + +# Applications page +applicationsPageTitle=Applications +internalApp=Internal +thirdPartyApp=Third-party +offlineAccess=Offline access +inUse=In use +notInUse=Not in use +applicationDetails=Application details +client=Client +description=Description +baseUrl=URL +accessGrantedOn=Access granted on +removeButton=Remove access +removeModalTitle=Remove access +removeModalMessage=This will remove the currently granted access permission for {0}. You will need to grant access again if you want to use this app. +confirmButton=Confirm +infoMessage=By clicking 'Remove Access', you will remove granted permissions of this application. This application will no longer use your information. +termsOfService=Terms of service +policy=Privacy policy +applicationType=Application type +status=Status + +#Delete account page +doDelete=Delete +deleteAccountSummary=Deleting your account will erase all your data and log you out immediately. +deleteAccount=Delete account +deleteAccountWarning=This is irreversible. All your data will be permanently destroyed, and irretrievable. + +error-invalid-value=''{0}'' has invalid value. +error-invalid-blank=Please specify value of ''{0}''. +error-empty=Please specify value of ''{0}''. +error-invalid-length=''{0}'' must have a length between {1} and {2}. +error-invalid-length-too-short=''{0}'' must have minimal length of {1}. +error-invalid-length-too-long=''{0}'' must have maximal length of {2}. +error-invalid-email=Invalid email address. +error-invalid-number=''{0}'' is invalid number. +error-number-out-of-range=''{0}'' must be a number between {1} and {2}. +error-number-out-of-range-too-small=''{0}'' must have minimal value of {1}. +error-number-out-of-range-too-big=''{0}'' must have maximal value of {2}. +error-pattern-no-match=''{0}'' doesn''t match required format. +error-invalid-uri=''{0}'' is invalid URL. +error-invalid-uri-scheme=''{0}'' has invalid URL scheme. +error-invalid-uri-fragment=''{0}'' is invalid URL fragment. +error-user-attribute-required=Please specify ''{0}''. +error-invalid-date=''{0}'' is invalid date. +error-username-invalid-character=''{0}'' contains invalid character. +error-person-name-invalid-character='{0}' contains invalid character. diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_es.properties b/keycloak-themes/keycloak.v2/account/messages/messages_es.properties new file mode 100644 index 0000000..2e929f2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_es.properties @@ -0,0 +1 @@ +fullName={0} {1} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_fr.properties b/keycloak-themes/keycloak.v2/account/messages/messages_fr.properties new file mode 100644 index 0000000..0dbac34 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_fr.properties @@ -0,0 +1,42 @@ +fullName={0} {1} +loadingMessage=Gestion du compte en cours de chargement ... + +# Personal informations page +selectLocale=Choisissez une langue + +# Authentication page +signingIn=Authentification +signingInSubMessage=Configurez les m\u00e9thodes d''authentification. +basic-authentication=Authentification de Base +password-display-name=Mot de passe +password-help-text=Authentifiez-vous en saisissant votre mot de passe +credentialCreatedAt=Cr\u00e9\u00e9 le +two-factor=Authentification \u00e0 Deux Facteurs +passwordless=Authentification Sans Mot de Passe +otp-display-name=Application d''authentification +otp-help-text=Entrez un code de v\u00e9rification \u00e0 usage unique fourni par l''application d''authentification. +webauthn-display-name=Cl\u00e9 de S\u00e9curit\u00e9 +webauthn-help-text=Utilisez votre cl\u00e9 de s\u00e9curit\u00e9 pour vous authentifier. +webauthn-passwordless-display-name=Cl\u00e9 de S\u00e9curit\u00e9 +webauthn-passwordless-help-text=Utilisez votre cl\u00e9 de s\u00e9curit\u00e9 pour une authentification sans mot de passe. +notSetUp={0} non configur\u00e9(e). +remove=Supprimer +refreshPage=Rafra\u00eechir la page +client_security-admin-console=Console d''administration de la s\u00e9curit\u00e9 +client_account-console=Console de gestion du compte + + +# Device Activity page +signedInDevices=Appareils Connect\u00e9s +signedInDevicesExplanation=D\u00e9connectez les appareils que vous ne reconnaissez pas. +currentSession=Session Courante +lastAccessedOn=Dernier acc\u00e8s le +startedAt=D\u00e9marr\u00e9(e) le +expiresAt=Expire le + +# Applications page +internalApp=Interne +thirdPartyApp=Tierce +inUse=Utilis\u00e9(e) +notInUse=Non utilis\u00e9(e) +setUpNew=Configurer {0} diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_hu.properties b/keycloak-themes/keycloak.v2/account/messages/messages_hu.properties new file mode 100644 index 0000000..2e929f2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_hu.properties @@ -0,0 +1 @@ +fullName={0} {1} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_it.properties b/keycloak-themes/keycloak.v2/account/messages/messages_it.properties new file mode 100644 index 0000000..2e929f2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_it.properties @@ -0,0 +1 @@ +fullName={0} {1} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_ja.properties b/keycloak-themes/keycloak.v2/account/messages/messages_ja.properties new file mode 100644 index 0000000..2e929f2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_ja.properties @@ -0,0 +1 @@ +fullName={0} {1} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_lt.properties b/keycloak-themes/keycloak.v2/account/messages/messages_lt.properties new file mode 100644 index 0000000..2e929f2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_lt.properties @@ -0,0 +1 @@ +fullName={0} {1} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_nl.properties b/keycloak-themes/keycloak.v2/account/messages/messages_nl.properties new file mode 100644 index 0000000..2e929f2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_nl.properties @@ -0,0 +1 @@ +fullName={0} {1} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_no.properties b/keycloak-themes/keycloak.v2/account/messages/messages_no.properties new file mode 100644 index 0000000..2e929f2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_no.properties @@ -0,0 +1 @@ +fullName={0} {1} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_pl.properties b/keycloak-themes/keycloak.v2/account/messages/messages_pl.properties new file mode 100644 index 0000000..2e929f2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_pl.properties @@ -0,0 +1 @@ +fullName={0} {1} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_pt_BR.properties b/keycloak-themes/keycloak.v2/account/messages/messages_pt_BR.properties new file mode 100644 index 0000000..3e056f9 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_pt_BR.properties @@ -0,0 +1,121 @@ +# Put new messages for Account Console Here +# Feel free to use any existing messages from the base theme +pageNotFound=P\u00e1gina N\u00e3o Encontrada +forbidden=Proibido +needAccessRights=Voc\u00ea n\u00e3o tem as permiss\u00f5es de acesso para esta solicita\u00e7\u00e3o. Entre em contato com um administrador. +invalidRoute={0} n\u00e3o \u00e9 uma rota v\u00e1lida. +actionRequiresIDP=Esta a\u00e7\u00e3o requer uma redire\u00e7\u00e3o do seu provedor de identidades. +actionNotDefined=Nenhuma a\u00e7\u00e3o definida +continue=Continuar +refreshPage=Atualizar p\u00e1gina +done=Pronto +cancel=Cancelar +remove=Remover +update=Atualizar +loadingMessage=Carregando console de conta... +unknownUser=An\u00f4nimo +fullName={0} {1} + +selectLocale=Selecionar l\u00edngua +doSignIn=Entrar + +# Device Activity Page +signedInDevices=Dispositivos autenticados +signedInDevicesExplanation=Saia de qualquer dispositivo que n\u00e3o reconhe\u00e7a. +signOutWarning=Finalizar todas as sess\u00f5es? +signOutAllDevices=Finalizar Sess\u00e3o em Todos os Dispositivos +signOutAllDevicesWarning=Esta a\u00e7\u00e3o ir\u00e1 finalizar a sess\u00e3o de todos os dispositivos logados na sua conta, incluindo o dispositivo que est\u00e1 sendo utilizado atualmente. +recentlyUsedDevices=Dispositivos Utilizados Recentemente +recentlyUsedDevicesExplanation=Dispositivos utilizados no \u00faltimo m\u00eas, mas sem sess\u00e3o ativa atualmente. +lastAccess=\u00daltimo Acesso +unknownOperatingSystem=Sistema Operacional Desconhecido +currentDevice=Dispositivo Atual +currentSession=Sess\u00e3o Atual +signedOutSession=Deslogado {0}/{1} +lastAccessedOn=\u00daltimo acesso em +clients=Clientes +startedAt=Iniciado em +expiresAt=Expira em +ipAddress=Endere\u00e7o IP + +# Resources Page +resourceName=Nome do Recurso +nextPage=Avan\u00e7ar +previousPage=Voltar +firstPage=Primeira P\u00e1gina +resourceSharedWith=O recurso \u00e9 compartilhado com {0} +and=\ e {0} outros usu\u00e1rios +add=Adicionar +share=Compartilhar +edit=Editar +close=Fechar +unShare=Descompartilhar tudo +shareSuccess=O recurso foi compartilhado com sucesso. +unShareSuccess=O recurso foi descompartilhado com sucesso. +updateSuccess=O recurso foi atualizado com sucesso. +resourceAlreadyShared=O recurso j\u00e1 foi compartilhado com este usu\u00e1rio. +resourceNotShared=O recurso n\u00e3o foi compartilhado. +permissionRequests=Pedidos de permiss\u00e3o +permissions=Permiss\u00f5es +unShareAllConfirm=Tem certeza de que quer remover todos os compartilhamentos? +userNotFound=Usu\u00e1rio com o nome ou e-mail {0} n\u00e3o foi encontrado + +# Linked Accounts Page +linkedAccountsTitle=Contas conectadas +linkedAccountsIntroMessage=Gerenciar acessos por contas de outras aplica\u00e7\u00f5es. +linkedLoginProviders=Provedores de Acesso Conectados +unlinkedLoginProviders=Provedores de Acesso N\u00e3o-Conectados +linkedEmpty=Nenhum Provedor Conectado +unlinkedEmpty=Nenhum Provedor N\u00e3o-Conectado +socialLogin=Login Social +systemDefined=Definido pelo Sistema +link=Conectar Conta +unLink=Desconectar Conta + +# Signing In Page +signingIn=Entrando na Conta +signingInSubMessage=Configure maneiras de entrar na conta. +credentialCreatedAt=Criada em +successRemovedMessage={0} removida com sucesso. +stopUsingCred=Para de usar {0}? +removeCred=Remover {0} +setUpNew=Configurar {0} +notSetUp={0} n\u00e3o est\u00e1 configurada. +two-factor=Autentica\u00e7\u00e3o de Dois Fatores +passwordless=Sem Senha +unknown=Desconhecida +password-display-name=Senha +password-help-text=Entre inserindo a sua senha. +password=Minha Senha +otp-display-name=App Autenticador +otp-help-text=Insira o c\u00f3digo de verifica\u00e7\u00e3o do app autenticador. +webauthn-display-name=Chave de Seguran\u00e7a +webauthn-help-text=Use a sua chave de seguran\u00e7a para entrar. +webauthn-passwordless-display-name=Chave de Seguran\u00e7a +webauthn-passwordless-help-text=Use a sua chave de seguran\u00e7a para entrar sem senha. +basic-authentication=Autentica\u00e7\u00e3o B\u00e1sica +invalidRequestMessage=Solicita\u00e7\u00e3o Inv\u00e1lida + +# Applications page +applicationsPageTitle=Aplica\u00e7\u00f5es +internalApp=Interna +thirdPartyApp=De Terceiros +offlineAccess=Acesso Offline +inUse=Em uso +notInUse=N\u00e3o utilizado +applicationDetails=Detalhes da Aplica\u00e7\u00e3o +client=Cliente +description=Descri\u00e7\u00e3o +baseUrl=URL +accessGrantedOn=Acesso concedido em +removeButton=Remover acesso +removeModalTitle=Remover Acesso +removeModalMessage=Isto ir\u00e1 remover a permiss\u00e3o atual de acesso concedido para {0}. Voc\u00ea precisar\u00e1 repetir o processo de concess\u00e3o se for utilizar o app novamente. +confirmButton=Confirmar +infoMessage=Ao clicar em 'Remover Acesso', voc\u00ea ir\u00e1 remover as permiss\u00f5es concedidas a esta aplica\u00e7\u00e3o. Ela n\u00e3o poder\u00e1 mais utilizar as suas informa\u00e7\u00f5es. + +#Delete Account page +doDelete=Apagar +deleteAccountSummary=Apagar a sua conta ir\u00e1 remover todos os seus dados e finalizar a sess\u00e3o imediatamente. +deleteAccount=Apagar Conta +deleteAccountWarning=Esta a\u00e7\u00e3o \u00e9 irrevers\u00edvel. Todos os seus dados ser\u00e3o apagados permanentemente e n\u00e3o poder\u00e3o ser recuperados. diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_ru.properties b/keycloak-themes/keycloak.v2/account/messages/messages_ru.properties new file mode 100644 index 0000000..2e929f2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_ru.properties @@ -0,0 +1 @@ +fullName={0} {1} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_sk.properties b/keycloak-themes/keycloak.v2/account/messages/messages_sk.properties new file mode 100644 index 0000000..2e929f2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_sk.properties @@ -0,0 +1 @@ +fullName={0} {1} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_sv.properties b/keycloak-themes/keycloak.v2/account/messages/messages_sv.properties new file mode 100644 index 0000000..2e929f2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_sv.properties @@ -0,0 +1 @@ +fullName={0} {1} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_tr.properties b/keycloak-themes/keycloak.v2/account/messages/messages_tr.properties new file mode 100644 index 0000000..2e929f2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_tr.properties @@ -0,0 +1 @@ +fullName={0} {1} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/messages/messages_zh_CN.properties b/keycloak-themes/keycloak.v2/account/messages/messages_zh_CN.properties new file mode 100644 index 0000000..2e929f2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/messages/messages_zh_CN.properties @@ -0,0 +1 @@ +fullName={0} {1} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/App.js b/keycloak-themes/keycloak.v2/account/resources/App.js new file mode 100644 index 0000000..3b55727 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/App.js @@ -0,0 +1,75 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../common/keycloak/web_modules/react.js"; +import { PageNav } from "./PageNav.js"; +import { PageHeaderTool } from "./PageHeaderTool.js"; +import { makeRoutes } from "./ContentPages.js"; +import { Brand, Page, PageHeader, PageSidebar } from "../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { KeycloakContext } from "./keycloak-service/KeycloakContext.js"; +; +export class App extends React.Component { + constructor(props, context) { + super(props); + + _defineProperty(this, "context", void 0); + + this.context = context; + toggleReact(); + } + + render() { + toggleReact(); // check login + + if (!this.context.authenticated() && !isWelcomePage()) { + this.context.login(); + } + + const username = /*#__PURE__*/React.createElement("span", { + style: { + marginLeft: '10px' + }, + id: "loggedInUser" + }, loggedInUserName()); + const Header = /*#__PURE__*/React.createElement(PageHeader, { + logo: /*#__PURE__*/React.createElement("a", { + id: "brandLink", + href: brandUrl + }, /*#__PURE__*/React.createElement(Brand, { + src: brandImg, + alt: "Logo", + className: "brand" + })), + headerTools: /*#__PURE__*/React.createElement(PageHeaderTool, null), + showNavToggle: true + }); + const Sidebar = /*#__PURE__*/React.createElement(PageSidebar, { + nav: /*#__PURE__*/React.createElement(PageNav, null) + }); + return /*#__PURE__*/React.createElement(Page, { + header: Header, + sidebar: Sidebar, + isManagedSidebar: true + }, makeRoutes()); + } + +} + +_defineProperty(App, "contextType", KeycloakContext); + +; +//# sourceMappingURL=App.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/App.js.map b/keycloak-themes/keycloak.v2/account/resources/App.js.map new file mode 100644 index 0000000..61555b0 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/App.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/app/App.tsx"],"names":["React","PageNav","PageHeaderTool","makeRoutes","Brand","Page","PageHeader","PageSidebar","KeycloakContext","App","Component","constructor","props","context","toggleReact","render","authenticated","isWelcomePage","login","username","marginLeft","loggedInUserName","Header","brandUrl","brandImg","Sidebar"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AAIA,SAAQC,OAAR;AACA,SAAQC,cAAR;AACA,SAAQC,UAAR;AAEA,SACIC,KADJ,EAEIC,IAFJ,EAGIC,UAHJ,EAIIC,WAJJ;AAOA,SAASC,eAAT;AAS4B;AAC5B,OAAO,MAAMC,GAAN,SAAkBT,KAAK,CAACU,SAAxB,CAA4C;AAIxCC,EAAAA,WAAW,CAACC,KAAD,EAAkBC,OAAlB,EAAsE;AACpF,UAAMD,KAAN;;AADoF;;AAEpF,SAAKC,OAAL,GAAeA,OAAf;AACAC,IAAAA,WAAW;AACd;;AAEMC,EAAAA,MAAM,GAAoB;AAC7BD,IAAAA,WAAW,GADkB,CAG7B;;AACA,QAAI,CAAC,KAAKD,OAAL,CAAcG,aAAd,EAAD,IAAkC,CAACC,aAAa,EAApD,EAAwD;AACpD,WAAKJ,OAAL,CAAcK,KAAd;AACH;;AAED,UAAMC,QAAQ,gBACV;AAAM,MAAA,KAAK,EAAE;AAACC,QAAAA,UAAU,EAAE;AAAb,OAAb;AAAmC,MAAA,EAAE,EAAC;AAAtC,OAAsDC,gBAAgB,EAAtE,CADJ;AAIA,UAAMC,MAAM,gBACR,oBAAC,UAAD;AACI,MAAA,IAAI,eAAE;AAAG,QAAA,EAAE,EAAC,WAAN;AAAkB,QAAA,IAAI,EAAEC;AAAxB,sBAAkC,oBAAC,KAAD;AAAO,QAAA,GAAG,EAAEC,QAAZ;AAAsB,QAAA,GAAG,EAAC,MAA1B;AAAiC,QAAA,SAAS,EAAC;AAA3C,QAAlC,CADV;AAEI,MAAA,WAAW,eAAE,oBAAC,cAAD,OAFjB;AAGI,MAAA,aAAa;AAHjB,MADJ;AAQA,UAAMC,OAAO,gBAAG,oBAAC,WAAD;AAAa,MAAA,GAAG,eAAE,oBAAC,OAAD;AAAlB,MAAhB;AAEA,wBACI,oBAAC,IAAD;AAAM,MAAA,MAAM,EAAEH,MAAd;AAAsB,MAAA,OAAO,EAAEG,OAA/B;AAAwC,MAAA,gBAAgB;AAAxD,OACKtB,UAAU,EADf,CADJ;AAKH;;AArC8C;;gBAAtCM,G,iBACYD,e;;AAqCxB","sourcesContent":["/*\n * Copyright 2018 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\n\nimport {KeycloakService} from './keycloak-service/keycloak.service';\n\nimport {PageNav} from './PageNav';\nimport {PageHeaderTool} from './PageHeaderTool';\nimport {makeRoutes} from './ContentPages';\n\nimport {\n Brand,\n Page,\n PageHeader,\n PageSidebar\n} from '@patternfly/react-core';\n\nimport { KeycloakContext } from './keycloak-service/KeycloakContext';\n\ndeclare function toggleReact(): void;\ndeclare function isWelcomePage(): boolean;\ndeclare function loggedInUserName(): string;\n\ndeclare const brandImg: string;\ndeclare const brandUrl: string;\n\nexport interface AppProps {};\nexport class App extends React.Component {\n static contextType = KeycloakContext;\n context: React.ContextType;\n\n public constructor(props: AppProps, context: React.ContextType) {\n super(props);\n this.context = context;\n toggleReact();\n }\n\n public render(): React.ReactNode {\n toggleReact();\n\n // check login\n if (!this.context!.authenticated() && !isWelcomePage()) {\n this.context!.login();\n }\n\n const username = (\n {loggedInUserName()}\n );\n\n const Header = (\n }\n headerTools={}\n showNavToggle\n />\n );\n\n const Sidebar = } />;\n\n return (\n \n {makeRoutes()}\n \n );\n }\n};\n"],"file":"App.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/ContentPages.js b/keycloak-themes/keycloak.v2/account/resources/ContentPages.js new file mode 100644 index 0000000..da2a117 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/ContentPages.js @@ -0,0 +1,157 @@ +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../common/keycloak/web_modules/react.js"; +import { Route, Switch } from "../../common/keycloak/web_modules/react-router-dom.js"; +import { NavItem, NavExpandable } from "../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { Msg } from "./widgets/Msg.js"; +import { PageNotFound } from "./content/page-not-found/PageNotFound.js"; +import { ForbiddenPage } from "./content/forbidden-page/ForbiddenPage.js"; +; +export function isModulePageDef(item) { + return item.modulePath !== undefined; +} +export function isExpansion(contentItem) { + return contentItem.content !== undefined; +} + +function groupId(group) { + return 'grp-' + group; +} + +function itemId(group, item) { + return 'grp-' + group + '_itm-' + item; +} + +function isChildOf(parent, child) { + for (var item of parent.content) { + if (isExpansion(item) && isChildOf(item, child)) return true; + if (parent.groupId === child.groupId) return true; + } + + return false; +} + +function createNavItems(activePage, contentParam, groupNum) { + if (typeof content === 'undefined') return /*#__PURE__*/React.createElement(React.Fragment, null); + const links = contentParam.map(item => { + const navLinkId = `nav-link-${item.id}`; + + if (isExpansion(item)) { + return /*#__PURE__*/React.createElement(NavExpandable, { + id: navLinkId, + groupId: item.groupId, + key: item.groupId, + title: Msg.localize(item.label, item.labelParams), + isExpanded: isChildOf(item, activePage) + }, createNavItems(activePage, item.content, groupNum + 1)); + } else { + const page = item; + return /*#__PURE__*/React.createElement(NavItem, { + id: navLinkId, + groupId: item.groupId, + itemId: item.itemId, + key: item.itemId, + to: '#/' + page.path, + isActive: activePage.itemId === item.itemId, + type: "button" + }, Msg.localize(page.label, page.labelParams)); + } + }); + return /*#__PURE__*/React.createElement(React.Fragment, null, links); +} + +export function makeNavItems(activePage) { + console.log({ + activePage + }); + return createNavItems(activePage, content, 0); +} + +function setIds(contentParam, groupNum) { + if (typeof contentParam === 'undefined') return groupNum; + let expansionGroupNum = groupNum; + + for (let i = 0; i < contentParam.length; i++) { + const item = contentParam[i]; + + if (isExpansion(item)) { + item.itemId = itemId(groupNum, i); + expansionGroupNum = expansionGroupNum + 1; + item.groupId = groupId(expansionGroupNum); + expansionGroupNum = setIds(item.content, expansionGroupNum); + console.log('currentGroup=' + expansionGroupNum); + } else { + item.groupId = groupId(groupNum); + item.itemId = itemId(groupNum, i); + } + } + + ; + return expansionGroupNum; +} + +export function initGroupAndItemIds() { + setIds(content, 0); + console.log({ + content + }); +} // get rid of Expansions and put all PageDef items into a single array + +export function flattenContent(pageDefs) { + const flat = []; + + for (let item of pageDefs) { + if (isExpansion(item)) { + flat.push(...flattenContent(item.content)); + } else { + flat.push(item); + } + } + + return flat; +} +export function makeRoutes() { + if (typeof content === 'undefined') return /*#__PURE__*/React.createElement("span", null); + const pageDefs = flattenContent(content); + const routes = pageDefs.map(page => { + if (isModulePageDef(page)) { + const node = React.createElement(page.module[page.componentName], { + 'pageDef': page + }); + return /*#__PURE__*/React.createElement(Route, { + key: page.itemId, + path: '/' + page.path, + exact: true, + render: () => node + }); + } else { + const pageDef = page; + return /*#__PURE__*/React.createElement(Route, { + key: page.itemId, + path: '/' + page.path, + exact: true, + component: pageDef.component + }); + } + }); + return /*#__PURE__*/React.createElement(Switch, null, routes, /*#__PURE__*/React.createElement(Route, { + path: "/forbidden", + component: ForbiddenPage + }), /*#__PURE__*/React.createElement(Route, { + component: PageNotFound + })); +} +//# sourceMappingURL=ContentPages.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/ContentPages.js.map b/keycloak-themes/keycloak.v2/account/resources/ContentPages.js.map new file mode 100644 index 0000000..f7e5f60 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/ContentPages.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/app/ContentPages.tsx"],"names":["React","Route","Switch","NavItem","NavExpandable","Msg","PageNotFound","ForbiddenPage","isModulePageDef","item","modulePath","undefined","isExpansion","contentItem","content","groupId","group","itemId","isChildOf","parent","child","createNavItems","activePage","contentParam","groupNum","links","map","navLinkId","id","localize","label","labelParams","page","path","makeNavItems","console","log","setIds","expansionGroupNum","i","length","initGroupAndItemIds","flattenContent","pageDefs","flat","push","makeRoutes","routes","node","createElement","module","componentName","pageDef","component"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AACA,SAAQC,KAAR,EAAeC,MAAf;AACA,SAAQC,OAAR,EAAiBC,aAAjB;AACA,SAAQC,GAAR;AACA,SAAQC,YAAR;AACA,SAASC,aAAT;AASC;AAoBD,OAAO,SAASC,eAAT,CAAyBC,IAAzB,EAAmE;AACtE,SAAQA,IAAD,CAAwBC,UAAxB,KAAuCC,SAA9C;AACH;AAED,OAAO,SAASC,WAAT,CAAqBC,WAArB,EAAyE;AAC5E,SAAQA,WAAD,CAA2BC,OAA3B,KAAuCH,SAA9C;AACH;;AAID,SAASI,OAAT,CAAiBC,KAAjB,EAAwC;AACpC,SAAO,SAASA,KAAhB;AACH;;AAED,SAASC,MAAT,CAAgBD,KAAhB,EAA+BP,IAA/B,EAAqD;AACjD,SAAO,SAASO,KAAT,GAAiB,OAAjB,GAA2BP,IAAlC;AACH;;AAED,SAASS,SAAT,CAAmBC,MAAnB,EAAsCC,KAAtC,EAA+D;AAC3D,OAAK,IAAIX,IAAT,IAAiBU,MAAM,CAACL,OAAxB,EAAiC;AAC7B,QAAIF,WAAW,CAACH,IAAD,CAAX,IAAqBS,SAAS,CAACT,IAAD,EAAOW,KAAP,CAAlC,EAAiD,OAAO,IAAP;AACjD,QAAID,MAAM,CAACJ,OAAP,KAAmBK,KAAK,CAACL,OAA7B,EAAsC,OAAO,IAAP;AACzC;;AAED,SAAO,KAAP;AACH;;AAED,SAASM,cAAT,CAAwBC,UAAxB,EAA6CC,YAA7C,EAA0EC,QAA1E,EAA6G;AACzG,MAAI,OAAOV,OAAP,KAAmB,WAAvB,EAAoC,oBAAQ,oBAAC,KAAD,CAAO,QAAP,OAAR;AAEpC,QAAMW,KAA2B,GAAGF,YAAY,CAACG,GAAb,CAAkBjB,IAAD,IAAuB;AACxE,UAAMkB,SAAS,GAAI,YAAWlB,IAAI,CAACmB,EAAG,EAAtC;;AACA,QAAIhB,WAAW,CAACH,IAAD,CAAf,EAAuB;AACnB,0BAAO,oBAAC,aAAD;AAAe,QAAA,EAAE,EAAEkB,SAAnB;AACe,QAAA,OAAO,EAAElB,IAAI,CAACM,OAD7B;AAEe,QAAA,GAAG,EAAEN,IAAI,CAACM,OAFzB;AAGe,QAAA,KAAK,EAAEV,GAAG,CAACwB,QAAJ,CAAapB,IAAI,CAACqB,KAAlB,EAAyBrB,IAAI,CAACsB,WAA9B,CAHtB;AAIe,QAAA,UAAU,EAAEb,SAAS,CAACT,IAAD,EAAOa,UAAP;AAJpC,SAMMD,cAAc,CAACC,UAAD,EAAab,IAAI,CAACK,OAAlB,EAA2BU,QAAQ,GAAG,CAAtC,CANpB,CAAP;AAQH,KATD,MASO;AACH,YAAMQ,IAAa,GAAGvB,IAAtB;AACA,0BAAO,oBAAC,OAAD;AAAS,QAAA,EAAE,EAAEkB,SAAb;AACS,QAAA,OAAO,EAAElB,IAAI,CAACM,OADvB;AAES,QAAA,MAAM,EAAEN,IAAI,CAACQ,MAFtB;AAGS,QAAA,GAAG,EAAER,IAAI,CAACQ,MAHnB;AAIS,QAAA,EAAE,EAAE,OAAOe,IAAI,CAACC,IAJzB;AAKS,QAAA,QAAQ,EAAEX,UAAU,CAACL,MAAX,KAAsBR,IAAI,CAACQ,MAL9C;AAMS,QAAA,IAAI,EAAC;AANd,SAOMZ,GAAG,CAACwB,QAAJ,CAAaG,IAAI,CAACF,KAAlB,EAAyBE,IAAI,CAACD,WAA9B,CAPN,CAAP;AASH;AACJ,GAvBmC,CAApC;AAyBA,sBAAQ,oBAAC,KAAD,CAAO,QAAP,QAAiBN,KAAjB,CAAR;AACH;;AAED,OAAO,SAASS,YAAT,CAAsBZ,UAAtB,EAA4D;AAC/Da,EAAAA,OAAO,CAACC,GAAR,CAAY;AAACd,IAAAA;AAAD,GAAZ;AACA,SAAOD,cAAc,CAACC,UAAD,EAAaR,OAAb,EAAsB,CAAtB,CAArB;AACH;;AAED,SAASuB,MAAT,CAAgBd,YAAhB,EAA6CC,QAA7C,EAAuE;AACnE,MAAI,OAAOD,YAAP,KAAwB,WAA5B,EAAyC,OAAOC,QAAP;AACzC,MAAIc,iBAAiB,GAAGd,QAAxB;;AAEA,OAAK,IAAIe,CAAC,GAAG,CAAb,EAAgBA,CAAC,GAAGhB,YAAY,CAACiB,MAAjC,EAAyCD,CAAC,EAA1C,EAA8C;AAC1C,UAAM9B,IAAiB,GAAGc,YAAY,CAACgB,CAAD,CAAtC;;AACA,QAAI3B,WAAW,CAACH,IAAD,CAAf,EAAuB;AACnBA,MAAAA,IAAI,CAACQ,MAAL,GAAcA,MAAM,CAACO,QAAD,EAAWe,CAAX,CAApB;AACAD,MAAAA,iBAAiB,GAAGA,iBAAiB,GAAG,CAAxC;AACA7B,MAAAA,IAAI,CAACM,OAAL,GAAeA,OAAO,CAACuB,iBAAD,CAAtB;AACAA,MAAAA,iBAAiB,GAAGD,MAAM,CAAC5B,IAAI,CAACK,OAAN,EAAewB,iBAAf,CAA1B;AACAH,MAAAA,OAAO,CAACC,GAAR,CAAY,kBAAmBE,iBAA/B;AACH,KAND,MAMO;AACH7B,MAAAA,IAAI,CAACM,OAAL,GAAeA,OAAO,CAACS,QAAD,CAAtB;AACAf,MAAAA,IAAI,CAACQ,MAAL,GAAcA,MAAM,CAACO,QAAD,EAAWe,CAAX,CAApB;AACH;AACJ;;AAAA;AAED,SAAOD,iBAAP;AACH;;AAED,OAAO,SAASG,mBAAT,GAAqC;AACxCJ,EAAAA,MAAM,CAACvB,OAAD,EAAU,CAAV,CAAN;AACAqB,EAAAA,OAAO,CAACC,GAAR,CAAY;AAACtB,IAAAA;AAAD,GAAZ;AACH,C,CAED;;AACA,OAAO,SAAS4B,cAAT,CAAwBC,QAAxB,EAA4D;AAC/D,QAAMC,IAAe,GAAG,EAAxB;;AAEA,OAAK,IAAInC,IAAT,IAAiBkC,QAAjB,EAA2B;AACvB,QAAI/B,WAAW,CAACH,IAAD,CAAf,EAAuB;AACnBmC,MAAAA,IAAI,CAACC,IAAL,CAAU,GAAGH,cAAc,CAACjC,IAAI,CAACK,OAAN,CAA3B;AACH,KAFD,MAEO;AACH8B,MAAAA,IAAI,CAACC,IAAL,CAAUpC,IAAV;AACH;AACJ;;AAED,SAAOmC,IAAP;AACH;AAED,OAAO,SAASE,UAAT,GAAuC;AAC1C,MAAI,OAAOhC,OAAP,KAAmB,WAAvB,EAAoC,oBAAQ,iCAAR;AAEpC,QAAM6B,QAAmB,GAAGD,cAAc,CAAC5B,OAAD,CAA1C;AAEA,QAAMiC,MAAmC,GAAGJ,QAAQ,CAACjB,GAAT,CAAcM,IAAD,IAAmB;AACxE,QAAIxB,eAAe,CAACwB,IAAD,CAAnB,EAA2B;AACvB,YAAMgB,IAAqB,GAAGhD,KAAK,CAACiD,aAAN,CAAoBjB,IAAI,CAACkB,MAAL,CAAYlB,IAAI,CAACmB,aAAjB,CAApB,EAAqD;AAAC,mBAAWnB;AAAZ,OAArD,CAA9B;AACA,0BAAO,oBAAC,KAAD;AAAO,QAAA,GAAG,EAAEA,IAAI,CAACf,MAAjB;AAAyB,QAAA,IAAI,EAAE,MAAMe,IAAI,CAACC,IAA1C;AAAgD,QAAA,KAAK,MAArD;AAAsD,QAAA,MAAM,EAAE,MAAMe;AAApE,QAAP;AACH,KAHD,MAGO;AACH,YAAMI,OAAyB,GAAGpB,IAAlC;AACA,0BAAO,oBAAC,KAAD;AAAO,QAAA,GAAG,EAAEA,IAAI,CAACf,MAAjB;AAAyB,QAAA,IAAI,EAAE,MAAMe,IAAI,CAACC,IAA1C;AAAgD,QAAA,KAAK,MAArD;AAAsD,QAAA,SAAS,EAAEmB,OAAO,CAACC;AAAzE,QAAP;AACH;AACJ,GAR2C,CAA5C;AAUA,sBAAQ,oBAAC,MAAD,QACKN,MADL,eAEI,oBAAC,KAAD;AAAO,IAAA,IAAI,EAAC,YAAZ;AAAyB,IAAA,SAAS,EAAExC;AAApC,IAFJ,eAGI,oBAAC,KAAD;AAAO,IAAA,SAAS,EAAED;AAAlB,IAHJ,CAAR;AAKH","sourcesContent":["/*\n * Copyright 2019 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\nimport {Route, Switch} from 'react-router-dom';\nimport {NavItem, NavExpandable} from '@patternfly/react-core';\nimport {Msg} from './widgets/Msg';\nimport {PageNotFound} from './content/page-not-found/PageNotFound';\nimport { ForbiddenPage } from './content/forbidden-page/ForbiddenPage';\n\nexport interface ContentItem {\n id?: string;\n label: string;\n labelParams?: string[];\n hidden?: string;\n groupId: string; // computed value\n itemId: string; // computed value\n};\n\nexport interface Expansion extends ContentItem {\n content: ContentItem[];\n}\n\nexport interface PageDef extends ContentItem {\n path: string;\n}\n\nexport interface ComponentPageDef extends PageDef {\n component: React.ComponentType;\n}\n\nexport interface ModulePageDef extends PageDef {\n modulePath: string;\n componentName: string;\n module: React.Component; // computed value\n}\n\nexport function isModulePageDef(item: ContentItem): item is ModulePageDef {\n return (item as ModulePageDef).modulePath !== undefined;\n}\n\nexport function isExpansion(contentItem: ContentItem): contentItem is Expansion {\n return (contentItem as Expansion).content !== undefined;\n}\n\ndeclare const content: ContentItem[];\n\nfunction groupId(group: number): string {\n return 'grp-' + group;\n}\n\nfunction itemId(group: number, item: number): string {\n return 'grp-' + group + '_itm-' + item;\n}\n\nfunction isChildOf(parent: Expansion, child: PageDef): boolean {\n for (var item of parent.content) {\n if (isExpansion(item) && isChildOf(item, child)) return true;\n if (parent.groupId === child.groupId) return true;\n }\n\n return false;\n}\n\nfunction createNavItems(activePage: PageDef, contentParam: ContentItem[], groupNum: number): React.ReactNode {\n if (typeof content === 'undefined') return ();\n\n const links: React.ReactElement[] = contentParam.map((item: ContentItem) => {\n const navLinkId = `nav-link-${item.id}`;\n if (isExpansion(item)) {\n return \n {createNavItems(activePage, item.content, groupNum + 1)}\n \n } else {\n const page: PageDef = item as PageDef;\n return \n {Msg.localize(page.label, page.labelParams)}\n \n }\n });\n\n return ({links});\n}\n\nexport function makeNavItems(activePage: PageDef): React.ReactNode {\n console.log({activePage});\n return createNavItems(activePage, content, 0);\n}\n\nfunction setIds(contentParam: ContentItem[], groupNum: number): number {\n if (typeof contentParam === 'undefined') return groupNum;\n let expansionGroupNum = groupNum;\n\n for (let i = 0; i < contentParam.length; i++) {\n const item: ContentItem = contentParam[i];\n if (isExpansion(item)) {\n item.itemId = itemId(groupNum, i);\n expansionGroupNum = expansionGroupNum + 1;\n item.groupId = groupId(expansionGroupNum);\n expansionGroupNum = setIds(item.content, expansionGroupNum);\n console.log('currentGroup=' + (expansionGroupNum));\n } else {\n item.groupId = groupId(groupNum);\n item.itemId = itemId(groupNum, i);\n }\n };\n\n return expansionGroupNum;\n}\n\nexport function initGroupAndItemIds(): void {\n setIds(content, 0);\n console.log({content});\n}\n\n// get rid of Expansions and put all PageDef items into a single array\nexport function flattenContent(pageDefs: ContentItem[]): PageDef[] {\n const flat: PageDef[] = [];\n\n for (let item of pageDefs) {\n if (isExpansion(item)) {\n flat.push(...flattenContent(item.content));\n } else {\n flat.push(item as PageDef);\n }\n }\n\n return flat;\n}\n\nexport function makeRoutes(): React.ReactNode {\n if (typeof content === 'undefined') return ();\n\n const pageDefs: PageDef[] = flattenContent(content);\n\n const routes: React.ReactElement[] = pageDefs.map((page: PageDef) => {\n if (isModulePageDef(page)) {\n const node: React.ReactNode = React.createElement(page.module[page.componentName], {'pageDef': page});\n return node} />;\n } else {\n const pageDef: ComponentPageDef = page as ComponentPageDef;\n return ;\n }\n });\n\n return (\n {routes}\n \n \n );\n}\n"],"file":"ContentPages.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/Main.js b/keycloak-themes/keycloak.v2/account/resources/Main.js new file mode 100644 index 0000000..4bc8921 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/Main.js @@ -0,0 +1,97 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../common/keycloak/web_modules/react.js"; +import * as ReactDOM from "../../common/keycloak/web_modules/react-dom.js"; +import { HashRouter } from "../../common/keycloak/web_modules/react-router-dom.js"; +import { App } from "./App.js"; +import { flattenContent, initGroupAndItemIds, isExpansion, isModulePageDef } from "./ContentPages.js"; +import { KeycloakService } from "./keycloak-service/keycloak.service.js"; +import { KeycloakContext } from "./keycloak-service/KeycloakContext.js"; +import { AccountServiceClient } from "./account-service/account.service.js"; +import { AccountServiceContext } from "./account-service/AccountServiceContext.js"; +export class Main extends React.Component { + constructor(props) { + super(props); + } + + componentDidMount() { + isReactLoading = false; + toggleReact(); + } + + render() { + const keycloakService = new KeycloakService(keycloak); + return /*#__PURE__*/React.createElement(HashRouter, null, /*#__PURE__*/React.createElement(KeycloakContext.Provider, { + value: keycloakService + }, /*#__PURE__*/React.createElement(AccountServiceContext.Provider, { + value: new AccountServiceClient(keycloakService) + }, /*#__PURE__*/React.createElement(App, null)))); + } + +} +; +const e = React.createElement; + +function removeHidden(items) { + const visible = []; + + for (let item of items) { + if (item.hidden && eval(item.hidden)) continue; + + if (isExpansion(item)) { + visible.push(item); + item.content = removeHidden(item.content); + + if (item.content.length === 0) { + visible.pop(); // remove empty expansion + } + } else { + visible.push(item); + } + } + + return visible; +} + +content = removeHidden(content); +initGroupAndItemIds(); + +function loadModule(modulePage) { + return new Promise((resolve, reject) => { + console.log('loading: ' + resourceUrl + modulePage.modulePath); + import(resourceUrl + modulePage.modulePath).then(module => { + modulePage.module = module; + resolve(modulePage); + }).catch(error => { + console.warn('Unable to load ' + modulePage.label + ' because ' + error.message); + reject(modulePage); + }); + }); +} + +; +const moduleLoaders = []; +flattenContent(content).forEach(item => { + if (isModulePageDef(item)) { + moduleLoaders.push(loadModule(item)); + } +}); // load content modules and start + +Promise.all(moduleLoaders).then(() => { + const domContainer = document.querySelector('#main_react_container'); + ReactDOM.render(e(Main), domContainer); +}); +//# sourceMappingURL=Main.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/Main.js.map b/keycloak-themes/keycloak.v2/account/resources/Main.js.map new file mode 100644 index 0000000..3e3c38e --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/Main.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/app/Main.tsx"],"names":["React","ReactDOM","HashRouter","App","flattenContent","initGroupAndItemIds","isExpansion","isModulePageDef","KeycloakService","KeycloakContext","AccountServiceClient","AccountServiceContext","Main","Component","constructor","props","componentDidMount","isReactLoading","toggleReact","render","keycloakService","keycloak","e","createElement","removeHidden","items","visible","item","hidden","eval","push","content","length","pop","loadModule","modulePage","Promise","resolve","reject","console","log","resourceUrl","modulePath","then","module","catch","error","warn","label","message","moduleLoaders","forEach","all","domContainer","document","querySelector"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AACA,OAAO,KAAKC,QAAZ;AAEA,SAAQC,UAAR;AAEA,SAAQC,GAAR;AACA,SAAoCC,cAApC,EAAoDC,mBAApD,EAAyEC,WAAzE,EAAsFC,eAAtF;AAEA,SAAyBC,eAAzB;AACA,SAASC,eAAT;AACA,SAASC,oBAAT;AACA,SAASC,qBAAT;AASA,OAAO,MAAMC,IAAN,SAAmBZ,KAAK,CAACa,SAAzB,CAA8C;AAE1CC,EAAAA,WAAW,CAACC,KAAD,EAAmB;AACjC,UAAMA,KAAN;AACH;;AAEMC,EAAAA,iBAAiB,GAAS;AAC7BC,IAAAA,cAAc,GAAG,KAAjB;AACAC,IAAAA,WAAW;AACd;;AAEMC,EAAAA,MAAM,GAAoB;AAC7B,UAAMC,eAAe,GAAG,IAAIZ,eAAJ,CAAoBa,QAApB,CAAxB;AACA,wBACI,oBAAC,UAAD,qBACI,oBAAC,eAAD,CAAiB,QAAjB;AAA0B,MAAA,KAAK,EAAED;AAAjC,oBACI,oBAAC,qBAAD,CAAuB,QAAvB;AAAgC,MAAA,KAAK,EAAE,IAAIV,oBAAJ,CAAyBU,eAAzB;AAAvC,oBACI,oBAAC,GAAD,OADJ,CADJ,CADJ,CADJ;AASH;;AAtBgD;AAuBpD;AAID,MAAME,CAAC,GAAGtB,KAAK,CAACuB,aAAhB;;AAEA,SAASC,YAAT,CAAsBC,KAAtB,EAA2D;AACvD,QAAMC,OAAsB,GAAG,EAA/B;;AAEA,OAAK,IAAIC,IAAT,IAAiBF,KAAjB,EAAwB;AACpB,QAAIE,IAAI,CAACC,MAAL,IAAeC,IAAI,CAACF,IAAI,CAACC,MAAN,CAAvB,EAAsC;;AAEtC,QAAItB,WAAW,CAACqB,IAAD,CAAf,EAAuB;AACnBD,MAAAA,OAAO,CAACI,IAAR,CAAaH,IAAb;AACAA,MAAAA,IAAI,CAACI,OAAL,GAAeP,YAAY,CAACG,IAAI,CAACI,OAAN,CAA3B;;AACA,UAAIJ,IAAI,CAACI,OAAL,CAAaC,MAAb,KAAwB,CAA5B,EAA+B;AAC3BN,QAAAA,OAAO,CAACO,GAAR,GAD2B,CACZ;AAClB;AACJ,KAND,MAMO;AACHP,MAAAA,OAAO,CAACI,IAAR,CAAaH,IAAb;AACH;AACJ;;AAED,SAAOD,OAAP;AACH;;AAEDK,OAAO,GAAGP,YAAY,CAACO,OAAD,CAAtB;AACA1B,mBAAmB;;AAEnB,SAAS6B,UAAT,CAAoBC,UAApB,EAAuE;AACnE,SAAO,IAAIC,OAAJ,CAAa,CAACC,OAAD,EAAUC,MAAV,KAAqB;AACrCC,IAAAA,OAAO,CAACC,GAAR,CAAY,cAAcC,WAAd,GAA4BN,UAAU,CAACO,UAAnD;AACA,WAAOD,WAAW,GAAGN,UAAU,CAACO,UAAhC,EAA4CC,IAA5C,CAAmDC,MAAD,IAA6B;AAC3ET,MAAAA,UAAU,CAACS,MAAX,GAAoBA,MAApB;AACAP,MAAAA,OAAO,CAACF,UAAD,CAAP;AACH,KAHD,EAGGU,KAHH,CAGUC,KAAD,IAAkB;AACvBP,MAAAA,OAAO,CAACQ,IAAR,CAAa,oBAAoBZ,UAAU,CAACa,KAA/B,GAAuC,WAAvC,GAAqDF,KAAK,CAACG,OAAxE;AACAX,MAAAA,MAAM,CAACH,UAAD,CAAN;AACH,KAND;AAOH,GATM,CAAP;AAUH;;AAAA;AAED,MAAMe,aAAuC,GAAG,EAAhD;AACA9C,cAAc,CAAC2B,OAAD,CAAd,CAAwBoB,OAAxB,CAAiCxB,IAAD,IAAuB;AACnD,MAAIpB,eAAe,CAACoB,IAAD,CAAnB,EAA2B;AACvBuB,IAAAA,aAAa,CAACpB,IAAd,CAAmBI,UAAU,CAACP,IAAD,CAA7B;AACH;AACJ,CAJD,E,CAMA;;AACAS,OAAO,CAACgB,GAAR,CAAYF,aAAZ,EAA2BP,IAA3B,CAAgC,MAAM;AAClC,QAAMU,YAAY,GAAGC,QAAQ,CAACC,aAAT,CAAuB,uBAAvB,CAArB;AACAtD,EAAAA,QAAQ,CAACkB,MAAT,CAAgBG,CAAC,CAACV,IAAD,CAAjB,EAAyByC,YAAzB;AACH,CAHD","sourcesContent":["/*\n * Copyright 2018 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\nimport * as ReactDOM from 'react-dom';\n\nimport {HashRouter} from 'react-router-dom';\n\nimport {App} from './App';\nimport {ContentItem, ModulePageDef, flattenContent, initGroupAndItemIds, isExpansion, isModulePageDef} from './ContentPages';\n\nimport { KeycloakClient, KeycloakService } from './keycloak-service/keycloak.service';\nimport { KeycloakContext } from './keycloak-service/KeycloakContext';\nimport { AccountServiceClient } from './account-service/account.service';\nimport { AccountServiceContext } from './account-service/AccountServiceContext';\n\ndeclare const keycloak: KeycloakClient;\n\ndeclare let isReactLoading: boolean;\ndeclare function toggleReact(): void;\ndeclare const features: { [key: string]: boolean; };\n\nexport interface MainProps {}\nexport class Main extends React.Component {\n\n public constructor(props: MainProps) {\n super(props);\n }\n\n public componentDidMount(): void {\n isReactLoading = false;\n toggleReact();\n }\n\n public render(): React.ReactNode {\n const keycloakService = new KeycloakService(keycloak);\n return (\n \n \n \n \n \n \n \n );\n }\n};\n\ndeclare const resourceUrl: string;\ndeclare let content: ContentItem[];\nconst e = React.createElement;\n\nfunction removeHidden(items: ContentItem[]): ContentItem[] {\n const visible: ContentItem[] = [];\n\n for (let item of items) {\n if (item.hidden && eval(item.hidden)) continue;\n\n if (isExpansion(item)) {\n visible.push(item);\n item.content = removeHidden(item.content);\n if (item.content.length === 0) {\n visible.pop(); // remove empty expansion\n }\n } else {\n visible.push(item);\n }\n }\n\n return visible;\n}\n\ncontent = removeHidden(content);\ninitGroupAndItemIds();\n\nfunction loadModule(modulePage: ModulePageDef): Promise {\n return new Promise ((resolve, reject) => {\n console.log('loading: ' + resourceUrl + modulePage.modulePath);\n import(resourceUrl + modulePage.modulePath).then( (module: React.Component) => {\n modulePage.module = module;\n resolve(modulePage);\n }).catch((error: Error) => {\n console.warn('Unable to load ' + modulePage.label + ' because ' + error.message);\n reject(modulePage);\n });\n });\n};\n\nconst moduleLoaders: Promise[] = [];\nflattenContent(content).forEach((item: ContentItem) => {\n if (isModulePageDef(item)) {\n moduleLoaders.push(loadModule(item));\n }\n});\n\n// load content modules and start\nPromise.all(moduleLoaders).then(() => {\n const domContainer = document.querySelector('#main_react_container');\n ReactDOM.render(e(Main), domContainer);\n});\n"],"file":"Main.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/PageHeaderTool.js b/keycloak-themes/keycloak.v2/account/resources/PageHeaderTool.js new file mode 100644 index 0000000..47c55c1 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/PageHeaderTool.js @@ -0,0 +1,23 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +import * as React from "../../common/keycloak/web_modules/react.js"; +import { PageHeaderTools } from "../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { ReferrerLink } from "./widgets/ReferrerLink.js"; +import { LogoutButton } from "./widgets/Logout.js"; +export class PageHeaderTool extends React.Component { + constructor(...args) { + super(...args); + + _defineProperty(this, "hasReferrer", typeof referrerName !== 'undefined'); + } + + render() { + return /*#__PURE__*/React.createElement(PageHeaderTools, null, this.hasReferrer && /*#__PURE__*/React.createElement("div", { + className: "pf-c-page__header-tools-group" + }, /*#__PURE__*/React.createElement(ReferrerLink, null)), /*#__PURE__*/React.createElement("div", { + className: "pf-c-page__header-tools-group" + }, /*#__PURE__*/React.createElement(LogoutButton, null))); + } + +} +//# sourceMappingURL=PageHeaderTool.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/PageHeaderTool.js.map b/keycloak-themes/keycloak.v2/account/resources/PageHeaderTool.js.map new file mode 100644 index 0000000..9ccd7b1 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/PageHeaderTool.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/app/PageHeaderTool.tsx"],"names":["React","PageHeaderTools","ReferrerLink","LogoutButton","PageHeaderTool","Component","referrerName","render","hasReferrer"],"mappings":";;AAAA,OAAO,KAAKA,KAAZ;AAEA,SAAQC,eAAR;AACA,SAAQC,YAAR;AACA,SAAQC,YAAR;AAIA,OAAO,MAAMC,cAAN,SAA6BJ,KAAK,CAACK,SAAnC,CAA6C;AAAA;AAAA;;AAAA,yCACjB,OAAOC,YAAP,KAAwB,WADP;AAAA;;AAGzCC,EAAAA,MAAM,GAAoB;AAC7B,wBACI,oBAAC,eAAD,QACK,KAAKC,WAAL,iBACG;AAAK,MAAA,SAAS,EAAC;AAAf,oBACI,oBAAC,YAAD,OADJ,CAFR,eAOI;AAAK,MAAA,SAAS,EAAC;AAAf,oBACI,oBAAC,YAAD,OADJ,CAPJ,CADJ;AAaH;;AAjB+C","sourcesContent":["import * as React from 'react';\n\nimport {PageHeaderTools} from '@patternfly/react-core';\nimport {ReferrerLink} from './widgets/ReferrerLink';\nimport {LogoutButton} from './widgets/Logout';\n\ndeclare const referrerName: string;\n\nexport class PageHeaderTool extends React.Component {\n private hasReferrer: boolean = typeof referrerName !== 'undefined';\n\n public render(): React.ReactNode {\n return (\n \n {this.hasReferrer &&\n
    \n \n
    \n }\n\n
    \n \n
    \n
    \n );\n }\n}\n"],"file":"PageHeaderTool.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/PageNav.js b/keycloak-themes/keycloak.v2/account/resources/PageNav.js new file mode 100644 index 0000000..f75b7de --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/PageNav.js @@ -0,0 +1,51 @@ +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../common/keycloak/web_modules/react.js"; +import { withRouter } from "../../common/keycloak/web_modules/react-router-dom.js"; +import { Nav, NavList } from "../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { makeNavItems, flattenContent } from "./ContentPages.js"; + +class PageNavigation extends React.Component { + constructor(props) { + super(props); + } + + findActiveItem() { + const currentPath = this.props.location.pathname; + const items = flattenContent(content); + const firstItem = items[0]; + + for (let item of items) { + const itemPath = '/' + item.path; + + if (itemPath === currentPath) { + return item; + } + } + + ; + return firstItem; + } + + render() { + const activeItem = this.findActiveItem(); + return /*#__PURE__*/React.createElement(Nav, null, /*#__PURE__*/React.createElement(NavList, null, makeNavItems(activeItem))); + } + +} + +export const PageNav = withRouter(PageNavigation); +//# sourceMappingURL=PageNav.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/PageNav.js.map b/keycloak-themes/keycloak.v2/account/resources/PageNav.js.map new file mode 100644 index 0000000..d56998f --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/PageNav.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/app/PageNav.tsx"],"names":["React","withRouter","Nav","NavList","makeNavItems","flattenContent","PageNavigation","Component","constructor","props","findActiveItem","currentPath","location","pathname","items","content","firstItem","item","itemPath","path","render","activeItem","PageNav"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AACA,SAAQC,UAAR;AACA,SAAQC,GAAR,EAAaC,OAAb;AAEA,SAAQC,YAAR,EAAsBC,cAAtB;;AAQA,MAAMC,cAAN,SAA6BN,KAAK,CAACO,SAAnC,CAAyE;AAE9DC,EAAAA,WAAW,CAACC,KAAD,EAAsB;AACpC,UAAMA,KAAN;AACH;;AAEOC,EAAAA,cAAc,GAAY;AAC9B,UAAMC,WAAmB,GAAG,KAAKF,KAAL,CAAWG,QAAX,CAAoBC,QAAhD;AACA,UAAMC,KAAgB,GAAGT,cAAc,CAACU,OAAD,CAAvC;AACA,UAAMC,SAAS,GAAGF,KAAK,CAAC,CAAD,CAAvB;;AACA,SAAK,IAAIG,IAAT,IAAiBH,KAAjB,EAAwB;AACpB,YAAMI,QAAgB,GAAG,MAAMD,IAAI,CAACE,IAApC;;AACA,UAAID,QAAQ,KAAKP,WAAjB,EAA8B;AAC1B,eAAOM,IAAP;AACH;AACJ;;AAAA;AAED,WAAOD,SAAP;AACH;;AAEMI,EAAAA,MAAM,GAAoB;AAC7B,UAAMC,UAAmB,GAAG,KAAKX,cAAL,EAA5B;AACA,wBACI,oBAAC,GAAD,qBACI,oBAAC,OAAD,QACKN,YAAY,CAACiB,UAAD,CADjB,CADJ,CADJ;AAOH;;AA7BoE;;AAgCzE,OAAO,MAAMC,OAAO,GAAGrB,UAAU,CAACK,cAAD,CAA1B","sourcesContent":["/*\n * Copyright 2019 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\nimport {withRouter, RouteComponentProps} from 'react-router-dom';\nimport {Nav, NavList} from '@patternfly/react-core';\n\nimport {makeNavItems, flattenContent, ContentItem, PageDef} from './ContentPages';\n\ndeclare const content: ContentItem[];\n\nexport interface PageNavProps extends RouteComponentProps {}\n\nexport interface PageNavState {}\n\nclass PageNavigation extends React.Component {\n\n public constructor(props: PageNavProps) {\n super(props);\n }\n\n private findActiveItem(): PageDef {\n const currentPath: string = this.props.location.pathname;\n const items: PageDef[] = flattenContent(content);\n const firstItem = items[0];\n for (let item of items) {\n const itemPath: string = '/' + item.path;\n if (itemPath === currentPath) {\n return item;\n }\n };\n\n return firstItem;\n }\n\n public render(): React.ReactNode {\n const activeItem: PageDef = this.findActiveItem();\n return (\n \n );\n }\n}\n\nexport const PageNav = withRouter(PageNavigation);\n"],"file":"PageNav.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/PageToolbar.js b/keycloak-themes/keycloak.v2/account/resources/PageToolbar.js new file mode 100644 index 0000000..3ed61cd --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/PageToolbar.js @@ -0,0 +1,60 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../common/keycloak/web_modules/react.js"; +import { Toolbar, ToolbarGroup, ToolbarItem } from "../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { ReferrerLink } from "./widgets/ReferrerLink.js"; +import { LogoutButton } from "./widgets/Logout.js"; +export class PageToolbar extends React.Component { + constructor(props) { + super(props); + + _defineProperty(this, "hasReferrer", typeof referrerName !== 'undefined'); + + _defineProperty(this, "onKebabDropdownToggle", isKebabDropdownOpen => { + this.setState({ + isKebabDropdownOpen + }); + }); + + this.state = { + isKebabDropdownOpen: false + }; + } + + render() { + return /*#__PURE__*/React.createElement(Toolbar, null, this.hasReferrer && /*#__PURE__*/React.createElement(ToolbarGroup, { + key: "referrerGroup", + alignment: { + default: "alignRight" + } + }, /*#__PURE__*/React.createElement(ToolbarItem, { + className: "pf-m-icons", + key: "referrer" + }, /*#__PURE__*/React.createElement(ReferrerLink, null))), /*#__PURE__*/React.createElement(ToolbarGroup, { + key: "secondGroup", + alignment: { + default: "alignRight" + } + }, /*#__PURE__*/React.createElement(ToolbarItem, { + className: "pf-m-icons", + key: "logout" + }, /*#__PURE__*/React.createElement(LogoutButton, null)))); + } + +} +//# sourceMappingURL=PageToolbar.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/PageToolbar.js.map b/keycloak-themes/keycloak.v2/account/resources/PageToolbar.js.map new file mode 100644 index 0000000..646e2b9 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/PageToolbar.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/app/PageToolbar.tsx"],"names":["React","Toolbar","ToolbarGroup","ToolbarItem","ReferrerLink","LogoutButton","PageToolbar","Component","constructor","props","referrerName","isKebabDropdownOpen","setState","state","render","hasReferrer","default"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AAEA,SAA+BC,OAA/B,EAAwCC,YAAxC,EAAsDC,WAAtD;AAGA,SAAQC,YAAR;AAEA,SAAQC,YAAR;AAOA,OAAO,MAAMC,WAAN,SAA0BN,KAAK,CAACO,SAAhC,CAA8E;AAG1EC,EAAAA,WAAW,CAACC,KAAD,EAA0B;AACxC,UAAMA,KAAN;;AADwC,yCAFb,OAAOC,YAAP,KAAwB,WAEX;;AAAA,mDAQXC,mBAAD,IAAkC;AAC9D,WAAKC,QAAL,CAAc;AACVD,QAAAA;AADU,OAAd;AAGH,KAZ2C;;AAGxC,SAAKE,KAAL,GAAa;AACTF,MAAAA,mBAAmB,EAAE;AADZ,KAAb;AAGH;;AAQMG,EAAAA,MAAM,GAAoB;AAC7B,wBACI,oBAAC,OAAD,QACK,KAAKC,WAAL,iBACG,oBAAC,YAAD;AAAc,MAAA,GAAG,EAAC,eAAlB;AAAkC,MAAA,SAAS,EAAE;AAACC,QAAAA,OAAO,EAAC;AAAT;AAA7C,oBACI,oBAAC,WAAD;AAAa,MAAA,SAAS,EAAC,YAAvB;AAAoC,MAAA,GAAG,EAAC;AAAxC,oBACI,oBAAC,YAAD,OADJ,CADJ,CAFR,eASI,oBAAC,YAAD;AAAc,MAAA,GAAG,EAAC,aAAlB;AAAgC,MAAA,SAAS,EAAE;AAACA,QAAAA,OAAO,EAAC;AAAT;AAA3C,oBACI,oBAAC,WAAD;AAAa,MAAA,SAAS,EAAC,YAAvB;AAAoC,MAAA,GAAG,EAAC;AAAxC,oBACI,oBAAC,YAAD,OADJ,CADJ,CATJ,CADJ;AAiBH;;AAnCgF","sourcesContent":["/*\n * Copyright 2019 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\n\nimport {Dropdown, KebabToggle, Toolbar, ToolbarGroup, ToolbarItem} from '@patternfly/react-core';\n\nimport {ReferrerDropdownItem} from './widgets/ReferrerDropdownItem';\nimport {ReferrerLink} from './widgets/ReferrerLink';\nimport {Features} from './widgets/features';\nimport {LogoutButton,LogoutDropdownItem} from './widgets/Logout';\n\ndeclare const referrerName: string;\ndeclare const features: Features;\n\ninterface PageToolbarProps {}\ninterface PageToolbarState {isKebabDropdownOpen: boolean}\nexport class PageToolbar extends React.Component {\n private hasReferrer: boolean = typeof referrerName !== 'undefined';\n\n public constructor(props: PageToolbarProps) {\n super(props);\n\n this.state = {\n isKebabDropdownOpen: false,\n };\n }\n\n private onKebabDropdownToggle = (isKebabDropdownOpen: boolean) => {\n this.setState({\n isKebabDropdownOpen\n });\n };\n\n public render(): React.ReactNode {\n return (\n \n {this.hasReferrer &&\n \n \n \n \n \n }\n\n \n \n \n \n \n \n );\n }\n}\n"],"file":"PageToolbar.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/account-service/AccountServiceContext.js b/keycloak-themes/keycloak.v2/account/resources/account-service/AccountServiceContext.js new file mode 100644 index 0000000..a5aec7b --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/account-service/AccountServiceContext.js @@ -0,0 +1,3 @@ +import * as React from "../../../common/keycloak/web_modules/react.js"; +export const AccountServiceContext = React.createContext(undefined); +//# sourceMappingURL=AccountServiceContext.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/account-service/AccountServiceContext.js.map b/keycloak-themes/keycloak.v2/account/resources/account-service/AccountServiceContext.js.map new file mode 100644 index 0000000..1fa9f2b --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/account-service/AccountServiceContext.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/account-service/AccountServiceContext.tsx"],"names":["React","AccountServiceContext","createContext","undefined"],"mappings":"AAAA,OAAO,KAAKA,KAAZ;AAGA,OAAO,MAAMC,qBAAqB,GAAGD,KAAK,CAACE,aAAN,CAAsDC,SAAtD,CAA9B","sourcesContent":["import * as React from 'react';\nimport { AccountServiceClient } from './account.service';\n\nexport const AccountServiceContext = React.createContext(undefined);"],"file":"AccountServiceContext.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/account-service/account.service.js b/keycloak-themes/keycloak.v2/account/resources/account-service/account.service.js new file mode 100644 index 0000000..f2e85e7 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/account-service/account.service.js @@ -0,0 +1,149 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2018 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @author tags. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +import { ContentAlert } from "../content/ContentAlert.js"; +export class AccountServiceError extends Error { + constructor(response) { + super(response.statusText); + this.response = response; + } + +} +/** + * + * @author Stan Silvert ssilvert@redhat.com (C) 2018 Red Hat Inc. + */ + +export class AccountServiceClient { + constructor(keycloakService) { + _defineProperty(this, "kcSvc", void 0); + + _defineProperty(this, "accountUrl", void 0); + + this.kcSvc = keycloakService; + this.accountUrl = this.kcSvc.authServerUrl() + 'realms/' + this.kcSvc.realm() + '/account'; + } + + async doGet(endpoint, config) { + return this.doRequest(endpoint, { ...config, + method: 'get' + }); + } + + async doDelete(endpoint, config) { + return this.doRequest(endpoint, { ...config, + method: 'delete' + }); + } + + async doPost(endpoint, body, config) { + return this.doRequest(endpoint, { ...config, + body: JSON.stringify(body), + method: 'post' + }); + } + + async doPut(endpoint, body, config) { + return this.doRequest(endpoint, { ...config, + body: JSON.stringify(body), + method: 'put' + }); + } + + async doRequest(endpoint, config) { + const response = await fetch(this.makeUrl(endpoint, config).toString(), await this.makeConfig(config)); + + try { + response.data = await response.json(); + } catch (e) {} // ignore. Might be empty + + + if (!response.ok) { + this.handleError(response); + throw new AccountServiceError(response); + } + + return response; + } + + handleError(response) { + if (response !== null && response.status === 401) { + if (this.kcSvc.authenticated() && !this.kcSvc.audiencePresent()) { + // authenticated and the audience is not present => not allowed + window.location.href = baseUrl + '#/forbidden'; + } else { + // session timed out? + this.kcSvc.login(); + } + } + + if (response !== null && response.status === 403) { + window.location.href = baseUrl + '#/forbidden'; + } + + if (response !== null && response.data != null) { + if (response.data['errors'] != null) { + for (let err of response.data['errors']) ContentAlert.danger(err['errorMessage'], err['params']); + } else { + ContentAlert.danger(`${response.statusText}: ${response.data['errorMessage'] ? response.data['errorMessage'] : ''} ${response.data['error'] ? response.data['error'] : ''}`); + } + + ; + } else { + ContentAlert.danger(response.statusText); + } + } + + makeUrl(endpoint, config) { + if (endpoint.startsWith('http')) return new URL(endpoint); + const url = new URL(this.accountUrl + endpoint); // add request params + + if (config && config.hasOwnProperty('params')) { + const params = config.params || {}; + Object.keys(params).forEach(key => url.searchParams.append(key, params[key])); + } + + return url; + } + + makeConfig(config = {}) { + return new Promise(resolve => { + this.kcSvc.getToken().then(token => { + resolve({ ...config, + headers: { + 'Content-Type': 'application/json', + ...config.headers, + Authorization: 'Bearer ' + token + } + }); + }).catch(() => { + this.kcSvc.login(); + }); + }); + } + +} +window.addEventListener("unhandledrejection", event => { + event.promise.catch(error => { + if (error instanceof AccountServiceError) { + // We already handled the error. Ignore unhandled rejection. + event.preventDefault(); + } + }); +}); +//# sourceMappingURL=account.service.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/account-service/account.service.js.map b/keycloak-themes/keycloak.v2/account/resources/account-service/account.service.js.map new file mode 100644 index 0000000..0e06da6 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/account-service/account.service.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/account-service/account.service.ts"],"names":["ContentAlert","AccountServiceError","Error","constructor","response","statusText","AccountServiceClient","keycloakService","kcSvc","accountUrl","authServerUrl","realm","doGet","endpoint","config","doRequest","method","doDelete","doPost","body","JSON","stringify","doPut","fetch","makeUrl","toString","makeConfig","data","json","e","ok","handleError","status","authenticated","audiencePresent","window","location","href","baseUrl","login","err","danger","startsWith","URL","url","hasOwnProperty","params","Object","keys","forEach","key","searchParams","append","Promise","resolve","getToken","then","token","headers","Authorization","catch","addEventListener","event","promise","error","preventDefault"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA,SAAQA,YAAR;AAcA,OAAO,MAAMC,mBAAN,SAAkCC,KAAlC,CAAwC;AAC3CC,EAAAA,WAAW,CAAQC,QAAR,EAAgC;AACvC,UAAMA,QAAQ,CAACC,UAAf;AADuC,SAAxBD,QAAwB,GAAxBA,QAAwB;AAE1C;;AAH0C;AAM/C;AACA;AACA;AACA;;AACA,OAAO,MAAME,oBAAN,CAA2B;AAIvBH,EAAAA,WAAW,CAACI,eAAD,EAAmC;AAAA;;AAAA;;AACjD,SAAKC,KAAL,GAAaD,eAAb;AACA,SAAKE,UAAL,GAAkB,KAAKD,KAAL,CAAWE,aAAX,KAA6B,SAA7B,GAAyC,KAAKF,KAAL,CAAWG,KAAX,EAAzC,GAA8D,UAAhF;AACH;;AAEiB,QAALC,KAAK,CAAIC,QAAJ,EACIC,MADJ,EAC8D;AAC5E,WAAO,KAAKC,SAAL,CAAeF,QAAf,EAAyB,EAAC,GAAGC,MAAJ;AAAYE,MAAAA,MAAM,EAAE;AAApB,KAAzB,CAAP;AACH;;AAEoB,QAARC,QAAQ,CAAIJ,QAAJ,EACGC,MADH,EAC6D;AAC9E,WAAO,KAAKC,SAAL,CAAeF,QAAf,EAAyB,EAAC,GAAGC,MAAJ;AAAYE,MAAAA,MAAM,EAAE;AAApB,KAAzB,CAAP;AACH;;AAEkB,QAANE,MAAM,CAAIL,QAAJ,EACGM,IADH,EAEGL,MAFH,EAE6D;AAC5E,WAAO,KAAKC,SAAL,CAAeF,QAAf,EAAyB,EAAC,GAAGC,MAAJ;AAAYK,MAAAA,IAAI,EAAEC,IAAI,CAACC,SAAL,CAAeF,IAAf,CAAlB;AAAwCH,MAAAA,MAAM,EAAE;AAAhD,KAAzB,CAAP;AACH;;AAEiB,QAALM,KAAK,CAAIT,QAAJ,EACGM,IADH,EAEGL,MAFH,EAE6D;AAC3E,WAAO,KAAKC,SAAL,CAAeF,QAAf,EAAyB,EAAC,GAAGC,MAAJ;AAAYK,MAAAA,IAAI,EAAEC,IAAI,CAACC,SAAL,CAAeF,IAAf,CAAlB;AAAwCH,MAAAA,MAAM,EAAE;AAAhD,KAAzB,CAAP;AACH;;AAEqB,QAATD,SAAS,CAAIF,QAAJ,EACIC,MADJ,EAC8D;AAEhF,UAAMV,QAAyB,GAAG,MAAMmB,KAAK,CAAC,KAAKC,OAAL,CAAaX,QAAb,EAAuBC,MAAvB,EAA+BW,QAA/B,EAAD,EACC,MAAM,KAAKC,UAAL,CAAgBZ,MAAhB,CADP,CAA7C;;AAGA,QAAI;AACAV,MAAAA,QAAQ,CAACuB,IAAT,GAAgB,MAAMvB,QAAQ,CAACwB,IAAT,EAAtB;AACH,KAFD,CAEE,OAAOC,CAAP,EAAU,CAAE,CAPkE,CAOjE;;;AAEf,QAAI,CAACzB,QAAQ,CAAC0B,EAAd,EAAkB;AACd,WAAKC,WAAL,CAAiB3B,QAAjB;AACA,YAAM,IAAIH,mBAAJ,CAAwBG,QAAxB,CAAN;AACH;;AAED,WAAOA,QAAP;AACH;;AAEO2B,EAAAA,WAAW,CAAC3B,QAAD,EAA+B;AAC9C,QAAIA,QAAQ,KAAK,IAAb,IAAqBA,QAAQ,CAAC4B,MAAT,KAAoB,GAA7C,EAAkD;AAC9C,UAAI,KAAKxB,KAAL,CAAWyB,aAAX,MAA8B,CAAC,KAAKzB,KAAL,CAAW0B,eAAX,EAAnC,EAAiE;AAC7D;AACAC,QAAAA,MAAM,CAACC,QAAP,CAAgBC,IAAhB,GAAuBC,OAAO,GAAG,aAAjC;AACH,OAHD,MAGO;AACH;AACA,aAAK9B,KAAL,CAAW+B,KAAX;AACH;AACJ;;AAED,QAAInC,QAAQ,KAAK,IAAb,IAAqBA,QAAQ,CAAC4B,MAAT,KAAoB,GAA7C,EAAkD;AAC9CG,MAAAA,MAAM,CAACC,QAAP,CAAgBC,IAAhB,GAAuBC,OAAO,GAAG,aAAjC;AACH;;AAED,QAAIlC,QAAQ,KAAK,IAAb,IAAqBA,QAAQ,CAACuB,IAAT,IAAiB,IAA1C,EAAgD;AAC5C,UAAIvB,QAAQ,CAACuB,IAAT,CAAc,QAAd,KAA2B,IAA/B,EAAqC;AACjC,aAAI,IAAIa,GAAR,IAAepC,QAAQ,CAACuB,IAAT,CAAc,QAAd,CAAf,EACI3B,YAAY,CAACyC,MAAb,CAAoBD,GAAG,CAAC,cAAD,CAAvB,EAAyCA,GAAG,CAAC,QAAD,CAA5C;AACP,OAHD,MAGO;AACHxC,QAAAA,YAAY,CAACyC,MAAb,CACC,GAAErC,QAAQ,CAACC,UAAW,KAAID,QAAQ,CAACuB,IAAT,CAAc,cAAd,IAAgCvB,QAAQ,CAACuB,IAAT,CAAc,cAAd,CAAhC,GAAgE,EAAG,IAAGvB,QAAQ,CAACuB,IAAT,CAAc,OAAd,IAAyBvB,QAAQ,CAACuB,IAAT,CAAc,OAAd,CAAzB,GAAkD,EAAG,EADtJ;AAEH;;AAAA;AACJ,KARD,MAQO;AACH3B,MAAAA,YAAY,CAACyC,MAAb,CAAoBrC,QAAQ,CAACC,UAA7B;AACH;AACJ;;AAEOmB,EAAAA,OAAO,CAACX,QAAD,EAAmBC,MAAnB,EAAwD;AACnE,QAAID,QAAQ,CAAC6B,UAAT,CAAoB,MAApB,CAAJ,EAAiC,OAAO,IAAIC,GAAJ,CAAQ9B,QAAR,CAAP;AACjC,UAAM+B,GAAG,GAAG,IAAID,GAAJ,CAAQ,KAAKlC,UAAL,GAAkBI,QAA1B,CAAZ,CAFmE,CAInE;;AACA,QAAIC,MAAM,IAAIA,MAAM,CAAC+B,cAAP,CAAsB,QAAtB,CAAd,EAA+C;AAC3C,YAAMC,MAAgC,GAAGhC,MAAM,CAACgC,MAAP,IAAuB,EAAhE;AACAC,MAAAA,MAAM,CAACC,IAAP,CAAYF,MAAZ,EAAoBG,OAApB,CAA4BC,GAAG,IAAIN,GAAG,CAACO,YAAJ,CAAiBC,MAAjB,CAAwBF,GAAxB,EAA6BJ,MAAM,CAACI,GAAD,CAAnC,CAAnC;AACH;;AAED,WAAON,GAAP;AACH;;AAEOlB,EAAAA,UAAU,CAACZ,MAAmB,GAAG,EAAvB,EAAiD;AAC/D,WAAO,IAAIuC,OAAJ,CAAcC,OAAD,IAA4B;AAC5C,WAAK9C,KAAL,CAAW+C,QAAX,GACKC,IADL,CACYC,KAAD,IAAmB;AACtBH,QAAAA,OAAO,CAAE,EACL,GAAGxC,MADE;AAEL4C,UAAAA,OAAO,EAAE;AAAC,4BAAgB,kBAAjB;AACA,eAAG5C,MAAM,CAAC4C,OADV;AAECC,YAAAA,aAAa,EAAE,YAAYF;AAF5B;AAFJ,SAAF,CAAP;AAMH,OARL,EAQOG,KARP,CAQa,MAAM;AACX,aAAKpD,KAAL,CAAW+B,KAAX;AACH,OAVL;AAWH,KAZM,CAAP;AAaH;;AAxG6B;AA4GlCJ,MAAM,CAAC0B,gBAAP,CAAwB,oBAAxB,EAA+CC,KAAD,IAAkC;AAC5EA,EAAAA,KAAK,CAACC,OAAN,CAAcH,KAAd,CAAoBI,KAAK,IAAI;AACzB,QAAIA,KAAK,YAAY/D,mBAArB,EAA0C;AACtC;AACA6D,MAAAA,KAAK,CAACG,cAAN;AACH;AACJ,GALD;AAMH,CAPD","sourcesContent":["/*\n * Copyright 2018 Red Hat Inc. and/or its affiliates and other contributors\n * as indicated by the @author tags. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\nimport {KeycloakService} from '../keycloak-service/keycloak.service';\nimport {ContentAlert} from '../content/ContentAlert';\n\ndeclare const baseUrl: string;\n\ntype ConfigResolve = (config: RequestInit) => void;\n\nexport interface HttpResponse extends Response {\n data?: T;\n}\n\nexport interface RequestInitWithParams extends RequestInit {\n params?: {[name: string]: string | number};\n}\n\nexport class AccountServiceError extends Error {\n constructor(public response: HttpResponse) {\n super(response.statusText);\n }\n}\n\n/**\n *\n * @author Stan Silvert ssilvert@redhat.com (C) 2018 Red Hat Inc.\n */\nexport class AccountServiceClient {\n private kcSvc: KeycloakService;\n private accountUrl: string;\n\n public constructor(keycloakService: KeycloakService) {\n this.kcSvc = keycloakService;\n this.accountUrl = this.kcSvc.authServerUrl() + 'realms/' + this.kcSvc.realm() + '/account';\n }\n\n public async doGet(endpoint: string,\n config?: RequestInitWithParams): Promise> {\n return this.doRequest(endpoint, {...config, method: 'get'});\n }\n\n public async doDelete(endpoint: string,\n config?: RequestInitWithParams): Promise> {\n return this.doRequest(endpoint, {...config, method: 'delete'});\n }\n\n public async doPost(endpoint: string,\n body: string | {},\n config?: RequestInitWithParams): Promise> {\n return this.doRequest(endpoint, {...config, body: JSON.stringify(body), method: 'post'});\n }\n\n public async doPut(endpoint: string,\n body: string | {},\n config?: RequestInitWithParams): Promise> {\n return this.doRequest(endpoint, {...config, body: JSON.stringify(body), method: 'put'});\n }\n\n public async doRequest(endpoint: string,\n config?: RequestInitWithParams): Promise> {\n\n const response: HttpResponse = await fetch(this.makeUrl(endpoint, config).toString(),\n await this.makeConfig(config));\n\n try {\n response.data = await response.json();\n } catch (e) {} // ignore. Might be empty\n\n if (!response.ok) {\n this.handleError(response);\n throw new AccountServiceError(response);\n }\n\n return response;\n }\n\n private handleError(response: HttpResponse): void {\n if (response !== null && response.status === 401) {\n if (this.kcSvc.authenticated() && !this.kcSvc.audiencePresent()) {\n // authenticated and the audience is not present => not allowed\n window.location.href = baseUrl + '#/forbidden';\n } else {\n // session timed out?\n this.kcSvc.login();\n }\n }\n\n if (response !== null && response.status === 403) {\n window.location.href = baseUrl + '#/forbidden';\n }\n\n if (response !== null && response.data != null) {\n if (response.data['errors'] != null) {\n for(let err of response.data['errors'])\n ContentAlert.danger(err['errorMessage'], err['params']);\n } else {\n ContentAlert.danger(\n `${response.statusText}: ${response.data['errorMessage'] ? response.data['errorMessage'] : ''} ${response.data['error'] ? response.data['error'] : ''}`);\n };\n } else {\n ContentAlert.danger(response.statusText);\n }\n }\n\n private makeUrl(endpoint: string, config?: RequestInitWithParams): URL {\n if (endpoint.startsWith('http')) return new URL(endpoint);\n const url = new URL(this.accountUrl + endpoint);\n\n // add request params\n if (config && config.hasOwnProperty('params')) {\n const params: {[name: string]: string} = config.params as {} || {};\n Object.keys(params).forEach(key => url.searchParams.append(key, params[key]))\n }\n\n return url;\n }\n\n private makeConfig(config: RequestInit = {}): Promise {\n return new Promise( (resolve: ConfigResolve) => {\n this.kcSvc.getToken()\n .then( (token: string) => {\n resolve( {\n ...config,\n headers: {'Content-Type': 'application/json',\n ...config.headers,\n Authorization: 'Bearer ' + token}\n });\n }).catch(() => {\n this.kcSvc.login();\n });\n });\n }\n\n}\n\nwindow.addEventListener(\"unhandledrejection\", (event: PromiseRejectionEvent) => {\n event.promise.catch(error => {\n if (error instanceof AccountServiceError) {\n // We already handled the error. Ignore unhandled rejection.\n event.preventDefault();\n }\n });\n});\n"],"file":"account.service.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content.json b/keycloak-themes/keycloak.v2/account/resources/content.json new file mode 100644 index 0000000..ef26e31 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content.json @@ -0,0 +1,60 @@ +[ + { + "id": "personal-info", + "path": "personal-info", + "icon": "pf-icon-user", + "label": "personalInfoSidebarTitle", + "descriptionLabel": "personalInfoIntroMessage", + "modulePath": "/content/account-page/AccountPage.js", + "componentName": "AccountPage" + }, + { + "id": "security", + "icon": "pf-icon-security", + "label": "accountSecuritySidebarTitle", + "descriptionLabel": "accountSecurityIntroMessage", + "content": [ + { + "id": "signingin", + "path": "security/signingin", + "label": "signingInSidebarTitle", + "modulePath": "/content/signingin-page/SigningInPage.js", + "componentName": "SigningInPage" + }, + { + "id": "device-activity", + "path": "security/device-activity", + "label": "deviceActivitySidebarTitle", + "modulePath": "/content/device-activity-page/DeviceActivityPage.js", + "componentName": "DeviceActivityPage" + }, + { + "id": "linked-accounts", + "path": "security/linked-accounts", + "label": "linkedAccountsSidebarTitle", + "modulePath": "/content/linked-accounts-page/LinkedAccountsPage.js", + "componentName": "LinkedAccountsPage", + "hidden": "!features.isLinkedAccountsEnabled" + } + ] + }, + { + "id": "applications", + "icon": "pf-icon-applications", + "path": "applications", + "label": "applications", + "descriptionLabel": "applicationsIntroMessage", + "modulePath": "/content/applications-page/ApplicationsPage.js", + "componentName": "ApplicationsPage" + }, + { + "id": "resources", + "icon": "pf-icon-repository", + "path": "resources", + "label": "resources", + "descriptionLabel": "resourceIntroMessage", + "modulePath": "/content/my-resources-page/MyResourcesPage.js", + "componentName": "MyResourcesPage", + "hidden": "!features.isMyResourcesEnabled" + } +] \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/ContentAlert.js b/keycloak-themes/keycloak.v2/account/resources/content/ContentAlert.js new file mode 100644 index 0000000..c8a6933 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/ContentAlert.js @@ -0,0 +1,113 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../common/keycloak/web_modules/react.js"; +import { Alert, AlertActionCloseButton, AlertGroup, AlertVariant } from "../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { Msg } from "../widgets/Msg.js"; +export class ContentAlert extends React.Component { + constructor(props) { + super(props); + + _defineProperty(this, "hideAlert", key => { + this.setState({ + alerts: [...this.state.alerts.filter(el => el.key !== key)] + }); + }); + + _defineProperty(this, "getUniqueId", () => new Date().getTime()); + + _defineProperty(this, "postAlert", (variant, message, params) => { + const alerts = this.state.alerts; + const key = this.getUniqueId(); + alerts.push({ + key, + message: Msg.localize(message, params), + variant + }); + this.setState({ + alerts + }); + + if (variant !== AlertVariant.danger) { + setTimeout(() => this.hideAlert(key), 8000); + } + }); + + this.state = { + alerts: [] + }; + ContentAlert.instance = this; + } + /** + * @param message A literal text message or localization key. + */ + + + static success(message, params) { + ContentAlert.instance.postAlert(AlertVariant.success, message, params); + } + /** + * @param message A literal text message or localization key. + */ + + + static danger(message, params) { + ContentAlert.instance.postAlert(AlertVariant.danger, message, params); + } + /** + * @param message A literal text message or localization key. + */ + + + static warning(message, params) { + ContentAlert.instance.postAlert(AlertVariant.warning, message, params); + } + /** + * @param message A literal text message or localization key. + */ + + + static info(message, params) { + ContentAlert.instance.postAlert(AlertVariant.info, message, params); + } + + render() { + return /*#__PURE__*/React.createElement(AlertGroup, { + isToast: true, + "aria-live": "assertive" + }, this.state.alerts.map(({ + key, + variant, + message + }) => /*#__PURE__*/React.createElement(Alert, { + "aria-details": message, + isLiveRegion: true, + variant: variant, + title: message, + actionClose: /*#__PURE__*/React.createElement(AlertActionCloseButton, { + title: message, + variantLabel: `${variant} alert`, + onClose: () => this.hideAlert(key) + }), + key: key + }))); + } + +} + +_defineProperty(ContentAlert, "instance", void 0); +//# sourceMappingURL=ContentAlert.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/ContentAlert.js.map b/keycloak-themes/keycloak.v2/account/resources/content/ContentAlert.js.map new file mode 100644 index 0000000..14e3f13 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/ContentAlert.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/content/ContentAlert.tsx"],"names":["React","Alert","AlertActionCloseButton","AlertGroup","AlertVariant","Msg","ContentAlert","Component","constructor","props","key","setState","alerts","state","filter","el","Date","getTime","variant","message","params","getUniqueId","push","localize","danger","setTimeout","hideAlert","instance","success","postAlert","warning","info","render","map"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AACA,SAASC,KAAT,EAAgBC,sBAAhB,EAAwCC,UAAxC,EAAoDC,YAApD;AACA,SAASC,GAAT;AAWA,OAAO,MAAMC,YAAN,SAA2BN,KAAK,CAACO,SAAjC,CAAiF;AAG5EC,EAAAA,WAAW,CAACC,KAAD,EAA2B;AAC1C,UAAMA,KAAN;;AAD0C,uCAqCzBC,GAAD,IAAiB;AACjC,WAAKC,QAAL,CAAc;AAAEC,QAAAA,MAAM,EAAE,CAAC,GAAG,KAAKC,KAAL,CAAWD,MAAX,CAAkBE,MAAlB,CAAyBC,EAAE,IAAIA,EAAE,CAACL,GAAH,KAAWA,GAA1C,CAAJ;AAAV,OAAd;AACH,KAvC6C;;AAAA,yCAyCxB,MAAO,IAAIM,IAAJ,GAAWC,OAAX,EAzCiB;;AAAA,uCA2C1B,CAACC,OAAD,EAAwBC,OAAxB,EAAyCC,MAAzC,KAA+D;AAC/E,YAAMR,MAAM,GAAG,KAAKC,KAAL,CAAWD,MAA1B;AACA,YAAMF,GAAG,GAAG,KAAKW,WAAL,EAAZ;AACAT,MAAAA,MAAM,CAACU,IAAP,CAAY;AACRZ,QAAAA,GADQ;AAERS,QAAAA,OAAO,EAAEd,GAAG,CAACkB,QAAJ,CAAaJ,OAAb,EAAsBC,MAAtB,CAFD;AAGRF,QAAAA;AAHQ,OAAZ;AAKA,WAAKP,QAAL,CAAc;AAAEC,QAAAA;AAAF,OAAd;;AAEA,UAAIM,OAAO,KAAKd,YAAY,CAACoB,MAA7B,EAAqC;AACjCC,QAAAA,UAAU,CAAC,MAAM,KAAKC,SAAL,CAAehB,GAAf,CAAP,EAA4B,IAA5B,CAAV;AACH;AACJ,KAxD6C;;AAG1C,SAAKG,KAAL,GAAa;AACTD,MAAAA,MAAM,EAAE;AADC,KAAb;AAGAN,IAAAA,YAAY,CAACqB,QAAb,GAAwB,IAAxB;AACH;AAED;AACJ;AACA;;;AACyB,SAAPC,OAAO,CAACT,OAAD,EAAkBC,MAAlB,EAA2C;AAC5Dd,IAAAA,YAAY,CAACqB,QAAb,CAAsBE,SAAtB,CAAgCzB,YAAY,CAACwB,OAA7C,EAAsDT,OAAtD,EAA+DC,MAA/D;AACH;AAED;AACJ;AACA;;;AACwB,SAANI,MAAM,CAACL,OAAD,EAAkBC,MAAlB,EAA2C;AAC3Dd,IAAAA,YAAY,CAACqB,QAAb,CAAsBE,SAAtB,CAAgCzB,YAAY,CAACoB,MAA7C,EAAqDL,OAArD,EAA8DC,MAA9D;AACH;AAED;AACJ;AACA;;;AACyB,SAAPU,OAAO,CAACX,OAAD,EAAkBC,MAAlB,EAA2C;AAC5Dd,IAAAA,YAAY,CAACqB,QAAb,CAAsBE,SAAtB,CAAgCzB,YAAY,CAAC0B,OAA7C,EAAsDX,OAAtD,EAA+DC,MAA/D;AACH;AAED;AACJ;AACA;;;AACsB,SAAJW,IAAI,CAACZ,OAAD,EAAkBC,MAAlB,EAA2C;AACzDd,IAAAA,YAAY,CAACqB,QAAb,CAAsBE,SAAtB,CAAgCzB,YAAY,CAAC2B,IAA7C,EAAmDZ,OAAnD,EAA4DC,MAA5D;AACH;;AAuBMY,EAAAA,MAAM,GAAoB;AAC7B,wBACI,oBAAC,UAAD;AAAY,MAAA,OAAO,MAAnB;AAAoB,mBAAU;AAA9B,OACK,KAAKnB,KAAL,CAAWD,MAAX,CAAkBqB,GAAlB,CAAsB,CAAC;AAAEvB,MAAAA,GAAF;AAAOQ,MAAAA,OAAP;AAAgBC,MAAAA;AAAhB,KAAD,kBACnB,oBAAC,KAAD;AACI,sBAAcA,OADlB;AAEI,MAAA,YAAY,MAFhB;AAGI,MAAA,OAAO,EAAED,OAHb;AAII,MAAA,KAAK,EAAEC,OAJX;AAKI,MAAA,WAAW,eACP,oBAAC,sBAAD;AACI,QAAA,KAAK,EAAEA,OADX;AAEI,QAAA,YAAY,EAAG,GAAED,OAAQ,QAF7B;AAGI,QAAA,OAAO,EAAE,MAAM,KAAKQ,SAAL,CAAehB,GAAf;AAHnB,QANR;AAYI,MAAA,GAAG,EAAEA;AAZT,MADH,CADL,CADJ;AAmBH;;AAjFmF;;gBAA3EJ,Y","sourcesContent":["/*\n * Copyright 2019 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\nimport { Alert, AlertActionCloseButton, AlertGroup, AlertVariant } from '@patternfly/react-core';\nimport { Msg } from '../widgets/Msg';\n\ninterface ContentAlertProps { }\n\ninterface ContentAlertState {\n alerts: {\n key: number;\n message: string;\n variant: AlertVariant;\n }[];\n}\nexport class ContentAlert extends React.Component {\n private static instance: ContentAlert;\n\n private constructor(props: ContentAlertProps) {\n super(props);\n\n this.state = {\n alerts: []\n };\n ContentAlert.instance = this;\n }\n\n /**\n * @param message A literal text message or localization key.\n */\n public static success(message: string, params?: string[]): void {\n ContentAlert.instance.postAlert(AlertVariant.success, message, params);\n }\n\n /**\n * @param message A literal text message or localization key.\n */\n public static danger(message: string, params?: string[]): void {\n ContentAlert.instance.postAlert(AlertVariant.danger, message, params);\n }\n\n /**\n * @param message A literal text message or localization key.\n */\n public static warning(message: string, params?: string[]): void {\n ContentAlert.instance.postAlert(AlertVariant.warning, message, params);\n }\n\n /**\n * @param message A literal text message or localization key.\n */\n public static info(message: string, params?: string[]): void {\n ContentAlert.instance.postAlert(AlertVariant.info, message, params);\n }\n\n private hideAlert = (key: number) => {\n this.setState({ alerts: [...this.state.alerts.filter(el => el.key !== key)] });\n }\n\n private getUniqueId = () => (new Date().getTime());\n\n private postAlert = (variant: AlertVariant, message: string, params?: string[]) => {\n const alerts = this.state.alerts;\n const key = this.getUniqueId();\n alerts.push({\n key,\n message: Msg.localize(message, params),\n variant\n });\n this.setState({ alerts });\n\n if (variant !== AlertVariant.danger) {\n setTimeout(() => this.hideAlert(key), 8000);\n }\n }\n\n public render(): React.ReactNode {\n return (\n \n {this.state.alerts.map(({ key, variant, message }) => (\n this.hideAlert(key)}\n />\n }\n key={key} />\n ))}\n \n );\n }\n}\n"],"file":"ContentAlert.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/ContentPage.js b/keycloak-themes/keycloak.v2/account/resources/content/ContentPage.js new file mode 100644 index 0000000..184bbe2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/ContentPage.js @@ -0,0 +1,63 @@ +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../common/keycloak/web_modules/react.js"; +import { Button, Text, Title, Tooltip, PageSection, TextContent, PageSectionVariants, SplitItem, Split } from "../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { SyncAltIcon } from "../../../common/keycloak/web_modules/@patternfly/react-icons.js"; +import { Msg } from "../widgets/Msg.js"; +import { ContentAlert } from "./ContentAlert.js"; + +/** + * @author Stan Silvert ssilvert@redhat.com (C) 2019 Red Hat Inc. + */ +export class ContentPage extends React.Component { + constructor(props) { + super(props); + } + + render() { + return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ContentAlert, null), /*#__PURE__*/React.createElement(PageSection, { + variant: PageSectionVariants.light, + className: "pf-u-pb-xs" + }, /*#__PURE__*/React.createElement(Split, null, /*#__PURE__*/React.createElement(SplitItem, { + isFilled: true + }, /*#__PURE__*/React.createElement(TextContent, null, /*#__PURE__*/React.createElement(Title, { + headingLevel: "h1", + size: "2xl", + className: "pf-u-mb-xl" + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: this.props.title + })), this.props.introMessage && /*#__PURE__*/React.createElement(Text, { + component: "p" + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: this.props.introMessage + })))), this.props.onRefresh && /*#__PURE__*/React.createElement(SplitItem, null, /*#__PURE__*/React.createElement(Tooltip, { + content: /*#__PURE__*/React.createElement(Msg, { + msgKey: "refreshPage" + }) + }, /*#__PURE__*/React.createElement(Button, { + "aria-label": Msg.localize('refreshPage'), + id: "refresh-page", + variant: "link", + onClick: this.props.onRefresh, + icon: /*#__PURE__*/React.createElement(SyncAltIcon, null) + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "refresh" + })))))), this.props.children); + } + +} +; +//# sourceMappingURL=ContentPage.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/ContentPage.js.map b/keycloak-themes/keycloak.v2/account/resources/content/ContentPage.js.map new file mode 100644 index 0000000..4b0078d --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/ContentPage.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/content/ContentPage.tsx"],"names":["React","Button","Text","Title","Tooltip","PageSection","TextContent","PageSectionVariants","SplitItem","Split","SyncAltIcon","Msg","ContentAlert","ContentPage","Component","constructor","props","render","light","title","introMessage","onRefresh","localize","children"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AACA,SAAQC,MAAR,EAAgCC,IAAhC,EAAsCC,KAAtC,EAA6CC,OAA7C,EAAwFC,WAAxF,EAAqGC,WAArG,EAAkHC,mBAAlH,EAAuIC,SAAvI,EAAkJC,KAAlJ;AACA,SAAkBC,WAAlB;AAEA,SAAQC,GAAR;AACA,SAAQC,YAAR;;AASA;AACA;AACA;AACA,OAAO,MAAMC,WAAN,SAA0Bb,KAAK,CAACc,SAAhC,CAA4D;AAExDC,EAAAA,WAAW,CAACC,KAAD,EAA0B;AACxC,UAAMA,KAAN;AACH;;AAEMC,EAAAA,MAAM,GAAoB;AAC7B,wBACI,oBAAC,KAAD,CAAO,QAAP,qBACA,oBAAC,YAAD,OADA,eAGA,oBAAC,WAAD;AAAa,MAAA,OAAO,EAAEV,mBAAmB,CAACW,KAA1C;AAAiD,MAAA,SAAS,EAAC;AAA3D,oBACE,oBAAC,KAAD,qBACE,oBAAC,SAAD;AAAW,MAAA,QAAQ;AAAnB,oBACE,oBAAC,WAAD,qBACE,oBAAC,KAAD;AAAO,MAAA,YAAY,EAAC,IAApB;AAAyB,MAAA,IAAI,EAAC,KAA9B;AAAoC,MAAA,SAAS,EAAC;AAA9C,oBACE,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAE,KAAKF,KAAL,CAAWG;AAAxB,MADF,CADF,EAIG,KAAKH,KAAL,CAAWI,YAAX,iBACC,oBAAC,IAAD;AAAM,MAAA,SAAS,EAAC;AAAhB,oBACE,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAE,KAAKJ,KAAL,CAAWI;AAAxB,MADF,CALJ,CADF,CADF,EAaG,KAAKJ,KAAL,CAAWK,SAAX,iBACC,oBAAC,SAAD,qBACE,oBAAC,OAAD;AAAS,MAAA,OAAO,eAAE,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ;AAAlB,oBACE,oBAAC,MAAD;AACE,oBAAYV,GAAG,CAACW,QAAJ,CAAa,aAAb,CADd;AAEE,MAAA,EAAE,EAAC,cAFL;AAGE,MAAA,OAAO,EAAC,MAHV;AAIE,MAAA,OAAO,EAAE,KAAKN,KAAL,CAAWK,SAJtB;AAKE,MAAA,IAAI,eAAE,oBAAC,WAAD;AALR,oBAOE,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MAPF,CADF,CADF,CAdJ,CADF,CAHA,EAkCC,KAAKL,KAAL,CAAWO,QAlCZ,CADJ;AAsCH;;AA7C8D;AA8ClE","sourcesContent":["/*\n * Copyright 2019 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\nimport {Button, Grid, GridItem, Text, Title, Tooltip, Card, CardBody, Stack, StackItem, PageSection, TextContent, PageSectionVariants, SplitItem, Split} from '@patternfly/react-core';\nimport {RedoIcon, SyncAltIcon} from '@patternfly/react-icons';\n\nimport {Msg} from '../widgets/Msg';\nimport {ContentAlert} from './ContentAlert';\n\ninterface ContentPageProps {\n title: string; // Literal title or key into message bundle\n introMessage?: string; // Literal message or key into message bundle\n onRefresh?: () => void;\n children: React.ReactNode;\n}\n\n/**\n * @author Stan Silvert ssilvert@redhat.com (C) 2019 Red Hat Inc.\n */\nexport class ContentPage extends React.Component {\n\n public constructor(props: ContentPageProps) {\n super(props);\n }\n\n public render(): React.ReactNode {\n return (\n \n \n\n \n \n \n \n \n <Msg msgKey={this.props.title} />\n \n {this.props.introMessage && (\n \n \n \n )}\n \n \n {this.props.onRefresh && (\n \n }>\n }\n >\n \n \n \n \n )}\n \n \n {this.props.children}\n \n );\n }\n};\n"],"file":"ContentPage.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/account-page/AccountPage.js b/keycloak-themes/keycloak.v2/account/resources/content/account-page/AccountPage.js new file mode 100644 index 0000000..d785f5a --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/account-page/AccountPage.js @@ -0,0 +1,276 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../../common/keycloak/web_modules/react.js"; +import { ActionGroup, Button, Form, FormGroup, TextInput, Grid, GridItem, ExpandableSection, ValidatedOptions, PageSection, PageSectionVariants, Text, TextVariants, TextContent } from "../../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { AccountServiceContext } from "../../account-service/AccountServiceContext.js"; +import { Msg } from "../../widgets/Msg.js"; +import { ContentPage } from "../ContentPage.js"; +import { ContentAlert } from "../ContentAlert.js"; +import { LocaleSelector } from "../../widgets/LocaleSelectors.js"; +import { KeycloakContext } from "../../keycloak-service/KeycloakContext.js"; +import { AIACommand } from "../../util/AIACommand.js"; + +/** + * @author Stan Silvert ssilvert@redhat.com (C) 2018 Red Hat Inc. + */ +export class AccountPage extends React.Component { + constructor(props, context) { + super(props); + + _defineProperty(this, "context", void 0); + + _defineProperty(this, "isRegistrationEmailAsUsername", features.isRegistrationEmailAsUsername); + + _defineProperty(this, "isEditUserNameAllowed", features.isEditUserNameAllowed); + + _defineProperty(this, "isDeleteAccountAllowed", features.deleteAccountAllowed); + + _defineProperty(this, "DEFAULT_STATE", { + errors: { + username: '', + firstName: '', + lastName: '', + email: '' + }, + formFields: { + username: '', + firstName: '', + lastName: '', + email: '', + attributes: {} + } + }); + + _defineProperty(this, "state", this.DEFAULT_STATE); + + _defineProperty(this, "handleCancel", () => { + this.fetchPersonalInfo(); + }); + + _defineProperty(this, "handleChange", (value, event) => { + const target = event.currentTarget; + const name = target.name; + this.setState({ + errors: { ...this.state.errors, + [name]: target.validationMessage + }, + formFields: { ...this.state.formFields, + [name]: value + } + }); + }); + + _defineProperty(this, "handleSubmit", event => { + event.preventDefault(); + const form = event.target; + const isValid = form.checkValidity(); + + if (isValid) { + const reqData = { ...this.state.formFields + }; + this.context.doPost("/", reqData).then(() => { + ContentAlert.success('accountUpdatedMessage'); + + if (locale !== this.state.formFields.attributes.locale[0]) { + window.location.reload(); + } + }); + } else { + const formData = new FormData(form); + const validationMessages = Array.from(formData.keys()).reduce((acc, key) => { + acc[key] = form.elements[key].validationMessage; + return acc; + }, {}); + this.setState({ + errors: { ...validationMessages + }, + formFields: this.state.formFields + }); + } + }); + + _defineProperty(this, "handleDelete", keycloak => { + new AIACommand(keycloak, "delete_account").execute(); + }); + + _defineProperty(this, "UsernameInput", () => /*#__PURE__*/React.createElement(TextInput, { + isRequired: true, + type: "text", + id: "user-name", + name: "username", + maxLength: 254, + value: this.state.formFields.username, + onChange: this.handleChange, + validated: this.state.errors.username !== '' ? ValidatedOptions.error : ValidatedOptions.default + })); + + _defineProperty(this, "RestrictedUsernameInput", () => /*#__PURE__*/React.createElement(TextInput, { + isReadOnly: true, + type: "text", + id: "user-name", + name: "username", + value: this.state.formFields.username + })); + + this.context = context; + this.fetchPersonalInfo(); + } + + fetchPersonalInfo() { + this.context.doGet("/").then(response => { + this.setState(this.DEFAULT_STATE); + const formFields = response.data; + + if (!formFields.attributes) { + formFields.attributes = { + locale: [locale] + }; + } else if (!formFields.attributes.locale) { + formFields.attributes.locale = [locale]; + } + + this.setState({ ...{ + formFields: formFields + } + }); + }); + } + + render() { + const fields = this.state.formFields; + return /*#__PURE__*/React.createElement(ContentPage, { + title: "personalInfoHtmlTitle", + introMessage: "personalSubMessage" + }, /*#__PURE__*/React.createElement(PageSection, { + isFilled: true, + variant: PageSectionVariants.light + }, /*#__PURE__*/React.createElement(TextContent, { + className: "pf-u-mb-lg" + }, /*#__PURE__*/React.createElement(Text, { + component: TextVariants.small + }, Msg.localize('allFieldsRequired'))), /*#__PURE__*/React.createElement(Form, { + onSubmit: event => this.handleSubmit(event), + className: "personal-info-form" + }, !this.isRegistrationEmailAsUsername && /*#__PURE__*/React.createElement(FormGroup, { + label: Msg.localize("username"), + fieldId: "user-name", + helperTextInvalid: this.state.errors.username, + validated: this.state.errors.username !== "" ? ValidatedOptions.error : ValidatedOptions.default + }, this.isEditUserNameAllowed && /*#__PURE__*/React.createElement(this.UsernameInput, null), !this.isEditUserNameAllowed && /*#__PURE__*/React.createElement(this.RestrictedUsernameInput, null)), /*#__PURE__*/React.createElement(FormGroup, { + label: Msg.localize("email"), + fieldId: "email-address", + helperTextInvalid: this.state.errors.email, + validated: this.state.errors.email !== "" ? ValidatedOptions.error : ValidatedOptions.default + }, /*#__PURE__*/React.createElement(TextInput, { + isRequired: true, + type: "email", + id: "email-address", + name: "email", + maxLength: 254, + value: fields.email, + onChange: this.handleChange, + validated: this.state.errors.email !== "" ? ValidatedOptions.error : ValidatedOptions.default + })), /*#__PURE__*/React.createElement(FormGroup, { + label: Msg.localize("firstName"), + fieldId: "first-name", + helperTextInvalid: this.state.errors.firstName, + validated: this.state.errors.firstName !== "" ? ValidatedOptions.error : ValidatedOptions.default + }, /*#__PURE__*/React.createElement(TextInput, { + isRequired: true, + type: "text", + id: "first-name", + name: "firstName", + maxLength: 254, + value: fields.firstName, + onChange: this.handleChange, + validated: this.state.errors.firstName !== "" ? ValidatedOptions.error : ValidatedOptions.default + })), /*#__PURE__*/React.createElement(FormGroup, { + label: Msg.localize("lastName"), + fieldId: "last-name", + helperTextInvalid: this.state.errors.lastName, + validated: this.state.errors.lastName !== "" ? ValidatedOptions.error : ValidatedOptions.default + }, /*#__PURE__*/React.createElement(TextInput, { + isRequired: true, + type: "text", + id: "last-name", + name: "lastName", + maxLength: 254, + value: fields.lastName, + onChange: this.handleChange, + validated: this.state.errors.lastName !== "" ? ValidatedOptions.error : ValidatedOptions.default + })), features.isInternationalizationEnabled && /*#__PURE__*/React.createElement(FormGroup, { + label: Msg.localize("selectLocale"), + isRequired: true, + fieldId: "locale" + }, /*#__PURE__*/React.createElement(LocaleSelector, { + id: "locale-selector", + value: fields.attributes.locale || "", + onChange: value => this.setState({ + errors: this.state.errors, + formFields: { ...this.state.formFields, + attributes: { ...this.state.formFields.attributes, + locale: [value] + } + } + }) + })), /*#__PURE__*/React.createElement(ActionGroup, null, /*#__PURE__*/React.createElement(Button, { + type: "submit", + id: "save-btn", + variant: "primary", + isDisabled: Object.values(this.state.errors).filter(e => e !== "").length !== 0 + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "doSave" + })), /*#__PURE__*/React.createElement(Button, { + id: "cancel-btn", + variant: "link", + onClick: this.handleCancel + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "doCancel" + })))), this.isDeleteAccountAllowed && /*#__PURE__*/React.createElement("div", { + id: "delete-account", + style: { + marginTop: "30px" + } + }, /*#__PURE__*/React.createElement(ExpandableSection, { + toggleText: "Delete Account" + }, /*#__PURE__*/React.createElement(Grid, { + hasGutter: true + }, /*#__PURE__*/React.createElement(GridItem, { + span: 6 + }, /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement(Msg, { + msgKey: "deleteAccountWarning" + }))), /*#__PURE__*/React.createElement(GridItem, { + span: 4 + }, /*#__PURE__*/React.createElement(KeycloakContext.Consumer, null, keycloak => /*#__PURE__*/React.createElement(Button, { + id: "delete-account-btn", + variant: "danger", + onClick: () => this.handleDelete(keycloak), + className: "delete-button" + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "doDelete" + })))), /*#__PURE__*/React.createElement(GridItem, { + span: 2 + })))))); + } + +} + +_defineProperty(AccountPage, "contextType", AccountServiceContext); + +; +//# sourceMappingURL=AccountPage.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/account-page/AccountPage.js.map b/keycloak-themes/keycloak.v2/account/resources/content/account-page/AccountPage.js.map new file mode 100644 index 0000000..6155537 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/account-page/AccountPage.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/account-page/AccountPage.tsx"],"names":["React","ActionGroup","Button","Form","FormGroup","TextInput","Grid","GridItem","ExpandableSection","ValidatedOptions","PageSection","PageSectionVariants","Text","TextVariants","TextContent","AccountServiceContext","Msg","ContentPage","ContentAlert","LocaleSelector","KeycloakContext","AIACommand","AccountPage","Component","constructor","props","context","features","isRegistrationEmailAsUsername","isEditUserNameAllowed","deleteAccountAllowed","errors","username","firstName","lastName","email","formFields","attributes","DEFAULT_STATE","fetchPersonalInfo","value","event","target","currentTarget","name","setState","state","validationMessage","preventDefault","form","isValid","checkValidity","reqData","doPost","then","success","locale","window","location","reload","formData","FormData","validationMessages","Array","from","keys","reduce","acc","key","elements","keycloak","execute","handleChange","error","default","doGet","response","data","render","fields","light","small","localize","handleSubmit","isInternationalizationEnabled","Object","values","filter","e","length","handleCancel","isDeleteAccountAllowed","marginTop","handleDelete"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,KAAKA,KAAZ;AACA,SAASC,WAAT,EACIC,MADJ,EAEIC,IAFJ,EAGIC,SAHJ,EAIIC,SAJJ,EAKIC,IALJ,EAMIC,QANJ,EAOIC,iBAPJ,EAQIC,gBARJ,EASIC,WATJ,EAUIC,mBAVJ,EAWIC,IAXJ,EAYIC,YAZJ,EAaIC,WAbJ;AAiBA,SAASC,qBAAT;AAEA,SAASC,GAAT;AACA,SAASC,WAAT;AACA,SAASC,YAAT;AACA,SAASC,cAAT;AACA,SAASC,eAAT;AAEA,SAASC,UAAT;;AAqBA;AACA;AACA;AACA,OAAO,MAAMC,WAAN,SAA0BtB,KAAK,CAACuB,SAAhC,CAA8E;AAwB1EC,EAAAA,WAAW,CAACC,KAAD,EAA0BC,OAA1B,EAAoF;AAClG,UAAMD,KAAN;;AADkG;;AAAA,2DArBrDE,QAAQ,CAACC,6BAqB4C;;AAAA,mDApB7DD,QAAQ,CAACE,qBAoBoD;;AAAA,oDAnB5DF,QAAQ,CAACG,oBAmBmD;;AAAA,2CAlBnD;AAC/CC,MAAAA,MAAM,EAAE;AACJC,QAAAA,QAAQ,EAAE,EADN;AAEJC,QAAAA,SAAS,EAAE,EAFP;AAGJC,QAAAA,QAAQ,EAAE,EAHN;AAIJC,QAAAA,KAAK,EAAE;AAJH,OADuC;AAO/CC,MAAAA,UAAU,EAAE;AACRJ,QAAAA,QAAQ,EAAE,EADF;AAERC,QAAAA,SAAS,EAAE,EAFH;AAGRC,QAAAA,QAAQ,EAAE,EAHF;AAIRC,QAAAA,KAAK,EAAE,EAJC;AAKRE,QAAAA,UAAU,EAAE;AALJ;AAPmC,KAkBmD;;AAAA,mCAFrE,KAAKC,aAEgE;;AAAA,0CAuB/E,MAAY;AAC/B,WAAKC,iBAAL;AACH,KAzBqG;;AAAA,0CA2B/E,CAACC,KAAD,EAAgBC,KAAhB,KAA6D;AAChF,YAAMC,MAAM,GAAGD,KAAK,CAACE,aAArB;AACA,YAAMC,IAAI,GAAGF,MAAM,CAACE,IAApB;AAEA,WAAKC,QAAL,CAAc;AACVd,QAAAA,MAAM,EAAE,EAAE,GAAG,KAAKe,KAAL,CAAWf,MAAhB;AAAwB,WAACa,IAAD,GAAQF,MAAM,CAACK;AAAvC,SADE;AAEVX,QAAAA,UAAU,EAAE,EAAE,GAAG,KAAKU,KAAL,CAAWV,UAAhB;AAA4B,WAACQ,IAAD,GAAQJ;AAApC;AAFF,OAAd;AAIH,KAnCqG;;AAAA,0CAqC9EC,KAAD,IAAmD;AACtEA,MAAAA,KAAK,CAACO,cAAN;AACA,YAAMC,IAAI,GAAGR,KAAK,CAACC,MAAnB;AACA,YAAMQ,OAAO,GAAGD,IAAI,CAACE,aAAL,EAAhB;;AACA,UAAID,OAAJ,EAAa;AACT,cAAME,OAAmB,GAAG,EAAE,GAAG,KAAKN,KAAL,CAAWV;AAAhB,SAA5B;AACA,aAAKV,OAAL,CAAc2B,MAAd,CAA2B,GAA3B,EAAgCD,OAAhC,EACKE,IADL,CACU,MAAM;AACRpC,UAAAA,YAAY,CAACqC,OAAb,CAAqB,uBAArB;;AACA,cAAIC,MAAM,KAAK,KAAKV,KAAL,CAAWV,UAAX,CAAsBC,UAAtB,CAAkCmB,MAAlC,CAA0C,CAA1C,CAAf,EAA6D;AACzDC,YAAAA,MAAM,CAACC,QAAP,CAAgBC,MAAhB;AACH;AACJ,SANL;AAOH,OATD,MASO;AACH,cAAMC,QAAQ,GAAG,IAAIC,QAAJ,CAAaZ,IAAb,CAAjB;AACA,cAAMa,kBAAkB,GAAGC,KAAK,CAACC,IAAN,CAAWJ,QAAQ,CAACK,IAAT,EAAX,EAA4BC,MAA5B,CAAmC,CAACC,GAAD,EAAMC,GAAN,KAAc;AACxED,UAAAA,GAAG,CAACC,GAAD,CAAH,GAAWnB,IAAI,CAACoB,QAAL,CAAcD,GAAd,EAAmBrB,iBAA9B;AACA,iBAAOoB,GAAP;AACH,SAH0B,EAGxB,EAHwB,CAA3B;AAIA,aAAKtB,QAAL,CAAc;AACVd,UAAAA,MAAM,EAAE,EAAE,GAAG+B;AAAL,WADE;AAEV1B,UAAAA,UAAU,EAAE,KAAKU,KAAL,CAAWV;AAFb,SAAd;AAIH;AAEJ,KA9DqG;;AAAA,0CAgE9EkC,QAAD,IAAqC;AACxD,UAAIjD,UAAJ,CAAeiD,QAAf,EAAyB,gBAAzB,EAA2CC,OAA3C;AACH,KAlEqG;;AAAA,2CAgQ9E,mBACpB,oBAAC,SAAD;AACI,MAAA,UAAU,MADd;AAEI,MAAA,IAAI,EAAC,MAFT;AAGI,MAAA,EAAE,EAAC,WAHP;AAII,MAAA,IAAI,EAAC,UAJT;AAKI,MAAA,SAAS,EAAE,GALf;AAMI,MAAA,KAAK,EAAE,KAAKzB,KAAL,CAAWV,UAAX,CAAsBJ,QANjC;AAOI,MAAA,QAAQ,EAAE,KAAKwC,YAPnB;AAQI,MAAA,SAAS,EAAE,KAAK1B,KAAL,CAAWf,MAAX,CAAkBC,QAAlB,KAA+B,EAA/B,GAAoCvB,gBAAgB,CAACgE,KAArD,GAA6DhE,gBAAgB,CAACiE;AAR7F,MAjQkG;;AAAA,qDA8QpE,mBAC9B,oBAAC,SAAD;AACI,MAAA,UAAU,MADd;AAEI,MAAA,IAAI,EAAC,MAFT;AAGI,MAAA,EAAE,EAAC,WAHP;AAII,MAAA,IAAI,EAAC,UAJT;AAKI,MAAA,KAAK,EAAE,KAAK5B,KAAL,CAAWV,UAAX,CAAsBJ;AALjC,MA/QkG;;AAElG,SAAKN,OAAL,GAAeA,OAAf;AAEA,SAAKa,iBAAL;AACH;;AAEOA,EAAAA,iBAAiB,GAAS;AAC9B,SAAKb,OAAL,CAAciD,KAAd,CAAgC,GAAhC,EACKrB,IADL,CACWsB,QAAD,IAAwC;AAC1C,WAAK/B,QAAL,CAAc,KAAKP,aAAnB;AACA,YAAMF,UAAU,GAAGwC,QAAQ,CAACC,IAA5B;;AACA,UAAI,CAACzC,UAAU,CAAEC,UAAjB,EAA6B;AACzBD,QAAAA,UAAU,CAAEC,UAAZ,GAAyB;AAAEmB,UAAAA,MAAM,EAAE,CAACA,MAAD;AAAV,SAAzB;AACH,OAFD,MAGK,IAAI,CAACpB,UAAU,CAAEC,UAAZ,CAAuBmB,MAA5B,EAAoC;AACrCpB,QAAAA,UAAU,CAAEC,UAAZ,CAAuBmB,MAAvB,GAAgC,CAACA,MAAD,CAAhC;AACH;;AAED,WAAKX,QAAL,CAAc,EAAC,GAAG;AAAET,UAAAA,UAAU,EAAEA;AAAd;AAAJ,OAAd;AACH,KAZL;AAaH;;AA+CM0C,EAAAA,MAAM,GAAoB;AAC7B,UAAMC,MAAkB,GAAG,KAAKjC,KAAL,CAAWV,UAAtC;AACA,wBACI,oBAAC,WAAD;AACI,MAAA,KAAK,EAAC,uBADV;AAEI,MAAA,YAAY,EAAC;AAFjB,oBAII,oBAAC,WAAD;AAAa,MAAA,QAAQ,MAArB;AAAsB,MAAA,OAAO,EAAEzB,mBAAmB,CAACqE;AAAnD,oBACI,oBAAC,WAAD;AAAa,MAAA,SAAS,EAAC;AAAvB,oBACI,oBAAC,IAAD;AAAM,MAAA,SAAS,EAAEnE,YAAY,CAACoE;AAA9B,OACGjE,GAAG,CAACkE,QAAJ,CAAa,mBAAb,CADH,CADJ,CADJ,eAMI,oBAAC,IAAD;AACI,MAAA,QAAQ,EAAGzC,KAAD,IAAW,KAAK0C,YAAL,CAAkB1C,KAAlB,CADzB;AAEI,MAAA,SAAS,EAAC;AAFd,OAIK,CAAC,KAAKb,6BAAN,iBACG,oBAAC,SAAD;AACI,MAAA,KAAK,EAAEZ,GAAG,CAACkE,QAAJ,CAAa,UAAb,CADX;AAEI,MAAA,OAAO,EAAC,WAFZ;AAGI,MAAA,iBAAiB,EAAE,KAAKpC,KAAL,CAAWf,MAAX,CAAkBC,QAHzC;AAII,MAAA,SAAS,EACL,KAAKc,KAAL,CAAWf,MAAX,CAAkBC,QAAlB,KAA+B,EAA/B,GACMvB,gBAAgB,CAACgE,KADvB,GAEMhE,gBAAgB,CAACiE;AAP/B,OAUK,KAAK7C,qBAAL,iBAA8B,yBAAM,aAAN,OAVnC,EAWK,CAAC,KAAKA,qBAAN,iBACG,yBAAM,uBAAN,OAZR,CALR,eAqBI,oBAAC,SAAD;AACI,MAAA,KAAK,EAAEb,GAAG,CAACkE,QAAJ,CAAa,OAAb,CADX;AAEI,MAAA,OAAO,EAAC,eAFZ;AAGI,MAAA,iBAAiB,EAAE,KAAKpC,KAAL,CAAWf,MAAX,CAAkBI,KAHzC;AAII,MAAA,SAAS,EACL,KAAKW,KAAL,CAAWf,MAAX,CAAkBI,KAAlB,KAA4B,EAA5B,GACM1B,gBAAgB,CAACgE,KADvB,GAEMhE,gBAAgB,CAACiE;AAP/B,oBAUI,oBAAC,SAAD;AACI,MAAA,UAAU,MADd;AAEI,MAAA,IAAI,EAAC,OAFT;AAGI,MAAA,EAAE,EAAC,eAHP;AAII,MAAA,IAAI,EAAC,OAJT;AAKI,MAAA,SAAS,EAAE,GALf;AAMI,MAAA,KAAK,EAAEK,MAAM,CAAC5C,KANlB;AAOI,MAAA,QAAQ,EAAE,KAAKqC,YAPnB;AAQI,MAAA,SAAS,EACL,KAAK1B,KAAL,CAAWf,MAAX,CAAkBI,KAAlB,KAA4B,EAA5B,GACM1B,gBAAgB,CAACgE,KADvB,GAEMhE,gBAAgB,CAACiE;AAX/B,MAVJ,CArBJ,eA8CI,oBAAC,SAAD;AACI,MAAA,KAAK,EAAE1D,GAAG,CAACkE,QAAJ,CAAa,WAAb,CADX;AAEI,MAAA,OAAO,EAAC,YAFZ;AAGI,MAAA,iBAAiB,EAAE,KAAKpC,KAAL,CAAWf,MAAX,CAAkBE,SAHzC;AAII,MAAA,SAAS,EACL,KAAKa,KAAL,CAAWf,MAAX,CAAkBE,SAAlB,KAAgC,EAAhC,GACMxB,gBAAgB,CAACgE,KADvB,GAEMhE,gBAAgB,CAACiE;AAP/B,oBAUI,oBAAC,SAAD;AACI,MAAA,UAAU,MADd;AAEI,MAAA,IAAI,EAAC,MAFT;AAGI,MAAA,EAAE,EAAC,YAHP;AAII,MAAA,IAAI,EAAC,WAJT;AAKI,MAAA,SAAS,EAAE,GALf;AAMI,MAAA,KAAK,EAAEK,MAAM,CAAC9C,SANlB;AAOI,MAAA,QAAQ,EAAE,KAAKuC,YAPnB;AAQI,MAAA,SAAS,EACL,KAAK1B,KAAL,CAAWf,MAAX,CAAkBE,SAAlB,KAAgC,EAAhC,GACMxB,gBAAgB,CAACgE,KADvB,GAEMhE,gBAAgB,CAACiE;AAX/B,MAVJ,CA9CJ,eAuEI,oBAAC,SAAD;AACI,MAAA,KAAK,EAAE1D,GAAG,CAACkE,QAAJ,CAAa,UAAb,CADX;AAEI,MAAA,OAAO,EAAC,WAFZ;AAGI,MAAA,iBAAiB,EAAE,KAAKpC,KAAL,CAAWf,MAAX,CAAkBG,QAHzC;AAII,MAAA,SAAS,EACL,KAAKY,KAAL,CAAWf,MAAX,CAAkBG,QAAlB,KAA+B,EAA/B,GACMzB,gBAAgB,CAACgE,KADvB,GAEMhE,gBAAgB,CAACiE;AAP/B,oBAUI,oBAAC,SAAD;AACI,MAAA,UAAU,MADd;AAEI,MAAA,IAAI,EAAC,MAFT;AAGI,MAAA,EAAE,EAAC,WAHP;AAII,MAAA,IAAI,EAAC,UAJT;AAKI,MAAA,SAAS,EAAE,GALf;AAMI,MAAA,KAAK,EAAEK,MAAM,CAAC7C,QANlB;AAOI,MAAA,QAAQ,EAAE,KAAKsC,YAPnB;AAQI,MAAA,SAAS,EACL,KAAK1B,KAAL,CAAWf,MAAX,CAAkBG,QAAlB,KAA+B,EAA/B,GACMzB,gBAAgB,CAACgE,KADvB,GAEMhE,gBAAgB,CAACiE;AAX/B,MAVJ,CAvEJ,EAgGK/C,QAAQ,CAACyD,6BAAT,iBACG,oBAAC,SAAD;AACI,MAAA,KAAK,EAAEpE,GAAG,CAACkE,QAAJ,CAAa,cAAb,CADX;AAEI,MAAA,UAAU,MAFd;AAGI,MAAA,OAAO,EAAC;AAHZ,oBAKI,oBAAC,cAAD;AACI,MAAA,EAAE,EAAC,iBADP;AAEI,MAAA,KAAK,EAAEH,MAAM,CAAC1C,UAAP,CAAmBmB,MAAnB,IAA6B,EAFxC;AAGI,MAAA,QAAQ,EAAGhB,KAAD,IACN,KAAKK,QAAL,CAAc;AACVd,QAAAA,MAAM,EAAE,KAAKe,KAAL,CAAWf,MADT;AAEVK,QAAAA,UAAU,EAAE,EACR,GAAG,KAAKU,KAAL,CAAWV,UADN;AAERC,UAAAA,UAAU,EAAE,EACR,GAAG,KAAKS,KAAL,CAAWV,UAAX,CAAsBC,UADjB;AAERmB,YAAAA,MAAM,EAAE,CAAChB,KAAD;AAFA;AAFJ;AAFF,OAAd;AAJR,MALJ,CAjGR,eAwHI,oBAAC,WAAD,qBACI,oBAAC,MAAD;AACI,MAAA,IAAI,EAAC,QADT;AAEI,MAAA,EAAE,EAAC,UAFP;AAGI,MAAA,OAAO,EAAC,SAHZ;AAII,MAAA,UAAU,EACN6C,MAAM,CAACC,MAAP,CAAc,KAAKxC,KAAL,CAAWf,MAAzB,EAAiCwD,MAAjC,CAAyCC,CAAD,IAAOA,CAAC,KAAK,EAArD,EACCC,MADD,KACY;AANpB,oBASI,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MATJ,CADJ,eAYI,oBAAC,MAAD;AACI,MAAA,EAAE,EAAC,YADP;AAEI,MAAA,OAAO,EAAC,MAFZ;AAGI,MAAA,OAAO,EAAE,KAAKC;AAHlB,oBAKI,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MALJ,CAZJ,CAxHJ,CANJ,EAoJH,KAAKC,sBAAL,iBACG;AAAK,MAAA,EAAE,EAAC,gBAAR;AAAyB,MAAA,KAAK,EAAE;AAAEC,QAAAA,SAAS,EAAE;AAAb;AAAhC,oBACI,oBAAC,iBAAD;AAAmB,MAAA,UAAU,EAAC;AAA9B,oBACI,oBAAC,IAAD;AAAM,MAAA,SAAS;AAAf,oBACI,oBAAC,QAAD;AAAU,MAAA,IAAI,EAAE;AAAhB,oBACI,4CACI,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MADJ,CADJ,CADJ,eAMI,oBAAC,QAAD;AAAU,MAAA,IAAI,EAAE;AAAhB,oBACI,oBAAC,eAAD,CAAiB,QAAjB,QACMtB,QAAD,iBACG,oBAAC,MAAD;AACI,MAAA,EAAE,EAAC,oBADP;AAEI,MAAA,OAAO,EAAC,QAFZ;AAGI,MAAA,OAAO,EAAE,MAAM,KAAKuB,YAAL,CAAkBvB,QAAlB,CAHnB;AAII,MAAA,SAAS,EAAC;AAJd,oBAMI,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MANJ,CAFR,CADJ,CANJ,eAoBI,oBAAC,QAAD;AAAU,MAAA,IAAI,EAAE;AAAhB,MApBJ,CADJ,CADJ,CArJA,CAJJ,CADJ;AAwLH;;AAtRgF;;gBAAxEhD,W,iBACYP,qB;;AA+SxB","sourcesContent":["/*\n * Copyright 2018 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport * as React from 'react';\nimport { ActionGroup, \n Button, \n Form, \n FormGroup, \n TextInput, \n Grid, \n GridItem, \n ExpandableSection, \n ValidatedOptions,\n PageSection,\n PageSectionVariants,\n Text,\n TextVariants,\n TextContent\n} from '@patternfly/react-core';\n\nimport { HttpResponse } from '../../account-service/account.service';\nimport { AccountServiceContext } from '../../account-service/AccountServiceContext';\nimport { Features } from '../../widgets/features';\nimport { Msg } from '../../widgets/Msg';\nimport { ContentPage } from '../ContentPage';\nimport { ContentAlert } from '../ContentAlert';\nimport { LocaleSelector } from '../../widgets/LocaleSelectors';\nimport { KeycloakContext } from '../../keycloak-service/KeycloakContext';\nimport { KeycloakService } from '../../keycloak-service/keycloak.service';\nimport { AIACommand } from '../../util/AIACommand';\n\ndeclare const features: Features;\ndeclare const locale: string;\n\ninterface AccountPageProps {\n}\n\ninterface FormFields {\n readonly username?: string;\n readonly firstName?: string;\n readonly lastName?: string;\n readonly email?: string;\n attributes?: { locale?: [string] };\n}\n\ninterface AccountPageState {\n readonly errors: FormFields;\n readonly formFields: FormFields;\n}\n\n/**\n * @author Stan Silvert ssilvert@redhat.com (C) 2018 Red Hat Inc.\n */\nexport class AccountPage extends React.Component {\n static contextType = AccountServiceContext;\n context: React.ContextType;\n private isRegistrationEmailAsUsername: boolean = features.isRegistrationEmailAsUsername;\n private isEditUserNameAllowed: boolean = features.isEditUserNameAllowed;\n private isDeleteAccountAllowed: boolean = features.deleteAccountAllowed;\n private readonly DEFAULT_STATE: AccountPageState = {\n errors: {\n username: '',\n firstName: '',\n lastName: '',\n email: ''\n },\n formFields: {\n username: '',\n firstName: '',\n lastName: '',\n email: '',\n attributes: {}\n }\n };\n\n public state: AccountPageState = this.DEFAULT_STATE;\n\n public constructor(props: AccountPageProps, context: React.ContextType) {\n super(props);\n this.context = context;\n\n this.fetchPersonalInfo();\n }\n\n private fetchPersonalInfo(): void {\n this.context!.doGet(\"/\")\n .then((response: HttpResponse) => {\n this.setState(this.DEFAULT_STATE);\n const formFields = response.data;\n if (!formFields!.attributes) {\n formFields!.attributes = { locale: [locale] };\n }\n else if (!formFields!.attributes.locale) {\n formFields!.attributes.locale = [locale];\n }\n\n this.setState({...{ formFields: formFields as FormFields }});\n });\n }\n\n private handleCancel = (): void => {\n this.fetchPersonalInfo();\n }\n\n private handleChange = (value: string, event: React.FormEvent) => {\n const target = event.currentTarget;\n const name = target.name;\n\n this.setState({\n errors: { ...this.state.errors, [name]: target.validationMessage },\n formFields: { ...this.state.formFields, [name]: value }\n });\n }\n\n private handleSubmit = (event: React.FormEvent): void => {\n event.preventDefault();\n const form = event.target as HTMLFormElement;\n const isValid = form.checkValidity();\n if (isValid) {\n const reqData: FormFields = { ...this.state.formFields };\n this.context!.doPost(\"/\", reqData)\n .then(() => {\n ContentAlert.success('accountUpdatedMessage');\n if (locale !== this.state.formFields.attributes!.locale![0]) {\n window.location.reload();\n }\n });\n } else {\n const formData = new FormData(form);\n const validationMessages = Array.from(formData.keys()).reduce((acc, key) => {\n acc[key] = form.elements[key].validationMessage\n return acc\n }, {});\n this.setState({\n errors: { ...validationMessages },\n formFields: this.state.formFields\n });\n }\n\n }\n\n private handleDelete = (keycloak: KeycloakService): void => {\n new AIACommand(keycloak, \"delete_account\").execute();\n }\n\n public render(): React.ReactNode {\n const fields: FormFields = this.state.formFields;\n return (\n \n \n \n \n {Msg.localize('allFieldsRequired')}\n \n \n this.handleSubmit(event)}\n className=\"personal-info-form\"\n >\n {!this.isRegistrationEmailAsUsername && (\n \n {this.isEditUserNameAllowed && }\n {!this.isEditUserNameAllowed && (\n \n )}\n \n )}\n \n \n \n \n \n \n \n \n \n {features.isInternationalizationEnabled && (\n \n \n this.setState({\n errors: this.state.errors,\n formFields: {\n ...this.state.formFields,\n attributes: {\n ...this.state.formFields.attributes,\n locale: [value],\n },\n },\n })\n }\n />\n \n )}\n \n e !== \"\")\n .length !== 0\n }\n >\n \n \n \n \n \n \n \n\n {this.isDeleteAccountAllowed && (\n
    \n \n \n \n

    \n \n

    \n
    \n \n \n {(keycloak: KeycloakService) => (\n this.handleDelete(keycloak)}\n className=\"delete-button\"\n >\n \n \n )}\n \n \n \n
    \n
    \n
    \n )}\n
    \n \n );\n }\n\n private UsernameInput = () => (\n \n \n );\n\n private RestrictedUsernameInput = () => (\n \n \n );\n};\n"],"file":"AccountPage.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/aia-page/AppInitiatedActionPage.js b/keycloak-themes/keycloak.v2/account/resources/content/aia-page/AppInitiatedActionPage.js new file mode 100644 index 0000000..6c96f53 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/aia-page/AppInitiatedActionPage.js @@ -0,0 +1,70 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../../common/keycloak/web_modules/react.js"; +import { withRouter } from "../../../../common/keycloak/web_modules/react-router-dom.js"; +import { AIACommand } from "../../util/AIACommand.js"; +import { Msg } from "../../widgets/Msg.js"; +import { Title, Button, EmptyState, EmptyStateVariant, EmptyStateIcon, EmptyStateBody, TitleSizes } from "../../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { PassportIcon } from "../../../../common/keycloak/web_modules/@patternfly/react-icons.js"; +import { KeycloakContext } from "../../keycloak-service/KeycloakContext.js"; // Note: This class demonstrates two features of the ContentPages framework: +// 1) The PageDef is available as a React property. +// 2) You can add additional custom properties to the PageDef. In this case, +// we add a value called kcAction in content.js and access it by extending the +// PageDef interface. + +/** + * @author Stan Silvert + */ +class ApplicationInitiatedActionPage extends React.Component { + constructor(props) { + super(props); + + _defineProperty(this, "handleClick", keycloak => { + new AIACommand(keycloak, this.props.pageDef.kcAction).execute(); + }); + } + + render() { + return /*#__PURE__*/React.createElement(EmptyState, { + variant: EmptyStateVariant.full + }, /*#__PURE__*/React.createElement(EmptyStateIcon, { + icon: PassportIcon + }), /*#__PURE__*/React.createElement(Title, { + headingLevel: "h5", + size: TitleSizes.lg + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: this.props.pageDef.label, + params: this.props.pageDef.labelParams + })), /*#__PURE__*/React.createElement(EmptyStateBody, null, /*#__PURE__*/React.createElement(Msg, { + msgKey: "actionRequiresIDP" + })), /*#__PURE__*/React.createElement(KeycloakContext.Consumer, null, keycloak => /*#__PURE__*/React.createElement(Button, { + variant: "primary", + onClick: () => this.handleClick(keycloak), + target: "_blank" + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "continue" + })))); + } + +} + +; // Note that the class name is not exported above. To get access to the router, +// we use withRouter() and export a different name. + +export const AppInitiatedActionPage = withRouter(ApplicationInitiatedActionPage); +//# sourceMappingURL=AppInitiatedActionPage.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/aia-page/AppInitiatedActionPage.js.map b/keycloak-themes/keycloak.v2/account/resources/content/aia-page/AppInitiatedActionPage.js.map new file mode 100644 index 0000000..a8d4712 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/aia-page/AppInitiatedActionPage.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/aia-page/AppInitiatedActionPage.tsx"],"names":["React","withRouter","AIACommand","Msg","Title","Button","EmptyState","EmptyStateVariant","EmptyStateIcon","EmptyStateBody","TitleSizes","PassportIcon","KeycloakContext","ApplicationInitiatedActionPage","Component","constructor","props","keycloak","pageDef","kcAction","execute","render","full","lg","label","labelParams","handleClick","AppInitiatedActionPage"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AACA,SAAQC,UAAR;AAEA,SAAQC,UAAR;AAEA,SAAQC,GAAR;AAEA,SACEC,KADF,EAEEC,MAFF,EAGEC,UAHF,EAIEC,iBAJF,EAKEC,cALF,EAMEC,cANF,EAOEC,UAPF;AASA,SAASC,YAAT;AAEA,SAASC,eAAT,oD,CAEA;AACA;AACA;AACA;AACA;;AAYA;AACA;AACA;AACA,MAAMC,8BAAN,SAA6Cb,KAAK,CAACc,SAAnD,CAA0F;AAE/EC,EAAAA,WAAW,CAACC,KAAD,EAAqC;AACnD,UAAMA,KAAN;;AADmD,yCAIhCC,QAAD,IAAqC;AACvD,UAAIf,UAAJ,CAAee,QAAf,EAAyB,KAAKD,KAAL,CAAWE,OAAX,CAAmBC,QAA5C,EAAsDC,OAAtD;AACH,KANsD;AAEtD;;AAMMC,EAAAA,MAAM,GAAoB;AAC7B,wBACI,oBAAC,UAAD;AAAY,MAAA,OAAO,EAAEd,iBAAiB,CAACe;AAAvC,oBACI,oBAAC,cAAD;AAAgB,MAAA,IAAI,EAAEX;AAAtB,MADJ,eAEI,oBAAC,KAAD;AAAO,MAAA,YAAY,EAAC,IAApB;AAAyB,MAAA,IAAI,EAAED,UAAU,CAACa;AAA1C,oBACE,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAE,KAAKP,KAAL,CAAWE,OAAX,CAAmBM,KAAhC;AAAuC,MAAA,MAAM,EAAE,KAAKR,KAAL,CAAWE,OAAX,CAAmBO;AAAlE,MADF,CAFJ,eAKI,oBAAC,cAAD,qBACE,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MADF,CALJ,eAQI,oBAAC,eAAD,CAAiB,QAAjB,QACER,QAAQ,iBACN,oBAAC,MAAD;AAAQ,MAAA,OAAO,EAAC,SAAhB;AACQ,MAAA,OAAO,EAAE,MAAM,KAAKS,WAAL,CAAiBT,QAAjB,CADvB;AAEQ,MAAA,MAAM,EAAC;AAFf,oBAEwB,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MAFxB,CAFJ,CARJ,CADJ;AAmBH;;AA9BqF;;AA+BzF,C,CAED;AACA;;AACA,OAAO,MAAMU,sBAAsB,GAAG1B,UAAU,CAACY,8BAAD,CAAzC","sourcesContent":["/*\n * Copyright 2019 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\nimport {withRouter, RouteComponentProps} from 'react-router-dom';\n\nimport {AIACommand} from '../../util/AIACommand';\nimport {PageDef} from '../../ContentPages';\nimport {Msg} from '../../widgets/Msg';\n\nimport {\n Title,\n Button,\n EmptyState,\n EmptyStateVariant,\n EmptyStateIcon,\n EmptyStateBody,\n TitleSizes\n} from '@patternfly/react-core';\nimport { PassportIcon } from '@patternfly/react-icons';\nimport { KeycloakService } from '../../keycloak-service/keycloak.service';\nimport { KeycloakContext } from '../../keycloak-service/KeycloakContext';\n\n// Note: This class demonstrates two features of the ContentPages framework:\n// 1) The PageDef is available as a React property.\n// 2) You can add additional custom properties to the PageDef. In this case,\n// we add a value called kcAction in content.js and access it by extending the\n// PageDef interface.\ninterface ActionPageDef extends PageDef {\n kcAction: string;\n}\n\n// Extend RouteComponentProps to get access to router information such as\n// the hash-routed path associated with this page. See this.props.location.pathname\n// as used below.\ninterface AppInitiatedActionPageProps extends RouteComponentProps {\n pageDef: ActionPageDef;\n}\n\n/**\n * @author Stan Silvert\n */\nclass ApplicationInitiatedActionPage extends React.Component {\n\n public constructor(props: AppInitiatedActionPageProps) {\n super(props);\n }\n\n private handleClick = (keycloak: KeycloakService): void => {\n new AIACommand(keycloak, this.props.pageDef.kcAction).execute();\n }\n\n public render(): React.ReactNode {\n return (\n \n \n \n <Msg msgKey={this.props.pageDef.label} params={this.props.pageDef.labelParams}/>\n \n \n \n \n \n { keycloak => (\n \n )}\n \n \n \n );\n }\n};\n\n// Note that the class name is not exported above. To get access to the router,\n// we use withRouter() and export a different name.\nexport const AppInitiatedActionPage = withRouter(ApplicationInitiatedActionPage);\n"],"file":"AppInitiatedActionPage.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/applications-page/ApplicationsPage.js b/keycloak-themes/keycloak.v2/account/resources/content/applications-page/ApplicationsPage.js new file mode 100644 index 0000000..3bc40b2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/applications-page/ApplicationsPage.js @@ -0,0 +1,184 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../../common/keycloak/web_modules/react.js"; +import { DataList, DataListItem, DataListItemRow, DataListCell, DataListToggle, DataListContent, DataListItemCells, DescriptionList, DescriptionListTerm, DescriptionListGroup, DescriptionListDescription, Grid, GridItem, Button, PageSection, PageSectionVariants, Stack } from "../../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { InfoAltIcon, CheckIcon, ExternalLinkAltIcon } from "../../../../common/keycloak/web_modules/@patternfly/react-icons.js"; +import { ContentPage } from "../ContentPage.js"; +import { ContinueCancelModal } from "../../widgets/ContinueCancelModal.js"; +import { AccountServiceContext } from "../../account-service/AccountServiceContext.js"; +import { Msg } from "../../widgets/Msg.js"; +export class ApplicationsPage extends React.Component { + constructor(props, context) { + super(props); + + _defineProperty(this, "context", void 0); + + _defineProperty(this, "removeConsent", clientId => { + this.context.doDelete("/applications/" + clientId + "/consent").then(() => { + this.fetchApplications(); + }); + }); + + _defineProperty(this, "onToggle", row => { + const newIsRowOpen = this.state.isRowOpen; + newIsRowOpen[row] = !newIsRowOpen[row]; + this.setState({ + isRowOpen: newIsRowOpen + }); + }); + + this.context = context; + this.state = { + isRowOpen: [], + applications: [] + }; + this.fetchApplications(); + } + + fetchApplications() { + this.context.doGet("/applications").then(response => { + const applications = response.data || []; + this.setState({ + isRowOpen: new Array(applications.length).fill(false), + applications: applications + }); + }); + } + + elementId(item, application) { + return `application-${item}-${application.clientId}`; + } + + render() { + return /*#__PURE__*/React.createElement(ContentPage, { + title: Msg.localize('applicationsPageTitle'), + introMessage: "Manage your application permissions." + }, /*#__PURE__*/React.createElement(PageSection, { + isFilled: true, + variant: PageSectionVariants.light + }, /*#__PURE__*/React.createElement(Stack, { + hasGutter: true + }, /*#__PURE__*/React.createElement(DataList, { + id: "applications-list", + "aria-label": Msg.localize('applicationsPageTitle') + }, /*#__PURE__*/React.createElement(DataListItem, { + id: "applications-list-header", + "aria-labelledby": "Columns names" + }, /*#__PURE__*/React.createElement(DataListItemRow, null, "// invisible toggle allows headings to line up properly", /*#__PURE__*/React.createElement("span", { + style: { + visibility: 'hidden', + height: 55 + } + }, /*#__PURE__*/React.createElement(DataListToggle, { + isExpanded: false, + id: "applications-list-header-invisible-toggle", + "aria-controls": "hidden" + })), /*#__PURE__*/React.createElement(DataListItemCells, { + dataListCells: [/*#__PURE__*/React.createElement(DataListCell, { + key: "applications-list-client-id-header", + width: 2, + className: "pf-u-pt-md" + }, /*#__PURE__*/React.createElement("strong", null, /*#__PURE__*/React.createElement(Msg, { + msgKey: "applicationName" + }))), /*#__PURE__*/React.createElement(DataListCell, { + key: "applications-list-app-type-header", + width: 2, + className: "pf-u-pt-md" + }, /*#__PURE__*/React.createElement("strong", null, /*#__PURE__*/React.createElement(Msg, { + msgKey: "applicationType" + }))), /*#__PURE__*/React.createElement(DataListCell, { + key: "applications-list-status", + width: 2, + className: "pf-u-pt-md" + }, /*#__PURE__*/React.createElement("strong", null, /*#__PURE__*/React.createElement(Msg, { + msgKey: "status" + })))] + }))), this.state.applications.map((application, appIndex) => { + return /*#__PURE__*/React.createElement(DataListItem, { + id: this.elementId("client-id", application), + key: 'application-' + appIndex, + "aria-labelledby": "applications-list", + isExpanded: this.state.isRowOpen[appIndex] + }, /*#__PURE__*/React.createElement(DataListItemRow, { + className: "pf-u-align-items-center" + }, /*#__PURE__*/React.createElement(DataListToggle, { + onClick: () => this.onToggle(appIndex), + isExpanded: this.state.isRowOpen[appIndex], + id: this.elementId('toggle', application), + "aria-controls": this.elementId("expandable", application) + }), /*#__PURE__*/React.createElement(DataListItemCells, { + className: "pf-u-align-items-center", + dataListCells: [/*#__PURE__*/React.createElement(DataListCell, { + id: this.elementId('name', application), + width: 2, + key: 'app-' + appIndex + }, /*#__PURE__*/React.createElement(Button, { + className: "pf-u-pl-0 title-case", + component: "a", + variant: "link", + onClick: () => window.open(application.effectiveUrl) + }, application.clientName || application.clientId, " ", /*#__PURE__*/React.createElement(ExternalLinkAltIcon, null))), /*#__PURE__*/React.createElement(DataListCell, { + id: this.elementId('internal', application), + width: 2, + key: 'internal-' + appIndex + }, application.userConsentRequired ? Msg.localize('thirdPartyApp') : Msg.localize('internalApp'), application.offlineAccess ? ', ' + Msg.localize('offlineAccess') : ''), /*#__PURE__*/React.createElement(DataListCell, { + id: this.elementId('status', application), + width: 2, + key: 'status-' + appIndex + }, application.inUse ? Msg.localize('inUse') : Msg.localize('notInUse'))] + })), /*#__PURE__*/React.createElement(DataListContent, { + className: "pf-u-pl-35xl", + hasNoPadding: false, + "aria-label": Msg.localize('applicationDetails'), + id: this.elementId("expandable", application), + isHidden: !this.state.isRowOpen[appIndex] + }, /*#__PURE__*/React.createElement(DescriptionList, null, /*#__PURE__*/React.createElement(DescriptionListGroup, null, /*#__PURE__*/React.createElement(DescriptionListTerm, null, Msg.localize('client')), /*#__PURE__*/React.createElement(DescriptionListDescription, null, application.clientId)), application.description && /*#__PURE__*/React.createElement(DescriptionListGroup, null, /*#__PURE__*/React.createElement(DescriptionListTerm, null, Msg.localize('description')), /*#__PURE__*/React.createElement(DescriptionListDescription, null, application.description)), application.effectiveUrl && /*#__PURE__*/React.createElement(DescriptionListGroup, null, /*#__PURE__*/React.createElement(DescriptionListTerm, null, "URL"), /*#__PURE__*/React.createElement(DescriptionListDescription, null, application.effectiveUrl.split('"'))), application.consent && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(DescriptionListGroup, null, /*#__PURE__*/React.createElement(DescriptionListTerm, null, "Has access to"), application.consent.grantedScopes.map((scope, scopeIndex) => { + return /*#__PURE__*/React.createElement(React.Fragment, { + key: 'scope-' + scopeIndex + }, /*#__PURE__*/React.createElement(DescriptionListDescription, null, /*#__PURE__*/React.createElement(CheckIcon, null), " ", scope.name)); + })), /*#__PURE__*/React.createElement(DescriptionListGroup, null, /*#__PURE__*/React.createElement(DescriptionListTerm, null, Msg.localize('accessGrantedOn') + ': '), /*#__PURE__*/React.createElement(DescriptionListDescription, null, new Intl.DateTimeFormat(locale, { + year: 'numeric', + month: 'long', + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + second: 'numeric' + }).format(application.consent.createDate))))), (application.consent || application.offlineAccess) && /*#__PURE__*/React.createElement(Grid, { + hasGutter: true + }, /*#__PURE__*/React.createElement("hr", null), /*#__PURE__*/React.createElement(GridItem, null, /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ContinueCancelModal, { + buttonTitle: Msg.localize('removeButton') // required + , + buttonVariant: "secondary" // defaults to 'primary' + , + modalTitle: Msg.localize('removeModalTitle') // required + , + modalMessage: Msg.localize('removeModalMessage', [application.clientId]), + modalContinueButtonLabel: Msg.localize('confirmButton') // defaults to 'Continue' + , + onContinue: () => this.removeConsent(application.clientId) // required + + }))), /*#__PURE__*/React.createElement(GridItem, null, /*#__PURE__*/React.createElement(InfoAltIcon, null), " ", Msg.localize('infoMessage'))))); + }))))); + } + +} + +_defineProperty(ApplicationsPage, "contextType", AccountServiceContext); + +; +//# sourceMappingURL=ApplicationsPage.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/applications-page/ApplicationsPage.js.map b/keycloak-themes/keycloak.v2/account/resources/content/applications-page/ApplicationsPage.js.map new file mode 100644 index 0000000..45b50bd --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/applications-page/ApplicationsPage.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/applications-page/ApplicationsPage.tsx"],"names":["React","DataList","DataListItem","DataListItemRow","DataListCell","DataListToggle","DataListContent","DataListItemCells","DescriptionList","DescriptionListTerm","DescriptionListGroup","DescriptionListDescription","Grid","GridItem","Button","PageSection","PageSectionVariants","Stack","InfoAltIcon","CheckIcon","ExternalLinkAltIcon","ContentPage","ContinueCancelModal","AccountServiceContext","Msg","ApplicationsPage","Component","constructor","props","context","clientId","doDelete","then","fetchApplications","row","newIsRowOpen","state","isRowOpen","setState","applications","doGet","response","data","Array","length","fill","elementId","item","application","render","localize","light","visibility","height","map","appIndex","onToggle","window","open","effectiveUrl","clientName","userConsentRequired","offlineAccess","inUse","description","split","consent","grantedScopes","scope","scopeIndex","name","Intl","DateTimeFormat","locale","year","month","day","hour","minute","second","format","createDate","removeConsent"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AAEA,SACEC,QADF,EAEEC,YAFF,EAGEC,eAHF,EAIEC,YAJF,EAKEC,cALF,EAMEC,eANF,EAOEC,iBAPF,EAQEC,eARF,EASEC,mBATF,EAUEC,oBAVF,EAWEC,0BAXF,EAYEC,IAZF,EAaEC,QAbF,EAcEC,MAdF,EAeEC,WAfF,EAgBEC,mBAhBF,EAiBEC,KAjBF;AAwBA,SAASC,WAAT,EAAsBC,SAAtB,EAAiCC,mBAAjC;AACA,SAASC,WAAT;AACA,SAASC,mBAAT;AAEA,SAASC,qBAAT;AACA,SAASC,GAAT;AAuCA,OAAO,MAAMC,gBAAN,SAA+BzB,KAAK,CAAC0B,SAArC,CAA6F;AAI3FC,EAAAA,WAAW,CAACC,KAAD,EAA+BC,OAA/B,EAAyF;AACzG,UAAMD,KAAN;;AADyG;;AAAA,2CAWlFE,QAAD,IAAsB;AAC5C,WAAKD,OAAL,CAAcE,QAAd,CAAuB,mBAAmBD,QAAnB,GAA8B,UAArD,EACGE,IADH,CACQ,MAAM;AACV,aAAKC,iBAAL;AACD,OAHH;AAID,KAhB0G;;AAAA,sCAkBvFC,GAAD,IAAuB;AACxC,YAAMC,YAAuB,GAAG,KAAKC,KAAL,CAAWC,SAA3C;AACAF,MAAAA,YAAY,CAACD,GAAD,CAAZ,GAAoB,CAACC,YAAY,CAACD,GAAD,CAAjC;AACA,WAAKI,QAAL,CAAc;AAAED,QAAAA,SAAS,EAAEF;AAAb,OAAd;AACD,KAtB0G;;AAEzG,SAAKN,OAAL,GAAeA,OAAf;AACA,SAAKO,KAAL,GAAa;AACXC,MAAAA,SAAS,EAAE,EADA;AAEXE,MAAAA,YAAY,EAAE;AAFH,KAAb;AAKA,SAAKN,iBAAL;AACD;;AAeOA,EAAAA,iBAAiB,GAAS;AAChC,SAAKJ,OAAL,CAAcW,KAAd,CAAmC,eAAnC,EACGR,IADH,CACSS,QAAD,IAA2C;AAC/C,YAAMF,YAAY,GAAGE,QAAQ,CAACC,IAAT,IAAiB,EAAtC;AACA,WAAKJ,QAAL,CAAc;AACZD,QAAAA,SAAS,EAAE,IAAIM,KAAJ,CAAUJ,YAAY,CAACK,MAAvB,EAA+BC,IAA/B,CAAoC,KAApC,CADC;AAEZN,QAAAA,YAAY,EAAEA;AAFF,OAAd;AAID,KAPH;AAQD;;AAEOO,EAAAA,SAAS,CAACC,IAAD,EAAeC,WAAf,EAAiD;AAChE,WAAQ,eAAcD,IAAK,IAAGC,WAAW,CAAClB,QAAS,EAAnD;AACD;;AAEMmB,EAAAA,MAAM,GAAoB;AAC/B,wBACE,oBAAC,WAAD;AACE,MAAA,KAAK,EAAEzB,GAAG,CAAC0B,QAAJ,CAAa,uBAAb,CADT;AAEE,MAAA,YAAY,EAAC;AAFf,oBAIE,oBAAC,WAAD;AAAa,MAAA,QAAQ,MAArB;AAAsB,MAAA,OAAO,EAAElC,mBAAmB,CAACmC;AAAnD,oBAEE,oBAAC,KAAD;AAAO,MAAA,SAAS;AAAhB,oBACE,oBAAC,QAAD;AAAU,MAAA,EAAE,EAAC,mBAAb;AAAiC,oBAAY3B,GAAG,CAAC0B,QAAJ,CAAa,uBAAb;AAA7C,oBACE,oBAAC,YAAD;AAAc,MAAA,EAAE,EAAC,0BAAjB;AAA4C,yBAAgB;AAA5D,oBACE,oBAAC,eAAD,gFAEE;AAAM,MAAA,KAAK,EAAE;AAAEE,QAAAA,UAAU,EAAE,QAAd;AAAwBC,QAAAA,MAAM,EAAE;AAAhC;AAAb,oBACE,oBAAC,cAAD;AACE,MAAA,UAAU,EAAE,KADd;AAEE,MAAA,EAAE,EAAC,2CAFL;AAGE,uBAAc;AAHhB,MADF,CAFF,eASE,oBAAC,iBAAD;AACE,MAAA,aAAa,EAAE,cACb,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC,oCAAlB;AAAuD,QAAA,KAAK,EAAE,CAA9D;AAAiE,QAAA,SAAS,EAAC;AAA3E,sBACE,iDAAQ,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QAAR,CADF,CADa,eAIb,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC,mCAAlB;AAAsD,QAAA,KAAK,EAAE,CAA7D;AAAgE,QAAA,SAAS,EAAC;AAA1E,sBACE,iDAAQ,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QAAR,CADF,CAJa,eAOb,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC,0BAAlB;AAA6C,QAAA,KAAK,EAAE,CAApD;AAAuD,QAAA,SAAS,EAAC;AAAjE,sBACE,iDAAQ,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QAAR,CADF,CAPa;AADjB,MATF,CADF,CADF,EA0BG,KAAKjB,KAAL,CAAWG,YAAX,CAAwBe,GAAxB,CAA4B,CAACN,WAAD,EAA2BO,QAA3B,KAAgD;AAC3E,0BACE,oBAAC,YAAD;AAAc,QAAA,EAAE,EAAE,KAAKT,SAAL,CAAe,WAAf,EAA4BE,WAA5B,CAAlB;AAA4D,QAAA,GAAG,EAAE,iBAAiBO,QAAlF;AAA4F,2BAAgB,mBAA5G;AAAgI,QAAA,UAAU,EAAE,KAAKnB,KAAL,CAAWC,SAAX,CAAqBkB,QAArB;AAA5I,sBACE,oBAAC,eAAD;AAAiB,QAAA,SAAS,EAAC;AAA3B,sBACE,oBAAC,cAAD;AACE,QAAA,OAAO,EAAE,MAAM,KAAKC,QAAL,CAAcD,QAAd,CADjB;AAEE,QAAA,UAAU,EAAE,KAAKnB,KAAL,CAAWC,SAAX,CAAqBkB,QAArB,CAFd;AAGE,QAAA,EAAE,EAAE,KAAKT,SAAL,CAAe,QAAf,EAAyBE,WAAzB,CAHN;AAIE,yBAAe,KAAKF,SAAL,CAAe,YAAf,EAA6BE,WAA7B;AAJjB,QADF,eAOE,oBAAC,iBAAD;AACE,QAAA,SAAS,EAAC,yBADZ;AAEE,QAAA,aAAa,EAAE,cACb,oBAAC,YAAD;AAAc,UAAA,EAAE,EAAE,KAAKF,SAAL,CAAe,MAAf,EAAuBE,WAAvB,CAAlB;AAAuD,UAAA,KAAK,EAAE,CAA9D;AAAiE,UAAA,GAAG,EAAE,SAASO;AAA/E,wBACE,oBAAC,MAAD;AAAQ,UAAA,SAAS,EAAC,sBAAlB;AAAyC,UAAA,SAAS,EAAC,GAAnD;AAAuD,UAAA,OAAO,EAAC,MAA/D;AAAsE,UAAA,OAAO,EAAE,MAAME,MAAM,CAACC,IAAP,CAAYV,WAAW,CAACW,YAAxB;AAArF,WACGX,WAAW,CAACY,UAAZ,IAA0BZ,WAAW,CAAClB,QADzC,oBACmD,oBAAC,mBAAD,OADnD,CADF,CADa,eAMb,oBAAC,YAAD;AAAc,UAAA,EAAE,EAAE,KAAKgB,SAAL,CAAe,UAAf,EAA2BE,WAA3B,CAAlB;AAA2D,UAAA,KAAK,EAAE,CAAlE;AAAqE,UAAA,GAAG,EAAE,cAAcO;AAAxF,WACGP,WAAW,CAACa,mBAAZ,GAAkCrC,GAAG,CAAC0B,QAAJ,CAAa,eAAb,CAAlC,GAAkE1B,GAAG,CAAC0B,QAAJ,CAAa,aAAb,CADrE,EAEGF,WAAW,CAACc,aAAZ,GAA4B,OAAOtC,GAAG,CAAC0B,QAAJ,CAAa,eAAb,CAAnC,GAAmE,EAFtE,CANa,eAUb,oBAAC,YAAD;AAAc,UAAA,EAAE,EAAE,KAAKJ,SAAL,CAAe,QAAf,EAAyBE,WAAzB,CAAlB;AAAyD,UAAA,KAAK,EAAE,CAAhE;AAAmE,UAAA,GAAG,EAAE,YAAYO;AAApF,WACGP,WAAW,CAACe,KAAZ,GAAoBvC,GAAG,CAAC0B,QAAJ,CAAa,OAAb,CAApB,GAA4C1B,GAAG,CAAC0B,QAAJ,CAAa,UAAb,CAD/C,CAVa;AAFjB,QAPF,CADF,eA2BA,oBAAC,eAAD;AACE,QAAA,SAAS,EAAC,cADZ;AAEE,QAAA,YAAY,EAAE,KAFhB;AAGE,sBAAY1B,GAAG,CAAC0B,QAAJ,CAAa,oBAAb,CAHd;AAIE,QAAA,EAAE,EAAE,KAAKJ,SAAL,CAAe,YAAf,EAA6BE,WAA7B,CAJN;AAKE,QAAA,QAAQ,EAAE,CAAC,KAAKZ,KAAL,CAAWC,SAAX,CAAqBkB,QAArB;AALb,sBAOE,oBAAC,eAAD,qBACE,oBAAC,oBAAD,qBACE,oBAAC,mBAAD,QAAsB/B,GAAG,CAAC0B,QAAJ,CAAa,QAAb,CAAtB,CADF,eAEE,oBAAC,0BAAD,QAA6BF,WAAW,CAAClB,QAAzC,CAFF,CADF,EAKGkB,WAAW,CAACgB,WAAZ,iBACC,oBAAC,oBAAD,qBACE,oBAAC,mBAAD,QAAsBxC,GAAG,CAAC0B,QAAJ,CAAa,aAAb,CAAtB,CADF,eAEE,oBAAC,0BAAD,QAA6BF,WAAW,CAACgB,WAAzC,CAFF,CANJ,EAWGhB,WAAW,CAACW,YAAZ,iBACC,oBAAC,oBAAD,qBACE,oBAAC,mBAAD,cADF,eAEE,oBAAC,0BAAD,QAA6BX,WAAW,CAACW,YAAZ,CAAyBM,KAAzB,CAA+B,GAA/B,CAA7B,CAFF,CAZJ,EAiBGjB,WAAW,CAACkB,OAAZ,iBACC,oBAAC,KAAD,CAAO,QAAP,qBACE,oBAAC,oBAAD,qBACE,oBAAC,mBAAD,wBADF,EAEGlB,WAAW,CAACkB,OAAZ,CAAoBC,aAApB,CAAkCb,GAAlC,CAAsC,CAACc,KAAD,EAAsBC,UAAtB,KAA6C;AAChF,4BACE,oBAAC,KAAD,CAAO,QAAP;AAAgB,UAAA,GAAG,EAAE,WAAWA;AAAhC,wBACE,oBAAC,0BAAD,qBAA4B,oBAAC,SAAD,OAA5B,OAA2CD,KAAK,CAACE,IAAjD,CADF,CADF;AAKD,OANF,CAFH,CADF,eAWE,oBAAC,oBAAD,qBACE,oBAAC,mBAAD,QAAsB9C,GAAG,CAAC0B,QAAJ,CAAa,iBAAb,IAAkC,IAAxD,CADF,eAEE,oBAAC,0BAAD,QACG,IAAIqB,IAAI,CAACC,cAAT,CAAwBC,MAAxB,EAAgC;AAC7BC,QAAAA,IAAI,EAAE,SADuB;AAE7BC,QAAAA,KAAK,EAAE,MAFsB;AAG7BC,QAAAA,GAAG,EAAE,SAHwB;AAI7BC,QAAAA,IAAI,EAAE,SAJuB;AAK7BC,QAAAA,MAAM,EAAE,SALqB;AAM7BC,QAAAA,MAAM,EAAE;AANqB,OAAhC,EAOIC,MAPJ,CAOWhC,WAAW,CAACkB,OAAZ,CAAoBe,UAP/B,CADH,CAFF,CAXF,CAlBJ,CAPF,EAoDG,CAACjC,WAAW,CAACkB,OAAZ,IAAuBlB,WAAW,CAACc,aAApC,kBACD,oBAAC,IAAD;AAAM,QAAA,SAAS;AAAf,sBACE,+BADF,eAEE,oBAAC,QAAD,qBACE,oBAAC,KAAD,CAAO,QAAP,qBACE,oBAAC,mBAAD;AACE,QAAA,WAAW,EAAEtC,GAAG,CAAC0B,QAAJ,CAAa,cAAb,CADf,CAC6C;AAD7C;AAEE,QAAA,aAAa,EAAC,WAFhB,CAE4B;AAF5B;AAGE,QAAA,UAAU,EAAE1B,GAAG,CAAC0B,QAAJ,CAAa,kBAAb,CAHd,CAGgD;AAHhD;AAIE,QAAA,YAAY,EAAE1B,GAAG,CAAC0B,QAAJ,CAAa,oBAAb,EAAmC,CAACF,WAAW,CAAClB,QAAb,CAAnC,CAJhB;AAKE,QAAA,wBAAwB,EAAEN,GAAG,CAAC0B,QAAJ,CAAa,eAAb,CAL5B,CAK2D;AAL3D;AAME,QAAA,UAAU,EAAE,MAAM,KAAKgC,aAAL,CAAmBlC,WAAW,CAAClB,QAA/B,CANpB,CAM8D;;AAN9D,QADF,CADF,CAFF,eAcE,oBAAC,QAAD,qBAAU,oBAAC,WAAD,OAAV,OAA2BN,GAAG,CAAC0B,QAAJ,CAAa,aAAb,CAA3B,CAdF,CArDF,CA3BA,CADF;AAqGD,KAtGA,CA1BH,CADF,CAFF,CAJF,CADF;AA8ID;;AA1LiG;;gBAAvFzB,gB,iBACUF,qB;;AA0LtB","sourcesContent":["/*\n * Copyright 2018 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\n\nimport {\n DataList,\n DataListItem,\n DataListItemRow,\n DataListCell,\n DataListToggle,\n DataListContent,\n DataListItemCells,\n DescriptionList,\n DescriptionListTerm,\n DescriptionListGroup,\n DescriptionListDescription,\n Grid,\n GridItem,\n Button,\n PageSection,\n PageSectionVariants,\n Stack,\n StackItem,\n SplitItem,\n Split,\n TextContent\n} from '@patternfly/react-core';\n\nimport { InfoAltIcon, CheckIcon, ExternalLinkAltIcon } from '@patternfly/react-icons';\nimport { ContentPage } from '../ContentPage';\nimport { ContinueCancelModal } from '../../widgets/ContinueCancelModal';\nimport { HttpResponse } from '../../account-service/account.service';\nimport { AccountServiceContext } from '../../account-service/AccountServiceContext';\nimport { Msg } from '../../widgets/Msg';\n\ndeclare const locale: string;\n\nexport interface ApplicationsPageProps {\n}\n\nexport interface ApplicationsPageState {\n isRowOpen: boolean[];\n applications: Application[];\n}\n\nexport interface GrantedScope {\n displayTest: string;\n id: string;\n name: string;\n}\n\nexport interface Consent {\n createDate: number;\n grantedScopes: GrantedScope[];\n lastUpdatedDate: number;\n}\n\ninterface Application {\n effectiveUrl: string;\n clientId: string;\n clientName: string;\n consent: Consent;\n description: string;\n inUse: boolean;\n offlineAccess: boolean;\n userConsentRequired: boolean;\n scope: string[];\n logoUri: string;\n policyUri: string;\n tosUri: string;\n}\n\nexport class ApplicationsPage extends React.Component {\n static contextType = AccountServiceContext;\n context: React.ContextType;\n\n public constructor(props: ApplicationsPageProps, context: React.ContextType) {\n super(props);\n this.context = context;\n this.state = {\n isRowOpen: [],\n applications: []\n };\n\n this.fetchApplications();\n }\n\n private removeConsent = (clientId: string) => {\n this.context!.doDelete(\"/applications/\" + clientId + \"/consent\")\n .then(() => {\n this.fetchApplications();\n });\n }\n\n private onToggle = (row: number): void => {\n const newIsRowOpen: boolean[] = this.state.isRowOpen;\n newIsRowOpen[row] = !newIsRowOpen[row];\n this.setState({ isRowOpen: newIsRowOpen });\n };\n\n private fetchApplications(): void {\n this.context!.doGet(\"/applications\")\n .then((response: HttpResponse) => {\n const applications = response.data || [];\n this.setState({\n isRowOpen: new Array(applications.length).fill(false),\n applications: applications\n });\n });\n }\n\n private elementId(item: string, application: Application): string {\n return `application-${item}-${application.clientId}`;\n }\n\n public render(): React.ReactNode {\n return (\n \n \n\n \n \n \n \n // invisible toggle allows headings to line up properly\n \n \n \n \n \n ,\n \n \n ,\n \n \n ,\n ]}\n />\n \n \n {this.state.applications.map((application: Application, appIndex: number) => {\n return (\n \n \n this.onToggle(appIndex)}\n isExpanded={this.state.isRowOpen[appIndex]}\n id={this.elementId('toggle', application)}\n aria-controls={this.elementId(\"expandable\", application)}\n />\n \n \n ,\n \n {application.userConsentRequired ? Msg.localize('thirdPartyApp') : Msg.localize('internalApp')}\n {application.offlineAccess ? ', ' + Msg.localize('offlineAccess') : ''}\n ,\n \n {application.inUse ? Msg.localize('inUse') : Msg.localize('notInUse')}\n \n ]}\n />\n \n \n \n \n \n {Msg.localize('client')}\n {application.clientId}\n \n {application.description &&\n \n {Msg.localize('description')}\n {application.description}\n \n }\n {application.effectiveUrl &&\n \n URL\n {application.effectiveUrl.split('\"')}\n \n }\n {application.consent &&\n \n \n Has access to\n {application.consent.grantedScopes.map((scope: GrantedScope, scopeIndex: number) => {\n return (\n \n {scope.name}\n \n )\n })}\n \n \n {Msg.localize('accessGrantedOn') + ': '}\n \n {new Intl.DateTimeFormat(locale, {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n second: 'numeric'\n }).format(application.consent.createDate)}\n \n \n \n }\n \n {(application.consent || application.offlineAccess) &&\n \n
    \n \n \n this.removeConsent(application.clientId)} // required\n />\n \n \n {Msg.localize('infoMessage')}\n
    \n }\n \n
    \n )\n })}\n
    \n
    \n
    \n \n );\n }\n};\n"],"file":"ApplicationsPage.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/authenticator-page/AuthenticatorPage.js b/keycloak-themes/keycloak.v2/account/resources/content/authenticator-page/AuthenticatorPage.js new file mode 100644 index 0000000..cebe2a5 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/authenticator-page/AuthenticatorPage.js @@ -0,0 +1,28 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../../common/keycloak/web_modules/react.js"; +export class AuthenticatorPage extends React.Component { + constructor(props) { + super(props); + } + + render() { + return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("h2", null, "Hello Authenticator Page")); + } + +} +; +//# sourceMappingURL=AuthenticatorPage.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/authenticator-page/AuthenticatorPage.js.map b/keycloak-themes/keycloak.v2/account/resources/content/authenticator-page/AuthenticatorPage.js.map new file mode 100644 index 0000000..7e6c8bd --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/authenticator-page/AuthenticatorPage.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/authenticator-page/AuthenticatorPage.tsx"],"names":["React","AuthenticatorPage","Component","constructor","props","render"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AAKA,OAAO,MAAMC,iBAAN,SAAgCD,KAAK,CAACE,SAAtC,CAAwE;AAEpEC,EAAAA,WAAW,CAACC,KAAD,EAAgC;AAC9C,UAAMA,KAAN;AACH;;AAEMC,EAAAA,MAAM,GAAoB;AAC7B,wBACI,8CACE,2DADF,CADJ;AAKH;;AAZ0E;AAa9E","sourcesContent":["/* \n * Copyright 2018 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\n \nexport interface AuthenticatorPageProps {\n}\n \nexport class AuthenticatorPage extends React.Component {\n \n public constructor(props: AuthenticatorPageProps) {\n super(props);\n }\n\n public render(): React.ReactNode {\n return (\n
    \n

    Hello Authenticator Page

    \n
    \n );\n }\n};"],"file":"AuthenticatorPage.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/device-activity-page/DeviceActivityPage.js b/keycloak-themes/keycloak.v2/account/resources/content/device-activity-page/DeviceActivityPage.js new file mode 100644 index 0000000..c8c53ce --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/device-activity-page/DeviceActivityPage.js @@ -0,0 +1,238 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../../common/keycloak/web_modules/react.js"; +import { AccountServiceContext } from "../../account-service/AccountServiceContext.js"; +import TimeUtil from "../../util/TimeUtil.js"; +import { Button, DataList, DataListItem, DataListItemRow, DataListContent, DescriptionList, DescriptionListTerm, DescriptionListDescription, DescriptionListGroup, Grid, GridItem, Label, PageSection, PageSectionVariants, Title, Tooltip, SplitItem, Split } from "../../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { DesktopIcon, MobileAltIcon, SyncAltIcon } from "../../../../common/keycloak/web_modules/@patternfly/react-icons.js"; +import { Msg } from "../../widgets/Msg.js"; +import { ContinueCancelModal } from "../../widgets/ContinueCancelModal.js"; +import { KeycloakContext } from "../../keycloak-service/KeycloakContext.js"; +import { ContentPage } from "../ContentPage.js"; +import { ContentAlert } from "../ContentAlert.js"; + +/** + * @author Stan Silvert ssilvert@redhat.com (C) 2019 Red Hat Inc. + */ +export class DeviceActivityPage extends React.Component { + constructor(props, context) { + super(props); + + _defineProperty(this, "context", void 0); + + _defineProperty(this, "signOutAll", keycloakService => { + this.context.doDelete("/sessions").then(() => { + keycloakService.logout(); + }); + }); + + _defineProperty(this, "signOutSession", (device, session) => { + this.context.doDelete("/sessions/" + session.id).then(() => { + this.fetchDevices(); + ContentAlert.success('signedOutSession', [session.browser, device.os]); + }); + }); + + this.context = context; + this.state = { + devices: [] + }; + this.fetchDevices(); + } + + fetchDevices() { + this.context.doGet("/sessions/devices").then(response => { + console.log({ + response + }); + let devices = this.moveCurrentToTop(response.data); + this.setState({ + devices: devices + }); + }); + } // current device and session should display at the top of their respective lists + + + moveCurrentToTop(devices) { + let currentDevice = devices[0]; + devices.forEach((device, index) => { + if (device.current) { + currentDevice = device; + devices.splice(index, 1); + devices.unshift(device); + } + }); + currentDevice.sessions.forEach((session, index) => { + if (session.current) { + const currentSession = currentDevice.sessions.splice(index, 1); + currentDevice.sessions.unshift(currentSession[0]); + } + }); + return devices; + } + + time(time) { + return TimeUtil.format(time * 1000); + } + + elementId(item, session, element = 'session') { + return `${element}-${session.id.substring(0, 7)}-${item}`; + } + + findDeviceTypeIcon(session, device) { + const deviceType = device.mobile; + if (deviceType === true) return /*#__PURE__*/React.createElement(MobileAltIcon, { + id: this.elementId('icon-mobile', session, 'device') + }); + return /*#__PURE__*/React.createElement(DesktopIcon, { + id: this.elementId('icon-desktop', session, 'device') + }); + } + + findOS(device) { + if (device.os.toLowerCase().includes('unknown')) return Msg.localize('unknownOperatingSystem'); + return device.os; + } + + findOSVersion(device) { + if (device.osVersion.toLowerCase().includes('unknown')) return ''; + return device.osVersion; + } + + makeClientsString(clients) { + let clientsString = ""; + clients.forEach((client, index) => { + let clientName; + + if (client.hasOwnProperty('clientName') && client.clientName !== undefined && client.clientName !== '') { + clientName = Msg.localize(client.clientName); + } else { + clientName = client.clientId; + } + + clientsString += clientName; + if (clients.length > index + 1) clientsString += ', '; + }); + return clientsString; + } + + isShowSignOutAll(devices) { + if (devices.length === 0) return false; + if (devices.length > 1) return true; + if (devices[0].sessions.length > 1) return true; + return false; + } + + render() { + return /*#__PURE__*/React.createElement(ContentPage, { + title: "device-activity", + introMessage: "signedInDevicesExplanation" + }, /*#__PURE__*/React.createElement(PageSection, { + isFilled: true, + variant: PageSectionVariants.light + }, /*#__PURE__*/React.createElement(Split, { + hasGutter: true, + className: "pf-u-mb-lg" + }, /*#__PURE__*/React.createElement(SplitItem, { + isFilled: true + }, /*#__PURE__*/React.createElement("div", { + id: "signedInDevicesTitle", + className: "pf-c-content" + }, /*#__PURE__*/React.createElement(Title, { + headingLevel: "h2", + size: "xl" + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "signedInDevices" + })))), /*#__PURE__*/React.createElement(SplitItem, null, /*#__PURE__*/React.createElement(Tooltip, { + content: /*#__PURE__*/React.createElement(Msg, { + msgKey: "refreshPage" + }) + }, /*#__PURE__*/React.createElement(Button, { + "aria-describedby": "refresh page", + id: "refresh-page", + variant: "link", + onClick: this.fetchDevices.bind(this), + icon: /*#__PURE__*/React.createElement(SyncAltIcon, null) + }, "Refresh"))), /*#__PURE__*/React.createElement(SplitItem, null, /*#__PURE__*/React.createElement(KeycloakContext.Consumer, null, keycloak => this.isShowSignOutAll(this.state.devices) && /*#__PURE__*/React.createElement(ContinueCancelModal, { + buttonTitle: "signOutAllDevices", + buttonId: "sign-out-all", + modalTitle: "signOutAllDevices", + modalMessage: "signOutAllDevicesWarning", + onContinue: () => this.signOutAll(keycloak) + })))), /*#__PURE__*/React.createElement(DataList, { + className: "signed-in-device-list", + "aria-label": Msg.localize('signedInDevices') + }, /*#__PURE__*/React.createElement(DataListItem, { + "aria-labelledby": "sessions", + id: "device-activity-sessions" + }, this.state.devices.map((device, deviceIndex) => { + return /*#__PURE__*/React.createElement(React.Fragment, null, device.sessions.map((session, sessionIndex) => { + return /*#__PURE__*/React.createElement(React.Fragment, { + key: 'device-' + deviceIndex + '-session-' + sessionIndex + }, /*#__PURE__*/React.createElement(DataListItemRow, null, /*#__PURE__*/React.createElement(DataListContent, { + "aria-label": "device-sessions-content", + isHidden: false, + className: "pf-u-flex-grow-1" + }, /*#__PURE__*/React.createElement(Grid, { + className: "signed-in-device-grid", + hasGutter: true + }, /*#__PURE__*/React.createElement(GridItem, { + className: "device-icon", + span: 1, + rowSpan: 2 + }, /*#__PURE__*/React.createElement("span", null, this.findDeviceTypeIcon(session, device))), /*#__PURE__*/React.createElement(GridItem, { + sm: 8, + md: 9, + span: 10 + }, /*#__PURE__*/React.createElement("span", { + id: this.elementId('browser', session), + className: "pf-u-mr-md" + }, this.findOS(device), " ", this.findOSVersion(device), " / ", session.browser), session.current && /*#__PURE__*/React.createElement(Label, { + color: "green" + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "currentSession" + }))), /*#__PURE__*/React.createElement(GridItem, { + className: "pf-u-text-align-right", + sm: 3, + md: 2, + span: 1 + }, !session.current && /*#__PURE__*/React.createElement(ContinueCancelModal, { + buttonTitle: "doSignOut", + buttonId: this.elementId('sign-out', session), + modalTitle: "doSignOut", + buttonVariant: "secondary", + modalMessage: "signOutWarning", + onContinue: () => this.signOutSession(device, session) + })), /*#__PURE__*/React.createElement(GridItem, { + span: 11 + }, /*#__PURE__*/React.createElement(DescriptionList, { + columnModifier: { + sm: '2Col', + lg: '3Col' + } + }, /*#__PURE__*/React.createElement(DescriptionListGroup, null, /*#__PURE__*/React.createElement(DescriptionListTerm, null, Msg.localize('ipAddress')), /*#__PURE__*/React.createElement(DescriptionListDescription, null, session.ipAddress)), /*#__PURE__*/React.createElement(DescriptionListGroup, null, /*#__PURE__*/React.createElement(DescriptionListTerm, null, Msg.localize('lastAccessedOn')), /*#__PURE__*/React.createElement(DescriptionListDescription, null, this.time(session.lastAccess))), /*#__PURE__*/React.createElement(DescriptionListGroup, null, /*#__PURE__*/React.createElement(DescriptionListTerm, null, Msg.localize('clients')), /*#__PURE__*/React.createElement(DescriptionListDescription, null, this.makeClientsString(session.clients))), /*#__PURE__*/React.createElement(DescriptionListGroup, null, /*#__PURE__*/React.createElement(DescriptionListTerm, null, Msg.localize('started')), /*#__PURE__*/React.createElement(DescriptionListDescription, null, this.time(session.started))), /*#__PURE__*/React.createElement(DescriptionListGroup, null, /*#__PURE__*/React.createElement(DescriptionListTerm, null, Msg.localize('expires')), /*#__PURE__*/React.createElement(DescriptionListDescription, null, this.time(session.expires))))))))); + })); + }))))); + } + +} + +_defineProperty(DeviceActivityPage, "contextType", AccountServiceContext); + +; +//# sourceMappingURL=DeviceActivityPage.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/device-activity-page/DeviceActivityPage.js.map b/keycloak-themes/keycloak.v2/account/resources/content/device-activity-page/DeviceActivityPage.js.map new file mode 100644 index 0000000..82e222f --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/device-activity-page/DeviceActivityPage.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/device-activity-page/DeviceActivityPage.tsx"],"names":["React","AccountServiceContext","TimeUtil","Button","DataList","DataListItem","DataListItemRow","DataListContent","DescriptionList","DescriptionListTerm","DescriptionListDescription","DescriptionListGroup","Grid","GridItem","Label","PageSection","PageSectionVariants","Title","Tooltip","SplitItem","Split","DesktopIcon","MobileAltIcon","SyncAltIcon","Msg","ContinueCancelModal","KeycloakContext","ContentPage","ContentAlert","DeviceActivityPage","Component","constructor","props","context","keycloakService","doDelete","then","logout","device","session","id","fetchDevices","success","browser","os","state","devices","doGet","response","console","log","moveCurrentToTop","data","setState","currentDevice","forEach","index","current","splice","unshift","sessions","currentSession","time","format","elementId","item","element","substring","findDeviceTypeIcon","deviceType","mobile","findOS","toLowerCase","includes","localize","findOSVersion","osVersion","makeClientsString","clients","clientsString","client","clientName","hasOwnProperty","undefined","clientId","length","isShowSignOutAll","render","light","bind","keycloak","signOutAll","map","deviceIndex","sessionIndex","signOutSession","sm","lg","ipAddress","lastAccess","started","expires"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AAGA,SAASC,qBAAT;AACA,OAAOC,QAAP;AAEA,SACEC,MADF,EAEEC,QAFF,EAGEC,YAHF,EAIEC,eAJF,EAKEC,eALF,EAMEC,eANF,EAOEC,mBAPF,EAQEC,0BARF,EASEC,oBATF,EAUEC,IAVF,EAWEC,QAXF,EAYEC,KAZF,EAaEC,WAbF,EAcEC,mBAdF,EAeEC,KAfF,EAgBEC,OAhBF,EAiBEC,SAjBF,EAkBEC,KAlBF;AAqBA,SACQC,WADR,EAEQC,aAFR,EAGQC,WAHR;AAMA,SAAQC,GAAR;AACA,SAAQC,mBAAR;AAEA,SAASC,eAAT;AAEA,SAAQC,WAAR;AACA,SAASC,YAAT;;AAqCA;AACA;AACA;AACA,OAAO,MAAMC,kBAAN,SAAiC7B,KAAK,CAAC8B,SAAvC,CAAmG;AAI/FC,EAAAA,WAAW,CAACC,KAAD,EAAiCC,OAAjC,EAA2F;AACzG,UAAMD,KAAN;;AADyG;;AAAA,wCAWvFE,eAAD,IAAsC;AACzD,WAAKD,OAAL,CAAcE,QAAd,CAAuB,WAAvB,EACGC,IADH,CACS,MAAM;AACXF,QAAAA,eAAe,CAACG,MAAhB;AACD,OAHH;AAID,KAhB4G;;AAAA,4CAkBpF,CAACC,MAAD,EAAiBC,OAAjB,KAAsC;AAC7D,WAAKN,OAAL,CAAcE,QAAd,CAAuB,eAAeI,OAAO,CAACC,EAA9C,EACKJ,IADL,CACW,MAAM;AACX,aAAKK,YAAL;AACAb,QAAAA,YAAY,CAACc,OAAb,CAAqB,kBAArB,EAAyC,CAACH,OAAO,CAACI,OAAT,EAAkBL,MAAM,CAACM,EAAzB,CAAzC;AACD,OAJL;AAKD,KAxB4G;;AAEzG,SAAKX,OAAL,GAAeA,OAAf;AAEA,SAAKY,KAAL,GAAa;AACXC,MAAAA,OAAO,EAAE;AADE,KAAb;AAIA,SAAKL,YAAL;AACH;;AAiBOA,EAAAA,YAAY,GAAS;AAC3B,SAAKR,OAAL,CAAcc,KAAd,CAA8B,mBAA9B,EACKX,IADL,CACWY,QAAD,IAAsC;AAC1CC,MAAAA,OAAO,CAACC,GAAR,CAAY;AAACF,QAAAA;AAAD,OAAZ;AAEA,UAAIF,OAAiB,GAAG,KAAKK,gBAAL,CAAsBH,QAAQ,CAACI,IAA/B,CAAxB;AAEA,WAAKC,QAAL,CAAc;AACZP,QAAAA,OAAO,EAAEA;AADG,OAAd;AAID,KAVL;AAWD,GA1CqG,CA4CtG;;;AACQK,EAAAA,gBAAgB,CAACL,OAAD,EAA8B;AACpD,QAAIQ,aAAqB,GAAGR,OAAO,CAAC,CAAD,CAAnC;AAEAA,IAAAA,OAAO,CAACS,OAAR,CAAgB,CAACjB,MAAD,EAAiBkB,KAAjB,KAAmC;AACjD,UAAIlB,MAAM,CAACmB,OAAX,EAAoB;AAClBH,QAAAA,aAAa,GAAGhB,MAAhB;AACAQ,QAAAA,OAAO,CAACY,MAAR,CAAeF,KAAf,EAAsB,CAAtB;AACAV,QAAAA,OAAO,CAACa,OAAR,CAAgBrB,MAAhB;AACD;AACF,KAND;AAQAgB,IAAAA,aAAa,CAACM,QAAd,CAAuBL,OAAvB,CAA+B,CAAChB,OAAD,EAAmBiB,KAAnB,KAAqC;AAClE,UAAIjB,OAAO,CAACkB,OAAZ,EAAqB;AACnB,cAAMI,cAAyB,GAAGP,aAAa,CAACM,QAAd,CAAuBF,MAAvB,CAA8BF,KAA9B,EAAqC,CAArC,CAAlC;AACAF,QAAAA,aAAa,CAACM,QAAd,CAAuBD,OAAvB,CAA+BE,cAAc,CAAC,CAAD,CAA7C;AACD;AACF,KALD;AAOA,WAAOf,OAAP;AACD;;AAEOgB,EAAAA,IAAI,CAACA,IAAD,EAAuB;AACjC,WAAO5D,QAAQ,CAAC6D,MAAT,CAAgBD,IAAI,GAAG,IAAvB,CAAP;AACD;;AAEOE,EAAAA,SAAS,CAACC,IAAD,EAAe1B,OAAf,EAAiC2B,OAAe,GAAC,SAAjD,EAAoE;AACjF,WAAQ,GAAEA,OAAQ,IAAG3B,OAAO,CAACC,EAAR,CAAW2B,SAAX,CAAqB,CAArB,EAAuB,CAAvB,CAA0B,IAAGF,IAAK,EAAvD;AACH;;AAEOG,EAAAA,kBAAkB,CAAC7B,OAAD,EAAmBD,MAAnB,EAAoD;AAC5E,UAAM+B,UAAmB,GAAG/B,MAAM,CAACgC,MAAnC;AACA,QAAID,UAAU,KAAK,IAAnB,EAAyB,oBAAQ,oBAAC,aAAD;AAAe,MAAA,EAAE,EAAE,KAAKL,SAAL,CAAe,aAAf,EAA8BzB,OAA9B,EAAuC,QAAvC;AAAnB,MAAR;AAEzB,wBAAQ,oBAAC,WAAD;AAAa,MAAA,EAAE,EAAE,KAAKyB,SAAL,CAAe,cAAf,EAA+BzB,OAA/B,EAAwC,QAAxC;AAAjB,MAAR;AACD;;AAEOgC,EAAAA,MAAM,CAACjC,MAAD,EAAyB;AACrC,QAAIA,MAAM,CAACM,EAAP,CAAU4B,WAAV,GAAwBC,QAAxB,CAAiC,SAAjC,CAAJ,EAAiD,OAAOjD,GAAG,CAACkD,QAAJ,CAAa,wBAAb,CAAP;AAEjD,WAAOpC,MAAM,CAACM,EAAd;AACD;;AAEO+B,EAAAA,aAAa,CAACrC,MAAD,EAAyB;AAC5C,QAAIA,MAAM,CAACsC,SAAP,CAAiBJ,WAAjB,GAA+BC,QAA/B,CAAwC,SAAxC,CAAJ,EAAwD,OAAO,EAAP;AAExD,WAAOnC,MAAM,CAACsC,SAAd;AACD;;AAEOC,EAAAA,iBAAiB,CAACC,OAAD,EAA4B;AACnD,QAAIC,aAAa,GAAG,EAApB;AACAD,IAAAA,OAAO,CAACvB,OAAR,CAAiB,CAACyB,MAAD,EAAiBxB,KAAjB,KAAmC;AAClD,UAAIyB,UAAJ;;AACA,UAAID,MAAM,CAACE,cAAP,CAAsB,YAAtB,KAAwCF,MAAM,CAACC,UAAP,KAAsBE,SAA9D,IAA6EH,MAAM,CAACC,UAAP,KAAsB,EAAvG,EAA4G;AAC1GA,QAAAA,UAAU,GAAGzD,GAAG,CAACkD,QAAJ,CAAaM,MAAM,CAACC,UAApB,CAAb;AACD,OAFD,MAEO;AACLA,QAAAA,UAAU,GAAGD,MAAM,CAACI,QAApB;AACD;;AAEDL,MAAAA,aAAa,IAAIE,UAAjB;AAEA,UAAIH,OAAO,CAACO,MAAR,GAAiB7B,KAAK,GAAG,CAA7B,EAAgCuB,aAAa,IAAI,IAAjB;AACjC,KAXD;AAaA,WAAOA,aAAP;AACD;;AAEOO,EAAAA,gBAAgB,CAACxC,OAAD,EAA6B;AACnD,QAAIA,OAAO,CAACuC,MAAR,KAAmB,CAAvB,EAA0B,OAAO,KAAP;AAC1B,QAAIvC,OAAO,CAACuC,MAAR,GAAiB,CAArB,EAAwB,OAAO,IAAP;AACxB,QAAIvC,OAAO,CAAC,CAAD,CAAP,CAAWc,QAAX,CAAoByB,MAApB,GAA6B,CAAjC,EAAoC,OAAO,IAAP;AAEpC,WAAO,KAAP;AACD;;AAEME,EAAAA,MAAM,GAAoB;AAE/B,wBACI,oBAAC,WAAD;AACE,MAAA,KAAK,EAAC,iBADR;AAEE,MAAA,YAAY,EAAC;AAFf,oBAIE,oBAAC,WAAD;AAAa,MAAA,QAAQ,MAArB;AAAsB,MAAA,OAAO,EAAEvE,mBAAmB,CAACwE;AAAnD,oBACA,oBAAC,KAAD;AAAO,MAAA,SAAS,MAAhB;AAAiB,MAAA,SAAS,EAAC;AAA3B,oBACE,oBAAC,SAAD;AAAW,MAAA,QAAQ;AAAnB,oBACE;AAAK,MAAA,EAAE,EAAC,sBAAR;AAA+B,MAAA,SAAS,EAAC;AAAzC,oBAAwD,oBAAC,KAAD;AAAO,MAAA,YAAY,EAAC,IAApB;AAAyB,MAAA,IAAI,EAAC;AAA9B,oBAAmC,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MAAnC,CAAxD,CADF,CADF,eAIE,oBAAC,SAAD,qBACE,oBAAC,OAAD;AAAS,MAAA,OAAO,eAAE,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ;AAAlB,oBACE,oBAAC,MAAD;AACE,0BAAiB,cADnB;AAEE,MAAA,EAAE,EAAC,cAFL;AAGE,MAAA,OAAO,EAAC,MAHV;AAIE,MAAA,OAAO,EAAE,KAAK/C,YAAL,CAAkBgD,IAAlB,CAAuB,IAAvB,CAJX;AAKE,MAAA,IAAI,eAAE,oBAAC,WAAD;AALR,iBADF,CADF,CAJF,eAiBE,oBAAC,SAAD,qBACA,oBAAC,eAAD,CAAiB,QAAjB,QACKC,QAAD,IACE,KAAKJ,gBAAL,CAAsB,KAAKzC,KAAL,CAAWC,OAAjC,kBACE,oBAAC,mBAAD;AAAqB,MAAA,WAAW,EAAC,mBAAjC;AACc,MAAA,QAAQ,EAAC,cADvB;AAEc,MAAA,UAAU,EAAC,mBAFzB;AAGc,MAAA,YAAY,EAAC,0BAH3B;AAIc,MAAA,UAAU,EAAE,MAAM,KAAK6C,UAAL,CAAgBD,QAAhB;AAJhC,MAHR,CADA,CAjBF,CADA,eAgCA,oBAAC,QAAD;AAAU,MAAA,SAAS,EAAC,uBAApB;AAA4C,oBAAYlE,GAAG,CAACkD,QAAJ,CAAa,iBAAb;AAAxD,oBACE,oBAAC,YAAD;AAAc,yBAAgB,UAA9B;AAAyC,MAAA,EAAE,EAAC;AAA5C,OACG,KAAK7B,KAAL,CAAWC,OAAX,CAAmB8C,GAAnB,CAAuB,CAACtD,MAAD,EAAiBuD,WAAjB,KAAyC;AAC/D,0BACE,oBAAC,KAAD,CAAO,QAAP,QACGvD,MAAM,CAACsB,QAAP,CAAgBgC,GAAhB,CAAoB,CAACrD,OAAD,EAAmBuD,YAAnB,KAA4C;AAC/D,4BACE,oBAAC,KAAD,CAAO,QAAP;AAAgB,UAAA,GAAG,EAAE,YAAYD,WAAZ,GAA0B,WAA1B,GAAwCC;AAA7D,wBACE,oBAAC,eAAD,qBACE,oBAAC,eAAD;AAAiB,wBAAW,yBAA5B;AAAsD,UAAA,QAAQ,EAAE,KAAhE;AAAuE,UAAA,SAAS,EAAC;AAAjF,wBACE,oBAAC,IAAD;AAAM,UAAA,SAAS,EAAC,uBAAhB;AAAwC,UAAA,SAAS;AAAjD,wBACE,oBAAC,QAAD;AAAU,UAAA,SAAS,EAAC,aAApB;AAAkC,UAAA,IAAI,EAAE,CAAxC;AAA2C,UAAA,OAAO,EAAE;AAApD,wBACE,kCAAO,KAAK1B,kBAAL,CAAwB7B,OAAxB,EAAiCD,MAAjC,CAAP,CADF,CADF,eAIE,oBAAC,QAAD;AAAU,UAAA,EAAE,EAAE,CAAd;AAAiB,UAAA,EAAE,EAAE,CAArB;AAAwB,UAAA,IAAI,EAAE;AAA9B,wBACE;AAAM,UAAA,EAAE,EAAE,KAAK0B,SAAL,CAAe,SAAf,EAA0BzB,OAA1B,CAAV;AAA8C,UAAA,SAAS,EAAC;AAAxD,WAAsE,KAAKgC,MAAL,CAAYjC,MAAZ,CAAtE,OAA4F,KAAKqC,aAAL,CAAmBrC,MAAnB,CAA5F,SAA2HC,OAAO,CAACI,OAAnI,CADF,EAEGJ,OAAO,CAACkB,OAAR,iBACC,oBAAC,KAAD;AAAO,UAAA,KAAK,EAAC;AAAb,wBAAqB,oBAAC,GAAD;AAAK,UAAA,MAAM,EAAC;AAAZ,UAArB,CAHJ,CAJF,eASE,oBAAC,QAAD;AAAU,UAAA,SAAS,EAAC,uBAApB;AAA4C,UAAA,EAAE,EAAE,CAAhD;AAAmD,UAAA,EAAE,EAAE,CAAvD;AAA0D,UAAA,IAAI,EAAE;AAAhE,WACG,CAAClB,OAAO,CAACkB,OAAT,iBACC,oBAAC,mBAAD;AAAqB,UAAA,WAAW,EAAC,WAAjC;AACE,UAAA,QAAQ,EAAE,KAAKO,SAAL,CAAe,UAAf,EAA2BzB,OAA3B,CADZ;AAEE,UAAA,UAAU,EAAC,WAFb;AAGE,UAAA,aAAa,EAAC,WAHhB;AAIE,UAAA,YAAY,EAAC,gBAJf;AAKE,UAAA,UAAU,EAAE,MAAM,KAAKwD,cAAL,CAAoBzD,MAApB,EAA4BC,OAA5B;AALpB,UAFJ,CATF,eAoBE,oBAAC,QAAD;AAAU,UAAA,IAAI,EAAE;AAAhB,wBACE,oBAAC,eAAD;AAAiB,UAAA,cAAc,EAAE;AAAEyD,YAAAA,EAAE,EAAE,MAAN;AAAcC,YAAAA,EAAE,EAAE;AAAlB;AAAjC,wBACE,oBAAC,oBAAD,qBACE,oBAAC,mBAAD,QAAsBzE,GAAG,CAACkD,QAAJ,CAAa,WAAb,CAAtB,CADF,eAEE,oBAAC,0BAAD,QAA6BnC,OAAO,CAAC2D,SAArC,CAFF,CADF,eAKE,oBAAC,oBAAD,qBACE,oBAAC,mBAAD,QAAsB1E,GAAG,CAACkD,QAAJ,CAAa,gBAAb,CAAtB,CADF,eAEE,oBAAC,0BAAD,QAA6B,KAAKZ,IAAL,CAAUvB,OAAO,CAAC4D,UAAlB,CAA7B,CAFF,CALF,eASE,oBAAC,oBAAD,qBACE,oBAAC,mBAAD,QAAsB3E,GAAG,CAACkD,QAAJ,CAAa,SAAb,CAAtB,CADF,eAEE,oBAAC,0BAAD,QAA6B,KAAKG,iBAAL,CAAuBtC,OAAO,CAACuC,OAA/B,CAA7B,CAFF,CATF,eAaE,oBAAC,oBAAD,qBACE,oBAAC,mBAAD,QAAsBtD,GAAG,CAACkD,QAAJ,CAAa,SAAb,CAAtB,CADF,eAEE,oBAAC,0BAAD,QAA6B,KAAKZ,IAAL,CAAUvB,OAAO,CAAC6D,OAAlB,CAA7B,CAFF,CAbF,eAiBE,oBAAC,oBAAD,qBACE,oBAAC,mBAAD,QAAsB5E,GAAG,CAACkD,QAAJ,CAAa,SAAb,CAAtB,CADF,eAEE,oBAAC,0BAAD,QAA6B,KAAKZ,IAAL,CAAUvB,OAAO,CAAC8D,OAAlB,CAA7B,CAFF,CAjBF,CADF,CApBF,CADF,CADF,CADF,CADF;AAqDD,OAtDA,CADH,CADF;AA2DD,KA5DA,CADH,CADF,CAhCA,CAJF,CADJ;AAyGD;;AAlOqG;;gBAA7FxE,kB,iBACY5B,qB;;AAkOxB","sourcesContent":["/*\n * Copyright 2018 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\n\nimport {HttpResponse} from '../../account-service/account.service';\nimport { AccountServiceContext } from '../../account-service/AccountServiceContext';\nimport TimeUtil from '../../util/TimeUtil';\n\nimport {\n Button,\n DataList,\n DataListItem,\n DataListItemRow,\n DataListContent,\n DescriptionList,\n DescriptionListTerm,\n DescriptionListDescription,\n DescriptionListGroup,\n Grid,\n GridItem,\n Label,\n PageSection,\n PageSectionVariants,\n Title,\n Tooltip,\n SplitItem,\n Split\n} from '@patternfly/react-core';\n\nimport {\n DesktopIcon,\n MobileAltIcon,\n SyncAltIcon,\n} from '@patternfly/react-icons';\n\nimport {Msg} from '../../widgets/Msg';\nimport {ContinueCancelModal} from '../../widgets/ContinueCancelModal';\nimport { KeycloakService } from '../../keycloak-service/keycloak.service';\nimport { KeycloakContext } from '../../keycloak-service/KeycloakContext';\n\nimport {ContentPage} from '../ContentPage';\nimport { ContentAlert } from '../ContentAlert';\n\nexport interface DeviceActivityPageProps {\n}\n\nexport interface DeviceActivityPageState {\n devices: Device[];\n}\n\ninterface Device {\n browser: string;\n current: boolean;\n device: string;\n ipAddress: string;\n lastAccess: number;\n mobile: boolean;\n os: string;\n osVersion: string;\n sessions: Session[];\n}\n\ninterface Session {\n browser: string;\n current: boolean;\n clients: Client[];\n expires: number;\n id: string;\n ipAddress: string;\n lastAccess: number;\n started: number;\n}\n\ninterface Client {\n clientId: string;\n clientName: string;\n}\n\n/**\n * @author Stan Silvert ssilvert@redhat.com (C) 2019 Red Hat Inc.\n */\nexport class DeviceActivityPage extends React.Component {\n static contextType = AccountServiceContext;\n context: React.ContextType;\n\n public constructor(props: DeviceActivityPageProps, context: React.ContextType) {\n super(props);\n this.context = context;\n\n this.state = {\n devices: []\n };\n\n this.fetchDevices();\n }\n\n private signOutAll = (keycloakService: KeycloakService) => {\n this.context!.doDelete(\"/sessions\")\n .then( () => {\n keycloakService.logout();\n });\n }\n\n private signOutSession = (device: Device, session: Session) => {\n this.context!.doDelete(\"/sessions/\" + session.id)\n .then (() => {\n this.fetchDevices();\n ContentAlert.success('signedOutSession', [session.browser, device.os]);\n });\n }\n\n private fetchDevices(): void {\n this.context!.doGet(\"/sessions/devices\")\n .then((response: HttpResponse) => {\n console.log({response});\n\n let devices: Device[] = this.moveCurrentToTop(response.data as Device[]);\n\n this.setState({\n devices: devices\n });\n\n });\n }\n\n // current device and session should display at the top of their respective lists\n private moveCurrentToTop(devices: Device[]): Device[] {\n let currentDevice: Device = devices[0];\n\n devices.forEach((device: Device, index: number) => {\n if (device.current) {\n currentDevice = device;\n devices.splice(index, 1);\n devices.unshift(device);\n }\n });\n\n currentDevice.sessions.forEach((session: Session, index: number) => {\n if (session.current) {\n const currentSession: Session[] = currentDevice.sessions.splice(index, 1);\n currentDevice.sessions.unshift(currentSession[0]);\n }\n });\n\n return devices;\n }\n\n private time(time: number): string {\n return TimeUtil.format(time * 1000);\n }\n\n private elementId(item: string, session: Session, element: string='session'): string {\n return `${element}-${session.id.substring(0,7)}-${item}`;\n }\n\n private findDeviceTypeIcon(session: Session, device: Device): React.ReactNode {\n const deviceType: boolean = device.mobile;\n if (deviceType === true) return ();\n\n return ();\n }\n\n private findOS(device: Device): string {\n if (device.os.toLowerCase().includes('unknown')) return Msg.localize('unknownOperatingSystem');\n\n return device.os;\n }\n\n private findOSVersion(device: Device): string {\n if (device.osVersion.toLowerCase().includes('unknown')) return '';\n\n return device.osVersion;\n }\n\n private makeClientsString(clients: Client[]): string {\n let clientsString = \"\";\n clients.forEach( (client: Client, index: number) => {\n let clientName: string;\n if (client.hasOwnProperty('clientName') && (client.clientName !== undefined) && (client.clientName !== '')) {\n clientName = Msg.localize(client.clientName);\n } else {\n clientName = client.clientId;\n }\n\n clientsString += clientName;\n\n if (clients.length > index + 1) clientsString += ', ';\n })\n\n return clientsString;\n }\n\n private isShowSignOutAll(devices: Device[]): boolean {\n if (devices.length === 0) return false;\n if (devices.length > 1) return true;\n if (devices[0].sessions.length > 1) return true;\n\n return false;\n }\n\n public render(): React.ReactNode {\n\n return (\n \n \n \n \n
    <Msg msgKey=\"signedInDevices\"/>
    \n
    \n \n }>\n }\n >\n Refresh\n \n \n \n \n \n { (keycloak: KeycloakService) => (\n this.isShowSignOutAll(this.state.devices) &&\n this.signOutAll(keycloak)}\n />\n )}\n \n \n
    \n \n \n {this.state.devices.map((device: Device, deviceIndex: number) => {\n return (\n \n {device.sessions.map((session: Session, sessionIndex: number) => {\n return (\n \n \n \n \n \n {this.findDeviceTypeIcon(session, device)}\n \n \n {this.findOS(device)} {this.findOSVersion(device)} / {session.browser}\n {session.current &&\n }\n \n \n {!session.current &&\n this.signOutSession(device, session)}\n />\n }\n \n \n \n \n {Msg.localize('ipAddress')}\n {session.ipAddress}\n \n \n {Msg.localize('lastAccessedOn')}\n {this.time(session.lastAccess)}\n \n \n {Msg.localize('clients')}\n {this.makeClientsString(session.clients)}\n \n \n {Msg.localize('started')}\n {this.time(session.started)}\n \n \n {Msg.localize('expires')}\n {this.time(session.expires)}\n \n \n \n \n \n \n \n );\n })}\n \n )\n })}\n \n \n
    \n
    \n );\n }\n};\n"],"file":"DeviceActivityPage.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/forbidden-page/ForbiddenPage.js b/keycloak-themes/keycloak.v2/account/resources/content/forbidden-page/ForbiddenPage.js new file mode 100644 index 0000000..9ecae88 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/forbidden-page/ForbiddenPage.js @@ -0,0 +1,36 @@ +/* + * Copyright 2020 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../../common/keycloak/web_modules/react.js"; +import { WarningTriangleIcon } from "../../../../common/keycloak/web_modules/@patternfly/react-icons.js"; +import { Msg } from "../../widgets/Msg.js"; +import EmptyMessageState from "../../widgets/EmptyMessageState.js"; +export class ForbiddenPage extends React.Component { + constructor() { + super({}); + } + + render() { + return /*#__PURE__*/React.createElement(EmptyMessageState, { + icon: WarningTriangleIcon, + messageKey: "forbidden" + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "needAccessRights" + })); + } + +} +; +//# sourceMappingURL=ForbiddenPage.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/forbidden-page/ForbiddenPage.js.map b/keycloak-themes/keycloak.v2/account/resources/content/forbidden-page/ForbiddenPage.js.map new file mode 100644 index 0000000..d46e907 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/forbidden-page/ForbiddenPage.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/forbidden-page/ForbiddenPage.tsx"],"names":["React","WarningTriangleIcon","Msg","EmptyMessageState","ForbiddenPage","Component","constructor","render"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,KAAKA,KAAZ;AAEA,SAASC,mBAAT;AACA,SAAQC,GAAR;AACA,OAAOC,iBAAP;AAGA,OAAO,MAAMC,aAAN,SAA4BJ,KAAK,CAACK,SAAlC,CAA4C;AAExCC,EAAAA,WAAW,GAAG;AACjB,UAAM,EAAN;AACH;;AAEMC,EAAAA,MAAM,GAAoB;AAC7B,wBACI,oBAAC,iBAAD;AAAmB,MAAA,IAAI,EAAEN,mBAAzB;AAA8C,MAAA,UAAU,EAAC;AAAzD,oBACI,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MADJ,CADJ;AAKH;;AAZ8C;AAalD","sourcesContent":["/*\n * Copyright 2020 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport * as React from 'react';\n\nimport { WarningTriangleIcon } from '@patternfly/react-icons';\nimport {Msg} from '../../widgets/Msg';\nimport EmptyMessageState from '../../widgets/EmptyMessageState';\n\n\nexport class ForbiddenPage extends React.Component {\n\n public constructor() {\n super({});\n }\n\n public render(): React.ReactNode {\n return (\n \n \n \n );\n }\n};\n"],"file":"ForbiddenPage.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/linked-accounts-page/LinkedAccountsPage.js b/keycloak-themes/keycloak.v2/account/resources/content/linked-accounts-page/LinkedAccountsPage.js new file mode 100644 index 0000000..6d8a6e7 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/linked-accounts-page/LinkedAccountsPage.js @@ -0,0 +1,261 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../../common/keycloak/web_modules/react.js"; +import { withRouter } from "../../../../common/keycloak/web_modules/react-router-dom.js"; +import { Button, DataList, DataListAction, DataListItemCells, DataListCell, DataListItemRow, Label, PageSection, PageSectionVariants, Split, SplitItem, Stack, StackItem, Title, DataListItem } from "../../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { BitbucketIcon, CubeIcon, GitlabIcon, LinkIcon, PaypalIcon, UnlinkIcon } from "../../../../common/keycloak/web_modules/@patternfly/react-icons.js"; +import { AccountServiceContext } from "../../account-service/AccountServiceContext.js"; +import { Msg } from "../../widgets/Msg.js"; +import { ContentPage } from "../ContentPage.js"; +import { createRedirect } from "../../util/RedirectUri.js"; + +/** + * @author Stan Silvert + */ +class LinkedAccountsPage extends React.Component { + constructor(props, context) { + super(props); + + _defineProperty(this, "context", void 0); + + this.context = context; + this.state = { + linkedAccounts: [], + unLinkedAccounts: [] + }; + this.getLinkedAccounts(); + } + + getLinkedAccounts() { + this.context.doGet("/linked-accounts").then(response => { + console.log({ + response + }); + const linkedAccounts = response.data.filter(account => account.connected); + const unLinkedAccounts = response.data.filter(account => !account.connected); + this.setState({ + linkedAccounts: linkedAccounts, + unLinkedAccounts: unLinkedAccounts + }); + }); + } + + unLinkAccount(account) { + const url = '/linked-accounts/' + account.providerName; + this.context.doDelete(url).then(response => { + console.log({ + response + }); + this.getLinkedAccounts(); + }); + } + + linkAccount(account) { + const url = '/linked-accounts/' + account.providerName; + const redirectUri = createRedirect(this.props.location.pathname); + this.context.doGet(url, { + params: { + providerId: account.providerName, + redirectUri + } + }).then(response => { + console.log({ + response + }); + window.location.href = response.data.accountLinkUri; + }); + } + + render() { + return /*#__PURE__*/React.createElement(ContentPage, { + title: Msg.localize('linkedAccountsTitle'), + introMessage: Msg.localize('linkedAccountsIntroMessage') + }, /*#__PURE__*/React.createElement(PageSection, { + isFilled: true, + variant: PageSectionVariants.light + }, /*#__PURE__*/React.createElement(Stack, { + hasGutter: true + }, /*#__PURE__*/React.createElement(StackItem, null, /*#__PURE__*/React.createElement(Title, { + headingLevel: "h2", + className: "pf-u-mb-lg", + size: "xl" + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "linkedLoginProviders" + })), /*#__PURE__*/React.createElement(DataList, { + id: "linked-idps", + "aria-label": Msg.localize('linkedLoginProviders') + }, this.makeRows(this.state.linkedAccounts, true))), /*#__PURE__*/React.createElement(StackItem, null, /*#__PURE__*/React.createElement(Title, { + headingLevel: "h2", + className: "pf-u-mt-xl pf-u-mb-lg", + size: "xl" + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "unlinkedLoginProviders" + })), /*#__PURE__*/React.createElement(DataList, { + id: "unlinked-idps", + "aria-label": Msg.localize('unlinkedLoginProviders') + }, this.makeRows(this.state.unLinkedAccounts, false)))))); + } + + emptyRow(isLinked) { + let isEmptyMessage = ''; + + if (isLinked) { + isEmptyMessage = Msg.localize('linkedEmpty'); + } else { + isEmptyMessage = Msg.localize('unlinkedEmpty'); + } + + return /*#__PURE__*/React.createElement(DataListItem, { + key: "emptyItem", + "aria-labelledby": Msg.localize('isEmptyMessage') + }, /*#__PURE__*/React.createElement(DataListItemRow, { + key: "emptyRow" + }, /*#__PURE__*/React.createElement(DataListItemCells, { + dataListCells: [/*#__PURE__*/React.createElement(DataListCell, { + key: "empty" + }, isEmptyMessage)] + }))); + } + + makeRows(accounts, isLinked) { + if (accounts.length === 0) { + return this.emptyRow(isLinked); + } + + return /*#__PURE__*/React.createElement(React.Fragment, null, " ", accounts.map(account => /*#__PURE__*/React.createElement(DataListItem, { + id: `${account.providerAlias}-idp`, + key: account.providerName, + "aria-labelledby": Msg.localize('linkedAccountsTitle') + }, /*#__PURE__*/React.createElement(DataListItemRow, { + key: account.providerName + }, /*#__PURE__*/React.createElement(DataListItemCells, { + dataListCells: [/*#__PURE__*/React.createElement(DataListCell, { + key: "idp" + }, /*#__PURE__*/React.createElement(Split, null, /*#__PURE__*/React.createElement(SplitItem, { + className: "pf-u-mr-sm" + }, this.findIcon(account)), /*#__PURE__*/React.createElement(SplitItem, { + className: "pf-u-my-xs", + isFilled: true + }, /*#__PURE__*/React.createElement("span", { + id: `${account.providerAlias}-idp-name` + }, account.displayName)))), /*#__PURE__*/React.createElement(DataListCell, { + key: "label" + }, /*#__PURE__*/React.createElement(Split, null, /*#__PURE__*/React.createElement(SplitItem, { + className: "pf-u-my-xs", + isFilled: true + }, /*#__PURE__*/React.createElement("span", { + id: `${account.providerAlias}-idp-label` + }, this.label(account))))), /*#__PURE__*/React.createElement(DataListCell, { + key: "username", + width: 5 + }, /*#__PURE__*/React.createElement(Split, null, /*#__PURE__*/React.createElement(SplitItem, { + className: "pf-u-my-xs", + isFilled: true + }, /*#__PURE__*/React.createElement("span", { + id: `${account.providerAlias}-idp-username` + }, account.linkedUsername))))] + }), /*#__PURE__*/React.createElement(DataListAction, { + "aria-labelledby": Msg.localize('link'), + "aria-label": Msg.localize('unLink'), + id: "setPasswordAction" + }, isLinked && /*#__PURE__*/React.createElement(Button, { + id: `${account.providerAlias}-idp-unlink`, + variant: "link", + onClick: () => this.unLinkAccount(account) + }, /*#__PURE__*/React.createElement(UnlinkIcon, { + size: "sm" + }), " ", /*#__PURE__*/React.createElement(Msg, { + msgKey: "unLink" + })), !isLinked && /*#__PURE__*/React.createElement(Button, { + id: `${account.providerAlias}-idp-link`, + variant: "link", + onClick: () => this.linkAccount(account) + }, /*#__PURE__*/React.createElement(LinkIcon, { + size: "sm" + }), " ", /*#__PURE__*/React.createElement(Msg, { + msgKey: "link" + })))))), " "); + } + + label(account) { + if (account.social) { + return /*#__PURE__*/React.createElement(Label, { + color: "blue" + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "socialLogin" + })); + } + + return /*#__PURE__*/React.createElement(Label, { + color: "green" + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "systemDefined" + })); + } + + findIcon(account) { + const socialIconId = `${account.providerAlias}-idp-icon-social`; + console.log(account); + + switch (true) { + case account.providerName.toLowerCase().includes('bitbucket'): + return /*#__PURE__*/React.createElement(BitbucketIcon, { + id: socialIconId, + size: "lg" + }); + + case account.providerName.toLowerCase().includes('openshift'): + return /*#__PURE__*/React.createElement("div", { + className: "idp-icon-social", + id: "openshift-idp-icon-social" + }); + + case account.providerName.toLowerCase().includes('gitlab'): + return /*#__PURE__*/React.createElement(GitlabIcon, { + id: socialIconId, + size: "lg" + }); + + case account.providerName.toLowerCase().includes('paypal'): + return /*#__PURE__*/React.createElement(PaypalIcon, { + id: socialIconId, + size: "lg" + }); + + case account.providerName !== '' && account.social: + return /*#__PURE__*/React.createElement("div", { + className: "idp-icon-social", + id: socialIconId + }); + + default: + return /*#__PURE__*/React.createElement(CubeIcon, { + id: `${account.providerAlias}-idp-icon-default`, + size: "lg" + }); + } + } + +} + +_defineProperty(LinkedAccountsPage, "contextType", AccountServiceContext); + +; +const LinkedAccountsPagewithRouter = withRouter(LinkedAccountsPage); +export { LinkedAccountsPagewithRouter as LinkedAccountsPage }; +//# sourceMappingURL=LinkedAccountsPage.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/linked-accounts-page/LinkedAccountsPage.js.map b/keycloak-themes/keycloak.v2/account/resources/content/linked-accounts-page/LinkedAccountsPage.js.map new file mode 100644 index 0000000..c544f35 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/linked-accounts-page/LinkedAccountsPage.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/linked-accounts-page/LinkedAccountsPage.tsx"],"names":["React","withRouter","Button","DataList","DataListAction","DataListItemCells","DataListCell","DataListItemRow","Label","PageSection","PageSectionVariants","Split","SplitItem","Stack","StackItem","Title","DataListItem","BitbucketIcon","CubeIcon","GitlabIcon","LinkIcon","PaypalIcon","UnlinkIcon","AccountServiceContext","Msg","ContentPage","createRedirect","LinkedAccountsPage","Component","constructor","props","context","state","linkedAccounts","unLinkedAccounts","getLinkedAccounts","doGet","then","response","console","log","data","filter","account","connected","setState","unLinkAccount","url","providerName","doDelete","linkAccount","redirectUri","location","pathname","params","providerId","window","href","accountLinkUri","render","localize","light","makeRows","emptyRow","isLinked","isEmptyMessage","accounts","length","map","providerAlias","findIcon","displayName","label","linkedUsername","social","socialIconId","toLowerCase","includes","LinkedAccountsPagewithRouter"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AACA,SAAQC,UAAR;AAEA,SACIC,MADJ,EAEIC,QAFJ,EAGIC,cAHJ,EAIIC,iBAJJ,EAKIC,YALJ,EAMIC,eANJ,EAQIC,KARJ,EASIC,WATJ,EAUIC,mBAVJ,EAWIC,KAXJ,EAYIC,SAZJ,EAaIC,KAbJ,EAcIC,SAdJ,EAeIC,KAfJ,EAgBIC,YAhBJ;AAmBA,SACIC,aADJ,EAEIC,QAFJ,EAGIC,UAHJ,EAIIC,QAJJ,EAMIC,UANJ,EAOIC,UAPJ;AAWA,SAAQC,qBAAR;AACA,SAAQC,GAAR;AACA,SAAQC,WAAR;AACA,SAAQC,cAAR;;AAmBA;AACA;AACA;AACA,MAAMC,kBAAN,SAAiC3B,KAAK,CAAC4B,SAAvC,CAAmG;AAIxFC,EAAAA,WAAW,CAACC,KAAD,EAAiCC,OAAjC,EAA2F;AACzG,UAAMD,KAAN;;AADyG;;AAEzG,SAAKC,OAAL,GAAeA,OAAf;AAEA,SAAKC,KAAL,GAAa;AACTC,MAAAA,cAAc,EAAE,EADP;AAETC,MAAAA,gBAAgB,EAAE;AAFT,KAAb;AAKA,SAAKC,iBAAL;AACH;;AAEOA,EAAAA,iBAAiB,GAAS;AAC9B,SAAKJ,OAAL,CAAcK,KAAd,CAAqC,kBAArC,EACKC,IADL,CACWC,QAAD,IAA6C;AAC/CC,MAAAA,OAAO,CAACC,GAAR,CAAY;AAACF,QAAAA;AAAD,OAAZ;AACA,YAAML,cAAc,GAAGK,QAAQ,CAACG,IAAT,CAAeC,MAAf,CAAuBC,OAAD,IAAaA,OAAO,CAACC,SAA3C,CAAvB;AACA,YAAMV,gBAAgB,GAAGI,QAAQ,CAACG,IAAT,CAAeC,MAAf,CAAuBC,OAAD,IAAa,CAACA,OAAO,CAACC,SAA5C,CAAzB;AACA,WAAKC,QAAL,CAAc;AAACZ,QAAAA,cAAc,EAAEA,cAAjB;AAAiCC,QAAAA,gBAAgB,EAAEA;AAAnD,OAAd;AACH,KANL;AAOH;;AAEOY,EAAAA,aAAa,CAACH,OAAD,EAA+B;AAChD,UAAMI,GAAG,GAAG,sBAAsBJ,OAAO,CAACK,YAA1C;AAEA,SAAKjB,OAAL,CAAckB,QAAd,CAA6BF,GAA7B,EACKV,IADL,CACWC,QAAD,IAAkC;AACpCC,MAAAA,OAAO,CAACC,GAAR,CAAY;AAACF,QAAAA;AAAD,OAAZ;AACA,WAAKH,iBAAL;AACH,KAJL;AAKH;;AAEOe,EAAAA,WAAW,CAACP,OAAD,EAA+B;AAC9C,UAAMI,GAAG,GAAG,sBAAsBJ,OAAO,CAACK,YAA1C;AAEA,UAAMG,WAAmB,GAAGzB,cAAc,CAAC,KAAKI,KAAL,CAAWsB,QAAX,CAAoBC,QAArB,CAA1C;AAEA,SAAKtB,OAAL,CAAcK,KAAd,CAA8CW,GAA9C,EAAmD;AAAEO,MAAAA,MAAM,EAAE;AAACC,QAAAA,UAAU,EAAEZ,OAAO,CAACK,YAArB;AAAmCG,QAAAA;AAAnC;AAAV,KAAnD,EACKd,IADL,CACWC,QAAD,IAAsD;AACxDC,MAAAA,OAAO,CAACC,GAAR,CAAY;AAACF,QAAAA;AAAD,OAAZ;AACAkB,MAAAA,MAAM,CAACJ,QAAP,CAAgBK,IAAhB,GAAuBnB,QAAQ,CAACG,IAAT,CAAeiB,cAAtC;AACH,KAJL;AAKH;;AAEMC,EAAAA,MAAM,GAAoB;AAE7B,wBACI,oBAAC,WAAD;AAAa,MAAA,KAAK,EAAEnC,GAAG,CAACoC,QAAJ,CAAa,qBAAb,CAApB;AAAyD,MAAA,YAAY,EAAEpC,GAAG,CAACoC,QAAJ,CAAa,4BAAb;AAAvE,oBACI,oBAAC,WAAD;AAAa,MAAA,QAAQ,MAArB;AAAsB,MAAA,OAAO,EAAElD,mBAAmB,CAACmD;AAAnD,oBACI,oBAAC,KAAD;AAAO,MAAA,SAAS;AAAhB,oBACI,oBAAC,SAAD,qBACI,oBAAC,KAAD;AAAO,MAAA,YAAY,EAAC,IAApB;AAAyB,MAAA,SAAS,EAAC,YAAnC;AAAgD,MAAA,IAAI,EAAC;AAArD,oBACI,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MADJ,CADJ,eAII,oBAAC,QAAD;AAAU,MAAA,EAAE,EAAC,aAAb;AAA2B,oBAAYrC,GAAG,CAACoC,QAAJ,CAAa,sBAAb;AAAvC,OACK,KAAKE,QAAL,CAAc,KAAK9B,KAAL,CAAWC,cAAzB,EAAyC,IAAzC,CADL,CAJJ,CADJ,eASI,oBAAC,SAAD,qBACI,oBAAC,KAAD;AAAO,MAAA,YAAY,EAAC,IAApB;AAAyB,MAAA,SAAS,EAAC,uBAAnC;AAA2D,MAAA,IAAI,EAAC;AAAhE,oBACI,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MADJ,CADJ,eAII,oBAAC,QAAD;AAAU,MAAA,EAAE,EAAC,eAAb;AAA6B,oBAAYT,GAAG,CAACoC,QAAJ,CAAa,wBAAb;AAAzC,OACK,KAAKE,QAAL,CAAc,KAAK9B,KAAL,CAAWE,gBAAzB,EAA2C,KAA3C,CADL,CAJJ,CATJ,CADJ,CADJ,CADJ;AAwBH;;AAEO6B,EAAAA,QAAQ,CAACC,QAAD,EAAqC;AACjD,QAAIC,cAAc,GAAG,EAArB;;AACA,QAAID,QAAJ,EAAc;AACVC,MAAAA,cAAc,GAAGzC,GAAG,CAACoC,QAAJ,CAAa,aAAb,CAAjB;AACH,KAFD,MAEO;AACHK,MAAAA,cAAc,GAAGzC,GAAG,CAACoC,QAAJ,CAAa,eAAb,CAAjB;AACH;;AAED,wBACI,oBAAC,YAAD;AAAc,MAAA,GAAG,EAAC,WAAlB;AAA8B,yBAAiBpC,GAAG,CAACoC,QAAJ,CAAa,gBAAb;AAA/C,oBACI,oBAAC,eAAD;AAAiB,MAAA,GAAG,EAAC;AAArB,oBACI,oBAAC,iBAAD;AAAmB,MAAA,aAAa,EAAE,cAC9B,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC;AAAlB,SAA2BK,cAA3B,CAD8B;AAAlC,MADJ,CADJ,CADJ;AASH;;AAEOH,EAAAA,QAAQ,CAACI,QAAD,EAA4BF,QAA5B,EAAgE;AAC5E,QAAIE,QAAQ,CAACC,MAAT,KAAoB,CAAxB,EAA2B;AACvB,aAAO,KAAKJ,QAAL,CAAcC,QAAd,CAAP;AACH;;AAED,wBACI,+CAEIE,QAAQ,CAACE,GAAT,CAAezB,OAAD,iBACV,oBAAC,YAAD;AAAc,MAAA,EAAE,EAAG,GAAEA,OAAO,CAAC0B,aAAc,MAA3C;AAAkD,MAAA,GAAG,EAAE1B,OAAO,CAACK,YAA/D;AAA6E,yBAAiBxB,GAAG,CAACoC,QAAJ,CAAa,qBAAb;AAA9F,oBACI,oBAAC,eAAD;AAAiB,MAAA,GAAG,EAAEjB,OAAO,CAACK;AAA9B,oBACI,oBAAC,iBAAD;AACI,MAAA,aAAa,EAAE,cACX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC;AAAlB,sBACI,oBAAC,KAAD,qBACI,oBAAC,SAAD;AAAW,QAAA,SAAS,EAAC;AAArB,SAAmC,KAAKsB,QAAL,CAAc3B,OAAd,CAAnC,CADJ,eAEI,oBAAC,SAAD;AAAW,QAAA,SAAS,EAAC,YAArB;AAAkC,QAAA,QAAQ;AAA1C,sBAA2C;AAAM,QAAA,EAAE,EAAG,GAAEA,OAAO,CAAC0B,aAAc;AAAnC,SAAgD1B,OAAO,CAAC4B,WAAxD,CAA3C,CAFJ,CADJ,CADW,eAOX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC;AAAlB,sBACI,oBAAC,KAAD,qBACI,oBAAC,SAAD;AAAW,QAAA,SAAS,EAAC,YAArB;AAAkC,QAAA,QAAQ;AAA1C,sBAA2C;AAAM,QAAA,EAAE,EAAG,GAAE5B,OAAO,CAAC0B,aAAc;AAAnC,SAAiD,KAAKG,KAAL,CAAW7B,OAAX,CAAjD,CAA3C,CADJ,CADJ,CAPW,eAYX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC,UAAlB;AAA6B,QAAA,KAAK,EAAE;AAApC,sBACI,oBAAC,KAAD,qBACI,oBAAC,SAAD;AAAW,QAAA,SAAS,EAAC,YAArB;AAAkC,QAAA,QAAQ;AAA1C,sBAA2C;AAAM,QAAA,EAAE,EAAG,GAAEA,OAAO,CAAC0B,aAAc;AAAnC,SAAoD1B,OAAO,CAAC8B,cAA5D,CAA3C,CADJ,CADJ,CAZW;AADnB,MADJ,eAoBI,oBAAC,cAAD;AAAgB,yBAAiBjD,GAAG,CAACoC,QAAJ,CAAa,MAAb,CAAjC;AAAuD,oBAAYpC,GAAG,CAACoC,QAAJ,CAAa,QAAb,CAAnE;AAA2F,MAAA,EAAE,EAAC;AAA9F,OACKI,QAAQ,iBAAI,oBAAC,MAAD;AAAQ,MAAA,EAAE,EAAG,GAAErB,OAAO,CAAC0B,aAAc,aAArC;AAAmD,MAAA,OAAO,EAAC,MAA3D;AAAkE,MAAA,OAAO,EAAE,MAAM,KAAKvB,aAAL,CAAmBH,OAAnB;AAAjF,oBAA8G,oBAAC,UAAD;AAAY,MAAA,IAAI,EAAC;AAAjB,MAA9G,oBAAsI,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MAAtI,CADjB,EAEK,CAACqB,QAAD,iBAAa,oBAAC,MAAD;AAAQ,MAAA,EAAE,EAAG,GAAErB,OAAO,CAAC0B,aAAc,WAArC;AAAiD,MAAA,OAAO,EAAC,MAAzD;AAAgE,MAAA,OAAO,EAAE,MAAM,KAAKnB,WAAL,CAAiBP,OAAjB;AAA/E,oBAA0G,oBAAC,QAAD;AAAU,MAAA,IAAI,EAAC;AAAf,MAA1G,oBAAgI,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MAAhI,CAFlB,CApBJ,CADJ,CADJ,CAFJ,MADJ;AAoCH;;AAEO6B,EAAAA,KAAK,CAAC7B,OAAD,EAA0C;AACnD,QAAIA,OAAO,CAAC+B,MAAZ,EAAoB;AAChB,0BAAQ,oBAAC,KAAD;AAAO,QAAA,KAAK,EAAC;AAAb,sBAAoB,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QAApB,CAAR;AACH;;AAED,wBAAQ,oBAAC,KAAD;AAAO,MAAA,KAAK,EAAC;AAAb,oBAAqB,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MAArB,CAAR;AACH;;AAEOJ,EAAAA,QAAQ,CAAC3B,OAAD,EAA0C;AACxD,UAAMgC,YAAY,GAAI,GAAEhC,OAAO,CAAC0B,aAAc,kBAA9C;AACA9B,IAAAA,OAAO,CAACC,GAAR,CAAYG,OAAZ;;AACA,YAAQ,IAAR;AACE,WAAKA,OAAO,CAACK,YAAR,CAAqB4B,WAArB,GAAmCC,QAAnC,CAA4C,WAA5C,CAAL;AACE,4BAAO,oBAAC,aAAD;AAAe,UAAA,EAAE,EAAEF,YAAnB;AAAiC,UAAA,IAAI,EAAC;AAAtC,UAAP;;AACF,WAAKhC,OAAO,CAACK,YAAR,CAAqB4B,WAArB,GAAmCC,QAAnC,CAA4C,WAA5C,CAAL;AACE,4BAAO;AAAK,UAAA,SAAS,EAAC,iBAAf;AAAiC,UAAA,EAAE,EAAC;AAApC,UAAP;;AACF,WAAKlC,OAAO,CAACK,YAAR,CAAqB4B,WAArB,GAAmCC,QAAnC,CAA4C,QAA5C,CAAL;AACE,4BAAO,oBAAC,UAAD;AAAY,UAAA,EAAE,EAAEF,YAAhB;AAA8B,UAAA,IAAI,EAAC;AAAnC,UAAP;;AACF,WAAKhC,OAAO,CAACK,YAAR,CAAqB4B,WAArB,GAAmCC,QAAnC,CAA4C,QAA5C,CAAL;AACE,4BAAO,oBAAC,UAAD;AAAY,UAAA,EAAE,EAAEF,YAAhB;AAA8B,UAAA,IAAI,EAAC;AAAnC,UAAP;;AACF,WAAMhC,OAAO,CAACK,YAAR,KAAyB,EAAzB,IAA+BL,OAAO,CAAC+B,MAA7C;AACE,4BAAO;AAAK,UAAA,SAAS,EAAC,iBAAf;AAAiC,UAAA,EAAE,EAAEC;AAArC,UAAP;;AACF;AACE,4BAAO,oBAAC,QAAD;AAAU,UAAA,EAAE,EAAG,GAAEhC,OAAO,CAAC0B,aAAc,mBAAvC;AAA2D,UAAA,IAAI,EAAC;AAAhE,UAAP;AAZJ;AAcD;;AAnK8F;;gBAA7F1C,kB,iBACmBJ,qB;;AAoKxB;AAED,MAAMuD,4BAA4B,GAAG7E,UAAU,CAAC0B,kBAAD,CAA/C;AACA,SAAQmD,4BAA4B,IAAInD,kBAAxC","sourcesContent":["/*\n * Copyright 2019 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\nimport {withRouter, RouteComponentProps} from 'react-router-dom';\n\nimport {\n Button,\n DataList,\n DataListAction,\n DataListItemCells,\n DataListCell,\n DataListItemRow,\n Divider,\n Label,\n PageSection,\n PageSectionVariants,\n Split,\n SplitItem,\n Stack,\n StackItem,\n Title,\n DataListItem,\n} from '@patternfly/react-core';\n\nimport {\n BitbucketIcon,\n CubeIcon,\n GitlabIcon,\n LinkIcon,\n OpenshiftIcon,\n PaypalIcon,\n UnlinkIcon\n} from '@patternfly/react-icons';\n\nimport {HttpResponse} from '../../account-service/account.service';\nimport {AccountServiceContext} from '../../account-service/AccountServiceContext';\nimport {Msg} from '../../widgets/Msg';\nimport {ContentPage} from '../ContentPage';\nimport {createRedirect} from '../../util/RedirectUri';\n\ninterface LinkedAccount {\n connected: boolean;\n social: boolean;\n providerAlias: string;\n providerName: string;\n displayName: string;\n linkedUsername: string;\n}\n\ninterface LinkedAccountsPageProps extends RouteComponentProps {\n}\n\ninterface LinkedAccountsPageState {\n linkedAccounts: LinkedAccount[];\n unLinkedAccounts: LinkedAccount[];\n}\n\n/**\n * @author Stan Silvert\n */\nclass LinkedAccountsPage extends React.Component {\n static contextType = AccountServiceContext;\n context: React.ContextType;\n\n public constructor(props: LinkedAccountsPageProps, context: React.ContextType) {\n super(props);\n this.context = context;\n\n this.state = {\n linkedAccounts: [],\n unLinkedAccounts: []\n }\n\n this.getLinkedAccounts();\n }\n\n private getLinkedAccounts(): void {\n this.context!.doGet(\"/linked-accounts\")\n .then((response: HttpResponse) => {\n console.log({response});\n const linkedAccounts = response.data!.filter((account) => account.connected);\n const unLinkedAccounts = response.data!.filter((account) => !account.connected);\n this.setState({linkedAccounts: linkedAccounts, unLinkedAccounts: unLinkedAccounts});\n });\n }\n\n private unLinkAccount(account: LinkedAccount): void {\n const url = '/linked-accounts/' + account.providerName;\n\n this.context!.doDelete(url)\n .then((response: HttpResponse) => {\n console.log({response});\n this.getLinkedAccounts();\n });\n }\n\n private linkAccount(account: LinkedAccount): void {\n const url = '/linked-accounts/' + account.providerName;\n\n const redirectUri: string = createRedirect(this.props.location.pathname);\n\n this.context!.doGet<{accountLinkUri: string}>(url, { params: {providerId: account.providerName, redirectUri}})\n .then((response: HttpResponse<{accountLinkUri: string}>) => {\n console.log({response});\n window.location.href = response.data!.accountLinkUri;\n });\n }\n\n public render(): React.ReactNode {\n\n return (\n \n \n \n \n \n <Msg msgKey='linkedLoginProviders'/>\n \n \n {this.makeRows(this.state.linkedAccounts, true)}\n \n \n \n \n <Msg msgKey='unlinkedLoginProviders'/>\n \n \n {this.makeRows(this.state.unLinkedAccounts, false)}\n \n \n \n \n \n );\n }\n\n private emptyRow(isLinked: boolean): React.ReactNode {\n let isEmptyMessage = '';\n if (isLinked) {\n isEmptyMessage = Msg.localize('linkedEmpty');\n } else {\n isEmptyMessage = Msg.localize('unlinkedEmpty');\n }\n\n return (\n \n \n {isEmptyMessage}\n ]}/>\n \n \n )\n }\n\n private makeRows(accounts: LinkedAccount[], isLinked: boolean): React.ReactNode {\n if (accounts.length === 0) {\n return this.emptyRow(isLinked);\n }\n\n return (\n <> {\n\n accounts.map( (account: LinkedAccount) => (\n \n \n \n \n {this.findIcon(account)}\n {account.displayName}\n \n ,\n \n \n {this.label(account)}\n \n ,\n \n \n {account.linkedUsername}\n \n ,\n ]}/>\n \n {isLinked && }\n {!isLinked && }\n \n \n \n ))\n\n } \n\n )\n }\n\n private label(account: LinkedAccount): React.ReactNode {\n if (account.social) {\n return ();\n }\n\n return ();\n }\n\n private findIcon(account: LinkedAccount): React.ReactNode {\n const socialIconId = `${account.providerAlias}-idp-icon-social`;\n console.log(account);\n switch (true) {\n case account.providerName.toLowerCase().includes('bitbucket'):\n return ;\n case account.providerName.toLowerCase().includes('openshift'):\n return
    ;\n case account.providerName.toLowerCase().includes('gitlab'):\n return ;\n case account.providerName.toLowerCase().includes('paypal'):\n return ;\n case (account.providerName !== '' && account.social):\n return
    ;\n default:\n return ;\n }\n }\n\n};\n\nconst LinkedAccountsPagewithRouter = withRouter(LinkedAccountsPage);\nexport {LinkedAccountsPagewithRouter as LinkedAccountsPage};\n"],"file":"LinkedAccountsPage.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/AbstractResourceTable.js b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/AbstractResourceTable.js new file mode 100644 index 0000000..9d86dd9 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/AbstractResourceTable.js @@ -0,0 +1,40 @@ +import * as React from "../../../../common/keycloak/web_modules/react.js"; +import { Msg } from "../../widgets/Msg.js"; +export class AbstractResourcesTable extends React.Component { + hasPermissions(row) { + return this.state.permissions.has(row) && this.state.permissions.get(row).length > 0; + } + + firstUser(row) { + if (!this.hasPermissions(row)) return 'ERROR!!!!'; // should never happen + + return this.state.permissions.get(row)[0].username; + } + + numOthers(row) { + if (!this.hasPermissions(row)) return -1; // should never happen + + return this.state.permissions.get(row).length - 1; + } + + sharedWithUsersMessage(row) { + if (!this.hasPermissions(row)) return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Msg, { + msgKey: "resourceNotShared" + })); + return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Msg, { + msgKey: "resourceSharedWith" + }, /*#__PURE__*/React.createElement("strong", null, this.firstUser(row))), this.numOthers(row) > 0 && /*#__PURE__*/React.createElement(Msg, { + msgKey: "and" + }, /*#__PURE__*/React.createElement("strong", null, this.numOthers(row))), "."); + } + + getClientName(client) { + if (client.hasOwnProperty('name') && client.name !== null && client.name !== '') { + return Msg.localize(client.name); + } else { + return client.clientId; + } + } + +} +//# sourceMappingURL=AbstractResourceTable.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/AbstractResourceTable.js.map b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/AbstractResourceTable.js.map new file mode 100644 index 0000000..7ea5943 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/AbstractResourceTable.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/my-resources-page/AbstractResourceTable.tsx"],"names":["React","Msg","AbstractResourcesTable","Component","hasPermissions","row","state","permissions","has","get","length","firstUser","username","numOthers","sharedWithUsersMessage","getClientName","client","hasOwnProperty","name","localize","clientId"],"mappings":"AAAA,OAAO,KAAKA,KAAZ;AAEA,SAASC,GAAT;AAUA,OAAO,MAAeC,sBAAf,SAA6EF,KAAK,CAACG,SAAnF,CAAqH;AAEhHC,EAAAA,cAAc,CAACC,GAAD,EAAuB;AAC7C,WAAQ,KAAKC,KAAL,CAAWC,WAAX,CAAuBC,GAAvB,CAA2BH,GAA3B,CAAD,IAAsC,KAAKC,KAAL,CAAWC,WAAX,CAAuBE,GAAvB,CAA2BJ,GAA3B,EAAiCK,MAAjC,GAA0C,CAAvF;AACD;;AAEOC,EAAAA,SAAS,CAACN,GAAD,EAAsB;AACrC,QAAI,CAAC,KAAKD,cAAL,CAAoBC,GAApB,CAAL,EAA+B,OAAO,WAAP,CADM,CACc;;AAEnD,WAAO,KAAKC,KAAL,CAAWC,WAAX,CAAuBE,GAAvB,CAA2BJ,GAA3B,EAAiC,CAAjC,EAAoCO,QAA3C;AACD;;AAESC,EAAAA,SAAS,CAACR,GAAD,EAAsB;AACvC,QAAI,CAAC,KAAKD,cAAL,CAAoBC,GAApB,CAAL,EAA+B,OAAO,CAAC,CAAR,CADQ,CACG;;AAE1C,WAAO,KAAKC,KAAL,CAAWC,WAAX,CAAuBE,GAAvB,CAA2BJ,GAA3B,EAAiCK,MAAjC,GAA0C,CAAjD;AACD;;AAEMI,EAAAA,sBAAsB,CAACT,GAAD,EAA+B;AAC1D,QAAI,CAAC,KAAKD,cAAL,CAAoBC,GAApB,CAAL,EAA+B,oBAAQ,oBAAC,KAAD,CAAO,QAAP,qBAAgB,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MAAhB,CAAR;AAE/B,wBACE,oBAAC,KAAD,CAAO,QAAP,qBACE,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,oBACE,oCAAS,KAAKM,SAAL,CAAeN,GAAf,CAAT,CADF,CADF,EAIG,KAAKQ,SAAL,CAAeR,GAAf,IAAsB,CAAtB,iBAA2B,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,oBAC1B,oCAAS,KAAKQ,SAAL,CAAeR,GAAf,CAAT,CAD0B,CAJ9B,MADF;AAUD;;AAESU,EAAAA,aAAa,CAACC,MAAD,EAAyB;AAC9C,QAAIA,MAAM,CAACC,cAAP,CAAsB,MAAtB,KAAiCD,MAAM,CAACE,IAAP,KAAgB,IAAjD,IAAyDF,MAAM,CAACE,IAAP,KAAgB,EAA7E,EAAiF;AAC/E,aAAOjB,GAAG,CAACkB,QAAJ,CAAaH,MAAM,CAACE,IAApB,CAAP;AACD,KAFD,MAEO;AACL,aAAOF,MAAM,CAACI,QAAd;AACD;AACF;;AAvCyH","sourcesContent":["import * as React from 'react';\nimport { Permission, PaginatedResources, Client } from './resource-model';\nimport { Msg } from '../../widgets/Msg';\n\nexport interface ResourcesTableProps {\n resources: PaginatedResources;\n}\n\nexport interface ResourcesTableState {\n permissions: Map;\n}\n\nexport abstract class AbstractResourcesTable extends React.Component {\n\n protected hasPermissions(row: number): boolean {\n return (this.state.permissions.has(row)) && (this.state.permissions.get(row)!.length > 0);\n }\n\n private firstUser(row: number): string {\n if (!this.hasPermissions(row)) return 'ERROR!!!!'; // should never happen\n\n return this.state.permissions.get(row)![0].username;\n }\n\n protected numOthers(row: number): number {\n if (!this.hasPermissions(row)) return -1; // should never happen\n\n return this.state.permissions.get(row)!.length - 1;\n }\n\n public sharedWithUsersMessage(row: number): React.ReactNode {\n if (!this.hasPermissions(row)) return ();\n\n return (\n \n \n {this.firstUser(row)}\n \n {this.numOthers(row) > 0 && \n {this.numOthers(row)}\n }.\n \n );\n }\n\n protected getClientName(client: Client): string {\n if (client.hasOwnProperty('name') && client.name !== null && client.name !== '') {\n return Msg.localize(client.name!);\n } else {\n return client.clientId;\n }\n }\n}\n"],"file":"AbstractResourceTable.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/EditTheResource.js b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/EditTheResource.js new file mode 100644 index 0000000..647e121 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/EditTheResource.js @@ -0,0 +1,120 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../../common/keycloak/web_modules/react.js"; +import { Button, Modal, Form, FormGroup, TextInput, InputGroup, ModalVariant } from "../../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { OkIcon } from "../../../../common/keycloak/web_modules/@patternfly/react-icons.js"; +import { Scope } from "./resource-model.js"; +import { Msg } from "../../widgets/Msg.js"; +import { AccountServiceContext } from "../../account-service/AccountServiceContext.js"; +import { ContentAlert } from "../ContentAlert.js"; +import { PermissionSelect } from "./PermissionSelect.js"; +export class EditTheResource extends React.Component { + constructor(props, context) { + super(props); + + _defineProperty(this, "context", void 0); + + _defineProperty(this, "handleToggleDialog", () => { + if (this.state.isOpen) { + this.setState({ + isOpen: false + }); + this.props.onClose(); + } else { + this.clearState(); + this.setState({ + isOpen: true + }); + } + }); + + _defineProperty(this, "updateChanged", row => { + const changed = this.state.changed; + changed[row] = !changed[row]; + this.setState({ + changed + }); + }); + + this.context = context; + this.state = { + changed: [], + isOpen: false + }; + } + + clearState() { + this.setState({}); + } + + async savePermission(permission) { + await this.context.doPut(`/resources/${this.props.resource._id}/permissions`, [permission]); + ContentAlert.success(Msg.localize('updateSuccess')); + } + + render() { + return /*#__PURE__*/React.createElement(React.Fragment, null, this.props.children(this.handleToggleDialog), /*#__PURE__*/React.createElement(Modal, { + title: 'Edit the resource - ' + this.props.resource.name, + variant: ModalVariant.large, + isOpen: this.state.isOpen, + onClose: this.handleToggleDialog, + actions: [/*#__PURE__*/React.createElement(Button, { + key: "done", + variant: "link", + id: "done", + onClick: this.handleToggleDialog + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "done" + }))] + }, /*#__PURE__*/React.createElement(Form, { + isHorizontal: true + }, this.props.permissions.map((p, row) => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(FormGroup, { + fieldId: `username-${row}`, + label: Msg.localize('User') + }, /*#__PURE__*/React.createElement(TextInput, { + id: `username-${row}`, + type: "text", + value: p.username, + isDisabled: true + })), /*#__PURE__*/React.createElement(FormGroup, { + fieldId: `permissions-${row}`, + label: Msg.localize('permissions'), + isRequired: true + }, /*#__PURE__*/React.createElement(InputGroup, null, /*#__PURE__*/React.createElement(PermissionSelect, { + scopes: this.props.resource.scopes, + selected: p.scopes.map(s => new Scope(s)), + direction: row === this.props.permissions.length - 1 ? "up" : "down", + onSelect: selection => { + p.scopes = selection.map(s => s.name); + this.updateChanged(row); + } + }), /*#__PURE__*/React.createElement(Button, { + id: `save-${row}`, + isDisabled: !this.state.changed[row], + onClick: () => this.savePermission(p) + }, /*#__PURE__*/React.createElement(OkIcon, null)))), /*#__PURE__*/React.createElement("hr", null)))))); + } + +} + +_defineProperty(EditTheResource, "defaultProps", { + permissions: [] +}); + +_defineProperty(EditTheResource, "contextType", AccountServiceContext); +//# sourceMappingURL=EditTheResource.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/EditTheResource.js.map b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/EditTheResource.js.map new file mode 100644 index 0000000..05857b0 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/EditTheResource.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/my-resources-page/EditTheResource.tsx"],"names":["React","Button","Modal","Form","FormGroup","TextInput","InputGroup","ModalVariant","OkIcon","Scope","Msg","AccountServiceContext","ContentAlert","PermissionSelect","EditTheResource","Component","constructor","props","context","state","isOpen","setState","onClose","clearState","row","changed","savePermission","permission","doPut","resource","_id","success","localize","render","children","handleToggleDialog","name","large","permissions","map","p","username","scopes","s","length","selection","updateChanged"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AAEA,SACIC,MADJ,EAEIC,KAFJ,EAGIC,IAHJ,EAIIC,SAJJ,EAKIC,SALJ,EAMIC,UANJ,EAOIC,YAPJ;AASA,SAASC,MAAT;AAEA,SAA4CC,KAA5C;AACA,SAASC,GAAT;AACA,SAASC,qBAAT;AACA,SAASC,YAAT;AACA,SAASC,gBAAT;AAcA,OAAO,MAAMC,eAAN,SAA8Bd,KAAK,CAACe,SAApC,CAA0F;AAKtFC,EAAAA,WAAW,CAACC,KAAD,EAA8BC,OAA9B,EAAwF;AACtG,UAAMD,KAAN;;AADsG;;AAAA,gDAc7E,MAAM;AAC/B,UAAI,KAAKE,KAAL,CAAWC,MAAf,EAAuB;AACnB,aAAKC,QAAL,CAAc;AAAED,UAAAA,MAAM,EAAE;AAAV,SAAd;AACA,aAAKH,KAAL,CAAWK,OAAX;AACH,OAHD,MAGO;AACH,aAAKC,UAAL;AACA,aAAKF,QAAL,CAAc;AAAED,UAAAA,MAAM,EAAE;AAAV,SAAd;AACH;AACJ,KAtByG;;AAAA,2CAwBjFI,GAAD,IAAiB;AACrC,YAAMC,OAAO,GAAG,KAAKN,KAAL,CAAWM,OAA3B;AACAA,MAAAA,OAAO,CAACD,GAAD,CAAP,GAAe,CAACC,OAAO,CAACD,GAAD,CAAvB;AACA,WAAKH,QAAL,CAAc;AAAEI,QAAAA;AAAF,OAAd;AACH,KA5ByG;;AAEtG,SAAKP,OAAL,GAAeA,OAAf;AAEA,SAAKC,KAAL,GAAa;AACTM,MAAAA,OAAO,EAAE,EADA;AAETL,MAAAA,MAAM,EAAE;AAFC,KAAb;AAIH;;AAEOG,EAAAA,UAAU,GAAS;AACvB,SAAKF,QAAL,CAAc,EAAd;AACH;;AAkBmB,QAAdK,cAAc,CAACC,UAAD,EAAwC;AACxD,UAAM,KAAKT,OAAL,CAAcU,KAAd,CAAqB,cAAa,KAAKX,KAAL,CAAWY,QAAX,CAAoBC,GAAI,cAA1D,EAAyE,CAACH,UAAD,CAAzE,CAAN;AACAf,IAAAA,YAAY,CAACmB,OAAb,CAAqBrB,GAAG,CAACsB,QAAJ,CAAa,eAAb,CAArB;AACH;;AAEMC,EAAAA,MAAM,GAAoB;AAC7B,wBACI,oBAAC,KAAD,CAAO,QAAP,QACK,KAAKhB,KAAL,CAAWiB,QAAX,CAAoB,KAAKC,kBAAzB,CADL,eAGI,oBAAC,KAAD;AACI,MAAA,KAAK,EAAE,yBAAyB,KAAKlB,KAAL,CAAWY,QAAX,CAAoBO,IADxD;AAEI,MAAA,OAAO,EAAE7B,YAAY,CAAC8B,KAF1B;AAGI,MAAA,MAAM,EAAE,KAAKlB,KAAL,CAAWC,MAHvB;AAII,MAAA,OAAO,EAAE,KAAKe,kBAJlB;AAKI,MAAA,OAAO,EAAE,cACL,oBAAC,MAAD;AAAQ,QAAA,GAAG,EAAC,MAAZ;AAAmB,QAAA,OAAO,EAAC,MAA3B;AAAkC,QAAA,EAAE,EAAC,MAArC;AAA4C,QAAA,OAAO,EAAE,KAAKA;AAA1D,sBACI,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QADJ,CADK;AALb,oBAWI,oBAAC,IAAD;AAAM,MAAA,YAAY;AAAlB,OACK,KAAKlB,KAAL,CAAWqB,WAAX,CAAuBC,GAAvB,CAA2B,CAACC,CAAD,EAAIhB,GAAJ,kBACxB,oBAAC,KAAD,CAAO,QAAP,qBACI,oBAAC,SAAD;AACI,MAAA,OAAO,EAAG,YAAWA,GAAI,EAD7B;AAEI,MAAA,KAAK,EAAEd,GAAG,CAACsB,QAAJ,CAAa,MAAb;AAFX,oBAII,oBAAC,SAAD;AAAW,MAAA,EAAE,EAAG,YAAWR,GAAI,EAA/B;AAAkC,MAAA,IAAI,EAAC,MAAvC;AAA8C,MAAA,KAAK,EAAEgB,CAAC,CAACC,QAAvD;AAAiE,MAAA,UAAU;AAA3E,MAJJ,CADJ,eAQI,oBAAC,SAAD;AACI,MAAA,OAAO,EAAG,eAAcjB,GAAI,EADhC;AAEI,MAAA,KAAK,EAAEd,GAAG,CAACsB,QAAJ,CAAa,aAAb,CAFX;AAGI,MAAA,UAAU;AAHd,oBAKI,oBAAC,UAAD,qBACI,oBAAC,gBAAD;AACI,MAAA,MAAM,EAAE,KAAKf,KAAL,CAAWY,QAAX,CAAoBa,MADhC;AAEI,MAAA,QAAQ,EAAGF,CAAC,CAACE,MAAH,CAAuBH,GAAvB,CAA2BI,CAAC,IAAI,IAAIlC,KAAJ,CAAUkC,CAAV,CAAhC,CAFd;AAGI,MAAA,SAAS,EAAEnB,GAAG,KAAK,KAAKP,KAAL,CAAWqB,WAAX,CAAuBM,MAAvB,GAAgC,CAAxC,GAA4C,IAA5C,GAAmD,MAHlE;AAII,MAAA,QAAQ,EAAEC,SAAS,IAAI;AACnBL,QAAAA,CAAC,CAACE,MAAF,GAAWG,SAAS,CAACN,GAAV,CAAcI,CAAC,IAAIA,CAAC,CAACP,IAArB,CAAX;AACA,aAAKU,aAAL,CAAmBtB,GAAnB;AACH;AAPL,MADJ,eAUI,oBAAC,MAAD;AACI,MAAA,EAAE,EAAG,QAAOA,GAAI,EADpB;AAEI,MAAA,UAAU,EAAE,CAAC,KAAKL,KAAL,CAAWM,OAAX,CAAmBD,GAAnB,CAFjB;AAGI,MAAA,OAAO,EAAE,MAAM,KAAKE,cAAL,CAAoBc,CAApB;AAHnB,oBAKI,oBAAC,MAAD,OALJ,CAVJ,CALJ,CARJ,eAgCI,+BAhCJ,CADH,CADL,CAXJ,CAHJ,CADJ;AAwDH;;AAjG4F;;gBAApF1B,e,kBACmC;AAAEwB,EAAAA,WAAW,EAAE;AAAf,C;;gBADnCxB,e,iBAEYH,qB","sourcesContent":["/*\n * Copyright 2019 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\n\nimport {\n Button,\n Modal,\n Form,\n FormGroup,\n TextInput,\n InputGroup,\n ModalVariant\n} from '@patternfly/react-core';\nimport { OkIcon } from '@patternfly/react-icons';\n\nimport { Resource, Permission, Permissions, Scope } from './resource-model';\nimport { Msg } from '../../widgets/Msg';\nimport { AccountServiceContext } from '../../account-service/AccountServiceContext';\nimport { ContentAlert } from '../ContentAlert';\nimport { PermissionSelect } from './PermissionSelect';\n\ninterface EditTheResourceProps {\n resource: Resource;\n permissions: Permission[];\n onClose: () => void;\n children: (toggle: () => void) => void;\n}\n\ninterface EditTheResourceState {\n changed: boolean[];\n isOpen: boolean;\n}\n\nexport class EditTheResource extends React.Component {\n protected static defaultProps:Permissions = { permissions: [] };\n static contextType = AccountServiceContext;\n context: React.ContextType;\n\n public constructor(props: EditTheResourceProps, context: React.ContextType) {\n super(props);\n this.context = context;\n\n this.state = {\n changed: [],\n isOpen: false,\n };\n }\n\n private clearState(): void {\n this.setState({});\n }\n\n private handleToggleDialog = () => {\n if (this.state.isOpen) {\n this.setState({ isOpen: false });\n this.props.onClose();\n } else {\n this.clearState();\n this.setState({ isOpen: true });\n }\n };\n\n private updateChanged = (row: number) => {\n const changed = this.state.changed;\n changed[row] = !changed[row];\n this.setState({ changed });\n }\n\n async savePermission(permission: Permission): Promise {\n await this.context!.doPut(`/resources/${this.props.resource._id}/permissions`, [permission]);\n ContentAlert.success(Msg.localize('updateSuccess'));\n }\n\n public render(): React.ReactNode {\n return (\n \n {this.props.children(this.handleToggleDialog)}\n\n \n \n ,\n ]}\n >\n
    \n {this.props.permissions.map((p, row) => (\n \n \n \n\n \n \n \n new Scope(s))}\n direction={row === this.props.permissions.length - 1 ? \"up\" : \"down\"}\n onSelect={selection => {\n p.scopes = selection.map(s => s.name);\n this.updateChanged(row);\n }}\n />\n this.savePermission(p)}\n >\n \n \n \n \n
    \n
    \n ))}\n
    \n \n
    \n );\n }\n}\n"],"file":"EditTheResource.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/MyResourcesPage.js b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/MyResourcesPage.js new file mode 100644 index 0000000..dc012a0 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/MyResourcesPage.js @@ -0,0 +1,284 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../../common/keycloak/web_modules/react.js"; +import parse from "../../util/ParseLink.js"; +import { Button, Level, LevelItem, PageSection, PageSectionVariants, Stack, StackItem, Tab, Tabs, TextInput } from "../../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { AccountServiceContext } from "../../account-service/AccountServiceContext.js"; +import { Scope } from "./resource-model.js"; +import { ResourcesTable } from "./ResourcesTable.js"; +import { ContentPage } from "../ContentPage.js"; +import { Msg } from "../../widgets/Msg.js"; +import { SharedResourcesTable } from "./SharedResourcesTable.js"; +const MY_RESOURCES_TAB = 0; +const SHARED_WITH_ME_TAB = 1; +export class MyResourcesPage extends React.Component { + constructor(props, context) { + super(props); + + _defineProperty(this, "context", void 0); + + _defineProperty(this, "first", 0); + + _defineProperty(this, "max", 5); + + _defineProperty(this, "makeScopeObj", scope => { + return new Scope(scope.name, scope.displayName); + }); + + _defineProperty(this, "fetchPermissionRequests", () => { + this.state.myResources.data.forEach(resource => { + this.fetchShareRequests(resource); + }); + }); + + _defineProperty(this, "fetchPending", async () => { + const response = await this.context.doGet(`/resources/pending-requests`); + const resources = response.data || []; + resources.forEach(pendingRequest => { + this.state.sharedWithMe.data.forEach(resource => { + if (resource._id === pendingRequest._id) { + resource.shareRequests = [{ + username: 'me', + scopes: pendingRequest.scopes + }]; + this.forceUpdate(); + } + }); + }); + }); + + _defineProperty(this, "handleFilterRequest", value => { + this.setState({ + nameFilter: value + }); + this.fetchFilteredResources({ + name: value + }); + }); + + _defineProperty(this, "handleFirstPageClick", () => { + this.fetchInitialResources(); + }); + + _defineProperty(this, "handleNextClick", () => { + if (this.isSharedWithMeTab()) { + this.fetchResources(this.state.sharedWithMe.nextUrl); + } else { + this.fetchResources(this.state.myResources.nextUrl); + } + }); + + _defineProperty(this, "handlePreviousClick", () => { + if (this.isSharedWithMeTab()) { + this.fetchResources(this.state.sharedWithMe.prevUrl); + } else { + this.fetchResources(this.state.myResources.prevUrl); + } + }); + + _defineProperty(this, "handleTabClick", (event, tabIndex) => { + if (this.state.activeTabKey === tabIndex) return; + this.setState({ + nameFilter: '', + activeTabKey: tabIndex + }, () => { + this.fetchInitialResources(); + }); + }); + + this.context = context; + this.state = { + activeTabKey: MY_RESOURCES_TAB, + nameFilter: '', + isModalOpen: false, + myResources: { + nextUrl: '', + prevUrl: '', + data: [] + }, + sharedWithMe: { + nextUrl: '', + prevUrl: '', + data: [] + } + }; + this.fetchInitialResources(); + } + + isSharedWithMeTab() { + return this.state.activeTabKey === SHARED_WITH_ME_TAB; + } + + hasNext() { + if (this.isSharedWithMeTab()) { + return this.state.sharedWithMe.nextUrl !== null && this.state.sharedWithMe.nextUrl !== ''; + } else { + return this.state.myResources.nextUrl !== null && this.state.myResources.nextUrl !== ''; + } + } + + hasPrevious() { + if (this.isSharedWithMeTab()) { + return this.state.sharedWithMe.prevUrl !== null && this.state.sharedWithMe.prevUrl !== ''; + } else { + return this.state.myResources.prevUrl !== null && this.state.myResources.prevUrl !== ''; + } + } + + fetchInitialResources() { + if (this.isSharedWithMeTab()) { + this.fetchResources("/resources/shared-with-me"); + } else { + this.fetchResources("/resources", { + first: this.first, + max: this.max + }); + } + } + + fetchFilteredResources(params) { + if (this.isSharedWithMeTab()) { + this.fetchResources("/resources/shared-with-me", params); + } else { + this.fetchResources("/resources", { ...params, + first: this.first, + max: this.max + }); + } + } + + fetchResources(url, extraParams) { + this.context.doGet(url, { + params: extraParams + }).then(response => { + const resources = response.data || []; + resources.forEach(resource => resource.shareRequests = []); // serialize the Scope objects from JSON so that toString() will work. + + resources.forEach(resource => resource.scopes = resource.scopes.map(this.makeScopeObj)); + + if (this.isSharedWithMeTab()) { + this.setState({ + sharedWithMe: this.parseResourceResponse(response) + }, this.fetchPending); + } else { + this.setState({ + myResources: this.parseResourceResponse(response) + }, this.fetchPermissionRequests); + } + }); + } + + fetchShareRequests(resource) { + this.context.doGet('/resources/' + resource._id + '/permissions/requests').then(response => { + resource.shareRequests = response.data || []; + + if (resource.shareRequests.length > 0) { + this.forceUpdate(); + } + }); + } + + parseResourceResponse(response) { + const links = response.headers.get('link') || undefined; + const parsed = parse(links); + let next = ''; + let prev = ''; + + if (parsed !== null) { + if (parsed.next) next = parsed.next; + if (parsed.prev) prev = parsed.prev; + } + + const resources = response.data || []; + return { + nextUrl: next, + prevUrl: prev, + data: resources + }; + } + + makeTab(eventKey, title, resources, sharedResourcesTab) { + return /*#__PURE__*/React.createElement(Tab, { + id: title, + eventKey: eventKey, + title: Msg.localize(title) + }, /*#__PURE__*/React.createElement(Stack, { + hasGutter: true + }, /*#__PURE__*/React.createElement(StackItem, { + isFilled: true + }, /*#__PURE__*/React.createElement("span", null)), /*#__PURE__*/React.createElement(StackItem, { + isFilled: true + }, /*#__PURE__*/React.createElement(Level, { + hasGutter: true + }, /*#__PURE__*/React.createElement(LevelItem, null, /*#__PURE__*/React.createElement(TextInput, { + value: this.state.nameFilter, + onChange: this.handleFilterRequest, + id: 'filter-' + title, + type: "text", + placeholder: Msg.localize('filterByName'), + iconVariant: "search" + })))), /*#__PURE__*/React.createElement(StackItem, { + isFilled: true + }, !sharedResourcesTab && /*#__PURE__*/React.createElement(ResourcesTable, { + resources: resources + }), sharedResourcesTab && /*#__PURE__*/React.createElement(SharedResourcesTable, { + resources: resources + })))); + } + + render() { + return /*#__PURE__*/React.createElement(ContentPage, { + title: "resources", + onRefresh: this.fetchInitialResources.bind(this) + }, /*#__PURE__*/React.createElement(PageSection, { + variant: PageSectionVariants.light + }, /*#__PURE__*/React.createElement(Tabs, { + activeKey: this.state.activeTabKey, + onSelect: this.handleTabClick + }, this.makeTab(0, 'myResources', this.state.myResources, false), this.makeTab(1, 'sharedwithMe', this.state.sharedWithMe, true)), /*#__PURE__*/React.createElement(Level, { + hasGutter: true + }, /*#__PURE__*/React.createElement(LevelItem, null, this.hasPrevious() && /*#__PURE__*/React.createElement(Button, { + onClick: this.handlePreviousClick + }, "<", /*#__PURE__*/React.createElement(Msg, { + msgKey: "previousPage" + }))), /*#__PURE__*/React.createElement(LevelItem, null, this.hasPrevious() && /*#__PURE__*/React.createElement(Button, { + onClick: this.handleFirstPageClick + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "firstPage" + }))), /*#__PURE__*/React.createElement(LevelItem, null, this.hasNext() && /*#__PURE__*/React.createElement(Button, { + onClick: this.handleNextClick + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "nextPage" + }), ">"))))); + } + + clearNextPrev() { + const newMyResources = this.state.myResources; + newMyResources.nextUrl = ''; + newMyResources.prevUrl = ''; + this.setState({ + myResources: newMyResources + }); + } + +} + +_defineProperty(MyResourcesPage, "contextType", AccountServiceContext); + +; +//# sourceMappingURL=MyResourcesPage.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/MyResourcesPage.js.map b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/MyResourcesPage.js.map new file mode 100644 index 0000000..629d859 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/MyResourcesPage.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/my-resources-page/MyResourcesPage.tsx"],"names":["React","parse","Button","Level","LevelItem","PageSection","PageSectionVariants","Stack","StackItem","Tab","Tabs","TextInput","AccountServiceContext","Scope","ResourcesTable","ContentPage","Msg","SharedResourcesTable","MY_RESOURCES_TAB","SHARED_WITH_ME_TAB","MyResourcesPage","Component","constructor","props","context","scope","name","displayName","state","myResources","data","forEach","resource","fetchShareRequests","response","doGet","resources","pendingRequest","sharedWithMe","_id","shareRequests","username","scopes","forceUpdate","value","setState","nameFilter","fetchFilteredResources","fetchInitialResources","isSharedWithMeTab","fetchResources","nextUrl","prevUrl","event","tabIndex","activeTabKey","isModalOpen","hasNext","hasPrevious","first","max","params","url","extraParams","then","map","makeScopeObj","parseResourceResponse","fetchPending","fetchPermissionRequests","length","links","headers","get","undefined","parsed","next","prev","makeTab","eventKey","title","sharedResourcesTab","localize","handleFilterRequest","render","bind","light","handleTabClick","handlePreviousClick","handleFirstPageClick","handleNextClick","clearNextPrev","newMyResources"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AAEA,OAAOC,KAAP;AAEA,SACIC,MADJ,EAEIC,KAFJ,EAGIC,SAHJ,EAIIC,WAJJ,EAKIC,mBALJ,EAMIC,KANJ,EAOIC,SAPJ,EAQIC,GARJ,EASIC,IATJ,EAUIC,SAVJ;AAcA,SAAQC,qBAAR;AAEA,SAAuCC,KAAvC;AACA,SAAQC,cAAR;AACA,SAAQC,WAAR;AACA,SAAQC,GAAR;AACA,SAASC,oBAAT;AAaA,MAAMC,gBAAgB,GAAG,CAAzB;AACA,MAAMC,kBAAkB,GAAG,CAA3B;AAEA,OAAO,MAAMC,eAAN,SAA8BpB,KAAK,CAACqB,SAApC,CAA0F;AAMtFC,EAAAA,WAAW,CAACC,KAAD,EAA8BC,OAA9B,EAAwF;AACtG,UAAMD,KAAN;;AADsG;;AAAA,mCAH1F,CAG0F;;AAAA,iCAF5F,CAE4F;;AAAA,0CAoElFE,KAAD,IAAyB;AAC5C,aAAO,IAAIZ,KAAJ,CAAUY,KAAK,CAACC,IAAhB,EAAsBD,KAAK,CAACE,WAA5B,CAAP;AACH,KAtEyG;;AAAA,qDAwExE,MAAM;AACpC,WAAKC,KAAL,CAAWC,WAAX,CAAuBC,IAAvB,CAA4BC,OAA5B,CAAqCC,QAAD,IAAwB;AACxD,aAAKC,kBAAL,CAAwBD,QAAxB;AACH,OAFD;AAGH,KA5EyG;;AAAA,0CAwFnF,YAAY;AAC/B,YAAME,QAAkC,GAAG,MAAM,KAAKV,OAAL,CAAcW,KAAd,CAAqB,6BAArB,CAAjD;AACA,YAAMC,SAAqB,GAAGF,QAAQ,CAACJ,IAAT,IAAiB,EAA/C;AACAM,MAAAA,SAAS,CAACL,OAAV,CAAmBM,cAAD,IAA8B;AAC5C,aAAKT,KAAL,CAAWU,YAAX,CAAwBR,IAAxB,CAA6BC,OAA7B,CAAqCC,QAAQ,IAAI;AAC7C,cAAIA,QAAQ,CAACO,GAAT,KAAiBF,cAAc,CAACE,GAApC,EAAyC;AACrCP,YAAAA,QAAQ,CAACQ,aAAT,GAAyB,CAAC;AAACC,cAAAA,QAAQ,EAAE,IAAX;AAAiBC,cAAAA,MAAM,EAAEL,cAAc,CAACK;AAAxC,aAAD,CAAzB;AACA,iBAAKC,WAAL;AACH;AACJ,SALD;AAMH,OAPD;AAQH,KAnGyG;;AAAA,iDAsK3EC,KAAD,IAAmB;AAC7C,WAAKC,QAAL,CAAc;AAACC,QAAAA,UAAU,EAAEF;AAAb,OAAd;AACA,WAAKG,sBAAL,CAA4B;AAACrB,QAAAA,IAAI,EAAEkB;AAAP,OAA5B;AACH,KAzKyG;;AAAA,kDAkL3E,MAAM;AACjC,WAAKI,qBAAL;AACH,KApLyG;;AAAA,6CAsLhF,MAAM;AAC5B,UAAI,KAAKC,iBAAL,EAAJ,EAA8B;AAC1B,aAAKC,cAAL,CAAoB,KAAKtB,KAAL,CAAWU,YAAX,CAAwBa,OAA5C;AACH,OAFD,MAEO;AACH,aAAKD,cAAL,CAAoB,KAAKtB,KAAL,CAAWC,WAAX,CAAuBsB,OAA3C;AACH;AACJ,KA5LyG;;AAAA,iDA8L5E,MAAM;AAChC,UAAI,KAAKF,iBAAL,EAAJ,EAA8B;AAC1B,aAAKC,cAAL,CAAoB,KAAKtB,KAAL,CAAWU,YAAX,CAAwBc,OAA5C;AACH,OAFD,MAEO;AACH,aAAKF,cAAL,CAAoB,KAAKtB,KAAL,CAAWC,WAAX,CAAuBuB,OAA3C;AACH;AACJ,KApMyG;;AAAA,4CAsMjF,CAACC,KAAD,EAA4CC,QAA5C,KAAiE;AACtF,UAAI,KAAK1B,KAAL,CAAW2B,YAAX,KAA4BD,QAAhC,EAA0C;AAE1C,WAAKT,QAAL,CAAc;AACVC,QAAAA,UAAU,EAAE,EADF;AAEVS,QAAAA,YAAY,EAAED;AAFJ,OAAd,EAGG,MAAM;AAAC,aAAKN,qBAAL;AAA6B,OAHvC;AAIH,KA7MyG;;AAEtG,SAAKxB,OAAL,GAAeA,OAAf;AAEA,SAAKI,KAAL,GAAa;AACT2B,MAAAA,YAAY,EAAErC,gBADL;AAET4B,MAAAA,UAAU,EAAE,EAFH;AAGTU,MAAAA,WAAW,EAAE,KAHJ;AAIT3B,MAAAA,WAAW,EAAE;AAACsB,QAAAA,OAAO,EAAE,EAAV;AAAcC,QAAAA,OAAO,EAAE,EAAvB;AAA2BtB,QAAAA,IAAI,EAAE;AAAjC,OAJJ;AAKTQ,MAAAA,YAAY,EAAE;AAACa,QAAAA,OAAO,EAAE,EAAV;AAAcC,QAAAA,OAAO,EAAE,EAAvB;AAA2BtB,QAAAA,IAAI,EAAE;AAAjC;AALL,KAAb;AAQA,SAAKkB,qBAAL;AACH;;AAEOC,EAAAA,iBAAiB,GAAY;AACjC,WAAO,KAAKrB,KAAL,CAAW2B,YAAX,KAA4BpC,kBAAnC;AACH;;AAEOsC,EAAAA,OAAO,GAAY;AACvB,QAAI,KAAKR,iBAAL,EAAJ,EAA8B;AAC1B,aAAQ,KAAKrB,KAAL,CAAWU,YAAX,CAAwBa,OAAxB,KAAoC,IAArC,IAA+C,KAAKvB,KAAL,CAAWU,YAAX,CAAwBa,OAAxB,KAAoC,EAA1F;AACH,KAFD,MAEO;AACH,aAAQ,KAAKvB,KAAL,CAAWC,WAAX,CAAuBsB,OAAvB,KAAmC,IAApC,IAA8C,KAAKvB,KAAL,CAAWC,WAAX,CAAuBsB,OAAvB,KAAmC,EAAxF;AACH;AACJ;;AAEOO,EAAAA,WAAW,GAAY;AAC3B,QAAI,KAAKT,iBAAL,EAAJ,EAA8B;AAC1B,aAAQ,KAAKrB,KAAL,CAAWU,YAAX,CAAwBc,OAAxB,KAAoC,IAArC,IAA+C,KAAKxB,KAAL,CAAWU,YAAX,CAAwBc,OAAxB,KAAoC,EAA1F;AACH,KAFD,MAEO;AACH,aAAQ,KAAKxB,KAAL,CAAWC,WAAX,CAAuBuB,OAAvB,KAAmC,IAApC,IAA8C,KAAKxB,KAAL,CAAWC,WAAX,CAAuBuB,OAAvB,KAAmC,EAAxF;AACH;AACJ;;AAEOJ,EAAAA,qBAAqB,GAAS;AAClC,QAAI,KAAKC,iBAAL,EAAJ,EAA8B;AAC1B,WAAKC,cAAL,CAAoB,2BAApB;AACH,KAFD,MAEO;AACH,WAAKA,cAAL,CAAoB,YAApB,EAAkC;AAACS,QAAAA,KAAK,EAAE,KAAKA,KAAb;AAAoBC,QAAAA,GAAG,EAAE,KAAKA;AAA9B,OAAlC;AACH;AACJ;;AAEOb,EAAAA,sBAAsB,CAACc,MAAD,EAA8C;AACxE,QAAI,KAAKZ,iBAAL,EAAJ,EAA8B;AAC1B,WAAKC,cAAL,CAAoB,2BAApB,EAAiDW,MAAjD;AACH,KAFD,MAEO;AACH,WAAKX,cAAL,CAAoB,YAApB,EAAkC,EAAC,GAAGW,MAAJ;AAAYF,QAAAA,KAAK,EAAE,KAAKA,KAAxB;AAA+BC,QAAAA,GAAG,EAAE,KAAKA;AAAzC,OAAlC;AACH;AACJ;;AAEOV,EAAAA,cAAc,CAACY,GAAD,EAAcC,WAAd,EAAiE;AACnF,SAAKvC,OAAL,CAAcW,KAAd,CAAgC2B,GAAhC,EAAqC;AAACD,MAAAA,MAAM,EAAEE;AAAT,KAArC,EACKC,IADL,CACW9B,QAAD,IAAwC;AAC1C,YAAME,SAAqB,GAAGF,QAAQ,CAACJ,IAAT,IAAiB,EAA/C;AACAM,MAAAA,SAAS,CAACL,OAAV,CAAmBC,QAAD,IAAwBA,QAAQ,CAACQ,aAAT,GAAyB,EAAnE,EAF0C,CAI1C;;AACAJ,MAAAA,SAAS,CAACL,OAAV,CAAmBC,QAAD,IAAwBA,QAAQ,CAACU,MAAT,GAAkBV,QAAQ,CAACU,MAAT,CAAgBuB,GAAhB,CAAoB,KAAKC,YAAzB,CAA5D;;AAEA,UAAI,KAAKjB,iBAAL,EAAJ,EAA8B;AAC1B,aAAKJ,QAAL,CAAc;AAACP,UAAAA,YAAY,EAAE,KAAK6B,qBAAL,CAA2BjC,QAA3B;AAAf,SAAd,EAAoE,KAAKkC,YAAzE;AACH,OAFD,MAEO;AACH,aAAKvB,QAAL,CAAc;AAAChB,UAAAA,WAAW,EAAE,KAAKsC,qBAAL,CAA2BjC,QAA3B;AAAd,SAAd,EAAmE,KAAKmC,uBAAxE;AACH;AACJ,KAbL;AAcH;;AAYOpC,EAAAA,kBAAkB,CAACD,QAAD,EAA2B;AACjD,SAAKR,OAAL,CAAcW,KAAd,CAAoB,gBAAgBH,QAAQ,CAACO,GAAzB,GAA+B,uBAAnD,EACKyB,IADL,CACW9B,QAAD,IAA0C;AAC5CF,MAAAA,QAAQ,CAACQ,aAAT,GAAyBN,QAAQ,CAACJ,IAAT,IAAiB,EAA1C;;AACA,UAAIE,QAAQ,CAACQ,aAAT,CAAuB8B,MAAvB,GAAgC,CAApC,EAAuC;AACnC,aAAK3B,WAAL;AACH;AACJ,KANL;AAOH;;AAeOwB,EAAAA,qBAAqB,CAACjC,QAAD,EAAyD;AAClF,UAAMqC,KAAyB,GAAGrC,QAAQ,CAACsC,OAAT,CAAiBC,GAAjB,CAAqB,MAArB,KAAgCC,SAAlE;AACA,UAAMC,MAAM,GAAG1E,KAAK,CAACsE,KAAD,CAApB;AAEA,QAAIK,IAAI,GAAG,EAAX;AACA,QAAIC,IAAI,GAAG,EAAX;;AAEA,QAAIF,MAAM,KAAK,IAAf,EAAqB;AACjB,UAAIA,MAAM,CAACC,IAAX,EAAiBA,IAAI,GAAGD,MAAM,CAACC,IAAd;AACjB,UAAID,MAAM,CAACE,IAAX,EAAiBA,IAAI,GAAGF,MAAM,CAACE,IAAd;AACpB;;AAED,UAAMzC,SAAqB,GAAGF,QAAQ,CAACJ,IAAT,IAAiB,EAA/C;AAEA,WAAO;AAACqB,MAAAA,OAAO,EAAEyB,IAAV;AAAgBxB,MAAAA,OAAO,EAAEyB,IAAzB;AAA+B/C,MAAAA,IAAI,EAAEM;AAArC,KAAP;AACH;;AAEO0C,EAAAA,OAAO,CAACC,QAAD,EAAmBC,KAAnB,EAAkC5C,SAAlC,EAAiE6C,kBAAjE,EAA+G;AAC1H,wBACI,oBAAC,GAAD;AAAK,MAAA,EAAE,EAAED,KAAT;AAAgB,MAAA,QAAQ,EAAED,QAA1B;AAAoC,MAAA,KAAK,EAAE/D,GAAG,CAACkE,QAAJ,CAAaF,KAAb;AAA3C,oBACI,oBAAC,KAAD;AAAO,MAAA,SAAS;AAAhB,oBACI,oBAAC,SAAD;AAAW,MAAA,QAAQ;AAAnB,oBAAoB,iCAApB,CADJ,eAEI,oBAAC,SAAD;AAAW,MAAA,QAAQ;AAAnB,oBACI,oBAAC,KAAD;AAAO,MAAA,SAAS;AAAhB,oBACI,oBAAC,SAAD,qBACI,oBAAC,SAAD;AAAW,MAAA,KAAK,EAAE,KAAKpD,KAAL,CAAWkB,UAA7B;AAAyC,MAAA,QAAQ,EAAE,KAAKqC,mBAAxD;AAA6E,MAAA,EAAE,EAAE,YAAYH,KAA7F;AAAoG,MAAA,IAAI,EAAC,MAAzG;AAAgH,MAAA,WAAW,EAAEhE,GAAG,CAACkE,QAAJ,CAAa,cAAb,CAA7H;AAA2J,MAAA,WAAW,EAAC;AAAvK,MADJ,CADJ,CADJ,CAFJ,eASI,oBAAC,SAAD;AAAW,MAAA,QAAQ;AAAnB,OACK,CAACD,kBAAD,iBAAuB,oBAAC,cAAD;AAAgB,MAAA,SAAS,EAAE7C;AAA3B,MAD5B,EAEK6C,kBAAkB,iBAAI,oBAAC,oBAAD;AAAsB,MAAA,SAAS,EAAE7C;AAAjC,MAF3B,CATJ,CADJ,CADJ;AAkBH;;AAEMgD,EAAAA,MAAM,GAAoB;AAC7B,wBACI,oBAAC,WAAD;AAAa,MAAA,KAAK,EAAC,WAAnB;AAA+B,MAAA,SAAS,EAAE,KAAKpC,qBAAL,CAA2BqC,IAA3B,CAAgC,IAAhC;AAA1C,oBACI,oBAAC,WAAD;AAAa,MAAA,OAAO,EAAE/E,mBAAmB,CAACgF;AAA1C,oBACI,oBAAC,IAAD;AAAM,MAAA,SAAS,EAAE,KAAK1D,KAAL,CAAW2B,YAA5B;AAA0C,MAAA,QAAQ,EAAE,KAAKgC;AAAzD,OACK,KAAKT,OAAL,CAAa,CAAb,EAAgB,aAAhB,EAA+B,KAAKlD,KAAL,CAAWC,WAA1C,EAAuD,KAAvD,CADL,EAEK,KAAKiD,OAAL,CAAa,CAAb,EAAgB,cAAhB,EAAgC,KAAKlD,KAAL,CAAWU,YAA3C,EAAyD,IAAzD,CAFL,CADJ,eAMI,oBAAC,KAAD;AAAO,MAAA,SAAS;AAAhB,oBACI,oBAAC,SAAD,QACK,KAAKoB,WAAL,mBAAsB,oBAAC,MAAD;AAAQ,MAAA,OAAO,EAAE,KAAK8B;AAAtB,yBAA+C,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MAA/C,CAD3B,CADJ,eAKI,oBAAC,SAAD,QACK,KAAK9B,WAAL,mBAAsB,oBAAC,MAAD;AAAQ,MAAA,OAAO,EAAE,KAAK+B;AAAtB,oBAA4C,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MAA5C,CAD3B,CALJ,eASI,oBAAC,SAAD,QACK,KAAKhC,OAAL,mBAAkB,oBAAC,MAAD;AAAQ,MAAA,OAAO,EAAE,KAAKiC;AAAtB,oBAAuC,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MAAvC,MADvB,CATJ,CANJ,CADJ,CADJ;AAwBH;;AAOOC,EAAAA,aAAa,GAAS;AAC1B,UAAMC,cAAkC,GAAG,KAAKhE,KAAL,CAAWC,WAAtD;AACA+D,IAAAA,cAAc,CAACzC,OAAf,GAAyB,EAAzB;AACAyC,IAAAA,cAAc,CAACxC,OAAf,GAAyB,EAAzB;AACA,SAAKP,QAAL,CAAc;AAAChB,MAAAA,WAAW,EAAE+D;AAAd,KAAd;AACH;;AAtL4F;;gBAApFxE,e,iBACYR,qB;;AAmNxB","sourcesContent":["/*\n * Copyright 2018 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\n\nimport parse from '../../util/ParseLink';\n\nimport {\n Button,\n Level,\n LevelItem,\n PageSection,\n PageSectionVariants,\n Stack,\n StackItem,\n Tab,\n Tabs,\n TextInput\n} from '@patternfly/react-core';\n\nimport {HttpResponse} from '../../account-service/account.service';\nimport {AccountServiceContext} from '../../account-service/AccountServiceContext';\n\nimport { PaginatedResources, Resource, Scope, Permission } from './resource-model';\nimport {ResourcesTable} from './ResourcesTable';\nimport {ContentPage} from '../ContentPage';\nimport {Msg} from '../../widgets/Msg';\nimport { SharedResourcesTable } from './SharedResourcesTable';\n\nexport interface MyResourcesPageProps {\n}\n\nexport interface MyResourcesPageState {\n activeTabKey: number;\n isModalOpen: boolean;\n nameFilter: string;\n myResources: PaginatedResources;\n sharedWithMe: PaginatedResources;\n}\n\nconst MY_RESOURCES_TAB = 0;\nconst SHARED_WITH_ME_TAB = 1;\n\nexport class MyResourcesPage extends React.Component {\n static contextType = AccountServiceContext;\n context: React.ContextType;\n private first = 0;\n private max = 5;\n\n public constructor(props: MyResourcesPageProps, context: React.ContextType) {\n super(props);\n this.context = context;\n\n this.state = {\n activeTabKey: MY_RESOURCES_TAB,\n nameFilter: '',\n isModalOpen: false,\n myResources: {nextUrl: '', prevUrl: '', data: []},\n sharedWithMe: {nextUrl: '', prevUrl: '', data: []}\n };\n\n this.fetchInitialResources();\n }\n\n private isSharedWithMeTab(): boolean {\n return this.state.activeTabKey === SHARED_WITH_ME_TAB;\n }\n\n private hasNext(): boolean {\n if (this.isSharedWithMeTab()) {\n return (this.state.sharedWithMe.nextUrl !== null) && (this.state.sharedWithMe.nextUrl !== '');\n } else {\n return (this.state.myResources.nextUrl !== null) && (this.state.myResources.nextUrl !== '');\n }\n }\n\n private hasPrevious(): boolean {\n if (this.isSharedWithMeTab()) {\n return (this.state.sharedWithMe.prevUrl !== null) && (this.state.sharedWithMe.prevUrl !== '');\n } else {\n return (this.state.myResources.prevUrl !== null) && (this.state.myResources.prevUrl !== '');\n }\n }\n\n private fetchInitialResources(): void {\n if (this.isSharedWithMeTab()) {\n this.fetchResources(\"/resources/shared-with-me\");\n } else {\n this.fetchResources(\"/resources\", {first: this.first, max: this.max});\n }\n }\n\n private fetchFilteredResources(params: Record): void {\n if (this.isSharedWithMeTab()) {\n this.fetchResources(\"/resources/shared-with-me\", params);\n } else {\n this.fetchResources(\"/resources\", {...params, first: this.first, max: this.max});\n }\n }\n\n private fetchResources(url: string, extraParams?: Record): void {\n this.context!.doGet(url, {params: extraParams})\n .then((response: HttpResponse) => {\n const resources: Resource[] = response.data || [];\n resources.forEach((resource: Resource) => resource.shareRequests = []);\n\n // serialize the Scope objects from JSON so that toString() will work.\n resources.forEach((resource: Resource) => resource.scopes = resource.scopes.map(this.makeScopeObj));\n\n if (this.isSharedWithMeTab()) {\n this.setState({sharedWithMe: this.parseResourceResponse(response)}, this.fetchPending);\n } else {\n this.setState({myResources: this.parseResourceResponse(response)}, this.fetchPermissionRequests);\n }\n });\n }\n\n private makeScopeObj = (scope: Scope): Scope => {\n return new Scope(scope.name, scope.displayName);\n }\n\n private fetchPermissionRequests = () => {\n this.state.myResources.data.forEach((resource: Resource) => {\n this.fetchShareRequests(resource);\n });\n }\n\n private fetchShareRequests(resource: Resource): void {\n this.context!.doGet('/resources/' + resource._id + '/permissions/requests')\n .then((response: HttpResponse) => {\n resource.shareRequests = response.data || [];\n if (resource.shareRequests.length > 0) {\n this.forceUpdate();\n }\n });\n }\n\n private fetchPending = async () => {\n const response: HttpResponse = await this.context!.doGet(`/resources/pending-requests`);\n const resources: Resource[] = response.data || [];\n resources.forEach((pendingRequest: Resource) => {\n this.state.sharedWithMe.data.forEach(resource => {\n if (resource._id === pendingRequest._id) {\n resource.shareRequests = [{username: 'me', scopes: pendingRequest.scopes}]\n this.forceUpdate();\n }\n });\n });\n }\n\n private parseResourceResponse(response: HttpResponse): PaginatedResources {\n const links: string | undefined = response.headers.get('link') || undefined;\n const parsed = parse(links);\n\n let next = '';\n let prev = '';\n\n if (parsed !== null) {\n if (parsed.next) next = parsed.next;\n if (parsed.prev) prev = parsed.prev;\n }\n\n const resources: Resource[] = response.data || [];\n\n return {nextUrl: next, prevUrl: prev, data: resources};\n }\n\n private makeTab(eventKey: number, title: string, resources: PaginatedResources, sharedResourcesTab: boolean): React.ReactNode {\n return (\n \n \n \n \n \n \n \n \n \n \n \n {!sharedResourcesTab && }\n {sharedResourcesTab && }\n \n \n \n )\n }\n\n public render(): React.ReactNode {\n return (\n \n \n \n {this.makeTab(0, 'myResources', this.state.myResources, false)}\n {this.makeTab(1, 'sharedwithMe', this.state.sharedWithMe, true)}\n \n\n \n \n {this.hasPrevious() && }\n \n\n \n {this.hasPrevious() && }\n \n\n \n {this.hasNext() && }\n \n \n \n \n );\n }\n\n private handleFilterRequest = (value: string) => {\n this.setState({nameFilter: value});\n this.fetchFilteredResources({name: value});\n }\n\n private clearNextPrev(): void {\n const newMyResources: PaginatedResources = this.state.myResources;\n newMyResources.nextUrl = '';\n newMyResources.prevUrl = '';\n this.setState({myResources: newMyResources});\n }\n\n private handleFirstPageClick = () => {\n this.fetchInitialResources();\n }\n\n private handleNextClick = () => {\n if (this.isSharedWithMeTab()) {\n this.fetchResources(this.state.sharedWithMe.nextUrl);\n } else {\n this.fetchResources(this.state.myResources.nextUrl);\n }\n }\n\n private handlePreviousClick = () => {\n if (this.isSharedWithMeTab()) {\n this.fetchResources(this.state.sharedWithMe.prevUrl);\n } else {\n this.fetchResources(this.state.myResources.prevUrl);\n }\n }\n\n private handleTabClick = (event: React.MouseEvent, tabIndex: number) => {\n if (this.state.activeTabKey === tabIndex) return;\n\n this.setState({\n nameFilter: '',\n activeTabKey: tabIndex\n }, () => {this.fetchInitialResources()});\n };\n};\n"],"file":"MyResourcesPage.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/PermissionRequest.js b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/PermissionRequest.js new file mode 100644 index 0000000..ea06e51 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/PermissionRequest.js @@ -0,0 +1,151 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../../common/keycloak/web_modules/react.js"; +import { Button, Modal, Text, Badge, DataListItem, DataList, TextVariants, DataListItemRow, DataListItemCells, DataListCell, Chip, Split, SplitItem, ModalVariant } from "../../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { UserCheckIcon } from "../../../../common/keycloak/web_modules/@patternfly/react-icons.js"; +import { AccountServiceContext } from "../../account-service/AccountServiceContext.js"; +import { Msg } from "../../widgets/Msg.js"; +import { ContentAlert } from "../ContentAlert.js"; +export class PermissionRequest extends React.Component { + constructor(props, context) { + super(props); + + _defineProperty(this, "context", void 0); + + _defineProperty(this, "handleApprove", async (shareRequest, index) => { + this.handle(shareRequest.username, shareRequest.scopes, true); + this.props.resource.shareRequests.splice(index, 1); + }); + + _defineProperty(this, "handleDeny", async (shareRequest, index) => { + this.handle(shareRequest.username, shareRequest.scopes); + this.props.resource.shareRequests.splice(index, 1); + }); + + _defineProperty(this, "handle", async (username, scopes, approve = false) => { + const id = this.props.resource._id; + this.handleToggleDialog(); + const permissionsRequest = await this.context.doGet(`/resources/${id}/permissions`); + const permissions = permissionsRequest.data || []; + const foundPermission = permissions.find(p => p.username === username); + const userScopes = foundPermission ? foundPermission.scopes : []; + + if (approve) { + userScopes.push(...scopes); + } + + try { + await this.context.doPut(`/resources/${id}/permissions`, [{ + username: username, + scopes: userScopes + }]); + ContentAlert.success(Msg.localize('shareSuccess')); + this.props.onClose(); + } catch (e) { + console.error('Could not update permissions', e.error); + } + }); + + _defineProperty(this, "handleToggleDialog", () => { + this.setState({ + isOpen: !this.state.isOpen + }); + }); + + this.context = context; + this.state = { + isOpen: false + }; + } + + render() { + const id = `shareRequest-${this.props.resource.name.replace(/\s/, '-')}`; + return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Button, { + id: id, + variant: "link", + onClick: this.handleToggleDialog + }, /*#__PURE__*/React.createElement(UserCheckIcon, { + size: "lg" + }), /*#__PURE__*/React.createElement(Badge, null, this.props.resource.shareRequests.length)), /*#__PURE__*/React.createElement(Modal, { + id: `modal-${id}`, + title: Msg.localize('permissionRequests') + ' - ' + this.props.resource.name, + variant: ModalVariant.large, + isOpen: this.state.isOpen, + onClose: this.handleToggleDialog, + actions: [/*#__PURE__*/React.createElement(Button, { + id: `close-${id}`, + key: "close", + variant: "link", + onClick: this.handleToggleDialog + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "close" + }))] + }, /*#__PURE__*/React.createElement(DataList, { + "aria-label": Msg.localize('permissionRequests') + }, /*#__PURE__*/React.createElement(DataListItemRow, null, /*#__PURE__*/React.createElement(DataListItemCells, { + dataListCells: [/*#__PURE__*/React.createElement(DataListCell, { + key: "permissions-name-header", + width: 5 + }, /*#__PURE__*/React.createElement("strong", null, "Requestor")), /*#__PURE__*/React.createElement(DataListCell, { + key: "permissions-requested-header", + width: 5 + }, /*#__PURE__*/React.createElement("strong", null, /*#__PURE__*/React.createElement(Msg, { + msgKey: "permissionRequests" + }))), /*#__PURE__*/React.createElement(DataListCell, { + key: "permission-request-header", + width: 5 + })] + })), this.props.resource.shareRequests.map((shareRequest, i) => /*#__PURE__*/React.createElement(DataListItem, { + key: i, + "aria-labelledby": "requestor" + }, /*#__PURE__*/React.createElement(DataListItemRow, null, /*#__PURE__*/React.createElement(DataListItemCells, { + dataListCells: [/*#__PURE__*/React.createElement(DataListCell, { + id: `requestor${i}`, + key: `requestor${i}` + }, /*#__PURE__*/React.createElement("span", null, shareRequest.firstName, " ", shareRequest.lastName, " ", shareRequest.lastName ? '' : shareRequest.username), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement(Text, { + component: TextVariants.small + }, shareRequest.email)), /*#__PURE__*/React.createElement(DataListCell, { + id: `permissions${i}`, + key: `permissions${i}` + }, shareRequest.scopes.map((scope, j) => /*#__PURE__*/React.createElement(Chip, { + key: j, + isReadOnly: true + }, scope))), /*#__PURE__*/React.createElement(DataListCell, { + key: `actions${i}` + }, /*#__PURE__*/React.createElement(Split, { + hasGutter: true + }, /*#__PURE__*/React.createElement(SplitItem, null, /*#__PURE__*/React.createElement(Button, { + id: `accept-${i}-${id}`, + onClick: () => this.handleApprove(shareRequest, i) + }, "Accept")), /*#__PURE__*/React.createElement(SplitItem, null, /*#__PURE__*/React.createElement(Button, { + id: `deny-${i}-${id}`, + variant: "danger", + onClick: () => this.handleDeny(shareRequest, i) + }, "Deny"))))] + }))))))); + } + +} + +_defineProperty(PermissionRequest, "defaultProps", { + permissions: [], + row: 0 +}); + +_defineProperty(PermissionRequest, "contextType", AccountServiceContext); +//# sourceMappingURL=PermissionRequest.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/PermissionRequest.js.map b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/PermissionRequest.js.map new file mode 100644 index 0000000..99f26c2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/PermissionRequest.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/my-resources-page/PermissionRequest.tsx"],"names":["React","Button","Modal","Text","Badge","DataListItem","DataList","TextVariants","DataListItemRow","DataListItemCells","DataListCell","Chip","Split","SplitItem","ModalVariant","UserCheckIcon","AccountServiceContext","Msg","ContentAlert","PermissionRequest","Component","constructor","props","context","shareRequest","index","handle","username","scopes","resource","shareRequests","splice","approve","id","_id","handleToggleDialog","permissionsRequest","doGet","permissions","data","foundPermission","find","p","userScopes","push","doPut","success","localize","onClose","e","console","error","setState","isOpen","state","render","name","replace","length","large","map","i","firstName","lastName","small","email","scope","j","handleApprove","handleDeny","row"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,KAAKA,KAAZ;AACA,SACIC,MADJ,EAEIC,KAFJ,EAGIC,IAHJ,EAIIC,KAJJ,EAKIC,YALJ,EAMIC,QANJ,EAOIC,YAPJ,EAQIC,eARJ,EASIC,iBATJ,EAUIC,YAVJ,EAWIC,IAXJ,EAYIC,KAZJ,EAaIC,SAbJ,EAcIC,YAdJ;AAgBA,SAASC,aAAT;AAGA,SAASC,qBAAT;AACA,SAASC,GAAT;AACA,SAASC,YAAT;AAaA,OAAO,MAAMC,iBAAN,SAAgCnB,KAAK,CAACoB,SAAtC,CAAgG;AAK5FC,EAAAA,WAAW,CAACC,KAAD,EAAgCC,OAAhC,EAA0F;AACxG,UAAMD,KAAN;;AADwG;;AAAA,2CASpF,OAAOE,YAAP,EAAiCC,KAAjC,KAAmD;AACvE,WAAKC,MAAL,CAAYF,YAAY,CAACG,QAAzB,EAAmCH,YAAY,CAACI,MAAhD,EAAmE,IAAnE;AACA,WAAKN,KAAL,CAAWO,QAAX,CAAoBC,aAApB,CAAkCC,MAAlC,CAAyCN,KAAzC,EAAgD,CAAhD;AACH,KAZ2G;;AAAA,wCAcvF,OAAOD,YAAP,EAAiCC,KAAjC,KAAmD;AACpE,WAAKC,MAAL,CAAYF,YAAY,CAACG,QAAzB,EAAmCH,YAAY,CAACI,MAAhD;AACA,WAAKN,KAAL,CAAWO,QAAX,CAAoBC,aAApB,CAAkCC,MAAlC,CAAyCN,KAAzC,EAAgD,CAAhD;AACH,KAjB2G;;AAAA,oCAmB3F,OAAOE,QAAP,EAAyBC,MAAzB,EAA0CI,OAAgB,GAAG,KAA7D,KAAuE;AACpF,YAAMC,EAAE,GAAG,KAAKX,KAAL,CAAWO,QAAX,CAAoBK,GAA/B;AACA,WAAKC,kBAAL;AAEA,YAAMC,kBAA8C,GAAG,MAAM,KAAKb,OAAL,CAAcc,KAAd,CAAqB,cAAaJ,EAAG,cAArC,CAA7D;AACA,YAAMK,WAAW,GAAGF,kBAAkB,CAACG,IAAnB,IAA2B,EAA/C;AACA,YAAMC,eAAe,GAAGF,WAAW,CAACG,IAAZ,CAAiBC,CAAC,IAAIA,CAAC,CAACf,QAAF,KAAeA,QAArC,CAAxB;AACA,YAAMgB,UAAU,GAAGH,eAAe,GAAIA,eAAe,CAACZ,MAApB,GAAwC,EAA1E;;AACA,UAAII,OAAJ,EAAa;AACTW,QAAAA,UAAU,CAACC,IAAX,CAAgB,GAAGhB,MAAnB;AACH;;AACD,UAAI;AACA,cAAM,KAAKL,OAAL,CAAcsB,KAAd,CAAqB,cAAaZ,EAAG,cAArC,EAAoD,CAAC;AAAEN,UAAAA,QAAQ,EAAEA,QAAZ;AAAsBC,UAAAA,MAAM,EAAEe;AAA9B,SAAD,CAApD,CAAN;AACAzB,QAAAA,YAAY,CAAC4B,OAAb,CAAqB7B,GAAG,CAAC8B,QAAJ,CAAa,cAAb,CAArB;AACA,aAAKzB,KAAL,CAAW0B,OAAX;AACH,OAJD,CAIE,OAAOC,CAAP,EAAU;AACRC,QAAAA,OAAO,CAACC,KAAR,CAAc,8BAAd,EAA8CF,CAAC,CAACE,KAAhD;AACH;AACJ,KArC2G;;AAAA,gDAuC/E,MAAM;AAC/B,WAAKC,QAAL,CAAc;AAAEC,QAAAA,MAAM,EAAE,CAAC,KAAKC,KAAL,CAAWD;AAAtB,OAAd;AACH,KAzC2G;;AAExG,SAAK9B,OAAL,GAAeA,OAAf;AAEA,SAAK+B,KAAL,GAAa;AACTD,MAAAA,MAAM,EAAE;AADC,KAAb;AAGH;;AAoCME,EAAAA,MAAM,GAAoB;AAC7B,UAAMtB,EAAE,GAAI,gBAAe,KAAKX,KAAL,CAAWO,QAAX,CAAoB2B,IAApB,CAAyBC,OAAzB,CAAiC,IAAjC,EAAuC,GAAvC,CAA4C,EAAvE;AACA,wBACI,oBAAC,KAAD,CAAO,QAAP,qBACI,oBAAC,MAAD;AAAQ,MAAA,EAAE,EAAExB,EAAZ;AAAgB,MAAA,OAAO,EAAC,MAAxB;AAA+B,MAAA,OAAO,EAAE,KAAKE;AAA7C,oBACI,oBAAC,aAAD;AAAe,MAAA,IAAI,EAAC;AAApB,MADJ,eAEI,oBAAC,KAAD,QAAQ,KAAKb,KAAL,CAAWO,QAAX,CAAoBC,aAApB,CAAkC4B,MAA1C,CAFJ,CADJ,eAMI,oBAAC,KAAD;AACI,MAAA,EAAE,EAAG,SAAQzB,EAAG,EADpB;AAEI,MAAA,KAAK,EAAEhB,GAAG,CAAC8B,QAAJ,CAAa,oBAAb,IAAqC,KAArC,GAA6C,KAAKzB,KAAL,CAAWO,QAAX,CAAoB2B,IAF5E;AAGI,MAAA,OAAO,EAAE1C,YAAY,CAAC6C,KAH1B;AAII,MAAA,MAAM,EAAE,KAAKL,KAAL,CAAWD,MAJvB;AAKI,MAAA,OAAO,EAAE,KAAKlB,kBALlB;AAMI,MAAA,OAAO,EAAE,cACL,oBAAC,MAAD;AAAQ,QAAA,EAAE,EAAG,SAAQF,EAAG,EAAxB;AAA2B,QAAA,GAAG,EAAC,OAA/B;AAAuC,QAAA,OAAO,EAAC,MAA/C;AAAsD,QAAA,OAAO,EAAE,KAAKE;AAApE,sBACI,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QADJ,CADK;AANb,oBAYI,oBAAC,QAAD;AAAU,oBAAYlB,GAAG,CAAC8B,QAAJ,CAAa,oBAAb;AAAtB,oBACI,oBAAC,eAAD,qBACI,oBAAC,iBAAD;AACI,MAAA,aAAa,EAAE,cACX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC,yBAAlB;AAA4C,QAAA,KAAK,EAAE;AAAnD,sBACI,gDADJ,CADW,eAIX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC,8BAAlB;AAAiD,QAAA,KAAK,EAAE;AAAxD,sBACI,iDAAQ,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QAAR,CADJ,CAJW,eAOX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC,2BAAlB;AAA8C,QAAA,KAAK,EAAE;AAArD,QAPW;AADnB,MADJ,CADJ,EAeK,KAAKzB,KAAL,CAAWO,QAAX,CAAoBC,aAApB,CAAkC8B,GAAlC,CAAsC,CAACpC,YAAD,EAAeqC,CAAf,kBACnC,oBAAC,YAAD;AAAc,MAAA,GAAG,EAAEA,CAAnB;AAAsB,yBAAgB;AAAtC,oBACI,oBAAC,eAAD,qBACI,oBAAC,iBAAD;AACI,MAAA,aAAa,EAAE,cACX,oBAAC,YAAD;AAAc,QAAA,EAAE,EAAG,YAAWA,CAAE,EAAhC;AAAmC,QAAA,GAAG,EAAG,YAAWA,CAAE;AAAtD,sBACI,kCACKrC,YAAY,CAACsC,SADlB,OAC8BtC,YAAY,CAACuC,QAD3C,OACsDvC,YAAY,CAACuC,QAAb,GAAwB,EAAxB,GAA6BvC,YAAY,CAACG,QADhG,CADJ,eAGW,+BAHX,eAII,oBAAC,IAAD;AAAM,QAAA,SAAS,EAAEpB,YAAY,CAACyD;AAA9B,SAAsCxC,YAAY,CAACyC,KAAnD,CAJJ,CADW,eAOX,oBAAC,YAAD;AAAc,QAAA,EAAE,EAAG,cAAaJ,CAAE,EAAlC;AAAqC,QAAA,GAAG,EAAG,cAAaA,CAAE;AAA1D,SACMrC,YAAY,CAACI,MAAd,CAAiCgC,GAAjC,CAAqC,CAACM,KAAD,EAAQC,CAAR,kBAAc,oBAAC,IAAD;AAAM,QAAA,GAAG,EAAEA,CAAX;AAAc,QAAA,UAAU;AAAxB,SAA0BD,KAA1B,CAAnD,CADL,CAPW,eAUX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAG,UAASL,CAAE;AAA/B,sBACI,oBAAC,KAAD;AAAO,QAAA,SAAS;AAAhB,sBACI,oBAAC,SAAD,qBACI,oBAAC,MAAD;AACI,QAAA,EAAE,EAAG,UAASA,CAAE,IAAG5B,EAAG,EAD1B;AAEI,QAAA,OAAO,EAAE,MAAM,KAAKmC,aAAL,CAAmB5C,YAAnB,EAAiCqC,CAAjC;AAFnB,kBADJ,CADJ,eASI,oBAAC,SAAD,qBACI,oBAAC,MAAD;AACI,QAAA,EAAE,EAAG,QAAOA,CAAE,IAAG5B,EAAG,EADxB;AAEI,QAAA,OAAO,EAAC,QAFZ;AAGI,QAAA,OAAO,EAAE,MAAM,KAAKoC,UAAL,CAAgB7C,YAAhB,EAA8BqC,CAA9B;AAHnB,gBADJ,CATJ,CADJ,CAVW;AADnB,MADJ,CADJ,CADH,CAfL,CAZJ,CANJ,CADJ;AA8EH;;AAhIkG;;gBAA1F1C,iB,kBACmC;AAAEmB,EAAAA,WAAW,EAAE,EAAf;AAAmBgC,EAAAA,GAAG,EAAE;AAAxB,C;;gBADnCnD,iB,iBAEYH,qB","sourcesContent":["/*\n * Copyright 2019 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport * as React from 'react';\nimport {\n Button,\n Modal,\n Text,\n Badge,\n DataListItem,\n DataList,\n TextVariants,\n DataListItemRow,\n DataListItemCells,\n DataListCell,\n Chip,\n Split,\n SplitItem,\n ModalVariant\n} from '@patternfly/react-core';\nimport { UserCheckIcon } from '@patternfly/react-icons';\n\nimport { HttpResponse } from '../../account-service/account.service';\nimport { AccountServiceContext } from '../../account-service/AccountServiceContext';\nimport { Msg } from '../../widgets/Msg';\nimport { ContentAlert } from '../ContentAlert';\nimport { Resource, Scope, Permission, Permissions } from './resource-model';\n\n\ninterface PermissionRequestProps {\n resource: Resource;\n onClose: () => void;\n}\n\ninterface PermissionRequestState {\n isOpen: boolean;\n}\n\nexport class PermissionRequest extends React.Component {\n protected static defaultProps:Permissions = { permissions: [], row: 0 };\n static contextType = AccountServiceContext;\n context: React.ContextType;\n\n public constructor(props: PermissionRequestProps, context: React.ContextType) {\n super(props);\n this.context = context;\n \n this.state = {\n isOpen: false,\n };\n }\n\n private handleApprove = async (shareRequest: Permission, index: number) => {\n this.handle(shareRequest.username, shareRequest.scopes as Scope[], true);\n this.props.resource.shareRequests.splice(index, 1);\n };\n\n private handleDeny = async (shareRequest: Permission, index: number) => {\n this.handle(shareRequest.username, shareRequest.scopes as Scope[]);\n this.props.resource.shareRequests.splice(index, 1)\n };\n\n private handle = async (username: string, scopes: Scope[], approve: boolean = false) => {\n const id = this.props.resource._id\n this.handleToggleDialog();\n\n const permissionsRequest: HttpResponse = await this.context!.doGet(`/resources/${id}/permissions`);\n const permissions = permissionsRequest.data || [];\n const foundPermission = permissions.find(p => p.username === username);\n const userScopes = foundPermission ? (foundPermission.scopes as Scope[]): [];\n if (approve) {\n userScopes.push(...scopes);\n }\n try {\n await this.context!.doPut(`/resources/${id}/permissions`, [{ username: username, scopes: userScopes }] )\n ContentAlert.success(Msg.localize('shareSuccess'));\n this.props.onClose();\n } catch (e) {\n console.error('Could not update permissions', e.error);\n }\n };\n\n private handleToggleDialog = () => {\n this.setState({ isOpen: !this.state.isOpen });\n };\n\n public render(): React.ReactNode {\n const id = `shareRequest-${this.props.resource.name.replace(/\\s/, '-')}`;\n return (\n \n \n\n \n \n ,\n ]}\n >\n \n \n \n Requestor\n ,\n \n \n ,\n \n \n ]}\n />\n \n {this.props.resource.shareRequests.map((shareRequest, i) =>\n \n \n \n \n {shareRequest.firstName} {shareRequest.lastName} {shareRequest.lastName ? '' : shareRequest.username}\n
    \n {shareRequest.email}\n ,\n \n {(shareRequest.scopes as Scope[]).map((scope, j) => {scope})}\n ,\n \n \n \n this.handleApprove(shareRequest, i)}\n >\n Accept\n \n \n \n this.handleDeny(shareRequest, i)}\n >\n Deny\n \n \n \n \n ]}\n />\n
    \n
    \n )}\n
    \n \n
    \n );\n }\n}\n"],"file":"PermissionRequest.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/PermissionSelect.js b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/PermissionSelect.js new file mode 100644 index 0000000..973abcb --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/PermissionSelect.js @@ -0,0 +1,103 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +import * as React from "../../../../common/keycloak/web_modules/react.js"; +import { Select, SelectOption, SelectVariant } from "../../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { Msg } from "../../widgets/Msg.js"; + +class ScopeValue { + constructor(value) { + _defineProperty(this, "value", void 0); + + this.value = value; + } + + toString() { + return this.value.displayName ? this.value.displayName : this.value.name; + } + + compareTo(selectOption) { + return selectOption.name === this.value.name; + } + +} + +export class PermissionSelect extends React.Component { + constructor(props) { + super(props); + + _defineProperty(this, "onSelect", (_event, selection) => { + const { + selected + } = this.state; + const { + onSelect + } = this.props; + + if (selected.includes(selection)) { + this.setState(prevState => ({ + selected: prevState.selected.filter(item => item !== selection) + }), () => onSelect(this.state.selected.map(sv => sv.value))); + } else { + this.setState(prevState => ({ + selected: [...prevState.selected, selection] + }), () => onSelect(this.state.selected.map(sv => sv.value))); + } + }); + + _defineProperty(this, "onToggle", isExpanded => { + this.setState({ + isExpanded + }); + }); + + _defineProperty(this, "clearSelection", () => { + this.setState({ + selected: [], + isExpanded: false + }); + this.props.onSelect([]); + }); + + let values = []; + + if (this.props.selected) { + values = this.props.selected.map(s => new ScopeValue(s)); + } + + this.state = { + isExpanded: false, + selected: values, + scopes: this.props.scopes.map((option, index) => /*#__PURE__*/React.createElement(SelectOption, { + key: index, + value: values.find(s => s.compareTo(option)) || new ScopeValue(option) + })) + }; + } + + render() { + const { + isExpanded, + selected + } = this.state; + const titleId = 'permission-id'; + return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("span", { + id: titleId, + hidden: true + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "selectPermissions" + })), /*#__PURE__*/React.createElement(Select, { + direction: this.props.direction || 'down', + variant: SelectVariant.typeaheadMulti, + typeAheadAriaLabel: Msg.localize("selectPermissions"), + onToggle: this.onToggle, + onSelect: this.onSelect, + onClear: this.clearSelection, + selections: selected, + isOpen: isExpanded, + "aria-labelledby": titleId, + placeholderText: Msg.localize("selectPermissions") + }, this.state.scopes)); + } + +} +//# sourceMappingURL=PermissionSelect.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/PermissionSelect.js.map b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/PermissionSelect.js.map new file mode 100644 index 0000000..e2c0adc --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/PermissionSelect.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/my-resources-page/PermissionSelect.tsx"],"names":["React","Select","SelectOption","SelectVariant","Msg","ScopeValue","constructor","value","toString","displayName","name","compareTo","selectOption","PermissionSelect","Component","props","_event","selection","selected","state","onSelect","includes","setState","prevState","filter","item","map","sv","isExpanded","values","s","scopes","option","index","find","render","titleId","direction","typeaheadMulti","localize","onToggle","clearSelection"],"mappings":";;AAAA,OAAO,KAAKA,KAAZ;AAEA,SAASC,MAAT,EAAiBC,YAAjB,EAA+BC,aAA/B;AAEA,SAASC,GAAT;;AAeA,MAAMC,UAAN,CAA+C;AAE7CC,EAAAA,WAAW,CAACC,KAAD,EAAe;AAAA;;AACxB,SAAKA,KAAL,GAAaA,KAAb;AACD;;AAEDC,EAAAA,QAAQ,GAAG;AACT,WAAO,KAAKD,KAAL,CAAWE,WAAX,GAAyB,KAAKF,KAAL,CAAWE,WAApC,GAAkD,KAAKF,KAAL,CAAWG,IAApE;AACD;;AAEDC,EAAAA,SAAS,CAACC,YAAD,EAA+B;AACtC,WAAOA,YAAY,CAACF,IAAb,KAAsB,KAAKH,KAAL,CAAWG,IAAxC;AACD;;AAZ4C;;AAe/C,OAAO,MAAMG,gBAAN,SAA+Bb,KAAK,CAACc,SAArC,CAA6F;AAClGR,EAAAA,WAAW,CAACS,KAAD,EAA+B;AACxC,UAAMA,KAAN;;AADwC,sCAiBvB,CAACC,MAAD,EAA+CC,SAA/C,KAA+E;AAChG,YAAM;AAAEC,QAAAA;AAAF,UAAe,KAAKC,KAA1B;AACA,YAAM;AAAEC,QAAAA;AAAF,UAAe,KAAKL,KAA1B;;AACA,UAAIG,QAAQ,CAACG,QAAT,CAAkBJ,SAAlB,CAAJ,EAAkC;AAChC,aAAKK,QAAL,CACEC,SAAS,KAAK;AAAEL,UAAAA,QAAQ,EAAEK,SAAS,CAACL,QAAV,CAAmBM,MAAnB,CAA0BC,IAAI,IAAIA,IAAI,KAAKR,SAA3C;AAAZ,SAAL,CADX,EAEE,MAAMG,QAAQ,CAAC,KAAKD,KAAL,CAAWD,QAAX,CAAoBQ,GAApB,CAAwBC,EAAE,IAAIA,EAAE,CAACpB,KAAjC,CAAD,CAFhB;AAID,OALD,MAKO;AACL,aAAKe,QAAL,CACEC,SAAS,KAAK;AAAEL,UAAAA,QAAQ,EAAE,CAAC,GAAGK,SAAS,CAACL,QAAd,EAAwBD,SAAxB;AAAZ,SAAL,CADX,EAEE,MAAMG,QAAQ,CAAC,KAAKD,KAAL,CAAWD,QAAX,CAAoBQ,GAApB,CAAwBC,EAAE,IAAIA,EAAE,CAACpB,KAAjC,CAAD,CAFhB;AAID;AACF,KA/ByC;;AAAA,sCAiCtBqB,UAAD,IAAyB;AAC1C,WAAKN,QAAL,CAAc;AACZM,QAAAA;AADY,OAAd;AAGD,KArCyC;;AAAA,4CAuCjB,MAAM;AAC7B,WAAKN,QAAL,CAAc;AACZJ,QAAAA,QAAQ,EAAE,EADE;AAEZU,QAAAA,UAAU,EAAE;AAFA,OAAd;AAIA,WAAKb,KAAL,CAAWK,QAAX,CAAoB,EAApB;AACD,KA7CyC;;AAGxC,QAAIS,MAAoB,GAAG,EAA3B;;AACA,QAAI,KAAKd,KAAL,CAAWG,QAAf,EAAyB;AACvBW,MAAAA,MAAM,GAAG,KAAKd,KAAL,CAAWG,QAAX,CAAqBQ,GAArB,CAAyBI,CAAC,IAAI,IAAIzB,UAAJ,CAAeyB,CAAf,CAA9B,CAAT;AACD;;AAED,SAAKX,KAAL,GAAa;AACXS,MAAAA,UAAU,EAAE,KADD;AAEXV,MAAAA,QAAQ,EAAEW,MAFC;AAGXE,MAAAA,MAAM,EAAE,KAAKhB,KAAL,CAAWgB,MAAX,CAAkBL,GAAlB,CAAsB,CAACM,MAAD,EAASC,KAAT,kBAC5B,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAEA,KAAnB;AAA0B,QAAA,KAAK,EAAEJ,MAAM,CAACK,IAAP,CAAYJ,CAAC,IAAIA,CAAC,CAACnB,SAAF,CAAYqB,MAAZ,CAAjB,KAAyC,IAAI3B,UAAJ,CAAe2B,MAAf;AAA1E,QADM;AAHG,KAAb;AAOD;;AAgCDG,EAAAA,MAAM,GAAG;AACP,UAAM;AAAEP,MAAAA,UAAF;AAAcV,MAAAA;AAAd,QAA2B,KAAKC,KAAtC;AACA,UAAMiB,OAAO,GAAG,eAAhB;AAEA,wBACE,8CACE;AAAM,MAAA,EAAE,EAAEA,OAAV;AAAmB,MAAA,MAAM;AAAzB,oBACE,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MADF,CADF,eAIE,oBAAC,MAAD;AACE,MAAA,SAAS,EAAE,KAAKrB,KAAL,CAAWsB,SAAX,IAAwB,MADrC;AAEE,MAAA,OAAO,EAAElC,aAAa,CAACmC,cAFzB;AAGE,MAAA,kBAAkB,EAAElC,GAAG,CAACmC,QAAJ,CAAa,mBAAb,CAHtB;AAIE,MAAA,QAAQ,EAAE,KAAKC,QAJjB;AAKE,MAAA,QAAQ,EAAE,KAAKpB,QALjB;AAME,MAAA,OAAO,EAAE,KAAKqB,cANhB;AAOE,MAAA,UAAU,EAAEvB,QAPd;AAQE,MAAA,MAAM,EAAEU,UARV;AASE,yBAAiBQ,OATnB;AAUE,MAAA,eAAe,EAAEhC,GAAG,CAACmC,QAAJ,CAAa,mBAAb;AAVnB,OAYG,KAAKpB,KAAL,CAAWY,MAZd,CAJF,CADF;AAqBD;;AAzEiG","sourcesContent":["import * as React from 'react';\n\nimport { Select, SelectOption, SelectVariant, SelectOptionObject } from '@patternfly/react-core';\nimport { Scope } from './resource-model';\nimport { Msg } from '../../widgets/Msg';\n\ninterface PermissionSelectState {\n selected: ScopeValue[];\n isExpanded: boolean;\n scopes: JSX.Element[];\n}\n\ninterface PermissionSelectProps {\n scopes: Scope[];\n selected?: Scope[];\n direction?: 'up' | 'down';\n onSelect: (selected: Scope[]) => void;\n}\n\nclass ScopeValue implements SelectOptionObject {\n value: Scope;\n constructor(value: Scope) {\n this.value = value;\n }\n\n toString() {\n return this.value.displayName ? this.value.displayName : this.value.name;\n }\n\n compareTo(selectOption: Scope): boolean {\n return selectOption.name === this.value.name;\n }\n}\n\nexport class PermissionSelect extends React.Component {\n constructor(props: PermissionSelectProps) {\n super(props);\n\n let values: ScopeValue[] = [];\n if (this.props.selected) {\n values = this.props.selected!.map(s => new ScopeValue(s))\n }\n\n this.state = {\n isExpanded: false,\n selected: values,\n scopes: this.props.scopes.map((option, index) => (\n s.compareTo(option)) || new ScopeValue(option)} />\n ))\n };\n }\n\n private onSelect = (_event: React.MouseEvent | React.ChangeEvent, selection: ScopeValue): void => {\n const { selected } = this.state;\n const { onSelect } = this.props;\n if (selected.includes(selection)) {\n this.setState(\n prevState => ({ selected: prevState.selected.filter(item => item !== selection) }),\n () => onSelect(this.state.selected.map(sv => sv.value))\n );\n } else {\n this.setState(\n prevState => ({ selected: [...prevState.selected, selection] }),\n () => onSelect(this.state.selected.map(sv => sv.value))\n );\n }\n }\n\n private onToggle = (isExpanded: boolean) => {\n this.setState({\n isExpanded\n });\n }\n\n private clearSelection = () => {\n this.setState({\n selected: [],\n isExpanded: false\n });\n this.props.onSelect([]);\n };\n\n render() {\n const { isExpanded, selected } = this.state;\n const titleId = 'permission-id';\n\n return (\n
    \n \n \n {this.state.scopes}\n \n
    \n );\n }\n}\n"],"file":"PermissionSelect.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/ResourcesTable.js b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/ResourcesTable.js new file mode 100644 index 0000000..7262452 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/ResourcesTable.js @@ -0,0 +1,313 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../../common/keycloak/web_modules/react.js"; +import { DataList, DataListItem, DataListItemRow, DataListCell, DataListToggle, DataListContent, DataListItemCells, Level, LevelItem, Button, DataListAction, Dropdown, DropdownPosition, DropdownItem, KebabToggle } from "../../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { Remove2Icon, RepositoryIcon, ShareAltIcon, EditAltIcon } from "../../../../common/keycloak/web_modules/@patternfly/react-icons.js"; +import { AccountServiceContext } from "../../account-service/AccountServiceContext.js"; +import { PermissionRequest } from "./PermissionRequest.js"; +import { ShareTheResource } from "./ShareTheResource.js"; +import { Msg } from "../../widgets/Msg.js"; +import { AbstractResourcesTable } from "./AbstractResourceTable.js"; +import { EditTheResource } from "./EditTheResource.js"; +import { ContentAlert } from "../ContentAlert.js"; +import EmptyMessageState from "../../widgets/EmptyMessageState.js"; +import { ContinueCancelModal } from "../../widgets/ContinueCancelModal.js"; +export class ResourcesTable extends AbstractResourcesTable { + constructor(props, context) { + super(props); + + _defineProperty(this, "context", void 0); + + _defineProperty(this, "onToggle", row => { + const newIsRowOpen = this.state.isRowOpen; + newIsRowOpen[row] = !newIsRowOpen[row]; + if (newIsRowOpen[row]) this.fetchPermissions(this.props.resources.data[row], row); + this.setState({ + isRowOpen: newIsRowOpen + }); + }); + + _defineProperty(this, "onContextToggle", (row, isOpen) => { + if (this.state.isModalActive) return; + const data = this.props.resources.data; + const contextOpen = this.state.contextOpen; + contextOpen[row] = isOpen; + + if (isOpen) { + const index = row > data.length ? row - data.length - 1 : row; + this.fetchPermissions(data[index], index); + } + + this.setState({ + contextOpen + }); + }); + + this.context = context; + this.state = { + isRowOpen: [], + contextOpen: [], + isModalActive: false, + permissions: new Map() + }; + } + + fetchPermissions(resource, row) { + this.context.doGet(`/resources/${resource._id}/permissions`).then(response => { + const newPermissions = new Map(this.state.permissions); + newPermissions.set(row, response.data || []); + this.setState({ + permissions: newPermissions + }); + }); + } + + removeShare(resource, row) { + const permissions = this.state.permissions.get(row).map(a => ({ + username: a.username, + scopes: [] + })); + return this.context.doPut(`/resources/${resource._id}/permissions`, permissions).then(() => { + ContentAlert.success(Msg.localize('unShareSuccess')); + }); + } + + render() { + if (this.props.resources.data.length === 0) { + return /*#__PURE__*/React.createElement(EmptyMessageState, { + icon: RepositoryIcon, + messageKey: "notHaveAnyResource" + }); + } + + return /*#__PURE__*/React.createElement(DataList, { + "aria-label": Msg.localize('resources'), + id: "resourcesList" + }, /*#__PURE__*/React.createElement(DataListItem, { + key: "resource-header", + "aria-labelledby": "resource-header" + }, /*#__PURE__*/React.createElement(DataListItemRow, null, "// invisible toggle allows headings to line up properly", /*#__PURE__*/React.createElement("span", { + style: { + visibility: 'hidden' + } + }, /*#__PURE__*/React.createElement(DataListToggle, { + isExpanded: false, + id: "resource-header-invisible-toggle", + "aria-controls": "ex-expand1" + })), /*#__PURE__*/React.createElement(DataListItemCells, { + dataListCells: [/*#__PURE__*/React.createElement(DataListCell, { + key: "resource-name-header", + width: 5 + }, /*#__PURE__*/React.createElement("strong", null, /*#__PURE__*/React.createElement(Msg, { + msgKey: "resourceName" + }))), /*#__PURE__*/React.createElement(DataListCell, { + key: "application-name-header", + width: 5 + }, /*#__PURE__*/React.createElement("strong", null, /*#__PURE__*/React.createElement(Msg, { + msgKey: "application" + }))), /*#__PURE__*/React.createElement(DataListCell, { + key: "permission-request-header", + width: 5 + }, /*#__PURE__*/React.createElement("strong", null, /*#__PURE__*/React.createElement(Msg, { + msgKey: "permissionRequests" + })))] + }))), this.props.resources.data.map((resource, row) => /*#__PURE__*/React.createElement(DataListItem, { + key: 'resource-' + row, + "aria-labelledby": resource.name, + isExpanded: this.state.isRowOpen[row] + }, /*#__PURE__*/React.createElement(DataListItemRow, null, /*#__PURE__*/React.createElement(DataListToggle, { + onClick: () => this.onToggle(row), + isExpanded: this.state.isRowOpen[row], + id: 'resourceToggle-' + row, + "aria-controls": "ex-expand1" + }), /*#__PURE__*/React.createElement(DataListItemCells, { + dataListCells: [/*#__PURE__*/React.createElement(DataListCell, { + id: 'resourceName-' + row, + key: 'resourceName-' + row, + width: 5 + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: resource.name + })), /*#__PURE__*/React.createElement(DataListCell, { + id: 'resourceClient-' + row, + key: 'resourceClient-' + row, + width: 5 + }, /*#__PURE__*/React.createElement("a", { + href: resource.client.baseUrl + }, this.getClientName(resource.client))), /*#__PURE__*/React.createElement(DataListCell, { + id: 'resourceRequests-' + row, + key: 'permissionRequests-' + row, + width: 5 + }, resource.shareRequests.length > 0 && /*#__PURE__*/React.createElement(PermissionRequest, { + resource: resource, + onClose: () => this.fetchPermissions(resource, row) + }))] + }), /*#__PURE__*/React.createElement(DataListAction, { + visibility: { + lg: 'hidden' + }, + "aria-labelledby": "check-action-item3 check-action-action3", + id: "check-action-action3", + "aria-label": "Actions" + }, /*#__PURE__*/React.createElement(Dropdown, { + isPlain: true, + position: DropdownPosition.right, + onSelect: () => this.setState({ + isModalActive: true + }), + toggle: /*#__PURE__*/React.createElement(KebabToggle, { + onToggle: isOpen => this.onContextToggle(row + this.props.resources.data.length + 1, isOpen) + }), + isOpen: this.state.contextOpen[row + this.props.resources.data.length + 1], + dropdownItems: [/*#__PURE__*/React.createElement(ShareTheResource, { + resource: resource, + permissions: this.state.permissions.get(row), + sharedWithUsersMsg: this.sharedWithUsersMessage(row), + onClose: () => { + this.setState({ + isModalActive: false + }, () => { + this.onContextToggle(row + this.props.resources.data.length + 1, false); + this.fetchPermissions(resource, row + this.props.resources.data.length + 1); + }); + } + }, toggle => /*#__PURE__*/React.createElement(DropdownItem, { + id: 'mob-share-' + row, + key: "mob-share", + onClick: toggle + }, /*#__PURE__*/React.createElement(ShareAltIcon, null), " ", /*#__PURE__*/React.createElement(Msg, { + msgKey: "share" + }))), /*#__PURE__*/React.createElement(EditTheResource, { + resource: resource, + permissions: this.state.permissions.get(row), + onClose: () => { + this.setState({ + isModalActive: false + }, () => { + this.onContextToggle(row + this.props.resources.data.length + 1, false); + this.fetchPermissions(resource, row + this.props.resources.data.length + 1); + }); + } + }, toggle => /*#__PURE__*/React.createElement(DropdownItem, { + id: 'mob-edit-' + row, + key: "mob-edit", + isDisabled: this.numOthers(row) < 0, + onClick: toggle + }, /*#__PURE__*/React.createElement(EditAltIcon, null), " ", /*#__PURE__*/React.createElement(Msg, { + msgKey: "edit" + }))), /*#__PURE__*/React.createElement(ContinueCancelModal, { + render: toggle => /*#__PURE__*/React.createElement(DropdownItem, { + id: 'mob-remove-' + row, + key: "mob-remove", + isDisabled: this.numOthers(row) < 0, + onClick: toggle + }, /*#__PURE__*/React.createElement(Remove2Icon, null), " ", /*#__PURE__*/React.createElement(Msg, { + msgKey: "unShare" + })), + modalTitle: "unShare", + modalMessage: "unShareAllConfirm", + onClose: () => this.setState({ + isModalActive: false + }, () => { + this.onContextToggle(row + this.props.resources.data.length + 1, false); + }), + onContinue: () => this.removeShare(resource, row).then(() => this.fetchPermissions(resource, row + this.props.resources.data.length + 1)) + })] + })), /*#__PURE__*/React.createElement(DataListAction, { + id: `actions-${row}`, + visibility: { + default: 'hidden', + lg: 'visible' + }, + "aria-labelledby": "Row actions", + "aria-label": "Actions" + }, /*#__PURE__*/React.createElement(ShareTheResource, { + resource: resource, + permissions: this.state.permissions.get(row), + sharedWithUsersMsg: this.sharedWithUsersMessage(row), + onClose: () => this.fetchPermissions(resource, row) + }, toggle => /*#__PURE__*/React.createElement(Button, { + id: `share-${row}`, + variant: "link", + onClick: toggle + }, /*#__PURE__*/React.createElement(ShareAltIcon, null), " ", /*#__PURE__*/React.createElement(Msg, { + msgKey: "share" + }))), /*#__PURE__*/React.createElement(Dropdown, { + id: `action-menu-${row}`, + isPlain: true, + position: DropdownPosition.right, + toggle: /*#__PURE__*/React.createElement(KebabToggle, { + onToggle: isOpen => this.onContextToggle(row, isOpen) + }), + onSelect: () => this.setState({ + isModalActive: true + }), + isOpen: this.state.contextOpen[row], + dropdownItems: [/*#__PURE__*/React.createElement(EditTheResource, { + resource: resource, + permissions: this.state.permissions.get(row), + onClose: () => { + this.setState({ + isModalActive: false + }, () => { + this.onContextToggle(row, false); + this.fetchPermissions(resource, row); + }); + } + }, toggle => /*#__PURE__*/React.createElement(DropdownItem, { + id: 'edit-' + row, + key: "edit", + component: "button", + isDisabled: this.numOthers(row) < 0, + onClick: toggle + }, /*#__PURE__*/React.createElement(EditAltIcon, null), " ", /*#__PURE__*/React.createElement(Msg, { + msgKey: "edit" + }))), /*#__PURE__*/React.createElement(ContinueCancelModal, { + render: toggle => /*#__PURE__*/React.createElement(DropdownItem, { + id: 'remove-' + row, + key: "remove", + component: "button", + isDisabled: this.numOthers(row) < 0, + onClick: toggle + }, /*#__PURE__*/React.createElement(Remove2Icon, null), " ", /*#__PURE__*/React.createElement(Msg, { + msgKey: "unShare" + })), + modalTitle: "unShare", + modalMessage: "unShareAllConfirm", + onClose: () => this.setState({ + isModalActive: false + }, () => { + this.onContextToggle(row, false); + }), + onContinue: () => this.removeShare(resource, row).then(() => this.fetchPermissions(resource, row)) + })] + }))), /*#__PURE__*/React.createElement(DataListContent, { + hasNoPadding: false, + "aria-label": "Session Details", + id: 'ex-expand' + row, + isHidden: !this.state.isRowOpen[row] + }, /*#__PURE__*/React.createElement(Level, { + hasGutter: true + }, /*#__PURE__*/React.createElement(LevelItem, null, /*#__PURE__*/React.createElement("span", null)), /*#__PURE__*/React.createElement(LevelItem, { + id: 'shared-with-user-message-' + row + }, this.sharedWithUsersMessage(row)), /*#__PURE__*/React.createElement(LevelItem, null, /*#__PURE__*/React.createElement("span", null))))))); + } + +} + +_defineProperty(ResourcesTable, "contextType", AccountServiceContext); +//# sourceMappingURL=ResourcesTable.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/ResourcesTable.js.map b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/ResourcesTable.js.map new file mode 100644 index 0000000..d79f986 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/ResourcesTable.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/my-resources-page/ResourcesTable.tsx"],"names":["React","DataList","DataListItem","DataListItemRow","DataListCell","DataListToggle","DataListContent","DataListItemCells","Level","LevelItem","Button","DataListAction","Dropdown","DropdownPosition","DropdownItem","KebabToggle","Remove2Icon","RepositoryIcon","ShareAltIcon","EditAltIcon","AccountServiceContext","PermissionRequest","ShareTheResource","Msg","AbstractResourcesTable","EditTheResource","ContentAlert","EmptyMessageState","ContinueCancelModal","ResourcesTable","constructor","props","context","row","newIsRowOpen","state","isRowOpen","fetchPermissions","resources","data","setState","isOpen","isModalActive","contextOpen","index","length","permissions","Map","resource","doGet","_id","then","response","newPermissions","set","removeShare","get","map","a","username","scopes","doPut","success","localize","render","visibility","name","onToggle","client","baseUrl","getClientName","shareRequests","lg","right","onContextToggle","sharedWithUsersMessage","toggle","numOthers","default"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AAEA,SACIC,QADJ,EAEIC,YAFJ,EAGIC,eAHJ,EAIIC,YAJJ,EAKIC,cALJ,EAMIC,eANJ,EAOIC,iBAPJ,EAQIC,KARJ,EASIC,SATJ,EAUIC,MAVJ,EAWIC,cAXJ,EAYIC,QAZJ,EAaIC,gBAbJ,EAcIC,YAdJ,EAeIC,WAfJ;AAmBA,SAASC,WAAT,EAAsBC,cAAtB,EAAsCC,YAAtC,EAAoDC,WAApD;AAGA,SAASC,qBAAT;AACA,SAASC,iBAAT;AACA,SAASC,gBAAT;AAEA,SAASC,GAAT;AACA,SAAmDC,sBAAnD;AACA,SAASC,eAAT;AACA,SAASC,YAAT;AACA,OAAOC,iBAAP;AACA,SAASC,mBAAT;AAQA,OAAO,MAAMC,cAAN,SAA6BL,sBAA7B,CAAoF;AAIhFM,EAAAA,WAAW,CAACC,KAAD,EAA6BC,OAA7B,EAAuF;AACrG,UAAMD,KAAN;;AADqG;;AAAA,sCAYrFE,GAAD,IAAuB;AACtC,YAAMC,YAAuB,GAAG,KAAKC,KAAL,CAAWC,SAA3C;AACAF,MAAAA,YAAY,CAACD,GAAD,CAAZ,GAAoB,CAACC,YAAY,CAACD,GAAD,CAAjC;AACA,UAAIC,YAAY,CAACD,GAAD,CAAhB,EAAuB,KAAKI,gBAAL,CAAsB,KAAKN,KAAL,CAAWO,SAAX,CAAqBC,IAArB,CAA0BN,GAA1B,CAAtB,EAAsDA,GAAtD;AACvB,WAAKO,QAAL,CAAc;AAAEJ,QAAAA,SAAS,EAAEF;AAAb,OAAd;AACH,KAjBwG;;AAAA,6CAmB/E,CAACD,GAAD,EAAcQ,MAAd,KAAwC;AAC9D,UAAI,KAAKN,KAAL,CAAWO,aAAf,EAA8B;AAC9B,YAAMH,IAAI,GAAG,KAAKR,KAAL,CAAWO,SAAX,CAAqBC,IAAlC;AACA,YAAMI,WAAW,GAAG,KAAKR,KAAL,CAAWQ,WAA/B;AACAA,MAAAA,WAAW,CAACV,GAAD,CAAX,GAAmBQ,MAAnB;;AACA,UAAIA,MAAJ,EAAY;AACR,cAAMG,KAAK,GAAGX,GAAG,GAAGM,IAAI,CAACM,MAAX,GAAoBZ,GAAG,GAAGM,IAAI,CAACM,MAAX,GAAoB,CAAxC,GAA4CZ,GAA1D;AACA,aAAKI,gBAAL,CAAsBE,IAAI,CAACK,KAAD,CAA1B,EAAmCA,KAAnC;AACH;;AACD,WAAKJ,QAAL,CAAc;AAAEG,QAAAA;AAAF,OAAd;AACH,KA7BwG;;AAErG,SAAKX,OAAL,GAAeA,OAAf;AAEA,SAAKG,KAAL,GAAa;AACTC,MAAAA,SAAS,EAAE,EADF;AAETO,MAAAA,WAAW,EAAE,EAFJ;AAGTD,MAAAA,aAAa,EAAE,KAHN;AAITI,MAAAA,WAAW,EAAE,IAAIC,GAAJ;AAJJ,KAAb;AAMH;;AAqBOV,EAAAA,gBAAgB,CAACW,QAAD,EAAqBf,GAArB,EAAwC;AAC5D,SAAKD,OAAL,CAAciB,KAAd,CAAqB,cAAaD,QAAQ,CAACE,GAAI,cAA/C,EACKC,IADL,CACWC,QAAD,IAA0C;AAC5C,YAAMC,cAAyC,GAAG,IAAIN,GAAJ,CAAQ,KAAKZ,KAAL,CAAWW,WAAnB,CAAlD;AACAO,MAAAA,cAAc,CAACC,GAAf,CAAmBrB,GAAnB,EAAwBmB,QAAQ,CAACb,IAAT,IAAiB,EAAzC;AACA,WAAKC,QAAL,CAAc;AAAEM,QAAAA,WAAW,EAAEO;AAAf,OAAd;AACH,KALL;AAMH;;AAEOE,EAAAA,WAAW,CAACP,QAAD,EAAqBf,GAArB,EAAiD;AAChE,UAAMa,WAAW,GAAG,KAAKX,KAAL,CAAWW,WAAX,CAAuBU,GAAvB,CAA2BvB,GAA3B,EAAiCwB,GAAjC,CAAqCC,CAAC,KAAK;AAAEC,MAAAA,QAAQ,EAAED,CAAC,CAACC,QAAd;AAAwBC,MAAAA,MAAM,EAAE;AAAhC,KAAL,CAAtC,CAApB;AACA,WAAO,KAAK5B,OAAL,CAAc6B,KAAd,CAAqB,cAAab,QAAQ,CAACE,GAAI,cAA/C,EAA8DJ,WAA9D,EACFK,IADE,CACG,MAAM;AACRzB,MAAAA,YAAY,CAACoC,OAAb,CAAqBvC,GAAG,CAACwC,QAAJ,CAAa,gBAAb,CAArB;AACH,KAHE,CAAP;AAIH;;AAEMC,EAAAA,MAAM,GAAoB;AAC7B,QAAI,KAAKjC,KAAL,CAAWO,SAAX,CAAqBC,IAArB,CAA0BM,MAA1B,KAAqC,CAAzC,EAA4C;AACxC,0BACI,oBAAC,iBAAD;AAAmB,QAAA,IAAI,EAAE5B,cAAzB;AAAyC,QAAA,UAAU,EAAC;AAApD,QADJ;AAGH;;AACD,wBACI,oBAAC,QAAD;AAAU,oBAAYM,GAAG,CAACwC,QAAJ,CAAa,WAAb,CAAtB;AAAiD,MAAA,EAAE,EAAC;AAApD,oBACI,oBAAC,YAAD;AAAc,MAAA,GAAG,EAAC,iBAAlB;AAAoC,yBAAgB;AAApD,oBACI,oBAAC,eAAD,gFAEI;AAAM,MAAA,KAAK,EAAE;AAAEE,QAAAA,UAAU,EAAE;AAAd;AAAb,oBACI,oBAAC,cAAD;AACI,MAAA,UAAU,EAAE,KADhB;AAEI,MAAA,EAAE,EAAC,kCAFP;AAGI,uBAAc;AAHlB,MADJ,CAFJ,eASI,oBAAC,iBAAD;AACI,MAAA,aAAa,EAAE,cACX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC,sBAAlB;AAAyC,QAAA,KAAK,EAAE;AAAhD,sBACI,iDAAQ,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QAAR,CADJ,CADW,eAIX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC,yBAAlB;AAA4C,QAAA,KAAK,EAAE;AAAnD,sBACI,iDAAQ,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QAAR,CADJ,CAJW,eAOX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC,2BAAlB;AAA8C,QAAA,KAAK,EAAE;AAArD,sBACI,iDAAQ,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QAAR,CADJ,CAPW;AADnB,MATJ,CADJ,CADJ,EA0BK,KAAKlC,KAAL,CAAWO,SAAX,CAAqBC,IAArB,CAA0BkB,GAA1B,CAA8B,CAACT,QAAD,EAAqBf,GAArB,kBAC3B,oBAAC,YAAD;AAAc,MAAA,GAAG,EAAE,cAAcA,GAAjC;AAAsC,yBAAiBe,QAAQ,CAACkB,IAAhE;AAAsE,MAAA,UAAU,EAAE,KAAK/B,KAAL,CAAWC,SAAX,CAAqBH,GAArB;AAAlF,oBACI,oBAAC,eAAD,qBACI,oBAAC,cAAD;AACI,MAAA,OAAO,EAAE,MAAM,KAAKkC,QAAL,CAAclC,GAAd,CADnB;AAEI,MAAA,UAAU,EAAE,KAAKE,KAAL,CAAWC,SAAX,CAAqBH,GAArB,CAFhB;AAGI,MAAA,EAAE,EAAE,oBAAoBA,GAH5B;AAII,uBAAc;AAJlB,MADJ,eAOI,oBAAC,iBAAD;AACI,MAAA,aAAa,EAAE,cACX,oBAAC,YAAD;AAAc,QAAA,EAAE,EAAE,kBAAkBA,GAApC;AAAyC,QAAA,GAAG,EAAE,kBAAkBA,GAAhE;AAAqE,QAAA,KAAK,EAAE;AAA5E,sBACI,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAEe,QAAQ,CAACkB;AAAtB,QADJ,CADW,eAIX,oBAAC,YAAD;AAAc,QAAA,EAAE,EAAE,oBAAoBjC,GAAtC;AAA2C,QAAA,GAAG,EAAE,oBAAoBA,GAApE;AAAyE,QAAA,KAAK,EAAE;AAAhF,sBACI;AAAG,QAAA,IAAI,EAAEe,QAAQ,CAACoB,MAAT,CAAgBC;AAAzB,SAAmC,KAAKC,aAAL,CAAmBtB,QAAQ,CAACoB,MAA5B,CAAnC,CADJ,CAJW,eAOX,oBAAC,YAAD;AAAc,QAAA,EAAE,EAAE,sBAAsBnC,GAAxC;AAA6C,QAAA,GAAG,EAAE,wBAAwBA,GAA1E;AAA+E,QAAA,KAAK,EAAE;AAAtF,SACKe,QAAQ,CAACuB,aAAT,CAAuB1B,MAAvB,GAAgC,CAAhC,iBACG,oBAAC,iBAAD;AACI,QAAA,QAAQ,EAAEG,QADd;AAEI,QAAA,OAAO,EAAE,MAAM,KAAKX,gBAAL,CAAsBW,QAAtB,EAAgCf,GAAhC;AAFnB,QAFR,CAPW;AADnB,MAPJ,eAyBI,oBAAC,cAAD;AACI,MAAA,UAAU,EAAE;AAAEuC,QAAAA,EAAE,EAAE;AAAN,OADhB;AAEI,yBAAgB,yCAFpB;AAGI,MAAA,EAAE,EAAC,sBAHP;AAII,oBAAW;AAJf,oBAMI,oBAAC,QAAD;AACI,MAAA,OAAO,MADX;AAEI,MAAA,QAAQ,EAAE3D,gBAAgB,CAAC4D,KAF/B;AAGI,MAAA,QAAQ,EAAE,MAAM,KAAKjC,QAAL,CAAc;AAAEE,QAAAA,aAAa,EAAE;AAAjB,OAAd,CAHpB;AAII,MAAA,MAAM,eAAE,oBAAC,WAAD;AAAa,QAAA,QAAQ,EAAED,MAAM,IAAI,KAAKiC,eAAL,CAAqBzC,GAAG,GAAG,KAAKF,KAAL,CAAWO,SAAX,CAAqBC,IAArB,CAA0BM,MAAhC,GAAyC,CAA9D,EAAiEJ,MAAjE;AAAjC,QAJZ;AAKI,MAAA,MAAM,EAAE,KAAKN,KAAL,CAAWQ,WAAX,CAAuBV,GAAG,GAAG,KAAKF,KAAL,CAAWO,SAAX,CAAqBC,IAArB,CAA0BM,MAAhC,GAAyC,CAAhE,CALZ;AAMI,MAAA,aAAa,EAAE,cACX,oBAAC,gBAAD;AACI,QAAA,QAAQ,EAAEG,QADd;AAEI,QAAA,WAAW,EAAE,KAAKb,KAAL,CAAWW,WAAX,CAAuBU,GAAvB,CAA2BvB,GAA3B,CAFjB;AAGI,QAAA,kBAAkB,EAAE,KAAK0C,sBAAL,CAA4B1C,GAA5B,CAHxB;AAII,QAAA,OAAO,EAAE,MAAM;AACX,eAAKO,QAAL,CAAc;AAAEE,YAAAA,aAAa,EAAE;AAAjB,WAAd,EAAwC,MAAM;AAC1C,iBAAKgC,eAAL,CAAqBzC,GAAG,GAAG,KAAKF,KAAL,CAAWO,SAAX,CAAqBC,IAArB,CAA0BM,MAAhC,GAAyC,CAA9D,EAAiE,KAAjE;AACA,iBAAKR,gBAAL,CAAsBW,QAAtB,EAAgCf,GAAG,GAAG,KAAKF,KAAL,CAAWO,SAAX,CAAqBC,IAArB,CAA0BM,MAAhC,GAAyC,CAAzE;AACH,WAHD;AAIH;AATL,SAYS+B,MAAD,iBACI,oBAAC,YAAD;AAAc,QAAA,EAAE,EAAE,eAAe3C,GAAjC;AAAsC,QAAA,GAAG,EAAC,WAA1C;AAAsD,QAAA,OAAO,EAAE2C;AAA/D,sBACI,oBAAC,YAAD,OADJ,oBACqB,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QADrB,CAbZ,CADW,eAmBX,oBAAC,eAAD;AACI,QAAA,QAAQ,EAAE5B,QADd;AAEI,QAAA,WAAW,EAAE,KAAKb,KAAL,CAAWW,WAAX,CAAuBU,GAAvB,CAA2BvB,GAA3B,CAFjB;AAGI,QAAA,OAAO,EAAE,MAAM;AACX,eAAKO,QAAL,CAAc;AAAEE,YAAAA,aAAa,EAAE;AAAjB,WAAd,EAAwC,MAAM;AAC1C,iBAAKgC,eAAL,CAAqBzC,GAAG,GAAG,KAAKF,KAAL,CAAWO,SAAX,CAAqBC,IAArB,CAA0BM,MAAhC,GAAyC,CAA9D,EAAiE,KAAjE;AACA,iBAAKR,gBAAL,CAAsBW,QAAtB,EAAgCf,GAAG,GAAG,KAAKF,KAAL,CAAWO,SAAX,CAAqBC,IAArB,CAA0BM,MAAhC,GAAyC,CAAzE;AACH,WAHD;AAIH;AARL,SAWS+B,MAAD,iBACI,oBAAC,YAAD;AACI,QAAA,EAAE,EAAE,cAAc3C,GADtB;AAC2B,QAAA,GAAG,EAAC,UAD/B;AAEI,QAAA,UAAU,EAAE,KAAK4C,SAAL,CAAe5C,GAAf,IAAsB,CAFtC;AAGI,QAAA,OAAO,EAAE2C;AAHb,sBAKI,oBAAC,WAAD,OALJ,oBAKoB,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QALpB,CAZZ,CAnBW,eAwCX,oBAAC,mBAAD;AACI,QAAA,MAAM,EAAGA,MAAD,iBACJ,oBAAC,YAAD;AACI,UAAA,EAAE,EAAE,gBAAgB3C,GADxB;AAEI,UAAA,GAAG,EAAC,YAFR;AAGI,UAAA,UAAU,EAAE,KAAK4C,SAAL,CAAe5C,GAAf,IAAsB,CAHtC;AAII,UAAA,OAAO,EAAE2C;AAJb,wBAMI,oBAAC,WAAD,OANJ,oBAMoB,oBAAC,GAAD;AAAK,UAAA,MAAM,EAAC;AAAZ,UANpB,CAFR;AAWI,QAAA,UAAU,EAAC,SAXf;AAYI,QAAA,YAAY,EAAC,mBAZjB;AAaI,QAAA,OAAO,EAAE,MACL,KAAKpC,QAAL,CAAc;AAAEE,UAAAA,aAAa,EAAE;AAAjB,SAAd,EAAwC,MAAM;AAC1C,eAAKgC,eAAL,CAAqBzC,GAAG,GAAG,KAAKF,KAAL,CAAWO,SAAX,CAAqBC,IAArB,CAA0BM,MAAhC,GAAyC,CAA9D,EAAiE,KAAjE;AACH,SAFD,CAdR;AAkBI,QAAA,UAAU,EAAE,MAAM,KAAKU,WAAL,CAAiBP,QAAjB,EAA2Bf,GAA3B,EACbkB,IADa,CACR,MAAM,KAAKd,gBAAL,CAAsBW,QAAtB,EAAgCf,GAAG,GAAG,KAAKF,KAAL,CAAWO,SAAX,CAAqBC,IAArB,CAA0BM,MAAhC,GAAyC,CAAzE,CADE;AAlBtB,QAxCW;AANnB,MANJ,CAzBJ,eAqGI,oBAAC,cAAD;AACI,MAAA,EAAE,EAAG,WAAUZ,GAAI,EADvB;AAEI,MAAA,UAAU,EAAE;AAAE6C,QAAAA,OAAO,EAAE,QAAX;AAAqBN,QAAAA,EAAE,EAAE;AAAzB,OAFhB;AAGI,yBAAgB,aAHpB;AAII,oBAAW;AAJf,oBAMI,oBAAC,gBAAD;AACI,MAAA,QAAQ,EAAExB,QADd;AAEI,MAAA,WAAW,EAAE,KAAKb,KAAL,CAAWW,WAAX,CAAuBU,GAAvB,CAA2BvB,GAA3B,CAFjB;AAGI,MAAA,kBAAkB,EAAE,KAAK0C,sBAAL,CAA4B1C,GAA5B,CAHxB;AAII,MAAA,OAAO,EAAE,MAAM,KAAKI,gBAAL,CAAsBW,QAAtB,EAAgCf,GAAhC;AAJnB,OAOS2C,MAAD,iBACI,oBAAC,MAAD;AAAQ,MAAA,EAAE,EAAG,SAAQ3C,GAAI,EAAzB;AAA4B,MAAA,OAAO,EAAC,MAApC;AAA2C,MAAA,OAAO,EAAE2C;AAApD,oBACI,oBAAC,YAAD,OADJ,oBACqB,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MADrB,CARZ,CANJ,eAoBI,oBAAC,QAAD;AACI,MAAA,EAAE,EAAG,eAAc3C,GAAI,EAD3B;AAEI,MAAA,OAAO,MAFX;AAGI,MAAA,QAAQ,EAAEpB,gBAAgB,CAAC4D,KAH/B;AAII,MAAA,MAAM,eAAE,oBAAC,WAAD;AAAa,QAAA,QAAQ,EAAEhC,MAAM,IAAI,KAAKiC,eAAL,CAAqBzC,GAArB,EAA0BQ,MAA1B;AAAjC,QAJZ;AAKI,MAAA,QAAQ,EAAE,MAAM,KAAKD,QAAL,CAAc;AAAEE,QAAAA,aAAa,EAAE;AAAjB,OAAd,CALpB;AAMI,MAAA,MAAM,EAAE,KAAKP,KAAL,CAAWQ,WAAX,CAAuBV,GAAvB,CANZ;AAOI,MAAA,aAAa,EAAE,cACX,oBAAC,eAAD;AACI,QAAA,QAAQ,EAAEe,QADd;AAEI,QAAA,WAAW,EAAE,KAAKb,KAAL,CAAWW,WAAX,CAAuBU,GAAvB,CAA2BvB,GAA3B,CAFjB;AAGI,QAAA,OAAO,EAAE,MAAM;AACX,eAAKO,QAAL,CAAc;AAAEE,YAAAA,aAAa,EAAE;AAAjB,WAAd,EAAwC,MAAM;AAC1C,iBAAKgC,eAAL,CAAqBzC,GAArB,EAA0B,KAA1B;AACA,iBAAKI,gBAAL,CAAsBW,QAAtB,EAAgCf,GAAhC;AACH,WAHD;AAIH;AARL,SAWS2C,MAAD,iBACI,oBAAC,YAAD;AACI,QAAA,EAAE,EAAE,UAAU3C,GADlB;AAEI,QAAA,GAAG,EAAC,MAFR;AAGI,QAAA,SAAS,EAAC,QAHd;AAII,QAAA,UAAU,EAAE,KAAK4C,SAAL,CAAe5C,GAAf,IAAsB,CAJtC;AAKI,QAAA,OAAO,EAAE2C;AALb,sBAOI,oBAAC,WAAD,OAPJ,oBAOoB,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QAPpB,CAZZ,CADW,eAwBX,oBAAC,mBAAD;AACI,QAAA,MAAM,EAAGA,MAAD,iBACJ,oBAAC,YAAD;AACI,UAAA,EAAE,EAAE,YAAY3C,GADpB;AAEI,UAAA,GAAG,EAAC,QAFR;AAGI,UAAA,SAAS,EAAC,QAHd;AAII,UAAA,UAAU,EAAE,KAAK4C,SAAL,CAAe5C,GAAf,IAAsB,CAJtC;AAKI,UAAA,OAAO,EAAE2C;AALb,wBAOI,oBAAC,WAAD,OAPJ,oBAOoB,oBAAC,GAAD;AAAK,UAAA,MAAM,EAAC;AAAZ,UAPpB,CAFR;AAYI,QAAA,UAAU,EAAC,SAZf;AAaI,QAAA,YAAY,EAAC,mBAbjB;AAcI,QAAA,OAAO,EAAE,MACL,KAAKpC,QAAL,CAAc;AAAEE,UAAAA,aAAa,EAAE;AAAjB,SAAd,EAAwC,MAAM;AAC1C,eAAKgC,eAAL,CAAqBzC,GAArB,EAA0B,KAA1B;AACH,SAFD,CAfR;AAmBI,QAAA,UAAU,EAAE,MAAM,KAAKsB,WAAL,CAAiBP,QAAjB,EAA2Bf,GAA3B,EAAgCkB,IAAhC,CAAqC,MAAM,KAAKd,gBAAL,CAAsBW,QAAtB,EAAgCf,GAAhC,CAA3C;AAnBtB,QAxBW;AAPnB,MApBJ,CArGJ,CADJ,eAkLI,oBAAC,eAAD;AACI,MAAA,YAAY,EAAE,KADlB;AAEI,oBAAW,iBAFf;AAGI,MAAA,EAAE,EAAE,cAAcA,GAHtB;AAII,MAAA,QAAQ,EAAE,CAAC,KAAKE,KAAL,CAAWC,SAAX,CAAqBH,GAArB;AAJf,oBAMI,oBAAC,KAAD;AAAO,MAAA,SAAS;AAAhB,oBACI,oBAAC,SAAD,qBAAW,iCAAX,CADJ,eAEI,oBAAC,SAAD;AAAW,MAAA,EAAE,EAAE,8BAA8BA;AAA7C,OAAmD,KAAK0C,sBAAL,CAA4B1C,GAA5B,CAAnD,CAFJ,eAGI,oBAAC,SAAD,qBAAW,iCAAX,CAHJ,CANJ,CAlLJ,CADH,CA1BL,CADJ;AA8NH;;AAxRsF;;gBAA9EJ,c,iBACYT,qB","sourcesContent":["/*\n * Copyright 2018 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\n\nimport {\n DataList,\n DataListItem,\n DataListItemRow,\n DataListCell,\n DataListToggle,\n DataListContent,\n DataListItemCells,\n Level,\n LevelItem,\n Button,\n DataListAction,\n Dropdown,\n DropdownPosition,\n DropdownItem,\n KebabToggle\n} from '@patternfly/react-core';\nimport { css } from '@patternfly/react-styles';\n\nimport { Remove2Icon, RepositoryIcon, ShareAltIcon, EditAltIcon } from '@patternfly/react-icons';\n\nimport { HttpResponse } from '../../account-service/account.service';\nimport { AccountServiceContext } from '../../account-service/AccountServiceContext';\nimport { PermissionRequest } from \"./PermissionRequest\";\nimport { ShareTheResource } from \"./ShareTheResource\";\nimport { Permission, Resource } from \"./resource-model\";\nimport { Msg } from '../../widgets/Msg';\nimport { ResourcesTableState, ResourcesTableProps, AbstractResourcesTable } from './AbstractResourceTable';\nimport { EditTheResource } from './EditTheResource';\nimport { ContentAlert } from '../ContentAlert';\nimport EmptyMessageState from '../../widgets/EmptyMessageState';\nimport { ContinueCancelModal } from '../../widgets/ContinueCancelModal';\n\nexport interface CollapsibleResourcesTableState extends ResourcesTableState {\n isRowOpen: boolean[];\n contextOpen: boolean[];\n isModalActive: boolean;\n}\n\nexport class ResourcesTable extends AbstractResourcesTable {\n static contextType = AccountServiceContext;\n context: React.ContextType;\n\n public constructor(props: ResourcesTableProps, context: React.ContextType) {\n super(props);\n this.context = context;\n\n this.state = {\n isRowOpen: [],\n contextOpen: [],\n isModalActive: false,\n permissions: new Map()\n }\n }\n\n private onToggle = (row: number): void => {\n const newIsRowOpen: boolean[] = this.state.isRowOpen;\n newIsRowOpen[row] = !newIsRowOpen[row];\n if (newIsRowOpen[row]) this.fetchPermissions(this.props.resources.data[row], row);\n this.setState({ isRowOpen: newIsRowOpen });\n };\n\n private onContextToggle = (row: number, isOpen: boolean): void => {\n if (this.state.isModalActive) return;\n const data = this.props.resources.data;\n const contextOpen = this.state.contextOpen;\n contextOpen[row] = isOpen;\n if (isOpen) {\n const index = row > data.length ? row - data.length - 1 : row;\n this.fetchPermissions(data[index], index);\n }\n this.setState({ contextOpen });\n }\n\n private fetchPermissions(resource: Resource, row: number): void {\n this.context!.doGet(`/resources/${resource._id}/permissions`)\n .then((response: HttpResponse) => {\n const newPermissions: Map = new Map(this.state.permissions);\n newPermissions.set(row, response.data || []);\n this.setState({ permissions: newPermissions });\n });\n }\n\n private removeShare(resource: Resource, row: number): Promise {\n const permissions = this.state.permissions.get(row)!.map(a => ({ username: a.username, scopes: [] }));\n return this.context!.doPut(`/resources/${resource._id}/permissions`, permissions)\n .then(() => {\n ContentAlert.success(Msg.localize('unShareSuccess'));\n });\n }\n\n public render(): React.ReactNode {\n if (this.props.resources.data.length === 0) {\n return (\n \n );\n }\n return (\n \n \n \n // invisible toggle allows headings to line up properly\n \n \n \n \n \n ,\n \n \n ,\n \n \n ,\n ]}\n />\n \n \n {this.props.resources.data.map((resource: Resource, row: number) => (\n \n \n this.onToggle(row)}\n isExpanded={this.state.isRowOpen[row]}\n id={'resourceToggle-' + row}\n aria-controls=\"ex-expand1\"\n />\n \n \n ,\n \n {this.getClientName(resource.client)}\n ,\n \n {resource.shareRequests.length > 0 &&\n this.fetchPermissions(resource, row)}\n >\n }\n \n ]}\n />\n \n this.setState({ isModalActive: true })}\n toggle={ this.onContextToggle(row + this.props.resources.data.length + 1, isOpen)} />}\n isOpen={this.state.contextOpen[row + this.props.resources.data.length + 1]}\n dropdownItems={[\n {\n this.setState({ isModalActive: false }, () => {\n this.onContextToggle(row + this.props.resources.data.length + 1, false);\n this.fetchPermissions(resource, row + this.props.resources.data.length + 1);\n });\n }}\n >\n {\n (toggle: () => void) => (\n \n \n )\n }\n ,\n {\n this.setState({ isModalActive: false }, () => {\n this.onContextToggle(row + this.props.resources.data.length + 1, false);\n this.fetchPermissions(resource, row + this.props.resources.data.length + 1);\n });\n }}\n >\n {\n (toggle: () => void) => (\n \n \n )\n }\n ,\n void) => (\n \n \n \n )}\n modalTitle=\"unShare\"\n modalMessage=\"unShareAllConfirm\"\n onClose={() =>\n this.setState({ isModalActive: false }, () => {\n this.onContextToggle(row + this.props.resources.data.length + 1, false);\n })\n }\n onContinue={() => this.removeShare(resource, row)\n .then(() => this.fetchPermissions(resource, row + this.props.resources.data.length + 1))}\n />\n ]}\n />\n \n \n this.fetchPermissions(resource, row)}\n >\n {\n (toggle: () => void) => (\n \n )\n }\n \n this.onContextToggle(row, isOpen)} />}\n onSelect={() => this.setState({ isModalActive: true })}\n isOpen={this.state.contextOpen[row]}\n dropdownItems={[\n {\n this.setState({ isModalActive: false }, () => {\n this.onContextToggle(row, false);\n this.fetchPermissions(resource, row);\n });\n }}\n >\n {\n (toggle: () => void) => (\n \n \n )\n }\n ,\n void) => (\n \n \n \n )}\n modalTitle=\"unShare\"\n modalMessage='unShareAllConfirm'\n onClose={() =>\n this.setState({ isModalActive: false }, () => {\n this.onContextToggle(row, false);\n })\n }\n onContinue={() => this.removeShare(resource, row).then(() => this.fetchPermissions(resource, row))}\n />\n ]}\n />\n \n \n \n \n \n {this.sharedWithUsersMessage(row)}\n \n \n \n \n ))}\n \n );\n }\n}\n"],"file":"ResourcesTable.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/ShareTheResource.js b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/ShareTheResource.js new file mode 100644 index 0000000..310a010 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/ShareTheResource.js @@ -0,0 +1,222 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../../common/keycloak/web_modules/react.js"; +import { Button, Chip, ChipGroup, Form, FormGroup, Gallery, GalleryItem, Modal, Stack, StackItem, TextInput, ModalVariant } from "../../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { AccountServiceContext } from "../../account-service/AccountServiceContext.js"; +import { Msg } from "../../widgets/Msg.js"; +import { ContentAlert } from "../ContentAlert.js"; +import { PermissionSelect } from "./PermissionSelect.js"; + +/** + * @author Stan Silvert ssilvert@redhat.com (C) 2019 Red Hat Inc. + */ +export class ShareTheResource extends React.Component { + constructor(props, context) { + super(props); + + _defineProperty(this, "context", void 0); + + _defineProperty(this, "handleAddPermission", () => { + const rscId = this.props.resource._id; + const newPermissions = []; + + for (const permission of this.state.permissionsSelected) { + newPermissions.push(permission.name); + } + + const permissions = []; + + for (const username of this.state.usernames) { + permissions.push({ + username: username, + scopes: newPermissions + }); + } + + this.handleToggleDialog(); + this.context.doPut(`/resources/${rscId}/permissions`, permissions).then(() => { + ContentAlert.success('shareSuccess'); + this.props.onClose(); + }); + }); + + _defineProperty(this, "handleToggleDialog", () => { + if (this.state.isOpen) { + this.setState({ + isOpen: false + }); + this.props.onClose(); + } else { + this.clearState(); + this.setState({ + isOpen: true + }); + } + }); + + _defineProperty(this, "handleUsernameChange", username => { + this.setState({ + usernameInput: username + }); + }); + + _defineProperty(this, "handleAddUsername", async () => { + if (this.state.usernameInput !== '' && !this.state.usernames.includes(this.state.usernameInput)) { + const response = await this.context.doGet(`/resources/${this.props.resource._id}/user`, { + params: { + value: this.state.usernameInput + } + }); + + if (response.data && response.data.username) { + this.setState({ + usernameInput: '', + usernames: [...this.state.usernames, this.state.usernameInput] + }); + } else { + ContentAlert.info('userNotFound', [this.state.usernameInput]); + } + } + }); + + _defineProperty(this, "handleEnterKeyInAddField", event => { + if (event.key === "Enter") { + event.preventDefault(); + this.handleAddUsername(); + } + }); + + _defineProperty(this, "handleDeleteUsername", username => { + const newUsernames = this.state.usernames.filter(user => user !== username); + this.setState({ + usernames: newUsernames + }); + }); + + this.context = context; + this.state = { + isOpen: false, + permissionsSelected: [], + permissionsUnSelected: this.props.resource.scopes, + usernames: [], + usernameInput: '' + }; + } + + clearState() { + this.setState({ + permissionsSelected: [], + permissionsUnSelected: this.props.resource.scopes, + usernames: [], + usernameInput: '' + }); + } + + isAddDisabled() { + return this.state.usernameInput === '' || this.isAlreadyShared(); + } + + isAlreadyShared() { + for (let permission of this.props.permissions) { + if (permission.username === this.state.usernameInput) return true; + } + + return false; + } + + isFormInvalid() { + return this.state.usernames.length === 0 || this.state.permissionsSelected.length === 0; + } + + render() { + return /*#__PURE__*/React.createElement(React.Fragment, null, this.props.children(this.handleToggleDialog), /*#__PURE__*/React.createElement(Modal, { + title: 'Share the resource - ' + this.props.resource.name, + variant: ModalVariant.large, + isOpen: this.state.isOpen, + onClose: this.handleToggleDialog, + actions: [/*#__PURE__*/React.createElement(Button, { + key: "cancel", + variant: "link", + onClick: this.handleToggleDialog + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "cancel" + })), /*#__PURE__*/React.createElement(Button, { + key: "confirm", + variant: "primary", + id: "done", + onClick: this.handleAddPermission, + isDisabled: this.isFormInvalid() + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "done" + }))] + }, /*#__PURE__*/React.createElement(Stack, { + hasGutter: true + }, /*#__PURE__*/React.createElement(StackItem, { + isFilled: true + }, /*#__PURE__*/React.createElement(Form, null, /*#__PURE__*/React.createElement(FormGroup, { + label: "Add users to share your resource with", + type: "string", + helperTextInvalid: Msg.localize('resourceAlreadyShared'), + fieldId: "username", + isRequired: true + }, /*#__PURE__*/React.createElement(Gallery, { + hasGutter: true + }, /*#__PURE__*/React.createElement(GalleryItem, null, /*#__PURE__*/React.createElement(TextInput, { + value: this.state.usernameInput, + id: "username", + "aria-describedby": "username-helper", + placeholder: "Username or email", + onChange: this.handleUsernameChange, + onKeyPress: this.handleEnterKeyInAddField + })), /*#__PURE__*/React.createElement(GalleryItem, null, /*#__PURE__*/React.createElement(Button, { + key: "add-user", + variant: "primary", + id: "add", + onClick: this.handleAddUsername, + isDisabled: this.isAddDisabled() + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "add" + })))), /*#__PURE__*/React.createElement(ChipGroup, { + categoryName: Msg.localize('shareWith') + }, this.state.usernames.map(currentChip => /*#__PURE__*/React.createElement(Chip, { + key: currentChip, + onClick: () => this.handleDeleteUsername(currentChip) + }, currentChip)))), /*#__PURE__*/React.createElement(FormGroup, { + label: "", + fieldId: "permissions-selected" + }, /*#__PURE__*/React.createElement(PermissionSelect, { + scopes: this.state.permissionsUnSelected, + onSelect: selection => this.setState({ + permissionsSelected: selection + }), + direction: "up" + })))), /*#__PURE__*/React.createElement(StackItem, { + isFilled: true + }, /*#__PURE__*/React.createElement("br", null)), /*#__PURE__*/React.createElement(StackItem, { + isFilled: true + }, this.props.sharedWithUsersMsg)))); + } + +} + +_defineProperty(ShareTheResource, "defaultProps", { + permissions: [] +}); + +_defineProperty(ShareTheResource, "contextType", AccountServiceContext); +//# sourceMappingURL=ShareTheResource.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/ShareTheResource.js.map b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/ShareTheResource.js.map new file mode 100644 index 0000000..5bc9431 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/ShareTheResource.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/my-resources-page/ShareTheResource.tsx"],"names":["React","Button","Chip","ChipGroup","Form","FormGroup","Gallery","GalleryItem","Modal","Stack","StackItem","TextInput","ModalVariant","AccountServiceContext","Msg","ContentAlert","PermissionSelect","ShareTheResource","Component","constructor","props","context","rscId","resource","_id","newPermissions","permission","state","permissionsSelected","push","name","permissions","username","usernames","scopes","handleToggleDialog","doPut","then","success","onClose","isOpen","setState","clearState","usernameInput","includes","response","doGet","params","value","data","info","event","key","preventDefault","handleAddUsername","newUsernames","filter","user","permissionsUnSelected","isAddDisabled","isAlreadyShared","isFormInvalid","length","render","children","large","handleAddPermission","localize","handleUsernameChange","handleEnterKeyInAddField","map","currentChip","handleDeleteUsername","selection","sharedWithUsersMsg"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AAEA,SACIC,MADJ,EAEIC,IAFJ,EAGIC,SAHJ,EAIIC,IAJJ,EAKIC,SALJ,EAMIC,OANJ,EAOIC,WAPJ,EAQIC,KARJ,EASIC,KATJ,EAUIC,SAVJ,EAWIC,SAXJ,EAYIC,YAZJ;AAeA,SAASC,qBAAT;AAEA,SAASC,GAAT;AACA,SAAQC,YAAR;AACA,SAASC,gBAAT;;AAkBA;AACA;AACA;AACA,OAAO,MAAMC,gBAAN,SAA+BjB,KAAK,CAACkB,SAArC,CAA6F;AAKzFC,EAAAA,WAAW,CAACC,KAAD,EAA+BC,OAA/B,EAAyF;AACvG,UAAMD,KAAN;;AADuG;;AAAA,iDAsB7E,MAAM;AAChC,YAAME,KAAa,GAAG,KAAKF,KAAL,CAAWG,QAAX,CAAoBC,GAA1C;AACA,YAAMC,cAAwB,GAAG,EAAjC;;AAEA,WAAK,MAAMC,UAAX,IAAyB,KAAKC,KAAL,CAAWC,mBAApC,EAAyD;AACrDH,QAAAA,cAAc,CAACI,IAAf,CAAoBH,UAAU,CAACI,IAA/B;AACH;;AAED,YAAMC,WAAW,GAAG,EAApB;;AAEA,WAAK,MAAMC,QAAX,IAAuB,KAAKL,KAAL,CAAWM,SAAlC,EAA6C;AACzCF,QAAAA,WAAW,CAACF,IAAZ,CAAiB;AAACG,UAAAA,QAAQ,EAAEA,QAAX;AAAqBE,UAAAA,MAAM,EAAET;AAA7B,SAAjB;AACH;;AAED,WAAKU,kBAAL;AAEA,WAAKd,OAAL,CAAce,KAAd,CAAqB,cAAad,KAAM,cAAxC,EAAuDS,WAAvD,EACKM,IADL,CACU,MAAM;AACRtB,QAAAA,YAAY,CAACuB,OAAb,CAAqB,cAArB;AACA,aAAKlB,KAAL,CAAWmB,OAAX;AACH,OAJL;AAKH,KA3C0G;;AAAA,gDA6C9E,MAAM;AAChC,UAAI,KAAKZ,KAAL,CAAWa,MAAf,EAAuB;AACnB,aAAKC,QAAL,CAAc;AAACD,UAAAA,MAAM,EAAE;AAAT,SAAd;AACA,aAAKpB,KAAL,CAAWmB,OAAX;AACH,OAHD,MAGO;AACH,aAAKG,UAAL;AACA,aAAKD,QAAL,CAAc;AAACD,UAAAA,MAAM,EAAE;AAAT,SAAd;AACH;AACH,KArD0G;;AAAA,kDAuD3ER,QAAD,IAAsB;AACjD,WAAKS,QAAL,CAAc;AAACE,QAAAA,aAAa,EAAEX;AAAhB,OAAd;AACH,KAzD0G;;AAAA,+CA2D/E,YAAY;AACpC,UAAK,KAAKL,KAAL,CAAWgB,aAAX,KAA6B,EAA9B,IAAsC,CAAC,KAAKhB,KAAL,CAAWM,SAAX,CAAqBW,QAArB,CAA8B,KAAKjB,KAAL,CAAWgB,aAAzC,CAA3C,EAAqG;AACjG,cAAME,QAAQ,GAAG,MAAM,KAAKxB,OAAL,CAAcyB,KAAd,CAAyC,cAAa,KAAK1B,KAAL,CAAWG,QAAX,CAAoBC,GAAI,OAA9E,EAAsF;AAAEuB,UAAAA,MAAM,EAAE;AAAEC,YAAAA,KAAK,EAAE,KAAKrB,KAAL,CAAWgB;AAApB;AAAV,SAAtF,CAAvB;;AACA,YAAIE,QAAQ,CAACI,IAAT,IAAiBJ,QAAQ,CAACI,IAAT,CAAcjB,QAAnC,EAA6C;AACzC,eAAKS,QAAL,CAAc;AAAEE,YAAAA,aAAa,EAAE,EAAjB;AAAqBV,YAAAA,SAAS,EAAE,CAAC,GAAG,KAAKN,KAAL,CAAWM,SAAf,EAA0B,KAAKN,KAAL,CAAWgB,aAArC;AAAhC,WAAd;AACH,SAFD,MAEO;AACH5B,UAAAA,YAAY,CAACmC,IAAb,CAAkB,cAAlB,EAAkC,CAAC,KAAKvB,KAAL,CAAWgB,aAAZ,CAAlC;AACH;AACJ;AACJ,KApE0G;;AAAA,sDAsEvEQ,KAAD,IAAgC;AAC/D,UAAIA,KAAK,CAACC,GAAN,KAAc,OAAlB,EAA2B;AACvBD,QAAAA,KAAK,CAACE,cAAN;AACA,aAAKC,iBAAL;AACH;AACJ,KA3E0G;;AAAA,kDA6E3EtB,QAAD,IAAsB;AACjD,YAAMuB,YAAsB,GAAG,KAAK5B,KAAL,CAAWM,SAAX,CAAqBuB,MAArB,CAA4BC,IAAI,IAAIA,IAAI,KAAKzB,QAA7C,CAA/B;AACA,WAAKS,QAAL,CAAc;AAACR,QAAAA,SAAS,EAAEsB;AAAZ,OAAd;AACH,KAhF0G;;AAEvG,SAAKlC,OAAL,GAAeA,OAAf;AAEA,SAAKM,KAAL,GAAa;AACTa,MAAAA,MAAM,EAAE,KADC;AAETZ,MAAAA,mBAAmB,EAAE,EAFZ;AAGT8B,MAAAA,qBAAqB,EAAE,KAAKtC,KAAL,CAAWG,QAAX,CAAoBW,MAHlC;AAITD,MAAAA,SAAS,EAAE,EAJF;AAKTU,MAAAA,aAAa,EAAE;AALN,KAAb;AAOH;;AAEOD,EAAAA,UAAU,GAAS;AACvB,SAAKD,QAAL,CAAc;AACVb,MAAAA,mBAAmB,EAAE,EADX;AAEV8B,MAAAA,qBAAqB,EAAE,KAAKtC,KAAL,CAAWG,QAAX,CAAoBW,MAFjC;AAGVD,MAAAA,SAAS,EAAE,EAHD;AAIVU,MAAAA,aAAa,EAAE;AAJL,KAAd;AAMH;;AA8DOgB,EAAAA,aAAa,GAAY;AAC7B,WAAO,KAAKhC,KAAL,CAAWgB,aAAX,KAA6B,EAA7B,IAAmC,KAAKiB,eAAL,EAA1C;AACH;;AAEOA,EAAAA,eAAe,GAAY;AAC/B,SAAK,IAAIlC,UAAT,IAAuB,KAAKN,KAAL,CAAWW,WAAlC,EAA+C;AAC3C,UAAIL,UAAU,CAACM,QAAX,KAAwB,KAAKL,KAAL,CAAWgB,aAAvC,EAAsD,OAAO,IAAP;AACzD;;AAED,WAAO,KAAP;AACH;;AAEOkB,EAAAA,aAAa,GAAY;AAC7B,WAAQ,KAAKlC,KAAL,CAAWM,SAAX,CAAqB6B,MAArB,KAAgC,CAAjC,IAAwC,KAAKnC,KAAL,CAAWC,mBAAX,CAA+BkC,MAA/B,KAA0C,CAAzF;AACH;;AAEMC,EAAAA,MAAM,GAAoB;AAC7B,wBACI,oBAAC,KAAD,CAAO,QAAP,QACK,KAAK3C,KAAL,CAAW4C,QAAX,CAAoB,KAAK7B,kBAAzB,CADL,eAGI,oBAAC,KAAD;AACA,MAAA,KAAK,EAAE,0BAA0B,KAAKf,KAAL,CAAWG,QAAX,CAAoBO,IADrD;AAEA,MAAA,OAAO,EAAElB,YAAY,CAACqD,KAFtB;AAGA,MAAA,MAAM,EAAE,KAAKtC,KAAL,CAAWa,MAHnB;AAIA,MAAA,OAAO,EAAE,KAAKL,kBAJd;AAKA,MAAA,OAAO,EAAE,cACL,oBAAC,MAAD;AAAQ,QAAA,GAAG,EAAC,QAAZ;AAAqB,QAAA,OAAO,EAAC,MAA7B;AAAoC,QAAA,OAAO,EAAE,KAAKA;AAAlD,sBACI,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QADJ,CADK,eAIL,oBAAC,MAAD;AAAQ,QAAA,GAAG,EAAC,SAAZ;AAAsB,QAAA,OAAO,EAAC,SAA9B;AAAwC,QAAA,EAAE,EAAC,MAA3C;AAAkD,QAAA,OAAO,EAAE,KAAK+B,mBAAhE;AAAqF,QAAA,UAAU,EAAE,KAAKL,aAAL;AAAjG,sBACI,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QADJ,CAJK;AALT,oBAcI,oBAAC,KAAD;AAAO,MAAA,SAAS;AAAhB,oBACI,oBAAC,SAAD;AAAW,MAAA,QAAQ;AAAnB,oBACA,oBAAC,IAAD,qBACI,oBAAC,SAAD;AACI,MAAA,KAAK,EAAC,uCADV;AAEI,MAAA,IAAI,EAAC,QAFT;AAGI,MAAA,iBAAiB,EAAE/C,GAAG,CAACqD,QAAJ,CAAa,uBAAb,CAHvB;AAII,MAAA,OAAO,EAAC,UAJZ;AAKI,MAAA,UAAU;AALd,oBAOQ,oBAAC,OAAD;AAAS,MAAA,SAAS;AAAlB,oBACI,oBAAC,WAAD,qBACI,oBAAC,SAAD;AACI,MAAA,KAAK,EAAE,KAAKxC,KAAL,CAAWgB,aADtB;AAEI,MAAA,EAAE,EAAC,UAFP;AAGI,0BAAiB,iBAHrB;AAII,MAAA,WAAW,EAAC,mBAJhB;AAKI,MAAA,QAAQ,EAAE,KAAKyB,oBALnB;AAMI,MAAA,UAAU,EAAE,KAAKC;AANrB,MADJ,CADJ,eAWI,oBAAC,WAAD,qBACI,oBAAC,MAAD;AAAQ,MAAA,GAAG,EAAC,UAAZ;AAAuB,MAAA,OAAO,EAAC,SAA/B;AAAyC,MAAA,EAAE,EAAC,KAA5C;AAAkD,MAAA,OAAO,EAAE,KAAKf,iBAAhE;AAAmF,MAAA,UAAU,EAAE,KAAKK,aAAL;AAA/F,oBACI,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MADJ,CADJ,CAXJ,CAPR,eAyBI,oBAAC,SAAD;AAAW,MAAA,YAAY,EAAE7C,GAAG,CAACqD,QAAJ,CAAa,WAAb;AAAzB,OACK,KAAKxC,KAAL,CAAWM,SAAX,CAAqBqC,GAArB,CAA0BC,WAAD,iBACtB,oBAAC,IAAD;AAAM,MAAA,GAAG,EAAEA,WAAX;AAAwB,MAAA,OAAO,EAAE,MAAM,KAAKC,oBAAL,CAA0BD,WAA1B;AAAvC,OACKA,WADL,CADH,CADL,CAzBJ,CADJ,eAkCI,oBAAC,SAAD;AACI,MAAA,KAAK,EAAC,EADV;AAEI,MAAA,OAAO,EAAC;AAFZ,oBAII,oBAAC,gBAAD;AACI,MAAA,MAAM,EAAE,KAAK5C,KAAL,CAAW+B,qBADvB;AAEI,MAAA,QAAQ,EAAEe,SAAS,IAAI,KAAKhC,QAAL,CAAc;AAAEb,QAAAA,mBAAmB,EAAE6C;AAAvB,OAAd,CAF3B;AAGI,MAAA,SAAS,EAAC;AAHd,MAJJ,CAlCJ,CADA,CADJ,eAgDA,oBAAC,SAAD;AAAW,MAAA,QAAQ;AAAnB,oBAAoB,+BAApB,CAhDA,eAiDA,oBAAC,SAAD;AAAW,MAAA,QAAQ;AAAnB,OACK,KAAKrD,KAAL,CAAWsD,kBADhB,CAjDA,CAdJ,CAHJ,CADJ;AA2EH;;AAnL+F;;gBAAvFzD,gB,kBAC2B;AAACc,EAAAA,WAAW,EAAE;AAAd,C;;gBAD3Bd,gB,iBAEYJ,qB","sourcesContent":["/*\n * Copyright 2019 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\n\nimport {\n Button,\n Chip,\n ChipGroup,\n Form,\n FormGroup,\n Gallery,\n GalleryItem,\n Modal,\n Stack,\n StackItem,\n TextInput,\n ModalVariant\n} from '@patternfly/react-core';\n\nimport { AccountServiceContext } from '../../account-service/AccountServiceContext';\nimport { Resource, Permission, Scope } from './resource-model';\nimport { Msg } from '../../widgets/Msg';\nimport {ContentAlert} from '../ContentAlert';\nimport { PermissionSelect } from './PermissionSelect';\n\ninterface ShareTheResourceProps {\n resource: Resource;\n permissions: Permission[];\n sharedWithUsersMsg: React.ReactNode;\n onClose: () => void;\n children: (toggle: () => void) => void;\n}\n\ninterface ShareTheResourceState {\n isOpen: boolean;\n permissionsSelected: Scope[];\n permissionsUnSelected: Scope[];\n usernames: string[];\n usernameInput: string;\n}\n\n/**\n * @author Stan Silvert ssilvert@redhat.com (C) 2019 Red Hat Inc.\n */\nexport class ShareTheResource extends React.Component {\n protected static defaultProps:any = {permissions: []};\n static contextType = AccountServiceContext;\n context: React.ContextType;\n\n public constructor(props: ShareTheResourceProps, context: React.ContextType) {\n super(props);\n this.context = context;\n \n this.state = {\n isOpen: false,\n permissionsSelected: [],\n permissionsUnSelected: this.props.resource.scopes,\n usernames: [],\n usernameInput: ''\n };\n }\n\n private clearState(): void {\n this.setState({\n permissionsSelected: [],\n permissionsUnSelected: this.props.resource.scopes,\n usernames: [],\n usernameInput: ''\n });\n }\n\n private handleAddPermission = () => {\n const rscId: string = this.props.resource._id;\n const newPermissions: string[] = [];\n\n for (const permission of this.state.permissionsSelected) {\n newPermissions.push(permission.name);\n }\n\n const permissions = [];\n\n for (const username of this.state.usernames) {\n permissions.push({username: username, scopes: newPermissions});\n }\n\n this.handleToggleDialog();\n\n this.context!.doPut(`/resources/${rscId}/permissions`, permissions)\n .then(() => {\n ContentAlert.success('shareSuccess');\n this.props.onClose();\n })\n };\n\n private handleToggleDialog = () => {\n if (this.state.isOpen) {\n this.setState({isOpen: false});\n this.props.onClose();\n } else {\n this.clearState();\n this.setState({isOpen: true});\n }\n };\n\n private handleUsernameChange = (username: string) => {\n this.setState({usernameInput: username});\n }\n\n private handleAddUsername = async () => {\n if ((this.state.usernameInput !== '') && (!this.state.usernames.includes(this.state.usernameInput))) {\n const response = await this.context!.doGet<{username: string}>(`/resources/${this.props.resource._id}/user`, { params: { value: this.state.usernameInput } });\n if (response.data && response.data.username) {\n this.setState({ usernameInput: '', usernames: [...this.state.usernames, this.state.usernameInput] });\n } else {\n ContentAlert.info('userNotFound', [this.state.usernameInput]);\n }\n }\n }\n\n private handleEnterKeyInAddField = (event: React.KeyboardEvent) => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n this.handleAddUsername();\n }\n }\n\n private handleDeleteUsername = (username: string) => {\n const newUsernames: string[] = this.state.usernames.filter(user => user !== username);\n this.setState({usernames: newUsernames});\n }\n\n private isAddDisabled(): boolean {\n return this.state.usernameInput === '' || this.isAlreadyShared();\n }\n\n private isAlreadyShared(): boolean {\n for (let permission of this.props.permissions) {\n if (permission.username === this.state.usernameInput) return true;\n }\n\n return false;\n }\n\n private isFormInvalid(): boolean {\n return (this.state.usernames.length === 0) || (this.state.permissionsSelected.length === 0);\n }\n\n public render(): React.ReactNode {\n return (\n \n {this.props.children(this.handleToggleDialog)}\n\n \n \n ,\n \n ]}\n >\n \n \n
    \n \n \n \n \n \n \n \n \n\n \n \n {this.state.usernames.map((currentChip: string) => (\n this.handleDeleteUsername(currentChip)}>\n {currentChip}\n \n ))}\n \n \n \n this.setState({ permissionsSelected: selection })}\n direction=\"up\"\n />\n \n \n
    \n
    \n \n {this.props.sharedWithUsersMsg}\n \n\n
    \n \n
    \n );\n }\n}\n"],"file":"ShareTheResource.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/SharedResourcesTable.js b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/SharedResourcesTable.js new file mode 100644 index 0000000..48acf12 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/SharedResourcesTable.js @@ -0,0 +1,97 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../../common/keycloak/web_modules/react.js"; +import { DataList, DataListItem, DataListItemRow, DataListCell, DataListItemCells, ChipGroup, Chip } from "../../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { RepositoryIcon } from "../../../../common/keycloak/web_modules/@patternfly/react-icons.js"; +import { Msg } from "../../widgets/Msg.js"; +import { AbstractResourcesTable } from "./AbstractResourceTable.js"; +import EmptyMessageState from "../../widgets/EmptyMessageState.js"; +export class SharedResourcesTable extends AbstractResourcesTable { + constructor(props) { + super(props); + this.state = { + permissions: new Map() + }; + } + + render() { + if (this.props.resources.data.length === 0) { + return /*#__PURE__*/React.createElement(EmptyMessageState, { + icon: RepositoryIcon, + messageKey: "noResourcesSharedWithYou" + }); + } + + return /*#__PURE__*/React.createElement(DataList, { + "aria-label": Msg.localize('resources'), + id: "sharedResourcesList" + }, /*#__PURE__*/React.createElement(DataListItem, { + key: "resource-header", + "aria-labelledby": "resource-header" + }, /*#__PURE__*/React.createElement(DataListItemRow, null, /*#__PURE__*/React.createElement(DataListItemCells, { + dataListCells: [/*#__PURE__*/React.createElement(DataListCell, { + key: "resource-name-header", + width: 2 + }, /*#__PURE__*/React.createElement("strong", null, /*#__PURE__*/React.createElement(Msg, { + msgKey: "resourceName" + }))), /*#__PURE__*/React.createElement(DataListCell, { + key: "application-name-header", + width: 2 + }, /*#__PURE__*/React.createElement("strong", null, /*#__PURE__*/React.createElement(Msg, { + msgKey: "application" + }))), /*#__PURE__*/React.createElement(DataListCell, { + key: "permission-header", + width: 2 + }), /*#__PURE__*/React.createElement(DataListCell, { + key: "requests-header", + width: 2 + })] + }))), this.props.resources.data.map((resource, row) => /*#__PURE__*/React.createElement(DataListItem, { + key: 'resource-' + row, + "aria-labelledby": resource.name + }, /*#__PURE__*/React.createElement(DataListItemRow, null, /*#__PURE__*/React.createElement(DataListItemCells, { + dataListCells: [/*#__PURE__*/React.createElement(DataListCell, { + key: 'resourceName-' + row, + width: 2 + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: resource.name + })), /*#__PURE__*/React.createElement(DataListCell, { + key: 'resourceClient-' + row, + width: 2 + }, /*#__PURE__*/React.createElement("a", { + href: resource.client.baseUrl + }, this.getClientName(resource.client))), /*#__PURE__*/React.createElement(DataListCell, { + key: 'permissions-' + row, + width: 2 + }, resource.scopes.length > 0 && /*#__PURE__*/React.createElement(ChipGroup, { + categoryName: Msg.localize('permissions') + }, resource.scopes.map(scope => /*#__PURE__*/React.createElement(Chip, { + key: scope.name, + isReadOnly: true + }, scope.displayName || scope.name)))), /*#__PURE__*/React.createElement(DataListCell, { + key: 'pending-' + row, + width: 2 + }, resource.shareRequests.length > 0 && /*#__PURE__*/React.createElement(ChipGroup, { + categoryName: Msg.localize('pending') + }, resource.shareRequests[0].scopes.map(scope => /*#__PURE__*/React.createElement(Chip, { + key: scope.name, + isReadOnly: true + }, scope.displayName || scope.name))))] + }))))); + } + +} +//# sourceMappingURL=SharedResourcesTable.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/SharedResourcesTable.js.map b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/SharedResourcesTable.js.map new file mode 100644 index 0000000..5e6255d --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/SharedResourcesTable.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/my-resources-page/SharedResourcesTable.tsx"],"names":["React","DataList","DataListItem","DataListItemRow","DataListCell","DataListItemCells","ChipGroup","Chip","RepositoryIcon","Msg","AbstractResourcesTable","EmptyMessageState","SharedResourcesTable","constructor","props","state","permissions","Map","render","resources","data","length","localize","map","resource","row","name","client","baseUrl","getClientName","scopes","scope","displayName","shareRequests"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AAEA,SACIC,QADJ,EAEIC,YAFJ,EAGIC,eAHJ,EAIIC,YAJJ,EAKIC,iBALJ,EAMIC,SANJ,EAOIC,IAPJ;AASA,SAASC,cAAT;AAIA,SAASC,GAAT;AACA,SAASC,sBAAT;AACA,OAAOC,iBAAP;AAOA,OAAO,MAAMC,oBAAN,SAAmCF,sBAAnC,CAA+E;AAE3EG,EAAAA,WAAW,CAACC,KAAD,EAA6B;AAC3C,UAAMA,KAAN;AACA,SAAKC,KAAL,GAAa;AACTC,MAAAA,WAAW,EAAE,IAAIC,GAAJ;AADJ,KAAb;AAGH;;AAEMC,EAAAA,MAAM,GAAoB;AAC7B,QAAI,KAAKJ,KAAL,CAAWK,SAAX,CAAqBC,IAArB,CAA0BC,MAA1B,KAAqC,CAAzC,EAA4C;AACxC,0BACI,oBAAC,iBAAD;AAAmB,QAAA,IAAI,EAAEb,cAAzB;AAAyC,QAAA,UAAU,EAAC;AAApD,QADJ;AAGH;;AACD,wBACI,oBAAC,QAAD;AAAU,oBAAYC,GAAG,CAACa,QAAJ,CAAa,WAAb,CAAtB;AAAiD,MAAA,EAAE,EAAC;AAApD,oBACI,oBAAC,YAAD;AAAc,MAAA,GAAG,EAAC,iBAAlB;AAAoC,yBAAgB;AAApD,oBACI,oBAAC,eAAD,qBACI,oBAAC,iBAAD;AACI,MAAA,aAAa,EAAE,cACX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC,sBAAlB;AAAyC,QAAA,KAAK,EAAE;AAAhD,sBACI,iDAAQ,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QAAR,CADJ,CADW,eAIX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC,yBAAlB;AAA4C,QAAA,KAAK,EAAE;AAAnD,sBACI,iDAAQ,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QAAR,CADJ,CAJW,eAOX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC,mBAAlB;AAAsC,QAAA,KAAK,EAAE;AAA7C,QAPW,eAQX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC,iBAAlB;AAAoC,QAAA,KAAK,EAAE;AAA3C,QARW;AADnB,MADJ,CADJ,CADJ,EAiBK,KAAKR,KAAL,CAAWK,SAAX,CAAqBC,IAArB,CAA0BG,GAA1B,CAA8B,CAACC,QAAD,EAAqBC,GAArB,kBAC3B,oBAAC,YAAD;AAAc,MAAA,GAAG,EAAE,cAAcA,GAAjC;AAAsC,yBAAiBD,QAAQ,CAACE;AAAhE,oBACI,oBAAC,eAAD,qBACI,oBAAC,iBAAD;AACI,MAAA,aAAa,EAAE,cACX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAE,kBAAkBD,GAArC;AAA0C,QAAA,KAAK,EAAE;AAAjD,sBACI,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAED,QAAQ,CAACE;AAAtB,QADJ,CADW,eAIX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAE,oBAAoBD,GAAvC;AAA4C,QAAA,KAAK,EAAE;AAAnD,sBACI;AAAG,QAAA,IAAI,EAAED,QAAQ,CAACG,MAAT,CAAgBC;AAAzB,SAAmC,KAAKC,aAAL,CAAmBL,QAAQ,CAACG,MAA5B,CAAnC,CADJ,CAJW,eAOX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAE,iBAAiBF,GAApC;AAAyC,QAAA,KAAK,EAAE;AAAhD,SACMD,QAAQ,CAACM,MAAT,CAAgBT,MAAhB,GAAyB,CAAzB,iBACF,oBAAC,SAAD;AAAW,QAAA,YAAY,EAAEZ,GAAG,CAACa,QAAJ,CAAa,aAAb;AAAzB,SAEQE,QAAQ,CAACM,MAAT,CAAgBP,GAAhB,CAAoBQ,KAAK,iBACrB,oBAAC,IAAD;AAAM,QAAA,GAAG,EAAEA,KAAK,CAACL,IAAjB;AAAuB,QAAA,UAAU;AAAjC,SACKK,KAAK,CAACC,WAAN,IAAqBD,KAAK,CAACL,IADhC,CADJ,CAFR,CAFJ,CAPW,eAmBX,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAE,aAAaD,GAAhC;AAAqC,QAAA,KAAK,EAAE;AAA5C,SACKD,QAAQ,CAACS,aAAT,CAAuBZ,MAAvB,GAAgC,CAAhC,iBACD,oBAAC,SAAD;AAAW,QAAA,YAAY,EAAEZ,GAAG,CAACa,QAAJ,CAAa,SAAb;AAAzB,SAESE,QAAQ,CAACS,aAAT,CAAuB,CAAvB,EAA0BH,MAA3B,CAA8CP,GAA9C,CAAkDQ,KAAK,iBACnD,oBAAC,IAAD;AAAM,QAAA,GAAG,EAAEA,KAAK,CAACL,IAAjB;AAAuB,QAAA,UAAU;AAAjC,SACKK,KAAK,CAACC,WAAN,IAAqBD,KAAK,CAACL,IADhC,CADJ,CAFR,CAFJ,CAnBW;AADnB,MADJ,CADJ,CADH,CAjBL,CADJ;AA6DH;;AA5EiF","sourcesContent":["/*\n * Copyright 2018 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\n\nimport {\n DataList,\n DataListItem,\n DataListItemRow,\n DataListCell,\n DataListItemCells,\n ChipGroup,\n Chip\n } from '@patternfly/react-core';\nimport { RepositoryIcon } from '@patternfly/react-icons';\n\n\nimport { PaginatedResources, Resource, Scope } from \"./resource-model\";\nimport { Msg } from '../../widgets/Msg';\nimport { AbstractResourcesTable, ResourcesTableState } from './AbstractResourceTable';\nimport EmptyMessageState from '../../widgets/EmptyMessageState';\n\nexport interface ResourcesTableProps {\n resources: PaginatedResources;\n noResourcesMessage: string;\n}\n\nexport class SharedResourcesTable extends AbstractResourcesTable {\n\n public constructor(props: ResourcesTableProps) {\n super(props);\n this.state = {\n permissions: new Map()\n }\n }\n\n public render(): React.ReactNode {\n if (this.props.resources.data.length === 0) {\n return (\n \n );\n }\n return (\n \n \n \n \n \n ,\n \n \n ,\n ,\n ,\n ]}\n />\n \n \n {this.props.resources.data.map((resource: Resource, row: number) => (\n \n \n \n \n ,\n \n {this.getClientName(resource.client)}\n ,\n \n { resource.scopes.length > 0 &&\n \n {\n resource.scopes.map(scope => (\n \n {scope.displayName || scope.name}\n \n ))\n }\n }\n ,\n \n {resource.shareRequests.length > 0 &&\n \n {\n (resource.shareRequests[0].scopes as Scope[]).map(scope => (\n \n {scope.displayName || scope.name}\n \n ))\n }\n \n }\n \n ]}\n />\n \n \n ))}\n \n );\n }\n}\n"],"file":"SharedResourcesTable.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/resource-model.js b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/resource-model.js new file mode 100644 index 0000000..2ab8c4e --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/resource-model.js @@ -0,0 +1,16 @@ +export class Scope { + constructor(name, displayName) { + this.name = name; + this.displayName = displayName; + } + + toString() { + if (this.hasOwnProperty('displayName') && this.displayName) { + return this.displayName; + } else { + return this.name; + } + } + +} +//# sourceMappingURL=resource-model.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/resource-model.js.map b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/resource-model.js.map new file mode 100644 index 0000000..2650a61 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/my-resources-page/resource-model.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/my-resources-page/resource-model.ts"],"names":["Scope","constructor","name","displayName","toString","hasOwnProperty"],"mappings":"AAeA,OAAO,MAAMA,KAAN,CAAY;AACVC,EAAAA,WAAW,CAAQC,IAAR,EAA6BC,WAA7B,EAAmD;AAAA,SAA3CD,IAA2C,GAA3CA,IAA2C;AAAA,SAAtBC,WAAsB,GAAtBA,WAAsB;AAAE;;AAEhEC,EAAAA,QAAQ,GAAW;AACtB,QAAI,KAAKC,cAAL,CAAoB,aAApB,KAAuC,KAAKF,WAAhD,EAA8D;AAC1D,aAAO,KAAKA,WAAZ;AACH,KAFD,MAEO;AACH,aAAO,KAAKD,IAAZ;AACH;AACJ;;AATgB","sourcesContent":["export interface Resource {\n _id: string;\n name: string;\n client: Client;\n scopes: Scope[];\n uris: string[];\n shareRequests: Permission[];\n}\n\nexport interface Client {\n baseUrl: string;\n clientId: string;\n name?: string;\n}\n\nexport class Scope {\n public constructor(public name: string, public displayName?: string) {}\n\n public toString(): string {\n if (this.hasOwnProperty('displayName') && (this.displayName)) {\n return this.displayName;\n } else {\n return this.name;\n }\n }\n}\n\nexport interface PaginatedResources {\n nextUrl: string;\n prevUrl: string;\n data: Resource[];\n}\n\nexport interface Permission {\n email?: string;\n firstName?: string;\n lastName?: string;\n scopes: Scope[] | string[]; // this should be Scope[] - fix API\n username: string;\n}\n\nexport interface Permissions {\n permissions: Permission[];\n row?: number;\n}\n"],"file":"resource-model.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/page-not-found/PageNotFound.js b/keycloak-themes/keycloak.v2/account/resources/content/page-not-found/PageNotFound.js new file mode 100644 index 0000000..5d89b58 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/page-not-found/PageNotFound.js @@ -0,0 +1,31 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +import * as React from "../../../../common/keycloak/web_modules/react.js"; +import { WarningTriangleIcon } from "../../../../common/keycloak/web_modules/@patternfly/react-icons.js"; +import { withRouter } from "../../../../common/keycloak/web_modules/react-router-dom.js"; +import { Msg } from "../../widgets/Msg.js"; +import EmptyMessageState from "../../widgets/EmptyMessageState.js"; + +class PgNotFound extends React.Component { + constructor(props) { + super(props); + } + + render() { + return /*#__PURE__*/React.createElement(EmptyMessageState, { + icon: WarningTriangleIcon, + messageKey: "pageNotFound" + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "invalidRoute", + params: [this.props.location.pathname] + })); + } + +} + +; +export const PageNotFound = withRouter(PgNotFound); +//# sourceMappingURL=PageNotFound.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/page-not-found/PageNotFound.js.map b/keycloak-themes/keycloak.v2/account/resources/content/page-not-found/PageNotFound.js.map new file mode 100644 index 0000000..39ccfb4 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/page-not-found/PageNotFound.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/page-not-found/PageNotFound.tsx"],"names":["React","WarningTriangleIcon","withRouter","Msg","EmptyMessageState","PgNotFound","Component","constructor","props","render","location","pathname","PageNotFound"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AAEA,SAASC,mBAAT;AACA,SAAQC,UAAR;AACA,SAAQC,GAAR;AACA,OAAOC,iBAAP;;AAIA,MAAMC,UAAN,SAAyBL,KAAK,CAACM,SAA/B,CAA4D;AAEjDC,EAAAA,WAAW,CAACC,KAAD,EAA2B;AACzC,UAAMA,KAAN;AACH;;AAEMC,EAAAA,MAAM,GAAoB;AAC7B,wBACI,oBAAC,iBAAD;AAAmB,MAAA,IAAI,EAAER,mBAAzB;AAA8C,MAAA,UAAU,EAAC;AAAzD,oBACI,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC,cAAZ;AAA2B,MAAA,MAAM,EAAE,CAAC,KAAKO,KAAL,CAAWE,QAAX,CAAoBC,QAArB;AAAnC,MADJ,CADJ;AAKH;;AAZuD;;AAa3D;AAED,OAAO,MAAMC,YAAY,GAAGV,UAAU,CAACG,UAAD,CAA/B","sourcesContent":["/*\n * To change this license header, choose License Headers in Project Properties.\n * To change this template file, choose Tools | Templates\n * and open the template in the editor.\n */\n\nimport * as React from 'react';\n\nimport { WarningTriangleIcon } from '@patternfly/react-icons';\nimport {withRouter, RouteComponentProps} from 'react-router-dom';\nimport {Msg} from '../../widgets/Msg';\nimport EmptyMessageState from '../../widgets/EmptyMessageState';\n\nexport interface PageNotFoundProps extends RouteComponentProps {}\n\nclass PgNotFound extends React.Component {\n\n public constructor(props: PageNotFoundProps) {\n super(props);\n }\n\n public render(): React.ReactNode {\n return (\n \n \n \n );\n }\n};\n\nexport const PageNotFound = withRouter(PgNotFound);"],"file":"PageNotFound.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/signingin-page/SigningInPage.js b/keycloak-themes/keycloak.v2/account/resources/content/signingin-page/SigningInPage.js new file mode 100644 index 0000000..9a14745 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/signingin-page/SigningInPage.js @@ -0,0 +1,350 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../../common/keycloak/web_modules/react.js"; +import { withRouter } from "../../../../common/keycloak/web_modules/react-router-dom.js"; +import { Alert, Button, DataList, DataListAction, DataListItemCells, DataListCell, DataListItem, DataListItemRow, EmptyState, EmptyStateVariant, EmptyStateBody, Split, SplitItem, Title, Dropdown, DropdownPosition, KebabToggle, PageSection, PageSectionVariants } from "../../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { AIACommand } from "../../util/AIACommand.js"; +import TimeUtil from "../../util/TimeUtil.js"; +import { AccountServiceContext } from "../../account-service/AccountServiceContext.js"; +import { ContinueCancelModal } from "../../widgets/ContinueCancelModal.js"; +import { Msg } from "../../widgets/Msg.js"; +import { ContentPage } from "../ContentPage.js"; +import { ContentAlert } from "../ContentAlert.js"; +import { KeycloakContext } from "../../keycloak-service/KeycloakContext.js"; + +/** + * @author Stan Silvert ssilvert@redhat.com (C) 2018 Red Hat Inc. + */ +class SigningInPage extends React.Component { + constructor(props, context) { + super(props); + + _defineProperty(this, "context", void 0); + + _defineProperty(this, "handleRemove", (credentialId, userLabel) => { + this.context.doDelete("/credentials/" + credentialId).then(() => { + this.getCredentialContainers(); + ContentAlert.success("successRemovedMessage", [userLabel]); + }); + }); + + this.context = context; + this.state = { + credentialContainers: new Map() + }; + this.getCredentialContainers(); + } + + getCredentialContainers() { + this.context.doGet("/credentials").then(response => { + const allContainers = new Map(); + const containers = response.data || []; + containers.forEach(container => { + let categoryMap = allContainers.get(container.category); + + if (!categoryMap) { + categoryMap = new Map(); + allContainers.set(container.category, categoryMap); + } + + categoryMap.set(container.type, container); + }); + this.setState({ + credentialContainers: allContainers + }); + }); + } + + static credElementId(credType, credId, item) { + return `${credType}-${item}-${credId.substring(0, 8)}`; + } + + render() { + return /*#__PURE__*/React.createElement(ContentPage, { + title: "signingIn", + introMessage: "signingInSubMessage" + }, this.renderCategories()); + } + + renderCategories() { + return Array.from(this.state.credentialContainers.keys()).map(category => /*#__PURE__*/React.createElement(PageSection, { + key: category, + variant: PageSectionVariants.light + }, /*#__PURE__*/React.createElement(Title, { + id: `${category}-categ-title`, + headingLevel: "h2", + size: "xl" + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: category + })), this.renderTypes(category))); + } + + renderTypes(category) { + let credTypeMap = this.state.credentialContainers.get(category); + return /*#__PURE__*/React.createElement(KeycloakContext.Consumer, null, keycloak => /*#__PURE__*/React.createElement(React.Fragment, null, Array.from(credTypeMap.keys()).map((credType, index, typeArray) => [this.renderCredTypeTitle(credTypeMap.get(credType), keycloak, category), this.renderUserCredentials(credTypeMap, credType, keycloak)]))); + } + + renderEmptyRow(type, isLast) { + if (isLast) return; // don't put empty row at the end + + return /*#__PURE__*/React.createElement(DataListItem, { + "aria-labelledby": "empty-list-item-" + type + }, /*#__PURE__*/React.createElement(DataListItemRow, { + key: "empty-row-" + type + }, /*#__PURE__*/React.createElement(DataListItemCells, { + dataListCells: [/*#__PURE__*/React.createElement(DataListCell, null)] + }))); + } + + renderUserCredentials(credTypeMap, credType, keycloak) { + const credContainer = credTypeMap.get(credType); + const userCredentialMetadatas = credContainer.userCredentialMetadatas; + const removeable = credContainer.removeable; + const type = credContainer.type; + const displayName = credContainer.displayName; + + if (!userCredentialMetadatas || userCredentialMetadatas.length === 0) { + const localizedDisplayName = Msg.localize(displayName); + return /*#__PURE__*/React.createElement(DataList, { + "aria-label": Msg.localize('notSetUp', [localizedDisplayName]), + className: "pf-u-mb-xl" + }, /*#__PURE__*/React.createElement(DataListItem, { + key: "no-credentials-list-item", + "aria-labelledby": Msg.localize('notSetUp', [localizedDisplayName]) + }, /*#__PURE__*/React.createElement(DataListItemRow, { + key: "no-credentials-list-item-row", + className: "pf-u-align-items-center" + }, /*#__PURE__*/React.createElement(DataListItemCells, { + dataListCells: [/*#__PURE__*/React.createElement(DataListCell, { + key: 'no-credentials-cell-0' + }), /*#__PURE__*/React.createElement(EmptyState, { + id: `${type}-not-set-up`, + key: 'no-credentials-cell-1', + variant: EmptyStateVariant.xs + }, /*#__PURE__*/React.createElement(EmptyStateBody, null, /*#__PURE__*/React.createElement(Msg, { + msgKey: "notSetUp", + params: [localizedDisplayName] + }))), /*#__PURE__*/React.createElement(DataListCell, { + key: 'no-credentials-cell-2' + })] + })))); + } + + userCredentialMetadatas.forEach(credentialMetadata => { + let credential = credentialMetadata.credential; + if (!credential.userLabel) credential.userLabel = Msg.localize(credential.type); + + if (credential.hasOwnProperty('createdDate') && credential.createdDate && credential.createdDate > 0) { + credential.strCreatedDate = TimeUtil.format(credential.createdDate); + } + }); + let updateAIA; + + if (credContainer.updateAction) { + updateAIA = new AIACommand(keycloak, credContainer.updateAction); + } + + let maxWidth = { + maxWidth: 689 + }; + return /*#__PURE__*/React.createElement(React.Fragment, { + key: "userCredentialMetadatas" + }, " ", userCredentialMetadatas.map(credentialMetadata => /*#__PURE__*/React.createElement(React.Fragment, null, credentialMetadata.infoMessage && !credentialMetadata.warningMessageTitle && !credentialMetadata.warningMessageDescription && /*#__PURE__*/React.createElement(Alert, { + variant: "default", + className: "pf-u-mb-md", + isInline: true, + isPlain: true, + title: Msg.localize(JSON.parse(credentialMetadata.infoMessage).key, JSON.parse(credentialMetadata.infoMessage).parameters) + }), credentialMetadata.warningMessageTitle && credentialMetadata.warningMessageDescription && /*#__PURE__*/React.createElement(Alert, { + variant: "warning", + className: "pf-u-mb-md", + isInline: true, + title: Msg.localize(JSON.parse(credentialMetadata.warningMessageTitle).key, JSON.parse(credentialMetadata.warningMessageTitle).parameters), + style: maxWidth + }, /*#__PURE__*/React.createElement("p", null, Msg.localize(JSON.parse(credentialMetadata.warningMessageDescription).key, JSON.parse(credentialMetadata.warningMessageDescription).parameters))), /*#__PURE__*/React.createElement(DataList, { + "aria-label": "user credential", + className: "pf-u-mb-xl" + }, /*#__PURE__*/React.createElement(DataListItem, { + id: `${SigningInPage.credElementId(type, credentialMetadata.credential.id, 'row')}`, + key: 'credential-list-item-' + credentialMetadata.credential.id, + "aria-labelledby": 'credential-list-item-' + credentialMetadata.credential.userLabel + }, /*#__PURE__*/React.createElement(DataListItemRow, { + key: 'userCredentialRow-' + credentialMetadata.credential.id, + className: "pf-u-align-items-center" + }, /*#__PURE__*/React.createElement(DataListItemCells, { + dataListCells: this.credentialRowCells(credentialMetadata, type) + }), /*#__PURE__*/React.createElement(CredentialAction, { + credential: credentialMetadata.credential, + removeable: removeable, + updateAction: updateAIA, + credRemover: this.handleRemove + })))))), " "); + } + + credentialRowCells(credMetadata, type) { + const credRowCells = []; + const credential = credMetadata.credential; + let maxWidth = { + "--pf-u-max-width--MaxWidth": "300px" + }; + credRowCells.push( /*#__PURE__*/React.createElement(DataListCell, { + id: `${SigningInPage.credElementId(type, credential.id, 'label')}`, + key: 'userLabel-' + credential.id, + className: "pf-u-max-width", + style: maxWidth + }, credential.userLabel)); + + if (credential.strCreatedDate) { + credRowCells.push( /*#__PURE__*/React.createElement(DataListCell, { + id: `${SigningInPage.credElementId(type, credential.id, "created-at")}`, + key: "created-" + credential.id + }, /*#__PURE__*/React.createElement("strong", { + className: "pf-u-mr-md" + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "credentialCreatedAt" + }), " "), credential.strCreatedDate)); + credRowCells.push( /*#__PURE__*/React.createElement(DataListCell, { + key: "spacer-" + credential.id + })); + } + + return credRowCells; + } + + renderCredTypeTitle(credContainer, keycloak, category) { + if (!credContainer.hasOwnProperty("helptext") && !credContainer.hasOwnProperty("createAction")) return; + let setupAction; + + if (credContainer.createAction) { + setupAction = new AIACommand(keycloak, credContainer.createAction); + } + + const credContainerDisplayName = Msg.localize(credContainer.displayName); + return /*#__PURE__*/React.createElement(React.Fragment, { + key: "credTypeTitle-" + credContainer.type + }, /*#__PURE__*/React.createElement(Split, { + className: "pf-u-mt-lg pf-u-mb-lg" + }, /*#__PURE__*/React.createElement(SplitItem, null, /*#__PURE__*/React.createElement(Title, { + headingLevel: "h3", + size: "md", + className: "pf-u-mb-md" + }, /*#__PURE__*/React.createElement("span", { + className: "cred-title pf-u-display-block", + id: `${credContainer.type}-cred-title` + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: credContainer.displayName + }))), /*#__PURE__*/React.createElement("span", { + id: `${credContainer.type}-cred-help` + }, credContainer.helptext && /*#__PURE__*/React.createElement(Msg, { + msgKey: credContainer.helptext + }))), /*#__PURE__*/React.createElement(SplitItem, { + isFilled: true + }, credContainer.createAction && /*#__PURE__*/React.createElement("div", { + id: "mob-setUpAction-" + credContainer.type, + className: "pf-u-display-none-on-lg pf-u-float-right" + }, /*#__PURE__*/React.createElement(Dropdown, { + isPlain: true, + position: DropdownPosition.right, + toggle: /*#__PURE__*/React.createElement(KebabToggle, { + onToggle: isOpen => { + credContainer.open = isOpen; + this.setState({ + credentialContainers: new Map(this.state.credentialContainers) + }); + } + }), + isOpen: credContainer.open, + dropdownItems: [/*#__PURE__*/React.createElement("button", { + id: `mob-${credContainer.type}-set-up`, + className: "pf-c-button pf-m-link", + type: "button", + onClick: () => setupAction.execute() + }, /*#__PURE__*/React.createElement("span", { + className: "pf-c-button__icon" + }, /*#__PURE__*/React.createElement("i", { + className: "fas fa-plus-circle", + "aria-hidden": "true" + })), /*#__PURE__*/React.createElement(Msg, { + msgKey: "setUpNew", + params: [credContainerDisplayName] + }))] + })), credContainer.createAction && /*#__PURE__*/React.createElement("div", { + id: "setUpAction-" + credContainer.type, + className: "pf-u-display-none pf-u-display-inline-flex-on-lg pf-u-float-right" + }, /*#__PURE__*/React.createElement("button", { + id: `${credContainer.type}-set-up`, + className: "pf-c-button pf-m-link", + type: "button", + onClick: () => setupAction.execute() + }, /*#__PURE__*/React.createElement("span", { + className: "pf-c-button__icon" + }, /*#__PURE__*/React.createElement("i", { + className: "fas fa-plus-circle", + "aria-hidden": "true" + })), /*#__PURE__*/React.createElement(Msg, { + msgKey: "setUpNew", + params: [credContainerDisplayName] + })))))); + } + +} + +_defineProperty(SigningInPage, "contextType", AccountServiceContext); + +; + +class CredentialAction extends React.Component { + render() { + if (this.props.updateAction) { + return /*#__PURE__*/React.createElement(DataListAction, { + "aria-labelledby": Msg.localize('updateCredAriaLabel'), + "aria-label": Msg.localize('updateCredAriaLabel'), + id: "updateAction-" + this.props.credential.id + }, /*#__PURE__*/React.createElement(Button, { + variant: "secondary", + id: `${SigningInPage.credElementId(this.props.credential.type, this.props.credential.id, "update")}`, + onClick: () => this.props.updateAction.execute() + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "update" + }))); + } + + if (this.props.removeable) { + const userLabel = this.props.credential.userLabel; + return /*#__PURE__*/React.createElement(DataListAction, { + "aria-label": Msg.localize('removeCredAriaLabel'), + "aria-labelledby": Msg.localize('removeCredAriaLabel'), + id: 'removeAction-' + this.props.credential.id + }, /*#__PURE__*/React.createElement(ContinueCancelModal, { + buttonTitle: "remove", + buttonVariant: "danger", + buttonId: `${SigningInPage.credElementId(this.props.credential.type, this.props.credential.id, 'remove')}`, + modalTitle: Msg.localize('removeCred', [userLabel]), + modalMessage: Msg.localize('stopUsingCred', [userLabel]), + onContinue: () => this.props.credRemover(this.props.credential.id, userLabel) + })); + } + + return /*#__PURE__*/React.createElement(React.Fragment, null); + } + +} + +const SigningInPageWithRouter = withRouter(SigningInPage); +export { SigningInPageWithRouter as SigningInPage }; +//# sourceMappingURL=SigningInPage.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/content/signingin-page/SigningInPage.js.map b/keycloak-themes/keycloak.v2/account/resources/content/signingin-page/SigningInPage.js.map new file mode 100644 index 0000000..ea4ca88 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/content/signingin-page/SigningInPage.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/app/content/signingin-page/SigningInPage.tsx"],"names":["React","withRouter","Alert","Button","DataList","DataListAction","DataListItemCells","DataListCell","DataListItem","DataListItemRow","EmptyState","EmptyStateVariant","EmptyStateBody","Split","SplitItem","Title","Dropdown","DropdownPosition","KebabToggle","PageSection","PageSectionVariants","AIACommand","TimeUtil","AccountServiceContext","ContinueCancelModal","Msg","ContentPage","ContentAlert","KeycloakContext","SigningInPage","Component","constructor","props","context","credentialId","userLabel","doDelete","then","getCredentialContainers","success","state","credentialContainers","Map","doGet","response","allContainers","containers","data","forEach","container","categoryMap","get","category","set","type","setState","credElementId","credType","credId","item","substring","render","renderCategories","Array","from","keys","map","light","renderTypes","credTypeMap","keycloak","index","typeArray","renderCredTypeTitle","renderUserCredentials","renderEmptyRow","isLast","credContainer","userCredentialMetadatas","removeable","displayName","length","localizedDisplayName","localize","xs","credentialMetadata","credential","hasOwnProperty","createdDate","strCreatedDate","format","updateAIA","updateAction","maxWidth","infoMessage","warningMessageTitle","warningMessageDescription","JSON","parse","key","parameters","id","credentialRowCells","handleRemove","credMetadata","credRowCells","push","setupAction","createAction","credContainerDisplayName","helptext","right","isOpen","open","execute","CredentialAction","credRemover","SigningInPageWithRouter"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AAEA,SAASC,UAAT;AACA,SACIC,KADJ,EAEIC,MAFJ,EAGIC,QAHJ,EAIIC,cAJJ,EAKIC,iBALJ,EAMIC,YANJ,EAOIC,YAPJ,EAQIC,eARJ,EASIC,UATJ,EAUIC,iBAVJ,EAWIC,cAXJ,EAYIC,KAZJ,EAaIC,SAbJ,EAcIC,KAdJ,EAeIC,QAfJ,EAgBIC,gBAhBJ,EAiBIC,WAjBJ,EAkBIC,WAlBJ,EAmBIC,mBAnBJ;AAsBA,SAASC,UAAT;AACA,OAAOC,QAAP;AAKA,SAASC,qBAAT;AACA,SAASC,mBAAT;AAEA,SAASC,GAAT;AACA,SAASC,WAAT;AACA,SAASC,YAAT;AACA,SAASC,eAAT;;AAoDA;AACA;AACA;AACA,MAAMC,aAAN,SAA4B7B,KAAK,CAAC8B,SAAlC,CAGE;AAISC,EAAAA,WAAW,CACdC,KADc,EAEdC,OAFc,EAGhB;AACE,UAAMD,KAAN;;AADF;;AAAA,0CA8BqB,CAACE,YAAD,EAAuBC,SAAvB,KAA6C;AAChE,WAAKF,OAAL,CAAcG,QAAd,CAAuB,kBAAkBF,YAAzC,EAAuDG,IAAvD,CAA4D,MAAM;AAC9D,aAAKC,uBAAL;AACAX,QAAAA,YAAY,CAACY,OAAb,CAAqB,uBAArB,EAA8C,CAACJ,SAAD,CAA9C;AACH,OAHD;AAIH,KAnCC;;AAEE,SAAKF,OAAL,GAAeA,OAAf;AAEA,SAAKO,KAAL,GAAa;AACTC,MAAAA,oBAAoB,EAAE,IAAIC,GAAJ;AADb,KAAb;AAIA,SAAKJ,uBAAL;AACH;;AAEOA,EAAAA,uBAAuB,GAAS;AACpC,SAAKL,OAAL,CAAcU,KAAd,CAAoB,cAApB,EAAoCN,IAApC,CACKO,QAAD,IAAmD;AAC/C,YAAMC,aAA+B,GAAG,IAAIH,GAAJ,EAAxC;AACA,YAAMI,UAAiC,GAAGF,QAAQ,CAACG,IAAT,IAAiB,EAA3D;AACAD,MAAAA,UAAU,CAACE,OAAX,CAAoBC,SAAD,IAAe;AAC9B,YAAIC,WAAW,GAAGL,aAAa,CAACM,GAAd,CAAkBF,SAAS,CAACG,QAA5B,CAAlB;;AACA,YAAI,CAACF,WAAL,EAAkB;AACdA,UAAAA,WAAW,GAAG,IAAIR,GAAJ,EAAd;AACAG,UAAAA,aAAa,CAACQ,GAAd,CAAkBJ,SAAS,CAACG,QAA5B,EAAsCF,WAAtC;AACH;;AACDA,QAAAA,WAAW,CAACG,GAAZ,CAAgBJ,SAAS,CAACK,IAA1B,EAAgCL,SAAhC;AACH,OAPD;AASA,WAAKM,QAAL,CAAc;AAAEd,QAAAA,oBAAoB,EAAEI;AAAxB,OAAd;AACH,KAdL;AAgBH;;AAS0B,SAAbW,aAAa,CACvBC,QADuB,EAEvBC,MAFuB,EAGvBC,IAHuB,EAIjB;AACN,WAAQ,GAAEF,QAAS,IAAGE,IAAK,IAAGD,MAAM,CAACE,SAAP,CAAiB,CAAjB,EAAoB,CAApB,CAAuB,EAArD;AACH;;AAEMC,EAAAA,MAAM,GAAoB;AAC7B,wBACI,oBAAC,WAAD;AAAa,MAAA,KAAK,EAAC,WAAnB;AAA+B,MAAA,YAAY,EAAC;AAA5C,OACK,KAAKC,gBAAL,EADL,CADJ;AAKH;;AAEOA,EAAAA,gBAAgB,GAAoB;AAC1C,WAAOC,KAAK,CAACC,IAAN,CAAW,KAAKxB,KAAL,CAAWC,oBAAX,CAAgCwB,IAAhC,EAAX,EAAmDC,GAAnD,CACFd,QAAD,iBACE,oBAAC,WAAD;AAAa,MAAA,GAAG,EAAEA,QAAlB;AAA4B,MAAA,OAAO,EAAEhC,mBAAmB,CAAC+C;AAAzD,oBACE,oBAAC,KAAD;AACI,MAAA,EAAE,EAAG,GAAEf,QAAS,cADpB;AAEI,MAAA,YAAY,EAAC,IAFjB;AAGI,MAAA,IAAI,EAAC;AAHT,oBAKE,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAEA;AAAb,MALF,CADF,EAQG,KAAKgB,WAAL,CAAiBhB,QAAjB,CARH,CAFC,CAAP;AAcD;;AAEOgB,EAAAA,WAAW,CAAChB,QAAD,EAA0C;AACzD,QAAIiB,WAAwB,GAAG,KAAK7B,KAAL,CAAWC,oBAAX,CAAgCU,GAAhC,CAC3BC,QAD2B,CAA/B;AAIA,wBACI,oBAAC,eAAD,CAAiB,QAAjB,QACMkB,QAAD,iBACG,0CACKP,KAAK,CAACC,IAAN,CACGK,WAAW,CAACJ,IAAZ,EADH,EAECC,GAFD,CAGG,CACIT,QADJ,EAEIc,KAFJ,EAGIC,SAHJ,KAIK,CACD,KAAKC,mBAAL,CACIJ,WAAW,CAAClB,GAAZ,CAAgBM,QAAhB,CADJ,EAEIa,QAFJ,EAGIlB,QAHJ,CADC,EAMD,KAAKsB,qBAAL,CACIL,WADJ,EAEIZ,QAFJ,EAGIa,QAHJ,CANC,CAPR,CADL,CAFR,CADJ;AA4BH;;AAEOK,EAAAA,cAAc,CAACrB,IAAD,EAAesB,MAAf,EAAiD;AACnE,QAAIA,MAAJ,EAAY,OADuD,CAC/C;;AAEpB,wBACI,oBAAC,YAAD;AAAc,yBAAiB,qBAAqBtB;AAApD,oBACI,oBAAC,eAAD;AAAiB,MAAA,GAAG,EAAE,eAAeA;AAArC,oBACI,oBAAC,iBAAD;AACI,MAAA,aAAa,EAAE,cAAC,oBAAC,YAAD,OAAD;AADnB,MADJ,CADJ,CADJ;AASH;;AAEOoB,EAAAA,qBAAqB,CACzBL,WADyB,EAEzBZ,QAFyB,EAGzBa,QAHyB,EAIV;AACf,UAAMO,aAAkC,GAAGR,WAAW,CAAClB,GAAZ,CAAgBM,QAAhB,CAA3C;AACA,UAAMqB,uBAAuC,GAAGD,aAAa,CAACC,uBAA9D;AACA,UAAMC,UAAmB,GAAGF,aAAa,CAACE,UAA1C;AACA,UAAMzB,IAAY,GAAGuB,aAAa,CAACvB,IAAnC;AACA,UAAM0B,WAAmB,GAAGH,aAAa,CAACG,WAA1C;;AAEA,QAAI,CAACF,uBAAD,IAA4BA,uBAAuB,CAACG,MAAxB,KAAmC,CAAnE,EAAsE;AAClE,YAAMC,oBAAoB,GAAGzD,GAAG,CAAC0D,QAAJ,CAAaH,WAAb,CAA7B;AACA,0BACE,oBAAC,QAAD;AAAU,sBAAYvD,GAAG,CAAC0D,QAAJ,CAAa,UAAb,EAAyB,CAACD,oBAAD,CAAzB,CAAtB;AAAwE,QAAA,SAAS,EAAC;AAAlF,sBACE,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAC,0BAAlB;AAA6C,2BAAiBzD,GAAG,CAAC0D,QAAJ,CAAa,UAAb,EAAyB,CAACD,oBAAD,CAAzB;AAA9D,sBACI,oBAAC,eAAD;AAAiB,QAAA,GAAG,EAAC,8BAArB;AAAoD,QAAA,SAAS,EAAC;AAA9D,sBACI,oBAAC,iBAAD;AACI,QAAA,aAAa,EAAE,cACX,oBAAC,YAAD;AAAc,UAAA,GAAG,EAAE;AAAnB,UADW,eAEX,oBAAC,UAAD;AAAY,UAAA,EAAE,EAAG,GAAE5B,IAAK,aAAxB;AAAsC,UAAA,GAAG,EAAE,uBAA3C;AAAoE,UAAA,OAAO,EAAE3C,iBAAiB,CAACyE;AAA/F,wBACI,oBAAC,cAAD,qBACI,oBAAC,GAAD;AAAK,UAAA,MAAM,EAAC,UAAZ;AAAuB,UAAA,MAAM,EAAE,CAACF,oBAAD;AAA/B,UADJ,CADJ,CAFW,eAOX,oBAAC,YAAD;AAAc,UAAA,GAAG,EAAE;AAAnB,UAPW;AADnB,QADJ,CADJ,CADF,CADF;AAkBH;;AAEDJ,IAAAA,uBAAuB,CAAC9B,OAAxB,CAAgCqC,kBAAkB,IAAI;AAClD,UAAIC,UAAU,GAAGD,kBAAkB,CAACC,UAApC;AACA,UAAI,CAACA,UAAU,CAACnD,SAAhB,EAA2BmD,UAAU,CAACnD,SAAX,GAAuBV,GAAG,CAAC0D,QAAJ,CAAaG,UAAU,CAAChC,IAAxB,CAAvB;;AAC3B,UAAIgC,UAAU,CAACC,cAAX,CAA0B,aAA1B,KAA4CD,UAAU,CAACE,WAAvD,IAAsEF,UAAU,CAACE,WAAX,GAA0B,CAApG,EAAuG;AACnGF,QAAAA,UAAU,CAACG,cAAX,GAA4BnE,QAAQ,CAACoE,MAAT,CAAgBJ,UAAU,CAACE,WAA3B,CAA5B;AACH;AACJ,KAND;AAQA,QAAIG,SAAJ;;AACA,QAAId,aAAa,CAACe,YAAlB,EAAgC;AAC5BD,MAAAA,SAAS,GAAG,IAAItE,UAAJ,CAAeiD,QAAf,EAAyBO,aAAa,CAACe,YAAvC,CAAZ;AACH;;AAED,QAAIC,QAAQ,GAAG;AAAEA,MAAAA,QAAQ,EAAE;AAAZ,KAAf;AAEA,wBACI,oBAAC,KAAD,CAAO,QAAP;AAAgB,MAAA,GAAG,EAAC;AAApB,YACIf,uBAAuB,CAACZ,GAAxB,CAA4BmB,kBAAkB,iBAC5C,0CACIA,kBAAkB,CAACS,WAAnB,IAAkC,CAACT,kBAAkB,CAACU,mBAAtD,IAA6E,CAACV,kBAAkB,CAACW,yBAAlG,iBACC,oBAAC,KAAD;AAAO,MAAA,OAAO,EAAC,SAAf;AAAyB,MAAA,SAAS,EAAC,YAAnC;AAAgD,MAAA,QAAQ,MAAxD;AAAyD,MAAA,OAAO,MAAhE;AAAiE,MAAA,KAAK,EAAEvE,GAAG,CAAC0D,QAAJ,CAAac,IAAI,CAACC,KAAL,CAAWb,kBAAkB,CAACS,WAA9B,EAA2CK,GAAxD,EAA6DF,IAAI,CAACC,KAAL,CAAWb,kBAAkB,CAACS,WAA9B,EAA2CM,UAAxG;AAAxE,MAFJ,EAIIf,kBAAkB,CAACU,mBAAnB,IAA0CV,kBAAkB,CAACW,yBAA9D,iBACC,oBAAC,KAAD;AAAO,MAAA,OAAO,EAAC,SAAf;AAAyB,MAAA,SAAS,EAAC,YAAnC;AAAgD,MAAA,QAAQ,MAAxD;AAAyD,MAAA,KAAK,EAAEvE,GAAG,CAAC0D,QAAJ,CAAac,IAAI,CAACC,KAAL,CAAWb,kBAAkB,CAACU,mBAA9B,EAAmDI,GAAhE,EAAqEF,IAAI,CAACC,KAAL,CAAWb,kBAAkB,CAACU,mBAA9B,EAAmDK,UAAxH,CAAhE;AAAqM,MAAA,KAAK,EAAEP;AAA5M,oBAEE,+BAAIpE,GAAG,CAAC0D,QAAJ,CAAac,IAAI,CAACC,KAAL,CAAWb,kBAAkB,CAACW,yBAA9B,EAAyDG,GAAtE,EAA2EF,IAAI,CAACC,KAAL,CAAWb,kBAAkB,CAACW,yBAA9B,EAAyDI,UAApI,CAAJ,CAFF,CALJ,eAUE,oBAAC,QAAD;AAAU,oBAAW,iBAArB;AAAuC,MAAA,SAAS,EAAC;AAAjD,oBACE,oBAAC,YAAD;AAAc,MAAA,EAAE,EAAG,GAAEvE,aAAa,CAAC2B,aAAd,CAA4BF,IAA5B,EAAkC+B,kBAAkB,CAACC,UAAnB,CAA8Be,EAAhE,EAAoE,KAApE,CAA2E,EAAhG;AAAmG,MAAA,GAAG,EAAE,0BAA0BhB,kBAAkB,CAACC,UAAnB,CAA8Be,EAAhK;AAAoK,yBAAiB,0BAA0BhB,kBAAkB,CAACC,UAAnB,CAA8BnD;AAA7O,oBACI,oBAAC,eAAD;AAAiB,MAAA,GAAG,EAAE,uBAAuBkD,kBAAkB,CAACC,UAAnB,CAA8Be,EAA3E;AAA+E,MAAA,SAAS,EAAC;AAAzF,oBACI,oBAAC,iBAAD;AAAmB,MAAA,aAAa,EAAE,KAAKC,kBAAL,CAAwBjB,kBAAxB,EAA4C/B,IAA5C;AAAlC,MADJ,eAEI,oBAAC,gBAAD;AACE,MAAA,UAAU,EAAE+B,kBAAkB,CAACC,UADjC;AAEE,MAAA,UAAU,EAAEP,UAFd;AAGE,MAAA,YAAY,EAAEY,SAHhB;AAIE,MAAA,WAAW,EAAE,KAAKY;AAJpB,MAFJ,CADJ,CADF,CAVF,CADF,CADJ,MADJ;AA8BH;;AAEOD,EAAAA,kBAAkB,CAACE,YAAD,EAA6BlD,IAA7B,EAA8D;AACpF,UAAMmD,YAA+B,GAAG,EAAxC;AACA,UAAMnB,UAAU,GAAGkB,YAAY,CAAClB,UAAhC;AACA,QAAIO,QAAQ,GAAG;AAAE,oCAA8B;AAAhC,KAAf;AACAY,IAAAA,YAAY,CAACC,IAAb,eACI,oBAAC,YAAD;AAAc,MAAA,EAAE,EAAG,GAAE7E,aAAa,CAAC2B,aAAd,CAA4BF,IAA5B,EAAkCgC,UAAU,CAACe,EAA7C,EAAiD,OAAjD,CAA0D,EAA/E;AAAkF,MAAA,GAAG,EAAE,eAAef,UAAU,CAACe,EAAjH;AAAqH,MAAA,SAAS,EAAC,gBAA/H;AAAgJ,MAAA,KAAK,EAAER;AAAvJ,OACKP,UAAU,CAACnD,SADhB,CADJ;;AAKA,QAAImD,UAAU,CAACG,cAAf,EAA+B;AAC3BgB,MAAAA,YAAY,CAACC,IAAb,eACI,oBAAC,YAAD;AACI,QAAA,EAAE,EAAG,GAAE7E,aAAa,CAAC2B,aAAd,CACHF,IADG,EAEHgC,UAAU,CAACe,EAFR,EAGH,YAHG,CAIL,EALN;AAMI,QAAA,GAAG,EAAE,aAAaf,UAAU,CAACe;AANjC,sBAQI;AAAQ,QAAA,SAAS,EAAC;AAAlB,sBACI,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QADJ,EACyC,GADzC,CARJ,EAWKf,UAAU,CAACG,cAXhB,CADJ;AAeAgB,MAAAA,YAAY,CAACC,IAAb,eAAkB,oBAAC,YAAD;AAAc,QAAA,GAAG,EAAE,YAAYpB,UAAU,CAACe;AAA1C,QAAlB;AACH;;AAED,WAAOI,YAAP;AACH;;AAEOhC,EAAAA,mBAAmB,CACvBI,aADuB,EAEvBP,QAFuB,EAGvBlB,QAHuB,EAIR;AAEf,QACI,CAACyB,aAAa,CAACU,cAAd,CAA6B,UAA7B,CAAD,IACA,CAACV,aAAa,CAACU,cAAd,CAA6B,cAA7B,CAFL,EAII;AAEJ,QAAIoB,WAAJ;;AACA,QAAI9B,aAAa,CAAC+B,YAAlB,EAAgC;AAC5BD,MAAAA,WAAW,GAAG,IAAItF,UAAJ,CAAeiD,QAAf,EAAyBO,aAAa,CAAC+B,YAAvC,CAAd;AACH;;AAED,UAAMC,wBAAgC,GAAGpF,GAAG,CAAC0D,QAAJ,CACrCN,aAAa,CAACG,WADuB,CAAzC;AAGA,wBACI,oBAAC,KAAD,CAAO,QAAP;AAAgB,MAAA,GAAG,EAAE,mBAAmBH,aAAa,CAACvB;AAAtD,oBACI,oBAAC,KAAD;AAAO,MAAA,SAAS,EAAC;AAAjB,oBACI,oBAAC,SAAD,qBACI,oBAAC,KAAD;AACI,MAAA,YAAY,EAAC,IADjB;AAEI,MAAA,IAAI,EAAC,IAFT;AAGI,MAAA,SAAS,EAAC;AAHd,oBAKI;AAAM,MAAA,SAAS,EAAC,+BAAhB;AAAgD,MAAA,EAAE,EAAG,GAAEuB,aAAa,CAACvB,IAAK;AAA1E,oBACI,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAEuB,aAAa,CAACG;AAA3B,MADJ,CALJ,CADJ,eAUI;AAAM,MAAA,EAAE,EAAG,GAAEH,aAAa,CAACvB,IAAK;AAAhC,OACKuB,aAAa,CAACiC,QAAd,iBACG,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAEjC,aAAa,CAACiC;AAA3B,MAFR,CAVJ,CADJ,eAkBI,oBAAC,SAAD;AAAW,MAAA,QAAQ;AAAnB,OACKjC,aAAa,CAAC+B,YAAd,iBACG;AACI,MAAA,EAAE,EAAE,qBAAqB/B,aAAa,CAACvB,IAD3C;AAEI,MAAA,SAAS,EAAC;AAFd,oBAII,oBAAC,QAAD;AACI,MAAA,OAAO,MADX;AAEI,MAAA,QAAQ,EAAErC,gBAAgB,CAAC8F,KAF/B;AAGI,MAAA,MAAM,eACF,oBAAC,WAAD;AACI,QAAA,QAAQ,EAAGC,MAAD,IAAY;AAClBnC,UAAAA,aAAa,CAACoC,IAAd,GAAqBD,MAArB;AACA,eAAKzD,QAAL,CAAc;AACVd,YAAAA,oBAAoB,EAAE,IAAIC,GAAJ,CAClB,KAAKF,KAAL,CAAWC,oBADO;AADZ,WAAd;AAKH;AARL,QAJR;AAeI,MAAA,MAAM,EAAEoC,aAAa,CAACoC,IAf1B;AAgBI,MAAA,aAAa,EAAE,cACX;AACI,QAAA,EAAE,EAAG,OAAMpC,aAAa,CAACvB,IAAK,SADlC;AAEI,QAAA,SAAS,EAAC,uBAFd;AAGI,QAAA,IAAI,EAAC,QAHT;AAII,QAAA,OAAO,EAAE,MACLqD,WAAW,CAACO,OAAZ;AALR,sBAQI;AAAM,QAAA,SAAS,EAAC;AAAhB,sBACI;AACI,QAAA,SAAS,EAAC,oBADd;AAEI,uBAAY;AAFhB,QADJ,CARJ,eAcI,oBAAC,GAAD;AACI,QAAA,MAAM,EAAC,UADX;AAEI,QAAA,MAAM,EAAE,CACJL,wBADI;AAFZ,QAdJ,CADW;AAhBnB,MAJJ,CAFR,EAgDKhC,aAAa,CAAC+B,YAAd,iBACG;AACI,MAAA,EAAE,EAAE,iBAAiB/B,aAAa,CAACvB,IADvC;AAEI,MAAA,SAAS,EAAC;AAFd,oBAII;AACI,MAAA,EAAE,EAAG,GAAEuB,aAAa,CAACvB,IAAK,SAD9B;AAEI,MAAA,SAAS,EAAC,uBAFd;AAGI,MAAA,IAAI,EAAC,QAHT;AAII,MAAA,OAAO,EAAE,MAAMqD,WAAW,CAACO,OAAZ;AAJnB,oBAMI;AAAM,MAAA,SAAS,EAAC;AAAhB,oBACI;AACI,MAAA,SAAS,EAAC,oBADd;AAEI,qBAAY;AAFhB,MADJ,CANJ,eAYI,oBAAC,GAAD;AACI,MAAA,MAAM,EAAC,UADX;AAEI,MAAA,MAAM,EAAE,CAACL,wBAAD;AAFZ,MAZJ,CAJJ,CAjDR,CAlBJ,CADJ,CADJ;AAgGH;;AAjWH;;gBAHIhF,a,iBAImBN,qB;;AAyWxB;;AAED,MAAM4F,gBAAN,SAA+BnH,KAAK,CAAC8B,SAArC,CAAsE;AAClE+B,EAAAA,MAAM,GAAoB;AACtB,QAAI,KAAK7B,KAAL,CAAW4D,YAAf,EAA6B;AACzB,0BACI,oBAAC,cAAD;AACI,2BAAiBnE,GAAG,CAAC0D,QAAJ,CAAa,qBAAb,CADrB;AAEI,sBAAY1D,GAAG,CAAC0D,QAAJ,CAAa,qBAAb,CAFhB;AAGI,QAAA,EAAE,EAAE,kBAAkB,KAAKnD,KAAL,CAAWsD,UAAX,CAAsBe;AAHhD,sBAKI,oBAAC,MAAD;AACI,QAAA,OAAO,EAAC,WADZ;AAEI,QAAA,EAAE,EAAG,GAAExE,aAAa,CAAC2B,aAAd,CACH,KAAKxB,KAAL,CAAWsD,UAAX,CAAsBhC,IADnB,EAEH,KAAKtB,KAAL,CAAWsD,UAAX,CAAsBe,EAFnB,EAGH,QAHG,CAIL,EANN;AAOI,QAAA,OAAO,EAAE,MAAM,KAAKrE,KAAL,CAAW4D,YAAX,CAAwBsB,OAAxB;AAPnB,sBASI,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC;AAAZ,QATJ,CALJ,CADJ;AAmBH;;AAED,QAAI,KAAKlF,KAAL,CAAW+C,UAAf,EAA2B;AACvB,YAAM5C,SAAiB,GAAG,KAAKH,KAAL,CAAWsD,UAAX,CAAsBnD,SAAhD;AACA,0BACI,oBAAC,cAAD;AACE,sBAAYV,GAAG,CAAC0D,QAAJ,CAAa,qBAAb,CADd;AAEE,2BAAiB1D,GAAG,CAAC0D,QAAJ,CAAa,qBAAb,CAFnB;AAGE,QAAA,EAAE,EAAE,kBAAkB,KAAKnD,KAAL,CAAWsD,UAAX,CAAsBe;AAH9C,sBAKI,oBAAC,mBAAD;AACI,QAAA,WAAW,EAAC,QADhB;AAEI,QAAA,aAAa,EAAC,QAFlB;AAGI,QAAA,QAAQ,EAAG,GAAExE,aAAa,CAAC2B,aAAd,CAA4B,KAAKxB,KAAL,CAAWsD,UAAX,CAAsBhC,IAAlD,EAAwD,KAAKtB,KAAL,CAAWsD,UAAX,CAAsBe,EAA9E,EAAkF,QAAlF,CAA4F,EAH7G;AAII,QAAA,UAAU,EAAE5E,GAAG,CAAC0D,QAAJ,CAAa,YAAb,EAA2B,CAAChD,SAAD,CAA3B,CAJhB;AAKI,QAAA,YAAY,EAAEV,GAAG,CAAC0D,QAAJ,CAAa,eAAb,EAA8B,CAAChD,SAAD,CAA9B,CALlB;AAMI,QAAA,UAAU,EAAE,MAAM,KAAKH,KAAL,CAAWoF,WAAX,CAAuB,KAAKpF,KAAL,CAAWsD,UAAX,CAAsBe,EAA7C,EAAiDlE,SAAjD;AANtB,QALJ,CADJ;AAgBH;;AAED,wBAAO,yCAAP;AACH;;AA7CiE;;AAgDtE,MAAMkF,uBAAuB,GAAGpH,UAAU,CAAC4B,aAAD,CAA1C;AACA,SAASwF,uBAAuB,IAAIxF,aAApC","sourcesContent":["/*\n * Copyright 2018 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from \"react\";\n\nimport { withRouter, RouteComponentProps } from \"react-router-dom\";\nimport {\n Alert,\n Button,\n DataList,\n DataListAction,\n DataListItemCells,\n DataListCell,\n DataListItem,\n DataListItemRow,\n EmptyState,\n EmptyStateVariant,\n EmptyStateBody,\n Split,\n SplitItem,\n Title,\n Dropdown,\n DropdownPosition,\n KebabToggle,\n PageSection,\n PageSectionVariants\n} from \"@patternfly/react-core\";\n\nimport { AIACommand } from \"../../util/AIACommand\";\nimport TimeUtil from \"../../util/TimeUtil\";\nimport {\n HttpResponse,\n AccountServiceClient,\n} from \"../../account-service/account.service\";\nimport { AccountServiceContext } from \"../../account-service/AccountServiceContext\";\nimport { ContinueCancelModal } from \"../../widgets/ContinueCancelModal\";\nimport { Features } from \"../../widgets/features\";\nimport { Msg } from \"../../widgets/Msg\";\nimport { ContentPage } from \"../ContentPage\";\nimport { ContentAlert } from \"../ContentAlert\";\nimport { KeycloakContext } from \"../../keycloak-service/KeycloakContext\";\nimport { KeycloakService } from \"../../keycloak-service/keycloak.service\";\nimport { css } from \"@patternfly/react-styles\";\n\ndeclare const features: Features;\n\ninterface PasswordDetails {\n registered: boolean;\n lastUpdate: number;\n}\n\ntype CredCategory = \"password\" | \"two-factor\" | \"passwordless\";\ntype CredType = string;\ntype CredTypeMap = Map;\ntype CredContainerMap = Map;\n\ninterface CredMetadata {\n infoMessage?: string;\n warningMessageTitle?: string;\n warningMessageDescription?: string;\n credential: UserCredential;\n}\n\ninterface UserCredential {\n id: string;\n type: string;\n userLabel: string;\n createdDate?: number;\n strCreatedDate?: string;\n credentialData?: string;\n}\n\n// A CredentialContainer is unique by combo of credential type and credential category\ninterface CredentialContainer {\n category: CredCategory;\n type: CredType;\n displayName: string;\n helptext?: string;\n createAction?: string;\n updateAction?: string;\n removeable: boolean;\n userCredentialMetadatas: CredMetadata[];\n open: boolean;\n}\n\ninterface SigningInPageProps extends RouteComponentProps {}\n\ninterface SigningInPageState {\n // Credential containers organized by category then type\n credentialContainers: CredContainerMap;\n}\n\n/**\n * @author Stan Silvert ssilvert@redhat.com (C) 2018 Red Hat Inc.\n */\nclass SigningInPage extends React.Component<\n SigningInPageProps,\n SigningInPageState\n> {\n static contextType = AccountServiceContext;\n context: React.ContextType;\n\n public constructor(\n props: SigningInPageProps,\n context: React.ContextType\n ) {\n super(props);\n this.context = context;\n\n this.state = {\n credentialContainers: new Map(),\n };\n\n this.getCredentialContainers();\n }\n\n private getCredentialContainers(): void {\n this.context!.doGet(\"/credentials\").then(\n (response: HttpResponse) => {\n const allContainers: CredContainerMap = new Map();\n const containers: CredentialContainer[] = response.data || [];\n containers.forEach((container) => {\n let categoryMap = allContainers.get(container.category);\n if (!categoryMap) {\n categoryMap = new Map();\n allContainers.set(container.category, categoryMap);\n }\n categoryMap.set(container.type, container);\n });\n\n this.setState({ credentialContainers: allContainers });\n }\n );\n }\n\n private handleRemove = (credentialId: string, userLabel: string) => {\n this.context!.doDelete(\"/credentials/\" + credentialId).then(() => {\n this.getCredentialContainers();\n ContentAlert.success(\"successRemovedMessage\", [userLabel]);\n });\n };\n\n public static credElementId(\n credType: CredType,\n credId: string,\n item: string\n ): string {\n return `${credType}-${item}-${credId.substring(0, 8)}`;\n }\n\n public render(): React.ReactNode {\n return (\n \n {this.renderCategories()}\n \n );\n }\n\n private renderCategories(): React.ReactNode {\n return Array.from(this.state.credentialContainers.keys()).map(\n (category) => (\n \n \n \n \n {this.renderTypes(category!)}\n \n )\n ) \n }\n\n private renderTypes(category: CredCategory): React.ReactNode {\n let credTypeMap: CredTypeMap = this.state.credentialContainers.get(\n category\n )!;\n\n return (\n \n {(keycloak) => (\n <>\n {Array.from(\n credTypeMap.keys()\n ).map(\n (\n credType: CredType,\n index: number,\n typeArray: string[]\n ) => [\n this.renderCredTypeTitle(\n credTypeMap.get(credType)!,\n keycloak!,\n category\n ),\n this.renderUserCredentials(\n credTypeMap,\n credType,\n keycloak!\n ),\n ]\n )}\n \n )}\n \n );\n }\n\n private renderEmptyRow(type: string, isLast: boolean): React.ReactNode {\n if (isLast) return; // don't put empty row at the end\n\n return (\n \n \n ]}\n />\n \n \n );\n }\n\n private renderUserCredentials(\n credTypeMap: CredTypeMap,\n credType: CredType,\n keycloak: KeycloakService\n ): React.ReactNode {\n const credContainer: CredentialContainer = credTypeMap.get(credType)!;\n const userCredentialMetadatas: CredMetadata[] = credContainer.userCredentialMetadatas;\n const removeable: boolean = credContainer.removeable;\n const type: string = credContainer.type;\n const displayName: string = credContainer.displayName;\n\n if (!userCredentialMetadatas || userCredentialMetadatas.length === 0) {\n const localizedDisplayName = Msg.localize(displayName);\n return (\n \n \n \n ,\n \n \n \n \n ,\n \n ]}/>\n \n \n \n );\n }\n\n userCredentialMetadatas.forEach(credentialMetadata => {\n let credential = credentialMetadata.credential;\n if (!credential.userLabel) credential.userLabel = Msg.localize(credential.type);\n if (credential.hasOwnProperty('createdDate') && credential.createdDate && credential.createdDate! > 0) {\n credential.strCreatedDate = TimeUtil.format(credential.createdDate as number);\n }\n });\n\n let updateAIA: AIACommand;\n if (credContainer.updateAction) {\n updateAIA = new AIACommand(keycloak, credContainer.updateAction);\n }\n\n let maxWidth = { maxWidth: 689 } as React.CSSProperties;\n\n return (\n {\n userCredentialMetadatas.map(credentialMetadata => (\n <>\n {(credentialMetadata.infoMessage && !credentialMetadata.warningMessageTitle && !credentialMetadata.warningMessageDescription) && \n \n }\n {(credentialMetadata.warningMessageTitle && credentialMetadata.warningMessageDescription) &&\n \n \n

    {Msg.localize(JSON.parse(credentialMetadata.warningMessageDescription).key, JSON.parse(credentialMetadata.warningMessageDescription).parameters)}

    \n
    \n }\n \n \n \n \n \n \n \n \n \n ))\n }
    \n )\n }\n\n private credentialRowCells(credMetadata: CredMetadata, type: string): React.ReactNode[] {\n const credRowCells: React.ReactNode[] = [];\n const credential = credMetadata.credential;\n let maxWidth = { \"--pf-u-max-width--MaxWidth\": \"300px\" } as React.CSSProperties;\n credRowCells.push(\n \n {credential.userLabel}\n \n );\n if (credential.strCreatedDate) {\n credRowCells.push(\n \n \n {\" \"}\n \n {credential.strCreatedDate}\n \n );\n credRowCells.push();\n }\n\n return credRowCells;\n }\n\n private renderCredTypeTitle(\n credContainer: CredentialContainer,\n keycloak: KeycloakService,\n category: CredCategory\n ): React.ReactNode {\n \n if (\n !credContainer.hasOwnProperty(\"helptext\") &&\n !credContainer.hasOwnProperty(\"createAction\")\n )\n return;\n\n let setupAction: AIACommand;\n if (credContainer.createAction) {\n setupAction = new AIACommand(keycloak, credContainer.createAction);\n }\n\n const credContainerDisplayName: string = Msg.localize(\n credContainer.displayName\n );\n return (\n \n \n \n \n \n \n \n \n \n {credContainer.helptext && (\n \n )}\n \n \n\n \n {credContainer.createAction && (\n \n {\n credContainer.open = isOpen;\n this.setState({\n credentialContainers: new Map(\n this.state.credentialContainers\n ),\n });\n }}\n />\n }\n isOpen={credContainer.open}\n dropdownItems={[\n \n setupAction.execute()\n }\n >\n \n \n \n \n ,\n ]}\n />\n
    \n )}\n {credContainer.createAction && (\n \n setupAction.execute()}\n >\n \n \n \n \n \n
    \n )}\n \n \n
    \n );\n }\n}\n\ntype CredRemover = (credentialId: string, userLabel: string) => void;\ninterface CredentialActionProps {\n credential: UserCredential;\n removeable: boolean;\n updateAction: AIACommand;\n credRemover: CredRemover;\n};\n\nclass CredentialAction extends React.Component {\n render(): React.ReactNode {\n if (this.props.updateAction) {\n return (\n \n this.props.updateAction.execute()}\n >\n \n \n \n );\n }\n\n if (this.props.removeable) {\n const userLabel: string = this.props.credential.userLabel;\n return (\n \n this.props.credRemover(this.props.credential.id, userLabel)}\n />\n \n );\n }\n\n return <>;\n }\n}\n\nconst SigningInPageWithRouter = withRouter(SigningInPage);\nexport { SigningInPageWithRouter as SigningInPage };\n"],"file":"SigningInPage.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_facebook_transparent.svg b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_facebook_transparent.svg new file mode 100644 index 0000000..98a8fbf --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_facebook_transparent.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + diff --git a/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_github_transparent.svg b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_github_transparent.svg new file mode 100644 index 0000000..d3775c4 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_github_transparent.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_google_transparent.svg b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_google_transparent.svg new file mode 100644 index 0000000..80c0ea7 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_google_transparent.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_instagram_transparent.svg b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_instagram_transparent.svg new file mode 100644 index 0000000..a8e7fb1 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_instagram_transparent.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + diff --git a/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_linkedin_transparent.svg b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_linkedin_transparent.svg new file mode 100644 index 0000000..b0149a9 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_linkedin_transparent.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_microsoft_transparent.svg b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_microsoft_transparent.svg new file mode 100644 index 0000000..f742463 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_microsoft_transparent.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_openshift_transparent.svg b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_openshift_transparent.svg new file mode 100644 index 0000000..c6af5f4 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_openshift_transparent.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_stack_transparent.svg b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_stack_transparent.svg new file mode 100644 index 0000000..c8c0fa8 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_stack_transparent.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_twitter_transparent.svg b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_twitter_transparent.svg new file mode 100644 index 0000000..eb4f43a --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/img/socialmedia/socialmedia_icons_twitter_transparent.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/keycloak-service/KeycloakContext.js b/keycloak-themes/keycloak.v2/account/resources/keycloak-service/KeycloakContext.js new file mode 100644 index 0000000..bf85785 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/keycloak-service/KeycloakContext.js @@ -0,0 +1,3 @@ +import * as React from "../../../common/keycloak/web_modules/react.js"; +export const KeycloakContext = React.createContext(undefined); +//# sourceMappingURL=KeycloakContext.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/keycloak-service/KeycloakContext.js.map b/keycloak-themes/keycloak.v2/account/resources/keycloak-service/KeycloakContext.js.map new file mode 100644 index 0000000..b693fee --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/keycloak-service/KeycloakContext.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/keycloak-service/KeycloakContext.tsx"],"names":["React","KeycloakContext","createContext","undefined"],"mappings":"AAAA,OAAO,KAAKA,KAAZ;AAGA,OAAO,MAAMC,eAAe,GAAGD,KAAK,CAACE,aAAN,CAAiDC,SAAjD,CAAxB","sourcesContent":["import * as React from 'react';\nimport { KeycloakService } from './keycloak.service';\n\nexport const KeycloakContext = React.createContext(undefined);"],"file":"KeycloakContext.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/keycloak-service/keycloak.service.js b/keycloak-themes/keycloak.v2/account/resources/keycloak-service/keycloak.service.js new file mode 100644 index 0000000..7eb3299 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/keycloak-service/keycloak.service.js @@ -0,0 +1,77 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2017 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export class KeycloakService { + constructor(keycloak) { + _defineProperty(this, "keycloakAuth", void 0); + + this.keycloakAuth = keycloak; + } + + authenticated() { + return this.keycloakAuth.authenticated ? this.keycloakAuth.authenticated : false; + } + + audiencePresent() { + if (this.keycloakAuth.tokenParsed) { + const audience = this.keycloakAuth.tokenParsed['aud']; + return audience === 'account' || Array.isArray(audience) && audience.indexOf('account') >= 0; + } + + return false; + } + + login(options) { + this.keycloakAuth.login(options); + } + + logout(redirectUri = baseUrl) { + this.keycloakAuth.logout({ + redirectUri: redirectUri + }); + } + + account() { + this.keycloakAuth.accountManagement(); + } + + authServerUrl() { + const authServerUrl = this.keycloakAuth.authServerUrl; + return authServerUrl.charAt(authServerUrl.length - 1) === '/' ? authServerUrl : authServerUrl + '/'; + } + + realm() { + return this.keycloakAuth.realm; + } + + getToken() { + return new Promise((resolve, reject) => { + if (this.keycloakAuth.token) { + this.keycloakAuth.updateToken(5).success(() => { + resolve(this.keycloakAuth.token); + }).error(() => { + reject('Failed to refresh token'); + }); + } else { + reject('Not logged in'); + } + }); + } + +} +//# sourceMappingURL=keycloak.service.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/keycloak-service/keycloak.service.js.map b/keycloak-themes/keycloak.v2/account/resources/keycloak-service/keycloak.service.js.map new file mode 100644 index 0000000..6119bab --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/keycloak-service/keycloak.service.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/keycloak-service/keycloak.service.ts"],"names":["KeycloakService","constructor","keycloak","keycloakAuth","authenticated","audiencePresent","tokenParsed","audience","Array","isArray","indexOf","login","options","logout","redirectUri","baseUrl","account","accountManagement","authServerUrl","charAt","length","realm","getToken","Promise","resolve","reject","token","updateToken","success","error"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA,OAAO,MAAMA,eAAN,CAAsB;AAGlBC,EAAAA,WAAW,CAACC,QAAD,EAA2B;AAAA;;AACzC,SAAKC,YAAL,GAAoBD,QAApB;AACH;;AAEME,EAAAA,aAAa,GAAY;AAC5B,WAAO,KAAKD,YAAL,CAAkBC,aAAlB,GAAkC,KAAKD,YAAL,CAAkBC,aAApD,GAAoE,KAA3E;AACH;;AAEMC,EAAAA,eAAe,GAAY;AAC9B,QAAI,KAAKF,YAAL,CAAkBG,WAAtB,EAAmC;AAC/B,YAAMC,QAAQ,GAAG,KAAKJ,YAAL,CAAkBG,WAAlB,CAA8B,KAA9B,CAAjB;AACA,aAAOC,QAAQ,KAAK,SAAb,IAA2BC,KAAK,CAACC,OAAN,CAAcF,QAAd,KAA2BA,QAAQ,CAACG,OAAT,CAAiB,SAAjB,KAA+B,CAA5F;AACH;;AACD,WAAO,KAAP;AACH;;AAEMC,EAAAA,KAAK,CAACC,OAAD,EAAuC;AAC/C,SAAKT,YAAL,CAAkBQ,KAAlB,CAAwBC,OAAxB;AACH;;AAEMC,EAAAA,MAAM,CAACC,WAAmB,GAAGC,OAAvB,EAAsC;AAC/C,SAAKZ,YAAL,CAAkBU,MAAlB,CAAyB;AAACC,MAAAA,WAAW,EAAEA;AAAd,KAAzB;AACH;;AAEME,EAAAA,OAAO,GAAS;AACnB,SAAKb,YAAL,CAAkBc,iBAAlB;AACH;;AAEMC,EAAAA,aAAa,GAAuB;AACvC,UAAMA,aAAa,GAAG,KAAKf,YAAL,CAAkBe,aAAxC;AACA,WAAOA,aAAa,CAAEC,MAAf,CAAsBD,aAAa,CAAEE,MAAf,GAAwB,CAA9C,MAAqD,GAArD,GAA2DF,aAA3D,GAA2EA,aAAa,GAAG,GAAlG;AACH;;AAEMG,EAAAA,KAAK,GAAuB;AAC/B,WAAO,KAAKlB,YAAL,CAAkBkB,KAAzB;AACH;;AAEMC,EAAAA,QAAQ,GAAoB;AAC/B,WAAO,IAAIC,OAAJ,CAAoB,CAACC,OAAD,EAAUC,MAAV,KAAqB;AAC5C,UAAI,KAAKtB,YAAL,CAAkBuB,KAAtB,EAA6B;AACzB,aAAKvB,YAAL,CACKwB,WADL,CACiB,CADjB,EAEKC,OAFL,CAEa,MAAM;AACXJ,UAAAA,OAAO,CAAC,KAAKrB,YAAL,CAAkBuB,KAAnB,CAAP;AACH,SAJL,EAKKG,KALL,CAKW,MAAM;AACTJ,UAAAA,MAAM,CAAC,yBAAD,CAAN;AACH,SAPL;AAQH,OATD,MASO;AACHA,QAAAA,MAAM,CAAC,eAAD,CAAN;AACH;AACJ,KAbM,CAAP;AAcH;;AAvDwB","sourcesContent":["/*\n * Copyright 2017 Red Hat, Inc. and/or its affiliates\n * and other contributors as indicated by the @author tags.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport Keycloak, { KeycloakLoginOptions } from \"../../../../../../../../../../adapters/oidc/js\";\n\ndeclare const baseUrl: string;\nexport type KeycloakClient = Keycloak;\n\nexport class KeycloakService {\n private keycloakAuth: KeycloakClient;\n\n public constructor(keycloak: KeycloakClient) {\n this.keycloakAuth = keycloak;\n }\n\n public authenticated(): boolean {\n return this.keycloakAuth.authenticated ? this.keycloakAuth.authenticated : false;\n }\n\n public audiencePresent(): boolean {\n if (this.keycloakAuth.tokenParsed) {\n const audience = this.keycloakAuth.tokenParsed['aud'];\n return audience === 'account' || (Array.isArray(audience) && audience.indexOf('account') >= 0);\n }\n return false;\n }\n\n public login(options?: KeycloakLoginOptions): void {\n this.keycloakAuth.login(options);\n }\n\n public logout(redirectUri: string = baseUrl): void {\n this.keycloakAuth.logout({redirectUri: redirectUri});\n }\n\n public account(): void {\n this.keycloakAuth.accountManagement();\n }\n\n public authServerUrl(): string | undefined {\n const authServerUrl = this.keycloakAuth.authServerUrl;\n return authServerUrl!.charAt(authServerUrl!.length - 1) === '/' ? authServerUrl : authServerUrl + '/';\n }\n\n public realm(): string | undefined {\n return this.keycloakAuth.realm;\n }\n\n public getToken(): Promise {\n return new Promise((resolve, reject) => {\n if (this.keycloakAuth.token) {\n this.keycloakAuth\n .updateToken(5)\n .success(() => {\n resolve(this.keycloakAuth.token as string);\n })\n .error(() => {\n reject('Failed to refresh token');\n });\n } else {\n reject('Not logged in');\n }\n });\n }\n}\n"],"file":"keycloak.service.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/public/favicon.ico b/keycloak-themes/keycloak.v2/account/resources/public/favicon.ico new file mode 100644 index 0000000..48188de Binary files /dev/null and b/keycloak-themes/keycloak.v2/account/resources/public/favicon.ico differ diff --git a/keycloak-themes/keycloak.v2/account/resources/public/layout.css b/keycloak-themes/keycloak.v2/account/resources/public/layout.css new file mode 100644 index 0000000..35bae9d --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/public/layout.css @@ -0,0 +1,126 @@ +/* Globals */ +.brand { + height: 35px; +} + +.delete-button { + width: 150px; + height: 50px; +} + +@media (max-width: 320px) { + .delete-button { + width: 120px; + height: 50px; + } +} + +/* Linked Accounts screen */ +.idp-icon-social { + width: 32px; + height: 32px; +} + +#github-idp-icon-social { + background-image: url(../img/socialmedia/socialmedia_icons_github_transparent.svg); +} + +#linkedin-idp-icon-social { + background-image: url(../img/socialmedia/socialmedia_icons_linkedin_transparent.svg); +} + +#facebook-idp-icon-social { + background-image: url(../img/socialmedia/socialmedia_icons_facebook_transparent.svg); +} + +#google-idp-icon-social { + background-image: url(../img/socialmedia/socialmedia_icons_google_transparent.svg); +} + +#microsoft-idp-icon-social { + background-image: url(../img/socialmedia/socialmedia_icons_microsoft_transparent.svg); +} + +#instagram-idp-icon-social { + background-image: url(../img/socialmedia/socialmedia_icons_instagram_transparent.svg); +} + +#stackoverflow-idp-icon-social { + background-image: url(../img/socialmedia/socialmedia_icons_stack_transparent.svg); +} + +#twitter-idp-icon-social { + background-image: url(../img/socialmedia/socialmedia_icons_twitter_transparent.svg); +} + +#openshift-idp-icon-social { + background-image: url(../img/socialmedia/socialmedia_icons_openshift_transparent.svg); +} + +/* Account Page screen */ +.personal-info-form .pf-c-form__group-control { + max-width: 600px; +} + +/* Device Activity screen */ +.signed-in-device-list .pf-c-data-list__item-row { + --pf-c-data-list__item-row--PaddingRight: 0; + --pf-c-data-list__item-row--PaddingLeft: 0; +} + +.signed-in-device-list .pf-c-data-list__expandable-content-body { + --pf-c-data-list__expandable-content-body--PaddingRight: 0; +} + +.signed-in-device-grid { + grid-template-columns: auto repeat(11, [col-start] 1fr); +} + +.signed-in-device-list.pf-c-data-list { + --pf-c-data-list--sm--BorderTopWidth: 0; +} + +.pf-c-data-list__item { + --pf-c-data-list__item--BorderBottomWidth: 1px; + --pf-c-data-list__item--BorderBottomColor: var(--pf-global--BorderColor--100); +} + +.signed-in-device-list.pf-c-data-list { + --pf-c-data-list--BorderTopWidth: 0; +} + +@media (min-width: 576px) { + .pf-c-data-list__item { + position: relative; + display: flex; + flex-direction: column; + background-color: var(--pf-c-data-list__item--BackgroundColor); + border-bottom: var(--pf-c-data-list__item--BorderBottomWidth) solid var(--pf-c-data-list__item--BorderBottomColor); + } + + .signed-in-device-list.pf-c-data-list { + --pf-c-data-list--BorderTopWidth: 0; + } +} + +@media (min-width: 768px) { + .signed-in-device-list .pf-c-description-list { + --pf-c-description-list--GridTemplateColumns--count: 5; + } +} + +/* Signing in screen */ +.title-case:first-letter, +.cred-title:first-letter, +#otp-not-set-up .pf-c-empty-state__body:first-letter { + text-transform: capitalize +} + +/* Applications screen */ +#applications-list-header .pf-c-data-list__item-content { + --pf-c-data-list__item-content--md--PaddingBottom: 1rem; +} + +.pf-u-pl-35xl { + padding-left: 4.5rem; +} diff --git a/keycloak-themes/keycloak.v2/account/resources/public/logo.svg b/keycloak-themes/keycloak.v2/account/resources/public/logo.svg new file mode 100644 index 0000000..17edc2c --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/public/logo.svg @@ -0,0 +1 @@ +keycloak_deliverables \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/util/AIACommand.js b/keycloak-themes/keycloak.v2/account/resources/util/AIACommand.js new file mode 100644 index 0000000..1e423e9 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/util/AIACommand.js @@ -0,0 +1,33 @@ +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Stan Silvert + */ +export class AIACommand { + constructor(keycloak, action) { + this.keycloak = keycloak; + this.action = action; + } + + execute() { + this.keycloak.login({ + action: this.action + }); + } + +} +//# sourceMappingURL=AIACommand.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/util/AIACommand.js.map b/keycloak-themes/keycloak.v2/account/resources/util/AIACommand.js.map new file mode 100644 index 0000000..d76cbd6 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/util/AIACommand.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/util/AIACommand.ts"],"names":["AIACommand","constructor","keycloak","action","execute","login"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAIA;AACA;AACA;AACA,OAAO,MAAMA,UAAN,CAAiB;AAEpBC,EAAAA,WAAW,CAASC,QAAT,EAA4CC,MAA5C,EAA4D;AAAA,SAAnDD,QAAmD,GAAnDA,QAAmD;AAAA,SAAhBC,MAAgB,GAAhBA,MAAgB;AAAE;;AAElEC,EAAAA,OAAO,GAAS;AACnB,SAAKF,QAAL,CAAcG,KAAd,CAAoB;AAChBF,MAAAA,MAAM,EAAE,KAAKA;AADG,KAApB;AAIH;;AATmB","sourcesContent":["/*\n * Copyright 2019 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {KeycloakService} from '../keycloak-service/keycloak.service';\n\n/**\n * @author Stan Silvert\n */\nexport class AIACommand {\n\n constructor(private keycloak: KeycloakService, private action: string) {}\n\n public execute(): void {\n this.keycloak.login({\n action: this.action,\n })\n\n }\n}"],"file":"AIACommand.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/util/ParseLink.js b/keycloak-themes/keycloak.v2/account/resources/util/ParseLink.js new file mode 100644 index 0000000..96d123f --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/util/ParseLink.js @@ -0,0 +1,19 @@ +function parse(linkHeader) { + if (!linkHeader) return {}; + const links = linkHeader.split(/,\s* { + const matcher = link.match(/]*)>(.*)/); + if (!matcher) return {}; + const linkUrl = matcher[1]; + const rel = matcher[2].match(/\s*(.+)\s*=\s*"?([^"]+)"?/); + + if (rel) { + acc[rel[2]] = linkUrl; + } + + return acc; + }, {}); +} + +export default parse; +//# sourceMappingURL=ParseLink.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/util/ParseLink.js.map b/keycloak-themes/keycloak.v2/account/resources/util/ParseLink.js.map new file mode 100644 index 0000000..2532f08 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/util/ParseLink.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/util/ParseLink.ts"],"names":["parse","linkHeader","links","split","reduce","acc","link","matcher","match","linkUrl","rel"],"mappings":"AAMA,SAASA,KAAT,CAAeC,UAAf,EAAsD;AACpD,MAAI,CAACA,UAAL,EAAiB,OAAO,EAAP;AACjB,QAAMC,KAAK,GAAGD,UAAU,CAACE,KAAX,CAAiB,OAAjB,CAAd;AACA,SAAOD,KAAK,CAACE,MAAN,CAAoB,CAACC,GAAD,EAAaC,IAAb,KAAqC;AAC9D,UAAMC,OAAO,GAAGD,IAAI,CAACE,KAAL,CAAW,gBAAX,CAAhB;AACA,QAAI,CAACD,OAAL,EAAc,OAAO,EAAP;AACd,UAAME,OAAO,GAAGF,OAAO,CAAC,CAAD,CAAvB;AACA,UAAMG,GAAG,GAAGH,OAAO,CAAC,CAAD,CAAP,CAAWC,KAAX,CAAiB,2BAAjB,CAAZ;;AACA,QAAIE,GAAJ,EAAS;AACLL,MAAAA,GAAG,CAACK,GAAG,CAAC,CAAD,CAAJ,CAAH,GAAcD,OAAd;AACH;;AACD,WAAOJ,GAAP;AACD,GATM,EASJ,EATI,CAAP;AAUD;;AAED,eAAeL,KAAf","sourcesContent":["\nexport interface Links {\n prev?: string;\n next?: string;\n}\n\nfunction parse(linkHeader: string | undefined): Links {\n if (!linkHeader) return {};\n const links = linkHeader.split(/,\\s*((acc: Links, link: string): Links => {\n const matcher = link.match(/]*)>(.*)/);\n if (!matcher) return {};\n const linkUrl = matcher[1];\n const rel = matcher[2].match(/\\s*(.+)\\s*=\\s*\"?([^\"]+)\"?/);\n if (rel) {\n acc[rel[2]] = linkUrl;\n }\n return acc;\n }, {});\n}\n\nexport default parse;"],"file":"ParseLink.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/util/RedirectUri.js b/keycloak-themes/keycloak.v2/account/resources/util/RedirectUri.js new file mode 100644 index 0000000..2cdfd98 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/util/RedirectUri.js @@ -0,0 +1,39 @@ +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Create a redirect uri that can return to this application with referrer and referrer_uri intact. + * + * @param currentLocation The ReactRouter location to return to. + * + * @author Stan Silvert + */ +export const createRedirect = currentLocation => { + let redirectUri = baseUrl; + + if (typeof referrer !== 'undefined') { + // '_hash_' is a workaround for when uri encoding is not + // sufficient to escape the # character properly. + // The problem is that both the redirect and the application URL contain a hash. + // The browser will consider anything after the first hash to be client-side. So + // it sees the hash in the redirect param and stops. + redirectUri += "?referrer=" + referrer + "&referrer_uri=" + referrerUri.replace('#', '_hash_'); + } + + return encodeURIComponent(redirectUri) + encodeURIComponent("/#" + currentLocation); +}; +//# sourceMappingURL=RedirectUri.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/util/RedirectUri.js.map b/keycloak-themes/keycloak.v2/account/resources/util/RedirectUri.js.map new file mode 100644 index 0000000..4076a2e --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/util/RedirectUri.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/util/RedirectUri.ts"],"names":["createRedirect","currentLocation","redirectUri","baseUrl","referrer","referrerUri","replace","encodeURIComponent"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMA,cAAc,GAAIC,eAAD,IAAqC;AAC/D,MAAIC,WAAmB,GAAGC,OAA1B;;AAEA,MAAI,OAAOC,QAAP,KAAoB,WAAxB,EAAqC;AACjC;AACA;AACA;AACA;AACA;AACAF,IAAAA,WAAW,IAAI,eAAeE,QAAf,GAA0B,gBAA1B,GAA6CC,WAAW,CAACC,OAAZ,CAAoB,GAApB,EAAyB,QAAzB,CAA5D;AACH;;AAED,SAAOC,kBAAkB,CAACL,WAAD,CAAlB,GAAkCK,kBAAkB,CAAC,OAAON,eAAR,CAA3D;AACH,CAbM","sourcesContent":["/*\n * Copyright 2019 Red Hat, Inc. and/or its affiliates\n * and other contributors as indicated by the @author tags.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ndeclare const baseUrl: string;\ndeclare const referrer: string;\ndeclare const referrerUri: string;\n\n/**\n * Create a redirect uri that can return to this application with referrer and referrer_uri intact.\n * \n * @param currentLocation The ReactRouter location to return to.\n * \n * @author Stan Silvert\n */\nexport const createRedirect = (currentLocation: string): string => {\n let redirectUri: string = baseUrl;\n \n if (typeof referrer !== 'undefined') {\n // '_hash_' is a workaround for when uri encoding is not\n // sufficient to escape the # character properly.\n // The problem is that both the redirect and the application URL contain a hash.\n // The browser will consider anything after the first hash to be client-side. So\n // it sees the hash in the redirect param and stops.\n redirectUri += \"?referrer=\" + referrer + \"&referrer_uri=\" + referrerUri.replace('#', '_hash_');\n }\n\n return encodeURIComponent(redirectUri) + encodeURIComponent(\"/#\" + currentLocation); \n}"],"file":"RedirectUri.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/util/TimeUtil.js b/keycloak-themes/keycloak.v2/account/resources/util/TimeUtil.js new file mode 100644 index 0000000..1097c92 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/util/TimeUtil.js @@ -0,0 +1,50 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2020 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Stan Silvert + */ +class TimeUtil { + constructor() { + _defineProperty(this, "options", { + year: 'numeric', + month: 'long', + day: 'numeric', + hour: 'numeric', + minute: 'numeric' + }); + + _defineProperty(this, "formatter", void 0); + + try { + this.formatter = new Intl.DateTimeFormat(locale, this.options); + } catch (e) { + // unknown locale falling back to English + this.formatter = new Intl.DateTimeFormat('en', this.options); + } + } + + format(time) { + return this.formatter.format(time); + } + +} + +const TimeUtilInstance = new TimeUtil(); +export default TimeUtilInstance; +//# sourceMappingURL=TimeUtil.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/util/TimeUtil.js.map b/keycloak-themes/keycloak.v2/account/resources/util/TimeUtil.js.map new file mode 100644 index 0000000..584288e --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/util/TimeUtil.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/util/TimeUtil.ts"],"names":["TimeUtil","constructor","year","month","day","hour","minute","formatter","Intl","DateTimeFormat","locale","options","e","format","time","TimeUtilInstance"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAIA;AACA;AACA;AACA,MAAMA,QAAN,CAAe;AAIXC,EAAAA,WAAW,GAAG;AAAA,qCAHI;AAAEC,MAAAA,IAAI,EAAE,SAAR;AAAmBC,MAAAA,KAAK,EAAE,MAA1B;AAAkCC,MAAAA,GAAG,EAAE,SAAvC;AAAkDC,MAAAA,IAAI,EAAE,SAAxD;AAAmEC,MAAAA,MAAM,EAAE;AAA3E,KAGJ;;AAAA;;AACV,QAAI;AACA,WAAKC,SAAL,GAAiB,IAAIC,IAAI,CAACC,cAAT,CAAwBC,MAAxB,EAAgC,KAAKC,OAArC,CAAjB;AACH,KAFD,CAEE,OAAMC,CAAN,EAAS;AACP;AACA,WAAKL,SAAL,GAAiB,IAAIC,IAAI,CAACC,cAAT,CAAwB,IAAxB,EAA8B,KAAKE,OAAnC,CAAjB;AACH;AACJ;;AAEDE,EAAAA,MAAM,CAACC,IAAD,EAAuB;AACzB,WAAO,KAAKP,SAAL,CAAeM,MAAf,CAAsBC,IAAtB,CAAP;AACH;;AAfU;;AAkBf,MAAMC,gBAA0B,GAAG,IAAIf,QAAJ,EAAnC;AACA,eAAee,gBAAf","sourcesContent":["/*\n * Copyright 2020 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ndeclare const locale: string;\n\n/**\n * @author Stan Silvert\n */\nclass TimeUtil {\n private options = { year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' };\n private formatter: Intl.DateTimeFormat;\n\n constructor() {\n try {\n this.formatter = new Intl.DateTimeFormat(locale, this.options);\n } catch(e) {\n // unknown locale falling back to English\n this.formatter = new Intl.DateTimeFormat('en', this.options);\n }\n }\n\n format(time: number): string {\n return this.formatter.format(time);\n }\n}\n\nconst TimeUtilInstance: TimeUtil = new TimeUtil();\nexport default TimeUtilInstance as TimeUtil;"],"file":"TimeUtil.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/welcome-page-scripts.js b/keycloak-themes/keycloak.v2/account/resources/welcome-page-scripts.js new file mode 100644 index 0000000..1ad130e --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/welcome-page-scripts.js @@ -0,0 +1,89 @@ +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +var isWelcomePage = function () { + var winHash = window.location.hash; + return winHash === '#/'; +}; + +var toggleReact = function () { + var welcomeScreen = document.getElementById("welcomeScreen"); + var spinnerScreen = document.getElementById("spinner_screen"); + var reactScreen = document.getElementById("main_react_container"); + + if (!isWelcomePage() && !isReactLoading) { + if (welcomeScreen) welcomeScreen.style.display = 'none'; + if (spinnerScreen) spinnerScreen.style.display = 'none'; + if (reactScreen) reactScreen.style.display = 'block'; + if (reactScreen) reactScreen.style.height = '100%'; + } else if (!isWelcomePage() && isReactLoading) { + if (welcomeScreen) welcomeScreen.style.display = 'none'; + if (reactScreen) reactScreen.style.display = 'none'; + if (spinnerScreen) spinnerScreen.style.display = 'block'; + if (spinnerScreen) spinnerScreen.style.height = '100%'; + } else { + if (reactScreen) reactScreen.style.display = 'none'; + if (spinnerScreen) spinnerScreen.style.display = 'none'; + if (welcomeScreen) welcomeScreen.style.display = 'block'; + if (welcomeScreen) welcomeScreen.style.height = '100%'; + } +}; + +function loggedInUserName() { + let userName = l18nMsg['unknownUser']; + if (keycloak.tokenParsed) { + const givenName = keycloak.tokenParsed.given_name; + const familyName = keycloak.tokenParsed.family_name; + const preferredUsername = keycloak.tokenParsed.preferred_username; + if (givenName && familyName) { + userName = [givenName, familyName].reduce((acc, value, index) => + acc.replace('{{param_'+ index + '}}', value), l18nMsg['fullName'] + ); + } else { + userName = (givenName || familyName) || preferredUsername || userName; + } + } + return sanitize(userName); +} + +function sanitize(dirtyString) { + let element = document.createElement("span"); + element.textContent = dirtyString; + return element.innerHTML; +} + +var toggleMobileDropdown = function () { + var mobileDropdown = document.getElementById("landingMobileDropdown"); + var mobileKebab = document.getElementById("landingMobileKebab"); + var mobileKebabButton = document.getElementById("landingMobileKebabButton"); + if (mobileDropdown.style.display === 'none') { + mobileDropdown.style.display = 'block'; + mobileKebab.classList.add("pf-m-expanded"); + mobileKebabButton.setAttribute("aria-expanded", "true"); + } else { + mobileDropdown.style.display = 'none'; + mobileKebab.classList.remove("pf-m-expanded"); + mobileKebabButton.setAttribute("aria-expanded", "false"); + } +} + +var loadjs = function (url, loadListener) { + const script = document.createElement("script"); + script.src = resourceUrl + url; + script.type = "module"; + if (loadListener) + script.addEventListener("load", loadListener); + document.head.appendChild(script); +}; diff --git a/keycloak-themes/keycloak.v2/account/resources/widgets/ContinueCancelModal.js b/keycloak-themes/keycloak.v2/account/resources/widgets/ContinueCancelModal.js new file mode 100644 index 0000000..1c18f0d --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/widgets/ContinueCancelModal.js @@ -0,0 +1,103 @@ +function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../common/keycloak/web_modules/react.js"; +import { Modal, ModalVariant, Button } from "../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { Msg } from "./Msg.js"; +/** + * For any of these properties that are strings, you can + * pass in a localization key instead of a static string. + */ + +/** + * This class renders a button that provides a continue/cancel modal dialog when clicked. If the user selects 'Continue' + * then the onContinue function is executed. + * + * @author Stan Silvert ssilvert@redhat.com (C) 2019 Red Hat Inc. + */ +export class ContinueCancelModal extends React.Component { + constructor(props) { + super(props); + + _defineProperty(this, "handleModalToggle", () => { + this.setState(({ + isModalOpen + }) => ({ + isModalOpen: !isModalOpen + })); + if (this.props.onClose) this.props.onClose(); + }); + + _defineProperty(this, "handleContinue", () => { + this.handleModalToggle(); + this.props.onContinue(); + }); + + this.state = { + isModalOpen: false + }; + } + + render() { + const { + isModalOpen + } = this.state; + return /*#__PURE__*/React.createElement(React.Fragment, null, !this.props.render && /*#__PURE__*/React.createElement(Button, { + id: this.props.buttonId, + variant: this.props.buttonVariant, + onClick: this.handleModalToggle, + isDisabled: this.props.isDisabled + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: this.props.buttonTitle + })), this.props.render && this.props.render(this.handleModalToggle), /*#__PURE__*/React.createElement(Modal, _extends({}, this.props, { + variant: ModalVariant.small, + title: Msg.localize(this.props.modalTitle), + isOpen: isModalOpen, + onClose: this.handleModalToggle, + actions: [/*#__PURE__*/React.createElement(Button, { + id: "modal-confirm", + key: "confirm", + variant: "primary", + onClick: this.handleContinue + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: this.props.modalContinueButtonLabel + })), /*#__PURE__*/React.createElement(Button, { + id: "modal-cancel", + key: "cancel", + variant: "secondary", + onClick: this.handleModalToggle + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: this.props.modalCancelButtonLabel + }))] + }), !this.props.modalMessage && this.props.children, this.props.modalMessage && /*#__PURE__*/React.createElement(Msg, { + msgKey: this.props.modalMessage + }))); + } + +} + +_defineProperty(ContinueCancelModal, "defaultProps", { + buttonVariant: 'primary', + modalContinueButtonLabel: 'continue', + modalCancelButtonLabel: 'doCancel', + isDisabled: false +}); + +; +//# sourceMappingURL=ContinueCancelModal.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/widgets/ContinueCancelModal.js.map b/keycloak-themes/keycloak.v2/account/resources/widgets/ContinueCancelModal.js.map new file mode 100644 index 0000000..3c24249 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/widgets/ContinueCancelModal.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/widgets/ContinueCancelModal.tsx"],"names":["React","Modal","ModalVariant","Button","Msg","ContinueCancelModal","Component","constructor","props","setState","isModalOpen","onClose","handleModalToggle","onContinue","state","render","buttonId","buttonVariant","isDisabled","buttonTitle","small","localize","modalTitle","handleContinue","modalContinueButtonLabel","modalCancelButtonLabel","modalMessage","children"],"mappings":";;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AACA,SAASC,KAAT,EAAgBC,YAAhB,EAA8BC,MAA9B;AACA,SAAQC,GAAR;AAEA;AACA;AACA;AACA;;AAmBA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,mBAAN,SAAkCL,KAAK,CAACM,SAAxC,CAAsG;AAQlGC,EAAAA,WAAW,CAACC,KAAD,EAAkC;AAChD,UAAMA,KAAN;;AADgD,+CAOxB,MAAM;AAC9B,WAAKC,QAAL,CAAc,CAAC;AAAEC,QAAAA;AAAF,OAAD,MAAsB;AAChCA,QAAAA,WAAW,EAAE,CAACA;AADkB,OAAtB,CAAd;AAGA,UAAI,KAAKF,KAAL,CAAWG,OAAf,EAAwB,KAAKH,KAAL,CAAWG,OAAX;AAC3B,KAZmD;;AAAA,4CAc3B,MAAM;AAC3B,WAAKC,iBAAL;AACA,WAAKJ,KAAL,CAAWK,UAAX;AACH,KAjBmD;;AAEhD,SAAKC,KAAL,GAAa;AACTJ,MAAAA,WAAW,EAAE;AADJ,KAAb;AAGH;;AAcMK,EAAAA,MAAM,GAAoB;AAC7B,UAAM;AAAEL,MAAAA;AAAF,QAAkB,KAAKI,KAA7B;AAEA,wBACI,oBAAC,KAAD,CAAO,QAAP,QACK,CAAC,KAAKN,KAAL,CAAWO,MAAZ,iBACD,oBAAC,MAAD;AAAQ,MAAA,EAAE,EAAE,KAAKP,KAAL,CAAWQ,QAAvB;AAAiC,MAAA,OAAO,EAAE,KAAKR,KAAL,CAAWS,aAArD;AAAoE,MAAA,OAAO,EAAE,KAAKL,iBAAlF;AAAqG,MAAA,UAAU,EAAE,KAAKJ,KAAL,CAAWU;AAA5H,oBACI,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAE,KAAKV,KAAL,CAAWW;AAAxB,MADJ,CAFJ,EAKK,KAAKX,KAAL,CAAWO,MAAX,IAAqB,KAAKP,KAAL,CAAWO,MAAX,CAAkB,KAAKH,iBAAvB,CAL1B,eAMI,oBAAC,KAAD,eACQ,KAAKJ,KADb;AAEI,MAAA,OAAO,EAAEN,YAAY,CAACkB,KAF1B;AAGI,MAAA,KAAK,EAAEhB,GAAG,CAACiB,QAAJ,CAAa,KAAKb,KAAL,CAAWc,UAAxB,CAHX;AAII,MAAA,MAAM,EAAEZ,WAJZ;AAKI,MAAA,OAAO,EAAE,KAAKE,iBALlB;AAMI,MAAA,OAAO,EAAE,cACL,oBAAC,MAAD;AAAQ,QAAA,EAAE,EAAC,eAAX;AAA2B,QAAA,GAAG,EAAC,SAA/B;AAAyC,QAAA,OAAO,EAAC,SAAjD;AAA2D,QAAA,OAAO,EAAE,KAAKW;AAAzE,sBACI,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAE,KAAKf,KAAL,CAAWgB;AAAxB,QADJ,CADK,eAIL,oBAAC,MAAD;AAAQ,QAAA,EAAE,EAAC,cAAX;AAA0B,QAAA,GAAG,EAAC,QAA9B;AAAuC,QAAA,OAAO,EAAC,WAA/C;AAA2D,QAAA,OAAO,EAAE,KAAKZ;AAAzE,sBACI,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAE,KAAKJ,KAAL,CAAWiB;AAAxB,QADJ,CAJK;AANb,QAeM,CAAC,KAAKjB,KAAL,CAAWkB,YAAZ,IAA4B,KAAKlB,KAAL,CAAWmB,QAf7C,EAgBM,KAAKnB,KAAL,CAAWkB,YAAX,iBAA2B,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAE,KAAKlB,KAAL,CAAWkB;AAAxB,MAhBjC,CANJ,CADJ;AA2BH;;AAzDwG;;gBAAhGrB,mB,kBACuB;AAC5BY,EAAAA,aAAa,EAAE,SADa;AAE5BO,EAAAA,wBAAwB,EAAE,UAFE;AAG5BC,EAAAA,sBAAsB,EAAE,UAHI;AAI5BP,EAAAA,UAAU,EAAE;AAJgB,C;;AAyDnC","sourcesContent":["/*\n * Copyright 2019 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\nimport { Modal, ModalVariant, Button, ButtonProps } from '@patternfly/react-core';\nimport {Msg} from './Msg';\n\n/**\n * For any of these properties that are strings, you can\n * pass in a localization key instead of a static string.\n */\ninterface ContinueCancelModalProps {\n buttonTitle?: string;\n buttonVariant?: ButtonProps['variant'];\n buttonId?: string;\n render?(toggle: () => void): React.ReactNode;\n modalTitle: string;\n modalMessage?: string;\n modalContinueButtonLabel?: string;\n modalCancelButtonLabel?: string;\n onContinue: () => void;\n onClose?: () => void;\n isDisabled?: boolean;\n}\n\ninterface ContinueCancelModalState {\n isModalOpen: boolean;\n}\n\n/**\n * This class renders a button that provides a continue/cancel modal dialog when clicked. If the user selects 'Continue'\n * then the onContinue function is executed.\n *\n * @author Stan Silvert ssilvert@redhat.com (C) 2019 Red Hat Inc.\n */\nexport class ContinueCancelModal extends React.Component {\n protected static defaultProps = {\n buttonVariant: 'primary',\n modalContinueButtonLabel: 'continue',\n modalCancelButtonLabel: 'doCancel',\n isDisabled: false\n };\n\n public constructor(props: ContinueCancelModalProps) {\n super(props);\n this.state = {\n isModalOpen: false\n };\n }\n\n private handleModalToggle = () => {\n this.setState(({ isModalOpen }) => ({\n isModalOpen: !isModalOpen\n }));\n if (this.props.onClose) this.props.onClose();\n };\n\n private handleContinue = () => {\n this.handleModalToggle();\n this.props.onContinue();\n }\n\n public render(): React.ReactNode {\n const { isModalOpen } = this.state;\n\n return (\n \n {!this.props.render &&\n }\n {this.props.render && this.props.render(this.handleModalToggle)}\n \n \n ,\n \n ]}\n >\n { !this.props.modalMessage && this.props.children}\n { this.props.modalMessage && }\n \n \n );\n }\n};\n"],"file":"ContinueCancelModal.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/widgets/EmptyMessageState.js b/keycloak-themes/keycloak.v2/account/resources/widgets/EmptyMessageState.js new file mode 100644 index 0000000..9e30de8 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/widgets/EmptyMessageState.js @@ -0,0 +1,38 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../common/keycloak/web_modules/react.js"; +import { EmptyState, EmptyStateVariant, Title, EmptyStateIcon, EmptyStateBody } from "../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { Msg } from "./Msg.js"; +export default class EmptyMessageState extends React.Component { + constructor(props) { + super(props); + } + + render() { + return /*#__PURE__*/React.createElement(EmptyState, { + variant: EmptyStateVariant.full + }, /*#__PURE__*/React.createElement(EmptyStateIcon, { + icon: this.props.icon + }), /*#__PURE__*/React.createElement(Title, { + headingLevel: "h5", + size: "lg" + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: this.props.messageKey + })), /*#__PURE__*/React.createElement(EmptyStateBody, null, this.props.children)); + } + +} +//# sourceMappingURL=EmptyMessageState.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/widgets/EmptyMessageState.js.map b/keycloak-themes/keycloak.v2/account/resources/widgets/EmptyMessageState.js.map new file mode 100644 index 0000000..5de8207 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/widgets/EmptyMessageState.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/widgets/EmptyMessageState.tsx"],"names":["React","EmptyState","EmptyStateVariant","Title","EmptyStateIcon","EmptyStateBody","Msg","EmptyMessageState","Component","constructor","props","render","full","icon","messageKey","children"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AACA,SACIC,UADJ,EAEIC,iBAFJ,EAGIC,KAHJ,EAIIC,cAJJ,EAKIC,cALJ;AAQA,SAASC,GAAT;AAQA,eAAe,MAAMC,iBAAN,SAAgCP,KAAK,CAACQ,SAAtC,CAA4E;AACvFC,EAAAA,WAAW,CAACC,KAAD,EAAgC;AACvC,UAAMA,KAAN;AACH;;AAEDC,EAAAA,MAAM,GAAG;AACL,wBACI,oBAAC,UAAD;AAAY,MAAA,OAAO,EAAET,iBAAiB,CAACU;AAAvC,oBACI,oBAAC,cAAD;AAAgB,MAAA,IAAI,EAAE,KAAKF,KAAL,CAAWG;AAAjC,MADJ,eAEI,oBAAC,KAAD;AAAO,MAAA,YAAY,EAAC,IAApB;AAAyB,MAAA,IAAI,EAAC;AAA9B,oBACI,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAE,KAAKH,KAAL,CAAWI;AAAxB,MADJ,CAFJ,eAKI,oBAAC,cAAD,QACK,KAAKJ,KAAL,CAAWK,QADhB,CALJ,CADJ;AAWH;;AAjBsF","sourcesContent":["/*\n * Copyright 2018 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\nimport {\n EmptyState,\n EmptyStateVariant,\n Title,\n EmptyStateIcon,\n EmptyStateBody,\n} from '@patternfly/react-core'\n\nimport { Msg } from './Msg';\nimport {SVGIconProps} from '@patternfly/react-icons/dist/esm/createIcon';\n\nexport interface EmptyMessageStateProps {\n icon: React.ComponentType;\n messageKey: string;\n}\n\nexport default class EmptyMessageState extends React.Component {\n constructor(props: EmptyMessageStateProps) {\n super(props);\n }\n\n render() {\n return (\n \n \n \n <Msg msgKey={this.props.messageKey} />\n \n \n {this.props.children}\n \n \n );\n }\n}\n"],"file":"EmptyMessageState.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/widgets/LocaleSelectors.js b/keycloak-themes/keycloak.v2/account/resources/widgets/LocaleSelectors.js new file mode 100644 index 0000000..851eae8 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/widgets/LocaleSelectors.js @@ -0,0 +1,41 @@ +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../common/keycloak/web_modules/react.js"; +import { FormSelect, FormSelectOption } from "../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { Msg } from "./Msg.js"; +; +export class LocaleSelector extends React.Component { + constructor(props) { + super(props); + } + + render() { + return /*#__PURE__*/React.createElement(FormSelect, { + id: "locale-select", + value: this.props.value, + onChange: (value, event) => { + if (this.props.onChange) this.props.onChange(value, event); + }, + "aria-label": Msg.localize('selectLocale') + }, availableLocales.map((locale, index) => /*#__PURE__*/React.createElement(FormSelectOption, { + key: index, + value: locale.locale, + label: locale.label + }))); + } + +} +//# sourceMappingURL=LocaleSelectors.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/widgets/LocaleSelectors.js.map b/keycloak-themes/keycloak.v2/account/resources/widgets/LocaleSelectors.js.map new file mode 100644 index 0000000..7522cc2 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/widgets/LocaleSelectors.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/widgets/LocaleSelectors.tsx"],"names":["React","FormSelect","FormSelectOption","Msg","LocaleSelector","Component","constructor","props","render","value","event","onChange","localize","availableLocales","map","locale","index","label"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,KAAKA,KAAZ;AAEA,SACIC,UADJ,EAEIC,gBAFJ;AAKA,SAASC,GAAT;AAKC;AAKD,OAAO,MAAMC,cAAN,SAA6BJ,KAAK,CAACK,SAAnC,CAAuF;AAE1FC,EAAAA,WAAW,CAACC,KAAD,EAA6B;AACpC,UAAMA,KAAN;AACH;;AAEDC,EAAAA,MAAM,GAAoB;AACtB,wBACI,oBAAC,UAAD;AACI,MAAA,EAAE,EAAC,eADP;AAEI,MAAA,KAAK,EAAE,KAAKD,KAAL,CAAWE,KAFtB;AAGI,MAAA,QAAQ,EAAE,CAACA,KAAD,EAAQC,KAAR,KAAkB;AAAE,YAAI,KAAKH,KAAL,CAAWI,QAAf,EAAyB,KAAKJ,KAAL,CAAWI,QAAX,CAAoBF,KAApB,EAA2BC,KAA3B;AAAmC,OAH9F;AAII,oBAAYP,GAAG,CAACS,QAAJ,CAAa,cAAb;AAJhB,OAMKC,gBAAgB,CAACC,GAAjB,CAAqB,CAACC,MAAD,EAASC,KAAT,kBAClB,oBAAC,gBAAD;AACI,MAAA,GAAG,EAAEA,KADT;AAEI,MAAA,KAAK,EAAED,MAAM,CAACA,MAFlB;AAGI,MAAA,KAAK,EAAEA,MAAM,CAACE;AAHlB,MADH,CANL,CADJ;AAgBH;;AAvByF","sourcesContent":["/*\n * Copyright 2019 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport * as React from 'react';\n\nimport {\n FormSelect,\n FormSelectOption,\n FormSelectProps\n} from '@patternfly/react-core';\nimport { Msg } from './Msg';\n\ninterface AvailableLocale {\n locale: string;\n label: string;\n};\ndeclare const availableLocales: [AvailableLocale];\n\ninterface LocaleSelectorProps extends Omit { }\ninterface LocaleSelectorState { }\nexport class LocaleSelector extends React.Component {\n\n constructor(props: LocaleSelectorProps) {\n super(props);\n }\n\n render(): React.ReactNode {\n return (\n { if (this.props.onChange) this.props.onChange(value, event) }}\n aria-label={Msg.localize('selectLocale')}\n >\n {availableLocales.map((locale, index) =>\n )\n }\n \n );\n }\n}"],"file":"LocaleSelectors.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/widgets/Logout.js b/keycloak-themes/keycloak.v2/account/resources/widgets/Logout.js new file mode 100644 index 0000000..bc7c566 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/widgets/Logout.js @@ -0,0 +1,46 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../common/keycloak/web_modules/react.js"; +import { Msg } from "./Msg.js"; +import { KeycloakContext } from "../keycloak-service/KeycloakContext.js"; +import { Button, DropdownItem } from "../../../common/keycloak/web_modules/@patternfly/react-core.js"; + +function handleLogout(keycloak) { + keycloak.logout(); +} + +export class LogoutButton extends React.Component { + render() { + return /*#__PURE__*/React.createElement(KeycloakContext.Consumer, null, keycloak => /*#__PURE__*/React.createElement(Button, { + id: "signOutButton", + onClick: () => handleLogout(keycloak) + }, /*#__PURE__*/React.createElement(Msg, { + msgKey: "doSignOut" + }))); + } + +} +export class LogoutDropdownItem extends React.Component { + render() { + return /*#__PURE__*/React.createElement(KeycloakContext.Consumer, null, keycloak => /*#__PURE__*/React.createElement(DropdownItem, { + id: "signOutLink", + key: "logout", + onClick: () => handleLogout(keycloak) + }, Msg.localize('doSignOut'))); + } + +} +//# sourceMappingURL=Logout.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/widgets/Logout.js.map b/keycloak-themes/keycloak.v2/account/resources/widgets/Logout.js.map new file mode 100644 index 0000000..569936d --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/widgets/Logout.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/widgets/Logout.tsx"],"names":["React","Msg","KeycloakContext","Button","DropdownItem","handleLogout","keycloak","logout","LogoutButton","Component","render","LogoutDropdownItem","localize"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AAEA,SAAQC,GAAR;AAEA,SAASC,eAAT;AAEA,SAAQC,MAAR,EAAgBC,YAAhB;;AAEA,SAASC,YAAT,CAAsBC,QAAtB,EAAuD;AACnDA,EAAAA,QAAQ,CAACC,MAAT;AACH;;AAGD,OAAO,MAAMC,YAAN,SAA2BR,KAAK,CAACS,SAAjC,CAAwD;AACpDC,EAAAA,MAAM,GAAoB;AAC7B,wBACI,oBAAC,eAAD,CAAiB,QAAjB,QACEJ,QAAQ,iBACN,oBAAC,MAAD;AAAQ,MAAA,EAAE,EAAC,eAAX;AAA2B,MAAA,OAAO,EAAE,MAAMD,YAAY,CAACC,QAAD;AAAtD,oBAAmE,oBAAC,GAAD;AAAK,MAAA,MAAM,EAAC;AAAZ,MAAnE,CAFJ,CADJ;AAQH;;AAV0D;AAc/D,OAAO,MAAMK,kBAAN,SAAiCX,KAAK,CAACS,SAAvC,CAA0E;AACtEC,EAAAA,MAAM,GAAoB;AAC7B,wBACI,oBAAC,eAAD,CAAiB,QAAjB,QACMJ,QAAQ,iBACV,oBAAC,YAAD;AAAc,MAAA,EAAE,EAAC,aAAjB;AAA+B,MAAA,GAAG,EAAC,QAAnC;AAA4C,MAAA,OAAO,EAAE,MAAMD,YAAY,CAACC,QAAD;AAAvE,OACKL,GAAG,CAACW,QAAJ,CAAa,WAAb,CADL,CAFJ,CADJ;AASH;;AAX4E","sourcesContent":["/*\n * Copyright 2018 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\n\nimport {Msg} from './Msg';\nimport {KeycloakService} from '../keycloak-service/keycloak.service';\nimport { KeycloakContext } from '../keycloak-service/KeycloakContext';\n\nimport {Button, DropdownItem} from '@patternfly/react-core';\n\nfunction handleLogout(keycloak: KeycloakService): void {\n keycloak.logout();\n}\n\ninterface LogoutProps {}\nexport class LogoutButton extends React.Component {\n public render(): React.ReactNode {\n return (\n \n { keycloak => (\n \n )}\n \n\n );\n }\n}\n\ninterface LogoutDropdownItemProps {}\nexport class LogoutDropdownItem extends React.Component {\n public render(): React.ReactNode {\n return (\n \n { keycloak => (\n handleLogout(keycloak!)}>\n {Msg.localize('doSignOut')}\n \n )}\n \n );\n }\n}"],"file":"Logout.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/widgets/Msg.js b/keycloak-themes/keycloak.v2/account/resources/widgets/Msg.js new file mode 100644 index 0000000..b0cfb84 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/widgets/Msg.js @@ -0,0 +1,69 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../common/keycloak/web_modules/react.js"; +export class Msg extends React.Component { + constructor(props) { + super(props); + } + + render() { + if (this.props.children) { + return Msg.localizeWithChildren(this.props.msgKey, this.props.children); + } + + return /*#__PURE__*/React.createElement(React.Fragment, null, Msg.localize(this.props.msgKey, this.props.params)); + } + + static localizeWithChildren(msgKey, children) { + const message = l18nMsg[this.processKey(msgKey)]; + const parts = message.split(/\{\{param_\d*}}/); + const count = React.Children.count(children); + return React.Children.map(children, (child, i) => [parts[i], child, count === i + 1 ? parts[count] : '']); + } + + static localize(msgKey, params) { + let message = l18nMsg[this.processKey(msgKey)]; + if (message === undefined) message = msgKey; + + if (params !== undefined && params.length > 0) { + params.forEach((value, index) => { + value = this.processParam(value); + message = message.replace('{{param_' + index + '}}', value); + }); + } + + return message; + } // if the message key has Freemarker syntax, remove it + + + static processKey(msgKey) { + if (!(msgKey.startsWith('${') && msgKey.endsWith('}'))) return msgKey; // remove Freemarker syntax + + return msgKey.substring(2, msgKey.length - 1); + } // if the param has Freemarker syntax, try to look up its value + + + static processParam(param) { + if (!(param.startsWith('${') && param.endsWith('}'))) return param; // remove Freemarker syntax + + const key = param.substring(2, param.length - 1); + let value = l18nMsg[key]; + if (value === undefined) return param; + return value; + } + +} +//# sourceMappingURL=Msg.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/widgets/Msg.js.map b/keycloak-themes/keycloak.v2/account/resources/widgets/Msg.js.map new file mode 100644 index 0000000..24e3e53 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/widgets/Msg.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/widgets/Msg.tsx"],"names":["React","Msg","Component","constructor","props","render","children","localizeWithChildren","msgKey","localize","params","message","l18nMsg","processKey","parts","split","count","Children","map","child","i","undefined","length","forEach","value","index","processParam","replace","startsWith","endsWith","substring","param","key"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AASA,OAAO,MAAMC,GAAN,SAAkBD,KAAK,CAACE,SAAxB,CAA4C;AAExCC,EAAAA,WAAW,CAACC,KAAD,EAAkB;AAChC,UAAMA,KAAN;AACH;;AAEMC,EAAAA,MAAM,GAAoB;AAC7B,QAAI,KAAKD,KAAL,CAAWE,QAAf,EAAyB;AACrB,aAAOL,GAAG,CAACM,oBAAJ,CAAyB,KAAKH,KAAL,CAAWI,MAApC,EAA4C,KAAKJ,KAAL,CAAWE,QAAvD,CAAP;AACH;;AACD,wBACI,oBAAC,KAAD,CAAO,QAAP,QAAiBL,GAAG,CAACQ,QAAJ,CAAa,KAAKL,KAAL,CAAWI,MAAxB,EAAgC,KAAKJ,KAAL,CAAWM,MAA3C,CAAjB,CADJ;AAGH;;AAEkC,SAApBH,oBAAoB,CAACC,MAAD,EAAiBF,QAAjB,EAA6D;AAC5F,UAAMK,OAAe,GAAGC,OAAO,CAAC,KAAKC,UAAL,CAAgBL,MAAhB,CAAD,CAA/B;AACA,UAAMM,KAAK,GAAGH,OAAO,CAACI,KAAR,CAAc,iBAAd,CAAd;AACA,UAAMC,KAAK,GAAGhB,KAAK,CAACiB,QAAN,CAAeD,KAAf,CAAqBV,QAArB,CAAd;AACA,WAAON,KAAK,CAACiB,QAAN,CAAeC,GAAf,CAAmBZ,QAAnB,EAA6B,CAACa,KAAD,EAAQC,CAAR,KAChC,CAACN,KAAK,CAACM,CAAD,CAAN,EAAWD,KAAX,EAAkBH,KAAK,KAAKI,CAAC,GAAG,CAAd,GAAkBN,KAAK,CAACE,KAAD,CAAvB,GAAiC,EAAnD,CADG,CAAP;AAGH;;AAEqB,SAARP,QAAQ,CAACD,MAAD,EAAiBE,MAAjB,EAA4C;AAC9D,QAAIC,OAAe,GAAGC,OAAO,CAAC,KAAKC,UAAL,CAAgBL,MAAhB,CAAD,CAA7B;AACA,QAAIG,OAAO,KAAKU,SAAhB,EAA2BV,OAAO,GAAGH,MAAV;;AAE3B,QAAKE,MAAM,KAAKW,SAAZ,IAA2BX,MAAM,CAACY,MAAP,GAAgB,CAA/C,EAAmD;AAC/CZ,MAAAA,MAAM,CAACa,OAAP,CAAe,CAACC,KAAD,EAAgBC,KAAhB,KAAkC;AAC7CD,QAAAA,KAAK,GAAG,KAAKE,YAAL,CAAkBF,KAAlB,CAAR;AACAb,QAAAA,OAAO,GAAGA,OAAO,CAACgB,OAAR,CAAgB,aAAYF,KAAZ,GAAoB,IAApC,EAA0CD,KAA1C,CAAV;AACH,OAHD;AAIH;;AAED,WAAOb,OAAP;AACH,GApC8C,CAsC/C;;;AACyB,SAAVE,UAAU,CAACL,MAAD,EAAyB;AAC9C,QAAI,EAAEA,MAAM,CAACoB,UAAP,CAAkB,IAAlB,KAA2BpB,MAAM,CAACqB,QAAP,CAAgB,GAAhB,CAA7B,CAAJ,EAAwD,OAAOrB,MAAP,CADV,CAG9C;;AACA,WAAOA,MAAM,CAACsB,SAAP,CAAiB,CAAjB,EAAoBtB,MAAM,CAACc,MAAP,GAAgB,CAApC,CAAP;AACH,GA5C8C,CA8C/C;;;AAC2B,SAAZI,YAAY,CAACK,KAAD,EAAwB;AAC/C,QAAI,EAAEA,KAAK,CAACH,UAAN,CAAiB,IAAjB,KAA0BG,KAAK,CAACF,QAAN,CAAe,GAAf,CAA5B,CAAJ,EAAsD,OAAOE,KAAP,CADP,CAG/C;;AACA,UAAMC,GAAW,GAAGD,KAAK,CAACD,SAAN,CAAgB,CAAhB,EAAmBC,KAAK,CAACT,MAAN,GAAe,CAAlC,CAApB;AAEA,QAAIE,KAAa,GAAGZ,OAAO,CAACoB,GAAD,CAA3B;AACA,QAAIR,KAAK,KAAKH,SAAd,EAAyB,OAAOU,KAAP;AAEzB,WAAOP,KAAP;AACH;;AAzD8C","sourcesContent":["/*\n * Copyright 2018 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\n\ndeclare const l18nMsg: {[key: string]: string};\n\nexport interface MsgProps {\n readonly msgKey: string;\n readonly params?: string[];\n}\n\nexport class Msg extends React.Component {\n\n public constructor(props: MsgProps) {\n super(props);\n }\n\n public render(): React.ReactNode {\n if (this.props.children) {\n return Msg.localizeWithChildren(this.props.msgKey, this.props.children);\n }\n return (\n {Msg.localize(this.props.msgKey, this.props.params)}\n );\n }\n\n private static localizeWithChildren(msgKey: string, children: React.ReactNode): React.ReactNode {\n const message: string = l18nMsg[this.processKey(msgKey)];\n const parts = message.split(/\\{\\{param_\\d*}}/);\n const count = React.Children.count(children);\n return React.Children.map(children, (child, i) =>\n [parts[i], child, count === i + 1 ? parts[count] : '']\n );\n }\n\n public static localize(msgKey: string, params?: string[]): string {\n let message: string = l18nMsg[this.processKey(msgKey)];\n if (message === undefined) message = msgKey;\n\n if ((params !== undefined) && (params.length > 0)) {\n params.forEach((value: string, index: number) => {\n value = this.processParam(value);\n message = message.replace('{{param_'+ index + '}}', value);\n })\n }\n\n return message;\n }\n\n // if the message key has Freemarker syntax, remove it\n private static processKey(msgKey: string): string {\n if (!(msgKey.startsWith('${') && msgKey.endsWith('}'))) return msgKey;\n\n // remove Freemarker syntax\n return msgKey.substring(2, msgKey.length - 1);\n }\n\n // if the param has Freemarker syntax, try to look up its value\n private static processParam(param: string): string {\n if (!(param.startsWith('${') && param.endsWith('}'))) return param;\n\n // remove Freemarker syntax\n const key: string = param.substring(2, param.length - 1);\n\n let value: string = l18nMsg[key];\n if (value === undefined) return param;\n\n return value;\n }\n}\n"],"file":"Msg.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/widgets/ReferrerDropdownItem.js b/keycloak-themes/keycloak.v2/account/resources/widgets/ReferrerDropdownItem.js new file mode 100644 index 0000000..e02ce0d --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/widgets/ReferrerDropdownItem.js @@ -0,0 +1,38 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../common/keycloak/web_modules/react.js"; +import { Msg } from "./Msg.js"; +import { DropdownItem } from "../../../common/keycloak/web_modules/@patternfly/react-core.js"; +import { ArrowIcon } from "../../../common/keycloak/web_modules/@patternfly/react-icons.js"; + +/** + * @author Stan Silvert ssilvert@redhat.com (C) 2018 Red Hat Inc. + */ +export class ReferrerDropdownItem extends React.Component { + constructor(props) { + super(props); + } + + render() { + return /*#__PURE__*/React.createElement(DropdownItem, { + id: "referrerMobileLink", + href: referrerUri + }, /*#__PURE__*/React.createElement(ArrowIcon, null), " ", Msg.localize('backTo', [referrerName])); + } + +} +; +//# sourceMappingURL=ReferrerDropdownItem.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/widgets/ReferrerDropdownItem.js.map b/keycloak-themes/keycloak.v2/account/resources/widgets/ReferrerDropdownItem.js.map new file mode 100644 index 0000000..9aafda5 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/widgets/ReferrerDropdownItem.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/widgets/ReferrerDropdownItem.tsx"],"names":["React","Msg","DropdownItem","ArrowIcon","ReferrerDropdownItem","Component","constructor","props","render","referrerUri","localize","referrerName"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AAEA,SAAQC,GAAR;AAEA,SAAQC,YAAR;AACA,SAAQC,SAAR;;AAQA;AACA;AACA;AACA,OAAO,MAAMC,oBAAN,SAAmCJ,KAAK,CAACK,SAAzC,CAA8E;AAE1EC,EAAAA,WAAW,CAACC,KAAD,EAAmC;AACjD,UAAMA,KAAN;AACH;;AAEMC,EAAAA,MAAM,GAAoB;AAE7B,wBACI,oBAAC,YAAD;AAAc,MAAA,EAAE,EAAC,oBAAjB;AAAsC,MAAA,IAAI,EAAEC;AAA5C,oBACI,oBAAC,SAAD,OADJ,OACmBR,GAAG,CAACS,QAAJ,CAAa,QAAb,EAAuB,CAACC,YAAD,CAAvB,CADnB,CADJ;AAKH;;AAbgF;AAcpF","sourcesContent":["/*\n * Copyright 2018 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\n\nimport {Msg} from '../widgets/Msg';\n\nimport {DropdownItem} from '@patternfly/react-core';\nimport {ArrowIcon} from '@patternfly/react-icons';\n\ndeclare const referrerName: string;\ndeclare const referrerUri: string;\n\nexport interface ReferrerDropdownItemProps {\n}\n\n/**\n * @author Stan Silvert ssilvert@redhat.com (C) 2018 Red Hat Inc.\n */\nexport class ReferrerDropdownItem extends React.Component {\n\n public constructor(props: ReferrerDropdownItemProps) {\n super(props);\n }\n\n public render(): React.ReactNode {\n\n return (\n \n {Msg.localize('backTo', [referrerName])}\n \n );\n }\n};"],"file":"ReferrerDropdownItem.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/widgets/ReferrerLink.js b/keycloak-themes/keycloak.v2/account/resources/widgets/ReferrerLink.js new file mode 100644 index 0000000..7e9b905 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/widgets/ReferrerLink.js @@ -0,0 +1,46 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "../../../common/keycloak/web_modules/react.js"; +import { Msg } from "./Msg.js"; +import { ArrowIcon } from "../../../common/keycloak/web_modules/@patternfly/react-icons.js"; + +/** + * @author Stan Silvert ssilvert@redhat.com (C) 2018 Red Hat Inc. + */ +export class ReferrerLink extends React.Component { + constructor(props) { + super(props); + } + + render() { + return ( + /*#__PURE__*/ + // '_hash_' is a workaround for when uri encoding is not + // sufficient to escape the # character properly. + // See AppInitiatedActionPage for more details. + React.createElement("a", { + id: "referrerLink", + href: referrerUri.replace('_hash_', '#') + }, /*#__PURE__*/React.createElement(ArrowIcon, null), " ", /*#__PURE__*/React.createElement(Msg, { + msgKey: "backTo", + params: [referrerName] + })) + ); + } + +} +; +//# sourceMappingURL=ReferrerLink.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/widgets/ReferrerLink.js.map b/keycloak-themes/keycloak.v2/account/resources/widgets/ReferrerLink.js.map new file mode 100644 index 0000000..a4d8d86 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/widgets/ReferrerLink.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/app/widgets/ReferrerLink.tsx"],"names":["React","Msg","ArrowIcon","ReferrerLink","Component","constructor","props","render","referrerUri","replace","referrerName"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA,OAAO,KAAKA,KAAZ;AAEA,SAAQC,GAAR;AAEA,SAAQC,SAAR;;AAQA;AACA;AACA;AACA,OAAO,MAAMC,YAAN,SAA2BH,KAAK,CAACI,SAAjC,CAA8D;AAE1DC,EAAAA,WAAW,CAACC,KAAD,EAA2B;AACzC,UAAMA,KAAN;AACH;;AAEMC,EAAAA,MAAM,GAAoB;AAC7B;AAAA;AACI;AACA;AACA;AACA;AAAG,QAAA,EAAE,EAAC,cAAN;AAAqB,QAAA,IAAI,EAAEC,WAAW,CAACC,OAAZ,CAAoB,QAApB,EAA8B,GAA9B;AAA3B,sBACG,oBAAC,SAAD,OADH,oBACgB,oBAAC,GAAD;AAAK,QAAA,MAAM,EAAC,QAAZ;AAAqB,QAAA,MAAM,EAAE,CAACC,YAAD;AAA7B,QADhB;AAJJ;AAQH;;AAfgE;AAgBpE","sourcesContent":["/*\n * Copyright 2018 Red Hat, Inc. and/or its affiliates.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as React from 'react';\n\nimport {Msg} from './Msg';\n\nimport {ArrowIcon} from '@patternfly/react-icons';\n \ndeclare const referrerName: string;\ndeclare const referrerUri: string;\n\nexport interface ReferrerLinkProps {\n}\n\n/**\n * @author Stan Silvert ssilvert@redhat.com (C) 2018 Red Hat Inc.\n */\nexport class ReferrerLink extends React.Component {\n\n public constructor(props: ReferrerLinkProps) {\n super(props);\n }\n\n public render(): React.ReactNode {\n return (\n // '_hash_' is a workaround for when uri encoding is not\n // sufficient to escape the # character properly.\n // See AppInitiatedActionPage for more details.\n \n \n \n );\n }\n};"],"file":"ReferrerLink.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/widgets/features.js b/keycloak-themes/keycloak.v2/account/resources/widgets/features.js new file mode 100644 index 0000000..164aa91 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/widgets/features.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=features.js.map \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/resources/widgets/features.js.map b/keycloak-themes/keycloak.v2/account/resources/widgets/features.js.map new file mode 100644 index 0000000..d74cab8 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/resources/widgets/features.js.map @@ -0,0 +1 @@ +{"version":3,"sources":[],"names":[],"mappings":"","sourcesContent":[],"file":"features.js"} \ No newline at end of file diff --git a/keycloak-themes/keycloak.v2/account/theme.properties b/keycloak-themes/keycloak.v2/account/theme.properties new file mode 100644 index 0000000..68635e6 --- /dev/null +++ b/keycloak-themes/keycloak.v2/account/theme.properties @@ -0,0 +1,18 @@ +parent=base +deprecatedMode=false + +scripts=welcome-page-scripts.js + +developmentMode=false + +# This is the logo in upper lefthand corner. +# It must be a relative path. +logo=/public/logo.svg + +# This is the link followed when clicking on the logo. +# It can be any valid URL, including an external site. +logoUrl=./ + +# This is the icon for the account console. +# It must be a relative path. +favIcon=/public/favicon.ico diff --git a/keycloak-themes/keycloak/account/resources/css/account.css b/keycloak-themes/keycloak/account/resources/css/account.css new file mode 100644 index 0000000..3878e43 --- /dev/null +++ b/keycloak-themes/keycloak/account/resources/css/account.css @@ -0,0 +1,277 @@ +html { + height: 100%; +} + +body { + background-color: #F9F9F9; + margin: 0; + padding: 0; + height: 100%; +} + +header .navbar { + margin-bottom: 0; + min-height: inherit; +} + +.header .container { + position: relative; +} + +.navbar-title { + background-image: url('../img/logo.png'); + height: 25px; + background-repeat: no-repeat; + width: 123px; + margin: 3px 10px 5px; + text-indent: -99999px; +} + +.navbar-pf .navbar-utility { + right: 20px; + top: -34px; + font-size: 12px; +} + +.navbar-pf .navbar-utility > li > a { + color: #fff !important; + padding-bottom: 12px; + padding-top: 11px; + border-left: medium none; +} + +.container { + height: 100%; +} + +.content-area { + background-color: #fff; + border-color: #CECECE; + border-style: solid; + border-width: 0 1px; + height: 100%; + padding: 0 30px; +} + +.margin-bottom { + margin-bottom: 10px; +} + +/* Sidebar */ + +.bs-sidebar { + background-color: #f9f9f9; + padding-top: 44px; + padding-right: 0; + padding-left: 0; + z-index: 20; +} +.bs-sidebar ul { + list-style: none; + padding-left: 12px; +} + +.bs-sidebar ul li { + margin-bottom: 0.5em; + margin-left: -1em; +} +.bs-sidebar ul li a { + font-size: 14px; + padding-left: 25px; + color: #4d5258; + line-height: 28px; + display: block; + border-width: 1px 0 1px 1px; + border-style: solid; + border-color: #f9f9f9; +} +.bs-sidebar ul li a:hover, +.bs-sidebar ul li a:focus { + text-decoration: none; + color: #777777; + border-right: 2px solid #aaa; +} +.bs-sidebar ul li.active a { + background-color: #c7e5f0; + border-color: #56bae0; + font-weight: bold; + background-image: url(../img/icon-sidebar-active.png); + background-repeat: no-repeat; + background-position: right center; +} + +.bs-sidebar ul li.active a:hover { + border-right: none; +} + + +.content-area h2 { + font-family: "Open Sans", sans-serif; + font-weight: 100; + font-size: 24px; + margin-bottom: 25px; + margin-top: 25px; +} + +.subtitle { + text-align: right; + margin-top: 30px; + color: #909090; +} + +.required { + color: #CB2915; +} + + +.alert { + margin-top: 30px; + margin-bottom: 0; +} + +.feedback-aligner .alert { + background-position: 1.27273em center; + background-repeat: no-repeat; + border-radius: 2px; + border-width: 1px; + color: #4D5258; + display: inline-block; + font-size: 1.1em; + line-height: 1.4em; + margin: 0; + padding: 0.909091em 3.63636em; + position: relative; + text-align: left; +} +.alert.alert-success { + background-color: #E4F1E1; + border-color: #4B9E39; +} +.alert.alert-error { + background-color: #F8E7E7; + border-color: #B91415; +} +.alert.alert-warning { + background-color: #FEF1E9; + border-color: #F17528; +} +.alert.alert-info { + background-color: #E4F3FA; + border-color: #5994B2; +} + +.form-horizontal { + border-top: 1px solid #E9E8E8; + padding-top: 23px; +} + +.form-horizontal .control-label { + color: #909090; + line-height: 1.4em; + padding-top: 5px; + position: relative; + text-align: right; + width: 100%; +} + +.form-group { + position: relative; +} + +.control-label + .required { + position: absolute; + right: -2px; + top: 0; +} + +#kc-form-buttons { + text-align: right; + margin-top: 10px; +} + +#kc-form-buttons .btn-primary { + float: right; + margin-left: 8px; +} + +/* Authenticator page */ + +ol { + padding-left: 40px; +} + +ol li { + font-size: 13px; + margin-bottom: 10px; + position: relative; +} + +ol li img { + margin-top: 15px; + margin-bottom: 5px; + border: 1px solid #eee; +} + +hr + .form-horizontal { + border: none; + padding-top: 0; +} + +.kc-dropdown{ + position: relative; +} +.kc-dropdown > a{ + display:block; + padding: 11px 10px 12px; + line-height: 12px; + font-size: 12px; + color: #fff !important; + text-decoration: none; +} +.kc-dropdown > a::after{ + content: "\2c5"; + margin-left: 4px; +} +.kc-dropdown:hover > a{ + background-color: rgba(0,0,0,0.2); +} +.kc-dropdown ul li a{ + padding: 1px 11px; + font-size: 12px; + color: #000 !important; + border: 1px solid #fff; + text-decoration: none; + display:block; + line-height: 20px; +} +.kc-dropdown ul li a:hover{ + color: #4d5258; + background-color: #d4edfa; + border-color: #b3d3e7; +} +.kc-dropdown ul{ + position: absolute; + z-index: 2000; + list-style:none; + display:none; + padding: 5px 0px; + margin: 0px; + background-color: #fff !important; + border: 1px solid #b6b6b6; + border-radius: 1px; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + background-clip: padding-box; + min-width: 100px; +} +.kc-dropdown:hover ul{ + display:block; +} + + +#kc-totp-secret-key { + border: 1px solid #eee; + font-size: 16px; + padding: 10px; + margin: 50px 0; +} \ No newline at end of file diff --git a/keycloak-themes/keycloak/account/resources/img/icon-sidebar-active.png b/keycloak-themes/keycloak/account/resources/img/icon-sidebar-active.png new file mode 100644 index 0000000..e7b9b08 Binary files /dev/null and b/keycloak-themes/keycloak/account/resources/img/icon-sidebar-active.png differ diff --git a/keycloak-themes/keycloak/account/resources/img/keycloak-logo.png b/keycloak-themes/keycloak/account/resources/img/keycloak-logo.png new file mode 100644 index 0000000..9555748 Binary files /dev/null and b/keycloak-themes/keycloak/account/resources/img/keycloak-logo.png differ diff --git a/keycloak-themes/keycloak/account/resources/img/logo.png b/keycloak-themes/keycloak/account/resources/img/logo.png new file mode 100644 index 0000000..a698c54 Binary files /dev/null and b/keycloak-themes/keycloak/account/resources/img/logo.png differ diff --git a/keycloak-themes/keycloak/account/theme.properties b/keycloak-themes/keycloak/account/theme.properties new file mode 100644 index 0000000..e7f1147 --- /dev/null +++ b/keycloak-themes/keycloak/account/theme.properties @@ -0,0 +1,14 @@ +parent=base +import=common/keycloak + +styles=css/account.css +stylesCommon=node_modules/patternfly/dist/css/patternfly.min.css node_modules/patternfly/dist/css/patternfly-additions.min.css + +##### css classes for form buttons +# main class used for all buttons +kcButtonClass=btn +# classes defining priority of the button - primary or default (there is typically only one priority button for the form) +kcButtonPrimaryClass=btn-primary +kcButtonDefaultClass=btn-default +# classes defining size of the button +kcButtonLargeClass=btn-lg diff --git a/keycloak-themes/keycloak/admin/resources/css/styles.css b/keycloak-themes/keycloak/admin/resources/css/styles.css new file mode 100644 index 0000000..bb85710 --- /dev/null +++ b/keycloak-themes/keycloak/admin/resources/css/styles.css @@ -0,0 +1,505 @@ +html,body { + height: 100%; +} + +form { + margin-top: 20px; +} + +table { + margin-top: 20px; +} + +.required { + color: #f00; +} + +.tooltip-inner { + min-width: 200px; +} + +.margin-top { + margin-top: 20px; +} + +.no-margin-top { + margin-top: 0px !important; +} + +table { + max-width: 100%; +} + +td.clip { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 0; +} + +th.w-10 { + width: 10%; +} + +th.w-15 { + width: 15%; +} + +th.w-20 { + width: 20%; +} + + +th.w-25 { + width: 25%; +} + +th.w-30 { + width: 30%; +} + + +th.w-35 { + width: 35%; +} + +th.w-40 { + width: 40%; +} + +/*********** Loading ***********/ + +.loading { + background-color: #f5f5f5; + border: 1px solid #eee; + position: absolute; + bottom: 0px; + left: 0px; + padding: 2px 200px 2px 5px; +} + +/*********** Feedback ***********/ + +.feedback-aligner { + position: fixed; + top: 15px; + text-align: center; + width: 100%; + height: 0; + z-index: 100; +} +.feedback-aligner .alert { + border-radius: 2px; + border-width: 1px; + display: inline-block; + position: relative; +} + +/*********** On-Off Switch ***********/ + +.onoffswitch { + -moz-user-select: none; + height: 26px; + position: relative; + width: 62px; +} +.onoffswitch .onoffswitch-checkbox { + display: none; +} +.onoffswitch .onoffswitch-label { + border: 1px solid #bbb; + border-radius: 2px; + cursor: pointer; + display: block; + overflow: hidden; + width: 62px; +} +.onoffswitch .onoffswitch-inner { + display: block; + margin-left: -100%; + transition: margin 0.3s ease-in 0s; + width: 200%; +} +.onoffswitch .onoffswitch-inner > span { + -moz-box-sizing: border-box; + color: white; + float: left; + font-size: 11px; + font-family: "Open Sans", sans-serif; + font-weight: bold; + height: 24px; + line-height: 24px; + padding: 0; + width: 50%; +} +.onoffswitch .onoffswitch-switch { + background-image: linear-gradient(top, #fafafa 0%, #ededed 100%); + background-image: -o-linear-gradient(top, #fafafa 0%, #ededed 100%); + background-image: -moz-linear-gradient(top, #fafafa 0%, #ededed 100%); + background-image: -webkit-linear-gradient(top, #fafafa 0%, #ededed 100%); + background-image: -ms-linear-gradient(top, #fafafa 0%, #ededed 100%); + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fafafa), color-stop(1, 0, #ededed)); + border: 1px solid #aaa; + border-radius: 2px; + bottom: 0; + margin: 0; + position: absolute; + right: 39px; + top: 0; + transition: all 0.3s ease-in 0s; + -webkit-transition: all 0.3s ease-in 0s; + width: 23px; +} +.onoffswitch .onoffswitch-inner .onoffswitch-active { + background-image: linear-gradient(top, #00a9ec 0%, #009bd3 100%); + background-image: -o-linear-gradient(top, #00a9ec 0%, #009bd3 100%); + background-image: -moz-linear-gradient(top, #00a9ec 0%, #009bd3 100%); + background-image: -webkit-linear-gradient(top, #00a9ec 0%, #009bd3 100%); + background-image: -ms-linear-gradient(top, #00a9ec 0%, #009bd3 100%); + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #00a9ec), color-stop(1, 0, #009bd3)); + color: #FFFFFF; + padding-left: 10px; +} +.onoffswitch-checkbox:disabled + .onoffswitch-label .onoffswitch-inner .onoffswitch-active, +.onoffswitch-checkbox:disabled + .onoffswitch-label .onoffswitch-inner .onoffswitch-inactive { + background-image: none; + background-color: #e5e5e5; + color: #9d9fa1; +} +.onoffswitch .onoffswitch-inner .onoffswitch-inactive { + background: linear-gradient(#fefefe, #e8e8e8) repeat scroll 0 0 transparent; + color: #4d5258; + padding-right: 10px; + text-align: right; +} +.onoffswitch .onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner { + margin-left: 0; +} +.onoffswitch .onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch { + right: 0; +} + + +/*********** Select 2 ***********/ + +.select2-container { + width: 100%; +} + +.select2-container-multi .select2-choices .select2-search-field { + height: 26px; +} + +.select2-container-single { + padding: 0; + margin: 0; +} + +.select2-container-single .form-group { + width: 100%; + margin: 0; +} + +.select2-container-single .form-group .input-group { + width: 100%; +} + +/*********** html select ********/ +.overflow-select { + overflow: auto; +} + + +/*********** New Menu ***********/ + + +.sidebar-pf-left{ + background: #292e34; +} + +.sidebar-pf .nav-pills > li a i, .sidebar-pf .nav-pills > li a span{ + color: #72767b; + display: inline-block; + margin-right: 10px; +} +.sidebar-pf .nav-pills > li > a{ + color: #dbdada; + padding: 0px 20px 0 30px!important; + line-height: 30px; + border-left-width: 12px; + border-left-style: solid; + border-left-color: #292e34; + margin-left: -6px; +} + +.sidebar-pf .nav-pills > li > a:hover{ + background: #393f44; + border-color:#292e34; + border-left-color: #393f44; + color: #fff; +} + +.sidebar-pf .nav-pills > li > a:after{ + display: none!important; +} + + +.sidebar-pf .nav-pills > li.active > a { + color: #fff; + background: #393f44!important; + border-bottom: 1px solid #000!important; + border-top: 1px solid #000!important; + border-left-color: #39a5dc!important; +} + +.sidebar-pf .nav-pills > li.active a i, .sidebar-pf .nav-pills > li.active a span{ + color: #39a5dc; +} + +/*********** Realm selector ***********/ + +.realm-selector{ + color: #fff; + margin: 0 -20px; + position: relative; +} + +.realm-dropmenu{ + display: none; + cursor: pointer; + position: absolute; + top: 60px; + left: 0; + right: 0; + z-index: 999; + background: #fff; +} + +.realm-selector:hover .realm-dropmenu{ + display: block; +} + +.realm-add{ + padding: 10px; +} + +.realm-selector h2{ + font-size: 16px; + line-height: 60px; + padding: 0 20px; + margin: 0; + border-bottom: 1px solid #d5d5d6; +} + +.realm-selector h2 i{ + display: inline-block; + float: right; + line-height: 60px; +} + + +.realm-selector ul{ + padding-left: 0; + margin: 0; + list-style: none; + max-height: 200px; + overflow-y:auto; +} + + +.realm-selector ul li a{ + line-height: 60px; + padding: 0 20px; + border-bottom: 1px solid #d5d5d6; + line-height: 39px; + display: block; + font-size: 14px; +} + + +/*********** Overwrites header defaults ***********/ + +.navbar-pf{ + border-top: none!important; +} + +.navbar-pf .navbar-brand { + padding: 0; + height: 56px; + line-height: 56px; + background-position: center center; + background-image: url('../img/keyclok-logo.png'); + background-size: 148px 30px; + background-repeat: no-repeat; + width: 148px; +} + +.navbar-pf .navbar-utility .dropdown-toggle { + padding: 23px !important; +} + +.clickable { + cursor: pointer; +} + +h1 i { + color: #999999; + font-size: 18px; + margin-left: 10px; +} + +/* Action cell */ +.kc-action-cell { + background-color: #eeeeee; + background-image: linear-gradient(to bottom, #fafafa 0%, #ededed 100%); + background-repeat: repeat-x; + + text-align: center; + vertical-align: middle; + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + cursor:pointer; +} + +.kc-action-cell:hover { + background-color: #eeeeee; + background-image: none; +} + +.kc-action-cell-disabled { + background-color: #fafafa; + color: #8b8d8f; + background-image: none; + cursor: not-allowed; +} + +.kc-sorter span { + margin-left: 10px; +} + + +/* Time selector */ + +.time-selector input { + display: inline-block; + width: 120px; + padding-right: 0; + margin-right: 0; +} + +.time-selector select { + display: inline-block; + width: 80px; + margin-left: 0; + padding-left: 0; +} + +.ace_editor { + height: 600px; + width: 100%; +} + +.kc-button-input-file input { + float: left; + width: 73%; +} + +.kc-button-input-file label { + float: left; + margin-left: 2%; + width: 25%; +} + +table.kc-authz-table-expanded { + margin-top: 0px !important; +} + +.no-gutter > [class*='col-'] { + padding-right:0!important; + padding-left:0!important; +} + +.password-conceal { + font-family: 'text-security-disc'; + font-size: 14px; +} + +.input-map input.form-control { + width: 50%; +} + +/* Deactivation styles for user-group membership tree models */ + +div[tree-model] li .deactivate { + color: #4a5053; + opacity: 0.4; +} + +div[tree-model] li .deactivate_selected { + background-color: #dcdcdc; + font-weight: bold; + padding: 1px 5px; +} + +/* search highlighting */ + +div[tree-model] li .highlight { + background-color: #aaddff; +} + +/* Manage credentials */ +table.credentials-table { + margin-top: 0; + margin-bottom: 20px; +} + +table.credentials-table td { + vertical-align: middle !important; +} + +table.credentials-table input[type='text'] { + width: 100%; +} + +td.credential-arrows-cell { + width: 75px; +} + +td.credential-label-cell { + padding: 5px !important; +} + +td.credential-action-cell { + padding: 0px !important; +} + +td.credential-action-cell div.kc-action-cell { + width: 100%; + height: 36px; + line-height: 34px; +} + +td.credential-action-cell.expanded div.kc-action-cell { + border-bottom: 1px solid #d1d1d1; +} + +table.credential-data-table td { + word-break: break-all; +} + +table.credential-data-table tr:first-child td { + border-top: 0; +} + +table.credential-data-table td:first-child { + width: 150px; +} + +table.credential-data-table td.key { + text-align: right; + font-weight: bold; +} + diff --git a/keycloak-themes/keycloak/admin/resources/img/keyclok-logo.png b/keycloak-themes/keycloak/admin/resources/img/keyclok-logo.png new file mode 100644 index 0000000..ca53f0a Binary files /dev/null and b/keycloak-themes/keycloak/admin/resources/img/keyclok-logo.png differ diff --git a/keycloak-themes/keycloak/admin/resources/img/keyclok-logo.svg b/keycloak-themes/keycloak/admin/resources/img/keyclok-logo.svg new file mode 100644 index 0000000..05fa87b --- /dev/null +++ b/keycloak-themes/keycloak/admin/resources/img/keyclok-logo.svg @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/keycloak-themes/keycloak/admin/resources/img/select-arrow.png b/keycloak-themes/keycloak/admin/resources/img/select-arrow.png new file mode 100644 index 0000000..a865a6f Binary files /dev/null and b/keycloak-themes/keycloak/admin/resources/img/select-arrow.png differ diff --git a/keycloak-themes/keycloak/admin/theme.properties b/keycloak-themes/keycloak/admin/theme.properties new file mode 100644 index 0000000..c1a677f --- /dev/null +++ b/keycloak-themes/keycloak/admin/theme.properties @@ -0,0 +1,5 @@ +parent=base +import=common/keycloak + +styles=css/styles.css +stylesCommon=node_modules/patternfly/dist/css/patternfly.min.css node_modules/patternfly/dist/css/patternfly-additions.min.css node_modules/select2/select2.css lib/angular/treeview/css/angular.treeview.css node_modules/text-security/text-security.css diff --git a/keycloak-themes/keycloak/common/resources/img/favicon.ico b/keycloak-themes/keycloak/common/resources/img/favicon.ico new file mode 100644 index 0000000..48188de Binary files /dev/null and b/keycloak-themes/keycloak/common/resources/img/favicon.ico differ diff --git a/keycloak-themes/keycloak/common/resources/lib/angular/errors.json b/keycloak-themes/keycloak/common/resources/lib/angular/errors.json new file mode 100644 index 0000000..0fe7286 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/lib/angular/errors.json @@ -0,0 +1 @@ +{"id":"ng","generated":"Thu Aug 13 2015 11:47:38 GMT-0700 (PDT)","errors":{"ng":{"areq":"Argument '{0}' is {1}","cpta":"Can't copy! TypedArray destination cannot be mutated.","test":"no injector found for element argument to getTestability","cpws":"Can't copy! Making copies of Window or Scope instances is not supported.","btstrpd":"App Already Bootstrapped with this Element '{0}'","cpi":"Can't copy! Source and destination are identical.","badname":"hasOwnProperty is not a valid {0} name"},"$http":{"legacy":"The method `{0}` on the promise returned from `$http` has been disabled.","badreq":"Http request configuration must be an object. Received: {0}"},"ngRepeat":{"badident":"alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.","iexp":"Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.","dupes":"Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}","iidexp":"'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'."},"$sce":{"imatcher":"Matchers may only be \"self\", string patterns or RegExp objects","icontext":"Attempted to trust a value in invalid context. Context: {0}; Value: {1}","iwcard":"Illegal sequence *** in string matcher. String: {0}","insecurl":"Blocked loading resource from url not allowed by $sceDelegate policy. URL: {0}","iequirks":"Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks mode. You can fix this by adding the text to the top of your HTML document. See http://docs.angularjs.org/api/ng.$sce for more information.","unsafe":"Attempting to use an unsafe value in a safe context.","itype":"Attempted to trust a non-string value in a content requiring a string: Context: {0}"},"ngPattern":{"noregexp":"Expected {0} to be a RegExp but was {1}. Element: {2}"},"$controller":{"ctrlfmt":"Badly formed controller string '{0}'. Must match `__name__ as __id__` or `__name__`.","noscp":"Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`."},"$parse":{"isecfn":"Referencing Function in Angular expressions is disallowed! Expression: {0}","isecwindow":"Referencing the Window in Angular expressions is disallowed! Expression: {0}","ueoe":"Unexpected end of expression: {0}","isecdom":"Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}","lexerr":"Lexer Error: {0} at column{1} in expression [{2}].","esc":"IMPOSSIBLE","isecobj":"Referencing Object in Angular expressions is disallowed! Expression: {0}","lval":"Trying to assing a value to a non l-value","isecff":"Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}","syntax":"Syntax Error: Token '{0}' {1} at column {2} of the expression [{3}] starting at [{4}].","isecfld":"Attempting to access a disallowed field in Angular expressions! Expression: {0}"},"jqLite":{"offargs":"jqLite#off() does not support the `selector` argument","onargs":"jqLite#on() does not support the `selector` or `eventData` parameters","nosel":"Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element"},"$animate":{"notcsel":"Expecting class selector starting with '.' got '{0}'.","nongcls":"$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the \"{0}\" CSS class."},"$q":{"norslvr":"Expected resolverFn, got '{0}'","qcycle":"Expected promise to be resolved with value other than itself '{0}'"},"$injector":{"pget":"Provider '{0}' must define $get factory method.","cdep":"Circular dependency found: {0}","nomod":"Module '{0}' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.","strictdi":"{0} is not using explicit annotation and cannot be invoked in strict mode","modulerr":"Failed to instantiate module {0} due to:\n{1}","undef":"Provider '{0}' must return a value from $get factory method.","unpr":"Unknown provider: {0}","itkn":"Incorrect injection token! Expected service name as string, got {0}"},"filter":{"notarray":"Expected array but received: {0}"},"ngTransclude":{"orphan":"Illegal use of ngTransclude directive in the template! No parent directive that requires a transclusion found. Element: {0}"},"ngModel":{"nonassign":"Expression '{0}' is non-assignable. Element: {1}","datefmt":"Expected `{0}` to be a date","$asyncValidators":"Expected asynchronous validator to return a promise but got '{0}' instead.","constexpr":"Expected constant expression for `{0}`, but saw `{1}`.","numfmt":"Expected `{0}` to be a number"},"$location":{"nostate":"History API state support is available only in HTML5 mode and only in browsers supporting HTML5 History API","ipthprfx":"Invalid url \"{0}\", missing path prefix \"{1}\".","isrcharg":"The first argument of the `$location#search()` call must be a string or an object.","nobase":"$location in HTML5 mode requires a tag to be present!"},"$cacheFactory":{"iid":"CacheId '{0}' is already taken!"},"$interpolate":{"noconcat":"Error while interpolating: {0}\nStrict Contextual Escaping disallows interpolations that concatenate multiple expressions when a trusted value is required. See http://docs.angularjs.org/api/ng.$sce","interr":"Can't interpolate: {0}\n{1}","nochgmustache":"angular-message-format.js currently does not allow you to use custom start and end symbols for interpolation.","reqcomma":"Expected a comma after the keyword “{0}” at line {1}, column {2} of text “{3}”","untermstr":"The string beginning at line {0}, column {1} is unterminated in text “{2}”","badexpr":"Unexpected operator “{0}” at line {1}, column {2} in text. Was expecting “{3}”. Text: “{4}”","dupvalue":"The choice “{0}” is specified more than once. Duplicate key is at line {1}, column {2} in text “{3}”","unsafe":"Use of select/plural MessageFormat syntax is currently disallowed in a secure context ({0}). At line {1}, column {2} of text “{3}”","reqother":"“other” is a required option.","reqendinterp":"Expecting end of interpolation symbol, “{0}”, at line {1}, column {2} in text “{3}”","reqarg":"Expected one of “plural” or “select” at line {0}, column {1} of text “{2}”","wantstring":"Expected the beginning of a string at line {0}, column {1} in text “{2}”","logicbug":"The messageformat parser has encountered an internal error. Please file a github issue against the AngularJS project and provide this message text that triggers the bug. Text: “{0}”","reqopenbrace":"The plural choice “{0}” must be followed by a message in braces at line {1}, column {2} in text “{3}”","unknarg":"Unsupported keyword “{0}” at line {0}, column {1}. Only “plural” and “select” are currently supported. Text: “{3}”","reqendbrace":"The plural/select choice “{0}” message starting at line {1}, column {2} does not have an ending closing brace. Text “{3}”"},"ngOptions":{"iexp":"Expected expression in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '{0}'. Element: {1}"},"$rootScope":{"inprog":"{0} already in progress","infdig":"{0} $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: {1}"},"$compile":{"noident":"Cannot bind to controller without identifier for directive '{0}'.","selmulti":"Binding to the 'multiple' attribute is not supported. Element: {0}","nodomevents":"Interpolations for HTML DOM event attributes are disallowed. Please use the ng- versions (such as ng-click instead of onclick) instead.","ctreq":"Controller '{0}', required by directive '{1}', can't be found!","nonassign":"Expression '{0}' used with directive '{1}' is non-assignable!","tplrt":"Template for directive '{0}' must have exactly one root element. {1}","iscp":"Invalid {3} for directive '{0}'. Definition: {... {1}: '{2}' ...}","baddir":"Directive name '{0}' is invalid. The name should not contain leading or trailing whitespaces","noctrl":"Cannot bind to controller without directive '{0}'s controller.","multidir":"Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}","tpload":"Failed to load template: {0} (HTTP status: {1} {2})","uterdir":"Unterminated attribute, found '{0}' but no matching '{1}' found."},"$resource":{"badargs":"Expected up to 4 arguments [params, data, success, error], got {0} arguments","badmember":"Dotted member path \"@{0}\" is invalid.","badname":"hasOwnProperty is not a valid parameter name.","badcfg":"Error in resource configuration for action `{0}`. Expected response to contain an {1} but got an {2} (Request: {3} {4})"},"$route":{"norout":"Tried updating route when with no current route"},"$sanitize":{"badparse":"The sanitizer was unable to parse the following block of html: {0}"}}} \ No newline at end of file diff --git a/keycloak-themes/keycloak/common/resources/lib/angular/treeview/LICENSE b/keycloak-themes/keycloak/common/resources/lib/angular/treeview/LICENSE new file mode 100644 index 0000000..514acd3 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/lib/angular/treeview/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Steve + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/keycloak-themes/keycloak/common/resources/lib/angular/treeview/angular.treeview.js b/keycloak-themes/keycloak/common/resources/lib/angular/treeview/angular.treeview.js new file mode 100644 index 0000000..2e56cad --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/lib/angular/treeview/angular.treeview.js @@ -0,0 +1,95 @@ +/* + @license Angular Treeview version 0.1.6 + ⓒ 2013 AHN JAE-HA http://github.com/eu81273/angular.treeview + License: MIT + + + [TREE attribute] + angular-treeview: the treeview directive + tree-id : each tree's unique id. + tree-model : the tree model on $scope. + node-id : each node's id + node-label : each node's label + node-children: each node's children + +
    +
    +*/ + +(function ( angular ) { + 'use strict'; + + angular.module( 'angularTreeview', [] ).directive( 'treeModel', ['$compile', function( $compile ) { + return { + restrict: 'A', + link: function ( scope, element, attrs ) { + //tree id + var treeId = attrs.treeId; + + //tree model + var treeModel = attrs.treeModel; + + //node id + var nodeId = attrs.nodeId || 'id'; + + //node label + var nodeLabel = attrs.nodeLabel || 'label'; + + //children + var nodeChildren = attrs.nodeChildren || 'children'; + + //tree template + var template = + '
      ' + + '
    • ' + + '' + + '{{node.' + nodeLabel + '}}' + + '
      ' + + '
    • ' + + '
    '; + + //check tree id, tree model + if( treeId && treeModel ) { + //root node + if( attrs.angularTreeview ) { + + //create tree object if not exists + scope[treeId] = scope[treeId] || {}; + + //if node head clicks, + scope[treeId].selectNodeHead = scope[treeId].selectNodeHead || function( selectedNode ){ + + //Collapse or Expand + selectedNode.collapsed = !selectedNode.collapsed; + scope[treeId].selectNodeLabel(selectedNode); + }; + + //if node label clicks, + scope[treeId].selectNodeLabel = scope[treeId].selectNodeLabel || function( selectedNode ){ + + //remove highlight from previous node + if( scope[treeId].currentNode && scope[treeId].currentNode.selected ) { + scope[treeId].currentNode.selected = undefined; + } + + //set highlight to selected node + selectedNode.selected = 'selected'; + + //set currentNode + scope[treeId].currentNode = selectedNode; + }; + } + + //Rendering template. + element.html('').append( $compile( template )( scope ) ); + } + } + }; + }]); +})( angular ); diff --git a/keycloak-themes/keycloak/common/resources/lib/angular/treeview/angular.treeview.min.js b/keycloak-themes/keycloak/common/resources/lib/angular/treeview/angular.treeview.min.js new file mode 100644 index 0000000..e02a85b --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/lib/angular/treeview/angular.treeview.min.js @@ -0,0 +1,9 @@ +/* + @license Angular Treeview version 0.1.6 + ⓒ 2013 AHN JAE-HA http://github.com/eu81273/angular.treeview + License: MIT +*/ + +(function(f){f.module("angularTreeview",[]).directive("treeModel",function($compile){return{restrict:"A",link:function(b,h,c){var a=c.treeId,g=c.treeModel,e=c.nodeLabel||"label",d=c.nodeChildren||"children",e='
    • {{node.'+e+'}}
      +// Heading containing HTML - +// +.directive('accordionHeading', function() { + return { + restrict: 'EA', + transclude: true, // Grab the contents to be used as the heading + template: '', // In effect remove this element! + replace: true, + require: '^accordionGroup', + link: function(scope, element, attr, accordionGroupCtrl, transclude) { + // Pass the heading to the accordion-group controller + // so that it can be transcluded into the right place in the template + // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat] + accordionGroupCtrl.setHeading(transclude(scope, function() {})); + } + }; +}) + +// Use in the accordion-group template to indicate where you want the heading to be transcluded +// You must provide the property on the accordion-group controller that will hold the transcluded element +//
      +// +// ... +//
      +.directive('accordionTransclude', function() { + return { + require: '^accordionGroup', + link: function(scope, element, attr, controller) { + scope.$watch(function() { return controller[attr.accordionTransclude]; }, function(heading) { + if ( heading ) { + element.html(''); + element.append(heading); + } + }); + } + }; +}); + +angular.module('ui.bootstrap.alert', []) + +.controller('AlertController', ['$scope', '$attrs', function ($scope, $attrs) { + $scope.closeable = 'close' in $attrs; +}]) + +.directive('alert', function () { + return { + restrict:'EA', + controller:'AlertController', + templateUrl:'template/alert/alert.html', + transclude:true, + replace:true, + scope: { + type: '@', + close: '&' + } + }; +}); + +angular.module('ui.bootstrap.bindHtml', []) + + .directive('bindHtmlUnsafe', function () { + return function (scope, element, attr) { + element.addClass('ng-binding').data('$binding', attr.bindHtmlUnsafe); + scope.$watch(attr.bindHtmlUnsafe, function bindHtmlUnsafeWatchAction(value) { + element.html(value || ''); + }); + }; + }); +angular.module('ui.bootstrap.buttons', []) + +.constant('buttonConfig', { + activeClass: 'active', + toggleEvent: 'click' +}) + +.controller('ButtonsController', ['buttonConfig', function(buttonConfig) { + this.activeClass = buttonConfig.activeClass || 'active'; + this.toggleEvent = buttonConfig.toggleEvent || 'click'; +}]) + +.directive('btnRadio', function () { + return { + require: ['btnRadio', 'ngModel'], + controller: 'ButtonsController', + link: function (scope, element, attrs, ctrls) { + var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1]; + + //model -> UI + ngModelCtrl.$render = function () { + element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.btnRadio))); + }; + + //ui->model + element.bind(buttonsCtrl.toggleEvent, function () { + var isActive = element.hasClass(buttonsCtrl.activeClass); + + if (!isActive || angular.isDefined(attrs.uncheckable)) { + scope.$apply(function () { + ngModelCtrl.$setViewValue(isActive ? null : scope.$eval(attrs.btnRadio)); + ngModelCtrl.$render(); + }); + } + }); + } + }; +}) + +.directive('btnCheckbox', function () { + return { + require: ['btnCheckbox', 'ngModel'], + controller: 'ButtonsController', + link: function (scope, element, attrs, ctrls) { + var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1]; + + function getTrueValue() { + return getCheckboxValue(attrs.btnCheckboxTrue, true); + } + + function getFalseValue() { + return getCheckboxValue(attrs.btnCheckboxFalse, false); + } + + function getCheckboxValue(attributeValue, defaultValue) { + var val = scope.$eval(attributeValue); + return angular.isDefined(val) ? val : defaultValue; + } + + //model -> UI + ngModelCtrl.$render = function () { + element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue())); + }; + + //ui->model + element.bind(buttonsCtrl.toggleEvent, function () { + scope.$apply(function () { + ngModelCtrl.$setViewValue(element.hasClass(buttonsCtrl.activeClass) ? getFalseValue() : getTrueValue()); + ngModelCtrl.$render(); + }); + }); + } + }; +}); + +/** +* @ngdoc overview +* @name ui.bootstrap.carousel +* +* @description +* AngularJS version of an image carousel. +* +*/ +angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition']) +.controller('CarouselController', ['$scope', '$timeout', '$transition', function ($scope, $timeout, $transition) { + var self = this, + slides = self.slides = $scope.slides = [], + currentIndex = -1, + currentTimeout, isPlaying; + self.currentSlide = null; + + var destroyed = false; + /* direction: "prev" or "next" */ + self.select = $scope.select = function(nextSlide, direction) { + var nextIndex = slides.indexOf(nextSlide); + //Decide direction if it's not given + if (direction === undefined) { + direction = nextIndex > currentIndex ? 'next' : 'prev'; + } + if (nextSlide && nextSlide !== self.currentSlide) { + if ($scope.$currentTransition) { + $scope.$currentTransition.cancel(); + //Timeout so ng-class in template has time to fix classes for finished slide + $timeout(goNext); + } else { + goNext(); + } + } + function goNext() { + // Scope has been destroyed, stop here. + if (destroyed) { return; } + //If we have a slide to transition from and we have a transition type and we're allowed, go + if (self.currentSlide && angular.isString(direction) && !$scope.noTransition && nextSlide.$element) { + //We shouldn't do class manip in here, but it's the same weird thing bootstrap does. need to fix sometime + nextSlide.$element.addClass(direction); + var reflow = nextSlide.$element[0].offsetWidth; //force reflow + + //Set all other slides to stop doing their stuff for the new transition + angular.forEach(slides, function(slide) { + angular.extend(slide, {direction: '', entering: false, leaving: false, active: false}); + }); + angular.extend(nextSlide, {direction: direction, active: true, entering: true}); + angular.extend(self.currentSlide||{}, {direction: direction, leaving: true}); + + $scope.$currentTransition = $transition(nextSlide.$element, {}); + //We have to create new pointers inside a closure since next & current will change + (function(next,current) { + $scope.$currentTransition.then( + function(){ transitionDone(next, current); }, + function(){ transitionDone(next, current); } + ); + }(nextSlide, self.currentSlide)); + } else { + transitionDone(nextSlide, self.currentSlide); + } + self.currentSlide = nextSlide; + currentIndex = nextIndex; + //every time you change slides, reset the timer + restartTimer(); + } + function transitionDone(next, current) { + angular.extend(next, {direction: '', active: true, leaving: false, entering: false}); + angular.extend(current||{}, {direction: '', active: false, leaving: false, entering: false}); + $scope.$currentTransition = null; + } + }; + $scope.$on('$destroy', function () { + destroyed = true; + }); + + /* Allow outside people to call indexOf on slides array */ + self.indexOfSlide = function(slide) { + return slides.indexOf(slide); + }; + + $scope.next = function() { + var newIndex = (currentIndex + 1) % slides.length; + + //Prevent this user-triggered transition from occurring if there is already one in progress + if (!$scope.$currentTransition) { + return self.select(slides[newIndex], 'next'); + } + }; + + $scope.prev = function() { + var newIndex = currentIndex - 1 < 0 ? slides.length - 1 : currentIndex - 1; + + //Prevent this user-triggered transition from occurring if there is already one in progress + if (!$scope.$currentTransition) { + return self.select(slides[newIndex], 'prev'); + } + }; + + $scope.isActive = function(slide) { + return self.currentSlide === slide; + }; + + $scope.$watch('interval', restartTimer); + $scope.$on('$destroy', resetTimer); + + function restartTimer() { + resetTimer(); + var interval = +$scope.interval; + if (!isNaN(interval) && interval>=0) { + currentTimeout = $timeout(timerFn, interval); + } + } + + function resetTimer() { + if (currentTimeout) { + $timeout.cancel(currentTimeout); + currentTimeout = null; + } + } + + function timerFn() { + if (isPlaying) { + $scope.next(); + restartTimer(); + } else { + $scope.pause(); + } + } + + $scope.play = function() { + if (!isPlaying) { + isPlaying = true; + restartTimer(); + } + }; + $scope.pause = function() { + if (!$scope.noPause) { + isPlaying = false; + resetTimer(); + } + }; + + self.addSlide = function(slide, element) { + slide.$element = element; + slides.push(slide); + //if this is the first slide or the slide is set to active, select it + if(slides.length === 1 || slide.active) { + self.select(slides[slides.length-1]); + if (slides.length == 1) { + $scope.play(); + } + } else { + slide.active = false; + } + }; + + self.removeSlide = function(slide) { + //get the index of the slide inside the carousel + var index = slides.indexOf(slide); + slides.splice(index, 1); + if (slides.length > 0 && slide.active) { + if (index >= slides.length) { + self.select(slides[index-1]); + } else { + self.select(slides[index]); + } + } else if (currentIndex > index) { + currentIndex--; + } + }; + +}]) + +/** + * @ngdoc directive + * @name ui.bootstrap.carousel.directive:carousel + * @restrict EA + * + * @description + * Carousel is the outer container for a set of image 'slides' to showcase. + * + * @param {number=} interval The time, in milliseconds, that it will take the carousel to go to the next slide. + * @param {boolean=} noTransition Whether to disable transitions on the carousel. + * @param {boolean=} noPause Whether to disable pausing on the carousel (by default, the carousel interval pauses on hover). + * + * @example + + + + + + + + + + + + + + + .carousel-indicators { + top: auto; + bottom: 15px; + } + + + */ +.directive('carousel', [function() { + return { + restrict: 'EA', + transclude: true, + replace: true, + controller: 'CarouselController', + require: 'carousel', + templateUrl: 'template/carousel/carousel.html', + scope: { + interval: '=', + noTransition: '=', + noPause: '=' + } + }; +}]) + +/** + * @ngdoc directive + * @name ui.bootstrap.carousel.directive:slide + * @restrict EA + * + * @description + * Creates a slide inside a {@link ui.bootstrap.carousel.directive:carousel carousel}. Must be placed as a child of a carousel element. + * + * @param {boolean=} active Model binding, whether or not this slide is currently active. + * + * @example + + +
      + + + + + + + Interval, in milliseconds: +
      Enter a negative number to stop the interval. +
      +
      + +function CarouselDemoCtrl($scope) { + $scope.myInterval = 5000; +} + + + .carousel-indicators { + top: auto; + bottom: 15px; + } + +
      +*/ + +.directive('slide', function() { + return { + require: '^carousel', + restrict: 'EA', + transclude: true, + replace: true, + templateUrl: 'template/carousel/slide.html', + scope: { + active: '=?' + }, + link: function (scope, element, attrs, carouselCtrl) { + carouselCtrl.addSlide(scope, element); + //when the scope is destroyed then remove the slide from the current slides array + scope.$on('$destroy', function() { + carouselCtrl.removeSlide(scope); + }); + + scope.$watch('active', function(active) { + if (active) { + carouselCtrl.select(scope); + } + }); + } + }; +}); + +angular.module('ui.bootstrap.dateparser', []) + +.service('dateParser', ['$locale', 'orderByFilter', function($locale, orderByFilter) { + + this.parsers = {}; + + var formatCodeToRegex = { + 'yyyy': { + regex: '\\d{4}', + apply: function(value) { this.year = +value; } + }, + 'yy': { + regex: '\\d{2}', + apply: function(value) { this.year = +value + 2000; } + }, + 'y': { + regex: '\\d{1,4}', + apply: function(value) { this.year = +value; } + }, + 'MMMM': { + regex: $locale.DATETIME_FORMATS.MONTH.join('|'), + apply: function(value) { this.month = $locale.DATETIME_FORMATS.MONTH.indexOf(value); } + }, + 'MMM': { + regex: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'), + apply: function(value) { this.month = $locale.DATETIME_FORMATS.SHORTMONTH.indexOf(value); } + }, + 'MM': { + regex: '0[1-9]|1[0-2]', + apply: function(value) { this.month = value - 1; } + }, + 'M': { + regex: '[1-9]|1[0-2]', + apply: function(value) { this.month = value - 1; } + }, + 'dd': { + regex: '[0-2][0-9]{1}|3[0-1]{1}', + apply: function(value) { this.date = +value; } + }, + 'd': { + regex: '[1-2]?[0-9]{1}|3[0-1]{1}', + apply: function(value) { this.date = +value; } + }, + 'EEEE': { + regex: $locale.DATETIME_FORMATS.DAY.join('|') + }, + 'EEE': { + regex: $locale.DATETIME_FORMATS.SHORTDAY.join('|') + } + }; + + this.createParser = function(format) { + var map = [], regex = format.split(''); + + angular.forEach(formatCodeToRegex, function(data, code) { + var index = format.indexOf(code); + + if (index > -1) { + format = format.split(''); + + regex[index] = '(' + data.regex + ')'; + format[index] = '$'; // Custom symbol to define consumed part of format + for (var i = index + 1, n = index + code.length; i < n; i++) { + regex[i] = ''; + format[i] = '$'; + } + format = format.join(''); + + map.push({ index: index, apply: data.apply }); + } + }); + + return { + regex: new RegExp('^' + regex.join('') + '$'), + map: orderByFilter(map, 'index') + }; + }; + + this.parse = function(input, format) { + if ( !angular.isString(input) ) { + return input; + } + + format = $locale.DATETIME_FORMATS[format] || format; + + if ( !this.parsers[format] ) { + this.parsers[format] = this.createParser(format); + } + + var parser = this.parsers[format], + regex = parser.regex, + map = parser.map, + results = input.match(regex); + + if ( results && results.length ) { + var fields = { year: 1900, month: 0, date: 1, hours: 0 }, dt; + + for( var i = 1, n = results.length; i < n; i++ ) { + var mapper = map[i-1]; + if ( mapper.apply ) { + mapper.apply.call(fields, results[i]); + } + } + + if ( isValid(fields.year, fields.month, fields.date) ) { + dt = new Date( fields.year, fields.month, fields.date, fields.hours); + } + + return dt; + } + }; + + // Check if date is valid for specific month (and year for February). + // Month: 0 = Jan, 1 = Feb, etc + function isValid(year, month, date) { + if ( month === 1 && date > 28) { + return date === 29 && ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0); + } + + if ( month === 3 || month === 5 || month === 8 || month === 10) { + return date < 31; + } + + return true; + } +}]); + +angular.module('ui.bootstrap.position', []) + +/** + * A set of utility methods that can be use to retrieve position of DOM elements. + * It is meant to be used where we need to absolute-position DOM elements in + * relation to other, existing elements (this is the case for tooltips, popovers, + * typeahead suggestions etc.). + */ + .factory('$position', ['$document', '$window', function ($document, $window) { + + function getStyle(el, cssprop) { + if (el.currentStyle) { //IE + return el.currentStyle[cssprop]; + } else if ($window.getComputedStyle) { + return $window.getComputedStyle(el)[cssprop]; + } + // finally try and get inline style + return el.style[cssprop]; + } + + /** + * Checks if a given element is statically positioned + * @param element - raw DOM element + */ + function isStaticPositioned(element) { + return (getStyle(element, 'position') || 'static' ) === 'static'; + } + + /** + * returns the closest, non-statically positioned parentOffset of a given element + * @param element + */ + var parentOffsetEl = function (element) { + var docDomEl = $document[0]; + var offsetParent = element.offsetParent || docDomEl; + while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent) ) { + offsetParent = offsetParent.offsetParent; + } + return offsetParent || docDomEl; + }; + + return { + /** + * Provides read-only equivalent of jQuery's position function: + * http://api.jquery.com/position/ + */ + position: function (element) { + var elBCR = this.offset(element); + var offsetParentBCR = { top: 0, left: 0 }; + var offsetParentEl = parentOffsetEl(element[0]); + if (offsetParentEl != $document[0]) { + offsetParentBCR = this.offset(angular.element(offsetParentEl)); + offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop; + offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft; + } + + var boundingClientRect = element[0].getBoundingClientRect(); + return { + width: boundingClientRect.width || element.prop('offsetWidth'), + height: boundingClientRect.height || element.prop('offsetHeight'), + top: elBCR.top - offsetParentBCR.top, + left: elBCR.left - offsetParentBCR.left + }; + }, + + /** + * Provides read-only equivalent of jQuery's offset function: + * http://api.jquery.com/offset/ + */ + offset: function (element) { + var boundingClientRect = element[0].getBoundingClientRect(); + return { + width: boundingClientRect.width || element.prop('offsetWidth'), + height: boundingClientRect.height || element.prop('offsetHeight'), + top: boundingClientRect.top + ($window.pageYOffset || $document[0].documentElement.scrollTop), + left: boundingClientRect.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft) + }; + }, + + /** + * Provides coordinates for the targetEl in relation to hostEl + */ + positionElements: function (hostEl, targetEl, positionStr, appendToBody) { + + var positionStrParts = positionStr.split('-'); + var pos0 = positionStrParts[0], pos1 = positionStrParts[1] || 'center'; + + var hostElPos, + targetElWidth, + targetElHeight, + targetElPos; + + hostElPos = appendToBody ? this.offset(hostEl) : this.position(hostEl); + + targetElWidth = targetEl.prop('offsetWidth'); + targetElHeight = targetEl.prop('offsetHeight'); + + var shiftWidth = { + center: function () { + return hostElPos.left + hostElPos.width / 2 - targetElWidth / 2; + }, + left: function () { + return hostElPos.left; + }, + right: function () { + return hostElPos.left + hostElPos.width; + } + }; + + var shiftHeight = { + center: function () { + return hostElPos.top + hostElPos.height / 2 - targetElHeight / 2; + }, + top: function () { + return hostElPos.top; + }, + bottom: function () { + return hostElPos.top + hostElPos.height; + } + }; + + switch (pos0) { + case 'right': + targetElPos = { + top: shiftHeight[pos1](), + left: shiftWidth[pos0]() + }; + break; + case 'left': + targetElPos = { + top: shiftHeight[pos1](), + left: hostElPos.left - targetElWidth + }; + break; + case 'bottom': + targetElPos = { + top: shiftHeight[pos0](), + left: shiftWidth[pos1]() + }; + break; + default: + targetElPos = { + top: hostElPos.top - targetElHeight, + left: shiftWidth[pos1]() + }; + break; + } + + return targetElPos; + } + }; + }]); + +angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootstrap.position']) + +.constant('datepickerConfig', { + formatDay: 'dd', + formatMonth: 'MMMM', + formatYear: 'yyyy', + formatDayHeader: 'EEE', + formatDayTitle: 'MMMM yyyy', + formatMonthTitle: 'yyyy', + datepickerMode: 'day', + minMode: 'day', + maxMode: 'year', + showWeeks: true, + startingDay: 0, + yearRange: 20, + minDate: null, + maxDate: null +}) + +.controller('DatepickerController', ['$scope', '$attrs', '$parse', '$interpolate', '$timeout', '$log', 'dateFilter', 'datepickerConfig', function($scope, $attrs, $parse, $interpolate, $timeout, $log, dateFilter, datepickerConfig) { + var self = this, + ngModelCtrl = { $setViewValue: angular.noop }; // nullModelCtrl; + + // Modes chain + this.modes = ['day', 'month', 'year']; + + // Configuration attributes + angular.forEach(['formatDay', 'formatMonth', 'formatYear', 'formatDayHeader', 'formatDayTitle', 'formatMonthTitle', + 'minMode', 'maxMode', 'showWeeks', 'startingDay', 'yearRange'], function( key, index ) { + self[key] = angular.isDefined($attrs[key]) ? (index < 8 ? $interpolate($attrs[key])($scope.$parent) : $scope.$parent.$eval($attrs[key])) : datepickerConfig[key]; + }); + + // Watchable attributes + angular.forEach(['minDate', 'maxDate'], function( key ) { + if ( $attrs[key] ) { + $scope.$parent.$watch($parse($attrs[key]), function(value) { + self[key] = value ? new Date(value) : null; + self.refreshView(); + }); + } else { + self[key] = datepickerConfig[key] ? new Date(datepickerConfig[key]) : null; + } + }); + + $scope.datepickerMode = $scope.datepickerMode || datepickerConfig.datepickerMode; + $scope.uniqueId = 'datepicker-' + $scope.$id + '-' + Math.floor(Math.random() * 10000); + this.activeDate = angular.isDefined($attrs.initDate) ? $scope.$parent.$eval($attrs.initDate) : new Date(); + + $scope.isActive = function(dateObject) { + if (self.compare(dateObject.date, self.activeDate) === 0) { + $scope.activeDateId = dateObject.uid; + return true; + } + return false; + }; + + this.init = function( ngModelCtrl_ ) { + ngModelCtrl = ngModelCtrl_; + + ngModelCtrl.$render = function() { + self.render(); + }; + }; + + this.render = function() { + if ( ngModelCtrl.$modelValue ) { + var date = new Date( ngModelCtrl.$modelValue ), + isValid = !isNaN(date); + + if ( isValid ) { + this.activeDate = date; + } else { + $log.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.'); + } + ngModelCtrl.$setValidity('date', isValid); + } + this.refreshView(); + }; + + this.refreshView = function() { + if ( this.element ) { + this._refreshView(); + + var date = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : null; + ngModelCtrl.$setValidity('date-disabled', !date || (this.element && !this.isDisabled(date))); + } + }; + + this.createDateObject = function(date, format) { + var model = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : null; + return { + date: date, + label: dateFilter(date, format), + selected: model && this.compare(date, model) === 0, + disabled: this.isDisabled(date), + current: this.compare(date, new Date()) === 0 + }; + }; + + this.isDisabled = function( date ) { + return ((this.minDate && this.compare(date, this.minDate) < 0) || (this.maxDate && this.compare(date, this.maxDate) > 0) || ($attrs.dateDisabled && $scope.dateDisabled({date: date, mode: $scope.datepickerMode}))); + }; + + // Split array into smaller arrays + this.split = function(arr, size) { + var arrays = []; + while (arr.length > 0) { + arrays.push(arr.splice(0, size)); + } + return arrays; + }; + + $scope.select = function( date ) { + if ( $scope.datepickerMode === self.minMode ) { + var dt = ngModelCtrl.$modelValue ? new Date( ngModelCtrl.$modelValue ) : new Date(0, 0, 0, 0, 0, 0, 0); + dt.setFullYear( date.getFullYear(), date.getMonth(), date.getDate() ); + ngModelCtrl.$setViewValue( dt ); + ngModelCtrl.$render(); + } else { + self.activeDate = date; + $scope.datepickerMode = self.modes[ self.modes.indexOf( $scope.datepickerMode ) - 1 ]; + } + }; + + $scope.move = function( direction ) { + var year = self.activeDate.getFullYear() + direction * (self.step.years || 0), + month = self.activeDate.getMonth() + direction * (self.step.months || 0); + self.activeDate.setFullYear(year, month, 1); + self.refreshView(); + }; + + $scope.toggleMode = function( direction ) { + direction = direction || 1; + + if (($scope.datepickerMode === self.maxMode && direction === 1) || ($scope.datepickerMode === self.minMode && direction === -1)) { + return; + } + + $scope.datepickerMode = self.modes[ self.modes.indexOf( $scope.datepickerMode ) + direction ]; + }; + + // Key event mapper + $scope.keys = { 13:'enter', 32:'space', 33:'pageup', 34:'pagedown', 35:'end', 36:'home', 37:'left', 38:'up', 39:'right', 40:'down' }; + + var focusElement = function() { + $timeout(function() { + self.element[0].focus(); + }, 0 , false); + }; + + // Listen for focus requests from popup directive + $scope.$on('datepicker.focus', focusElement); + + $scope.keydown = function( evt ) { + var key = $scope.keys[evt.which]; + + if ( !key || evt.shiftKey || evt.altKey ) { + return; + } + + evt.preventDefault(); + evt.stopPropagation(); + + if (key === 'enter' || key === 'space') { + if ( self.isDisabled(self.activeDate)) { + return; // do nothing + } + $scope.select(self.activeDate); + focusElement(); + } else if (evt.ctrlKey && (key === 'up' || key === 'down')) { + $scope.toggleMode(key === 'up' ? 1 : -1); + focusElement(); + } else { + self.handleKeyDown(key, evt); + self.refreshView(); + } + }; +}]) + +.directive( 'datepicker', function () { + return { + restrict: 'EA', + replace: true, + templateUrl: 'template/datepicker/datepicker.html', + scope: { + datepickerMode: '=?', + dateDisabled: '&' + }, + require: ['datepicker', '?^ngModel'], + controller: 'DatepickerController', + link: function(scope, element, attrs, ctrls) { + var datepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1]; + + if ( ngModelCtrl ) { + datepickerCtrl.init( ngModelCtrl ); + } + } + }; +}) + +.directive('daypicker', ['dateFilter', function (dateFilter) { + return { + restrict: 'EA', + replace: true, + templateUrl: 'template/datepicker/day.html', + require: '^datepicker', + link: function(scope, element, attrs, ctrl) { + scope.showWeeks = ctrl.showWeeks; + + ctrl.step = { months: 1 }; + ctrl.element = element; + + var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + function getDaysInMonth( year, month ) { + return ((month === 1) && (year % 4 === 0) && ((year % 100 !== 0) || (year % 400 === 0))) ? 29 : DAYS_IN_MONTH[month]; + } + + function getDates(startDate, n) { + var dates = new Array(n), current = new Date(startDate), i = 0; + current.setHours(12); // Prevent repeated dates because of timezone bug + while ( i < n ) { + dates[i++] = new Date(current); + current.setDate( current.getDate() + 1 ); + } + return dates; + } + + ctrl._refreshView = function() { + var year = ctrl.activeDate.getFullYear(), + month = ctrl.activeDate.getMonth(), + firstDayOfMonth = new Date(year, month, 1), + difference = ctrl.startingDay - firstDayOfMonth.getDay(), + numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : - difference, + firstDate = new Date(firstDayOfMonth); + + if ( numDisplayedFromPreviousMonth > 0 ) { + firstDate.setDate( - numDisplayedFromPreviousMonth + 1 ); + } + + // 42 is the number of days on a six-month calendar + var days = getDates(firstDate, 42); + for (var i = 0; i < 42; i ++) { + days[i] = angular.extend(ctrl.createDateObject(days[i], ctrl.formatDay), { + secondary: days[i].getMonth() !== month, + uid: scope.uniqueId + '-' + i + }); + } + + scope.labels = new Array(7); + for (var j = 0; j < 7; j++) { + scope.labels[j] = { + abbr: dateFilter(days[j].date, ctrl.formatDayHeader), + full: dateFilter(days[j].date, 'EEEE') + }; + } + + scope.title = dateFilter(ctrl.activeDate, ctrl.formatDayTitle); + scope.rows = ctrl.split(days, 7); + + if ( scope.showWeeks ) { + scope.weekNumbers = []; + var weekNumber = getISO8601WeekNumber( scope.rows[0][0].date ), + numWeeks = scope.rows.length; + while( scope.weekNumbers.push(weekNumber++) < numWeeks ) {} + } + }; + + ctrl.compare = function(date1, date2) { + return (new Date( date1.getFullYear(), date1.getMonth(), date1.getDate() ) - new Date( date2.getFullYear(), date2.getMonth(), date2.getDate() ) ); + }; + + function getISO8601WeekNumber(date) { + var checkDate = new Date(date); + checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); // Thursday + var time = checkDate.getTime(); + checkDate.setMonth(0); // Compare with Jan 1 + checkDate.setDate(1); + return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; + } + + ctrl.handleKeyDown = function( key, evt ) { + var date = ctrl.activeDate.getDate(); + + if (key === 'left') { + date = date - 1; // up + } else if (key === 'up') { + date = date - 7; // down + } else if (key === 'right') { + date = date + 1; // down + } else if (key === 'down') { + date = date + 7; + } else if (key === 'pageup' || key === 'pagedown') { + var month = ctrl.activeDate.getMonth() + (key === 'pageup' ? - 1 : 1); + ctrl.activeDate.setMonth(month, 1); + date = Math.min(getDaysInMonth(ctrl.activeDate.getFullYear(), ctrl.activeDate.getMonth()), date); + } else if (key === 'home') { + date = 1; + } else if (key === 'end') { + date = getDaysInMonth(ctrl.activeDate.getFullYear(), ctrl.activeDate.getMonth()); + } + ctrl.activeDate.setDate(date); + }; + + ctrl.refreshView(); + } + }; +}]) + +.directive('monthpicker', ['dateFilter', function (dateFilter) { + return { + restrict: 'EA', + replace: true, + templateUrl: 'template/datepicker/month.html', + require: '^datepicker', + link: function(scope, element, attrs, ctrl) { + ctrl.step = { years: 1 }; + ctrl.element = element; + + ctrl._refreshView = function() { + var months = new Array(12), + year = ctrl.activeDate.getFullYear(); + + for ( var i = 0; i < 12; i++ ) { + months[i] = angular.extend(ctrl.createDateObject(new Date(year, i, 1), ctrl.formatMonth), { + uid: scope.uniqueId + '-' + i + }); + } + + scope.title = dateFilter(ctrl.activeDate, ctrl.formatMonthTitle); + scope.rows = ctrl.split(months, 3); + }; + + ctrl.compare = function(date1, date2) { + return new Date( date1.getFullYear(), date1.getMonth() ) - new Date( date2.getFullYear(), date2.getMonth() ); + }; + + ctrl.handleKeyDown = function( key, evt ) { + var date = ctrl.activeDate.getMonth(); + + if (key === 'left') { + date = date - 1; // up + } else if (key === 'up') { + date = date - 3; // down + } else if (key === 'right') { + date = date + 1; // down + } else if (key === 'down') { + date = date + 3; + } else if (key === 'pageup' || key === 'pagedown') { + var year = ctrl.activeDate.getFullYear() + (key === 'pageup' ? - 1 : 1); + ctrl.activeDate.setFullYear(year); + } else if (key === 'home') { + date = 0; + } else if (key === 'end') { + date = 11; + } + ctrl.activeDate.setMonth(date); + }; + + ctrl.refreshView(); + } + }; +}]) + +.directive('yearpicker', ['dateFilter', function (dateFilter) { + return { + restrict: 'EA', + replace: true, + templateUrl: 'template/datepicker/year.html', + require: '^datepicker', + link: function(scope, element, attrs, ctrl) { + var range = ctrl.yearRange; + + ctrl.step = { years: range }; + ctrl.element = element; + + function getStartingYear( year ) { + return parseInt((year - 1) / range, 10) * range + 1; + } + + ctrl._refreshView = function() { + var years = new Array(range); + + for ( var i = 0, start = getStartingYear(ctrl.activeDate.getFullYear()); i < range; i++ ) { + years[i] = angular.extend(ctrl.createDateObject(new Date(start + i, 0, 1), ctrl.formatYear), { + uid: scope.uniqueId + '-' + i + }); + } + + scope.title = [years[0].label, years[range - 1].label].join(' - '); + scope.rows = ctrl.split(years, 5); + }; + + ctrl.compare = function(date1, date2) { + return date1.getFullYear() - date2.getFullYear(); + }; + + ctrl.handleKeyDown = function( key, evt ) { + var date = ctrl.activeDate.getFullYear(); + + if (key === 'left') { + date = date - 1; // up + } else if (key === 'up') { + date = date - 5; // down + } else if (key === 'right') { + date = date + 1; // down + } else if (key === 'down') { + date = date + 5; + } else if (key === 'pageup' || key === 'pagedown') { + date += (key === 'pageup' ? - 1 : 1) * ctrl.step.years; + } else if (key === 'home') { + date = getStartingYear( ctrl.activeDate.getFullYear() ); + } else if (key === 'end') { + date = getStartingYear( ctrl.activeDate.getFullYear() ) + range - 1; + } + ctrl.activeDate.setFullYear(date); + }; + + ctrl.refreshView(); + } + }; +}]) + +.constant('datepickerPopupConfig', { + datepickerPopup: 'yyyy-MM-dd', + currentText: 'Today', + clearText: 'Clear', + closeText: 'Done', + closeOnDateSelection: true, + appendToBody: false, + showButtonBar: true +}) + +.directive('datepickerPopup', ['$compile', '$parse', '$document', '$position', 'dateFilter', 'dateParser', 'datepickerPopupConfig', +function ($compile, $parse, $document, $position, dateFilter, dateParser, datepickerPopupConfig) { + return { + restrict: 'EA', + require: 'ngModel', + scope: { + isOpen: '=?', + currentText: '@', + clearText: '@', + closeText: '@', + dateDisabled: '&' + }, + link: function(scope, element, attrs, ngModel) { + var dateFormat, + closeOnDateSelection = angular.isDefined(attrs.closeOnDateSelection) ? scope.$parent.$eval(attrs.closeOnDateSelection) : datepickerPopupConfig.closeOnDateSelection, + appendToBody = angular.isDefined(attrs.datepickerAppendToBody) ? scope.$parent.$eval(attrs.datepickerAppendToBody) : datepickerPopupConfig.appendToBody; + + scope.showButtonBar = angular.isDefined(attrs.showButtonBar) ? scope.$parent.$eval(attrs.showButtonBar) : datepickerPopupConfig.showButtonBar; + + scope.getText = function( key ) { + return scope[key + 'Text'] || datepickerPopupConfig[key + 'Text']; + }; + + attrs.$observe('datepickerPopup', function(value) { + dateFormat = value || datepickerPopupConfig.datepickerPopup; + ngModel.$render(); + }); + + // popup element used to display calendar + var popupEl = angular.element('
      '); + popupEl.attr({ + 'ng-model': 'date', + 'ng-change': 'dateSelection()' + }); + + function cameltoDash( string ){ + return string.replace(/([A-Z])/g, function($1) { return '-' + $1.toLowerCase(); }); + } + + // datepicker element + var datepickerEl = angular.element(popupEl.children()[0]); + if ( attrs.datepickerOptions ) { + angular.forEach(scope.$parent.$eval(attrs.datepickerOptions), function( value, option ) { + datepickerEl.attr( cameltoDash(option), value ); + }); + } + + angular.forEach(['minDate', 'maxDate'], function( key ) { + if ( attrs[key] ) { + scope.$parent.$watch($parse(attrs[key]), function(value){ + scope[key] = value; + }); + datepickerEl.attr(cameltoDash(key), key); + } + }); + if (attrs.dateDisabled) { + datepickerEl.attr('date-disabled', 'dateDisabled({ date: date, mode: mode })'); + } + + function parseDate(viewValue) { + if (!viewValue) { + ngModel.$setValidity('date', true); + return null; + } else if (angular.isDate(viewValue) && !isNaN(viewValue)) { + ngModel.$setValidity('date', true); + return viewValue; + } else if (angular.isString(viewValue)) { + var date = dateParser.parse(viewValue, dateFormat) || new Date(viewValue); + if (isNaN(date)) { + ngModel.$setValidity('date', false); + return undefined; + } else { + ngModel.$setValidity('date', true); + return date; + } + } else { + ngModel.$setValidity('date', false); + return undefined; + } + } + ngModel.$parsers.unshift(parseDate); + + // Inner change + scope.dateSelection = function(dt) { + if (angular.isDefined(dt)) { + scope.date = dt; + } + ngModel.$setViewValue(scope.date); + ngModel.$render(); + + if ( closeOnDateSelection ) { + scope.isOpen = false; + element[0].focus(); + } + }; + + element.bind('input change keyup', function() { + scope.$apply(function() { + scope.date = ngModel.$modelValue; + }); + }); + + // Outter change + ngModel.$render = function() { + var date = ngModel.$viewValue ? dateFilter(ngModel.$viewValue, dateFormat) : ''; + element.val(date); + scope.date = parseDate( ngModel.$modelValue ); + }; + + var documentClickBind = function(event) { + if (scope.isOpen && event.target !== element[0]) { + scope.$apply(function() { + scope.isOpen = false; + }); + } + }; + + var keydown = function(evt, noApply) { + scope.keydown(evt); + }; + element.bind('keydown', keydown); + + scope.keydown = function(evt) { + if (evt.which === 27) { + evt.preventDefault(); + evt.stopPropagation(); + scope.close(); + } else if (evt.which === 40 && !scope.isOpen) { + scope.isOpen = true; + } + }; + + scope.$watch('isOpen', function(value) { + if (value) { + scope.$broadcast('datepicker.focus'); + scope.position = appendToBody ? $position.offset(element) : $position.position(element); + scope.position.top = scope.position.top + element.prop('offsetHeight'); + + $document.bind('click', documentClickBind); + } else { + $document.unbind('click', documentClickBind); + } + }); + + scope.select = function( date ) { + if (date === 'today') { + var today = new Date(); + if (angular.isDate(ngModel.$modelValue)) { + date = new Date(ngModel.$modelValue); + date.setFullYear(today.getFullYear(), today.getMonth(), today.getDate()); + } else { + date = new Date(today.setHours(0, 0, 0, 0)); + } + } + scope.dateSelection( date ); + }; + + scope.close = function() { + scope.isOpen = false; + element[0].focus(); + }; + + var $popup = $compile(popupEl)(scope); + if ( appendToBody ) { + $document.find('body').append($popup); + } else { + element.after($popup); + } + + scope.$on('$destroy', function() { + $popup.remove(); + element.unbind('keydown', keydown); + $document.unbind('click', documentClickBind); + }); + } + }; +}]) + +.directive('datepickerPopupWrap', function() { + return { + restrict:'EA', + replace: true, + transclude: true, + templateUrl: 'template/datepicker/popup.html', + link:function (scope, element, attrs) { + element.bind('click', function(event) { + event.preventDefault(); + event.stopPropagation(); + }); + } + }; +}); + +angular.module('ui.bootstrap.dropdown', []) + +.constant('dropdownConfig', { + openClass: 'open' +}) + +.service('dropdownService', ['$document', function($document) { + var openScope = null; + + this.open = function( dropdownScope ) { + if ( !openScope ) { + $document.bind('click', closeDropdown); + $document.bind('keydown', escapeKeyBind); + } + + if ( openScope && openScope !== dropdownScope ) { + openScope.isOpen = false; + } + + openScope = dropdownScope; + }; + + this.close = function( dropdownScope ) { + if ( openScope === dropdownScope ) { + openScope = null; + $document.unbind('click', closeDropdown); + $document.unbind('keydown', escapeKeyBind); + } + }; + + var closeDropdown = function( evt ) { + if (evt && evt.isDefaultPrevented()) { + return; + } + + openScope.$apply(function() { + openScope.isOpen = false; + }); + }; + + var escapeKeyBind = function( evt ) { + if ( evt.which === 27 ) { + openScope.focusToggleElement(); + closeDropdown(); + } + }; +}]) + +.controller('DropdownController', ['$scope', '$attrs', '$parse', 'dropdownConfig', 'dropdownService', '$animate', function($scope, $attrs, $parse, dropdownConfig, dropdownService, $animate) { + var self = this, + scope = $scope.$new(), // create a child scope so we are not polluting original one + openClass = dropdownConfig.openClass, + getIsOpen, + setIsOpen = angular.noop, + toggleInvoker = $attrs.onToggle ? $parse($attrs.onToggle) : angular.noop; + + this.init = function( element ) { + self.$element = element; + + if ( $attrs.isOpen ) { + getIsOpen = $parse($attrs.isOpen); + setIsOpen = getIsOpen.assign; + + $scope.$watch(getIsOpen, function(value) { + scope.isOpen = !!value; + }); + } + }; + + this.toggle = function( open ) { + return scope.isOpen = arguments.length ? !!open : !scope.isOpen; + }; + + // Allow other directives to watch status + this.isOpen = function() { + return scope.isOpen; + }; + + scope.focusToggleElement = function() { + if ( self.toggleElement ) { + self.toggleElement[0].focus(); + } + }; + + scope.$watch('isOpen', function( isOpen, wasOpen ) { + $animate[isOpen ? 'addClass' : 'removeClass'](self.$element, openClass); + + if ( isOpen ) { + scope.focusToggleElement(); + dropdownService.open( scope ); + } else { + dropdownService.close( scope ); + } + + setIsOpen($scope, isOpen); + if (angular.isDefined(isOpen) && isOpen !== wasOpen) { + toggleInvoker($scope, { open: !!isOpen }); + } + }); + + $scope.$on('$locationChangeSuccess', function() { + scope.isOpen = false; + }); + + $scope.$on('$destroy', function() { + scope.$destroy(); + }); +}]) + +.directive('dropdown', function() { + return { + restrict: 'CA', + controller: 'DropdownController', + link: function(scope, element, attrs, dropdownCtrl) { + dropdownCtrl.init( element ); + } + }; +}) + +.directive('dropdownToggle', function() { + return { + restrict: 'CA', + require: '?^dropdown', + link: function(scope, element, attrs, dropdownCtrl) { + if ( !dropdownCtrl ) { + return; + } + + dropdownCtrl.toggleElement = element; + + var toggleDropdown = function(event) { + event.preventDefault(); + + if ( !element.hasClass('disabled') && !attrs.disabled ) { + scope.$apply(function() { + dropdownCtrl.toggle(); + }); + } + }; + + element.bind('click', toggleDropdown); + + // WAI-ARIA + element.attr({ 'aria-haspopup': true, 'aria-expanded': false }); + scope.$watch(dropdownCtrl.isOpen, function( isOpen ) { + element.attr('aria-expanded', !!isOpen); + }); + + scope.$on('$destroy', function() { + element.unbind('click', toggleDropdown); + }); + } + }; +}); + +angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition']) + +/** + * A helper, internal data structure that acts as a map but also allows getting / removing + * elements in the LIFO order + */ + .factory('$$stackedMap', function () { + return { + createNew: function () { + var stack = []; + + return { + add: function (key, value) { + stack.push({ + key: key, + value: value + }); + }, + get: function (key) { + for (var i = 0; i < stack.length; i++) { + if (key == stack[i].key) { + return stack[i]; + } + } + }, + keys: function() { + var keys = []; + for (var i = 0; i < stack.length; i++) { + keys.push(stack[i].key); + } + return keys; + }, + top: function () { + return stack[stack.length - 1]; + }, + remove: function (key) { + var idx = -1; + for (var i = 0; i < stack.length; i++) { + if (key == stack[i].key) { + idx = i; + break; + } + } + return stack.splice(idx, 1)[0]; + }, + removeTop: function () { + return stack.splice(stack.length - 1, 1)[0]; + }, + length: function () { + return stack.length; + } + }; + } + }; + }) + +/** + * A helper directive for the $modal service. It creates a backdrop element. + */ + .directive('modalBackdrop', ['$timeout', function ($timeout) { + return { + restrict: 'EA', + replace: true, + templateUrl: 'template/modal/backdrop.html', + link: function (scope) { + + scope.animate = false; + + //trigger CSS transitions + $timeout(function () { + scope.animate = true; + }); + } + }; + }]) + + .directive('modalWindow', ['$modalStack', '$timeout', function ($modalStack, $timeout) { + return { + restrict: 'EA', + scope: { + index: '@', + animate: '=' + }, + replace: true, + transclude: true, + templateUrl: function(tElement, tAttrs) { + return tAttrs.templateUrl || 'template/modal/window.html'; + }, + link: function (scope, element, attrs) { + element.addClass(attrs.windowClass || ''); + scope.size = attrs.size; + + $timeout(function () { + // trigger CSS transitions + scope.animate = true; + // focus a freshly-opened modal + element[0].focus(); + }); + + scope.close = function (evt) { + var modal = $modalStack.getTop(); + if (modal && modal.value.backdrop && modal.value.backdrop != 'static' && (evt.target === evt.currentTarget)) { + evt.preventDefault(); + evt.stopPropagation(); + $modalStack.dismiss(modal.key, 'backdrop click'); + } + }; + } + }; + }]) + + .factory('$modalStack', ['$transition', '$timeout', '$document', '$compile', '$rootScope', '$$stackedMap', + function ($transition, $timeout, $document, $compile, $rootScope, $$stackedMap) { + + var OPENED_MODAL_CLASS = 'modal-open'; + + var backdropDomEl, backdropScope; + var openedWindows = $$stackedMap.createNew(); + var $modalStack = {}; + + function backdropIndex() { + var topBackdropIndex = -1; + var opened = openedWindows.keys(); + for (var i = 0; i < opened.length; i++) { + if (openedWindows.get(opened[i]).value.backdrop) { + topBackdropIndex = i; + } + } + return topBackdropIndex; + } + + $rootScope.$watch(backdropIndex, function(newBackdropIndex){ + if (backdropScope) { + backdropScope.index = newBackdropIndex; + } + }); + + function removeModalWindow(modalInstance) { + + var body = $document.find('body').eq(0); + var modalWindow = openedWindows.get(modalInstance).value; + + //clean up the stack + openedWindows.remove(modalInstance); + + //remove window DOM element + removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, 300, function() { + modalWindow.modalScope.$destroy(); + body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0); + checkRemoveBackdrop(); + }); + } + + function checkRemoveBackdrop() { + //remove backdrop if no longer needed + if (backdropDomEl && backdropIndex() == -1) { + var backdropScopeRef = backdropScope; + removeAfterAnimate(backdropDomEl, backdropScope, 150, function () { + backdropScopeRef.$destroy(); + backdropScopeRef = null; + }); + backdropDomEl = undefined; + backdropScope = undefined; + } + } + + function removeAfterAnimate(domEl, scope, emulateTime, done) { + // Closing animation + scope.animate = false; + + var transitionEndEventName = $transition.transitionEndEventName; + if (transitionEndEventName) { + // transition out + var timeout = $timeout(afterAnimating, emulateTime); + + domEl.bind(transitionEndEventName, function () { + $timeout.cancel(timeout); + afterAnimating(); + scope.$apply(); + }); + } else { + // Ensure this call is async + $timeout(afterAnimating, 0); + } + + function afterAnimating() { + if (afterAnimating.done) { + return; + } + afterAnimating.done = true; + + domEl.remove(); + if (done) { + done(); + } + } + } + + $document.bind('keydown', function (evt) { + var modal; + + if (evt.which === 27) { + modal = openedWindows.top(); + if (modal && modal.value.keyboard) { + evt.preventDefault(); + $rootScope.$apply(function () { + $modalStack.dismiss(modal.key, 'escape key press'); + }); + } + } + }); + + $modalStack.open = function (modalInstance, modal) { + + openedWindows.add(modalInstance, { + deferred: modal.deferred, + modalScope: modal.scope, + backdrop: modal.backdrop, + keyboard: modal.keyboard + }); + + var body = $document.find('body').eq(0), + currBackdropIndex = backdropIndex(); + + if (currBackdropIndex >= 0 && !backdropDomEl) { + backdropScope = $rootScope.$new(true); + backdropScope.index = currBackdropIndex; + backdropDomEl = $compile('
      ')(backdropScope); + body.append(backdropDomEl); + } + + var angularDomEl = angular.element('
      '); + angularDomEl.attr({ + 'template-url': modal.windowTemplateUrl, + 'window-class': modal.windowClass, + 'size': modal.size, + 'index': openedWindows.length() - 1, + 'animate': 'animate' + }).html(modal.content); + + var modalDomEl = $compile(angularDomEl)(modal.scope); + openedWindows.top().value.modalDomEl = modalDomEl; + body.append(modalDomEl); + body.addClass(OPENED_MODAL_CLASS); + }; + + $modalStack.close = function (modalInstance, result) { + var modalWindow = openedWindows.get(modalInstance).value; + if (modalWindow) { + modalWindow.deferred.resolve(result); + removeModalWindow(modalInstance); + } + }; + + $modalStack.dismiss = function (modalInstance, reason) { + var modalWindow = openedWindows.get(modalInstance).value; + if (modalWindow) { + modalWindow.deferred.reject(reason); + removeModalWindow(modalInstance); + } + }; + + $modalStack.dismissAll = function (reason) { + var topModal = this.getTop(); + while (topModal) { + this.dismiss(topModal.key, reason); + topModal = this.getTop(); + } + }; + + $modalStack.getTop = function () { + return openedWindows.top(); + }; + + return $modalStack; + }]) + + .provider('$modal', function () { + + var $modalProvider = { + options: { + backdrop: true, //can be also false or 'static' + keyboard: true + }, + $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack', + function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) { + + var $modal = {}; + + function getTemplatePromise(options) { + return options.template ? $q.when(options.template) : + $http.get(options.templateUrl, {cache: $templateCache}).then(function (result) { + return result.data; + }); + } + + function getResolvePromises(resolves) { + var promisesArr = []; + angular.forEach(resolves, function (value, key) { + if (angular.isFunction(value) || angular.isArray(value)) { + promisesArr.push($q.when($injector.invoke(value))); + } + }); + return promisesArr; + } + + $modal.open = function (modalOptions) { + + var modalResultDeferred = $q.defer(); + var modalOpenedDeferred = $q.defer(); + + //prepare an instance of a modal to be injected into controllers and returned to a caller + var modalInstance = { + result: modalResultDeferred.promise, + opened: modalOpenedDeferred.promise, + close: function (result) { + $modalStack.close(modalInstance, result); + }, + dismiss: function (reason) { + $modalStack.dismiss(modalInstance, reason); + } + }; + + //merge and clean up options + modalOptions = angular.extend({}, $modalProvider.options, modalOptions); + modalOptions.resolve = modalOptions.resolve || {}; + + //verify options + if (!modalOptions.template && !modalOptions.templateUrl) { + throw new Error('One of template or templateUrl options is required.'); + } + + var templateAndResolvePromise = + $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve))); + + + templateAndResolvePromise.then(function resolveSuccess(tplAndVars) { + + var modalScope = (modalOptions.scope || $rootScope).$new(); + modalScope.$close = modalInstance.close; + modalScope.$dismiss = modalInstance.dismiss; + + var ctrlInstance, ctrlLocals = {}; + var resolveIter = 1; + + //controllers + if (modalOptions.controller) { + ctrlLocals.$scope = modalScope; + ctrlLocals.$modalInstance = modalInstance; + angular.forEach(modalOptions.resolve, function (value, key) { + ctrlLocals[key] = tplAndVars[resolveIter++]; + }); + + ctrlInstance = $controller(modalOptions.controller, ctrlLocals); + } + + $modalStack.open(modalInstance, { + scope: modalScope, + deferred: modalResultDeferred, + content: tplAndVars[0], + backdrop: modalOptions.backdrop, + keyboard: modalOptions.keyboard, + windowClass: modalOptions.windowClass, + windowTemplateUrl: modalOptions.windowTemplateUrl, + size: modalOptions.size + }); + + }, function resolveError(reason) { + modalResultDeferred.reject(reason); + }); + + templateAndResolvePromise.then(function () { + modalOpenedDeferred.resolve(true); + }, function () { + modalOpenedDeferred.reject(false); + }); + + return modalInstance; + }; + + return $modal; + }] + }; + + return $modalProvider; + }); + +angular.module('ui.bootstrap.pagination', []) + +.controller('PaginationController', ['$scope', '$attrs', '$parse', function ($scope, $attrs, $parse) { + var self = this, + ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl + setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop; + + this.init = function(ngModelCtrl_, config) { + ngModelCtrl = ngModelCtrl_; + this.config = config; + + ngModelCtrl.$render = function() { + self.render(); + }; + + if ($attrs.itemsPerPage) { + $scope.$parent.$watch($parse($attrs.itemsPerPage), function(value) { + self.itemsPerPage = parseInt(value, 10); + $scope.totalPages = self.calculateTotalPages(); + }); + } else { + this.itemsPerPage = config.itemsPerPage; + } + }; + + this.calculateTotalPages = function() { + var totalPages = this.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / this.itemsPerPage); + return Math.max(totalPages || 0, 1); + }; + + this.render = function() { + $scope.page = parseInt(ngModelCtrl.$viewValue, 10) || 1; + }; + + $scope.selectPage = function(page) { + if ( $scope.page !== page && page > 0 && page <= $scope.totalPages) { + ngModelCtrl.$setViewValue(page); + ngModelCtrl.$render(); + } + }; + + $scope.getText = function( key ) { + return $scope[key + 'Text'] || self.config[key + 'Text']; + }; + $scope.noPrevious = function() { + return $scope.page === 1; + }; + $scope.noNext = function() { + return $scope.page === $scope.totalPages; + }; + + $scope.$watch('totalItems', function() { + $scope.totalPages = self.calculateTotalPages(); + }); + + $scope.$watch('totalPages', function(value) { + setNumPages($scope.$parent, value); // Readonly variable + + if ( $scope.page > value ) { + $scope.selectPage(value); + } else { + ngModelCtrl.$render(); + } + }); +}]) + +.constant('paginationConfig', { + itemsPerPage: 10, + boundaryLinks: false, + directionLinks: true, + firstText: 'First', + previousText: 'Previous', + nextText: 'Next', + lastText: 'Last', + rotate: true +}) + +.directive('pagination', ['$parse', 'paginationConfig', function($parse, paginationConfig) { + return { + restrict: 'EA', + scope: { + totalItems: '=', + firstText: '@', + previousText: '@', + nextText: '@', + lastText: '@' + }, + require: ['pagination', '?ngModel'], + controller: 'PaginationController', + templateUrl: 'template/pagination/pagination.html', + replace: true, + link: function(scope, element, attrs, ctrls) { + var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1]; + + if (!ngModelCtrl) { + return; // do nothing if no ng-model + } + + // Setup configuration parameters + var maxSize = angular.isDefined(attrs.maxSize) ? scope.$parent.$eval(attrs.maxSize) : paginationConfig.maxSize, + rotate = angular.isDefined(attrs.rotate) ? scope.$parent.$eval(attrs.rotate) : paginationConfig.rotate; + scope.boundaryLinks = angular.isDefined(attrs.boundaryLinks) ? scope.$parent.$eval(attrs.boundaryLinks) : paginationConfig.boundaryLinks; + scope.directionLinks = angular.isDefined(attrs.directionLinks) ? scope.$parent.$eval(attrs.directionLinks) : paginationConfig.directionLinks; + + paginationCtrl.init(ngModelCtrl, paginationConfig); + + if (attrs.maxSize) { + scope.$parent.$watch($parse(attrs.maxSize), function(value) { + maxSize = parseInt(value, 10); + paginationCtrl.render(); + }); + } + + // Create page object used in template + function makePage(number, text, isActive) { + return { + number: number, + text: text, + active: isActive + }; + } + + function getPages(currentPage, totalPages) { + var pages = []; + + // Default page limits + var startPage = 1, endPage = totalPages; + var isMaxSized = ( angular.isDefined(maxSize) && maxSize < totalPages ); + + // recompute if maxSize + if ( isMaxSized ) { + if ( rotate ) { + // Current page is displayed in the middle of the visible ones + startPage = Math.max(currentPage - Math.floor(maxSize/2), 1); + endPage = startPage + maxSize - 1; + + // Adjust if limit is exceeded + if (endPage > totalPages) { + endPage = totalPages; + startPage = endPage - maxSize + 1; + } + } else { + // Visible pages are paginated with maxSize + startPage = ((Math.ceil(currentPage / maxSize) - 1) * maxSize) + 1; + + // Adjust last page if limit is exceeded + endPage = Math.min(startPage + maxSize - 1, totalPages); + } + } + + // Add page number links + for (var number = startPage; number <= endPage; number++) { + var page = makePage(number, number, number === currentPage); + pages.push(page); + } + + // Add links to move between page sets + if ( isMaxSized && ! rotate ) { + if ( startPage > 1 ) { + var previousPageSet = makePage(startPage - 1, '...', false); + pages.unshift(previousPageSet); + } + + if ( endPage < totalPages ) { + var nextPageSet = makePage(endPage + 1, '...', false); + pages.push(nextPageSet); + } + } + + return pages; + } + + var originalRender = paginationCtrl.render; + paginationCtrl.render = function() { + originalRender(); + if (scope.page > 0 && scope.page <= scope.totalPages) { + scope.pages = getPages(scope.page, scope.totalPages); + } + }; + } + }; +}]) + +.constant('pagerConfig', { + itemsPerPage: 10, + previousText: '« Previous', + nextText: 'Next »', + align: true +}) + +.directive('pager', ['pagerConfig', function(pagerConfig) { + return { + restrict: 'EA', + scope: { + totalItems: '=', + previousText: '@', + nextText: '@' + }, + require: ['pager', '?ngModel'], + controller: 'PaginationController', + templateUrl: 'template/pagination/pager.html', + replace: true, + link: function(scope, element, attrs, ctrls) { + var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1]; + + if (!ngModelCtrl) { + return; // do nothing if no ng-model + } + + scope.align = angular.isDefined(attrs.align) ? scope.$parent.$eval(attrs.align) : pagerConfig.align; + paginationCtrl.init(ngModelCtrl, pagerConfig); + } + }; +}]); + +/** + * The following features are still outstanding: animation as a + * function, placement as a function, inside, support for more triggers than + * just mouse enter/leave, html tooltips, and selector delegation. + */ +angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap.bindHtml' ] ) + +/** + * The $tooltip service creates tooltip- and popover-like directives as well as + * houses global options for them. + */ +.provider( '$tooltip', function () { + // The default options tooltip and popover. + var defaultOptions = { + placement: 'top', + animation: true, + popupDelay: 0 + }; + + // Default hide triggers for each show trigger + var triggerMap = { + 'mouseenter': 'mouseleave', + 'click': 'click', + 'focus': 'blur' + }; + + // The options specified to the provider globally. + var globalOptions = {}; + + /** + * `options({})` allows global configuration of all tooltips in the + * application. + * + * var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) { + * // place tooltips left instead of top by default + * $tooltipProvider.options( { placement: 'left' } ); + * }); + */ + this.options = function( value ) { + angular.extend( globalOptions, value ); + }; + + /** + * This allows you to extend the set of trigger mappings available. E.g.: + * + * $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' ); + */ + this.setTriggers = function setTriggers ( triggers ) { + angular.extend( triggerMap, triggers ); + }; + + /** + * This is a helper function for translating camel-case to snake-case. + */ + function snake_case(name){ + var regexp = /[A-Z]/g; + var separator = '-'; + return name.replace(regexp, function(letter, pos) { + return (pos ? separator : '') + letter.toLowerCase(); + }); + } + + /** + * Returns the actual instance of the $tooltip service. + * TODO support multiple triggers + */ + this.$get = [ '$window', '$compile', '$timeout', '$parse', '$document', '$position', '$interpolate', function ( $window, $compile, $timeout, $parse, $document, $position, $interpolate ) { + return function $tooltip ( type, prefix, defaultTriggerShow ) { + var options = angular.extend( {}, defaultOptions, globalOptions ); + + /** + * Returns an object of show and hide triggers. + * + * If a trigger is supplied, + * it is used to show the tooltip; otherwise, it will use the `trigger` + * option passed to the `$tooltipProvider.options` method; else it will + * default to the trigger supplied to this directive factory. + * + * The hide trigger is based on the show trigger. If the `trigger` option + * was passed to the `$tooltipProvider.options` method, it will use the + * mapped trigger from `triggerMap` or the passed trigger if the map is + * undefined; otherwise, it uses the `triggerMap` value of the show + * trigger; else it will just use the show trigger. + */ + function getTriggers ( trigger ) { + var show = trigger || options.trigger || defaultTriggerShow; + var hide = triggerMap[show] || show; + return { + show: show, + hide: hide + }; + } + + var directiveName = snake_case( type ); + + var startSym = $interpolate.startSymbol(); + var endSym = $interpolate.endSymbol(); + var template = + '
      '+ + '
      '; + + return { + restrict: 'EA', + scope: true, + compile: function (tElem, tAttrs) { + var tooltipLinker = $compile( template ); + + return function link ( scope, element, attrs ) { + var tooltip; + var transitionTimeout; + var popupTimeout; + var appendToBody = angular.isDefined( options.appendToBody ) ? options.appendToBody : false; + var triggers = getTriggers( undefined ); + var hasEnableExp = angular.isDefined(attrs[prefix+'Enable']); + + var positionTooltip = function () { + + var ttPosition = $position.positionElements(element, tooltip, scope.tt_placement, appendToBody); + ttPosition.top += 'px'; + ttPosition.left += 'px'; + + // Now set the calculated positioning. + tooltip.css( ttPosition ); + }; + + // By default, the tooltip is not open. + // TODO add ability to start tooltip opened + scope.tt_isOpen = false; + + function toggleTooltipBind () { + if ( ! scope.tt_isOpen ) { + showTooltipBind(); + } else { + hideTooltipBind(); + } + } + + // Show the tooltip with delay if specified, otherwise show it immediately + function showTooltipBind() { + if(hasEnableExp && !scope.$eval(attrs[prefix+'Enable'])) { + return; + } + if ( scope.tt_popupDelay ) { + // Do nothing if the tooltip was already scheduled to pop-up. + // This happens if show is triggered multiple times before any hide is triggered. + if (!popupTimeout) { + popupTimeout = $timeout( show, scope.tt_popupDelay, false ); + popupTimeout.then(function(reposition){reposition();}); + } + } else { + show()(); + } + } + + function hideTooltipBind () { + scope.$apply(function () { + hide(); + }); + } + + // Show the tooltip popup element. + function show() { + + popupTimeout = null; + + // If there is a pending remove transition, we must cancel it, lest the + // tooltip be mysteriously removed. + if ( transitionTimeout ) { + $timeout.cancel( transitionTimeout ); + transitionTimeout = null; + } + + // Don't show empty tooltips. + if ( ! scope.tt_content ) { + return angular.noop; + } + + createTooltip(); + + // Set the initial positioning. + tooltip.css({ top: 0, left: 0, display: 'block' }); + + // Now we add it to the DOM because need some info about it. But it's not + // visible yet anyway. + if ( appendToBody ) { + $document.find( 'body' ).append( tooltip ); + } else { + element.after( tooltip ); + } + + positionTooltip(); + + // And show the tooltip. + scope.tt_isOpen = true; + scope.$digest(); // digest required as $apply is not called + + // Return positioning function as promise callback for correct + // positioning after draw. + return positionTooltip; + } + + // Hide the tooltip popup element. + function hide() { + // First things first: we don't show it anymore. + scope.tt_isOpen = false; + + //if tooltip is going to be shown after delay, we must cancel this + $timeout.cancel( popupTimeout ); + popupTimeout = null; + + // And now we remove it from the DOM. However, if we have animation, we + // need to wait for it to expire beforehand. + // FIXME: this is a placeholder for a port of the transitions library. + if ( scope.tt_animation ) { + if (!transitionTimeout) { + transitionTimeout = $timeout(removeTooltip, 500); + } + } else { + removeTooltip(); + } + } + + function createTooltip() { + // There can only be one tooltip element per directive shown at once. + if (tooltip) { + removeTooltip(); + } + tooltip = tooltipLinker(scope, function () {}); + + // Get contents rendered into the tooltip + scope.$digest(); + } + + function removeTooltip() { + transitionTimeout = null; + if (tooltip) { + tooltip.remove(); + tooltip = null; + } + } + + /** + * Observe the relevant attributes. + */ + attrs.$observe( type, function ( val ) { + scope.tt_content = val; + + if (!val && scope.tt_isOpen ) { + hide(); + } + }); + + attrs.$observe( prefix+'Title', function ( val ) { + scope.tt_title = val; + }); + + attrs.$observe( prefix+'Placement', function ( val ) { + scope.tt_placement = angular.isDefined( val ) ? val : options.placement; + }); + + attrs.$observe( prefix+'PopupDelay', function ( val ) { + var delay = parseInt( val, 10 ); + scope.tt_popupDelay = ! isNaN(delay) ? delay : options.popupDelay; + }); + + var unregisterTriggers = function () { + element.unbind(triggers.show, showTooltipBind); + element.unbind(triggers.hide, hideTooltipBind); + }; + + attrs.$observe( prefix+'Trigger', function ( val ) { + unregisterTriggers(); + + triggers = getTriggers( val ); + + if ( triggers.show === triggers.hide ) { + element.bind( triggers.show, toggleTooltipBind ); + } else { + element.bind( triggers.show, showTooltipBind ); + element.bind( triggers.hide, hideTooltipBind ); + } + }); + + var animation = scope.$eval(attrs[prefix + 'Animation']); + scope.tt_animation = angular.isDefined(animation) ? !!animation : options.animation; + + attrs.$observe( prefix+'AppendToBody', function ( val ) { + appendToBody = angular.isDefined( val ) ? $parse( val )( scope ) : appendToBody; + }); + + // if a tooltip is attached to we need to remove it on + // location change as its parent scope will probably not be destroyed + // by the change. + if ( appendToBody ) { + scope.$on('$locationChangeSuccess', function closeTooltipOnLocationChangeSuccess () { + if ( scope.tt_isOpen ) { + hide(); + } + }); + } + + // Make sure tooltip is destroyed and removed. + scope.$on('$destroy', function onDestroyTooltip() { + $timeout.cancel( transitionTimeout ); + $timeout.cancel( popupTimeout ); + unregisterTriggers(); + removeTooltip(); + }); + }; + } + }; + }; + }]; +}) + +.directive( 'tooltipPopup', function () { + return { + restrict: 'EA', + replace: true, + scope: { content: '@', placement: '@', animation: '&', isOpen: '&' }, + templateUrl: 'template/tooltip/tooltip-popup.html' + }; +}) + +.directive( 'tooltip', [ '$tooltip', function ( $tooltip ) { + return $tooltip( 'tooltip', 'tooltip', 'mouseenter' ); +}]) + +.directive( 'tooltipHtmlUnsafePopup', function () { + return { + restrict: 'EA', + replace: true, + scope: { content: '@', placement: '@', animation: '&', isOpen: '&' }, + templateUrl: 'template/tooltip/tooltip-html-unsafe-popup.html' + }; +}) + +.directive( 'tooltipHtmlUnsafe', [ '$tooltip', function ( $tooltip ) { + return $tooltip( 'tooltipHtmlUnsafe', 'tooltip', 'mouseenter' ); +}]); + +/** + * The following features are still outstanding: popup delay, animation as a + * function, placement as a function, inside, support for more triggers than + * just mouse enter/leave, html popovers, and selector delegatation. + */ +angular.module( 'ui.bootstrap.popover', [ 'ui.bootstrap.tooltip' ] ) + +.directive( 'popoverPopup', function () { + return { + restrict: 'EA', + replace: true, + scope: { title: '@', content: '@', placement: '@', animation: '&', isOpen: '&' }, + templateUrl: 'template/popover/popover.html' + }; +}) + +.directive( 'popover', [ '$tooltip', function ( $tooltip ) { + return $tooltip( 'popover', 'popover', 'click' ); +}]); + +angular.module('ui.bootstrap.progressbar', []) + +.constant('progressConfig', { + animate: true, + max: 100 +}) + +.controller('ProgressController', ['$scope', '$attrs', 'progressConfig', function($scope, $attrs, progressConfig) { + var self = this, + animate = angular.isDefined($attrs.animate) ? $scope.$parent.$eval($attrs.animate) : progressConfig.animate; + + this.bars = []; + $scope.max = angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : progressConfig.max; + + this.addBar = function(bar, element) { + if ( !animate ) { + element.css({'transition': 'none'}); + } + + this.bars.push(bar); + + bar.$watch('value', function( value ) { + bar.percent = +(100 * value / $scope.max).toFixed(2); + }); + + bar.$on('$destroy', function() { + element = null; + self.removeBar(bar); + }); + }; + + this.removeBar = function(bar) { + this.bars.splice(this.bars.indexOf(bar), 1); + }; +}]) + +.directive('progress', function() { + return { + restrict: 'EA', + replace: true, + transclude: true, + controller: 'ProgressController', + require: 'progress', + scope: {}, + templateUrl: 'template/progressbar/progress.html' + }; +}) + +.directive('bar', function() { + return { + restrict: 'EA', + replace: true, + transclude: true, + require: '^progress', + scope: { + value: '=', + type: '@' + }, + templateUrl: 'template/progressbar/bar.html', + link: function(scope, element, attrs, progressCtrl) { + progressCtrl.addBar(scope, element); + } + }; +}) + +.directive('progressbar', function() { + return { + restrict: 'EA', + replace: true, + transclude: true, + controller: 'ProgressController', + scope: { + value: '=', + type: '@' + }, + templateUrl: 'template/progressbar/progressbar.html', + link: function(scope, element, attrs, progressCtrl) { + progressCtrl.addBar(scope, angular.element(element.children()[0])); + } + }; +}); +angular.module('ui.bootstrap.rating', []) + +.constant('ratingConfig', { + max: 5, + stateOn: null, + stateOff: null +}) + +.controller('RatingController', ['$scope', '$attrs', 'ratingConfig', function($scope, $attrs, ratingConfig) { + var ngModelCtrl = { $setViewValue: angular.noop }; + + this.init = function(ngModelCtrl_) { + ngModelCtrl = ngModelCtrl_; + ngModelCtrl.$render = this.render; + + this.stateOn = angular.isDefined($attrs.stateOn) ? $scope.$parent.$eval($attrs.stateOn) : ratingConfig.stateOn; + this.stateOff = angular.isDefined($attrs.stateOff) ? $scope.$parent.$eval($attrs.stateOff) : ratingConfig.stateOff; + + var ratingStates = angular.isDefined($attrs.ratingStates) ? $scope.$parent.$eval($attrs.ratingStates) : + new Array( angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : ratingConfig.max ); + $scope.range = this.buildTemplateObjects(ratingStates); + }; + + this.buildTemplateObjects = function(states) { + for (var i = 0, n = states.length; i < n; i++) { + states[i] = angular.extend({ index: i }, { stateOn: this.stateOn, stateOff: this.stateOff }, states[i]); + } + return states; + }; + + $scope.rate = function(value) { + if ( !$scope.readonly && value >= 0 && value <= $scope.range.length ) { + ngModelCtrl.$setViewValue(value); + ngModelCtrl.$render(); + } + }; + + $scope.enter = function(value) { + if ( !$scope.readonly ) { + $scope.value = value; + } + $scope.onHover({value: value}); + }; + + $scope.reset = function() { + $scope.value = ngModelCtrl.$viewValue; + $scope.onLeave(); + }; + + $scope.onKeydown = function(evt) { + if (/(37|38|39|40)/.test(evt.which)) { + evt.preventDefault(); + evt.stopPropagation(); + $scope.rate( $scope.value + (evt.which === 38 || evt.which === 39 ? 1 : -1) ); + } + }; + + this.render = function() { + $scope.value = ngModelCtrl.$viewValue; + }; +}]) + +.directive('rating', function() { + return { + restrict: 'EA', + require: ['rating', 'ngModel'], + scope: { + readonly: '=?', + onHover: '&', + onLeave: '&' + }, + controller: 'RatingController', + templateUrl: 'template/rating/rating.html', + replace: true, + link: function(scope, element, attrs, ctrls) { + var ratingCtrl = ctrls[0], ngModelCtrl = ctrls[1]; + + if ( ngModelCtrl ) { + ratingCtrl.init( ngModelCtrl ); + } + } + }; +}); + +/** + * @ngdoc overview + * @name ui.bootstrap.tabs + * + * @description + * AngularJS version of the tabs directive. + */ + +angular.module('ui.bootstrap.tabs', []) + +.controller('TabsetController', ['$scope', function TabsetCtrl($scope) { + var ctrl = this, + tabs = ctrl.tabs = $scope.tabs = []; + + ctrl.select = function(selectedTab) { + angular.forEach(tabs, function(tab) { + if (tab.active && tab !== selectedTab) { + tab.active = false; + tab.onDeselect(); + } + }); + selectedTab.active = true; + selectedTab.onSelect(); + }; + + ctrl.addTab = function addTab(tab) { + tabs.push(tab); + // we can't run the select function on the first tab + // since that would select it twice + if (tabs.length === 1) { + tab.active = true; + } else if (tab.active) { + ctrl.select(tab); + } + }; + + ctrl.removeTab = function removeTab(tab) { + var index = tabs.indexOf(tab); + //Select a new tab if the tab to be removed is selected + if (tab.active && tabs.length > 1) { + //If this is the last tab, select the previous tab. else, the next tab. + var newActiveIndex = index == tabs.length - 1 ? index - 1 : index + 1; + ctrl.select(tabs[newActiveIndex]); + } + tabs.splice(index, 1); + }; +}]) + +/** + * @ngdoc directive + * @name ui.bootstrap.tabs.directive:tabset + * @restrict EA + * + * @description + * Tabset is the outer container for the tabs directive + * + * @param {boolean=} vertical Whether or not to use vertical styling for the tabs. + * @param {boolean=} justified Whether or not to use justified styling for the tabs. + * + * @example + + + + First Content! + Second Content! + +
      + + First Vertical Content! + Second Vertical Content! + + + First Justified Content! + Second Justified Content! + +
      +
      + */ +.directive('tabset', function() { + return { + restrict: 'EA', + transclude: true, + replace: true, + scope: { + type: '@' + }, + controller: 'TabsetController', + templateUrl: 'template/tabs/tabset.html', + link: function(scope, element, attrs) { + scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false; + scope.justified = angular.isDefined(attrs.justified) ? scope.$parent.$eval(attrs.justified) : false; + } + }; +}) + +/** + * @ngdoc directive + * @name ui.bootstrap.tabs.directive:tab + * @restrict EA + * + * @param {string=} heading The visible heading, or title, of the tab. Set HTML headings with {@link ui.bootstrap.tabs.directive:tabHeading tabHeading}. + * @param {string=} select An expression to evaluate when the tab is selected. + * @param {boolean=} active A binding, telling whether or not this tab is selected. + * @param {boolean=} disabled A binding, telling whether or not this tab is disabled. + * + * @description + * Creates a tab with a heading and content. Must be placed within a {@link ui.bootstrap.tabs.directive:tabset tabset}. + * + * @example + + +
      + + +
      + + First Tab + + Alert me! + Second Tab, with alert callback and html heading! + + + {{item.content}} + + +
      +
      + + function TabsDemoCtrl($scope) { + $scope.items = [ + { title:"Dynamic Title 1", content:"Dynamic Item 0" }, + { title:"Dynamic Title 2", content:"Dynamic Item 1", disabled: true } + ]; + + $scope.alertMe = function() { + setTimeout(function() { + alert("You've selected the alert tab!"); + }); + }; + }; + +
      + */ + +/** + * @ngdoc directive + * @name ui.bootstrap.tabs.directive:tabHeading + * @restrict EA + * + * @description + * Creates an HTML heading for a {@link ui.bootstrap.tabs.directive:tab tab}. Must be placed as a child of a tab element. + * + * @example + + + + + HTML in my titles?! + And some content, too! + + + Icon heading?!? + That's right. + + + + + */ +.directive('tab', ['$parse', function($parse) { + return { + require: '^tabset', + restrict: 'EA', + replace: true, + templateUrl: 'template/tabs/tab.html', + transclude: true, + scope: { + active: '=?', + heading: '@', + onSelect: '&select', //This callback is called in contentHeadingTransclude + //once it inserts the tab's content into the dom + onDeselect: '&deselect' + }, + controller: function() { + //Empty controller so other directives can require being 'under' a tab + }, + compile: function(elm, attrs, transclude) { + return function postLink(scope, elm, attrs, tabsetCtrl) { + scope.$watch('active', function(active) { + if (active) { + tabsetCtrl.select(scope); + } + }); + + scope.disabled = false; + if ( attrs.disabled ) { + scope.$parent.$watch($parse(attrs.disabled), function(value) { + scope.disabled = !! value; + }); + } + + scope.select = function() { + if ( !scope.disabled ) { + scope.active = true; + } + }; + + tabsetCtrl.addTab(scope); + scope.$on('$destroy', function() { + tabsetCtrl.removeTab(scope); + }); + + //We need to transclude later, once the content container is ready. + //when this link happens, we're inside a tab heading. + scope.$transcludeFn = transclude; + }; + } + }; +}]) + +.directive('tabHeadingTransclude', [function() { + return { + restrict: 'A', + require: '^tab', + link: function(scope, elm, attrs, tabCtrl) { + scope.$watch('headingElement', function updateHeadingElement(heading) { + if (heading) { + elm.html(''); + elm.append(heading); + } + }); + } + }; +}]) + +.directive('tabContentTransclude', function() { + return { + restrict: 'A', + require: '^tabset', + link: function(scope, elm, attrs) { + var tab = scope.$eval(attrs.tabContentTransclude); + + //Now our tab is ready to be transcluded: both the tab heading area + //and the tab content area are loaded. Transclude 'em both. + tab.$transcludeFn(tab.$parent, function(contents) { + angular.forEach(contents, function(node) { + if (isTabHeading(node)) { + //Let tabHeadingTransclude know. + tab.headingElement = node; + } else { + elm.append(node); + } + }); + }); + } + }; + function isTabHeading(node) { + return node.tagName && ( + node.hasAttribute('tab-heading') || + node.hasAttribute('data-tab-heading') || + node.tagName.toLowerCase() === 'tab-heading' || + node.tagName.toLowerCase() === 'data-tab-heading' + ); + } +}) + +; + +angular.module('ui.bootstrap.timepicker', []) + +.constant('timepickerConfig', { + hourStep: 1, + minuteStep: 1, + showMeridian: true, + meridians: null, + readonlyInput: false, + mousewheel: true +}) + +.controller('TimepickerController', ['$scope', '$attrs', '$parse', '$log', '$locale', 'timepickerConfig', function($scope, $attrs, $parse, $log, $locale, timepickerConfig) { + var selected = new Date(), + ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl + meridians = angular.isDefined($attrs.meridians) ? $scope.$parent.$eval($attrs.meridians) : timepickerConfig.meridians || $locale.DATETIME_FORMATS.AMPMS; + + this.init = function( ngModelCtrl_, inputs ) { + ngModelCtrl = ngModelCtrl_; + ngModelCtrl.$render = this.render; + + var hoursInputEl = inputs.eq(0), + minutesInputEl = inputs.eq(1); + + var mousewheel = angular.isDefined($attrs.mousewheel) ? $scope.$parent.$eval($attrs.mousewheel) : timepickerConfig.mousewheel; + if ( mousewheel ) { + this.setupMousewheelEvents( hoursInputEl, minutesInputEl ); + } + + $scope.readonlyInput = angular.isDefined($attrs.readonlyInput) ? $scope.$parent.$eval($attrs.readonlyInput) : timepickerConfig.readonlyInput; + this.setupInputEvents( hoursInputEl, minutesInputEl ); + }; + + var hourStep = timepickerConfig.hourStep; + if ($attrs.hourStep) { + $scope.$parent.$watch($parse($attrs.hourStep), function(value) { + hourStep = parseInt(value, 10); + }); + } + + var minuteStep = timepickerConfig.minuteStep; + if ($attrs.minuteStep) { + $scope.$parent.$watch($parse($attrs.minuteStep), function(value) { + minuteStep = parseInt(value, 10); + }); + } + + // 12H / 24H mode + $scope.showMeridian = timepickerConfig.showMeridian; + if ($attrs.showMeridian) { + $scope.$parent.$watch($parse($attrs.showMeridian), function(value) { + $scope.showMeridian = !!value; + + if ( ngModelCtrl.$error.time ) { + // Evaluate from template + var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate(); + if (angular.isDefined( hours ) && angular.isDefined( minutes )) { + selected.setHours( hours ); + refresh(); + } + } else { + updateTemplate(); + } + }); + } + + // Get $scope.hours in 24H mode if valid + function getHoursFromTemplate ( ) { + var hours = parseInt( $scope.hours, 10 ); + var valid = ( $scope.showMeridian ) ? (hours > 0 && hours < 13) : (hours >= 0 && hours < 24); + if ( !valid ) { + return undefined; + } + + if ( $scope.showMeridian ) { + if ( hours === 12 ) { + hours = 0; + } + if ( $scope.meridian === meridians[1] ) { + hours = hours + 12; + } + } + return hours; + } + + function getMinutesFromTemplate() { + var minutes = parseInt($scope.minutes, 10); + return ( minutes >= 0 && minutes < 60 ) ? minutes : undefined; + } + + function pad( value ) { + return ( angular.isDefined(value) && value.toString().length < 2 ) ? '0' + value : value; + } + + // Respond on mousewheel spin + this.setupMousewheelEvents = function( hoursInputEl, minutesInputEl ) { + var isScrollingUp = function(e) { + if (e.originalEvent) { + e = e.originalEvent; + } + //pick correct delta variable depending on event + var delta = (e.wheelDelta) ? e.wheelDelta : -e.deltaY; + return (e.detail || delta > 0); + }; + + hoursInputEl.bind('mousewheel wheel', function(e) { + $scope.$apply( (isScrollingUp(e)) ? $scope.incrementHours() : $scope.decrementHours() ); + e.preventDefault(); + }); + + minutesInputEl.bind('mousewheel wheel', function(e) { + $scope.$apply( (isScrollingUp(e)) ? $scope.incrementMinutes() : $scope.decrementMinutes() ); + e.preventDefault(); + }); + + }; + + this.setupInputEvents = function( hoursInputEl, minutesInputEl ) { + if ( $scope.readonlyInput ) { + $scope.updateHours = angular.noop; + $scope.updateMinutes = angular.noop; + return; + } + + var invalidate = function(invalidHours, invalidMinutes) { + ngModelCtrl.$setViewValue( null ); + ngModelCtrl.$setValidity('time', false); + if (angular.isDefined(invalidHours)) { + $scope.invalidHours = invalidHours; + } + if (angular.isDefined(invalidMinutes)) { + $scope.invalidMinutes = invalidMinutes; + } + }; + + $scope.updateHours = function() { + var hours = getHoursFromTemplate(); + + if ( angular.isDefined(hours) ) { + selected.setHours( hours ); + refresh( 'h' ); + } else { + invalidate(true); + } + }; + + hoursInputEl.bind('blur', function(e) { + if ( !$scope.invalidHours && $scope.hours < 10) { + $scope.$apply( function() { + $scope.hours = pad( $scope.hours ); + }); + } + }); + + $scope.updateMinutes = function() { + var minutes = getMinutesFromTemplate(); + + if ( angular.isDefined(minutes) ) { + selected.setMinutes( minutes ); + refresh( 'm' ); + } else { + invalidate(undefined, true); + } + }; + + minutesInputEl.bind('blur', function(e) { + if ( !$scope.invalidMinutes && $scope.minutes < 10 ) { + $scope.$apply( function() { + $scope.minutes = pad( $scope.minutes ); + }); + } + }); + + }; + + this.render = function() { + var date = ngModelCtrl.$modelValue ? new Date( ngModelCtrl.$modelValue ) : null; + + if ( isNaN(date) ) { + ngModelCtrl.$setValidity('time', false); + $log.error('Timepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.'); + } else { + if ( date ) { + selected = date; + } + makeValid(); + updateTemplate(); + } + }; + + // Call internally when we know that model is valid. + function refresh( keyboardChange ) { + makeValid(); + ngModelCtrl.$setViewValue( new Date(selected) ); + updateTemplate( keyboardChange ); + } + + function makeValid() { + ngModelCtrl.$setValidity('time', true); + $scope.invalidHours = false; + $scope.invalidMinutes = false; + } + + function updateTemplate( keyboardChange ) { + var hours = selected.getHours(), minutes = selected.getMinutes(); + + if ( $scope.showMeridian ) { + hours = ( hours === 0 || hours === 12 ) ? 12 : hours % 12; // Convert 24 to 12 hour system + } + + $scope.hours = keyboardChange === 'h' ? hours : pad(hours); + $scope.minutes = keyboardChange === 'm' ? minutes : pad(minutes); + $scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1]; + } + + function addMinutes( minutes ) { + var dt = new Date( selected.getTime() + minutes * 60000 ); + selected.setHours( dt.getHours(), dt.getMinutes() ); + refresh(); + } + + $scope.incrementHours = function() { + addMinutes( hourStep * 60 ); + }; + $scope.decrementHours = function() { + addMinutes( - hourStep * 60 ); + }; + $scope.incrementMinutes = function() { + addMinutes( minuteStep ); + }; + $scope.decrementMinutes = function() { + addMinutes( - minuteStep ); + }; + $scope.toggleMeridian = function() { + addMinutes( 12 * 60 * (( selected.getHours() < 12 ) ? 1 : -1) ); + }; +}]) + +.directive('timepicker', function () { + return { + restrict: 'EA', + require: ['timepicker', '?^ngModel'], + controller:'TimepickerController', + replace: true, + scope: {}, + templateUrl: 'template/timepicker/timepicker.html', + link: function(scope, element, attrs, ctrls) { + var timepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1]; + + if ( ngModelCtrl ) { + timepickerCtrl.init( ngModelCtrl, element.find('input') ); + } + } + }; +}); + +angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap.bindHtml']) + +/** + * A helper service that can parse typeahead's syntax (string provided by users) + * Extracted to a separate service for ease of unit testing + */ + .factory('typeaheadParser', ['$parse', function ($parse) { + + // 00000111000000000000022200000000000000003333333333333330000000000044000 + var TYPEAHEAD_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+(.*)$/; + + return { + parse:function (input) { + + var match = input.match(TYPEAHEAD_REGEXP); + if (!match) { + throw new Error( + 'Expected typeahead specification in form of "_modelValue_ (as _label_)? for _item_ in _collection_"' + + ' but got "' + input + '".'); + } + + return { + itemName:match[3], + source:$parse(match[4]), + viewMapper:$parse(match[2] || match[1]), + modelMapper:$parse(match[1]) + }; + } + }; +}]) + + .directive('typeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$position', 'typeaheadParser', + function ($compile, $parse, $q, $timeout, $document, $position, typeaheadParser) { + + var HOT_KEYS = [9, 13, 27, 38, 40]; + + return { + require:'ngModel', + link:function (originalScope, element, attrs, modelCtrl) { + + //SUPPORTED ATTRIBUTES (OPTIONS) + + //minimal no of characters that needs to be entered before typeahead kicks-in + var minSearch = originalScope.$eval(attrs.typeaheadMinLength) || 1; + + //minimal wait time after last character typed before typehead kicks-in + var waitTime = originalScope.$eval(attrs.typeaheadWaitMs) || 0; + + //should it restrict model values to the ones selected from the popup only? + var isEditable = originalScope.$eval(attrs.typeaheadEditable) !== false; + + //binding to a variable that indicates if matches are being retrieved asynchronously + var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop; + + //a callback executed when a match is selected + var onSelectCallback = $parse(attrs.typeaheadOnSelect); + + var inputFormatter = attrs.typeaheadInputFormatter ? $parse(attrs.typeaheadInputFormatter) : undefined; + + var appendToBody = attrs.typeaheadAppendToBody ? originalScope.$eval(attrs.typeaheadAppendToBody) : false; + + //INTERNAL VARIABLES + + //model setter executed upon match selection + var $setModelValue = $parse(attrs.ngModel).assign; + + //expressions used by typeahead + var parserResult = typeaheadParser.parse(attrs.typeahead); + + var hasFocus; + + //create a child scope for the typeahead directive so we are not polluting original scope + //with typeahead-specific data (matches, query etc.) + var scope = originalScope.$new(); + originalScope.$on('$destroy', function(){ + scope.$destroy(); + }); + + // WAI-ARIA + var popupId = 'typeahead-' + scope.$id + '-' + Math.floor(Math.random() * 10000); + element.attr({ + 'aria-autocomplete': 'list', + 'aria-expanded': false, + 'aria-owns': popupId + }); + + //pop-up element used to display matches + var popUpEl = angular.element('
      '); + popUpEl.attr({ + id: popupId, + matches: 'matches', + active: 'activeIdx', + select: 'select(activeIdx)', + query: 'query', + position: 'position' + }); + //custom item template + if (angular.isDefined(attrs.typeaheadTemplateUrl)) { + popUpEl.attr('template-url', attrs.typeaheadTemplateUrl); + } + + var resetMatches = function() { + scope.matches = []; + scope.activeIdx = -1; + element.attr('aria-expanded', false); + }; + + var getMatchId = function(index) { + return popupId + '-option-' + index; + }; + + // Indicate that the specified match is the active (pre-selected) item in the list owned by this typeahead. + // This attribute is added or removed automatically when the `activeIdx` changes. + scope.$watch('activeIdx', function(index) { + if (index < 0) { + element.removeAttr('aria-activedescendant'); + } else { + element.attr('aria-activedescendant', getMatchId(index)); + } + }); + + var getMatchesAsync = function(inputValue) { + + var locals = {$viewValue: inputValue}; + isLoadingSetter(originalScope, true); + $q.when(parserResult.source(originalScope, locals)).then(function(matches) { + + //it might happen that several async queries were in progress if a user were typing fast + //but we are interested only in responses that correspond to the current view value + var onCurrentRequest = (inputValue === modelCtrl.$viewValue); + if (onCurrentRequest && hasFocus) { + if (matches.length > 0) { + + scope.activeIdx = 0; + scope.matches.length = 0; + + //transform labels + for(var i=0; i= minSearch) { + if (waitTime > 0) { + if (timeoutPromise) { + $timeout.cancel(timeoutPromise);//cancel previous timeout + } + timeoutPromise = $timeout(function () { + getMatchesAsync(inputValue); + }, waitTime); + } else { + getMatchesAsync(inputValue); + } + } else { + isLoadingSetter(originalScope, false); + resetMatches(); + } + + if (isEditable) { + return inputValue; + } else { + if (!inputValue) { + // Reset in case user had typed something previously. + modelCtrl.$setValidity('editable', true); + return inputValue; + } else { + modelCtrl.$setValidity('editable', false); + return undefined; + } + } + }); + + modelCtrl.$formatters.push(function (modelValue) { + + var candidateViewValue, emptyViewValue; + var locals = {}; + + if (inputFormatter) { + + locals['$model'] = modelValue; + return inputFormatter(originalScope, locals); + + } else { + + //it might happen that we don't have enough info to properly render input value + //we need to check for this situation and simply return model value if we can't apply custom formatting + locals[parserResult.itemName] = modelValue; + candidateViewValue = parserResult.viewMapper(originalScope, locals); + locals[parserResult.itemName] = undefined; + emptyViewValue = parserResult.viewMapper(originalScope, locals); + + return candidateViewValue!== emptyViewValue ? candidateViewValue : modelValue; + } + }); + + scope.select = function (activeIdx) { + //called from within the $digest() cycle + var locals = {}; + var model, item; + + locals[parserResult.itemName] = item = scope.matches[activeIdx].model; + model = parserResult.modelMapper(originalScope, locals); + $setModelValue(originalScope, model); + modelCtrl.$setValidity('editable', true); + + onSelectCallback(originalScope, { + $item: item, + $model: model, + $label: parserResult.viewMapper(originalScope, locals) + }); + + resetMatches(); + + //return focus to the input element if a match was selected via a mouse click event + // use timeout to avoid $rootScope:inprog error + $timeout(function() { element[0].focus(); }, 0, false); + }; + + //bind keyboard events: arrows up(38) / down(40), enter(13) and tab(9), esc(27) + element.bind('keydown', function (evt) { + + //typeahead is open and an "interesting" key was pressed + if (scope.matches.length === 0 || HOT_KEYS.indexOf(evt.which) === -1) { + return; + } + + evt.preventDefault(); + + if (evt.which === 40) { + scope.activeIdx = (scope.activeIdx + 1) % scope.matches.length; + scope.$digest(); + + } else if (evt.which === 38) { + scope.activeIdx = (scope.activeIdx ? scope.activeIdx : scope.matches.length) - 1; + scope.$digest(); + + } else if (evt.which === 13 || evt.which === 9) { + scope.$apply(function () { + scope.select(scope.activeIdx); + }); + + } else if (evt.which === 27) { + evt.stopPropagation(); + + resetMatches(); + scope.$digest(); + } + }); + + element.bind('blur', function (evt) { + hasFocus = false; + }); + + // Keep reference to click handler to unbind it. + var dismissClickHandler = function (evt) { + if (element[0] !== evt.target) { + resetMatches(); + scope.$digest(); + } + }; + + $document.bind('click', dismissClickHandler); + + originalScope.$on('$destroy', function(){ + $document.unbind('click', dismissClickHandler); + }); + + var $popup = $compile(popUpEl)(scope); + if ( appendToBody ) { + $document.find('body').append($popup); + } else { + element.after($popup); + } + } + }; + +}]) + + .directive('typeaheadPopup', function () { + return { + restrict:'EA', + scope:{ + matches:'=', + query:'=', + active:'=', + position:'=', + select:'&' + }, + replace:true, + templateUrl:'template/typeahead/typeahead-popup.html', + link:function (scope, element, attrs) { + + scope.templateUrl = attrs.templateUrl; + + scope.isOpen = function () { + return scope.matches.length > 0; + }; + + scope.isActive = function (matchIdx) { + return scope.active == matchIdx; + }; + + scope.selectActive = function (matchIdx) { + scope.active = matchIdx; + }; + + scope.selectMatch = function (activeIdx) { + scope.select({activeIdx:activeIdx}); + }; + } + }; + }) + + .directive('typeaheadMatch', ['$http', '$templateCache', '$compile', '$parse', function ($http, $templateCache, $compile, $parse) { + return { + restrict:'EA', + scope:{ + index:'=', + match:'=', + query:'=' + }, + link:function (scope, element, attrs) { + var tplUrl = $parse(attrs.templateUrl)(scope.$parent) || 'template/typeahead/typeahead-match.html'; + $http.get(tplUrl, {cache: $templateCache}).success(function(tplContent){ + element.replaceWith($compile(tplContent.trim())(scope)); + }); + } + }; + }]) + + .filter('typeaheadHighlight', function() { + + function escapeRegexp(queryToEscape) { + return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1'); + } + + return function(matchItem, query) { + return query ? ('' + matchItem).replace(new RegExp(escapeRegexp(query), 'gi'), '$&') : matchItem; + }; + }); + +angular.module("template/accordion/accordion-group.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/accordion/accordion-group.html", + "
      \n" + + "
      \n" + + "

      \n" + + " {{heading}}\n" + + "

      \n" + + "
      \n" + + "
      \n" + + "
      \n" + + "
      \n" + + "
      "); +}]); + +angular.module("template/accordion/accordion.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/accordion/accordion.html", + "
      "); +}]); + +angular.module("template/alert/alert.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/alert/alert.html", + "
      \n" + + " \n" + + "
      \n" + + "
      \n" + + ""); +}]); + +angular.module("template/carousel/carousel.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/carousel/carousel.html", + "
      \n" + + "
        1\">\n" + + "
      1. \n" + + "
      \n" + + "
      \n" + + " 1\">\n" + + " 1\">\n" + + "
      \n" + + ""); +}]); + +angular.module("template/carousel/slide.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/carousel/slide.html", + "
      \n" + + ""); +}]); + +angular.module("template/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/datepicker/datepicker.html", + "
      \n" + + " \n" + + " \n" + + " \n" + + "
      "); +}]); + +angular.module("template/datepicker/day.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/datepicker/day.html", + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
      {{label.abbr}}
      {{ weekNumbers[$index] }}\n" + + " \n" + + "
      \n" + + ""); +}]); + +angular.module("template/datepicker/month.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/datepicker/month.html", + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
      \n" + + " \n" + + "
      \n" + + ""); +}]); + +angular.module("template/datepicker/popup.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/datepicker/popup.html", + "
        \n" + + "
      • \n" + + "
      • \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
      • \n" + + "
      \n" + + ""); +}]); + +angular.module("template/datepicker/year.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/datepicker/year.html", + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
      \n" + + " \n" + + "
      \n" + + ""); +}]); + +angular.module("template/modal/backdrop.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/modal/backdrop.html", + "
      \n" + + ""); +}]); + +angular.module("template/modal/window.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/modal/window.html", + "
      \n" + + "
      \n" + + "
      "); +}]); + +angular.module("template/pagination/pager.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/pagination/pager.html", + ""); +}]); + +angular.module("template/pagination/pagination.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/pagination/pagination.html", + ""); +}]); + +angular.module("template/tooltip/tooltip-html-unsafe-popup.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/tooltip/tooltip-html-unsafe-popup.html", + "
      \n" + + "
      \n" + + "
      \n" + + "
      \n" + + ""); +}]); + +angular.module("template/tooltip/tooltip-popup.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/tooltip/tooltip-popup.html", + "
      \n" + + "
      \n" + + "
      \n" + + "
      \n" + + ""); +}]); + +angular.module("template/popover/popover.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/popover/popover.html", + "
      \n" + + "
      \n" + + "\n" + + "
      \n" + + "

      \n" + + "
      \n" + + "
      \n" + + "
      \n" + + ""); +}]); + +angular.module("template/progressbar/bar.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/progressbar/bar.html", + "
      "); +}]); + +angular.module("template/progressbar/progress.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/progressbar/progress.html", + "
      "); +}]); + +angular.module("template/progressbar/progressbar.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/progressbar/progressbar.html", + "
      \n" + + "
      \n" + + "
      "); +}]); + +angular.module("template/rating/rating.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/rating/rating.html", + "\n" + + " \n" + + " ({{ $index < value ? '*' : ' ' }})\n" + + " \n" + + ""); +}]); + +angular.module("template/tabs/tab.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/tabs/tab.html", + "
    • \n" + + " {{heading}}\n" + + "
    • \n" + + ""); +}]); + +angular.module("template/tabs/tabset-titles.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/tabs/tabset-titles.html", + "
        \n" + + "
      \n" + + ""); +}]); + +angular.module("template/tabs/tabset.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/tabs/tabset.html", + "\n" + + "
      \n" + + "
        \n" + + "
        \n" + + "
        \n" + + "
        \n" + + "
        \n" + + "
        \n" + + ""); +}]); + +angular.module("template/timepicker/timepicker.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/timepicker/timepicker.html", + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
         
        \n" + + " \n" + + " :\n" + + " \n" + + "
         
        \n" + + ""); +}]); + +angular.module("template/typeahead/typeahead-match.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/typeahead/typeahead-match.html", + ""); +}]); + +angular.module("template/typeahead/typeahead-popup.html", []).run(["$templateCache", function($templateCache) { + $templateCache.put("template/typeahead/typeahead-popup.html", + "
          \n" + + "
        • \n" + + "
          \n" + + "
        • \n" + + "
        "); +}]); diff --git a/keycloak-themes/keycloak/common/resources/lib/angular/version.json b/keycloak-themes/keycloak/common/resources/lib/angular/version.json new file mode 100644 index 0000000..7325f62 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/lib/angular/version.json @@ -0,0 +1 @@ +{"raw":"v1.4.4","major":1,"minor":4,"patch":4,"prerelease":[],"build":[],"version":"1.4.4","codeName":"pylon-requirement","full":"1.4.4","branch":"v1.4.x","cdn":{"raw":"v1.4.3","major":1,"minor":4,"patch":3,"prerelease":[],"build":[],"version":"1.4.3","docsUrl":"http://code.angularjs.org/1.4.3/docs"}} \ No newline at end of file diff --git a/keycloak-themes/keycloak/common/resources/lib/filesaver/FileSaver.js b/keycloak-themes/keycloak/common/resources/lib/filesaver/FileSaver.js new file mode 100644 index 0000000..fb71494 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/lib/filesaver/FileSaver.js @@ -0,0 +1,188 @@ +/* FileSaver.js + * A saveAs() FileSaver implementation. + * 1.3.2 + * 2016-06-16 18:25:19 + * + * By Eli Grey, http://eligrey.com + * License: MIT + * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md + */ + +/*global self */ +/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ + +/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ + +var saveAs = saveAs || (function(view) { + "use strict"; + // IE <10 is explicitly unsupported + if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) { + return; + } + var + doc = view.document + // only get URL when necessary in case Blob.js hasn't overridden it yet + , get_URL = function() { + return view.URL || view.webkitURL || view; + } + , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") + , can_use_save_link = "download" in save_link + , click = function(node) { + var event = new MouseEvent("click"); + node.dispatchEvent(event); + } + , is_safari = /constructor/i.test(view.HTMLElement) || view.safari + , is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent) + , throw_outside = function(ex) { + (view.setImmediate || view.setTimeout)(function() { + throw ex; + }, 0); + } + , force_saveable_type = "application/octet-stream" + // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to + , arbitrary_revoke_timeout = 1000 * 40 // in ms + , revoke = function(file) { + var revoker = function() { + if (typeof file === "string") { // file is an object URL + get_URL().revokeObjectURL(file); + } else { // file is a File + file.remove(); + } + }; + setTimeout(revoker, arbitrary_revoke_timeout); + } + , dispatch = function(filesaver, event_types, event) { + event_types = [].concat(event_types); + var i = event_types.length; + while (i--) { + var listener = filesaver["on" + event_types[i]]; + if (typeof listener === "function") { + try { + listener.call(filesaver, event || filesaver); + } catch (ex) { + throw_outside(ex); + } + } + } + } + , auto_bom = function(blob) { + // prepend BOM for UTF-8 XML and text/* types (including HTML) + // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF + if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { + return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type}); + } + return blob; + } + , FileSaver = function(blob, name, no_auto_bom) { + if (!no_auto_bom) { + blob = auto_bom(blob); + } + // First try a.download, then web filesystem, then object URLs + var + filesaver = this + , type = blob.type + , force = type === force_saveable_type + , object_url + , dispatch_all = function() { + dispatch(filesaver, "writestart progress write writeend".split(" ")); + } + // on any filesys errors revert to saving with object URLs + , fs_error = function() { + if ((is_chrome_ios || (force && is_safari)) && view.FileReader) { + // Safari doesn't allow downloading of blob urls + var reader = new FileReader(); + reader.onloadend = function() { + var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;'); + var popup = view.open(url, '_blank'); + if(!popup) view.location.href = url; + url=undefined; // release reference before dispatching + filesaver.readyState = filesaver.DONE; + dispatch_all(); + }; + reader.readAsDataURL(blob); + filesaver.readyState = filesaver.INIT; + return; + } + // don't create more object URLs than needed + if (!object_url) { + object_url = get_URL().createObjectURL(blob); + } + if (force) { + view.location.href = object_url; + } else { + var opened = view.open(object_url, "_blank"); + if (!opened) { + // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html + view.location.href = object_url; + } + } + filesaver.readyState = filesaver.DONE; + dispatch_all(); + revoke(object_url); + } + ; + filesaver.readyState = filesaver.INIT; + + if (can_use_save_link) { + object_url = get_URL().createObjectURL(blob); + setTimeout(function() { + save_link.href = object_url; + save_link.download = name; + click(save_link); + dispatch_all(); + revoke(object_url); + filesaver.readyState = filesaver.DONE; + }); + return; + } + + fs_error(); + } + , FS_proto = FileSaver.prototype + , saveAs = function(blob, name, no_auto_bom) { + return new FileSaver(blob, name || blob.name || "download", no_auto_bom); + } + ; + // IE 10+ (native saveAs) + if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) { + return function(blob, name, no_auto_bom) { + name = name || blob.name || "download"; + + if (!no_auto_bom) { + blob = auto_bom(blob); + } + return navigator.msSaveOrOpenBlob(blob, name); + }; + } + + FS_proto.abort = function(){}; + FS_proto.readyState = FS_proto.INIT = 0; + FS_proto.WRITING = 1; + FS_proto.DONE = 2; + + FS_proto.error = + FS_proto.onwritestart = + FS_proto.onprogress = + FS_proto.onwrite = + FS_proto.onabort = + FS_proto.onerror = + FS_proto.onwriteend = + null; + + return saveAs; +}( + typeof self !== "undefined" && self + || typeof window !== "undefined" && window + || this.content +)); +// `self` is undefined in Firefox for Android content script context +// while `this` is nsIContentFrameMessageManager +// with an attribute `content` that corresponds to the window + +if (typeof module !== "undefined" && module.exports) { + module.exports.saveAs = saveAs; +} else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) { + define("FileSaver.js", function() { + return saveAs; + }); +} diff --git a/keycloak-themes/keycloak/common/resources/lib/fileupload/FileAPI.min.js b/keycloak-themes/keycloak/common/resources/lib/fileupload/FileAPI.min.js new file mode 100644 index 0000000..7cc0ff4 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/lib/fileupload/FileAPI.min.js @@ -0,0 +1,72 @@ +/**! + * FileAPI a set of tools for working with files + * + * @author RubaXa + * @build lib/canvas-to-blob lib/FileAPI.core lib/FileAPI.Image lib/FileAPI.Form lib/FileAPI.XHR lib/FileAPI.Flash + */ +(function(a){var k=a.HTMLCanvasElement&&a.HTMLCanvasElement.prototype,g;if(g=a.Blob)try{g=Boolean(new Blob)}catch(j){g=!1}var m=g;if(g=m)if(g=a.Uint8Array)try{g=100===(new Blob([new Uint8Array(100)])).size}catch(f){g=!1}var c=g,e=a.BlobBuilder||a.WebKitBlobBuilder||a.MozBlobBuilder||a.MSBlobBuilder,q=(m||e)&&a.atob&&a.ArrayBuffer&&a.Uint8Array&&function(a){var l,f,u,g;l=0<=a.split(",")[0].indexOf("base64")?atob(a.split(",")[1]):decodeURIComponent(a.split(",")[1]);f=new ArrayBuffer(l.length);u=new Uint8Array(f); +for(g=0;g= +a&&!c&&n.end()},isFail:function(){return c},fail:function(){!c&&b(c=!0)},end:function(){e||(e=!0,b())}};return n},each:g,afor:function(b,d){var a=0,c=b.length;l(b)&&c--?function B(){d(c!=a&&B,b[a],a++)}():d(!1)},extend:function(b){g(arguments,function(d){g(d,function(d,a){b[a]=d})});return b},isFile:function(b){return x&&b&&b instanceof v},isCanvas:function(b){return b&&U.test(b.nodeName)},getFilesFilter:function(b){return(b="string"==typeof b?b:b.getAttribute&&b.getAttribute("accept")||"")?RegExp("("+ +b.replace(/\./g,"\\.").replace(/,/g,"|")+")$","i"):/./},readAsDataURL:function(b,d){h.isCanvas(b)?c(b,d,"load",h.toDataURL(b)):e(b,d,"DataURL")},readAsBinaryString:function(b,d){p&&p.prototype.readAsBinaryString?e(b,d,"BinaryString"):e(b,function(b){if("load"==b.type)try{b.result=h.toBinaryString(b.result)}catch(a){b.type="error",b.message=a.toString()}d(b)},"DataURL")},readAsArrayBuffer:function(b,d){e(b,d,"ArrayBuffer")},readAsText:function(b,d,a){a||(a=d,d="utf-8");e(b,a,"Text",d)},toDataURL:function(b){if("string"== +typeof b)return b;if(b.toDataURL)return b.toDataURL("image/png")},toBinaryString:function(b){return a.atob(h.toDataURL(b).replace(I,""))},readAsImage:function(b,d,a){if(h.isFile(b))if(y){var e=y.createObjectURL(b);e===k?c(b,d,"error"):h.readAsImage(e,d,a)}else h.readAsDataURL(b,function(e){"load"==e.type?h.readAsImage(e.result,d,a):(a||"error"==e.type)&&c(b,d,e,null,{loaded:e.loaded,total:e.total})});else h.isCanvas(b)?c(b,d,"load",b):T.test(b.nodeName)?b.complete?c(b,d,"load",b):f(b,"error abort load", +function B(a){"load"==a.type&&y&&y.revokeObjectURL(b.src);m(b,"error abort load",B);c(b,d,a,b)}):b.iframe?c(b,d,{type:"error"}):(e=new Image,e.src=b.dataURL||b,h.readAsImage(e,d,a))},checkFileObj:function(b){var d={},a=h.accept;"object"==typeof b?d=b:d.name=(b+"").split(/\\|\//g).pop();null==d.type&&(d.type=d.name.split(".").pop());g(a,function(b,a){b=RegExp(b.replace(/\s/g,"|"),"i");b.test(d.type)&&(d.type=a.split("/")[0]+"/"+d.type)});return d},getDropFiles:function(b,d){var a=[],c=(b.originalEvent|| +b||"").dataTransfer||{},e=l(c.items)&&c.items[0]&&q(c.items[0]),n=h.queue(function(){d(a)});g((e?c.items:c.files)||[],function(b){n.inc();if(e)t(b,function(b,d){!b&&a.push.apply(a,d);n.next()});else{var d=function(d){d&&a.push(b);n.next()};if(!b.type&&0==b.size%4096&&102400>=b.size)if(p)try{var c=new p;f(c,K,function(b){b="error"!=b.type;d(b);b&&c.abort()});c.readAsDataURL(b)}catch(l){d(!1)}else d(null);else d(!0)}});n.check()},getFiles:function(b,d,a){var c=[];if(a)return h.filterFiles(h.getFiles(b), +d,a),null;b.jquery&&(b.each(function(){c=c.concat(h.getFiles(this))}),b=c,c=[]);"string"==typeof d&&(d=h.getFilesFilter(d));b.originalEvent?b=A(b.originalEvent):b.srcElement&&(b=A(b));b.dataTransfer?b=b.dataTransfer:b.target&&(b=b.target);b.files?c=b.files:!x&&L.test(b&&b.tagName)?h.trim(b.value)&&(c=[h.checkFileObj(b.value)],c[0].blob=b,c[0].iframe=!0):l(b)&&(c=b);return h.filter(c,function(b){return!d||d.test(b.name)})},getInfo:function(b,d){var a={},c=O.concat();h.isFile(b)?function B(){var e= +c.shift();e?e.test(b.type)?e(b,function(b,c){b?d(b):(h.extend(a,c),B())}):B():d(!1,a)}():d("not_support",a)},addInfoReader:function(b,d){d.test=function(d){return b.test(d)};O.push(d)},filter:function(b,d){for(var a=[],c=0,e=b.length,n;c>2,c=(c&3)<<4|e>>4;isNaN(e)?e=n=64:(e=(e&15)<<2|n>>6,n=isNaN(n)?64:n&63);d+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(l)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(c)+ +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(e)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(n)}return d}};h.addInfoReader(/^image/,function(b,d){if(!b.__dimensions){var a=b.__dimensions=h.defer();h.readAsImage(b,function(b){var d=b.target;a.resolve("load"==b.type?!1:"error",{width:d.width,height:d.height})})}b.__dimensions.then(d)});h.event.dnd=function(b,d,a){var c,e;a||(a=d,d=h.F);p?(j(b,"dragenter dragleave dragover",function(b){for(var a= +((b.originalEvent||b||"").dataTransfer||{}).types,n=a&&a.length;n--;)~a[n].indexOf("File")&&(b.preventDefault(),e!==b.type&&(e=b.type,"dragleave"!=e&&d.call(b.currentTarget,!0,b),clearTimeout(c),c=setTimeout(function(){d.call(b.currentTarget,"dragleave"!=e,b)},50)))}),j(b,"drop",function(b){b.preventDefault();e=0;d.call(b.currentTarget,!1,b);h.getDropFiles(b,function(d){a.call(b.currentTarget,d,b)})})):h.log("Drag'n'Drop -- not supported")};n&&!n.fn.dnd&&(n.fn.dnd=function(b,d){return this.each(function(){h.event.dnd(this, +b,d)})});a.FileAPI=h.extend(h,a.FileAPI);h.flashUrl||(h.flashUrl=h.staticPath+"FileAPI.flash.swf");h.flashImageUrl||(h.flashImageUrl=h.staticPath+"FileAPI.flash.image.swf")})(window); +(function(a,k,g){function j(a,c){if(!(this instanceof j))return new j(a);this.file=a;this.better=!c;this.matrix={sx:0,sy:0,sw:0,sh:0,dx:0,dy:0,dw:0,dh:0,resize:0,deg:0}}var m=Math.min,f=Math.round,c=!1,e={8:270,3:180,6:90};try{c=-1=s?(s=g,r=s/j):(r=c,s=r*j),s!=g||r!=c)e.sx=~~((g-s)/2),e.sy=~~((c-r)/2),g=s,c=r}else r&&("min"==r?(q=f(s=j?m(g,q):k*s),k=f(s>=j?q/s:m(c,k))));e.sw=g;e.sh=c;e.dw=q;e.dh=k;return e},_trans:function(a){this._load(this.file,function(c,e){c?a(c):this._apply(e,a)})},get:function(c){if(a.support.transform){var f=this;"auto"==f.matrix.deg?a.getInfo(this.file,function(a,g){f.matrix.deg= +e[g&&g.exif&&g.exif.Orientation]||0;f._trans(c)}):f._trans(c)}else c("not_support")},toData:function(a){this.get(a)}};j.exifOrientation=e;j.transform=function(c,e,f,q){a.getInfo(c,function(m,k){var y={},r=a.queue(function(a){q(a,y)});m?r.fail():a.each(e,function(a,e){if(!r.isFail()){var l=j(k.nodeType?k:c);if("function"==typeof a)a(k,l);else if(a.width)l[a.preview?"preview":"resize"](a.width,a.height,a.type);else a.maxWidth&&(k.width>a.maxWidth||k.height>a.maxHeight)&&l.resize(a.maxWidth,a.maxHeight, +"max");a.rotate===g&&f&&(a.rotate="auto");l.rotate(a.rotate);r.inc();l.toData(function(d,a){d?r.fail():(y[e]=a,r.next())})}})})};a.support.canvas=a.support.transform=c;a.Image=j})(FileAPI,document); +(function(a,k,g){var j=k.encodeURIComponent,m=k.FormData;k=function(){this.items=[]};k.prototype={append:function(a,c,e,g){this.items.push({name:a,blob:c&&c.blob||(void 0==c?"":c),file:c&&(e||c.name),type:c&&(g||c.type)})},each:function(a){for(var c=0,e=this.items.length;c',c.xhr.abort=function(){var a=e.getElementsByName("iframe")[0];if(a)try{a.stop?a.stop():a.contentWindow.stop?a.contentWindow.stop():a.contentWindow.document.execCommand("Stop")}catch(c){}e=null},j=e.getElementsByTagName("form")[0], +j.appendChild(f),k.log(j.parentNode.innerHTML),document.body.appendChild(e),c.xhr.node=e,a[q]=function(a,f,g){c.readyState=4;c.responseText=g;c.end(a,f);e=null},c.readyState=2,j.submit(),j=null):this.xhr&&this.xhr.aborted?k.log("Error: already aborted"):(e=c.xhr=k.getXHR(),f.params&&(j+=(0>j.indexOf("?")?"?":"&")+f.params.join("&")),e.open("POST",j,!0),k.withCredentials&&(e.withCredentials="true"),(!g.headers||!g.headers["X-Requested-With"])&&e.setRequestHeader("X-Requested-With","XMLHttpRequest"), +k.each(g.headers,function(a,c){e.setRequestHeader(c,a)}),g._chunked?(e.upload&&e.upload.addEventListener("progress",function(a){f.retry||g.progress({type:a.type,total:f.size,loaded:f.start+a.loaded,totalSize:f.size},c,g)},!1),e.onreadystatechange=function(){c.status=e.status;c.statusText=e.statusText;c.readyState=e.readyState;if(4==e.readyState){for(var a in{"":1,XML:1,Text:1,Body:1})c["response"+a]=e["response"+a];e.onreadystatechange=null;if(!e.status||0').replace(/#(\w+)#/ig,function(c,e){return a[e]})},t=function(a,c){if(a&&a.style){var e,f;for(e in c){f=c[e];"number"==typeof f&&(f+="px");try{a.style[e]=f}catch(g){}}}},l=function(d,c){a.each(c,function(a,c){var e=d[c];d[c]=function(){this.parent=e;return a.apply(this,arguments)}})},A=function(d){var c=d.wid=a.uid();p._fn[c]=d;return"FileAPI.Flash._fn."+c}, +u=function(a){try{p._fn[a.wid]=null,delete p._fn[a.wid]}catch(c){}},C=function(a,c){if(!v.test(a)){if(/^\.\//.test(a)||"/"!=a.charAt(0)){var e=location.pathname,e=e.substr(0,e.lastIndexOf("/"));a=(e+"/"+a).replace("/./","/")}"//"!=a.substr(0,2)&&(a="//"+location.host+a);v.test(a)||(a=location.protocol+a)}c&&(a+=(/\?/.test(a)?"&":"?")+c);return a},s=a.uid(),y=0,r={},v=/^https?:/i,p={_fn:{},init:function(){var d=g.body&&g.body.firstChild;if(d){do if(1==d.nodeType){a.log("FlashAPI.Flash.init...");var c= +g.createElement("div");t(c,{top:1,right:1,width:5,height:5,position:"absolute"});d.parentNode.insertBefore(c,d);p.publish(c,s);return}while(d=d.nextSibling)}10>y&&setTimeout(p.init,50*++y)},publish:function(d,c){d.innerHTML=q({id:c,src:C(a.flashUrl,"r="+a.version),wmode:"transparent",flashvars:"callback=FileAPI.Flash.event&flashId="+c+"&storeKey="+navigator.userAgent.match(/\d/ig).join("")+"_"+a.version+(p.isReady||(a.pingUrl?"&ping="+a.pingUrl:""))})},ready:function(){p.ready=a.F;p.isReady=!0;p.patch(); +a.event.on(g,"mouseover",p.mouseover);a.event.on(g,"click",function(a){p.mouseover(a)&&(a.preventDefault?a.preventDefault():a.returnValue=!0)})},getWrapper:function(a){do if(/js-fileapi-wrapper/.test(a.className))return a;while((a=a.parentNode)&&a!==g.body)},mouseover:function(d){d=a.event.fix(d).target;if(/input/i.test(d.nodeName)&&"file"==d.type){var c=d.getAttribute(s);if("i"==c||"r"==c)return!1;if("p"!=c){d.setAttribute(s,"i");var c=g.createElement("div"),e=p.getWrapper(d);if(!e){a.log("flash.mouseover.error: js-fileapi-wrapper not found"); +return}t(c,{top:0,left:0,width:d.offsetWidth+100,height:d.offsetHeight+100,zIndex:"1000000",position:"absolute"});e.appendChild(c);p.publish(c,a.uid());d.setAttribute(s,"p")}return!0}},event:function(d){var c=d.type;if("ready"==c){try{p.getInput(d.flashId).setAttribute(s,"r")}catch(e){}p.ready();setTimeout(function(){p.mouseenter(d)},50);return!0}"ping"===c?a.log("(flash -> js).ping:",[d.status,d.savedStatus],d.error):"log"===c?a.log("(flash -> js).log:",d.target):c in p&&setTimeout(function(){a.log("Flash.event."+ +d.type+":",d);p[c](d)},1)},mouseenter:function(d){var c=p.getInput(d.flashId);if(c){p.cmd(d,"multiple",null!=c.getAttribute("multiple"));var e=[],f={};a.each((c.getAttribute("accept")||"").split(/,\s*/),function(d){a.accept[d]&&a.each(a.accept[d].split(" "),function(a){f[a]=1})});a.each(f,function(a,d){e.push(d)});p.cmd(d,"accept",e.length?e.join(",")+","+e.join(",").toUpperCase():"*")}},get:function(a){return g[a]||k[a]||g.embeds[a]},getInput:function(d){try{var c=p.getWrapper(p.get(d));if(c)return c.getElementsByTagName("input")[0]}catch(e){a.log('Can not find "input" by flashId:', +d,e)}},select:function(d){var c=p.getInput(d.flashId),e=a.uid(c);d=d.target.files;a.each(d,function(d){a.checkFileObj(d)});r[e]=d;g.createEvent?(e=g.createEvent("Event"),e.initEvent("change",!0,!1),c.dispatchEvent(e)):g.createEventObject&&(e=g.createEventObject(),c.fireEvent("onchange",e))},cmd:function(d,c,e,f){try{return a.log("(js -> flash)."+c+":",e),p.get(d.flashId||d).cmd(c,e)}catch(g){a.log("(js -> flash).onError:",g),f||setTimeout(function(){p.cmd(d,c,e,!0)},50)}},patch:function(){a.flashEngine= +a.support.transform=!0;l(a,{getFiles:function(d,c,e){if(e)return a.filterFiles(a.getFiles(d),c,e),null;var f=a.isArray(d)?d:r[a.uid(d.target||d.srcElement||d)];if(!f)return this.parent.apply(this,arguments);c&&(c=a.getFilesFilter(c),f=a.filter(f,function(a){return c.test(a.name)}));return f},getInfo:function(d,c){if(d&&!d.flashId)this.parent.apply(this,arguments);else{if(!d.__info){var e=d.__info=a.defer();p.cmd(d,"getFileInfo",{id:d.id,callback:A(function F(a,c){u(F);e.resolve(a,d.info=c)})})}d.__info.then(c)}}}); +a.support.transform=!0;a.Image&&l(a.Image.prototype,{get:function(a,c){this.set({scaleMode:c||"noScale"});this.parent(a)},_load:function(d,c){a.log("FileAPI.Image._load:",d);if(d&&!d.flashId)this.parent.apply(this,arguments);else{var e=this;a.getInfo(d,function(a){c.call(e,a,d)})}},_apply:function(d,c){a.log("FileAPI.Image._apply:",d);if(d&&!d.flashId)this.parent.apply(this,arguments);else{var e=this.getMatrix(d.info);p.cmd(d,"imageTransform",{id:d.id,matrix:e,callback:A(function F(f,k){a.log("FileAPI.Image._apply.callback:", +f);u(F);if(f)c(f);else if(!a.support.dataURI||3E4 + * @version 1.1.10 + */ +if (window.XMLHttpRequest) { + if (window.FormData) { + // allow access to Angular XHR private field: https://github.com/angular/angular.js/issues/1934 + XMLHttpRequest = (function(origXHR) { + return function() { + var xhr = new origXHR(); + xhr.send = (function(orig) { + return function() { + if (arguments[0] instanceof FormData && arguments[0].__setXHR_) { + var formData = arguments[0]; + formData.__setXHR_(xhr); + } + orig.apply(xhr, arguments); + } + })(xhr.send); + return xhr; + } + })(XMLHttpRequest); + } +} diff --git a/keycloak-themes/keycloak/common/resources/lib/fileupload/angular-file-upload-html5-shim.min.js b/keycloak-themes/keycloak/common/resources/lib/fileupload/angular-file-upload-html5-shim.min.js new file mode 100644 index 0000000..64d9182 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/lib/fileupload/angular-file-upload-html5-shim.min.js @@ -0,0 +1,2 @@ +/*! 1.1.10 */ +window.XMLHttpRequest&&window.FormData&&(XMLHttpRequest=function(a){return function(){var b=new a;return b.send=function(a){return function(){if(arguments[0]instanceof FormData&&arguments[0].__setXHR_){var c=arguments[0];c.__setXHR_(b)}a.apply(b,arguments)}}(b.send),b}}(XMLHttpRequest)); \ No newline at end of file diff --git a/keycloak-themes/keycloak/common/resources/lib/fileupload/angular-file-upload-shim.js b/keycloak-themes/keycloak/common/resources/lib/fileupload/angular-file-upload-shim.js new file mode 100644 index 0000000..f526e58 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/lib/fileupload/angular-file-upload-shim.js @@ -0,0 +1,215 @@ +/**! + * AngularJS file upload shim for HTML5 FormData + * @author Danial + * @version 1.1.10 + */ +(function() { + +if (window.XMLHttpRequest) { + if (window.FormData) { + // allow access to Angular XHR private field: https://github.com/angular/angular.js/issues/1934 + XMLHttpRequest = (function(origXHR) { + return function() { + var xhr = new origXHR(); + xhr.send = (function(orig) { + return function() { + if (arguments[0] instanceof FormData && arguments[0].__setXHR_) { + var formData = arguments[0]; + formData.__setXHR_(xhr); + } + orig.apply(xhr, arguments); + } + })(xhr.send); + return xhr; + } + })(XMLHttpRequest); + } else { + XMLHttpRequest = (function(origXHR) { + return function() { + var xhr = new origXHR(); + var origSend = xhr.send; + xhr.__requestHeaders = []; + xhr.open = (function(orig) { + xhr.upload = { + addEventListener: function(t, fn, b) { + if (t == 'progress') { + xhr.__progress = fn; + } + } + }; + return function(m, url, b) { + orig.apply(xhr, [m, url, b]); + xhr.__url = url; + } + })(xhr.open); + xhr.getResponseHeader = (function(orig) { + return function(h) { + return xhr.__fileApiXHR ? xhr.__fileApiXHR.getResponseHeader(h) : orig.apply(xhr, [h]); + } + })(xhr.getResponseHeader); + xhr.getAllResponseHeaders = (function(orig) { + return function() { + return xhr.__fileApiXHR ? xhr.__fileApiXHR.getAllResponseHeaders() : orig.apply(xhr); + } + })(xhr.getAllResponseHeaders); + xhr.abort = (function(orig) { + return function() { + return xhr.__fileApiXHR ? xhr.__fileApiXHR.abort() : (orig == null ? null : orig.apply(xhr)); + } + })(xhr.abort); + xhr.send = function() { + if (arguments[0] != null && arguments[0].__isShim && arguments[0].__setXHR_) { + var formData = arguments[0]; + if (arguments[0].__setXHR_) { + var formData = arguments[0]; + formData.__setXHR_(xhr); + } + var config = { + url: xhr.__url, + complete: function(err, fileApiXHR) { + Object.defineProperty(xhr, 'status', {get: function() {return fileApiXHR.status}}); + Object.defineProperty(xhr, 'statusText', {get: function() {return fileApiXHR.statusText}}); + Object.defineProperty(xhr, 'readyState', {get: function() {return 4}}); + Object.defineProperty(xhr, 'response', {get: function() {return fileApiXHR.response}}); + Object.defineProperty(xhr, 'responseText', {get: function() {return fileApiXHR.responseText}}); + xhr.__fileApiXHR = fileApiXHR; + xhr.onreadystatechange(); + }, + progress: function(e) { + xhr.__progress(e); + }, + headers: xhr.__requestHeaders + } + config.data = {}; + config.files = {} + for (var i = 0; i < formData.data.length; i++) { + var item = formData.data[i]; + if (item.val != null && item.val.name != null && item.val.size != null && item.val.type != null) { + config.files[item.key] = item.val; + } else { + config.data[item.key] = item.val; + } + } + + setTimeout(function() { + xhr.__fileApiXHR = FileAPI.upload(config); + }, 1); + } else { + origSend.apply(xhr, arguments); + } + } + return xhr; + } + })(XMLHttpRequest); + } +} + +if (!window.FormData) { + var hasFlash = false; + try { + var fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash'); + if (fo) hasFlash = true; + } catch(e) { + if (navigator.mimeTypes["application/x-shockwave-flash"] != undefined) hasFlash = true; + } + var wrapFileApi = function(elem) { + if (!elem.__isWrapped && (elem.getAttribute('ng-file-select') != null || elem.getAttribute('data-ng-file-select') != null)) { + var wrap = document.createElement('div'); + wrap.innerHTML = '
        '; + wrap = wrap.firstChild; + var parent = elem.parentNode; + parent.insertBefore(wrap, elem); + parent.removeChild(elem); + wrap.appendChild(elem); + if (!hasFlash) { + wrap.appendChild(document.createTextNode('Flash is required')); + } + elem.__isWrapped = true; + } + }; + var changeFnWrapper = function(fn) { + return function(evt) { + var files = FileAPI.getFiles(evt); + if (!evt.target) { + evt.target = {}; + } + evt.target.files = files; + evt.target.files.item = function(i) { + return evt.target.files[i] || null; + } + fn(evt); + }; + }; + var isFileChange = function(elem, e) { + return (e.toLowerCase() === 'change' || e.toLowerCase() === 'onchange') && elem.getAttribute('type') == 'file'; + } + if (HTMLInputElement.prototype.addEventListener) { + HTMLInputElement.prototype.addEventListener = (function(origAddEventListener) { + return function(e, fn, b, d) { + if (isFileChange(this, e)) { + wrapFileApi(this); + origAddEventListener.apply(this, [e, changeFnWrapper(fn), b, d]); + } else { + origAddEventListener.apply(this, [e, fn, b, d]); + } + } + })(HTMLInputElement.prototype.addEventListener); + } + if (HTMLInputElement.prototype.attachEvent) { + HTMLInputElement.prototype.attachEvent = (function(origAttachEvent) { + return function(e, fn) { + if (isFileChange(this, e)) { + wrapFileApi(this); + origAttachEvent.apply(this, [e, changeFnWrapper(fn)]); + } else { + origAttachEvent.apply(this, [e, fn]); + } + } + })(HTMLInputElement.prototype.attachEvent); + } + + window.FormData = FormData = function() { + return { + append: function(key, val, name) { + this.data.push({ + key: key, + val: val, + name: name + }); + }, + data: [], + __isShim: true + }; + }; + + (function () { + //load FileAPI + if (!window.FileAPI || !FileAPI.upload) { + var base = '', script = document.createElement('script'), allScripts = document.getElementsByTagName('script'), i, index, src; + if (window.FileAPI && window.FileAPI.jsPath) { + base = window.FileAPI.jsPath; + } else { + for (i = 0; i < allScripts.length; i++) { + src = allScripts[i].src; + index = src.indexOf('angular-file-upload-shim.js') + if (index == -1) { + index = src.indexOf('angular-file-upload-shim.min.js'); + } + if (index > -1) { + base = src.substring(0, index); + break; + } + } + } + + if (!window.FileAPI || FileAPI.staticPath == null) { + FileAPI = { + staticPath: base + } + } + + script.setAttribute('src', base + "FileAPI.min.js"); + document.getElementsByTagName('head')[0].appendChild(script); + } + })(); +}})(); \ No newline at end of file diff --git a/keycloak-themes/keycloak/common/resources/lib/fileupload/angular-file-upload-shim.min.js b/keycloak-themes/keycloak/common/resources/lib/fileupload/angular-file-upload-shim.min.js new file mode 100644 index 0000000..e76e175 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/lib/fileupload/angular-file-upload-shim.min.js @@ -0,0 +1,2 @@ +/*! 1.1.10 */ +!function(){if(window.XMLHttpRequest&&(XMLHttpRequest=window.FormData?function(a){return function(){var b=new a;return b.send=function(a){return function(){if(arguments[0]instanceof FormData&&arguments[0].__setXHR_){var c=arguments[0];c.__setXHR_(b)}a.apply(b,arguments)}}(b.send),b}}(XMLHttpRequest):function(a){return function(){var b=new a,c=b.send;return b.__requestHeaders=[],b.open=function(a){return b.upload={addEventListener:function(a,c){"progress"==a&&(b.__progress=c)}},function(c,d,e){a.apply(b,[c,d,e]),b.__url=d}}(b.open),b.getResponseHeader=function(a){return function(c){return b.__fileApiXHR?b.__fileApiXHR.getResponseHeader(c):a.apply(b,[c])}}(b.getResponseHeader),b.getAllResponseHeaders=function(a){return function(){return b.__fileApiXHR?b.__fileApiXHR.getAllResponseHeaders():a.apply(b)}}(b.getAllResponseHeaders),b.abort=function(a){return function(){return b.__fileApiXHR?b.__fileApiXHR.abort():null==a?null:a.apply(b)}}(b.abort),b.send=function(){if(null!=arguments[0]&&arguments[0].__isShim&&arguments[0].__setXHR_){var a=arguments[0];if(arguments[0].__setXHR_){var a=arguments[0];a.__setXHR_(b)}var d={url:b.__url,complete:function(a,c){Object.defineProperty(b,"status",{get:function(){return c.status}}),Object.defineProperty(b,"statusText",{get:function(){return c.statusText}}),Object.defineProperty(b,"readyState",{get:function(){return 4}}),Object.defineProperty(b,"response",{get:function(){return c.response}}),Object.defineProperty(b,"responseText",{get:function(){return c.responseText}}),b.__fileApiXHR=c,b.onreadystatechange()},progress:function(a){b.__progress(a)},headers:b.__requestHeaders};d.data={},d.files={};for(var e=0;e
      ',c=c.firstChild;var d=b.parentNode;d.insertBefore(c,b),d.removeChild(b),c.appendChild(b),a||c.appendChild(document.createTextNode("Flash is required")),b.__isWrapped=!0}},e=function(a){return function(b){var c=FileAPI.getFiles(b);b.target||(b.target={}),b.target.files=c,b.target.files.item=function(a){return b.target.files[a]||null},a(b)}},f=function(a,b){return("change"===b.toLowerCase()||"onchange"===b.toLowerCase())&&"file"==a.getAttribute("type")};HTMLInputElement.prototype.addEventListener&&(HTMLInputElement.prototype.addEventListener=function(a){return function(b,c,g,h){f(this,b)?(d(this),a.apply(this,[b,e(c),g,h])):a.apply(this,[b,c,g,h])}}(HTMLInputElement.prototype.addEventListener)),HTMLInputElement.prototype.attachEvent&&(HTMLInputElement.prototype.attachEvent=function(a){return function(b,c){f(this,b)?(d(this),a.apply(this,[b,e(c)])):a.apply(this,[b,c])}}(HTMLInputElement.prototype.attachEvent)),window.FormData=FormData=function(){return{append:function(a,b,c){this.data.push({key:a,val:b,name:c})},data:[],__isShim:!0}},function(){if(!window.FileAPI||!FileAPI.upload){var a,b,c,d="",e=document.createElement("script"),f=document.getElementsByTagName("script");if(window.FileAPI&&window.FileAPI.jsPath)d=window.FileAPI.jsPath;else for(a=0;a-1){d=c.substring(0,b);break}window.FileAPI&&null!=FileAPI.staticPath||(FileAPI={staticPath:d}),e.setAttribute("src",d+"FileAPI.min.js"),document.getElementsByTagName("head")[0].appendChild(e)}}()}}(); \ No newline at end of file diff --git a/keycloak-themes/keycloak/common/resources/lib/fileupload/angular-file-upload.js b/keycloak-themes/keycloak/common/resources/lib/fileupload/angular-file-upload.js new file mode 100644 index 0000000..0daaa69 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/lib/fileupload/angular-file-upload.js @@ -0,0 +1,156 @@ +/**! + * AngularJS file upload/drop directive with http post and progress + * @author Danial + * @version 1.1.10 + */ +(function() { + +var angularFileUpload = angular.module('angularFileUpload', []); + +angularFileUpload.service('$upload', ['$http', '$rootScope', '$timeout', function($http, $rootScope, $timeout) { + this.upload = function(config) { + config.method = config.method || 'POST'; + config.headers = config.headers || {}; + config.headers['Content-Type'] = undefined; + config.transformRequest = config.transformRequest || $http.defaults.transformRequest; + var formData = new FormData(); + if (config.data) { + for (var key in config.data) { + var val = config.data[key]; + if (!config.formDataAppender) { + if (typeof config.transformRequest == 'function') { + val = config.transformRequest(val); + } else { + for (var i = 0; i < config.transformRequest.length; i++) { + var fn = config.transformRequest[i]; + if (typeof fn == 'function') { + val = fn(val); + } + } + } + formData.append(key, val); + } else { + config.formDataAppender(formData, key, val); + } + } + } + config.transformRequest = angular.identity; + formData.append(config.fileFormDataName || 'file', config.file, config.file.name); + + formData['__setXHR_'] = function(xhr) { + config.__XHR = xhr; + xhr.upload.addEventListener('progress', function(e) { + if (config.progress) { + $timeout(function() { + config.progress(e); + }); + } + }, false); + //fix for firefox not firing upload progress end + xhr.upload.addEventListener('load', function(e) { + if (e.lengthComputable) { + $timeout(function() { + config.progress(e); + }); + } + }, false); + }; + + config.data = formData; + + var promise = $http(config); + + promise.progress = function(fn) { + config.progress = fn; + return promise; + }; + + promise.abort = function() { + if (config.__XHR) { + $timeout(function() { + config.__XHR.abort(); + }); + } + return promise; + }; + promise.then = (function(promise, origThen) { + return function(s, e, p) { + config.progress = p || config.progress; + origThen.apply(promise, [s, e, p]); + return promise; + }; + })(promise, promise.then); + + return promise; + }; +}]); + +angularFileUpload.directive('ngFileSelect', [ '$parse', '$http', '$timeout', function($parse, $http, $timeout) { + return function(scope, elem, attr) { + var fn = $parse(attr['ngFileSelect']); + elem.bind('change', function(evt) { + var files = [], fileList, i; + fileList = evt.target.files; + if (fileList != null) { + for (i = 0; i < fileList.length; i++) { + files.push(fileList.item(i)); + } + } + $timeout(function() { + fn(scope, { + $files : files, + $event : evt + }); + }); + }); + elem.bind('click', function(){ + this.value = null; + }); + }; +} ]); + +angularFileUpload.directive('ngFileDropAvailable', [ '$parse', '$http', '$timeout', function($parse, $http, $timeout) { + return function(scope, elem, attr) { + if ('draggable' in document.createElement('span')) { + var fn = $parse(attr['ngFileDropAvailable']); + $timeout(function() { + fn(scope); + }); + } + }; +} ]); + +angularFileUpload.directive('ngFileDrop', [ '$parse', '$http', '$timeout', function($parse, $http, $timeout) { + return function(scope, elem, attr) { + if ('draggable' in document.createElement('span')) { + var fn = $parse(attr['ngFileDrop']); + elem[0].addEventListener("dragover", function(evt) { + evt.stopPropagation(); + evt.preventDefault(); + elem.addClass(attr['ngFileDragOverClass'] || "dragover"); + }, false); + elem[0].addEventListener("dragleave", function(evt) { + elem.removeClass(attr['ngFileDragOverClass'] || "dragover"); + }, false); + elem[0].addEventListener("drop", function(evt) { + evt.stopPropagation(); + evt.preventDefault(); + elem.removeClass(attr['ngFileDragOverClass'] || "dragover"); + var files = [], fileList = evt.dataTransfer.files, i; + if (fileList != null) { + for (i = 0; i < fileList.length; i++) { + files.push(fileList.item(i)); + } + } + $timeout(function() { + fn(scope, { + $files : files, + $event : evt + }); + }); + }, false); + } + }; +} ]); + +})(); diff --git a/keycloak-themes/keycloak/common/resources/lib/fileupload/angular-file-upload.min.js b/keycloak-themes/keycloak/common/resources/lib/fileupload/angular-file-upload.min.js new file mode 100644 index 0000000..ae51b1f --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/lib/fileupload/angular-file-upload.min.js @@ -0,0 +1,2 @@ +/*! 1.1.10 */ +!function(){var a=angular.module("angularFileUpload",[]);a.service("$upload",["$http","$rootScope","$timeout",function(a,b,c){this.upload=function(b){b.method=b.method||"POST",b.headers=b.headers||{},b.headers["Content-Type"]=void 0,b.transformRequest=b.transformRequest||a.defaults.transformRequest;var d=new FormData;if(b.data)for(var e in b.data){var f=b.data[e];if(b.formDataAppender)b.formDataAppender(d,e,f);else{if("function"==typeof b.transformRequest)f=b.transformRequest(f);else for(var g=0;g` tag. + * - **domain** - `{string}` - The cookie will be available only for this domain and + * its sub-domains. For security reasons the user agent will not accept the cookie + * if the current domain is not a sub-domain of this domain or equal to it. + * - **expires** - `{string|Date}` - String of the form "Wdy, DD Mon YYYY HH:MM:SS GMT" + * or a Date object indicating the exact date/time this cookie will expire. + * - **secure** - `{boolean}` - If `true`, then the cookie will only be available through a + * secured connection. + * - **samesite** - `{string}` - prevents the browser from sending the cookie along with cross-site requests. + * Accepts the values `lax` and `strict`. See the [OWASP Wiki](https://www.owasp.org/index.php/SameSite) + * for more info. Note that as of May 2018, not all browsers support `SameSite`, + * so it cannot be used as a single measure against Cross-Site-Request-Forgery (CSRF) attacks. + * + * Note: By default, the address that appears in your `` tag will be used as the path. + * This is important so that cookies will be visible for all routes when html5mode is enabled. + * + * @example + * + * ```js + * angular.module('cookiesProviderExample', ['ngCookies']) + * .config(['$cookiesProvider', function($cookiesProvider) { + * // Setting default options + * $cookiesProvider.defaults.domain = 'foo.com'; + * $cookiesProvider.defaults.secure = true; + * }]); + * ``` + **/ + var defaults = this.defaults = {}; + + function calcOptions(options) { + return options ? angular.extend({}, defaults, options) : defaults; + } + + /** + * @ngdoc service + * @name $cookies + * + * @description + * Provides read/write access to browser's cookies. + * + *
      + * Up until AngularJS 1.3, `$cookies` exposed properties that represented the + * current browser cookie values. In version 1.4, this behavior has changed, and + * `$cookies` now provides a standard api of getters, setters etc. + *
      + * + * Requires the {@link ngCookies `ngCookies`} module to be installed. + * + * @example + * + * ```js + * angular.module('cookiesExample', ['ngCookies']) + * .controller('ExampleController', ['$cookies', function($cookies) { + * // Retrieving a cookie + * var favoriteCookie = $cookies.get('myFavorite'); + * // Setting a cookie + * $cookies.put('myFavorite', 'oatmeal'); + * }]); + * ``` + */ + this.$get = ['$$cookieReader', '$$cookieWriter', function($$cookieReader, $$cookieWriter) { + return { + /** + * @ngdoc method + * @name $cookies#get + * + * @description + * Returns the value of given cookie key + * + * @param {string} key Id to use for lookup. + * @returns {string} Raw cookie value. + */ + get: function(key) { + return $$cookieReader()[key]; + }, + + /** + * @ngdoc method + * @name $cookies#getObject + * + * @description + * Returns the deserialized value of given cookie key + * + * @param {string} key Id to use for lookup. + * @returns {Object} Deserialized cookie value. + */ + getObject: function(key) { + var value = this.get(key); + return value ? angular.fromJson(value) : value; + }, + + /** + * @ngdoc method + * @name $cookies#getAll + * + * @description + * Returns a key value object with all the cookies + * + * @returns {Object} All cookies + */ + getAll: function() { + return $$cookieReader(); + }, + + /** + * @ngdoc method + * @name $cookies#put + * + * @description + * Sets a value for given cookie key + * + * @param {string} key Id for the `value`. + * @param {string} value Raw value to be stored. + * @param {Object=} options Options object. + * See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults} + */ + put: function(key, value, options) { + $$cookieWriter(key, value, calcOptions(options)); + }, + + /** + * @ngdoc method + * @name $cookies#putObject + * + * @description + * Serializes and sets a value for given cookie key + * + * @param {string} key Id for the `value`. + * @param {Object} value Value to be stored. + * @param {Object=} options Options object. + * See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults} + */ + putObject: function(key, value, options) { + this.put(key, angular.toJson(value), options); + }, + + /** + * @ngdoc method + * @name $cookies#remove + * + * @description + * Remove given cookie + * + * @param {string} key Id of the key-value pair to delete. + * @param {Object=} options Options object. + * See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults} + */ + remove: function(key, options) { + $$cookieWriter(key, undefined, calcOptions(options)); + } + }; + }]; + }]); + +/** + * @name $$cookieWriter + * @requires $document + * + * @description + * This is a private service for writing cookies + * + * @param {string} name Cookie name + * @param {string=} value Cookie value (if undefined, cookie will be deleted) + * @param {Object=} options Object with options that need to be stored for the cookie. + */ +function $$CookieWriter($document, $log, $browser) { + var cookiePath = $browser.baseHref(); + var rawDocument = $document[0]; + + function buildCookieString(name, value, options) { + var path, expires; + options = options || {}; + expires = options.expires; + path = angular.isDefined(options.path) ? options.path : cookiePath; + if (angular.isUndefined(value)) { + expires = 'Thu, 01 Jan 1970 00:00:00 GMT'; + value = ''; + } + if (angular.isString(expires)) { + expires = new Date(expires); + } + + var str = encodeURIComponent(name) + '=' + encodeURIComponent(value); + str += path ? ';path=' + path : ''; + str += options.domain ? ';domain=' + options.domain : ''; + str += expires ? ';expires=' + expires.toUTCString() : ''; + str += options.secure ? ';secure' : ''; + str += options.samesite ? ';samesite=' + options.samesite : ''; + + // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum: + // - 300 cookies + // - 20 cookies per unique domain + // - 4096 bytes per cookie + var cookieLength = str.length + 1; + if (cookieLength > 4096) { + $log.warn('Cookie \'' + name + + '\' possibly not set or overflowed because it was too large (' + + cookieLength + ' > 4096 bytes)!'); + } + + return str; + } + + return function(name, value, options) { + rawDocument.cookie = buildCookieString(name, value, options); + }; +} + +$$CookieWriter.$inject = ['$document', '$log', '$browser']; + +angular.module('ngCookies').provider('$$cookieWriter', /** @this */ function $$CookieWriterProvider() { + this.$get = $$CookieWriter; +}); + + +})(window, window.angular); diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-cookies/angular-cookies.min.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-cookies/angular-cookies.min.js new file mode 100644 index 0000000..873220d --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-cookies/angular-cookies.min.js @@ -0,0 +1,9 @@ +/* + AngularJS v1.8.0 + (c) 2010-2020 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(n,e){'use strict';function m(d,k,l){var a=l.baseHref(),h=d[0];return function(f,b,c){var d,g;c=c||{};g=c.expires;d=e.isDefined(c.path)?c.path:a;e.isUndefined(b)&&(g="Thu, 01 Jan 1970 00:00:00 GMT",b="");e.isString(g)&&(g=new Date(g));b=encodeURIComponent(f)+"="+encodeURIComponent(b);b=b+(d?";path="+d:"")+(c.domain?";domain="+c.domain:"");b+=g?";expires="+g.toUTCString():"";b+=c.secure?";secure":"";b+=c.samesite?";samesite="+c.samesite:"";c=b.length+1;4096 4096 bytes)!");h.cookie=b}}e.module("ngCookies",["ng"]).info({angularVersion:"1.8.0"}).provider("$cookies",[function(){var d=this.defaults={};this.$get=["$$cookieReader","$$cookieWriter",function(k,l){return{get:function(a){return k()[a]},getObject:function(a){return(a=this.get(a))?e.fromJson(a):a},getAll:function(){return k()},put:function(a,h,f){l(a,h,f?e.extend({},d,f):d)},putObject:function(a,d,f){this.put(a,e.toJson(d),f)},remove:function(a,h){l(a,void 0,h?e.extend({},d,h):d)}}}]}]);m.$inject= +["$document","$log","$browser"];e.module("ngCookies").provider("$$cookieWriter",function(){this.$get=m})})(window,window.angular); +//# sourceMappingURL=angular-cookies.min.js.map diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-cookies/angular-cookies.min.js.map b/keycloak-themes/keycloak/common/resources/node_modules/angular-cookies/angular-cookies.min.js.map new file mode 100644 index 0000000..c642643 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-cookies/angular-cookies.min.js.map @@ -0,0 +1,8 @@ +{ +"version":3, +"file":"angular-cookies.min.js", +"lineCount":8, +"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkB,CAqM3BC,QAASA,EAAc,CAACC,CAAD,CAAYC,CAAZ,CAAkBC,CAAlB,CAA4B,CACjD,IAAIC,EAAaD,CAAAE,SAAA,EAAjB,CACIC,EAAcL,CAAA,CAAU,CAAV,CAoClB,OAAO,SAAQ,CAACM,CAAD,CAAOC,CAAP,CAAcC,CAAd,CAAuB,CAlCW,IAC3CC,CAD2C,CACrCC,CACVF,EAAA,CAiCoDA,CAjCpD,EAAqB,EACrBE,EAAA,CAAUF,CAAAE,QACVD,EAAA,CAAOX,CAAAa,UAAA,CAAkBH,CAAAC,KAAlB,CAAA,CAAkCD,CAAAC,KAAlC,CAAiDN,CACpDL,EAAAc,YAAA,CAAoBL,CAApB,CAAJ,GACEG,CACA,CADU,+BACV,CAAAH,CAAA,CAAQ,EAFV,CAIIT,EAAAe,SAAA,CAAiBH,CAAjB,CAAJ,GACEA,CADF,CACY,IAAII,IAAJ,CAASJ,CAAT,CADZ,CAIIK,EAAAA,CAAMC,kBAAA,CAsB6BV,CAtB7B,CAANS,CAAiC,GAAjCA,CAAuCC,kBAAA,CAAmBT,CAAnB,CAE3CQ,EAAA,CADAA,CACA,EADON,CAAA,CAAO,QAAP,CAAkBA,CAAlB,CAAyB,EAChC,GAAOD,CAAAS,OAAA,CAAiB,UAAjB,CAA8BT,CAAAS,OAA9B,CAA+C,EAAtD,CACAF,EAAA,EAAOL,CAAA,CAAU,WAAV,CAAwBA,CAAAQ,YAAA,EAAxB,CAAgD,EACvDH,EAAA,EAAOP,CAAAW,OAAA,CAAiB,SAAjB,CAA6B,EACpCJ,EAAA,EAAOP,CAAAY,SAAA,CAAmB,YAAnB,CAAkCZ,CAAAY,SAAlC,CAAqD,EAMxDC,EAAAA,CAAeN,CAAAO,OAAfD,CAA4B,CACb,KAAnB,CAAIA,CAAJ,EACEpB,CAAAsB,KAAA,CAAU,UAAV,CASqCjB,CATrC,CACE,6DADF;AAEEe,CAFF,CAEiB,iBAFjB,CASFhB,EAAAmB,OAAA,CAJOT,CAG6B,CAtCW,CAxLnDjB,CAAA2B,OAAA,CAAe,WAAf,CAA4B,CAAC,IAAD,CAA5B,CAAAC,KAAA,CACO,CAAEC,eAAgB,OAAlB,CADP,CAAAC,SAAA,CAQY,UARZ,CAQwB,CAAaC,QAAyB,EAAG,CAsC7D,IAAIC,EAAW,IAAAA,SAAXA,CAA2B,EAiC/B,KAAAC,KAAA,CAAY,CAAC,gBAAD,CAAmB,gBAAnB,CAAqC,QAAQ,CAACC,CAAD,CAAiBC,CAAjB,CAAiC,CACxF,MAAO,CAWLC,IAAKA,QAAQ,CAACC,CAAD,CAAM,CACjB,MAAOH,EAAA,EAAA,CAAiBG,CAAjB,CADU,CAXd,CAyBLC,UAAWA,QAAQ,CAACD,CAAD,CAAM,CAEvB,MAAO,CADH5B,CACG,CADK,IAAA2B,IAAA,CAASC,CAAT,CACL,EAAQrC,CAAAuC,SAAA,CAAiB9B,CAAjB,CAAR,CAAkCA,CAFlB,CAzBpB,CAuCL+B,OAAQA,QAAQ,EAAG,CACjB,MAAON,EAAA,EADU,CAvCd,CAuDLO,IAAKA,QAAQ,CAACJ,CAAD,CAAM5B,CAAN,CAAaC,CAAb,CAAsB,CACjCyB,CAAA,CAAeE,CAAf,CAAoB5B,CAApB,CAAuCC,CAvFpC,CAAUV,CAAA0C,OAAA,CAAe,EAAf,CAAmBV,CAAnB,CAuF0BtB,CAvF1B,CAAV,CAAkDsB,CAuFrD,CADiC,CAvD9B,CAuELW,UAAWA,QAAQ,CAACN,CAAD,CAAM5B,CAAN,CAAaC,CAAb,CAAsB,CACvC,IAAA+B,IAAA,CAASJ,CAAT,CAAcrC,CAAA4C,OAAA,CAAenC,CAAf,CAAd,CAAqCC,CAArC,CADuC,CAvEpC,CAsFLmC,OAAQA,QAAQ,CAACR,CAAD,CAAM3B,CAAN,CAAe,CAC7ByB,CAAA,CAAeE,CAAf,CAAoBS,IAAAA,EAApB,CAA2CpC,CAtHxC,CAAUV,CAAA0C,OAAA,CAAe,EAAf,CAAmBV,CAAnB,CAsH8BtB,CAtH9B,CAAV,CAAkDsB,CAsHrD,CAD6B,CAtF1B,CADiF,CAA9E,CAvEiD,CAAzC,CARxB,CAmOA/B,EAAA8C,QAAA;AAAyB,CAAC,WAAD,CAAc,MAAd,CAAsB,UAAtB,CAEzB/C,EAAA2B,OAAA,CAAe,WAAf,CAAAG,SAAA,CAAqC,gBAArC,CAAoEkB,QAA+B,EAAG,CACpG,IAAAf,KAAA,CAAYhC,CADwF,CAAtG,CAlP2B,CAA1B,CAAD,CAuPGF,MAvPH,CAuPWA,MAAAC,QAvPX;", +"sources":["angular-cookies.js"], +"names":["window","angular","$$CookieWriter","$document","$log","$browser","cookiePath","baseHref","rawDocument","name","value","options","path","expires","isDefined","isUndefined","isString","Date","str","encodeURIComponent","domain","toUTCString","secure","samesite","cookieLength","length","warn","cookie","module","info","angularVersion","provider","$CookiesProvider","defaults","$get","$$cookieReader","$$cookieWriter","get","key","getObject","fromJson","getAll","put","extend","putObject","toJson","remove","undefined","$inject","$$CookieWriterProvider"] +} diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-cookies/bower.json b/keycloak-themes/keycloak/common/resources/node_modules/angular-cookies/bower.json new file mode 100644 index 0000000..a242299 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-cookies/bower.json @@ -0,0 +1,10 @@ +{ + "name": "angular-cookies", + "version": "1.8.0", + "license": "MIT", + "main": "./angular-cookies.js", + "ignore": [], + "dependencies": { + "angular": "1.8.0" + } +} diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-cookies/index.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-cookies/index.js new file mode 100644 index 0000000..6576675 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-cookies/index.js @@ -0,0 +1,2 @@ +require('./angular-cookies'); +module.exports = 'ngCookies'; diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-loader/LICENSE.md b/keycloak-themes/keycloak/common/resources/node_modules/angular-loader/LICENSE.md new file mode 100644 index 0000000..2c395ee --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-loader/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Angular + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-loader/angular-loader.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-loader/angular-loader.js new file mode 100644 index 0000000..f2c0bce --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-loader/angular-loader.js @@ -0,0 +1,638 @@ +/** + * @license AngularJS v1.8.0 + * (c) 2010-2020 Google, Inc. http://angularjs.org + * License: MIT + */ + +(function() {'use strict'; + // NOTE: + // These functions are copied here from `src/Angular.js`, because they are needed inside the + // `angular-loader.js` closure and need to be available before the main `angular.js` script has + // been loaded. + function isFunction(value) {return typeof value === 'function';} + function isDefined(value) {return typeof value !== 'undefined';} + function isNumber(value) {return typeof value === 'number';} + function isObject(value) {return value !== null && typeof value === 'object';} + function isScope(obj) {return obj && obj.$evalAsync && obj.$watch;} + function isUndefined(value) {return typeof value === 'undefined';} + function isWindow(obj) {return obj && obj.window === obj;} + function sliceArgs(args, startIndex) {return Array.prototype.slice.call(args, startIndex || 0);} + function toJsonReplacer(key, value) { + var val = value; + + if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') { + val = undefined; + } else if (isWindow(value)) { + val = '$WINDOW'; + } else if (value && window.document === value) { + val = '$DOCUMENT'; + } else if (isScope(value)) { + val = '$SCOPE'; + } + + return val; + } + +/* exported toDebugString */ + +function serializeObject(obj, maxDepth) { + var seen = []; + + // There is no direct way to stringify object until reaching a specific depth + // and a very deep object can cause a performance issue, so we copy the object + // based on this specific depth and then stringify it. + if (isValidObjectMaxDepth(maxDepth)) { + // This file is also included in `angular-loader`, so `copy()` might not always be available in + // the closure. Therefore, it is lazily retrieved as `angular.copy()` when needed. + obj = angular.copy(obj, null, maxDepth); + } + return JSON.stringify(obj, function(key, val) { + val = toJsonReplacer(key, val); + if (isObject(val)) { + + if (seen.indexOf(val) >= 0) return '...'; + + seen.push(val); + } + return val; + }); +} + +function toDebugString(obj, maxDepth) { + if (typeof obj === 'function') { + return obj.toString().replace(/ \{[\s\S]*$/, ''); + } else if (isUndefined(obj)) { + return 'undefined'; + } else if (typeof obj !== 'string') { + return serializeObject(obj, maxDepth); + } + return obj; +} + +/* exported + minErrConfig, + errorHandlingConfig, + isValidObjectMaxDepth +*/ + +var minErrConfig = { + objectMaxDepth: 5, + urlErrorParamsEnabled: true +}; + +/** + * @ngdoc function + * @name angular.errorHandlingConfig + * @module ng + * @kind function + * + * @description + * Configure several aspects of error handling in AngularJS if used as a setter or return the + * current configuration if used as a getter. The following options are supported: + * + * - **objectMaxDepth**: The maximum depth to which objects are traversed when stringified for error messages. + * + * Omitted or undefined options will leave the corresponding configuration values unchanged. + * + * @param {Object=} config - The configuration object. May only contain the options that need to be + * updated. Supported keys: + * + * * `objectMaxDepth` **{Number}** - The max depth for stringifying objects. Setting to a + * non-positive or non-numeric value, removes the max depth limit. + * Default: 5 + * + * * `urlErrorParamsEnabled` **{Boolean}** - Specifies whether the generated error url will + * contain the parameters of the thrown error. Disabling the parameters can be useful if the + * generated error url is very long. + * + * Default: true. When used without argument, it returns the current value. + */ +function errorHandlingConfig(config) { + if (isObject(config)) { + if (isDefined(config.objectMaxDepth)) { + minErrConfig.objectMaxDepth = isValidObjectMaxDepth(config.objectMaxDepth) ? config.objectMaxDepth : NaN; + } + if (isDefined(config.urlErrorParamsEnabled) && isBoolean(config.urlErrorParamsEnabled)) { + minErrConfig.urlErrorParamsEnabled = config.urlErrorParamsEnabled; + } + } else { + return minErrConfig; + } +} + +/** + * @private + * @param {Number} maxDepth + * @return {boolean} + */ +function isValidObjectMaxDepth(maxDepth) { + return isNumber(maxDepth) && maxDepth > 0; +} + + +/** + * @description + * + * This object provides a utility for producing rich Error messages within + * AngularJS. It can be called as follows: + * + * var exampleMinErr = minErr('example'); + * throw exampleMinErr('one', 'This {0} is {1}', foo, bar); + * + * The above creates an instance of minErr in the example namespace. The + * resulting error will have a namespaced error code of example.one. The + * resulting error will replace {0} with the value of foo, and {1} with the + * value of bar. The object is not restricted in the number of arguments it can + * take. + * + * If fewer arguments are specified than necessary for interpolation, the extra + * interpolation markers will be preserved in the final string. + * + * Since data will be parsed statically during a build step, some restrictions + * are applied with respect to how minErr instances are created and called. + * Instances should have names of the form namespaceMinErr for a minErr created + * using minErr('namespace'). Error codes, namespaces and template strings + * should all be static strings, not variables or general expressions. + * + * @param {string} module The namespace to use for the new minErr instance. + * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning + * error from returned function, for cases when a particular type of error is useful. + * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance + */ + +function minErr(module, ErrorConstructor) { + ErrorConstructor = ErrorConstructor || Error; + + var url = 'https://errors.angularjs.org/1.8.0/'; + var regex = url.replace('.', '\\.') + '[\\s\\S]*'; + var errRegExp = new RegExp(regex, 'g'); + + return function() { + var code = arguments[0], + template = arguments[1], + message = '[' + (module ? module + ':' : '') + code + '] ', + templateArgs = sliceArgs(arguments, 2).map(function(arg) { + return toDebugString(arg, minErrConfig.objectMaxDepth); + }), + paramPrefix, i; + + // A minErr message has two parts: the message itself and the url that contains the + // encoded message. + // The message's parameters can contain other error messages which also include error urls. + // To prevent the messages from getting too long, we strip the error urls from the parameters. + + message += template.replace(/\{\d+\}/g, function(match) { + var index = +match.slice(1, -1); + + if (index < templateArgs.length) { + return templateArgs[index].replace(errRegExp, ''); + } + + return match; + }); + + message += '\n' + url + (module ? module + '/' : '') + code; + + if (minErrConfig.urlErrorParamsEnabled) { + for (i = 0, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') { + message += paramPrefix + 'p' + i + '=' + encodeURIComponent(templateArgs[i]); + } + } + + return new ErrorConstructor(message); + }; +} + +/** + * @ngdoc type + * @name angular.Module + * @module ng + * @description + * + * Interface for configuring AngularJS {@link angular.module modules}. + */ + +function setupModuleLoader(window) { + + var $injectorMinErr = minErr('$injector'); + var ngMinErr = minErr('ng'); + + function ensure(obj, name, factory) { + return obj[name] || (obj[name] = factory()); + } + + var angular = ensure(window, 'angular', Object); + + // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap + angular.$$minErr = angular.$$minErr || minErr; + + return ensure(angular, 'module', function() { + /** @type {Object.} */ + var modules = {}; + + /** + * @ngdoc function + * @name angular.module + * @module ng + * @description + * + * The `angular.module` is a global place for creating, registering and retrieving AngularJS + * modules. + * All modules (AngularJS core or 3rd party) that should be available to an application must be + * registered using this mechanism. + * + * Passing one argument retrieves an existing {@link angular.Module}, + * whereas passing more than one argument creates a new {@link angular.Module} + * + * + * # Module + * + * A module is a collection of services, directives, controllers, filters, and configuration information. + * `angular.module` is used to configure the {@link auto.$injector $injector}. + * + * ```js + * // Create a new module + * var myModule = angular.module('myModule', []); + * + * // register a new service + * myModule.value('appName', 'MyCoolApp'); + * + * // configure existing services inside initialization blocks. + * myModule.config(['$locationProvider', function($locationProvider) { + * // Configure existing providers + * $locationProvider.hashPrefix('!'); + * }]); + * ``` + * + * Then you can create an injector and load your modules like this: + * + * ```js + * var injector = angular.injector(['ng', 'myModule']) + * ``` + * + * However it's more likely that you'll just use + * {@link ng.directive:ngApp ngApp} or + * {@link angular.bootstrap} to simplify this process for you. + * + * @param {!string} name The name of the module to create or retrieve. + * @param {!Array.=} requires If specified then new module is being created. If + * unspecified then the module is being retrieved for further configuration. + * @param {Function=} configFn Optional configuration function for the module. Same as + * {@link angular.Module#config Module#config()}. + * @returns {angular.Module} new module with the {@link angular.Module} api. + */ + return function module(name, requires, configFn) { + + var info = {}; + + var assertNotHasOwnProperty = function(name, context) { + if (name === 'hasOwnProperty') { + throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context); + } + }; + + assertNotHasOwnProperty(name, 'module'); + if (requires && modules.hasOwnProperty(name)) { + modules[name] = null; + } + return ensure(modules, name, function() { + if (!requires) { + throw $injectorMinErr('nomod', 'Module \'{0}\' is not available! You either misspelled ' + + 'the module name or forgot to load it. If registering a module ensure that you ' + + 'specify the dependencies as the second argument.', name); + } + + /** @type {!Array.>} */ + var invokeQueue = []; + + /** @type {!Array.} */ + var configBlocks = []; + + /** @type {!Array.} */ + var runBlocks = []; + + var config = invokeLater('$injector', 'invoke', 'push', configBlocks); + + /** @type {angular.Module} */ + var moduleInstance = { + // Private state + _invokeQueue: invokeQueue, + _configBlocks: configBlocks, + _runBlocks: runBlocks, + + /** + * @ngdoc method + * @name angular.Module#info + * @module ng + * + * @param {Object=} info Information about the module + * @returns {Object|Module} The current info object for this module if called as a getter, + * or `this` if called as a setter. + * + * @description + * Read and write custom information about this module. + * For example you could put the version of the module in here. + * + * ```js + * angular.module('myModule', []).info({ version: '1.0.0' }); + * ``` + * + * The version could then be read back out by accessing the module elsewhere: + * + * ``` + * var version = angular.module('myModule').info().version; + * ``` + * + * You can also retrieve this information during runtime via the + * {@link $injector#modules `$injector.modules`} property: + * + * ```js + * var version = $injector.modules['myModule'].info().version; + * ``` + */ + info: function(value) { + if (isDefined(value)) { + if (!isObject(value)) throw ngMinErr('aobj', 'Argument \'{0}\' must be an object', 'value'); + info = value; + return this; + } + return info; + }, + + /** + * @ngdoc property + * @name angular.Module#requires + * @module ng + * + * @description + * Holds the list of modules which the injector will load before the current module is + * loaded. + */ + requires: requires, + + /** + * @ngdoc property + * @name angular.Module#name + * @module ng + * + * @description + * Name of the module. + */ + name: name, + + + /** + * @ngdoc method + * @name angular.Module#provider + * @module ng + * @param {string} name service name + * @param {Function} providerType Construction function for creating new instance of the + * service. + * @description + * See {@link auto.$provide#provider $provide.provider()}. + */ + provider: invokeLaterAndSetModuleName('$provide', 'provider'), + + /** + * @ngdoc method + * @name angular.Module#factory + * @module ng + * @param {string} name service name + * @param {Function} providerFunction Function for creating new instance of the service. + * @description + * See {@link auto.$provide#factory $provide.factory()}. + */ + factory: invokeLaterAndSetModuleName('$provide', 'factory'), + + /** + * @ngdoc method + * @name angular.Module#service + * @module ng + * @param {string} name service name + * @param {Function} constructor A constructor function that will be instantiated. + * @description + * See {@link auto.$provide#service $provide.service()}. + */ + service: invokeLaterAndSetModuleName('$provide', 'service'), + + /** + * @ngdoc method + * @name angular.Module#value + * @module ng + * @param {string} name service name + * @param {*} object Service instance object. + * @description + * See {@link auto.$provide#value $provide.value()}. + */ + value: invokeLater('$provide', 'value'), + + /** + * @ngdoc method + * @name angular.Module#constant + * @module ng + * @param {string} name constant name + * @param {*} object Constant value. + * @description + * Because the constants are fixed, they get applied before other provide methods. + * See {@link auto.$provide#constant $provide.constant()}. + */ + constant: invokeLater('$provide', 'constant', 'unshift'), + + /** + * @ngdoc method + * @name angular.Module#decorator + * @module ng + * @param {string} name The name of the service to decorate. + * @param {Function} decorFn This function will be invoked when the service needs to be + * instantiated and should return the decorated service instance. + * @description + * See {@link auto.$provide#decorator $provide.decorator()}. + */ + decorator: invokeLaterAndSetModuleName('$provide', 'decorator', configBlocks), + + /** + * @ngdoc method + * @name angular.Module#animation + * @module ng + * @param {string} name animation name + * @param {Function} animationFactory Factory function for creating new instance of an + * animation. + * @description + * + * **NOTE**: animations take effect only if the **ngAnimate** module is loaded. + * + * + * Defines an animation hook that can be later used with + * {@link $animate $animate} service and directives that use this service. + * + * ```js + * module.animation('.animation-name', function($inject1, $inject2) { + * return { + * eventName : function(element, done) { + * //code to run the animation + * //once complete, then run done() + * return function cancellationFunction(element) { + * //code to cancel the animation + * } + * } + * } + * }) + * ``` + * + * See {@link ng.$animateProvider#register $animateProvider.register()} and + * {@link ngAnimate ngAnimate module} for more information. + */ + animation: invokeLaterAndSetModuleName('$animateProvider', 'register'), + + /** + * @ngdoc method + * @name angular.Module#filter + * @module ng + * @param {string} name Filter name - this must be a valid AngularJS expression identifier + * @param {Function} filterFactory Factory function for creating new instance of filter. + * @description + * See {@link ng.$filterProvider#register $filterProvider.register()}. + * + *
      + * **Note:** Filter names must be valid AngularJS {@link expression} identifiers, such as `uppercase` or `orderBy`. + * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace + * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores + * (`myapp_subsection_filterx`). + *
      + */ + filter: invokeLaterAndSetModuleName('$filterProvider', 'register'), + + /** + * @ngdoc method + * @name angular.Module#controller + * @module ng + * @param {string|Object} name Controller name, or an object map of controllers where the + * keys are the names and the values are the constructors. + * @param {Function} constructor Controller constructor function. + * @description + * See {@link ng.$controllerProvider#register $controllerProvider.register()}. + */ + controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'), + + /** + * @ngdoc method + * @name angular.Module#directive + * @module ng + * @param {string|Object} name Directive name, or an object map of directives where the + * keys are the names and the values are the factories. + * @param {Function} directiveFactory Factory function for creating new instance of + * directives. + * @description + * See {@link ng.$compileProvider#directive $compileProvider.directive()}. + */ + directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'), + + /** + * @ngdoc method + * @name angular.Module#component + * @module ng + * @param {string|Object} name Name of the component in camelCase (i.e. `myComp` which will match ``), + * or an object map of components where the keys are the names and the values are the component definition objects. + * @param {Object} options Component definition object (a simplified + * {@link ng.$compile#directive-definition-object directive definition object}) + * + * @description + * See {@link ng.$compileProvider#component $compileProvider.component()}. + */ + component: invokeLaterAndSetModuleName('$compileProvider', 'component'), + + /** + * @ngdoc method + * @name angular.Module#config + * @module ng + * @param {Function} configFn Execute this function on module load. Useful for service + * configuration. + * @description + * Use this method to configure services by injecting their + * {@link angular.Module#provider `providers`}, e.g. for adding routes to the + * {@link ngRoute.$routeProvider $routeProvider}. + * + * Note that you can only inject {@link angular.Module#provider `providers`} and + * {@link angular.Module#constant `constants`} into this function. + * + * For more about how to configure services, see + * {@link providers#provider-recipe Provider Recipe}. + */ + config: config, + + /** + * @ngdoc method + * @name angular.Module#run + * @module ng + * @param {Function} initializationFn Execute this function after injector creation. + * Useful for application initialization. + * @description + * Use this method to register work which should be performed when the injector is done + * loading all modules. + */ + run: function(block) { + runBlocks.push(block); + return this; + } + }; + + if (configFn) { + config(configFn); + } + + return moduleInstance; + + /** + * @param {string} provider + * @param {string} method + * @param {String=} insertMethod + * @returns {angular.Module} + */ + function invokeLater(provider, method, insertMethod, queue) { + if (!queue) queue = invokeQueue; + return function() { + queue[insertMethod || 'push']([provider, method, arguments]); + return moduleInstance; + }; + } + + /** + * @param {string} provider + * @param {string} method + * @returns {angular.Module} + */ + function invokeLaterAndSetModuleName(provider, method, queue) { + if (!queue) queue = invokeQueue; + return function(recipeName, factoryFunction) { + if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name; + queue.push([provider, method, arguments]); + return moduleInstance; + }; + } + }); + }; + }); + +} + +setupModuleLoader(window); +})(window); + +/** + * Closure compiler type information + * + * @typedef { { + * requires: !Array., + * invokeQueue: !Array.>, + * + * service: function(string, Function):angular.Module, + * factory: function(string, Function):angular.Module, + * value: function(string, *):angular.Module, + * + * filter: function(string, Function):angular.Module, + * + * init: function(Function):angular.Module + * } } + */ +angular.Module; + diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-loader/angular-loader.min.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-loader/angular-loader.min.js new file mode 100644 index 0000000..33ebe2d --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-loader/angular-loader.min.js @@ -0,0 +1,10 @@ +/* + AngularJS v1.8.0 + (c) 2010-2020 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(){'use strict';function g(a,f){f=f||Error;return function(){var d=arguments[0],e;e="["+(a?a+":":"")+d+"] http://errors.angularjs.org/1.8.0/"+(a?a+"/":"")+d;for(d=1;d=} actions Hash with declaration of custom actions that will be available + * in addition to the default set of resource actions (see below). If a custom action has the same + * key as a default action (e.g. `save`), then the default action will be *overwritten*, and not + * extended. + * + * The declaration should be created in the format of {@link ng.$http#usage $http.config}: + * + * { + * action1: {method:?, params:?, isArray:?, headers:?, ...}, + * action2: {method:?, params:?, isArray:?, headers:?, ...}, + * ... + * } + * + * Where: + * + * - **`action`** – {string} – The name of action. This name becomes the name of the method on + * your resource object. + * - **`method`** – {string} – Case insensitive HTTP method (e.g. `GET`, `POST`, `PUT`, + * `DELETE`, `JSONP`, etc). + * - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of + * the parameter value is a function, it will be called every time when a param value needs to + * be obtained for a request (unless the param was overridden). The function will be passed the + * current data value as an argument. + * - **`url`** – {string} – Action specific `url` override. The url templating is supported just + * like for the resource-level urls. + * - **`isArray`** – {boolean=} – If true then the returned object for this action is an array, + * see `returns` section. + * - **`transformRequest`** – + * `{function(data, headersGetter)|Array.}` – + * Transform function or an array of such functions. The transform function takes the http + * request body and headers and returns its transformed (typically serialized) version. + * By default, transformRequest will contain one function that checks if the request data is + * an object and serializes it using `angular.toJson`. To prevent this behavior, set + * `transformRequest` to an empty array: `transformRequest: []` + * - **`transformResponse`** – + * `{function(data, headersGetter, status)|Array.}` – + * Transform function or an array of such functions. The transform function takes the HTTP + * response body, headers and status and returns its transformed (typically deserialized) + * version. + * By default, transformResponse will contain one function that checks if the response looks + * like a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior, + * set `transformResponse` to an empty array: `transformResponse: []` + * - **`cache`** – `{boolean|Cache}` – A boolean value or object created with + * {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of the HTTP response. + * See {@link $http#caching $http Caching} for more information. + * - **`timeout`** – `{number}` – Timeout in milliseconds.
      + * **Note:** In contrast to {@link ng.$http#usage $http.config}, {@link ng.$q promises} are + * **not** supported in `$resource`, because the same value would be used for multiple requests. + * If you are looking for a way to cancel requests, you should use the `cancellable` option. + * - **`cancellable`** – `{boolean}` – If true, the request made by a "non-instance" call will be + * cancelled (if not already completed) by calling `$cancelRequest()` on the call's return + * value. Calling `$cancelRequest()` for a non-cancellable or an already completed/cancelled + * request will have no effect. + * - **`withCredentials`** – `{boolean}` – Whether to set the `withCredentials` flag on the + * XHR object. See + * [XMLHttpRequest.withCredentials](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials) + * for more information. + * - **`responseType`** – `{string}` – See + * [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType). + * - **`interceptor`** – `{Object=}` – The interceptor object has four optional methods - + * `request`, `requestError`, `response`, and `responseError`. See + * {@link ng.$http#interceptors $http interceptors} for details. Note that + * `request`/`requestError` interceptors are applied before calling `$http`, thus before any + * global `$http` interceptors. Also, rejecting or throwing an error inside the `request` + * interceptor will result in calling the `responseError` interceptor. + * The resource instance or collection is available on the `resource` property of the + * `http response` object passed to `response`/`responseError` interceptors. + * Keep in mind that the associated promise will be resolved with the value returned by the + * response interceptors. Make sure you return an appropriate value and not the `response` + * object passed as input. For reference, the default `response` interceptor (which gets applied + * if you don't specify a custom one) returns `response.resource`.
      + * See {@link ngResource.$resource#using-interceptors below} for an example of using + * interceptors in `$resource`. + * - **`hasBody`** – `{boolean}` – If true, then the request will have a body. + * If not specified, then only POST, PUT and PATCH requests will have a body. * + * @param {Object} options Hash with custom settings that should extend the + * default `$resourceProvider` behavior. The supported options are: + * + * - **`stripTrailingSlashes`** – {boolean} – If true then the trailing + * slashes from any calculated URL will be stripped. (Defaults to true.) + * - **`cancellable`** – {boolean} – If true, the request made by a "non-instance" call will be + * cancelled (if not already completed) by calling `$cancelRequest()` on the call's return value. + * This can be overwritten per action. (Defaults to false.) + * + * @returns {Object} A resource "class" object with methods for the default set of resource actions + * optionally extended with custom `actions`. The default set contains these actions: + * ```js + * { + * 'get': {method: 'GET'}, + * 'save': {method: 'POST'}, + * 'query': {method: 'GET', isArray: true}, + * 'remove': {method: 'DELETE'}, + * 'delete': {method: 'DELETE'} + * } + * ``` + * + * Calling these methods invoke {@link ng.$http} with the specified http method, destination and + * parameters. When the data is returned from the server then the object is an instance of the + * resource class. The actions `save`, `remove` and `delete` are available on it as methods with + * the `$` prefix. This allows you to easily perform CRUD operations (create, read, update, + * delete) on server-side data like this: + * ```js + * var User = $resource('/user/:userId', {userId: '@id'}); + * User.get({userId: 123}).$promise.then(function(user) { + * user.abc = true; + * user.$save(); + * }); + * ``` + * + * It is important to realize that invoking a `$resource` object method immediately returns an + * empty reference (object or array depending on `isArray`). Once the data is returned from the + * server the existing reference is populated with the actual data. This is a useful trick since + * usually the resource is assigned to a model which is then rendered by the view. Having an empty + * object results in no rendering, once the data arrives from the server then the object is + * populated with the data and the view automatically re-renders itself showing the new data. This + * means that in most cases one never has to write a callback function for the action methods. + * + * The action methods on the class object or instance object can be invoked with the following + * parameters: + * + * - "class" actions without a body: `Resource.action([parameters], [success], [error])` + * - "class" actions with a body: `Resource.action([parameters], postData, [success], [error])` + * - instance actions: `instance.$action([parameters], [success], [error])` + * + * + * When calling instance methods, the instance itself is used as the request body (if the action + * should have a body). By default, only actions using `POST`, `PUT` or `PATCH` have request + * bodies, but you can use the `hasBody` configuration option to specify whether an action + * should have a body or not (regardless of its HTTP method). + * + * + * Success callback is called with (value (Object|Array), responseHeaders (Function), + * status (number), statusText (string)) arguments, where `value` is the populated resource + * instance or collection object. The error callback is called with (httpResponse) argument. + * + * Class actions return an empty instance (with the additional properties listed below). + * Instance actions return a promise for the operation. + * + * The Resource instances and collections have these additional properties: + * + * - `$promise`: The {@link ng.$q promise} of the original server interaction that created this + * instance or collection. + * + * On success, the promise is resolved with the same resource instance or collection object, + * updated with data from server. This makes it easy to use in the + * {@link ngRoute.$routeProvider `resolve` section of `$routeProvider.when()`} to defer view + * rendering until the resource(s) are loaded. + * + * On failure, the promise is rejected with the {@link ng.$http http response} object. + * + * If an interceptor object was provided, the promise will instead be resolved with the value + * returned by the response interceptor (on success) or responceError interceptor (on failure). + * + * - `$resolved`: `true` after first server interaction is completed (either with success or + * rejection), `false` before that. Knowing if the Resource has been resolved is useful in + * data-binding. If there is a response/responseError interceptor and it returns a promise, + * `$resolved` will wait for that too. + * + * The Resource instances and collections have these additional methods: + * + * - `$cancelRequest`: If there is a cancellable, pending request related to the instance or + * collection, calling this method will abort the request. + * + * The Resource instances have these additional methods: + * + * - `toJSON`: It returns a simple object without any of the extra properties added as part of + * the Resource API. This object can be serialized through {@link angular.toJson} safely + * without attaching AngularJS-specific fields. Notice that `JSON.stringify` (and + * `angular.toJson`) automatically use this method when serializing a Resource instance + * (see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON%28%29_behavior)). + * + * @example + * + * ### Basic usage + * + ```js + // Define a CreditCard class + var CreditCard = $resource('/users/:userId/cards/:cardId', + {userId: 123, cardId: '@id'}, { + charge: {method: 'POST', params: {charge: true}} + }); + + // We can retrieve a collection from the server + var cards = CreditCard.query(); + // GET: /users/123/cards + // server returns: [{id: 456, number: '1234', name: 'Smith'}] + + // Wait for the request to complete + cards.$promise.then(function() { + var card = cards[0]; + + // Each item is an instance of CreditCard + expect(card instanceof CreditCard).toEqual(true); + + // Non-GET methods are mapped onto the instances + card.name = 'J. Smith'; + card.$save(); + // POST: /users/123/cards/456 {id: 456, number: '1234', name: 'J. Smith'} + // server returns: {id: 456, number: '1234', name: 'J. Smith'} + + // Our custom method is mapped as well (since it uses POST) + card.$charge({amount: 9.99}); + // POST: /users/123/cards/456?amount=9.99&charge=true {id: 456, number: '1234', name: 'J. Smith'} + }); + + // We can create an instance as well + var newCard = new CreditCard({number: '0123'}); + newCard.name = 'Mike Smith'; + + var savePromise = newCard.$save(); + // POST: /users/123/cards {number: '0123', name: 'Mike Smith'} + // server returns: {id: 789, number: '0123', name: 'Mike Smith'} + + savePromise.then(function() { + // Once the promise is resolved, the created instance + // is populated with the data returned by the server + expect(newCard.id).toEqual(789); + }); + ``` + * + * The object returned from a call to `$resource` is a resource "class" which has one "static" + * method for each action in the definition. + * + * Calling these methods invokes `$http` on the `url` template with the given HTTP `method`, + * `params` and `headers`. + * + * @example + * + * ### Accessing the response + * + * When the data is returned from the server then the object is an instance of the resource type and + * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD + * operations (create, read, update, delete) on server-side data. + * + ```js + var User = $resource('/users/:userId', {userId: '@id'}); + User.get({userId: 123}).$promise.then(function(user) { + user.abc = true; + user.$save(); + }); + ``` + * + * It's worth noting that the success callback for `get`, `query` and other methods gets called with + * the resource instance (populated with the data that came from the server) as well as an `$http` + * header getter function, the HTTP status code and the response status text. So one could rewrite + * the above example and get access to HTTP headers as follows: + * + ```js + var User = $resource('/users/:userId', {userId: '@id'}); + User.get({userId: 123}, function(user, getResponseHeaders) { + user.abc = true; + user.$save(function(user, putResponseHeaders) { + // `user` => saved `User` object + // `putResponseHeaders` => `$http` header getter + }); + }); + ``` + * + * @example + * + * ### Creating custom actions + * + * In this example we create a custom method on our resource to make a PUT request: + * + ```js + var app = angular.module('app', ['ngResource']); + + // Some APIs expect a PUT request in the format URL/object/ID + // Here we are creating an 'update' method + app.factory('Notes', ['$resource', function($resource) { + return $resource('/notes/:id', {id: '@id'}, { + update: {method: 'PUT'} + }); + }]); + + // In our controller we get the ID from the URL using `$location` + app.controller('NotesCtrl', ['$location', 'Notes', function($location, Notes) { + // First, retrieve the corresponding `Note` object from the server + // (Assuming a URL of the form `.../notes?id=XYZ`) + var noteId = $location.search().id; + var note = Notes.get({id: noteId}); + + note.$promise.then(function() { + note.content = 'Hello, world!'; + + // Now call `update` to save the changes on the server + Notes.update(note); + // This will PUT /notes/ID with the note object as the request payload + + // Since `update` is a non-GET method, it will also be available on the instance + // (prefixed with `$`), so we could replace the `Note.update()` call with: + //note.$update(); + }); + }]); + ``` + * + * @example + * + * ### Cancelling requests + * + * If an action's configuration specifies that it is cancellable, you can cancel the request related + * to an instance or collection (as long as it is a result of a "non-instance" call): + * + ```js + // ...defining the `Hotel` resource... + var Hotel = $resource('/api/hotels/:id', {id: '@id'}, { + // Let's make the `query()` method cancellable + query: {method: 'get', isArray: true, cancellable: true} + }); + + // ...somewhere in the PlanVacationController... + ... + this.onDestinationChanged = function onDestinationChanged(destination) { + // We don't care about any pending request for hotels + // in a different destination any more + if (this.availableHotels) { + this.availableHotels.$cancelRequest(); + } + + // Let's query for hotels in `destination` + // (calls: /api/hotels?location=) + this.availableHotels = Hotel.query({location: destination}); + }; + ``` + * + * @example + * + * ### Using interceptors + * + * You can use interceptors to transform the request or response, perform additional operations, and + * modify the returned instance/collection. The following example, uses `request` and `response` + * interceptors to augment the returned instance with additional info: + * + ```js + var Thing = $resource('/api/things/:id', {id: '@id'}, { + save: { + method: 'POST', + interceptor: { + request: function(config) { + // Before the request is sent out, store a timestamp on the request config + config.requestTimestamp = Date.now(); + return config; + }, + response: function(response) { + // Get the instance from the response object + var instance = response.resource; + + // Augment the instance with a custom `saveLatency` property, computed as the time + // between sending the request and receiving the response. + instance.saveLatency = Date.now() - response.config.requestTimestamp; + + // Return the instance + return instance; + } + } + } + }); + + Thing.save({foo: 'bar'}).$promise.then(function(thing) { + console.log('That thing was saved in ' + thing.saveLatency + 'ms.'); + }); + ``` + * + */ +angular.module('ngResource', ['ng']). + info({ angularVersion: '1.8.0' }). + provider('$resource', function ResourceProvider() { + var PROTOCOL_AND_IPV6_REGEX = /^https?:\/\/\[[^\]]*][^/]*/; + + var provider = this; + + /** + * @ngdoc property + * @name $resourceProvider#defaults + * @description + * Object containing default options used when creating `$resource` instances. + * + * The default values satisfy a wide range of usecases, but you may choose to overwrite any of + * them to further customize your instances. The available properties are: + * + * - **stripTrailingSlashes** – `{boolean}` – If true, then the trailing slashes from any + * calculated URL will be stripped.
      + * (Defaults to true.) + * - **cancellable** – `{boolean}` – If true, the request made by a "non-instance" call will be + * cancelled (if not already completed) by calling `$cancelRequest()` on the call's return + * value. For more details, see {@link ngResource.$resource}. This can be overwritten per + * resource class or action.
      + * (Defaults to false.) + * - **actions** - `{Object.}` - A hash with default actions declarations. Actions are + * high-level methods corresponding to RESTful actions/methods on resources. An action may + * specify what HTTP method to use, what URL to hit, if the return value will be a single + * object or a collection (array) of objects etc. For more details, see + * {@link ngResource.$resource}. The actions can also be enhanced or overwritten per resource + * class.
      + * The default actions are: + * ```js + * { + * get: {method: 'GET'}, + * save: {method: 'POST'}, + * query: {method: 'GET', isArray: true}, + * remove: {method: 'DELETE'}, + * delete: {method: 'DELETE'} + * } + * ``` + * + * #### Example + * + * For example, you can specify a new `update` action that uses the `PUT` HTTP verb: + * + * ```js + * angular. + * module('myApp'). + * config(['$resourceProvider', function ($resourceProvider) { + * $resourceProvider.defaults.actions.update = { + * method: 'PUT' + * }; + * }]); + * ``` + * + * Or you can even overwrite the whole `actions` list and specify your own: + * + * ```js + * angular. + * module('myApp'). + * config(['$resourceProvider', function ($resourceProvider) { + * $resourceProvider.defaults.actions = { + * create: {method: 'POST'}, + * get: {method: 'GET'}, + * getAll: {method: 'GET', isArray:true}, + * update: {method: 'PUT'}, + * delete: {method: 'DELETE'} + * }; + * }); + * ``` + * + */ + this.defaults = { + // Strip slashes by default + stripTrailingSlashes: true, + + // Make non-instance requests cancellable (via `$cancelRequest()`) + cancellable: false, + + // Default actions configuration + actions: { + 'get': {method: 'GET'}, + 'save': {method: 'POST'}, + 'query': {method: 'GET', isArray: true}, + 'remove': {method: 'DELETE'}, + 'delete': {method: 'DELETE'} + } + }; + + this.$get = ['$http', '$log', '$q', '$timeout', function($http, $log, $q, $timeout) { + + var noop = angular.noop, + forEach = angular.forEach, + extend = angular.extend, + copy = angular.copy, + isArray = angular.isArray, + isDefined = angular.isDefined, + isFunction = angular.isFunction, + isNumber = angular.isNumber, + encodeUriQuery = angular.$$encodeUriQuery, + encodeUriSegment = angular.$$encodeUriSegment; + + function Route(template, defaults) { + this.template = template; + this.defaults = extend({}, provider.defaults, defaults); + this.urlParams = {}; + } + + Route.prototype = { + setUrlParams: function(config, params, actionUrl) { + var self = this, + url = actionUrl || self.template, + val, + encodedVal, + protocolAndIpv6 = ''; + + var urlParams = self.urlParams = Object.create(null); + forEach(url.split(/\W/), function(param) { + if (param === 'hasOwnProperty') { + throw $resourceMinErr('badname', 'hasOwnProperty is not a valid parameter name.'); + } + if (!(new RegExp('^\\d+$').test(param)) && param && + (new RegExp('(^|[^\\\\]):' + param + '(\\W|$)').test(url))) { + urlParams[param] = { + isQueryParamValue: (new RegExp('\\?.*=:' + param + '(?:\\W|$)')).test(url) + }; + } + }); + url = url.replace(/\\:/g, ':'); + url = url.replace(PROTOCOL_AND_IPV6_REGEX, function(match) { + protocolAndIpv6 = match; + return ''; + }); + + params = params || {}; + forEach(self.urlParams, function(paramInfo, urlParam) { + val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam]; + if (isDefined(val) && val !== null) { + if (paramInfo.isQueryParamValue) { + encodedVal = encodeUriQuery(val, true); + } else { + encodedVal = encodeUriSegment(val); + } + url = url.replace(new RegExp(':' + urlParam + '(\\W|$)', 'g'), function(match, p1) { + return encodedVal + p1; + }); + } else { + url = url.replace(new RegExp('(/?):' + urlParam + '(\\W|$)', 'g'), function(match, + leadingSlashes, tail) { + if (tail.charAt(0) === '/') { + return tail; + } else { + return leadingSlashes + tail; + } + }); + } + }); + + // strip trailing slashes and set the url (unless this behavior is specifically disabled) + if (self.defaults.stripTrailingSlashes) { + url = url.replace(/\/+$/, '') || '/'; + } + + // Collapse `/.` if found in the last URL path segment before the query. + // E.g. `http://url.com/id/.format?q=x` becomes `http://url.com/id.format?q=x`. + url = url.replace(/\/\.(?=\w+($|\?))/, '.'); + // Replace escaped `/\.` with `/.`. + // (If `\.` comes from a param value, it will be encoded as `%5C.`.) + config.url = protocolAndIpv6 + url.replace(/\/(\\|%5C)\./, '/.'); + + + // set params - delegate param encoding to $http + forEach(params, function(value, key) { + if (!self.urlParams[key]) { + config.params = config.params || {}; + config.params[key] = value; + } + }); + } + }; + + + function resourceFactory(url, paramDefaults, actions, options) { + var route = new Route(url, options); + + actions = extend({}, provider.defaults.actions, actions); + + function extractParams(data, actionParams) { + var ids = {}; + actionParams = extend({}, paramDefaults, actionParams); + forEach(actionParams, function(value, key) { + if (isFunction(value)) { value = value(data); } + ids[key] = value && value.charAt && value.charAt(0) === '@' ? + lookupDottedPath(data, value.substr(1)) : value; + }); + return ids; + } + + function defaultResponseInterceptor(response) { + return response.resource; + } + + function Resource(value) { + shallowClearAndCopy(value || {}, this); + } + + Resource.prototype.toJSON = function() { + var data = extend({}, this); + delete data.$promise; + delete data.$resolved; + delete data.$cancelRequest; + return data; + }; + + forEach(actions, function(action, name) { + var hasBody = action.hasBody === true || (action.hasBody !== false && /^(POST|PUT|PATCH)$/i.test(action.method)); + var numericTimeout = action.timeout; + var cancellable = isDefined(action.cancellable) ? + action.cancellable : route.defaults.cancellable; + + if (numericTimeout && !isNumber(numericTimeout)) { + $log.debug('ngResource:\n' + + ' Only numeric values are allowed as `timeout`.\n' + + ' Promises are not supported in $resource, because the same value would ' + + 'be used for multiple requests. If you are looking for a way to cancel ' + + 'requests, you should use the `cancellable` option.'); + delete action.timeout; + numericTimeout = null; + } + + Resource[name] = function(a1, a2, a3, a4) { + var params = {}, data, onSuccess, onError; + + switch (arguments.length) { + case 4: + onError = a4; + onSuccess = a3; + // falls through + case 3: + case 2: + if (isFunction(a2)) { + if (isFunction(a1)) { + onSuccess = a1; + onError = a2; + break; + } + + onSuccess = a2; + onError = a3; + // falls through + } else { + params = a1; + data = a2; + onSuccess = a3; + break; + } + // falls through + case 1: + if (isFunction(a1)) onSuccess = a1; + else if (hasBody) data = a1; + else params = a1; + break; + case 0: break; + default: + throw $resourceMinErr('badargs', + 'Expected up to 4 arguments [params, data, success, error], got {0} arguments', + arguments.length); + } + + var isInstanceCall = this instanceof Resource; + var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data)); + var httpConfig = {}; + var requestInterceptor = action.interceptor && action.interceptor.request || undefined; + var requestErrorInterceptor = action.interceptor && action.interceptor.requestError || + undefined; + var responseInterceptor = action.interceptor && action.interceptor.response || + defaultResponseInterceptor; + var responseErrorInterceptor = action.interceptor && action.interceptor.responseError || + $q.reject; + var successCallback = onSuccess ? function(val) { + onSuccess(val, response.headers, response.status, response.statusText); + } : undefined; + var errorCallback = onError || undefined; + var timeoutDeferred; + var numericTimeoutPromise; + var response; + + forEach(action, function(value, key) { + switch (key) { + default: + httpConfig[key] = copy(value); + break; + case 'params': + case 'isArray': + case 'interceptor': + case 'cancellable': + break; + } + }); + + if (!isInstanceCall && cancellable) { + timeoutDeferred = $q.defer(); + httpConfig.timeout = timeoutDeferred.promise; + + if (numericTimeout) { + numericTimeoutPromise = $timeout(timeoutDeferred.resolve, numericTimeout); + } + } + + if (hasBody) httpConfig.data = data; + route.setUrlParams(httpConfig, + extend({}, extractParams(data, action.params || {}), params), + action.url); + + // Start the promise chain + var promise = $q. + resolve(httpConfig). + then(requestInterceptor). + catch(requestErrorInterceptor). + then($http); + + promise = promise.then(function(resp) { + var data = resp.data; + + if (data) { + // Need to convert action.isArray to boolean in case it is undefined + if (isArray(data) !== (!!action.isArray)) { + throw $resourceMinErr('badcfg', + 'Error in resource configuration for action `{0}`. Expected response to ' + + 'contain an {1} but got an {2} (Request: {3} {4})', name, action.isArray ? 'array' : 'object', + isArray(data) ? 'array' : 'object', httpConfig.method, httpConfig.url); + } + if (action.isArray) { + value.length = 0; + forEach(data, function(item) { + if (typeof item === 'object') { + value.push(new Resource(item)); + } else { + // Valid JSON values may be string literals, and these should not be converted + // into objects. These items will not have access to the Resource prototype + // methods, but unfortunately there + value.push(item); + } + }); + } else { + var promise = value.$promise; // Save the promise + shallowClearAndCopy(data, value); + value.$promise = promise; // Restore the promise + } + } + + resp.resource = value; + response = resp; + return responseInterceptor(resp); + }, function(rejectionOrResponse) { + rejectionOrResponse.resource = value; + response = rejectionOrResponse; + return responseErrorInterceptor(rejectionOrResponse); + }); + + promise = promise['finally'](function() { + value.$resolved = true; + if (!isInstanceCall && cancellable) { + value.$cancelRequest = noop; + $timeout.cancel(numericTimeoutPromise); + timeoutDeferred = numericTimeoutPromise = httpConfig.timeout = null; + } + }); + + // Run the `success`/`error` callbacks, but do not let them affect the returned promise. + promise.then(successCallback, errorCallback); + + if (!isInstanceCall) { + // we are creating instance / collection + // - set the initial promise + // - return the instance / collection + value.$promise = promise; + value.$resolved = false; + if (cancellable) value.$cancelRequest = cancelRequest; + + return value; + } + + // instance call + return promise; + + function cancelRequest(value) { + promise.catch(noop); + if (timeoutDeferred !== null) { + timeoutDeferred.resolve(value); + } + } + }; + + + Resource.prototype['$' + name] = function(params, success, error) { + if (isFunction(params)) { + error = success; success = params; params = {}; + } + var result = Resource[name].call(this, params, this, success, error); + return result.$promise || result; + }; + }); + + return Resource; + } + + return resourceFactory; + }]; + }); + + +})(window, window.angular); diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-resource/angular-resource.min.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-resource/angular-resource.min.js new file mode 100644 index 0000000..2679cad --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-resource/angular-resource.min.js @@ -0,0 +1,15 @@ +/* + AngularJS v1.8.0 + (c) 2010-2020 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(T,a){'use strict';function M(m,f){f=f||{};a.forEach(f,function(a,d){delete f[d]});for(var d in m)!m.hasOwnProperty(d)||"$"===d.charAt(0)&&"$"===d.charAt(1)||(f[d]=m[d]);return f}var B=a.$$minErr("$resource"),H=/^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;a.module("ngResource",["ng"]).info({angularVersion:"1.8.0"}).provider("$resource",function(){var m=/^https?:\/\/\[[^\]]*][^/]*/,f=this;this.defaults={stripTrailingSlashes:!0,cancellable:!1,actions:{get:{method:"GET"},save:{method:"POST"},query:{method:"GET", +isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}}};this.$get=["$http","$log","$q","$timeout",function(d,F,G,N){function C(a,d){this.template=a;this.defaults=n({},f.defaults,d);this.urlParams={}}var O=a.noop,r=a.forEach,n=a.extend,R=a.copy,P=a.isArray,D=a.isDefined,x=a.isFunction,I=a.isNumber,y=a.$$encodeUriQuery,S=a.$$encodeUriSegment;C.prototype={setUrlParams:function(a,d,f){var g=this,c=f||g.template,s,h,n="",b=g.urlParams=Object.create(null);r(c.split(/\W/),function(a){if("hasOwnProperty"=== +a)throw B("badname");!/^\d+$/.test(a)&&a&&(new RegExp("(^|[^\\\\]):"+a+"(\\W|$)")).test(c)&&(b[a]={isQueryParamValue:(new RegExp("\\?.*=:"+a+"(?:\\W|$)")).test(c)})});c=c.replace(/\\:/g,":");c=c.replace(m,function(b){n=b;return""});d=d||{};r(g.urlParams,function(b,a){s=d.hasOwnProperty(a)?d[a]:g.defaults[a];D(s)&&null!==s?(h=b.isQueryParamValue?y(s,!0):S(s),c=c.replace(new RegExp(":"+a+"(\\W|$)","g"),function(b,a){return h+a})):c=c.replace(new RegExp("(/?):"+a+"(\\W|$)","g"),function(b,a,e){return"/"=== +e.charAt(0)?e:a+e})});g.defaults.stripTrailingSlashes&&(c=c.replace(/\/+$/,"")||"/");c=c.replace(/\/\.(?=\w+($|\?))/,".");a.url=n+c.replace(/\/(\\|%5C)\./,"/.");r(d,function(b,c){g.urlParams[c]||(a.params=a.params||{},a.params[c]=b)})}};return function(m,y,z,g){function c(b,c){var d={};c=n({},y,c);r(c,function(c,f){x(c)&&(c=c(b));var e;if(c&&c.charAt&&"@"===c.charAt(0)){e=b;var k=c.substr(1);if(null==k||""===k||"hasOwnProperty"===k||!H.test("."+k))throw B("badmember",k);for(var k=k.split("."),h=0, +n=k.length;h}` - route parameters extracted from the current + * `$location.path()` by applying the current route + * + * One of `template` or `templateUrl` is required. + * + * - `templateUrl` – `{(string|Function)=}` – path or function that returns a path to an html + * template that should be used by {@link ngRoute.directive:ngView ngView}. + * + * If `templateUrl` is a function, it will be called with the following parameters: + * + * - `{Array.}` - route parameters extracted from the current + * `$location.path()` by applying the current route + * + * One of `templateUrl` or `template` is required. + * + * - `resolve` - `{Object.=}` - An optional map of dependencies which should + * be injected into the controller. If any of these dependencies are promises, the router + * will wait for them all to be resolved or one to be rejected before the controller is + * instantiated. + * If all the promises are resolved successfully, the values of the resolved promises are + * injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is + * fired. If any of the promises are rejected the + * {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired. + * For easier access to the resolved dependencies from the template, the `resolve` map will + * be available on the scope of the route, under `$resolve` (by default) or a custom name + * specified by the `resolveAs` property (see below). This can be particularly useful, when + * working with {@link angular.Module#component components} as route templates.
      + *
      + * **Note:** If your scope already contains a property with this name, it will be hidden + * or overwritten. Make sure, you specify an appropriate name for this property, that + * does not collide with other properties on the scope. + *
      + * The map object is: + * + * - `key` – `{string}`: a name of a dependency to be injected into the controller. + * - `factory` - `{string|Function}`: If `string` then it is an alias for a service. + * Otherwise if function, then it is {@link auto.$injector#invoke injected} + * and the return value is treated as the dependency. If the result is a promise, it is + * resolved before its value is injected into the controller. Be aware that + * `ngRoute.$routeParams` will still refer to the previous route within these resolve + * functions. Use `$route.current.params` to access the new route parameters, instead. + * + * - `resolveAs` - `{string=}` - The name under which the `resolve` map will be available on + * the scope of the route. If omitted, defaults to `$resolve`. + * + * - `redirectTo` – `{(string|Function)=}` – value to update + * {@link ng.$location $location} path with and trigger route redirection. + * + * If `redirectTo` is a function, it will be called with the following parameters: + * + * - `{Object.}` - route parameters extracted from the current + * `$location.path()` by applying the current route templateUrl. + * - `{string}` - current `$location.path()` + * - `{Object}` - current `$location.search()` + * + * The custom `redirectTo` function is expected to return a string which will be used + * to update `$location.url()`. If the function throws an error, no further processing will + * take place and the {@link ngRoute.$route#$routeChangeError $routeChangeError} event will + * be fired. + * + * Routes that specify `redirectTo` will not have their controllers, template functions + * or resolves called, the `$location` will be changed to the redirect url and route + * processing will stop. The exception to this is if the `redirectTo` is a function that + * returns `undefined`. In this case the route transition occurs as though there was no + * redirection. + * + * - `resolveRedirectTo` – `{Function=}` – a function that will (eventually) return the value + * to update {@link ng.$location $location} URL with and trigger route redirection. In + * contrast to `redirectTo`, dependencies can be injected into `resolveRedirectTo` and the + * return value can be either a string or a promise that will be resolved to a string. + * + * Similar to `redirectTo`, if the return value is `undefined` (or a promise that gets + * resolved to `undefined`), no redirection takes place and the route transition occurs as + * though there was no redirection. + * + * If the function throws an error or the returned promise gets rejected, no further + * processing will take place and the + * {@link ngRoute.$route#$routeChangeError $routeChangeError} event will be fired. + * + * `redirectTo` takes precedence over `resolveRedirectTo`, so specifying both on the same + * route definition, will cause the latter to be ignored. + * + * - `[reloadOnUrl=true]` - `{boolean=}` - reload route when any part of the URL changes + * (including the path) even if the new URL maps to the same route. + * + * If the option is set to `false` and the URL in the browser changes, but the new URL maps + * to the same route, then a `$routeUpdate` event is broadcasted on the root scope (without + * reloading the route). + * + * - `[reloadOnSearch=true]` - `{boolean=}` - reload route when only `$location.search()` + * or `$location.hash()` changes. + * + * If the option is set to `false` and the URL in the browser changes, then a `$routeUpdate` + * event is broadcasted on the root scope (without reloading the route). + * + *
      + * **Note:** This option has no effect if `reloadOnUrl` is set to `false`. + *
      + * + * - `[caseInsensitiveMatch=false]` - `{boolean=}` - match routes without being case sensitive + * + * If the option is set to `true`, then the particular route can be matched without being + * case sensitive + * + * @returns {Object} self + * + * @description + * Adds a new route definition to the `$route` service. + */ + this.when = function(path, route) { + //copy original route object to preserve params inherited from proto chain + var routeCopy = shallowCopy(route); + if (angular.isUndefined(routeCopy.reloadOnUrl)) { + routeCopy.reloadOnUrl = true; + } + if (angular.isUndefined(routeCopy.reloadOnSearch)) { + routeCopy.reloadOnSearch = true; + } + if (angular.isUndefined(routeCopy.caseInsensitiveMatch)) { + routeCopy.caseInsensitiveMatch = this.caseInsensitiveMatch; + } + routes[path] = angular.extend( + routeCopy, + {originalPath: path}, + path && routeToRegExp(path, routeCopy) + ); + + // create redirection for trailing slashes + if (path) { + var redirectPath = (path[path.length - 1] === '/') + ? path.substr(0, path.length - 1) + : path + '/'; + + routes[redirectPath] = angular.extend( + {originalPath: path, redirectTo: path}, + routeToRegExp(redirectPath, routeCopy) + ); + } + + return this; + }; + + /** + * @ngdoc property + * @name $routeProvider#caseInsensitiveMatch + * @description + * + * A boolean property indicating if routes defined + * using this provider should be matched using a case insensitive + * algorithm. Defaults to `false`. + */ + this.caseInsensitiveMatch = false; + + /** + * @ngdoc method + * @name $routeProvider#otherwise + * + * @description + * Sets route definition that will be used on route change when no other route definition + * is matched. + * + * @param {Object|string} params Mapping information to be assigned to `$route.current`. + * If called with a string, the value maps to `redirectTo`. + * @returns {Object} self + */ + this.otherwise = function(params) { + if (typeof params === 'string') { + params = {redirectTo: params}; + } + this.when(null, params); + return this; + }; + + /** + * @ngdoc method + * @name $routeProvider#eagerInstantiationEnabled + * @kind function + * + * @description + * Call this method as a setter to enable/disable eager instantiation of the + * {@link ngRoute.$route $route} service upon application bootstrap. You can also call it as a + * getter (i.e. without any arguments) to get the current value of the + * `eagerInstantiationEnabled` flag. + * + * Instantiating `$route` early is necessary for capturing the initial + * {@link ng.$location#$locationChangeStart $locationChangeStart} event and navigating to the + * appropriate route. Usually, `$route` is instantiated in time by the + * {@link ngRoute.ngView ngView} directive. Yet, in cases where `ngView` is included in an + * asynchronously loaded template (e.g. in another directive's template), the directive factory + * might not be called soon enough for `$route` to be instantiated _before_ the initial + * `$locationChangeSuccess` event is fired. Eager instantiation ensures that `$route` is always + * instantiated in time, regardless of when `ngView` will be loaded. + * + * The default value is true. + * + * **Note**:
      + * You may want to disable the default behavior when unit-testing modules that depend on + * `ngRoute`, in order to avoid an unexpected request for the default route's template. + * + * @param {boolean=} enabled - If provided, update the internal `eagerInstantiationEnabled` flag. + * + * @returns {*} The current value of the `eagerInstantiationEnabled` flag if used as a getter or + * itself (for chaining) if used as a setter. + */ + isEagerInstantiationEnabled = true; + this.eagerInstantiationEnabled = function eagerInstantiationEnabled(enabled) { + if (isDefined(enabled)) { + isEagerInstantiationEnabled = enabled; + return this; + } + + return isEagerInstantiationEnabled; + }; + + + this.$get = ['$rootScope', + '$location', + '$routeParams', + '$q', + '$injector', + '$templateRequest', + '$sce', + '$browser', + function($rootScope, $location, $routeParams, $q, $injector, $templateRequest, $sce, $browser) { + + /** + * @ngdoc service + * @name $route + * @requires $location + * @requires $routeParams + * + * @property {Object} current Reference to the current route definition. + * The route definition contains: + * + * - `controller`: The controller constructor as defined in the route definition. + * - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for + * controller instantiation. The `locals` contain + * the resolved values of the `resolve` map. Additionally the `locals` also contain: + * + * - `$scope` - The current route scope. + * - `$template` - The current route template HTML. + * + * The `locals` will be assigned to the route scope's `$resolve` property. You can override + * the property name, using `resolveAs` in the route definition. See + * {@link ngRoute.$routeProvider $routeProvider} for more info. + * + * @property {Object} routes Object with all route configuration Objects as its properties. + * + * @description + * `$route` is used for deep-linking URLs to controllers and views (HTML partials). + * It watches `$location.url()` and tries to map the path to an existing route definition. + * + * Requires the {@link ngRoute `ngRoute`} module to be installed. + * + * You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API. + * + * The `$route` service is typically used in conjunction with the + * {@link ngRoute.directive:ngView `ngView`} directive and the + * {@link ngRoute.$routeParams `$routeParams`} service. + * + * @example + * This example shows how changing the URL hash causes the `$route` to match a route against the + * URL, and the `ngView` pulls in the partial. + * + * + * + *
      + * Choose: + * Moby | + * Moby: Ch1 | + * Gatsby | + * Gatsby: Ch4 | + * Scarlet Letter
      + * + *
      + * + *
      + * + *
      $location.path() = {{$location.path()}}
      + *
      $route.current.templateUrl = {{$route.current.templateUrl}}
      + *
      $route.current.params = {{$route.current.params}}
      + *
      $route.current.scope.name = {{$route.current.scope.name}}
      + *
      $routeParams = {{$routeParams}}
      + *
      + *
      + * + * + * controller: {{name}}
      + * Book Id: {{params.bookId}}
      + *
      + * + * + * controller: {{name}}
      + * Book Id: {{params.bookId}}
      + * Chapter Id: {{params.chapterId}} + *
      + * + * + * angular.module('ngRouteExample', ['ngRoute']) + * + * .controller('MainController', function($scope, $route, $routeParams, $location) { + * $scope.$route = $route; + * $scope.$location = $location; + * $scope.$routeParams = $routeParams; + * }) + * + * .controller('BookController', function($scope, $routeParams) { + * $scope.name = 'BookController'; + * $scope.params = $routeParams; + * }) + * + * .controller('ChapterController', function($scope, $routeParams) { + * $scope.name = 'ChapterController'; + * $scope.params = $routeParams; + * }) + * + * .config(function($routeProvider, $locationProvider) { + * $routeProvider + * .when('/Book/:bookId', { + * templateUrl: 'book.html', + * controller: 'BookController', + * resolve: { + * // I will cause a 1 second delay + * delay: function($q, $timeout) { + * var delay = $q.defer(); + * $timeout(delay.resolve, 1000); + * return delay.promise; + * } + * } + * }) + * .when('/Book/:bookId/ch/:chapterId', { + * templateUrl: 'chapter.html', + * controller: 'ChapterController' + * }); + * + * // configure html5 to get links working on jsfiddle + * $locationProvider.html5Mode(true); + * }); + * + * + * + * + * it('should load and compile correct template', function() { + * element(by.linkText('Moby: Ch1')).click(); + * var content = element(by.css('[ng-view]')).getText(); + * expect(content).toMatch(/controller: ChapterController/); + * expect(content).toMatch(/Book Id: Moby/); + * expect(content).toMatch(/Chapter Id: 1/); + * + * element(by.partialLinkText('Scarlet')).click(); + * + * content = element(by.css('[ng-view]')).getText(); + * expect(content).toMatch(/controller: BookController/); + * expect(content).toMatch(/Book Id: Scarlet/); + * }); + * + *
      + */ + + /** + * @ngdoc event + * @name $route#$routeChangeStart + * @eventType broadcast on root scope + * @description + * Broadcasted before a route change. At this point the route services starts + * resolving all of the dependencies needed for the route change to occur. + * Typically this involves fetching the view template as well as any dependencies + * defined in `resolve` route property. Once all of the dependencies are resolved + * `$routeChangeSuccess` is fired. + * + * The route change (and the `$location` change that triggered it) can be prevented + * by calling `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} + * for more details about event object. + * + * @param {Object} angularEvent Synthetic event object. + * @param {Route} next Future route information. + * @param {Route} current Current route information. + */ + + /** + * @ngdoc event + * @name $route#$routeChangeSuccess + * @eventType broadcast on root scope + * @description + * Broadcasted after a route change has happened successfully. + * The `resolve` dependencies are now available in the `current.locals` property. + * + * {@link ngRoute.directive:ngView ngView} listens for the directive + * to instantiate the controller and render the view. + * + * @param {Object} angularEvent Synthetic event object. + * @param {Route} current Current route information. + * @param {Route|Undefined} previous Previous route information, or undefined if current is + * first route entered. + */ + + /** + * @ngdoc event + * @name $route#$routeChangeError + * @eventType broadcast on root scope + * @description + * Broadcasted if a redirection function fails or any redirection or resolve promises are + * rejected. + * + * @param {Object} angularEvent Synthetic event object + * @param {Route} current Current route information. + * @param {Route} previous Previous route information. + * @param {Route} rejection The thrown error or the rejection reason of the promise. Usually + * the rejection reason is the error that caused the promise to get rejected. + */ + + /** + * @ngdoc event + * @name $route#$routeUpdate + * @eventType broadcast on root scope + * @description + * Broadcasted if the same instance of a route (including template, controller instance, + * resolved dependencies, etc.) is being reused. This can happen if either `reloadOnSearch` or + * `reloadOnUrl` has been set to `false`. + * + * @param {Object} angularEvent Synthetic event object + * @param {Route} current Current/previous route information. + */ + + var forceReload = false, + preparedRoute, + preparedRouteIsUpdateOnly, + $route = { + routes: routes, + + /** + * @ngdoc method + * @name $route#reload + * + * @description + * Causes `$route` service to reload the current route even if + * {@link ng.$location $location} hasn't changed. + * + * As a result of that, {@link ngRoute.directive:ngView ngView} + * creates new scope and reinstantiates the controller. + */ + reload: function() { + forceReload = true; + + var fakeLocationEvent = { + defaultPrevented: false, + preventDefault: function fakePreventDefault() { + this.defaultPrevented = true; + forceReload = false; + } + }; + + $rootScope.$evalAsync(function() { + prepareRoute(fakeLocationEvent); + if (!fakeLocationEvent.defaultPrevented) commitRoute(); + }); + }, + + /** + * @ngdoc method + * @name $route#updateParams + * + * @description + * Causes `$route` service to update the current URL, replacing + * current route parameters with those specified in `newParams`. + * Provided property names that match the route's path segment + * definitions will be interpolated into the location's path, while + * remaining properties will be treated as query params. + * + * @param {!Object} newParams mapping of URL parameter names to values + */ + updateParams: function(newParams) { + if (this.current && this.current.$$route) { + newParams = angular.extend({}, this.current.params, newParams); + $location.path(interpolate(this.current.$$route.originalPath, newParams)); + // interpolate modifies newParams, only query params are left + $location.search(newParams); + } else { + throw $routeMinErr('norout', 'Tried updating route with no current route'); + } + } + }; + + $rootScope.$on('$locationChangeStart', prepareRoute); + $rootScope.$on('$locationChangeSuccess', commitRoute); + + return $route; + + ///////////////////////////////////////////////////// + + /** + * @param on {string} current url + * @param route {Object} route regexp to match the url against + * @return {?Object} + * + * @description + * Check if the route matches the current url. + * + * Inspired by match in + * visionmedia/express/lib/router/router.js. + */ + function switchRouteMatcher(on, route) { + var keys = route.keys, + params = {}; + + if (!route.regexp) return null; + + var m = route.regexp.exec(on); + if (!m) return null; + + for (var i = 1, len = m.length; i < len; ++i) { + var key = keys[i - 1]; + + var val = m[i]; + + if (key && val) { + params[key.name] = val; + } + } + return params; + } + + function prepareRoute($locationEvent) { + var lastRoute = $route.current; + + preparedRoute = parseRoute(); + preparedRouteIsUpdateOnly = isNavigationUpdateOnly(preparedRoute, lastRoute); + + if (!preparedRouteIsUpdateOnly && (lastRoute || preparedRoute)) { + if ($rootScope.$broadcast('$routeChangeStart', preparedRoute, lastRoute).defaultPrevented) { + if ($locationEvent) { + $locationEvent.preventDefault(); + } + } + } + } + + function commitRoute() { + var lastRoute = $route.current; + var nextRoute = preparedRoute; + + if (preparedRouteIsUpdateOnly) { + lastRoute.params = nextRoute.params; + angular.copy(lastRoute.params, $routeParams); + $rootScope.$broadcast('$routeUpdate', lastRoute); + } else if (nextRoute || lastRoute) { + forceReload = false; + $route.current = nextRoute; + + var nextRoutePromise = $q.resolve(nextRoute); + + $browser.$$incOutstandingRequestCount('$route'); + + nextRoutePromise. + then(getRedirectionData). + then(handlePossibleRedirection). + then(function(keepProcessingRoute) { + return keepProcessingRoute && nextRoutePromise. + then(resolveLocals). + then(function(locals) { + // after route change + if (nextRoute === $route.current) { + if (nextRoute) { + nextRoute.locals = locals; + angular.copy(nextRoute.params, $routeParams); + } + $rootScope.$broadcast('$routeChangeSuccess', nextRoute, lastRoute); + } + }); + }).catch(function(error) { + if (nextRoute === $route.current) { + $rootScope.$broadcast('$routeChangeError', nextRoute, lastRoute, error); + } + }).finally(function() { + // Because `commitRoute()` is called from a `$rootScope.$evalAsync` block (see + // `$locationWatch`), this `$$completeOutstandingRequest()` call will not cause + // `outstandingRequestCount` to hit zero. This is important in case we are redirecting + // to a new route which also requires some asynchronous work. + + $browser.$$completeOutstandingRequest(noop, '$route'); + }); + } + } + + function getRedirectionData(route) { + var data = { + route: route, + hasRedirection: false + }; + + if (route) { + if (route.redirectTo) { + if (angular.isString(route.redirectTo)) { + data.path = interpolate(route.redirectTo, route.params); + data.search = route.params; + data.hasRedirection = true; + } else { + var oldPath = $location.path(); + var oldSearch = $location.search(); + var newUrl = route.redirectTo(route.pathParams, oldPath, oldSearch); + + if (angular.isDefined(newUrl)) { + data.url = newUrl; + data.hasRedirection = true; + } + } + } else if (route.resolveRedirectTo) { + return $q. + resolve($injector.invoke(route.resolveRedirectTo)). + then(function(newUrl) { + if (angular.isDefined(newUrl)) { + data.url = newUrl; + data.hasRedirection = true; + } + + return data; + }); + } + } + + return data; + } + + function handlePossibleRedirection(data) { + var keepProcessingRoute = true; + + if (data.route !== $route.current) { + keepProcessingRoute = false; + } else if (data.hasRedirection) { + var oldUrl = $location.url(); + var newUrl = data.url; + + if (newUrl) { + $location. + url(newUrl). + replace(); + } else { + newUrl = $location. + path(data.path). + search(data.search). + replace(). + url(); + } + + if (newUrl !== oldUrl) { + // Exit out and don't process current next value, + // wait for next location change from redirect + keepProcessingRoute = false; + } + } + + return keepProcessingRoute; + } + + function resolveLocals(route) { + if (route) { + var locals = angular.extend({}, route.resolve); + angular.forEach(locals, function(value, key) { + locals[key] = angular.isString(value) ? + $injector.get(value) : + $injector.invoke(value, null, null, key); + }); + var template = getTemplateFor(route); + if (angular.isDefined(template)) { + locals['$template'] = template; + } + return $q.all(locals); + } + } + + function getTemplateFor(route) { + var template, templateUrl; + if (angular.isDefined(template = route.template)) { + if (angular.isFunction(template)) { + template = template(route.params); + } + } else if (angular.isDefined(templateUrl = route.templateUrl)) { + if (angular.isFunction(templateUrl)) { + templateUrl = templateUrl(route.params); + } + if (angular.isDefined(templateUrl)) { + route.loadedTemplateUrl = $sce.valueOf(templateUrl); + template = $templateRequest(templateUrl); + } + } + return template; + } + + /** + * @returns {Object} the current active route, by matching it against the URL + */ + function parseRoute() { + // Match a route + var params, match; + angular.forEach(routes, function(route, path) { + if (!match && (params = switchRouteMatcher($location.path(), route))) { + match = inherit(route, { + params: angular.extend({}, $location.search(), params), + pathParams: params}); + match.$$route = route; + } + }); + // No route matched; fallback to "otherwise" route + return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}}); + } + + /** + * @param {Object} newRoute - The new route configuration (as returned by `parseRoute()`). + * @param {Object} oldRoute - The previous route configuration (as returned by `parseRoute()`). + * @returns {boolean} Whether this is an "update-only" navigation, i.e. the URL maps to the same + * route and it can be reused (based on the config and the type of change). + */ + function isNavigationUpdateOnly(newRoute, oldRoute) { + // IF this is not a forced reload + return !forceReload + // AND both `newRoute`/`oldRoute` are defined + && newRoute && oldRoute + // AND they map to the same Route Definition Object + && (newRoute.$$route === oldRoute.$$route) + // AND `reloadOnUrl` is disabled + && (!newRoute.reloadOnUrl + // OR `reloadOnSearch` is disabled + || (!newRoute.reloadOnSearch + // AND both routes have the same path params + && angular.equals(newRoute.pathParams, oldRoute.pathParams) + ) + ); + } + + /** + * @returns {string} interpolation of the redirect path with the parameters + */ + function interpolate(string, params) { + var result = []; + angular.forEach((string || '').split(':'), function(segment, i) { + if (i === 0) { + result.push(segment); + } else { + var segmentMatch = segment.match(/(\w+)(?:[?*])?(.*)/); + var key = segmentMatch[1]; + result.push(params[key]); + result.push(segmentMatch[2] || ''); + delete params[key]; + } + }); + return result.join(''); + } + }]; +} + +instantiateRoute.$inject = ['$injector']; +function instantiateRoute($injector) { + if (isEagerInstantiationEnabled) { + // Instantiate `$route` + $injector.get('$route'); + } +} + +ngRouteModule.provider('$routeParams', $RouteParamsProvider); + + +/** + * @ngdoc service + * @name $routeParams + * @requires $route + * @this + * + * @description + * The `$routeParams` service allows you to retrieve the current set of route parameters. + * + * Requires the {@link ngRoute `ngRoute`} module to be installed. + * + * The route parameters are a combination of {@link ng.$location `$location`}'s + * {@link ng.$location#search `search()`} and {@link ng.$location#path `path()`}. + * The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched. + * + * In case of parameter name collision, `path` params take precedence over `search` params. + * + * The service guarantees that the identity of the `$routeParams` object will remain unchanged + * (but its properties will likely change) even when a route change occurs. + * + * Note that the `$routeParams` are only updated *after* a route change completes successfully. + * This means that you cannot rely on `$routeParams` being correct in route resolve functions. + * Instead you can use `$route.current.params` to access the new route's parameters. + * + * @example + * ```js + * // Given: + * // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby + * // Route: /Chapter/:chapterId/Section/:sectionId + * // + * // Then + * $routeParams ==> {chapterId:'1', sectionId:'2', search:'moby'} + * ``` + */ +function $RouteParamsProvider() { + this.$get = function() { return {}; }; +} + +ngRouteModule.directive('ngView', ngViewFactory); +ngRouteModule.directive('ngView', ngViewFillContentFactory); + + +/** + * @ngdoc directive + * @name ngView + * @restrict ECA + * + * @description + * `ngView` is a directive that complements the {@link ngRoute.$route $route} service by + * including the rendered template of the current route into the main layout (`index.html`) file. + * Every time the current route changes, the included view changes with it according to the + * configuration of the `$route` service. + * + * Requires the {@link ngRoute `ngRoute`} module to be installed. + * + * @animations + * | Animation | Occurs | + * |----------------------------------|-------------------------------------| + * | {@link ng.$animate#enter enter} | when the new element is inserted to the DOM | + * | {@link ng.$animate#leave leave} | when the old element is removed from to the DOM | + * + * The enter and leave animation occur concurrently. + * + * @scope + * @priority 400 + * @param {string=} onload Expression to evaluate whenever the view updates. + * + * @param {string=} autoscroll Whether `ngView` should call {@link ng.$anchorScroll + * $anchorScroll} to scroll the viewport after the view is updated. + * + * - If the attribute is not set, disable scrolling. + * - If the attribute is set without value, enable scrolling. + * - Otherwise enable scrolling only if the `autoscroll` attribute value evaluated + * as an expression yields a truthy value. + * @example + + +
      + Choose: + Moby | + Moby: Ch1 | + Gatsby | + Gatsby: Ch4 | + Scarlet Letter
      + +
      +
      +
      +
      + +
      $location.path() = {{main.$location.path()}}
      +
      $route.current.templateUrl = {{main.$route.current.templateUrl}}
      +
      $route.current.params = {{main.$route.current.params}}
      +
      $routeParams = {{main.$routeParams}}
      +
      +
      + + +
      + controller: {{book.name}}
      + Book Id: {{book.params.bookId}}
      +
      +
      + + +
      + controller: {{chapter.name}}
      + Book Id: {{chapter.params.bookId}}
      + Chapter Id: {{chapter.params.chapterId}} +
      +
      + + + .view-animate-container { + position:relative; + height:100px!important; + background:white; + border:1px solid black; + height:40px; + overflow:hidden; + } + + .view-animate { + padding:10px; + } + + .view-animate.ng-enter, .view-animate.ng-leave { + transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s; + + display:block; + width:100%; + border-left:1px solid black; + + position:absolute; + top:0; + left:0; + right:0; + bottom:0; + padding:10px; + } + + .view-animate.ng-enter { + left:100%; + } + .view-animate.ng-enter.ng-enter-active { + left:0; + } + .view-animate.ng-leave.ng-leave-active { + left:-100%; + } + + + + angular.module('ngViewExample', ['ngRoute', 'ngAnimate']) + .config(['$routeProvider', '$locationProvider', + function($routeProvider, $locationProvider) { + $routeProvider + .when('/Book/:bookId', { + templateUrl: 'book.html', + controller: 'BookCtrl', + controllerAs: 'book' + }) + .when('/Book/:bookId/ch/:chapterId', { + templateUrl: 'chapter.html', + controller: 'ChapterCtrl', + controllerAs: 'chapter' + }); + + $locationProvider.html5Mode(true); + }]) + .controller('MainCtrl', ['$route', '$routeParams', '$location', + function MainCtrl($route, $routeParams, $location) { + this.$route = $route; + this.$location = $location; + this.$routeParams = $routeParams; + }]) + .controller('BookCtrl', ['$routeParams', function BookCtrl($routeParams) { + this.name = 'BookCtrl'; + this.params = $routeParams; + }]) + .controller('ChapterCtrl', ['$routeParams', function ChapterCtrl($routeParams) { + this.name = 'ChapterCtrl'; + this.params = $routeParams; + }]); + + + + + it('should load and compile correct template', function() { + element(by.linkText('Moby: Ch1')).click(); + var content = element(by.css('[ng-view]')).getText(); + expect(content).toMatch(/controller: ChapterCtrl/); + expect(content).toMatch(/Book Id: Moby/); + expect(content).toMatch(/Chapter Id: 1/); + + element(by.partialLinkText('Scarlet')).click(); + + content = element(by.css('[ng-view]')).getText(); + expect(content).toMatch(/controller: BookCtrl/); + expect(content).toMatch(/Book Id: Scarlet/); + }); + +
      + */ + + +/** + * @ngdoc event + * @name ngView#$viewContentLoaded + * @eventType emit on the current ngView scope + * @description + * Emitted every time the ngView content is reloaded. + */ +ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate']; +function ngViewFactory($route, $anchorScroll, $animate) { + return { + restrict: 'ECA', + terminal: true, + priority: 400, + transclude: 'element', + link: function(scope, $element, attr, ctrl, $transclude) { + var currentScope, + currentElement, + previousLeaveAnimation, + autoScrollExp = attr.autoscroll, + onloadExp = attr.onload || ''; + + scope.$on('$routeChangeSuccess', update); + update(); + + function cleanupLastView() { + if (previousLeaveAnimation) { + $animate.cancel(previousLeaveAnimation); + previousLeaveAnimation = null; + } + + if (currentScope) { + currentScope.$destroy(); + currentScope = null; + } + if (currentElement) { + previousLeaveAnimation = $animate.leave(currentElement); + previousLeaveAnimation.done(function(response) { + if (response !== false) previousLeaveAnimation = null; + }); + currentElement = null; + } + } + + function update() { + var locals = $route.current && $route.current.locals, + template = locals && locals.$template; + + if (angular.isDefined(template)) { + var newScope = scope.$new(); + var current = $route.current; + + // Note: This will also link all children of ng-view that were contained in the original + // html. If that content contains controllers, ... they could pollute/change the scope. + // However, using ng-view on an element with additional content does not make sense... + // Note: We can't remove them in the cloneAttchFn of $transclude as that + // function is called before linking the content, which would apply child + // directives to non existing elements. + var clone = $transclude(newScope, function(clone) { + $animate.enter(clone, null, currentElement || $element).done(function onNgViewEnter(response) { + if (response !== false && angular.isDefined(autoScrollExp) + && (!autoScrollExp || scope.$eval(autoScrollExp))) { + $anchorScroll(); + } + }); + cleanupLastView(); + }); + + currentElement = clone; + currentScope = current.scope = newScope; + currentScope.$emit('$viewContentLoaded'); + currentScope.$eval(onloadExp); + } else { + cleanupLastView(); + } + } + } + }; +} + +// This directive is called during the $transclude call of the first `ngView` directive. +// It will replace and compile the content of the element with the loaded template. +// We need this directive so that the element content is already filled when +// the link function of another directive on the same element as ngView +// is called. +ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route']; +function ngViewFillContentFactory($compile, $controller, $route) { + return { + restrict: 'ECA', + priority: -400, + link: function(scope, $element) { + var current = $route.current, + locals = current.locals; + + $element.html(locals.$template); + + var link = $compile($element.contents()); + + if (current.controller) { + locals.$scope = scope; + var controller = $controller(current.controller, locals); + if (current.controllerAs) { + scope[current.controllerAs] = controller; + } + $element.data('$ngControllerController', controller); + $element.children().data('$ngControllerController', controller); + } + scope[current.resolveAs || '$resolve'] = locals; + + link(scope); + } + }; +} + + +})(window, window.angular); diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-route/angular-route.min.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-route/angular-route.min.js new file mode 100644 index 0000000..567eb15 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-route/angular-route.min.js @@ -0,0 +1,17 @@ +/* + AngularJS v1.8.0 + (c) 2010-2020 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(I,b){'use strict';function z(b,h){var d=[],c=b.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)(\*\?|[?*])?/g,function(b,c,h,k){b="?"===k||"*?"===k;k="*"===k||"*?"===k;d.push({name:h,optional:b});c=c||"";return(b?"(?:"+c:c+"(?:")+(k?"(.+?)":"([^/]+)")+(b?"?)?":")")}).replace(/([/$*])/g,"\\$1");h.ignoreTrailingSlashes&&(c=c.replace(/\/+$/,"")+"/*");return{keys:d,regexp:new RegExp("^"+c+"(?:[?#]|$)",h.caseInsensitiveMatch?"i":"")}}function A(b){p&&b.get("$route")}function v(u,h,d){return{restrict:"ECA", +terminal:!0,priority:400,transclude:"element",link:function(c,f,g,l,k){function q(){r&&(d.cancel(r),r=null);m&&(m.$destroy(),m=null);s&&(r=d.leave(s),r.done(function(b){!1!==b&&(r=null)}),s=null)}function C(){var g=u.current&&u.current.locals;if(b.isDefined(g&&g.$template)){var g=c.$new(),l=u.current;s=k(g,function(g){d.enter(g,null,s||f).done(function(d){!1===d||!b.isDefined(w)||w&&!c.$eval(w)||h()});q()});m=l.scope=g;m.$emit("$viewContentLoaded");m.$eval(p)}else q()}var m,s,r,w=g.autoscroll,p=g.onload|| +"";c.$on("$routeChangeSuccess",C);C()}}}function x(b,h,d){return{restrict:"ECA",priority:-400,link:function(c,f){var g=d.current,l=g.locals;f.html(l.$template);var k=b(f.contents());if(g.controller){l.$scope=c;var q=h(g.controller,l);g.controllerAs&&(c[g.controllerAs]=q);f.data("$ngControllerController",q);f.children().data("$ngControllerController",q)}c[g.resolveAs||"$resolve"]=l;k(c)}}}var D,E,F,G,y=b.module("ngRoute",[]).info({angularVersion:"1.8.0"}).provider("$route",function(){function u(d, +c){return b.extend(Object.create(d),c)}D=b.isArray;E=b.isObject;F=b.isDefined;G=b.noop;var h={};this.when=function(d,c){var f;f=void 0;if(D(c)){f=f||[];for(var g=0,l=c.length;g + + +
      + Snippet: + + + + + + + + + + + + + + + + + + + + + + + + + +
      DirectiveHowSourceRendered
      ng-bind-htmlAutomatically uses $sanitize
      <div ng-bind-html="snippet">
      </div>
      ng-bind-htmlBypass $sanitize by explicitly trusting the dangerous value +
      <div ng-bind-html="deliberatelyTrustDangerousSnippet()">
      +</div>
      +
      ng-bindAutomatically escapes
      <div ng-bind="snippet">
      </div>
      +
      +
      + + it('should sanitize the html snippet by default', function() { + expect(element(by.css('#bind-html-with-sanitize div')).getAttribute('innerHTML')). + toBe('

      an html\nclick here\nsnippet

      '); + }); + + it('should inline raw snippet if bound to a trusted value', function() { + expect(element(by.css('#bind-html-with-trust div')).getAttribute('innerHTML')). + toBe("

      an html\n" + + "click here\n" + + "snippet

      "); + }); + + it('should escape snippet without any filter', function() { + expect(element(by.css('#bind-default div')).getAttribute('innerHTML')). + toBe("<p style=\"color:blue\">an html\n" + + "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + + "snippet</p>"); + }); + + it('should update', function() { + element(by.model('snippet')).clear(); + element(by.model('snippet')).sendKeys('new text'); + expect(element(by.css('#bind-html-with-sanitize div')).getAttribute('innerHTML')). + toBe('new text'); + expect(element(by.css('#bind-html-with-trust div')).getAttribute('innerHTML')).toBe( + 'new text'); + expect(element(by.css('#bind-default div')).getAttribute('innerHTML')).toBe( + "new <b onclick=\"alert(1)\">text</b>"); + }); +
      + + */ + + +/** + * @ngdoc provider + * @name $sanitizeProvider + * @this + * + * @description + * Creates and configures {@link $sanitize} instance. + */ +function $SanitizeProvider() { + var hasBeenInstantiated = false; + var svgEnabled = false; + + this.$get = ['$$sanitizeUri', function($$sanitizeUri) { + hasBeenInstantiated = true; + if (svgEnabled) { + extend(validElements, svgElements); + } + return function(html) { + var buf = []; + htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) { + return !/^unsafe:/.test($$sanitizeUri(uri, isImage)); + })); + return buf.join(''); + }; + }]; + + + /** + * @ngdoc method + * @name $sanitizeProvider#enableSvg + * @kind function + * + * @description + * Enables a subset of svg to be supported by the sanitizer. + * + *
      + *

      By enabling this setting without taking other precautions, you might expose your + * application to click-hijacking attacks. In these attacks, sanitized svg elements could be positioned + * outside of the containing element and be rendered over other elements on the page (e.g. a login + * link). Such behavior can then result in phishing incidents.

      + * + *

      To protect against these, explicitly setup `overflow: hidden` css rule for all potential svg + * tags within the sanitized content:

      + * + *
      + * + *
      
      +   *   .rootOfTheIncludedContent svg {
      +   *     overflow: hidden !important;
      +   *   }
      +   *   
      + *
      + * + * @param {boolean=} flag Enable or disable SVG support in the sanitizer. + * @returns {boolean|$sanitizeProvider} Returns the currently configured value if called + * without an argument or self for chaining otherwise. + */ + this.enableSvg = function(enableSvg) { + if (isDefined(enableSvg)) { + svgEnabled = enableSvg; + return this; + } else { + return svgEnabled; + } + }; + + + /** + * @ngdoc method + * @name $sanitizeProvider#addValidElements + * @kind function + * + * @description + * Extends the built-in lists of valid HTML/SVG elements, i.e. elements that are considered safe + * and are not stripped off during sanitization. You can extend the following lists of elements: + * + * - `htmlElements`: A list of elements (tag names) to extend the current list of safe HTML + * elements. HTML elements considered safe will not be removed during sanitization. All other + * elements will be stripped off. + * + * - `htmlVoidElements`: This is similar to `htmlElements`, but marks the elements as + * "void elements" (similar to HTML + * [void elements](https://rawgit.com/w3c/html/html5.1-2/single-page.html#void-elements)). These + * elements have no end tag and cannot have content. + * + * - `svgElements`: This is similar to `htmlElements`, but for SVG elements. This list is only + * taken into account if SVG is {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for + * `$sanitize`. + * + *
      + * This method must be called during the {@link angular.Module#config config} phase. Once the + * `$sanitize` service has been instantiated, this method has no effect. + *
      + * + *
      + * Keep in mind that extending the built-in lists of elements may expose your app to XSS or + * other vulnerabilities. Be very mindful of the elements you add. + *
      + * + * @param {Array|Object} elements - A list of valid HTML elements or an object with one or + * more of the following properties: + * - **htmlElements** - `{Array}` - A list of elements to extend the current list of + * HTML elements. + * - **htmlVoidElements** - `{Array}` - A list of elements to extend the current list of + * void HTML elements; i.e. elements that do not have an end tag. + * - **svgElements** - `{Array}` - A list of elements to extend the current list of SVG + * elements. The list of SVG elements is only taken into account if SVG is + * {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for `$sanitize`. + * + * Passing an array (`[...]`) is equivalent to passing `{htmlElements: [...]}`. + * + * @return {$sanitizeProvider} Returns self for chaining. + */ + this.addValidElements = function(elements) { + if (!hasBeenInstantiated) { + if (isArray(elements)) { + elements = {htmlElements: elements}; + } + + addElementsTo(svgElements, elements.svgElements); + addElementsTo(voidElements, elements.htmlVoidElements); + addElementsTo(validElements, elements.htmlVoidElements); + addElementsTo(validElements, elements.htmlElements); + } + + return this; + }; + + + /** + * @ngdoc method + * @name $sanitizeProvider#addValidAttrs + * @kind function + * + * @description + * Extends the built-in list of valid attributes, i.e. attributes that are considered safe and are + * not stripped off during sanitization. + * + * **Note**: + * The new attributes will not be treated as URI attributes, which means their values will not be + * sanitized as URIs using `$compileProvider`'s + * {@link ng.$compileProvider#aHrefSanitizationWhitelist aHrefSanitizationWhitelist} and + * {@link ng.$compileProvider#imgSrcSanitizationWhitelist imgSrcSanitizationWhitelist}. + * + *
      + * This method must be called during the {@link angular.Module#config config} phase. Once the + * `$sanitize` service has been instantiated, this method has no effect. + *
      + * + *
      + * Keep in mind that extending the built-in list of attributes may expose your app to XSS or + * other vulnerabilities. Be very mindful of the attributes you add. + *
      + * + * @param {Array} attrs - A list of valid attributes. + * + * @returns {$sanitizeProvider} Returns self for chaining. + */ + this.addValidAttrs = function(attrs) { + if (!hasBeenInstantiated) { + extend(validAttrs, arrayToMap(attrs, true)); + } + return this; + }; + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Private stuff + ////////////////////////////////////////////////////////////////////////////////////////////////// + + bind = angular.bind; + extend = angular.extend; + forEach = angular.forEach; + isArray = angular.isArray; + isDefined = angular.isDefined; + lowercase = angular.$$lowercase; + noop = angular.noop; + + htmlParser = htmlParserImpl; + htmlSanitizeWriter = htmlSanitizeWriterImpl; + + nodeContains = window.Node.prototype.contains || /** @this */ function(arg) { + // eslint-disable-next-line no-bitwise + return !!(this.compareDocumentPosition(arg) & 16); + }; + + // Regular Expressions for parsing tags and attributes + var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g, + // Match everything outside of normal chars and " (quote character) + NON_ALPHANUMERIC_REGEXP = /([^#-~ |!])/g; + + + // Good source of info about elements and attributes + // http://dev.w3.org/html5/spec/Overview.html#semantics + // http://simon.html5.org/html-elements + + // Safe Void Elements - HTML5 + // http://dev.w3.org/html5/spec/Overview.html#void-elements + var voidElements = stringToMap('area,br,col,hr,img,wbr'); + + // Elements that you can, intentionally, leave open (and which close themselves) + // http://dev.w3.org/html5/spec/Overview.html#optional-tags + var optionalEndTagBlockElements = stringToMap('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr'), + optionalEndTagInlineElements = stringToMap('rp,rt'), + optionalEndTagElements = extend({}, + optionalEndTagInlineElements, + optionalEndTagBlockElements); + + // Safe Block Elements - HTML5 + var blockElements = extend({}, optionalEndTagBlockElements, stringToMap('address,article,' + + 'aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,' + + 'h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul')); + + // Inline Elements - HTML5 + var inlineElements = extend({}, optionalEndTagInlineElements, stringToMap('a,abbr,acronym,b,' + + 'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,' + + 'samp,small,span,strike,strong,sub,sup,time,tt,u,var')); + + // SVG Elements + // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements + // Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted. + // They can potentially allow for arbitrary javascript to be executed. See #11290 + var svgElements = stringToMap('circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,' + + 'hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,' + + 'radialGradient,rect,stop,svg,switch,text,title,tspan'); + + // Blocked Elements (will be stripped) + var blockedElements = stringToMap('script,style'); + + var validElements = extend({}, + voidElements, + blockElements, + inlineElements, + optionalEndTagElements); + + //Attributes that have href and hence need to be sanitized + var uriAttrs = stringToMap('background,cite,href,longdesc,src,xlink:href,xml:base'); + + var htmlAttrs = stringToMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' + + 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' + + 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' + + 'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' + + 'valign,value,vspace,width'); + + // SVG attributes (without "id" and "name" attributes) + // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes + var svgAttrs = stringToMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' + + 'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,' + + 'cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,' + + 'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,' + + 'height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,' + + 'marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,' + + 'max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,' + + 'path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,' + + 'requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,' + + 'stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,' + + 'stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,' + + 'stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,' + + 'underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,' + + 'width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,' + + 'xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan', true); + + var validAttrs = extend({}, + uriAttrs, + svgAttrs, + htmlAttrs); + + function stringToMap(str, lowercaseKeys) { + return arrayToMap(str.split(','), lowercaseKeys); + } + + function arrayToMap(items, lowercaseKeys) { + var obj = {}, i; + for (i = 0; i < items.length; i++) { + obj[lowercaseKeys ? lowercase(items[i]) : items[i]] = true; + } + return obj; + } + + function addElementsTo(elementsMap, newElements) { + if (newElements && newElements.length) { + extend(elementsMap, arrayToMap(newElements)); + } + } + + /** + * Create an inert document that contains the dirty HTML that needs sanitizing + * Depending upon browser support we use one of three strategies for doing this. + * Support: Safari 10.x -> XHR strategy + * Support: Firefox -> DomParser strategy + */ + var getInertBodyElement /* function(html: string): HTMLBodyElement */ = (function(window, document) { + var inertDocument; + if (document && document.implementation) { + inertDocument = document.implementation.createHTMLDocument('inert'); + } else { + throw $sanitizeMinErr('noinert', 'Can\'t create an inert html document'); + } + var inertBodyElement = (inertDocument.documentElement || inertDocument.getDocumentElement()).querySelector('body'); + + // Check for the Safari 10.1 bug - which allows JS to run inside the SVG G element + inertBodyElement.innerHTML = ''; + if (!inertBodyElement.querySelector('svg')) { + return getInertBodyElement_XHR; + } else { + // Check for the Firefox bug - which prevents the inner img JS from being sanitized + inertBodyElement.innerHTML = '

      '; + if (inertBodyElement.querySelector('svg img')) { + return getInertBodyElement_DOMParser; + } else { + return getInertBodyElement_InertDocument; + } + } + + function getInertBodyElement_XHR(html) { + // We add this dummy element to ensure that the rest of the content is parsed as expected + // e.g. leading whitespace is maintained and tags like `` do not get hoisted to the `` tag. + html = '' + html; + try { + html = encodeURI(html); + } catch (e) { + return undefined; + } + var xhr = new window.XMLHttpRequest(); + xhr.responseType = 'document'; + xhr.open('GET', 'data:text/html;charset=utf-8,' + html, false); + xhr.send(null); + var body = xhr.response.body; + body.firstChild.remove(); + return body; + } + + function getInertBodyElement_DOMParser(html) { + // We add this dummy element to ensure that the rest of the content is parsed as expected + // e.g. leading whitespace is maintained and tags like `` do not get hoisted to the `` tag. + html = '' + html; + try { + var body = new window.DOMParser().parseFromString(html, 'text/html').body; + body.firstChild.remove(); + return body; + } catch (e) { + return undefined; + } + } + + function getInertBodyElement_InertDocument(html) { + inertBodyElement.innerHTML = html; + + // Support: IE 9-11 only + // strip custom-namespaced attributes on IE<=11 + if (document.documentMode) { + stripCustomNsAttrs(inertBodyElement); + } + + return inertBodyElement; + } + })(window, window.document); + + /** + * @example + * htmlParser(htmlString, { + * start: function(tag, attrs) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * }); + * + * @param {string} html string + * @param {object} handler + */ + function htmlParserImpl(html, handler) { + if (html === null || html === undefined) { + html = ''; + } else if (typeof html !== 'string') { + html = '' + html; + } + + var inertBodyElement = getInertBodyElement(html); + if (!inertBodyElement) return ''; + + //mXSS protection + var mXSSAttempts = 5; + do { + if (mXSSAttempts === 0) { + throw $sanitizeMinErr('uinput', 'Failed to sanitize html because the input is unstable'); + } + mXSSAttempts--; + + // trigger mXSS if it is going to happen by reading and writing the innerHTML + html = inertBodyElement.innerHTML; + inertBodyElement = getInertBodyElement(html); + } while (html !== inertBodyElement.innerHTML); + + var node = inertBodyElement.firstChild; + while (node) { + switch (node.nodeType) { + case 1: // ELEMENT_NODE + handler.start(node.nodeName.toLowerCase(), attrToMap(node.attributes)); + break; + case 3: // TEXT NODE + handler.chars(node.textContent); + break; + } + + var nextNode; + if (!(nextNode = node.firstChild)) { + if (node.nodeType === 1) { + handler.end(node.nodeName.toLowerCase()); + } + nextNode = getNonDescendant('nextSibling', node); + if (!nextNode) { + while (nextNode == null) { + node = getNonDescendant('parentNode', node); + if (node === inertBodyElement) break; + nextNode = getNonDescendant('nextSibling', node); + if (node.nodeType === 1) { + handler.end(node.nodeName.toLowerCase()); + } + } + } + } + node = nextNode; + } + + while ((node = inertBodyElement.firstChild)) { + inertBodyElement.removeChild(node); + } + } + + function attrToMap(attrs) { + var map = {}; + for (var i = 0, ii = attrs.length; i < ii; i++) { + var attr = attrs[i]; + map[attr.name] = attr.value; + } + return map; + } + + + /** + * Escapes all potentially dangerous characters, so that the + * resulting string can be safely inserted into attribute or + * element text. + * @param value + * @returns {string} escaped text + */ + function encodeEntities(value) { + return value. + replace(/&/g, '&'). + replace(SURROGATE_PAIR_REGEXP, function(value) { + var hi = value.charCodeAt(0); + var low = value.charCodeAt(1); + return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';'; + }). + replace(NON_ALPHANUMERIC_REGEXP, function(value) { + return '&#' + value.charCodeAt(0) + ';'; + }). + replace(//g, '>'); + } + + /** + * create an HTML/XML writer which writes to buffer + * @param {Array} buf use buf.join('') to get out sanitized html string + * @returns {object} in the form of { + * start: function(tag, attrs) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * } + */ + function htmlSanitizeWriterImpl(buf, uriValidator) { + var ignoreCurrentElement = false; + var out = bind(buf, buf.push); + return { + start: function(tag, attrs) { + tag = lowercase(tag); + if (!ignoreCurrentElement && blockedElements[tag]) { + ignoreCurrentElement = tag; + } + if (!ignoreCurrentElement && validElements[tag] === true) { + out('<'); + out(tag); + forEach(attrs, function(value, key) { + var lkey = lowercase(key); + var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background'); + if (validAttrs[lkey] === true && + (uriAttrs[lkey] !== true || uriValidator(value, isImage))) { + out(' '); + out(key); + out('="'); + out(encodeEntities(value)); + out('"'); + } + }); + out('>'); + } + }, + end: function(tag) { + tag = lowercase(tag); + if (!ignoreCurrentElement && validElements[tag] === true && voidElements[tag] !== true) { + out(''); + } + // eslint-disable-next-line eqeqeq + if (tag == ignoreCurrentElement) { + ignoreCurrentElement = false; + } + }, + chars: function(chars) { + if (!ignoreCurrentElement) { + out(encodeEntities(chars)); + } + } + }; + } + + + /** + * When IE9-11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1' attribute to declare + * ns1 namespace and prefixes the attribute with 'ns1' (e.g. 'ns1:xlink:foo'). This is undesirable since we don't want + * to allow any of these custom attributes. This method strips them all. + * + * @param node Root element to process + */ + function stripCustomNsAttrs(node) { + while (node) { + if (node.nodeType === window.Node.ELEMENT_NODE) { + var attrs = node.attributes; + for (var i = 0, l = attrs.length; i < l; i++) { + var attrNode = attrs[i]; + var attrName = attrNode.name.toLowerCase(); + if (attrName === 'xmlns:ns1' || attrName.lastIndexOf('ns1:', 0) === 0) { + node.removeAttributeNode(attrNode); + i--; + l--; + } + } + } + + var nextNode = node.firstChild; + if (nextNode) { + stripCustomNsAttrs(nextNode); + } + + node = getNonDescendant('nextSibling', node); + } + } + + function getNonDescendant(propName, node) { + // An element is clobbered if its `propName` property points to one of its descendants + var nextNode = node[propName]; + if (nextNode && nodeContains.call(node, nextNode)) { + throw $sanitizeMinErr('elclob', 'Failed to sanitize html because the element is clobbered: {0}', node.outerHTML || node.outerText); + } + return nextNode; + } +} + +function sanitizeText(chars) { + var buf = []; + var writer = htmlSanitizeWriter(buf, noop); + writer.chars(chars); + return buf.join(''); +} + + +// define ngSanitize module and register $sanitize service +angular.module('ngSanitize', []) + .provider('$sanitize', $SanitizeProvider) + .info({ angularVersion: '1.8.0' }); + +/** + * @ngdoc filter + * @name linky + * @kind function + * + * @description + * Finds links in text input and turns them into html links. Supports `http/https/ftp/sftp/mailto` and + * plain email address links. + * + * Requires the {@link ngSanitize `ngSanitize`} module to be installed. + * + * @param {string} text Input text. + * @param {string} [target] Window (`_blank|_self|_parent|_top`) or named frame to open links in. + * @param {object|function(url)} [attributes] Add custom attributes to the link element. + * + * Can be one of: + * + * - `object`: A map of attributes + * - `function`: Takes the url as a parameter and returns a map of attributes + * + * If the map of attributes contains a value for `target`, it overrides the value of + * the target parameter. + * + * + * @returns {string} Html-linkified and {@link $sanitize sanitized} text. + * + * @usage + + * + * @example + + +

      + Snippet: + + + + + + + + + + + + + + + + + + + + + + + + + + +
      FilterSourceRendered
      linky filter +
      <div ng-bind-html="snippet | linky">
      </div>
      +
      +
      +
      linky target +
      <div ng-bind-html="snippetWithSingleURL | linky:'_blank'">
      </div>
      +
      +
      +
      linky custom attributes +
      <div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}">
      </div>
      +
      +
      +
      no filter
      <div ng-bind="snippet">
      </div>
      + + + angular.module('linkyExample', ['ngSanitize']) + .controller('ExampleController', ['$scope', function($scope) { + $scope.snippet = + 'Pretty text with some links:\n' + + 'http://angularjs.org/,\n' + + 'mailto:us@somewhere.org,\n' + + 'another@somewhere.org,\n' + + 'and one more: ftp://127.0.0.1/.'; + $scope.snippetWithSingleURL = 'http://angularjs.org/'; + }]); + + + it('should linkify the snippet with urls', function() { + expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). + toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' + + 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); + expect(element.all(by.css('#linky-filter a')).count()).toEqual(4); + }); + + it('should not linkify snippet without the linky filter', function() { + expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()). + toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' + + 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); + expect(element.all(by.css('#escaped-html a')).count()).toEqual(0); + }); + + it('should update', function() { + element(by.model('snippet')).clear(); + element(by.model('snippet')).sendKeys('new http://link.'); + expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). + toBe('new http://link.'); + expect(element.all(by.css('#linky-filter a')).count()).toEqual(1); + expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()) + .toBe('new http://link.'); + }); + + it('should work with the target property', function() { + expect(element(by.id('linky-target')). + element(by.binding("snippetWithSingleURL | linky:'_blank'")).getText()). + toBe('http://angularjs.org/'); + expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank'); + }); + + it('should optionally add custom attributes', function() { + expect(element(by.id('linky-custom-attributes')). + element(by.binding("snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}")).getText()). + toBe('http://angularjs.org/'); + expect(element(by.css('#linky-custom-attributes a')).getAttribute('rel')).toEqual('nofollow'); + }); + + + */ +angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) { + var LINKY_URL_REGEXP = + /((s?ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i, + MAILTO_REGEXP = /^mailto:/i; + + var linkyMinErr = angular.$$minErr('linky'); + var isDefined = angular.isDefined; + var isFunction = angular.isFunction; + var isObject = angular.isObject; + var isString = angular.isString; + + return function(text, target, attributes) { + if (text == null || text === '') return text; + if (!isString(text)) throw linkyMinErr('notstring', 'Expected string but received: {0}', text); + + var attributesFn = + isFunction(attributes) ? attributes : + isObject(attributes) ? function getAttributesObject() {return attributes;} : + function getEmptyAttributesObject() {return {};}; + + var match; + var raw = text; + var html = []; + var url; + var i; + while ((match = raw.match(LINKY_URL_REGEXP))) { + // We can not end in these as they are sometimes found at the end of the sentence + url = match[0]; + // if we did not match ftp/http/www/mailto then assume mailto + if (!match[2] && !match[4]) { + url = (match[3] ? 'http://' : 'mailto:') + url; + } + i = match.index; + addText(raw.substr(0, i)); + addLink(url, match[0].replace(MAILTO_REGEXP, '')); + raw = raw.substring(i + match[0].length); + } + addText(raw); + return $sanitize(html.join('')); + + function addText(text) { + if (!text) { + return; + } + html.push(sanitizeText(text)); + } + + function addLink(url, text) { + var key, linkAttributes = attributesFn(url); + html.push(''); + addText(text); + html.push(''); + } + }; +}]); + + +})(window, window.angular); diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-sanitize/angular-sanitize.min.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-sanitize/angular-sanitize.min.js new file mode 100644 index 0000000..42f78b8 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-sanitize/angular-sanitize.min.js @@ -0,0 +1,18 @@ +/* + AngularJS v1.8.0 + (c) 2010-2020 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(s,c){'use strict';function P(c){var h=[];C(h,E).chars(c);return h.join("")}var D=c.$$minErr("$sanitize"),F,h,G,H,I,q,E,J,K,C;c.module("ngSanitize",[]).provider("$sanitize",function(){function f(a,e){return B(a.split(","),e)}function B(a,e){var d={},b;for(b=0;b/g,">")}function A(a){for(;a;){if(a.nodeType===s.Node.ELEMENT_NODE)for(var e=a.attributes,d=0,b=e.length;d"))},end:function(a){a=q(a);d||!0!==m[a]||!0===r[a]||(b(""));a==d&&(d=!1)},chars:function(a){d|| +b(L(a))}}};J=s.Node.prototype.contains||function(a){return!!(this.compareDocumentPosition(a)&16)};var z=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,u=/([^#-~ |!])/g,r=f("area,br,col,hr,img,wbr"),x=f("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),p=f("rp,rt"),n=h({},p,x),x=h({},x,f("address,article,aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul")),p=h({},p,f("a,abbr,acronym,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small,span,strike,strong,sub,sup,time,tt,u,var")), +l=f("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,stop,svg,switch,text,title,tspan"),w=f("script,style"),m=h({},r,x,p,n),O=f("background,cite,href,longdesc,src,xlink:href,xml:base"),n=f("abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,valign,value,vspace,width"), +p=f("accent-height,accumulate,additive,alphabetic,arabic-form,ascent,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan", +!0),M=h({},O,p,n),N=function(a,e){function d(b){b=""+b;try{var d=(new a.DOMParser).parseFromString(b,"text/html").body;d.firstChild.remove();return d}catch(e){}}function b(a){c.innerHTML=a;e.documentMode&&A(c);return c}var g;if(e&&e.implementation)g=e.implementation.createHTMLDocument("inert");else throw D("noinert");var c=(g.documentElement||g.getDocumentElement()).querySelector("body");c.innerHTML='';return c.querySelector("svg")? +(c.innerHTML='

      ',c.querySelector("svg img")?d:b):function(b){b=""+b;try{b=encodeURI(b)}catch(d){return}var e=new a.XMLHttpRequest;e.responseType="document";e.open("GET","data:text/html;charset=utf-8,"+b,!1);e.send(null);b=e.response.body;b.firstChild.remove();return b}}(s,s.document)}).info({angularVersion:"1.8.0"});c.module("ngSanitize").filter("linky",["$sanitize",function(f){var h=/((s?ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i, +t=/^mailto:/i,q=c.$$minErr("linky"),s=c.isDefined,A=c.isFunction,v=c.isObject,y=c.isString;return function(c,z,u){function r(c){c&&l.push(P(c))}function x(c,g){var f,a=p(c);l.push("');r(g);l.push("")}if(null==c||""===c)return c;if(!y(c))throw q("notstring",c);for(var p=A(u)?u:v(u)?function(){return u}:function(){return{}},n=c,l=[],w,m;c=n.match(h);)w=c[0],c[2]|| +c[4]||(w=(c[3]?"http://":"mailto:")+w),m=c.index,r(n.substr(0,m)),x(w,c[0].replace(t,"")),n=n.substring(m+c[0].length);r(n);return f(l.join(""))}}])})(window,window.angular); +//# sourceMappingURL=angular-sanitize.min.js.map diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-sanitize/angular-sanitize.min.js.map b/keycloak-themes/keycloak/common/resources/node_modules/angular-sanitize/angular-sanitize.min.js.map new file mode 100644 index 0000000..133f378 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-sanitize/angular-sanitize.min.js.map @@ -0,0 +1,8 @@ +{ +"version":3, +"file":"angular-sanitize.min.js", +"lineCount":17, +"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkB,CAyrB3BC,QAASA,EAAY,CAACC,CAAD,CAAQ,CAC3B,IAAIC,EAAM,EACGC,EAAAC,CAAmBF,CAAnBE,CAAwBC,CAAxBD,CACbH,MAAA,CAAaA,CAAb,CACA,OAAOC,EAAAI,KAAA,CAAS,EAAT,CAJoB,CA5qB7B,IAAIC,EAAkBR,CAAAS,SAAA,CAAiB,WAAjB,CAAtB,CACIC,CADJ,CAEIC,CAFJ,CAGIC,CAHJ,CAIIC,CAJJ,CAKIC,CALJ,CAMIC,CANJ,CAOIT,CAPJ,CAQIU,CARJ,CASIC,CATJ,CAUIb,CA2qBJJ,EAAAkB,OAAA,CAAe,YAAf,CAA6B,EAA7B,CAAAC,SAAA,CACY,WADZ,CAhjBAC,QAA0B,EAAG,CAkQ3BC,QAASA,EAAW,CAACC,CAAD,CAAMC,CAAN,CAAqB,CACvC,MAAOC,EAAA,CAAWF,CAAAG,MAAA,CAAU,GAAV,CAAX,CAA2BF,CAA3B,CADgC,CAIzCC,QAASA,EAAU,CAACE,CAAD,CAAQH,CAAR,CAAuB,CAAA,IACpCI,EAAM,EAD8B,CAC1BC,CACd,KAAKA,CAAL,CAAS,CAAT,CAAYA,CAAZ,CAAgBF,CAAAG,OAAhB,CAA8BD,CAAA,EAA9B,CACED,CAAA,CAAIJ,CAAA,CAAgBR,CAAA,CAAUW,CAAA,CAAME,CAAN,CAAV,CAAhB,CAAsCF,CAAA,CAAME,CAAN,CAA1C,CAAA,CAAsD,CAAA,CAExD,OAAOD,EALiC,CAQ1CG,QAASA,EAAa,CAACC,CAAD,CAAcC,CAAd,CAA2B,CAC3CA,CAAJ,EAAmBA,CAAAH,OAAnB,EACElB,CAAA,CAAOoB,CAAP,CAAoBP,CAAA,CAAWQ,CAAX,CAApB,CAF6C,CAsJjDC,QAASA,EAAS,CAACC,CAAD,CAAQ,CAExB,IADA,IAAIC,EAAM,EAAV,CACSP,EAAI,CADb,CACgBQ,EAAKF,CAAAL,OAArB,CAAmCD,CAAnC,CAAuCQ,CAAvC,CAA2CR,CAAA,EAA3C,CAAgD,CAC9C,IAAIS,EAAOH,CAAA,CAAMN,CAAN,CACXO,EAAA,CAAIE,CAAAC,KAAJ,CAAA,CAAiBD,CAAAE,MAF6B,CAIhD,MAAOJ,EANiB,CAiB1BK,QAASA,EAAc,CAACD,CAAD,CAAQ,CAC7B,MAAOA,EAAAE,QAAA,CACG,IADH,CACS,OADT,CAAAA,QAAA,CAEGC,CAFH,CAE0B,QAAQ,CAACH,CAAD,CAAQ,CAC7C,IAAII;AAAKJ,CAAAK,WAAA,CAAiB,CAAjB,CACLC,EAAAA,CAAMN,CAAAK,WAAA,CAAiB,CAAjB,CACV,OAAO,IAAP,EAAgC,IAAhC,EAAiBD,CAAjB,CAAsB,KAAtB,GAA0CE,CAA1C,CAAgD,KAAhD,EAA0D,KAA1D,EAAqE,GAHxB,CAF1C,CAAAJ,QAAA,CAOGK,CAPH,CAO4B,QAAQ,CAACP,CAAD,CAAQ,CAC/C,MAAO,IAAP,CAAcA,CAAAK,WAAA,CAAiB,CAAjB,CAAd,CAAoC,GADW,CAP5C,CAAAH,QAAA,CAUG,IAVH,CAUS,MAVT,CAAAA,QAAA,CAWG,IAXH,CAWS,MAXT,CADsB,CAgF/BM,QAASA,EAAkB,CAACC,CAAD,CAAO,CAChC,IAAA,CAAOA,CAAP,CAAA,CAAa,CACX,GAAIA,CAAAC,SAAJ,GAAsBlD,CAAAmD,KAAAC,aAAtB,CAEE,IADA,IAAIjB,EAAQc,CAAAI,WAAZ,CACSxB,EAAI,CADb,CACgByB,EAAInB,CAAAL,OAApB,CAAkCD,CAAlC,CAAsCyB,CAAtC,CAAyCzB,CAAA,EAAzC,CAA8C,CAC5C,IAAI0B,EAAWpB,CAAA,CAAMN,CAAN,CAAf,CACI2B,EAAWD,CAAAhB,KAAAkB,YAAA,EACf,IAAiB,WAAjB,GAAID,CAAJ,EAAoE,CAApE,GAAgCA,CAAAE,YAAA,CAAqB,MAArB,CAA6B,CAA7B,CAAhC,CACET,CAAAU,oBAAA,CAAyBJ,CAAzB,CAEA,CADA1B,CAAA,EACA,CAAAyB,CAAA,EAN0C,CAYhD,CADIM,CACJ,CADeX,CAAAY,WACf,GACEb,CAAA,CAAmBY,CAAnB,CAGFX,EAAA,CAAOa,CAAA,CAAiB,aAAjB,CAAgCb,CAAhC,CAnBI,CADmB,CAwBlCa,QAASA,EAAgB,CAACC,CAAD,CAAWd,CAAX,CAAiB,CAExC,IAAIW,EAAWX,CAAA,CAAKc,CAAL,CACf,IAAIH,CAAJ,EAAgB3C,CAAA+C,KAAA,CAAkBf,CAAlB,CAAwBW,CAAxB,CAAhB,CACE,KAAMnD,EAAA,CAAgB,QAAhB;AAA2FwC,CAAAgB,UAA3F,EAA6GhB,CAAAiB,UAA7G,CAAN,CAEF,MAAON,EANiC,CA5hB1C,IAAIO,EAAsB,CAAA,CAA1B,CACIC,EAAa,CAAA,CAEjB,KAAAC,KAAA,CAAY,CAAC,eAAD,CAAkB,QAAQ,CAACC,CAAD,CAAgB,CACpDH,CAAA,CAAsB,CAAA,CAClBC,EAAJ,EACExD,CAAA,CAAO2D,CAAP,CAAsBC,CAAtB,CAEF,OAAO,SAAQ,CAACC,CAAD,CAAO,CACpB,IAAIrE,EAAM,EACVc,EAAA,CAAWuD,CAAX,CAAiBpE,CAAA,CAAmBD,CAAnB,CAAwB,QAAQ,CAACsE,CAAD,CAAMC,CAAN,CAAe,CAC9D,MAAO,CAAC,UAAAC,KAAA,CAAgBN,CAAA,CAAcI,CAAd,CAAmBC,CAAnB,CAAhB,CADsD,CAA/C,CAAjB,CAGA,OAAOvE,EAAAI,KAAA,CAAS,EAAT,CALa,CAL8B,CAA1C,CA6CZ,KAAAqE,UAAA,CAAiBC,QAAQ,CAACD,CAAD,CAAY,CACnC,MAAI9D,EAAA,CAAU8D,CAAV,CAAJ,EACET,CACO,CADMS,CACN,CAAA,IAFT,EAIST,CAL0B,CAwDrC,KAAAW,iBAAA,CAAwBC,QAAQ,CAACC,CAAD,CAAW,CACpCd,CAAL,GACMrD,CAAA,CAAQmE,CAAR,CAOJ,GANEA,CAMF,CANa,CAACC,aAAcD,CAAf,CAMb,EAHAlD,CAAA,CAAcyC,CAAd,CAA2BS,CAAAT,YAA3B,CAGA,CAFAzC,CAAA,CAAcoD,CAAd,CAA4BF,CAAAG,iBAA5B,CAEA,CADArD,CAAA,CAAcwC,CAAd,CAA6BU,CAAAG,iBAA7B,CACA,CAAArD,CAAA,CAAcwC,CAAd,CAA6BU,CAAAC,aAA7B,CARF,CAWA,OAAO,KAZkC,CA6C3C,KAAAG,cAAA,CAAqBC,QAAQ,CAACnD,CAAD,CAAQ,CAC9BgC,CAAL,EACEvD,CAAA,CAAO2E,CAAP,CAAmB9D,CAAA,CAAWU,CAAX,CAAkB,CAAA,CAAlB,CAAnB,CAEF,OAAO,KAJ4B,CAWrCxB,EAAA,CAAOV,CAAAU,KACPC,EAAA,CAASX,CAAAW,OACTC;CAAA,CAAUZ,CAAAY,QACVC,EAAA,CAAUb,CAAAa,QACVC,EAAA,CAAYd,CAAAc,UACZC,EAAA,CAAYf,CAAAuF,YACZjF,EAAA,CAAON,CAAAM,KAEPW,EAAA,CAgMAuE,QAAuB,CAAChB,CAAD,CAAOiB,CAAP,CAAgB,CACxB,IAAb,GAAIjB,CAAJ,EAA8BkB,IAAAA,EAA9B,GAAqBlB,CAArB,CACEA,CADF,CACS,EADT,CAE2B,QAF3B,GAEW,MAAOA,EAFlB,GAGEA,CAHF,CAGS,EAHT,CAGcA,CAHd,CAMA,KAAImB,EAAmBC,CAAA,CAAoBpB,CAApB,CACvB,IAAKmB,CAAAA,CAAL,CAAuB,MAAO,EAG9B,KAAIE,EAAe,CACnB,GAAG,CACD,GAAqB,CAArB,GAAIA,CAAJ,CACE,KAAMrF,EAAA,CAAgB,QAAhB,CAAN,CAEFqF,CAAA,EAGArB,EAAA,CAAOmB,CAAAG,UACPH,EAAA,CAAmBC,CAAA,CAAoBpB,CAApB,CARlB,CAAH,MASSA,CATT,GASkBmB,CAAAG,UATlB,CAYA,KADI9C,CACJ,CADW2C,CAAA/B,WACX,CAAOZ,CAAP,CAAA,CAAa,CACX,OAAQA,CAAAC,SAAR,EACE,KAAK,CAAL,CACEwC,CAAAM,MAAA,CAAc/C,CAAAgD,SAAAxC,YAAA,EAAd,CAA2CvB,CAAA,CAAUe,CAAAI,WAAV,CAA3C,CACA,MACF,MAAK,CAAL,CACEqC,CAAAvF,MAAA,CAAc8C,CAAAiD,YAAd,CALJ,CASA,IAAItC,CACJ,IAAM,EAAAA,CAAA,CAAWX,CAAAY,WAAX,CAAN,GACwB,CAIjBD,GAJDX,CAAAC,SAICU,EAHH8B,CAAAS,IAAA,CAAYlD,CAAAgD,SAAAxC,YAAA,EAAZ,CAGGG,CADLA,CACKA,CADME,CAAA,CAAiB,aAAjB,CAAgCb,CAAhC,CACNW,CAAAA,CAAAA,CALP,EAMI,IAAA,CAAmB,IAAnB,EAAOA,CAAP,CAAA,CAAyB,CACvBX,CAAA;AAAOa,CAAA,CAAiB,YAAjB,CAA+Bb,CAA/B,CACP,IAAIA,CAAJ,GAAa2C,CAAb,CAA+B,KAC/BhC,EAAA,CAAWE,CAAA,CAAiB,aAAjB,CAAgCb,CAAhC,CACW,EAAtB,GAAIA,CAAAC,SAAJ,EACEwC,CAAAS,IAAA,CAAYlD,CAAAgD,SAAAxC,YAAA,EAAZ,CALqB,CAU7BR,CAAA,CAAOW,CA3BI,CA8Bb,IAAA,CAAQX,CAAR,CAAe2C,CAAA/B,WAAf,CAAA,CACE+B,CAAAQ,YAAA,CAA6BnD,CAA7B,CAvDmC,CA/LvC5C,EAAA,CAoSAgG,QAA+B,CAACjG,CAAD,CAAMkG,CAAN,CAAoB,CACjD,IAAIC,EAAuB,CAAA,CAA3B,CACIC,EAAM7F,CAAA,CAAKP,CAAL,CAAUA,CAAAqG,KAAV,CACV,OAAO,CACLT,MAAOA,QAAQ,CAACU,CAAD,CAAMvE,CAAN,CAAa,CAC1BuE,CAAA,CAAM1F,CAAA,CAAU0F,CAAV,CACDH,EAAAA,CAAL,EAA6BI,CAAA,CAAgBD,CAAhB,CAA7B,GACEH,CADF,CACyBG,CADzB,CAGKH,EAAL,EAAoD,CAAA,CAApD,GAA6BhC,CAAA,CAAcmC,CAAd,CAA7B,GACEF,CAAA,CAAI,GAAJ,CAcA,CAbAA,CAAA,CAAIE,CAAJ,CAaA,CAZA7F,CAAA,CAAQsB,CAAR,CAAe,QAAQ,CAACK,CAAD,CAAQoE,CAAR,CAAa,CAClC,IAAIC,EAAO7F,CAAA,CAAU4F,CAAV,CAAX,CACIjC,EAAmB,KAAnBA,GAAW+B,CAAX/B,EAAqC,KAArCA,GAA4BkC,CAA5BlC,EAAyD,YAAzDA,GAAgDkC,CAC3B,EAAA,CAAzB,GAAItB,CAAA,CAAWsB,CAAX,CAAJ,EACsB,CAAA,CADtB,GACGC,CAAA,CAASD,CAAT,CADH,EAC8B,CAAAP,CAAA,CAAa9D,CAAb,CAAoBmC,CAApB,CAD9B,GAEE6B,CAAA,CAAI,GAAJ,CAIA,CAHAA,CAAA,CAAII,CAAJ,CAGA,CAFAJ,CAAA,CAAI,IAAJ,CAEA,CADAA,CAAA,CAAI/D,CAAA,CAAeD,CAAf,CAAJ,CACA,CAAAgE,CAAA,CAAI,GAAJ,CANF,CAHkC,CAApC,CAYA,CAAAA,CAAA,CAAI,GAAJ,CAfF,CAL0B,CADvB,CAwBLL,IAAKA,QAAQ,CAACO,CAAD,CAAM,CACjBA,CAAA,CAAM1F,CAAA,CAAU0F,CAAV,CACDH,EAAL,EAAoD,CAAA,CAApD,GAA6BhC,CAAA,CAAcmC,CAAd,CAA7B,EAAkF,CAAA,CAAlF,GAA4DvB,CAAA,CAAauB,CAAb,CAA5D,GACEF,CAAA,CAAI,IAAJ,CAEA,CADAA,CAAA,CAAIE,CAAJ,CACA,CAAAF,CAAA,CAAI,GAAJ,CAHF,CAMIE,EAAJ,EAAWH,CAAX,GACEA,CADF,CACyB,CAAA,CADzB,CARiB,CAxBd,CAoCLpG,MAAOA,QAAQ,CAACA,CAAD,CAAQ,CAChBoG,CAAL;AACEC,CAAA,CAAI/D,CAAA,CAAetC,CAAf,CAAJ,CAFmB,CApClB,CAH0C,CAlSnDc,EAAA,CAAejB,CAAAmD,KAAA4D,UAAAC,SAAf,EAA8D,QAAQ,CAACC,CAAD,CAAM,CAE1E,MAAO,CAAG,EAAA,IAAAC,wBAAA,CAA6BD,CAA7B,CAAA,CAAoC,EAApC,CAFgE,CA5KjD,KAkLvBtE,EAAwB,iCAlLD,CAoLzBI,EAA0B,cApLD,CA6LvBoC,EAAe7D,CAAA,CAAY,wBAAZ,CA7LQ,CAiMvB6F,EAA8B7F,CAAA,CAAY,gDAAZ,CAjMP,CAkMvB8F,EAA+B9F,CAAA,CAAY,OAAZ,CAlMR,CAmMvB+F,EAAyBzG,CAAA,CAAO,EAAP,CACewG,CADf,CAEeD,CAFf,CAnMF,CAwMvBG,EAAgB1G,CAAA,CAAO,EAAP,CAAWuG,CAAX,CAAwC7F,CAAA,CAAY,qKAAZ,CAAxC,CAxMO,CA6MvBiG,EAAiB3G,CAAA,CAAO,EAAP,CAAWwG,CAAX,CAAyC9F,CAAA,CAAY,2JAAZ,CAAzC,CA7MM;AAqNvBkD,EAAclD,CAAA,CAAY,wNAAZ,CArNS,CA0NvBqF,EAAkBrF,CAAA,CAAY,cAAZ,CA1NK,CA4NvBiD,EAAgB3D,CAAA,CAAO,EAAP,CACeuE,CADf,CAEemC,CAFf,CAGeC,CAHf,CAIeF,CAJf,CA5NO,CAmOvBP,EAAWxF,CAAA,CAAY,uDAAZ,CAnOY,CAqOvBkG,EAAYlG,CAAA,CAAY,kTAAZ,CArOW;AA6OvBmG,EAAWnG,CAAA,CAAY,guCAAZ;AAcoE,CAAA,CAdpE,CA7OY,CA6PvBiE,EAAa3E,CAAA,CAAO,EAAP,CACekG,CADf,CAEeW,CAFf,CAGeD,CAHf,CA7PU,CA0RvB3B,EAAqE,QAAQ,CAAC7F,CAAD,CAAS0H,CAAT,CAAmB,CAyClGC,QAASA,EAA6B,CAAClD,CAAD,CAAO,CAG3CA,CAAA,CAAO,mBAAP,CAA6BA,CAC7B,IAAI,CACF,IAAImD,EAAOC,CAAA,IAAI7H,CAAA8H,UAAJD,iBAAA,CAAuCpD,CAAvC,CAA6C,WAA7C,CAAAmD,KACXA,EAAA/D,WAAAkE,OAAA,EACA,OAAOH,EAHL,CAIF,MAAOI,CAAP,CAAU,EAR+B,CAa7CC,QAASA,EAAiC,CAACxD,CAAD,CAAO,CAC/CmB,CAAAG,UAAA,CAA6BtB,CAIzBiD,EAAAQ,aAAJ,EACElF,CAAA,CAAmB4C,CAAnB,CAGF,OAAOA,EATwC,CArDjD,IAAIuC,CACJ,IAAIT,CAAJ,EAAgBA,CAAAU,eAAhB,CACED,CAAA,CAAgBT,CAAAU,eAAAC,mBAAA,CAA2C,OAA3C,CADlB,KAGE,MAAM5H,EAAA,CAAgB,SAAhB,CAAN,CAEF,IAAImF,EAAmB0C,CAACH,CAAAI,gBAADD,EAAkCH,CAAAK,mBAAA,EAAlCF,eAAA,CAAoF,MAApF,CAGvB1C,EAAAG,UAAA,CAA6B,sDAC7B,OAAKH,EAAA0C,cAAA,CAA+B,KAA/B,CAAL;CAIE1C,CAAAG,UACA,CAD6B,kEAC7B,CAAIH,CAAA0C,cAAA,CAA+B,SAA/B,CAAJ,CACSX,CADT,CAGSM,CARX,EAYAQ,QAAgC,CAAChE,CAAD,CAAO,CAGrCA,CAAA,CAAO,mBAAP,CAA6BA,CAC7B,IAAI,CACFA,CAAA,CAAOiE,SAAA,CAAUjE,CAAV,CADL,CAEF,MAAOuD,CAAP,CAAU,CACV,MADU,CAGZ,IAAIW,EAAM,IAAI3I,CAAA4I,eACdD,EAAAE,aAAA,CAAmB,UACnBF,EAAAG,KAAA,CAAS,KAAT,CAAgB,+BAAhB,CAAkDrE,CAAlD,CAAwD,CAAA,CAAxD,CACAkE,EAAAI,KAAA,CAAS,IAAT,CACInB,EAAAA,CAAOe,CAAAK,SAAApB,KACXA,EAAA/D,WAAAkE,OAAA,EACA,OAAOH,EAf8B,CAvB2D,CAA5B,CAiErE5H,CAjEqE,CAiE7DA,CAAA0H,SAjE6D,CA1R7C,CAgjB7B,CAAAuB,KAAA,CAEQ,CAAEC,eAAgB,OAAlB,CAFR,CAmIAjJ,EAAAkB,OAAA,CAAe,YAAf,CAAAgI,OAAA,CAAoC,OAApC,CAA6C,CAAC,WAAD,CAAc,QAAQ,CAACC,CAAD,CAAY,CAAA,IACzEC,EACE,2FAFuE;AAGzEC,EAAgB,WAHyD,CAKzEC,EAActJ,CAAAS,SAAA,CAAiB,OAAjB,CAL2D,CAMzEK,EAAYd,CAAAc,UAN6D,CAOzEyI,EAAavJ,CAAAuJ,WAP4D,CAQzEC,EAAWxJ,CAAAwJ,SAR8D,CASzEC,EAAWzJ,CAAAyJ,SAEf,OAAO,SAAQ,CAACC,CAAD,CAAOC,CAAP,CAAevG,CAAf,CAA2B,CA6BxCwG,QAASA,EAAO,CAACF,CAAD,CAAO,CAChBA,CAAL,EAGAlF,CAAAgC,KAAA,CAAUvG,CAAA,CAAayJ,CAAb,CAAV,CAJqB,CAOvBG,QAASA,EAAO,CAACC,CAAD,CAAMJ,CAAN,CAAY,CAAA,IACtB/C,CADsB,CACjBoD,EAAiBC,CAAA,CAAaF,CAAb,CAC1BtF,EAAAgC,KAAA,CAAU,KAAV,CAEA,KAAKG,CAAL,GAAYoD,EAAZ,CACEvF,CAAAgC,KAAA,CAAUG,CAAV,CAAgB,IAAhB,CAAuBoD,CAAA,CAAepD,CAAf,CAAvB,CAA6C,IAA7C,CAGE,EAAA7F,CAAA,CAAU6I,CAAV,CAAJ,EAA2B,QAA3B,EAAuCI,EAAvC,EACEvF,CAAAgC,KAAA,CAAU,UAAV,CACUmD,CADV,CAEU,IAFV,CAIFnF,EAAAgC,KAAA,CAAU,QAAV,CACUsD,CAAArH,QAAA,CAAY,IAAZ,CAAkB,QAAlB,CADV,CAEU,IAFV,CAGAmH,EAAA,CAAQF,CAAR,CACAlF,EAAAgC,KAAA,CAAU,MAAV,CAjB0B,CAnC5B,GAAY,IAAZ,EAAIkD,CAAJ,EAA6B,EAA7B,GAAoBA,CAApB,CAAiC,MAAOA,EACxC,IAAK,CAAAD,CAAA,CAASC,CAAT,CAAL,CAAqB,KAAMJ,EAAA,CAAY,WAAZ,CAA8DI,CAA9D,CAAN,CAYrB,IAVA,IAAIM,EACFT,CAAA,CAAWnG,CAAX,CAAA,CAAyBA,CAAzB,CACAoG,CAAA,CAASpG,CAAT,CAAA,CAAuB6G,QAA4B,EAAG,CAAC,MAAO7G,EAAR,CAAtD,CACA8G,QAAiC,EAAG,CAAC,MAAO,EAAR,CAHtC,CAMIC,EAAMT,CANV,CAOIlF,EAAO,EAPX,CAQIsF,CARJ,CASIlI,CACJ,CAAQwI,CAAR,CAAgBD,CAAAC,MAAA,CAAUhB,CAAV,CAAhB,CAAA,CAEEU,CAQA,CARMM,CAAA,CAAM,CAAN,CAQN,CANKA,CAAA,CAAM,CAAN,CAML;AANkBA,CAAA,CAAM,CAAN,CAMlB,GALEN,CAKF,EALSM,CAAA,CAAM,CAAN,CAAA,CAAW,SAAX,CAAuB,SAKhC,EAL6CN,CAK7C,EAHAlI,CAGA,CAHIwI,CAAAC,MAGJ,CAFAT,CAAA,CAAQO,CAAAG,OAAA,CAAW,CAAX,CAAc1I,CAAd,CAAR,CAEA,CADAiI,CAAA,CAAQC,CAAR,CAAaM,CAAA,CAAM,CAAN,CAAA3H,QAAA,CAAiB4G,CAAjB,CAAgC,EAAhC,CAAb,CACA,CAAAc,CAAA,CAAMA,CAAAI,UAAA,CAAc3I,CAAd,CAAkBwI,CAAA,CAAM,CAAN,CAAAvI,OAAlB,CAER+H,EAAA,CAAQO,CAAR,CACA,OAAOhB,EAAA,CAAU3E,CAAAjE,KAAA,CAAU,EAAV,CAAV,CA3BiC,CAXmC,CAAlC,CAA7C,CAr0B2B,CAA1B,CAAD,CA24BGR,MA34BH,CA24BWA,MAAAC,QA34BX;", +"sources":["angular-sanitize.js"], +"names":["window","angular","sanitizeText","chars","buf","htmlSanitizeWriter","writer","noop","join","$sanitizeMinErr","$$minErr","bind","extend","forEach","isArray","isDefined","lowercase","nodeContains","htmlParser","module","provider","$SanitizeProvider","stringToMap","str","lowercaseKeys","arrayToMap","split","items","obj","i","length","addElementsTo","elementsMap","newElements","attrToMap","attrs","map","ii","attr","name","value","encodeEntities","replace","SURROGATE_PAIR_REGEXP","hi","charCodeAt","low","NON_ALPHANUMERIC_REGEXP","stripCustomNsAttrs","node","nodeType","Node","ELEMENT_NODE","attributes","l","attrNode","attrName","toLowerCase","lastIndexOf","removeAttributeNode","nextNode","firstChild","getNonDescendant","propName","call","outerHTML","outerText","hasBeenInstantiated","svgEnabled","$get","$$sanitizeUri","validElements","svgElements","html","uri","isImage","test","enableSvg","this.enableSvg","addValidElements","this.addValidElements","elements","htmlElements","voidElements","htmlVoidElements","addValidAttrs","this.addValidAttrs","validAttrs","$$lowercase","htmlParserImpl","handler","undefined","inertBodyElement","getInertBodyElement","mXSSAttempts","innerHTML","start","nodeName","textContent","end","removeChild","htmlSanitizeWriterImpl","uriValidator","ignoreCurrentElement","out","push","tag","blockedElements","key","lkey","uriAttrs","prototype","contains","arg","compareDocumentPosition","optionalEndTagBlockElements","optionalEndTagInlineElements","optionalEndTagElements","blockElements","inlineElements","htmlAttrs","svgAttrs","document","getInertBodyElement_DOMParser","body","parseFromString","DOMParser","remove","e","getInertBodyElement_InertDocument","documentMode","inertDocument","implementation","createHTMLDocument","querySelector","documentElement","getDocumentElement","getInertBodyElement_XHR","encodeURI","xhr","XMLHttpRequest","responseType","open","send","response","info","angularVersion","filter","$sanitize","LINKY_URL_REGEXP","MAILTO_REGEXP","linkyMinErr","isFunction","isObject","isString","text","target","addText","addLink","url","linkAttributes","attributesFn","getAttributesObject","getEmptyAttributesObject","raw","match","index","substr","substring"] +} diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-sanitize/bower.json b/keycloak-themes/keycloak/common/resources/node_modules/angular-sanitize/bower.json new file mode 100644 index 0000000..d72cde1 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-sanitize/bower.json @@ -0,0 +1,10 @@ +{ + "name": "angular-sanitize", + "version": "1.8.0", + "license": "MIT", + "main": "./angular-sanitize.js", + "ignore": [], + "dependencies": { + "angular": "1.8.0" + } +} diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-sanitize/index.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-sanitize/index.js new file mode 100644 index 0000000..dd5d22e --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-sanitize/index.js @@ -0,0 +1,2 @@ +require('./angular-sanitize'); +module.exports = 'ngSanitize'; diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate-loader-url/angular-translate-loader-url.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate-loader-url/angular-translate-loader-url.js new file mode 100644 index 0000000..a2e881e --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate-loader-url/angular-translate-loader-url.js @@ -0,0 +1,73 @@ +/*! + * angular-translate - v2.18.2 - 2020-01-04 + * + * Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT + */ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define([], function () { + return (factory()); + }); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + factory(); + } +}(this, function () { + +$translateUrlLoader.$inject = ['$q', '$http']; +angular.module('pascalprecht.translate') +/** + * @ngdoc object + * @name pascalprecht.translate.$translateUrlLoader + * @requires $q + * @requires $http + * + * @description + * Creates a loading function for a typical dynamic url pattern: + * "locale.php?lang=en_US", "locale.php?lang=de_DE", "locale.php?language=nl_NL" etc. + * Prefixing the specified url, the current requested, language id will be applied + * with "?{queryParameter}={key}". + * Using this service, the response of these urls must be an object of + * key-value pairs. + * + * @param {object} options Options object, which gets the url, key and + * optional queryParameter ('lang' is used by default). + */ +.factory('$translateUrlLoader', $translateUrlLoader); + +function $translateUrlLoader($q, $http) { + + 'use strict'; + + return function (options) { + + if (!options || !options.url) { + throw new Error('Couldn\'t use urlLoader since no url is given!'); + } + + var requestParams = {}; + + requestParams[options.queryParameter || 'lang'] = options.key; + + return $http(angular.extend({ + url: options.url, + params: requestParams, + method: 'GET' + }, options.$http)) + .then(function(result) { + return result.data; + }, function () { + return $q.reject(options.key); + }); + }; +} + +$translateUrlLoader.displayName = '$translateUrlLoader'; +return 'pascalprecht.translate'; + +})); diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate-loader-url/angular-translate-loader-url.min.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate-loader-url/angular-translate-loader-url.min.js new file mode 100644 index 0000000..04f4c42 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate-loader-url/angular-translate-loader-url.min.js @@ -0,0 +1,6 @@ +/*! + * angular-translate - v2.18.2 - 2020-01-04 + * + * Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT + */ +!function(e,t){"function"==typeof define&&define.amd?define([],function(){return t()}):"object"==typeof module&&module.exports?module.exports=t():t()}(0,function(){function e(r,n){"use strict";return function(e){if(!e||!e.url)throw new Error("Couldn't use urlLoader since no url is given!");var t={};return t[e.queryParameter||"lang"]=e.key,n(angular.extend({url:e.url,params:t,method:"GET"},e.$http)).then(function(e){return e.data},function(){return r.reject(e.key)})}}return e.$inject=["$q","$http"],angular.module("pascalprecht.translate").factory("$translateUrlLoader",e),e.displayName="$translateUrlLoader","pascalprecht.translate"}); \ No newline at end of file diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate-loader-url/bower.json b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate-loader-url/bower.json new file mode 100644 index 0000000..5e57310 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate-loader-url/bower.json @@ -0,0 +1,12 @@ +{ + "name": "angular-translate-loader-url", + "description": "A plugin for Angular Translate", + "version": "2.18.2", + "main": "./angular-translate-loader-url.js", + "ignore": [], + "author": "Pascal Precht", + "license": "MIT", + "dependencies": { + "angular-translate": "~2.18.2" + } +} diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/LICENSE b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/LICENSE new file mode 100644 index 0000000..d4d931c --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2017 The angular-translate team and Pascal Precht + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-handler-log/angular-translate-handler-log.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-handler-log/angular-translate-handler-log.js new file mode 100644 index 0000000..e2909f6 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-handler-log/angular-translate-handler-log.js @@ -0,0 +1,50 @@ +/*! + * angular-translate - v2.18.2 - 2020-01-04 + * + * Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT + */ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define([], function () { + return (factory()); + }); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + factory(); + } +}(this, function () { + +$translateMissingTranslationHandlerLog.$inject = ['$log']; +angular.module('pascalprecht.translate') + +/** + * @ngdoc object + * @name pascalprecht.translate.$translateMissingTranslationHandlerLog + * @requires $log + * + * @description + * Uses angular's `$log` service to give a warning when trying to translate a + * translation id which doesn't exist. + * + * @returns {function} Handler function + */ +.factory('$translateMissingTranslationHandlerLog', $translateMissingTranslationHandlerLog); + +function $translateMissingTranslationHandlerLog ($log) { + + 'use strict'; + + return function (translationId) { + $log.warn('Translation for ' + translationId + ' doesn\'t exist'); + }; +} + +$translateMissingTranslationHandlerLog.displayName = '$translateMissingTranslationHandlerLog'; +return 'pascalprecht.translate'; + +})); diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-handler-log/angular-translate-handler-log.min.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-handler-log/angular-translate-handler-log.min.js new file mode 100644 index 0000000..2eb5872 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-handler-log/angular-translate-handler-log.min.js @@ -0,0 +1,6 @@ +/*! + * angular-translate - v2.18.2 - 2020-01-04 + * + * Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT + */ +!function(n,t){"function"==typeof define&&define.amd?define([],function(){return t()}):"object"==typeof module&&module.exports?module.exports=t():t()}(0,function(){function n(t){"use strict";return function(n){t.warn("Translation for "+n+" doesn't exist")}}return n.$inject=["$log"],angular.module("pascalprecht.translate").factory("$translateMissingTranslationHandlerLog",n),n.displayName="$translateMissingTranslationHandlerLog","pascalprecht.translate"}); \ No newline at end of file diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-interpolation-messageformat/angular-translate-interpolation-messageformat.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-interpolation-messageformat/angular-translate-interpolation-messageformat.js new file mode 100644 index 0000000..039d02a --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-interpolation-messageformat/angular-translate-interpolation-messageformat.js @@ -0,0 +1,197 @@ +/*! + * angular-translate - v2.18.2 - 2020-01-04 + * + * Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT + */ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define(["messageformat"], function (a0) { + return (factory(a0)); + }); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(require("messageformat")); + } else { + factory(root["MessageFormat"]); + } +}(this, function (MessageFormat) { + +angular.module('pascalprecht.translate') + +/** + * @ngdoc property + * @name pascalprecht.translate.TRANSLATE_MF_INTERPOLATION_CACHE + * @requires TRANSLATE_MF_INTERPOLATION_CACHE + * + * @description + * Uses MessageFormat.js to interpolate strings against some values. + */ +.constant('TRANSLATE_MF_INTERPOLATION_CACHE', '$translateMessageFormatInterpolation') + +/** + * @ngdoc object + * @name pascalprecht.translate.$translateMessageFormatInterpolationProvider + * + * @description + * Configurations for $translateMessageFormatInterpolation + */ +.provider('$translateMessageFormatInterpolation', $translateMessageFormatInterpolationProvider); + +function $translateMessageFormatInterpolationProvider() { + + 'use strict'; + + var configurer; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateMessageFormatInterpolationProvider#messageFormatConfigurer + * @methodOf pascalprecht.translate.$translateMessageFormatInterpolationProvider + * + * @description + * Defines an optional configurer for the MessageFormat instance. + * + * Note: This hook will be called whenever a new instance of MessageFormat will be created. + * + * @param {function} fn callback with the instance as argument + */ + this.messageFormatConfigurer = function (fn) { + configurer = fn; + }; + + /** + * @ngdoc object + * @name pascalprecht.translate.$translateMessageFormatInterpolation + * @requires pascalprecht.translate.TRANSLATE_MF_INTERPOLATION_CACHE + * + * @description + * Uses MessageFormat.js to interpolate strings against some values. + * + * Be aware to configure a proper sanitization strategy. + * + * See also: + * * {@link pascalprecht.translate.$translateSanitization} + * * {@link https://github.com/SlexAxton/messageformat.js} + * + * @return {object} $translateMessageFormatInterpolation Interpolator service + */ + this.$get = ['$translateSanitization', '$cacheFactory', 'TRANSLATE_MF_INTERPOLATION_CACHE', function ($translateSanitization, $cacheFactory, TRANSLATE_MF_INTERPOLATION_CACHE) { + return $translateMessageFormatInterpolation($translateSanitization, $cacheFactory, TRANSLATE_MF_INTERPOLATION_CACHE, configurer); + }]; + +} + +function $translateMessageFormatInterpolation($translateSanitization, $cacheFactory, TRANSLATE_MF_INTERPOLATION_CACHE, messageFormatConfigurer) { + + 'use strict'; + + var $translateInterpolator = {}, + $cache = $cacheFactory.get(TRANSLATE_MF_INTERPOLATION_CACHE), + // instantiate with default locale (which is 'en') + $mf = new MessageFormat('en'), + $identifier = 'messageformat'; + + if (angular.isFunction(messageFormatConfigurer)) { + messageFormatConfigurer($mf); + } + + if (!$cache) { + // create cache if it doesn't exist already + $cache = $cacheFactory(TRANSLATE_MF_INTERPOLATION_CACHE); + } + + $cache.put('en', $mf); + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateMessageFormatInterpolation#setLocale + * @methodOf pascalprecht.translate.$translateMessageFormatInterpolation + * + * @description + * Sets current locale (this is currently not use in this interpolation). + * + * @param {string} locale Language key or locale. + */ + $translateInterpolator.setLocale = function (locale) { + $mf = $cache.get(locale); + if (!$mf) { + $mf = new MessageFormat(locale); + if (angular.isFunction(messageFormatConfigurer)) { + messageFormatConfigurer($mf); + } + $cache.put(locale, $mf); + } + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateMessageFormatInterpolation#getInterpolationIdentifier + * @methodOf pascalprecht.translate.$translateMessageFormatInterpolation + * + * @description + * Returns an identifier for this interpolation service. + * + * @returns {string} $identifier + */ + $translateInterpolator.getInterpolationIdentifier = function () { + return $identifier; + }; + + /** + * @deprecated will be removed in 3.0 + * @see {@link pascalprecht.translate.$translateSanitization} + */ + $translateInterpolator.useSanitizeValueStrategy = function (value) { + $translateSanitization.useStrategy(value); + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateMessageFormatInterpolation#interpolate + * @methodOf pascalprecht.translate.$translateMessageFormatInterpolation + * + * @description + * Interpolates given string against given interpolate params using MessageFormat.js. + * + * @returns {string} interpolated string. + */ + $translateInterpolator.interpolate = function (string, interpolationParams, context, sanitizeStrategy) { + interpolationParams = interpolationParams || {}; + interpolationParams = $translateSanitization.sanitize(interpolationParams, 'params', sanitizeStrategy); + + var compiledFunction = $cache.get('mf:' + string); + + // if given string wasn't compiled yet, we do so now and never have to do it again + if (!compiledFunction) { + + // Ensure explicit type if possible + // MessageFormat checks the actual type (i.e. for amount based conditions) + for (var key in interpolationParams) { + if (interpolationParams.hasOwnProperty(key)) { + // ensure number + var number = parseInt(interpolationParams[key], 10); + if (angular.isNumber(number) && ('' + number) === interpolationParams[key]) { + interpolationParams[key] = number; + } + } + } + + compiledFunction = $mf.compile(string); + $cache.put('mf:' + string, compiledFunction); + } + + var interpolatedText = compiledFunction(interpolationParams); + return $translateSanitization.sanitize(interpolatedText, 'text', sanitizeStrategy); + }; + + return $translateInterpolator; +} + +$translateMessageFormatInterpolation.displayName = '$translateMessageFormatInterpolation'; +return 'pascalprecht.translate'; + +})); diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-interpolation-messageformat/angular-translate-interpolation-messageformat.min.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-interpolation-messageformat/angular-translate-interpolation-messageformat.min.js new file mode 100644 index 0000000..6050aef --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-interpolation-messageformat/angular-translate-interpolation-messageformat.min.js @@ -0,0 +1,6 @@ +/*! + * angular-translate - v2.18.2 - 2020-01-04 + * + * Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT + */ +!function(t,e){"function"==typeof define&&define.amd?define(["messageformat"],function(t){return e(t)}):"object"==typeof module&&module.exports?module.exports=e(require("messageformat")):e(t.MessageFormat)}(this,function(r){function i(u,t,e,n){"use strict";var a={},c=t.get(e),f=new r("en");return angular.isFunction(n)&&n(f),c||(c=t(e)),c.put("en",f),a.setLocale=function(t){(f=c.get(t))||(f=new r(t),angular.isFunction(n)&&n(f),c.put(t,f))},a.getInterpolationIdentifier=function(){return"messageformat"},a.useSanitizeValueStrategy=function(t){return u.useStrategy(t),this},a.interpolate=function(t,e,n,a){e=e||{},e=u.sanitize(e,"params",a);var r=c.get("mf:"+t);if(!r){for(var i in e)if(e.hasOwnProperty(i)){var o=parseInt(e[i],10);angular.isNumber(o)&&""+o===e[i]&&(e[i]=o)}r=f.compile(t),c.put("mf:"+t,r)}var s=r(e);return u.sanitize(s,"text",a)},a}return angular.module("pascalprecht.translate").constant("TRANSLATE_MF_INTERPOLATION_CACHE","$translateMessageFormatInterpolation").provider("$translateMessageFormatInterpolation",function(){"use strict";var a;this.messageFormatConfigurer=function(t){a=t},this.$get=["$translateSanitization","$cacheFactory","TRANSLATE_MF_INTERPOLATION_CACHE",function(t,e,n){return i(t,e,n,a)}]}),i.displayName="$translateMessageFormatInterpolation","pascalprecht.translate"}); \ No newline at end of file diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-loader-partial/angular-translate-loader-partial.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-loader-partial/angular-translate-loader-partial.js new file mode 100644 index 0000000..79419f2 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-loader-partial/angular-translate-loader-partial.js @@ -0,0 +1,585 @@ +/*! + * angular-translate - v2.18.2 - 2020-01-04 + * + * Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT + */ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define([], function () { + return (factory()); + }); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + factory(); + } +}(this, function () { + +angular.module('pascalprecht.translate') +/** + * @ngdoc object + * @name pascalprecht.translate.$translatePartialLoaderProvider + * + * @description + * By using a $translatePartialLoaderProvider you can configure a list of a needed + * translation parts directly during the configuration phase of your application's + * lifetime. All parts you add by using this provider would be loaded by + * angular-translate at the startup as soon as possible. + */ + .provider('$translatePartialLoader', $translatePartialLoader); + +function $translatePartialLoader() { + + 'use strict'; + + /** + * @constructor + * @name Part + * + * @description + * Represents Part object to add and set parts at runtime. + */ + function Part(name, priority, urlTemplate) { + this.name = name; + this.isActive = true; + this.tables = {}; + this.priority = priority || 0; + this.langPromises = {}; + this.urlTemplate = urlTemplate; + } + + /** + * @name parseUrl + * @method + * + * @description + * Returns a parsed url template string and replaces given target lang + * and part name it. + * + * @param {string|function} urlTemplate - Either a string containing an url pattern (with + * '{part}' and '{lang}') or a function(part, lang) + * returning a string. + * @param {string} targetLang - Language key for language to be used. + * @return {string} Parsed url template string + */ + Part.prototype.parseUrl = function (urlTemplate, targetLang) { + if (angular.isFunction(urlTemplate)) { + return urlTemplate(this.name, targetLang); + } + return urlTemplate.replace(/\{part\}/g, this.name).replace(/\{lang\}/g, targetLang); + }; + + Part.prototype.getTable = function (lang, $q, $http, $httpOptions, urlTemplate, errorHandler) { + + //locals + var self = this; + var lastLangPromise = this.langPromises[lang]; + var deferred = $q.defer(); + + //private helper helpers + var fetchData = function () { + return $http( + angular.extend({ + method : 'GET', + url : self.parseUrl(self.urlTemplate || urlTemplate, lang) + }, + $httpOptions) + ); + }; + + //private helper + var handleNewData = function (data) { + self.tables[lang] = data; + deferred.resolve(data); + }; + + //private helper + var rejectDeferredWithPartName = function () { + deferred.reject(self.name); + }; + + //private helper + var tryGettingThisTable = function () { + //data fetching logic + fetchData().then( + function (result) { + handleNewData(result.data); + }, + function (errorResponse) { + if (errorHandler) { + errorHandler(self.name, lang, errorResponse).then(handleNewData, rejectDeferredWithPartName); + } else { + rejectDeferredWithPartName(); + } + }); + }; + + //loading logic + if (!this.tables[lang]) { + //let's try loading the data + if (!lastLangPromise) { + //this is the first request - just go ahead and hit the server + tryGettingThisTable(); + } else { + //this is an additional request after one or more unfinished or failed requests + //chain the deferred off the previous request's promise so that this request conditionally executes + //if the previous request succeeds then the result will be passed through, but if it fails then this request will try again and hit the server + lastLangPromise.then(deferred.resolve, tryGettingThisTable); + } + //retain a reference to the last promise so we can continue the chain if another request is made before any succeed + //you can picture the promise chain as a singly-linked list (formed by the .then handler queues) that's traversed by the execution context + this.langPromises[lang] = deferred.promise; + } + else { + //the part has already been loaded - if lastLangPromise is also undefined then the table has been populated using setPart + //this breaks the promise chain because we're not tying langDeferred's outcome to a previous call's promise handler queues, but we don't care because there's no asynchronous execution context to keep track of anymore + deferred.resolve(this.tables[lang]); + } + return deferred.promise; + }; + + var parts = {}; + + function hasPart(name) { + return Object.prototype.hasOwnProperty.call(parts, name); + } + + function isStringValid(str) { + return angular.isString(str) && str !== ''; + } + + function isPartAvailable(name) { + if (!isStringValid(name)) { + throw new TypeError('Invalid type of a first argument, a non-empty string expected.'); + } + + return (hasPart(name) && parts[name].isActive); + } + + function deepExtend(dst, src) { + for (var property in src) { + if (src[property] && src[property].constructor && + src[property].constructor === Object) { + dst[property] = dst[property] || {}; + deepExtend(dst[property], src[property]); + } else { + dst[property] = src[property]; + } + } + return dst; + } + + function getPrioritizedParts() { + var prioritizedParts = []; + for (var part in parts) { + if (parts[part].isActive) { + prioritizedParts.push(parts[part]); + } + } + prioritizedParts.sort(function (a, b) { + return a.priority - b.priority; + }); + return prioritizedParts; + } + + + /** + * @ngdoc function + * @name pascalprecht.translate.$translatePartialLoaderProvider#addPart + * @methodOf pascalprecht.translate.$translatePartialLoaderProvider + * + * @description + * Registers a new part of the translation table to be loaded once the + * `angular-translate` gets into runtime phase. It does not actually load any + * translation data, but only registers a part to be loaded in the future. + * + * @param {string} name A name of the part to add + * @param {int} [priority=0] Sets the load priority of this part. + * @param {string|function} urlTemplate Either a string containing an url pattern (with + * '{part}' and '{lang}') or a function(part, lang) + * returning a string. + * + * @returns {object} $translatePartialLoaderProvider, so this method is chainable + * @throws {TypeError} The method could throw a **TypeError** if you pass the param + * of the wrong type. Please, note that the `name` param has to be a + * non-empty **string**. + */ + this.addPart = function (name, priority, urlTemplate) { + if (!isStringValid(name)) { + throw new TypeError('Couldn\'t add part, part name has to be a string!'); + } + + if (!hasPart(name)) { + parts[name] = new Part(name, priority, urlTemplate); + } + parts[name].isActive = true; + + return this; + }; + + /** + * @ngdocs function + * @name pascalprecht.translate.$translatePartialLoaderProvider#setPart + * @methodOf pascalprecht.translate.$translatePartialLoaderProvider + * + * @description + * Sets a translation table to the specified part. This method does not make the + * specified part available, but only avoids loading this part from the server. + * + * @param {string} lang A language of the given translation table + * @param {string} part A name of the target part + * @param {object} table A translation table to set to the specified part + * + * @return {object} $translatePartialLoaderProvider, so this method is chainable + * @throws {TypeError} The method could throw a **TypeError** if you pass params + * of the wrong type. Please, note that the `lang` and `part` params have to be a + * non-empty **string**s and the `table` param has to be an object. + */ + this.setPart = function (lang, part, table) { + if (!isStringValid(lang)) { + throw new TypeError('Couldn\'t set part.`lang` parameter has to be a string!'); + } + if (!isStringValid(part)) { + throw new TypeError('Couldn\'t set part.`part` parameter has to be a string!'); + } + if (typeof table !== 'object' || table === null) { + throw new TypeError('Couldn\'t set part. `table` parameter has to be an object!'); + } + + if (!hasPart(part)) { + parts[part] = new Part(part); + parts[part].isActive = false; + } + + parts[part].tables[lang] = table; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translatePartialLoaderProvider#deletePart + * @methodOf pascalprecht.translate.$translatePartialLoaderProvider + * + * @description + * Removes the previously added part of the translation data. So, `angular-translate` will not + * load it at the startup. + * + * @param {string} name A name of the part to delete + * + * @returns {object} $translatePartialLoaderProvider, so this method is chainable + * + * @throws {TypeError} The method could throw a **TypeError** if you pass the param of the wrong + * type. Please, note that the `name` param has to be a non-empty **string**. + */ + this.deletePart = function (name) { + if (!isStringValid(name)) { + throw new TypeError('Couldn\'t delete part, first arg has to be string.'); + } + + if (hasPart(name)) { + parts[name].isActive = false; + } + + return this; + }; + + + /** + * @ngdoc function + * @name pascalprecht.translate.$translatePartialLoaderProvider#isPartAvailable + * @methodOf pascalprecht.translate.$translatePartialLoaderProvider + * + * @description + * Checks if the specific part is available. A part becomes available after it was added by the + * `addPart` method. Available parts would be loaded from the server once the `angular-translate` + * asks the loader to that. + * + * @param {string} name A name of the part to check + * + * @returns {boolean} Returns **true** if the part is available now and **false** if not. + * + * @throws {TypeError} The method could throw a **TypeError** if you pass the param of the wrong + * type. Please, note that the `name` param has to be a non-empty **string**. + */ + this.isPartAvailable = isPartAvailable; + + /** + * @ngdoc object + * @name pascalprecht.translate.$translatePartialLoader + * + * @requires $q + * @requires $http + * @requires $injector + * @requires $rootScope + * @requires $translate + * + * @description + * + * @param {object} options Options object + * + * @throws {TypeError} + */ + this.$get = ['$rootScope', '$injector', '$q', '$http', '$log', + function ($rootScope, $injector, $q, $http, $log) { + + /** + * @ngdoc event + * @name pascalprecht.translate.$translatePartialLoader#$translatePartialLoaderStructureChanged + * @eventOf pascalprecht.translate.$translatePartialLoader + * @eventType broadcast on root scope + * + * @description + * A $translatePartialLoaderStructureChanged event is called when a state of the loader was + * changed somehow. It could mean either some part is added or some part is deleted. Anyway when + * you get this event the translation table is not longer current and has to be updated. + * + * @param {string} name A name of the part which is a reason why the event was fired + */ + + var service = function (options) { + if (!isStringValid(options.key)) { + throw new TypeError('Unable to load data, a key is not a non-empty string.'); + } + + if (!isStringValid(options.urlTemplate) && !angular.isFunction(options.urlTemplate)) { + throw new TypeError('Unable to load data, a urlTemplate is not a non-empty string or not a function.'); + } + + var errorHandler = options.loadFailureHandler; + if (errorHandler !== undefined) { + if (!angular.isString(errorHandler)) { + throw new Error('Unable to load data, a loadFailureHandler is not a string.'); + } else { + errorHandler = $injector.get(errorHandler); + } + } + + var loaders = [], + prioritizedParts = getPrioritizedParts(); + + angular.forEach(prioritizedParts, function (part) { + loaders.push( + part.getTable(options.key, $q, $http, options.$http, options.urlTemplate, errorHandler) + ); + part.urlTemplate = part.urlTemplate || options.urlTemplate; + }); + + // workaround for #1781 + var structureHasBeenChangedWhileLoading = false; + var dirtyCheckEventCloser = $rootScope.$on('$translatePartialLoaderStructureChanged', function () { + structureHasBeenChangedWhileLoading = true; + }); + + return $q.all(loaders) + .then(function () { + dirtyCheckEventCloser(); + if (structureHasBeenChangedWhileLoading) { + if (!options.__retries) { + // the part structure has been changed while loading (the origin ones) + // this can happen if an addPart/removePart has been invoked right after a $translate.use(lang) + // TODO maybe we can optimize this with the actual list of missing parts + options.__retries = (options.__retries || 0) + 1; + return service(options); + } else { + // the part structure has been changed again while loading (retried one) + // because this could an infinite loop, this will not load another one again + $log.warn('The partial loader has detected a multiple structure change (with addPort/removePart) ' + + 'while loading translations. You should consider using promises of $translate.use(lang) and ' + + '$translate.refresh(). Also parts should be added/removed right before an explicit refresh ' + + 'if possible.'); + } + } + var table = {}; + prioritizedParts = getPrioritizedParts(); + angular.forEach(prioritizedParts, function (part) { + deepExtend(table, part.tables[options.key]); + }); + return table; + }, function () { + dirtyCheckEventCloser(); + return $q.reject(options.key); + }); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translatePartialLoader#addPart + * @methodOf pascalprecht.translate.$translatePartialLoader + * + * @description + * Registers a new part of the translation table. This method does not actually perform any xhr + * requests to get translation data. The new parts will be loaded in order of priority from the server next time + * `angular-translate` asks the loader to load translations. + * + * @param {string} name A name of the part to add + * @param {int} [priority=0] Sets the load priority of this part. + * + * @returns {object} $translatePartialLoader, so this method is chainable + * + * @fires {$translatePartialLoaderStructureChanged} The $translatePartialLoaderStructureChanged + * event would be fired by this method in case the new part affected somehow on the loaders + * state. This way it means that there are a new translation data available to be loaded from + * the server. + * + * @throws {TypeError} The method could throw a **TypeError** if you pass the param of the wrong + * type. Please, note that the `name` param has to be a non-empty **string**. + */ + service.addPart = function (name, priority, urlTemplate) { + if (!isStringValid(name)) { + throw new TypeError('Couldn\'t add part, first arg has to be a string'); + } + + if (!hasPart(name)) { + parts[name] = new Part(name, priority, urlTemplate); + $rootScope.$emit('$translatePartialLoaderStructureChanged', name); + } else if (!parts[name].isActive) { + parts[name].isActive = true; + $rootScope.$emit('$translatePartialLoaderStructureChanged', name); + } + + return service; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translatePartialLoader#deletePart + * @methodOf pascalprecht.translate.$translatePartialLoader + * + * @description + * Deletes the previously added part of the translation data. The target part could be deleted + * either logically or physically. When the data is deleted logically it is not actually deleted + * from the browser, but the loader marks it as not active and prevents it from affecting on the + * translations. If the deleted in such way part is added again, the loader will use the + * previously loaded data rather than loading it from the server once more time. But if the data + * is deleted physically, the loader will completely remove all information about it. So in case + * of recycling this part will be loaded from the server again. + * + * @param {string} name A name of the part to delete + * @param {boolean=} [removeData=false] An indicator if the loader has to remove a loaded + * translation data physically. If the `removeData` if set to **false** the loaded data will not be + * deleted physically and might be reused in the future to prevent an additional xhr requests. + * + * @returns {object} $translatePartialLoader, so this method is chainable + * + * @fires {$translatePartialLoaderStructureChanged} The $translatePartialLoaderStructureChanged + * event would be fired by this method in case a part deletion process affects somehow on the + * loaders state. This way it means that some part of the translation data is now deprecated and + * the translation table has to be recompiled with the remaining translation parts. + * + * @throws {TypeError} The method could throw a **TypeError** if you pass some param of the + * wrong type. Please, note that the `name` param has to be a non-empty **string** and + * the `removeData` param has to be either **undefined** or **boolean**. + */ + service.deletePart = function (name, removeData) { + if (!isStringValid(name)) { + throw new TypeError('Couldn\'t delete part, first arg has to be string'); + } + + if (removeData === undefined) { + removeData = false; + } else if (typeof removeData !== 'boolean') { + throw new TypeError('Invalid type of a second argument, a boolean expected.'); + } + + if (hasPart(name)) { + var wasActive = parts[name].isActive; + if (removeData) { + var $translate = $injector.get('$translate'); + var cache = $translate.loaderCache(); + if (typeof(cache) === 'string') { + // getting on-demand instance of loader + cache = $injector.get(cache); + } + // Purging items from cache... + if (typeof(cache) === 'object') { + angular.forEach(parts[name].tables, function (value, key) { + cache.remove(parts[name].parseUrl(parts[name].urlTemplate, key)); + }); + } + delete parts[name]; + } else { + parts[name].isActive = false; + } + if (wasActive) { + $rootScope.$emit('$translatePartialLoaderStructureChanged', name); + } + } + + return service; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translatePartialLoader#isPartLoaded + * @methodOf pascalprecht.translate.$translatePartialLoader + * + * @description + * Checks if the registered translation part is loaded into the translation table. + * + * @param {string} name A name of the part + * @param {string} lang A key of the language + * + * @returns {boolean} Returns **true** if the translation of the part is loaded to the translation table and **false** if not. + * + * @throws {TypeError} The method could throw a **TypeError** if you pass the param of the wrong + * type. Please, note that the `name` and `lang` params have to be non-empty **string**. + */ + service.isPartLoaded = function (name, lang) { + return angular.isDefined(parts[name]) && angular.isDefined(parts[name].tables[lang]); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translatePartialLoader#getRegisteredParts + * @methodOf pascalprecht.translate.$translatePartialLoader + * + * @description + * Gets names of the parts that were added with the `addPart`. + * + * @returns {array} Returns array of registered parts, if none were registered then an empty array is returned. + */ + service.getRegisteredParts = function () { + var registeredParts = []; + angular.forEach(parts, function (p) { + if (p.isActive) { + registeredParts.push(p.name); + } + }); + return registeredParts; + }; + + + /** + * @ngdoc function + * @name pascalprecht.translate.$translatePartialLoader#isPartAvailable + * @methodOf pascalprecht.translate.$translatePartialLoader + * + * @description + * Checks if a target translation part is available. The part becomes available just after it was + * added by the `addPart` method. Part's availability does not mean that it was loaded from the + * server, but only that it was added to the loader. The available part might be loaded next + * time the loader is called. + * + * @param {string} name A name of the part to delete + * + * @returns {boolean} Returns **true** if the part is available now and **false** if not. + * + * @throws {TypeError} The method could throw a **TypeError** if you pass the param of the wrong + * type. Please, note that the `name` param has to be a non-empty **string**. + */ + service.isPartAvailable = isPartAvailable; + + return service; + + }]; + +} + +$translatePartialLoader.displayName = '$translatePartialLoader'; +return 'pascalprecht.translate'; + +})); diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-loader-partial/angular-translate-loader-partial.min.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-loader-partial/angular-translate-loader-partial.min.js new file mode 100644 index 0000000..74ad786 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-loader-partial/angular-translate-loader-partial.min.js @@ -0,0 +1,6 @@ +/*! + * angular-translate - v2.18.2 - 2020-01-04 + * + * Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT + */ +!function(t,e){"function"==typeof define&&define.amd?define([],function(){return e()}):"object"==typeof module&&module.exports?module.exports=e():e()}(0,function(){function t(){"use strict";function a(t,e,r){this.name=t,this.isActive=!0,this.tables={},this.priority=e||0,this.langPromises={},this.urlTemplate=r}a.prototype.parseUrl=function(t,e){return angular.isFunction(t)?t(this.name,e):t.replace(/\{part\}/g,this.name).replace(/\{lang\}/g,e)},a.prototype.getTable=function(e,t,r,a,n,i){var o=this,s=this.langPromises[e],l=t.defer(),u=function(t){o.tables[e]=t,l.resolve(t)},c=function(){l.reject(o.name)},p=function(){r(angular.extend({method:"GET",url:o.parseUrl(o.urlTemplate||n,e)},a)).then(function(t){u(t.data)},function(t){i?i(o.name,e,t).then(u,c):c()})};return this.tables[e]?l.resolve(this.tables[e]):(s?s.then(l.resolve,p):p(),this.langPromises[e]=l.promise),l.promise};var n={};function i(t){return Object.prototype.hasOwnProperty.call(n,t)}function f(t){return angular.isString(t)&&""!==t}function t(t){if(!f(t))throw new TypeError("Invalid type of a first argument, a non-empty string expected.");return i(t)&&n[t].isActive}function d(){var t=[];for(var e in n)n[e].isActive&&t.push(n[e]);return t.sort(function(t,e){return t.priority-e.priority}),t}this.addPart=function(t,e,r){if(!f(t))throw new TypeError("Couldn't add part, part name has to be a string!");return i(t)||(n[t]=new a(t,e,r)),n[t].isActive=!0,this},this.setPart=function(t,e,r){if(!f(t))throw new TypeError("Couldn't set part.`lang` parameter has to be a string!");if(!f(e))throw new TypeError("Couldn't set part.`part` parameter has to be a string!");if("object"!=typeof r||null===r)throw new TypeError("Couldn't set part. `table` parameter has to be an object!");return i(e)||(n[e]=new a(e),n[e].isActive=!1),n[e].tables[t]=r,this},this.deletePart=function(t){if(!f(t))throw new TypeError("Couldn't delete part, first arg has to be string.");return i(t)&&(n[t].isActive=!1),this},this.isPartAvailable=t,this.$get=["$rootScope","$injector","$q","$http","$log",function(o,s,l,u,c){var p=function(r){if(!f(r.key))throw new TypeError("Unable to load data, a key is not a non-empty string.");if(!f(r.urlTemplate)&&!angular.isFunction(r.urlTemplate))throw new TypeError("Unable to load data, a urlTemplate is not a non-empty string or not a function.");var e=r.loadFailureHandler;if(void 0!==e){if(!angular.isString(e))throw new Error("Unable to load data, a loadFailureHandler is not a string.");e=s.get(e)}var a=[],t=d();angular.forEach(t,function(t){a.push(t.getTable(r.key,l,u,r.$http,r.urlTemplate,e)),t.urlTemplate=t.urlTemplate||r.urlTemplate});var n=!1,i=o.$on("$translatePartialLoaderStructureChanged",function(){n=!0});return l.all(a).then(function(){if(i(),n){if(!r.__retries)return r.__retries=(r.__retries||0)+1,p(r);c.warn("The partial loader has detected a multiple structure change (with addPort/removePart) while loading translations. You should consider using promises of $translate.use(lang) and $translate.refresh(). Also parts should be added/removed right before an explicit refresh if possible.")}var e={};return t=d(),angular.forEach(t,function(t){!function t(e,r){for(var a in r)r[a]&&r[a].constructor&&r[a].constructor===Object?(e[a]=e[a]||{},t(e[a],r[a])):e[a]=r[a];return e}(e,t.tables[r.key])}),e},function(){return i(),l.reject(r.key)})};return p.addPart=function(t,e,r){if(!f(t))throw new TypeError("Couldn't add part, first arg has to be a string");return i(t)?n[t].isActive||(n[t].isActive=!0,o.$emit("$translatePartialLoaderStructureChanged",t)):(n[t]=new a(t,e,r),o.$emit("$translatePartialLoaderStructureChanged",t)),p},p.deletePart=function(r,t){if(!f(r))throw new TypeError("Couldn't delete part, first arg has to be string");if(void 0===t)t=!1;else if("boolean"!=typeof t)throw new TypeError("Invalid type of a second argument, a boolean expected.");if(i(r)){var e=n[r].isActive;if(t){var a=s.get("$translate").loaderCache();"string"==typeof a&&(a=s.get(a)),"object"==typeof a&&angular.forEach(n[r].tables,function(t,e){a.remove(n[r].parseUrl(n[r].urlTemplate,e))}),delete n[r]}else n[r].isActive=!1;e&&o.$emit("$translatePartialLoaderStructureChanged",r)}return p},p.isPartLoaded=function(t,e){return angular.isDefined(n[t])&&angular.isDefined(n[t].tables[e])},p.getRegisteredParts=function(){var e=[];return angular.forEach(n,function(t){t.isActive&&e.push(t.name)}),e},p.isPartAvailable=t,p}]}return angular.module("pascalprecht.translate").provider("$translatePartialLoader",t),t.displayName="$translatePartialLoader","pascalprecht.translate"}); \ No newline at end of file diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-loader-static-files/angular-translate-loader-static-files.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-loader-static-files/angular-translate-loader-static-files.js new file mode 100644 index 0000000..7a911f1 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-loader-static-files/angular-translate-loader-static-files.js @@ -0,0 +1,112 @@ +/*! + * angular-translate - v2.18.2 - 2020-01-04 + * + * Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT + */ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define([], function () { + return (factory()); + }); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + factory(); + } +}(this, function () { + +$translateStaticFilesLoader.$inject = ['$q', '$http']; +angular.module('pascalprecht.translate') +/** + * @ngdoc object + * @name pascalprecht.translate.$translateStaticFilesLoader + * @requires $q + * @requires $http + * + * @description + * Creates a loading function for a typical static file url pattern: + * "lang-en_US.json", "lang-de_DE.json", etc. Using this builder, + * the response of these urls must be an object of key-value pairs. + * + * @param {object} options Options object, which gets prefix, suffix, key, and fileMap + */ +.factory('$translateStaticFilesLoader', $translateStaticFilesLoader); + +function $translateStaticFilesLoader($q, $http) { + + 'use strict'; + + return function (options) { + + if (!options || (!angular.isArray(options.files) && (!angular.isString(options.prefix) || !angular.isString(options.suffix)))) { + throw new Error('Couldn\'t load static files, no files and prefix or suffix specified!'); + } + + if (!options.files) { + options.files = [{ + prefix: options.prefix, + suffix: options.suffix + }]; + } + + var load = function (file) { + if (!file || (!angular.isString(file.prefix) || !angular.isString(file.suffix))) { + throw new Error('Couldn\'t load static file, no prefix or suffix specified!'); + } + + var fileUrl = [ + file.prefix, + options.key, + file.suffix + ].join(''); + + if (angular.isObject(options.fileMap) && options.fileMap[fileUrl]) { + fileUrl = options.fileMap[fileUrl]; + } + + return $http(angular.extend({ + url: fileUrl, + method: 'GET' + }, options.$http)) + .then(function(result) { + return result.data; + }, function () { + return $q.reject(options.key); + }); + }; + + var promises = [], + length = options.files.length; + + for (var i = 0; i < length; i++) { + promises.push(load({ + prefix: options.files[i].prefix, + key: options.key, + suffix: options.files[i].suffix + })); + } + + return $q.all(promises) + .then(function (data) { + var length = data.length, + mergedData = {}; + + for (var i = 0; i < length; i++) { + for (var key in data[i]) { + mergedData[key] = data[i][key]; + } + } + + return mergedData; + }); + }; +} + +$translateStaticFilesLoader.displayName = '$translateStaticFilesLoader'; +return 'pascalprecht.translate'; + +})); diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-loader-static-files/angular-translate-loader-static-files.min.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-loader-static-files/angular-translate-loader-static-files.min.js new file mode 100644 index 0000000..a66674d --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-loader-static-files/angular-translate-loader-static-files.min.js @@ -0,0 +1,6 @@ +/*! + * angular-translate - v2.18.2 - 2020-01-04 + * + * Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT + */ +!function(e,i){"function"==typeof define&&define.amd?define([],function(){return i()}):"object"==typeof module&&module.exports?module.exports=i():i()}(0,function(){function e(n,a){"use strict";return function(r){if(!(r&&(angular.isArray(r.files)||angular.isString(r.prefix)&&angular.isString(r.suffix))))throw new Error("Couldn't load static files, no files and prefix or suffix specified!");r.files||(r.files=[{prefix:r.prefix,suffix:r.suffix}]);for(var e=function(e){if(!e||!angular.isString(e.prefix)||!angular.isString(e.suffix))throw new Error("Couldn't load static file, no prefix or suffix specified!");var i=[e.prefix,r.key,e.suffix].join("");return angular.isObject(r.fileMap)&&r.fileMap[i]&&(i=r.fileMap[i]),a(angular.extend({url:i,method:"GET"},r.$http)).then(function(e){return e.data},function(){return n.reject(r.key)})},i=[],t=r.files.length,f=0;f= 4) { + var $cookies = $injector.get('$cookies'); + delegate = { + get : function (key) { + return $cookies.get(key); + }, + put : function (key, value) { + $cookies.put(key, value); + } + }; + } else { + var $cookieStore = $injector.get('$cookieStore'); + delegate = { + get : function (key) { + return $cookieStore.get(key); + }, + put : function (key, value) { + $cookieStore.put(key, value); + } + }; + } + + var $translateCookieStorage = { + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateCookieStorage#get + * @methodOf pascalprecht.translate.$translateCookieStorage + * + * @description + * Returns an item from cookieStorage by given name. + * + * @param {string} name Item name + * @return {string} Value of item name + */ + get : function (name) { + return delegate.get(name); + }, + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateCookieStorage#set + * @methodOf pascalprecht.translate.$translateCookieStorage + * + * @description + * Sets an item in cookieStorage by given name. + * + * @deprecated use #put + * + * @param {string} name Item name + * @param {string} value Item value + */ + set : function (name, value) { + delegate.put(name, value); + }, + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateCookieStorage#put + * @methodOf pascalprecht.translate.$translateCookieStorage + * + * @description + * Sets an item in cookieStorage by given name. + * + * @param {string} name Item name + * @param {string} value Item value + */ + put : function (name, value) { + delegate.put(name, value); + } + }; + + return $translateCookieStorage; +} + +$translateCookieStorageFactory.displayName = '$translateCookieStorage'; +return 'pascalprecht.translate'; + +})); diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-storage-cookie/angular-translate-storage-cookie.min.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-storage-cookie/angular-translate-storage-cookie.min.js new file mode 100644 index 0000000..ee5d077 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-storage-cookie/angular-translate-storage-cookie.min.js @@ -0,0 +1,6 @@ +/*! + * angular-translate - v2.18.2 - 2020-01-04 + * + * Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT + */ +!function(t,e){"function"==typeof define&&define.amd?define([],function(){return e()}):"object"==typeof module&&module.exports?module.exports=e():e()}(0,function(){function t(t){"use strict";var n;if(1===angular.version.major&&4<=angular.version.minor){var o=t.get("$cookies");n={get:function(t){return o.get(t)},put:function(t,e){o.put(t,e)}}}else{var r=t.get("$cookieStore");n={get:function(t){return r.get(t)},put:function(t,e){r.put(t,e)}}}return{get:function(t){return n.get(t)},set:function(t,e){n.put(t,e)},put:function(t,e){n.put(t,e)}}}return t.$inject=["$injector"],angular.module("pascalprecht.translate").factory("$translateCookieStorage",t),t.displayName="$translateCookieStorage","pascalprecht.translate"}); \ No newline at end of file diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-storage-local/angular-translate-storage-local.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-storage-local/angular-translate-storage-local.js new file mode 100644 index 0000000..d82b52e --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-storage-local/angular-translate-storage-local.js @@ -0,0 +1,123 @@ +/*! + * angular-translate - v2.18.2 - 2020-01-04 + * + * Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT + */ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define([], function () { + return (factory()); + }); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + factory(); + } +}(this, function () { + +$translateLocalStorageFactory.$inject = ['$window', '$translateCookieStorage']; +angular.module('pascalprecht.translate') + +/** + * @ngdoc object + * @name pascalprecht.translate.$translateLocalStorage + * @requires $window + * @requires $translateCookieStorage + * + * @description + * Abstraction layer for localStorage. This service is used when telling angular-translate + * to use localStorage as storage. + * + */ +.factory('$translateLocalStorage', $translateLocalStorageFactory); + +function $translateLocalStorageFactory($window, $translateCookieStorage) { + + 'use strict'; + + // Setup adapter + var localStorageAdapter = (function(){ + var langKey; + return { + /** + * @ngdoc function + * @name pascalprecht.translate.$translateLocalStorage#get + * @methodOf pascalprecht.translate.$translateLocalStorage + * + * @description + * Returns an item from localStorage by given name. + * + * @param {string} name Item name + * @return {string} Value of item name + */ + get: function (name) { + if(!langKey) { + langKey = $window.localStorage.getItem(name); + } + + return langKey; + }, + /** + * @ngdoc function + * @name pascalprecht.translate.$translateLocalStorage#set + * @methodOf pascalprecht.translate.$translateLocalStorage + * + * @description + * Sets an item in localStorage by given name. + * + * @deprecated use #put + * + * @param {string} name Item name + * @param {string} value Item value + */ + set: function (name, value) { + langKey=value; + $window.localStorage.setItem(name, value); + }, + /** + * @ngdoc function + * @name pascalprecht.translate.$translateLocalStorage#put + * @methodOf pascalprecht.translate.$translateLocalStorage + * + * @description + * Sets an item in localStorage by given name. + * + * @param {string} name Item name + * @param {string} value Item value + */ + put: function (name, value) { + langKey=value; + $window.localStorage.setItem(name, value); + } + }; + }()); + + var hasLocalStorageSupport = 'localStorage' in $window; + if (hasLocalStorageSupport) { + var testKey = 'pascalprecht.translate.storageTest'; + try { + // this check have to be wrapped within a try/catch because on + // a SecurityError: Dom Exception 18 on iOS + if ($window.localStorage !== null) { + $window.localStorage.setItem(testKey, 'foo'); + $window.localStorage.removeItem(testKey); + hasLocalStorageSupport = true; + } else { + hasLocalStorageSupport = false; + } + } catch (e){ + hasLocalStorageSupport = false; + } + } + var $translateLocalStorage = hasLocalStorageSupport ? localStorageAdapter : $translateCookieStorage; + return $translateLocalStorage; +} + +$translateLocalStorageFactory.displayName = '$translateLocalStorageFactory'; +return 'pascalprecht.translate'; + +})); diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-storage-local/angular-translate-storage-local.min.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-storage-local/angular-translate-storage-local.min.js new file mode 100644 index 0000000..5df4d0a --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate-storage-local/angular-translate-storage-local.min.js @@ -0,0 +1,6 @@ +/*! + * angular-translate - v2.18.2 - 2020-01-04 + * + * Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT + */ +!function(t,e){"function"==typeof define&&define.amd?define([],function(){return e()}):"object"==typeof module&&module.exports?module.exports=e():e()}(0,function(){function t(a,t){"use strict";var o,e={get:function(t){return o||(o=a.localStorage.getItem(t)),o},set:function(t,e){o=e,a.localStorage.setItem(t,e)},put:function(t,e){o=e,a.localStorage.setItem(t,e)}},r="localStorage"in a;if(r){var n="pascalprecht.translate.storageTest";try{r=null!==a.localStorage&&(a.localStorage.setItem(n,"foo"),a.localStorage.removeItem(n),!0)}catch(t){r=!1}}return r?e:t}return t.$inject=["$window","$translateCookieStorage"],angular.module("pascalprecht.translate").factory("$translateLocalStorage",t),t.displayName="$translateLocalStorageFactory","pascalprecht.translate"}); \ No newline at end of file diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate.js new file mode 100644 index 0000000..acd0b91 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate.js @@ -0,0 +1,3785 @@ +/*! + * angular-translate - v2.18.2 - 2020-01-04 + * + * Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT + */ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define([], function () { + return (factory()); + }); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + factory(); + } +}(this, function () { + +/** + * @ngdoc overview + * @name pascalprecht.translate + * + * @description + * The main module which holds everything together. + */ +runTranslate.$inject = ['$translate']; +$translate.$inject = ['$STORAGE_KEY', '$windowProvider', '$translateSanitizationProvider', 'pascalprechtTranslateOverrider']; +$translateDefaultInterpolation.$inject = ['$interpolate', '$translateSanitization']; +translateDirective.$inject = ['$translate', '$interpolate', '$compile', '$parse', '$rootScope']; +translateAttrDirective.$inject = ['$translate', '$rootScope']; +translateCloakDirective.$inject = ['$translate', '$rootScope']; +translateFilterFactory.$inject = ['$parse', '$translate']; +$translationCache.$inject = ['$cacheFactory']; +angular.module('pascalprecht.translate', ['ng']) + .run(runTranslate); + +function runTranslate($translate) { + + 'use strict'; + + var key = $translate.storageKey(), + storage = $translate.storage(); + + var fallbackFromIncorrectStorageValue = function () { + var preferred = $translate.preferredLanguage(); + if (angular.isString(preferred)) { + $translate.use(preferred); + // $translate.use() will also remember the language. + // So, we don't need to call storage.put() here. + } else { + storage.put(key, $translate.use()); + } + }; + + fallbackFromIncorrectStorageValue.displayName = 'fallbackFromIncorrectStorageValue'; + + if (storage) { + if (!storage.get(key)) { + fallbackFromIncorrectStorageValue(); + } else { + $translate.use(storage.get(key))['catch'](fallbackFromIncorrectStorageValue); + } + } else if (angular.isString($translate.preferredLanguage())) { + $translate.use($translate.preferredLanguage()); + } +} + +runTranslate.displayName = 'runTranslate'; + +/** + * @ngdoc object + * @name pascalprecht.translate.$translateSanitizationProvider + * + * @description + * + * Configurations for $translateSanitization + */ +angular.module('pascalprecht.translate').provider('$translateSanitization', $translateSanitizationProvider); + +function $translateSanitizationProvider () { + + 'use strict'; + + var $sanitize, + $sce, + currentStrategy = null, // TODO change to either 'sanitize', 'escape' or ['sanitize', 'escapeParameters'] in 3.0. + hasConfiguredStrategy = false, + hasShownNoStrategyConfiguredWarning = false, + strategies; + + /** + * Definition of a sanitization strategy function + * @callback StrategyFunction + * @param {string|object} value - value to be sanitized (either a string or an interpolated value map) + * @param {string} mode - either 'text' for a string (translation) or 'params' for the interpolated params + * @return {string|object} + */ + + /** + * @ngdoc property + * @name strategies + * @propertyOf pascalprecht.translate.$translateSanitizationProvider + * + * @description + * Following strategies are built-in: + *

      + *
      sanitize
      + *
      Sanitizes HTML in the translation text using $sanitize
      + *
      escape
      + *
      Escapes HTML in the translation
      + *
      sanitizeParameters
      + *
      Sanitizes HTML in the values of the interpolation parameters using $sanitize
      + *
      escapeParameters
      + *
      Escapes HTML in the values of the interpolation parameters
      + *
      escaped
      + *
      Support legacy strategy name 'escaped' for backwards compatibility (will be removed in 3.0)
      + *
      + * + */ + + strategies = { + sanitize: function (value, mode/*, context*/) { + if (mode === 'text') { + value = htmlSanitizeValue(value); + } + return value; + }, + escape: function (value, mode/*, context*/) { + if (mode === 'text') { + value = htmlEscapeValue(value); + } + return value; + }, + sanitizeParameters: function (value, mode/*, context*/) { + if (mode === 'params') { + value = mapInterpolationParameters(value, htmlSanitizeValue); + } + return value; + }, + escapeParameters: function (value, mode/*, context*/) { + if (mode === 'params') { + value = mapInterpolationParameters(value, htmlEscapeValue); + } + return value; + }, + sce: function (value, mode, context) { + if (mode === 'text') { + value = htmlTrustValue(value); + } else if (mode === 'params') { + if (context !== 'filter') { + // do html escape in filter context #1101 + value = mapInterpolationParameters(value, htmlEscapeValue); + } + } + return value; + }, + sceParameters: function (value, mode/*, context*/) { + if (mode === 'params') { + value = mapInterpolationParameters(value, htmlTrustValue); + } + return value; + } + }; + // Support legacy strategy name 'escaped' for backwards compatibility. + // TODO should be removed in 3.0 + strategies.escaped = strategies.escapeParameters; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateSanitizationProvider#addStrategy + * @methodOf pascalprecht.translate.$translateSanitizationProvider + * + * @description + * Adds a sanitization strategy to the list of known strategies. + * + * @param {string} strategyName - unique key for a strategy + * @param {StrategyFunction} strategyFunction - strategy function + * @returns {object} this + */ + this.addStrategy = function (strategyName, strategyFunction) { + strategies[strategyName] = strategyFunction; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateSanitizationProvider#removeStrategy + * @methodOf pascalprecht.translate.$translateSanitizationProvider + * + * @description + * Removes a sanitization strategy from the list of known strategies. + * + * @param {string} strategyName - unique key for a strategy + * @returns {object} this + */ + this.removeStrategy = function (strategyName) { + delete strategies[strategyName]; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateSanitizationProvider#useStrategy + * @methodOf pascalprecht.translate.$translateSanitizationProvider + * + * @description + * Selects a sanitization strategy. When an array is provided the strategies will be executed in order. + * + * @param {string|StrategyFunction|array} strategy The sanitization strategy / strategies which should be used. Either a name of an existing strategy, a custom strategy function, or an array consisting of multiple names and / or custom functions. + * @returns {object} this + */ + this.useStrategy = function (strategy) { + hasConfiguredStrategy = true; + currentStrategy = strategy; + return this; + }; + + /** + * @ngdoc object + * @name pascalprecht.translate.$translateSanitization + * @requires $injector + * @requires $log + * + * @description + * Sanitizes interpolation parameters and translated texts. + * + */ + this.$get = ['$injector', '$log', function ($injector, $log) { + + var cachedStrategyMap = {}; + + var applyStrategies = function (value, mode, context, selectedStrategies) { + angular.forEach(selectedStrategies, function (selectedStrategy) { + if (angular.isFunction(selectedStrategy)) { + value = selectedStrategy(value, mode, context); + } else if (angular.isFunction(strategies[selectedStrategy])) { + value = strategies[selectedStrategy](value, mode, context); + } else if (angular.isString(strategies[selectedStrategy])) { + if (!cachedStrategyMap[strategies[selectedStrategy]]) { + try { + cachedStrategyMap[strategies[selectedStrategy]] = $injector.get(strategies[selectedStrategy]); + } catch (e) { + cachedStrategyMap[strategies[selectedStrategy]] = function() {}; + throw new Error('pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: \'' + selectedStrategy + '\''); + } + } + value = cachedStrategyMap[strategies[selectedStrategy]](value, mode, context); + } else { + throw new Error('pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: \'' + selectedStrategy + '\''); + } + }); + return value; + }; + + // TODO: should be removed in 3.0 + var showNoStrategyConfiguredWarning = function () { + if (!hasConfiguredStrategy && !hasShownNoStrategyConfiguredWarning) { + $log.warn('pascalprecht.translate.$translateSanitization: No sanitization strategy has been configured. This can have serious security implications. See http://angular-translate.github.io/docs/#/guide/19_security for details.'); + hasShownNoStrategyConfiguredWarning = true; + } + }; + + if ($injector.has('$sanitize')) { + $sanitize = $injector.get('$sanitize'); + } + if ($injector.has('$sce')) { + $sce = $injector.get('$sce'); + } + + return { + /** + * @ngdoc function + * @name pascalprecht.translate.$translateSanitization#useStrategy + * @methodOf pascalprecht.translate.$translateSanitization + * + * @description + * Selects a sanitization strategy. When an array is provided the strategies will be executed in order. + * + * @param {string|StrategyFunction|array} strategy The sanitization strategy / strategies which should be used. Either a name of an existing strategy, a custom strategy function, or an array consisting of multiple names and / or custom functions. + */ + useStrategy: (function (self) { + return function (strategy) { + self.useStrategy(strategy); + }; + })(this), + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateSanitization#sanitize + * @methodOf pascalprecht.translate.$translateSanitization + * + * @description + * Sanitizes a value. + * + * @param {string|object} value The value which should be sanitized. + * @param {string} mode The current sanitization mode, either 'params' or 'text'. + * @param {string|StrategyFunction|array} [strategy] Optional custom strategy which should be used instead of the currently selected strategy. + * @param {string} [context] The context of this call: filter, service. Default is service + * @returns {string|object} sanitized value + */ + sanitize: function (value, mode, strategy, context) { + if (!currentStrategy) { + showNoStrategyConfiguredWarning(); + } + + if (!strategy && strategy !== null) { + strategy = currentStrategy; + } + + if (!strategy) { + return value; + } + + if (!context) { + context = 'service'; + } + + var selectedStrategies = angular.isArray(strategy) ? strategy : [strategy]; + return applyStrategies(value, mode, context, selectedStrategies); + } + }; + }]; + + var htmlEscapeValue = function (value) { + var element = angular.element('
      '); + element.text(value); // not chainable, see #1044 + return element.html(); + }; + + var htmlSanitizeValue = function (value) { + if (!$sanitize) { + throw new Error('pascalprecht.translate.$translateSanitization: Error cannot find $sanitize service. Either include the ngSanitize module (https://docs.angularjs.org/api/ngSanitize) or use a sanitization strategy which does not depend on $sanitize, such as \'escape\'.'); + } + return $sanitize(value); + }; + + var htmlTrustValue = function (value) { + if (!$sce) { + throw new Error('pascalprecht.translate.$translateSanitization: Error cannot find $sce service.'); + } + return $sce.trustAsHtml(value); + }; + + var mapInterpolationParameters = function (value, iteratee, stack) { + if (angular.isDate(value)) { + return value; + } else if (angular.isObject(value)) { + var result = angular.isArray(value) ? [] : {}; + + if (!stack) { + stack = []; + } else { + if (stack.indexOf(value) > -1) { + throw new Error('pascalprecht.translate.$translateSanitization: Error cannot interpolate parameter due recursive object'); + } + } + + stack.push(value); + angular.forEach(value, function (propertyValue, propertyKey) { + + /* Skipping function properties. */ + if (angular.isFunction(propertyValue)) { + return; + } + + result[propertyKey] = mapInterpolationParameters(propertyValue, iteratee, stack); + }); + stack.splice(-1, 1); // remove last + + return result; + } else if (angular.isNumber(value)) { + return value; + } else if (value === true || value === false) { + return value; + } else if (!angular.isUndefined(value) && value !== null) { + return iteratee(value); + } else { + return value; + } + }; +} + +/** + * @ngdoc object + * @name pascalprecht.translate.$translateProvider + * @description + * + * $translateProvider allows developers to register translation-tables, asynchronous loaders + * and similar to configure translation behavior directly inside of a module. + * + */ +angular.module('pascalprecht.translate') + .constant('pascalprechtTranslateOverrider', {}) + .provider('$translate', $translate); + +function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvider, pascalprechtTranslateOverrider) { + + 'use strict'; + + var $translationTable = {}, + $preferredLanguage, + $availableLanguageKeys = [], + $languageKeyAliases, + $fallbackLanguage, + $fallbackWasString, + $uses, + $nextLang, + $storageFactory, + $storageKey = $STORAGE_KEY, + $storagePrefix, + $missingTranslationHandlerFactory, + $interpolationFactory, + $interpolatorFactories = [], + $loaderFactory, + $cloakClassName = 'translate-cloak', + $loaderOptions, + $notFoundIndicatorLeft, + $notFoundIndicatorRight, + $postCompilingEnabled = false, + $forceAsyncReloadEnabled = false, + $nestedObjectDelimeter = '.', + $isReady = false, + $keepContent = false, + loaderCache, + directivePriority = 0, + statefulFilter = true, + postProcessFn, + uniformLanguageTagResolver = 'default', + languageTagResolver = { + 'default' : function (tag) { + return (tag || '').split('-').join('_'); + }, + java : function (tag) { + var temp = (tag || '').split('-').join('_'); + var parts = temp.split('_'); + return parts.length > 1 ? (parts[0].toLowerCase() + '_' + parts[1].toUpperCase()) : temp; + }, + bcp47 : function (tag) { + var temp = (tag || '').split('_').join('-'); + var parts = temp.split('-'); + + switch (parts.length) { + case 1: // language only + parts[0] = parts[0].toLowerCase(); + break; + case 2: // language-script or language-region + parts[0] = parts[0].toLowerCase(); + if (parts[1].length === 4) { // parts[1] is script + parts[1] = parts[1].charAt(0).toUpperCase() + parts[1].slice(1).toLowerCase(); + } else { // parts[1] is region + parts[1] = parts[1].toUpperCase(); + } + break; + case 3: // language-script-region + parts[0] = parts[0].toLowerCase(); + parts[1] = parts[1].charAt(0).toUpperCase() + parts[1].slice(1).toLowerCase(); + parts[2] = parts[2].toUpperCase(); + break; + default: + return temp; + } + + return parts.join('-'); + }, + 'iso639-1' : function (tag) { + var temp = (tag || '').split('_').join('-'); + var parts = temp.split('-'); + return parts[0].toLowerCase(); + } + }; + + var version = '2.18.2'; + + // tries to determine the browsers language + var getFirstBrowserLanguage = function () { + + // internal purpose only + if (angular.isFunction(pascalprechtTranslateOverrider.getLocale)) { + return pascalprechtTranslateOverrider.getLocale(); + } + + var nav = $windowProvider.$get().navigator, + browserLanguagePropertyKeys = ['language', 'browserLanguage', 'systemLanguage', 'userLanguage'], + i, + language; + + // support for HTML 5.1 "navigator.languages" + if (angular.isArray(nav.languages)) { + for (i = 0; i < nav.languages.length; i++) { + language = nav.languages[i]; + if (language && language.length) { + return language; + } + } + } + + // support for other well known properties in browsers + for (i = 0; i < browserLanguagePropertyKeys.length; i++) { + language = nav[browserLanguagePropertyKeys[i]]; + if (language && language.length) { + return language; + } + } + + return null; + }; + getFirstBrowserLanguage.displayName = 'angular-translate/service: getFirstBrowserLanguage'; + + // tries to determine the browsers locale + var getLocale = function () { + var locale = getFirstBrowserLanguage() || ''; + if (languageTagResolver[uniformLanguageTagResolver]) { + locale = languageTagResolver[uniformLanguageTagResolver](locale); + } + return locale; + }; + getLocale.displayName = 'angular-translate/service: getLocale'; + + /** + * @name indexOf + * @private + * + * @description + * indexOf polyfill. Kinda sorta. + * + * @param {array} array Array to search in. + * @param {string} searchElement Element to search for. + * + * @returns {int} Index of search element. + */ + var indexOf = function (array, searchElement) { + for (var i = 0, len = array.length; i < len; i++) { + if (array[i] === searchElement) { + return i; + } + } + return -1; + }; + + /** + * @name trim + * @private + * + * @description + * trim polyfill + * + * @returns {string} The string stripped of whitespace from both ends + */ + var trim = function () { + return this.toString().replace(/^\s+|\s+$/g, ''); + }; + + /** + * @name lowercase + * @private + * + * @description + * Return the lowercase string only if the type is string + * + * @returns {string} The string all in lowercase + */ + var lowercase = function (string) { + return angular.isString(string) ? string.toLowerCase() : string; + }; + + var negotiateLocale = function (preferred) { + if (!preferred) { + return; + } + + var avail = [], + locale = lowercase(preferred), + i = 0, + n = $availableLanguageKeys.length; + + for (; i < n; i++) { + avail.push(lowercase($availableLanguageKeys[i])); + } + + // Check for an exact match in our list of available keys + i = indexOf(avail, locale); + if (i > -1) { + return $availableLanguageKeys[i]; + } + + if ($languageKeyAliases) { + var alias; + for (var langKeyAlias in $languageKeyAliases) { + if ($languageKeyAliases.hasOwnProperty(langKeyAlias)) { + var hasWildcardKey = false; + var hasExactKey = Object.prototype.hasOwnProperty.call($languageKeyAliases, langKeyAlias) && + lowercase(langKeyAlias) === lowercase(preferred); + + if (langKeyAlias.slice(-1) === '*') { + hasWildcardKey = lowercase(langKeyAlias.slice(0, -1)) === lowercase(preferred.slice(0, langKeyAlias.length - 1)); + } + if (hasExactKey || hasWildcardKey) { + alias = $languageKeyAliases[langKeyAlias]; + if (indexOf(avail, lowercase(alias)) > -1) { + return alias; + } + } + } + } + } + + // Check for a language code without region + var parts = preferred.split('_'); + + if (parts.length > 1 && indexOf(avail, lowercase(parts[0])) > -1) { + return parts[0]; + } + + // If everything fails, return undefined. + return; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#translations + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Registers a new translation table for specific language key. + * + * To register a translation table for specific language, pass a defined language + * key as first parameter. + * + *
      +   *  // register translation table for language: 'de_DE'
      +   *  $translateProvider.translations('de_DE', {
      +   *    'GREETING': 'Hallo Welt!'
      +   *  });
      +   *
      +   *  // register another one
      +   *  $translateProvider.translations('en_US', {
      +   *    'GREETING': 'Hello world!'
      +   *  });
      +   * 
      + * + * When registering multiple translation tables for for the same language key, + * the actual translation table gets extended. This allows you to define module + * specific translation which only get added, once a specific module is loaded in + * your app. + * + * Invoking this method with no arguments returns the translation table which was + * registered with no language key. Invoking it with a language key returns the + * related translation table. + * + * @param {string} langKey A language key. + * @param {object} translationTable A plain old JavaScript object that represents a translation table. + * + */ + var translations = function (langKey, translationTable) { + + if (!langKey && !translationTable) { + return $translationTable; + } + + if (langKey && !translationTable) { + if (angular.isString(langKey)) { + return $translationTable[langKey]; + } + } else { + if (!angular.isObject($translationTable[langKey])) { + $translationTable[langKey] = {}; + } + angular.extend($translationTable[langKey], flatObject(translationTable)); + } + return this; + }; + + this.translations = translations; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#cloakClassName + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * + * Let's you change the class name for `translate-cloak` directive. + * Default class name is `translate-cloak`. + * + * @param {string} name translate-cloak class name + */ + this.cloakClassName = function (name) { + if (!name) { + return $cloakClassName; + } + $cloakClassName = name; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#nestedObjectDelimeter + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * + * Let's you change the delimiter for namespaced translations. + * Default delimiter is `.`. + * + * @param {string} delimiter namespace separator + */ + this.nestedObjectDelimeter = function (delimiter) { + if (!delimiter) { + return $nestedObjectDelimeter; + } + $nestedObjectDelimeter = delimiter; + return this; + }; + + /** + * @name flatObject + * @private + * + * @description + * Flats an object. This function is used to flatten given translation data with + * namespaces, so they are later accessible via dot notation. + */ + var flatObject = function (data, path, result, prevKey) { + var key, keyWithPath, keyWithShortPath, val; + + if (!path) { + path = []; + } + if (!result) { + result = {}; + } + for (key in data) { + if (!Object.prototype.hasOwnProperty.call(data, key)) { + continue; + } + val = data[key]; + if (angular.isObject(val)) { + flatObject(val, path.concat(key), result, key); + } else { + keyWithPath = path.length ? ('' + path.join($nestedObjectDelimeter) + $nestedObjectDelimeter + key) : key; + if (path.length && key === prevKey) { + // Create shortcut path (foo.bar == foo.bar.bar) + keyWithShortPath = '' + path.join($nestedObjectDelimeter); + // Link it to original path + result[keyWithShortPath] = '@:' + keyWithPath; + } + result[keyWithPath] = val; + } + } + return result; + }; + flatObject.displayName = 'flatObject'; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#addInterpolation + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Adds interpolation services to angular-translate, so it can manage them. + * + * @param {object} factory Interpolation service factory + */ + this.addInterpolation = function (factory) { + $interpolatorFactories.push(factory); + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useMessageFormatInterpolation + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use interpolation functionality of messageformat.js. + * This is useful when having high level pluralization and gender selection. + */ + this.useMessageFormatInterpolation = function () { + return this.useInterpolation('$translateMessageFormatInterpolation'); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useInterpolation + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate which interpolation style to use as default, application-wide. + * Simply pass a factory/service name. The interpolation service has to implement + * the correct interface. + * + * @param {string} factory Interpolation service name. + */ + this.useInterpolation = function (factory) { + $interpolationFactory = factory; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useSanitizeStrategy + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Simply sets a sanitation strategy type. + * + * @param {string} value Strategy type. + */ + this.useSanitizeValueStrategy = function (value) { + $translateSanitizationProvider.useStrategy(value); + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#preferredLanguage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells the module which of the registered translation tables to use for translation + * at initial startup by passing a language key. Similar to `$translateProvider#use` + * only that it says which language to **prefer**. + * It is recommended to call this after {@link pascalprecht.translate.$translate#fallbackLanguage fallbackLanguage()}. + * + * @param {string} langKey A language key. + */ + this.preferredLanguage = function (langKey) { + if (langKey) { + setupPreferredLanguage(langKey); + return this; + } + return $preferredLanguage; + }; + var setupPreferredLanguage = function (langKey) { + if (langKey) { + $preferredLanguage = langKey; + } + return $preferredLanguage; + }; + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#translationNotFoundIndicator + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Sets an indicator which is used when a translation isn't found. E.g. when + * setting the indicator as 'X' and one tries to translate a translation id + * called `NOT_FOUND`, this will result in `X NOT_FOUND X`. + * + * Internally this methods sets a left indicator and a right indicator using + * `$translateProvider.translationNotFoundIndicatorLeft()` and + * `$translateProvider.translationNotFoundIndicatorRight()`. + * + * **Note**: These methods automatically add a whitespace between the indicators + * and the translation id. + * + * @param {string} indicator An indicator, could be any string. + */ + this.translationNotFoundIndicator = function (indicator) { + this.translationNotFoundIndicatorLeft(indicator); + this.translationNotFoundIndicatorRight(indicator); + return this; + }; + + /** + * ngdoc function + * @name pascalprecht.translate.$translateProvider#translationNotFoundIndicatorLeft + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Sets an indicator which is used when a translation isn't found left to the + * translation id. + * + * @param {string} indicator An indicator. + */ + this.translationNotFoundIndicatorLeft = function (indicator) { + if (!indicator) { + return $notFoundIndicatorLeft; + } + $notFoundIndicatorLeft = indicator; + return this; + }; + + /** + * ngdoc function + * @name pascalprecht.translate.$translateProvider#translationNotFoundIndicatorLeft + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Sets an indicator which is used when a translation isn't found right to the + * translation id. + * + * @param {string} indicator An indicator. + */ + this.translationNotFoundIndicatorRight = function (indicator) { + if (!indicator) { + return $notFoundIndicatorRight; + } + $notFoundIndicatorRight = indicator; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#fallbackLanguage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells the module which of the registered translation tables to use when missing translations + * at initial startup by passing a language key. Similar to `$translateProvider#use` + * only that it says which language to **fallback**. + * + * @param {string||array} langKey A language key. + * + */ + this.fallbackLanguage = function (langKey) { + fallbackStack(langKey); + return this; + }; + + var fallbackStack = function (langKey) { + if (langKey) { + if (angular.isString(langKey)) { + $fallbackWasString = true; + $fallbackLanguage = [langKey]; + } else if (angular.isArray(langKey)) { + $fallbackWasString = false; + $fallbackLanguage = langKey; + } + if (angular.isString($preferredLanguage) && indexOf($fallbackLanguage, $preferredLanguage) < 0) { + $fallbackLanguage.push($preferredLanguage); + } + + return this; + } else { + if ($fallbackWasString) { + return $fallbackLanguage[0]; + } else { + return $fallbackLanguage; + } + } + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#use + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Set which translation table to use for translation by given language key. When + * trying to 'use' a language which isn't provided, it'll throw an error. + * + * You actually don't have to use this method since `$translateProvider#preferredLanguage` + * does the job too. + * + * @param {string} langKey A language key. + */ + this.use = function (langKey) { + if (langKey) { + if (!$translationTable[langKey] && (!$loaderFactory)) { + // only throw an error, when not loading translation data asynchronously + throw new Error('$translateProvider couldn\'t find translationTable for langKey: \'' + langKey + '\''); + } + $uses = langKey; + return this; + } + return $uses; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#resolveClientLocale + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * This returns the current browser/client's language key. The result is processed with the configured uniform tag resolver. + * + * @returns {string} the current client/browser language key + */ + this.resolveClientLocale = function () { + return getLocale(); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#storageKey + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells the module which key must represent the choosed language by a user in the storage. + * + * @param {string} key A key for the storage. + */ + var storageKey = function (key) { + if (!key) { + if ($storagePrefix) { + return $storagePrefix + $storageKey; + } + return $storageKey; + } + $storageKey = key; + return this; + }; + + this.storageKey = storageKey; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useUrlLoader + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use `$translateUrlLoader` extension service as loader. + * + * @param {string} url Url + * @param {Object=} options Optional configuration object + */ + this.useUrlLoader = function (url, options) { + return this.useLoader('$translateUrlLoader', angular.extend({url : url}, options)); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useStaticFilesLoader + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use `$translateStaticFilesLoader` extension service as loader. + * + * @param {Object=} options Optional configuration object + */ + this.useStaticFilesLoader = function (options) { + return this.useLoader('$translateStaticFilesLoader', options); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useLoader + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use any other service as loader. + * + * @param {string} loaderFactory Factory name to use + * @param {Object=} options Optional configuration object + */ + this.useLoader = function (loaderFactory, options) { + $loaderFactory = loaderFactory; + $loaderOptions = options || {}; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useLocalStorage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use `$translateLocalStorage` service as storage layer. + * + */ + this.useLocalStorage = function () { + return this.useStorage('$translateLocalStorage'); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useCookieStorage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use `$translateCookieStorage` service as storage layer. + */ + this.useCookieStorage = function () { + return this.useStorage('$translateCookieStorage'); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useStorage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use custom service as storage layer. + */ + this.useStorage = function (storageFactory) { + $storageFactory = storageFactory; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#storagePrefix + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Sets prefix for storage key. + * + * @param {string} prefix Storage key prefix + */ + this.storagePrefix = function (prefix) { + if (!prefix) { + return prefix; + } + $storagePrefix = prefix; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useMissingTranslationHandlerLog + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use built-in log handler when trying to translate + * a translation Id which doesn't exist. + * + * This is actually a shortcut method for `useMissingTranslationHandler()`. + * + */ + this.useMissingTranslationHandlerLog = function () { + return this.useMissingTranslationHandler('$translateMissingTranslationHandlerLog'); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useMissingTranslationHandler + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Expects a factory name which later gets instantiated with `$injector`. + * This method can be used to tell angular-translate to use a custom + * missingTranslationHandler. Just build a factory which returns a function + * and expects a translation id as argument. + * + * Example: + *
      +   *  app.config(function ($translateProvider) {
      +   *    $translateProvider.useMissingTranslationHandler('customHandler');
      +   *  });
      +   *
      +   *  app.factory('customHandler', function (dep1, dep2) {
      +   *    return function (translationId) {
      +   *      // something with translationId and dep1 and dep2
      +   *    };
      +   *  });
      +   * 
      + * + * @param {string} factory Factory name + */ + this.useMissingTranslationHandler = function (factory) { + $missingTranslationHandlerFactory = factory; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#usePostCompiling + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * If post compiling is enabled, all translated values will be processed + * again with AngularJS' $compile. + * + * Example: + *
      +   *  app.config(function ($translateProvider) {
      +   *    $translateProvider.usePostCompiling(true);
      +   *  });
      +   * 
      + * + * @param {string} factory Factory name + */ + this.usePostCompiling = function (value) { + $postCompilingEnabled = !(!value); + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#forceAsyncReload + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * If force async reload is enabled, async loader will always be called + * even if $translationTable already contains the language key, adding + * possible new entries to the $translationTable. + * + * Example: + *
      +   *  app.config(function ($translateProvider) {
      +   *    $translateProvider.forceAsyncReload(true);
      +   *  });
      +   * 
      + * + * @param {boolean} value - valid values are true or false + */ + this.forceAsyncReload = function (value) { + $forceAsyncReloadEnabled = !(!value); + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#uniformLanguageTag + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate which language tag should be used as a result when determining + * the current browser language. + * + * This setting must be set before invoking {@link pascalprecht.translate.$translateProvider#methods_determinePreferredLanguage determinePreferredLanguage()}. + * + *
      +   * $translateProvider
      +   *   .uniformLanguageTag('bcp47')
      +   *   .determinePreferredLanguage()
      +   * 
      + * + * The resolver currently supports: + * * default + * (traditionally: hyphens will be converted into underscores, i.e. en-US => en_US) + * en-US => en_US + * en_US => en_US + * en-us => en_us + * * java + * like default, but the second part will be always in uppercase + * en-US => en_US + * en_US => en_US + * en-us => en_US + * * BCP 47 (RFC 4646 & 4647) + * EN => en + * en-US => en-US + * en_US => en-US + * en-us => en-US + * sr-latn => sr-Latn + * sr-latn-rs => sr-Latn-RS + * + * See also: + * * http://en.wikipedia.org/wiki/IETF_language_tag + * * http://www.w3.org/International/core/langtags/ + * * http://tools.ietf.org/html/bcp47 + * + * @param {string|object} options - options (or standard) + * @param {string} options.standard - valid values are 'default', 'bcp47', 'java' + */ + this.uniformLanguageTag = function (options) { + + if (!options) { + options = {}; + } else if (angular.isString(options)) { + options = { + standard : options + }; + } + + uniformLanguageTagResolver = options.standard; + + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#determinePreferredLanguage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to try to determine on its own which language key + * to set as preferred language. When `fn` is given, angular-translate uses it + * to determine a language key, otherwise it uses the built-in `getLocale()` + * method. + * + * The `getLocale()` returns a language key in the format `[lang]_[country]` or + * `[lang]` depending on what the browser provides. + * + * Use this method at your own risk, since not all browsers return a valid + * locale (see {@link pascalprecht.translate.$translateProvider#methods_uniformLanguageTag uniformLanguageTag()}). + * + * @param {Function=} fn Function to determine a browser's locale + */ + this.determinePreferredLanguage = function (fn) { + + var locale = (fn && angular.isFunction(fn)) ? fn() : getLocale(); + + if (!$availableLanguageKeys.length) { + $preferredLanguage = locale; + } else { + $preferredLanguage = negotiateLocale(locale) || locale; + } + + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#registerAvailableLanguageKeys + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Registers a set of language keys the app will work with. Use this method in + * combination with + * {@link pascalprecht.translate.$translateProvider#determinePreferredLanguage determinePreferredLanguage}. + * When available languages keys are registered, angular-translate + * tries to find the best fitting language key depending on the browsers locale, + * considering your language key convention. + * + * @param {object} languageKeys Array of language keys the your app will use + * @param {object=} aliases Alias map. + */ + this.registerAvailableLanguageKeys = function (languageKeys, aliases) { + if (languageKeys) { + $availableLanguageKeys = languageKeys; + if (aliases) { + $languageKeyAliases = aliases; + } + return this; + } + return $availableLanguageKeys; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useLoaderCache + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Registers a cache for internal $http based loaders. + * {@link pascalprecht.translate.$translationCache $translationCache}. + * When false the cache will be disabled (default). When true or undefined + * the cache will be a default (see $cacheFactory). When an object it will + * be treat as a cache object itself: the usage is $http({cache: cache}) + * + * @param {object} cache boolean, string or cache-object + */ + this.useLoaderCache = function (cache) { + if (cache === false) { + // disable cache + loaderCache = undefined; + } else if (cache === true) { + // enable cache using AJS defaults + loaderCache = true; + } else if (typeof(cache) === 'undefined') { + // enable cache using default + loaderCache = '$translationCache'; + } else if (cache) { + // enable cache using given one (see $cacheFactory) + loaderCache = cache; + } + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#directivePriority + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Sets the default priority of the translate directive. The standard value is `0`. + * Calling this function without an argument will return the current value. + * + * @param {number} priority for the translate-directive + */ + this.directivePriority = function (priority) { + if (priority === undefined) { + // getter + return directivePriority; + } else { + // setter with chaining + directivePriority = priority; + return this; + } + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#statefulFilter + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Since AngularJS 1.3, filters which are not stateless (depending at the scope) + * have to explicit define this behavior. + * Sets whether the translate filter should be stateful or stateless. The standard value is `true` + * meaning being stateful. + * Calling this function without an argument will return the current value. + * + * @param {boolean} state - defines the state of the filter + */ + this.statefulFilter = function (state) { + if (state === undefined) { + // getter + return statefulFilter; + } else { + // setter with chaining + statefulFilter = state; + return this; + } + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#postProcess + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * The post processor will be intercept right after the translation result. It can modify the result. + * + * @param {object} fn Function or service name (string) to be called after the translation value has been set / resolved. The function itself will enrich every value being processed and then continue the normal resolver process + */ + this.postProcess = function (fn) { + if (fn) { + postProcessFn = fn; + } else { + postProcessFn = undefined; + } + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#keepContent + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * If keepContent is set to true than translate directive will always use innerHTML + * as a default translation + * + * Example: + *
      +   *  app.config(function ($translateProvider) {
      +   *    $translateProvider.keepContent(true);
      +   *  });
      +   * 
      + * + * @param {boolean} value - valid values are true or false + */ + this.keepContent = function (value) { + $keepContent = !(!value); + return this; + }; + + /** + * @ngdoc object + * @name pascalprecht.translate.$translate + * @requires $interpolate + * @requires $log + * @requires $rootScope + * @requires $q + * + * @description + * The `$translate` service is the actual core of angular-translate. It expects a translation id + * and optional interpolate parameters to translate contents. + * + *
      +   *  $translate('HEADLINE_TEXT').then(function (translation) {
      +   *    $scope.translatedText = translation;
      +   *  });
      +   * 
      + * + * @param {string|array} translationId A token which represents a translation id + * This can be optionally an array of translation ids which + * results that the function returns an object where each key + * is the translation id and the value the translation. + * @param {object=} [interpolateParams={}] An object hash for dynamic values + * @param {string=} [interpolationId=undefined] The id of the interpolation to use (use default unless set via useInterpolation()) + * @param {string=} [defaultTranslationText=undefined] the optional default translation text that is written as + * as default text in case it is not found in any configured language + * @param {string=} [forceLanguage=false] A language to be used instead of the current language + * @param {string=} [sanitizeStrategy=undefined] force sanitize strategy for this call instead of using the configured one (use default unless set) + * @returns {object} promise + */ + this.$get = ['$log', '$injector', '$rootScope', '$q', function ($log, $injector, $rootScope, $q) { + + var Storage, + defaultInterpolator = $injector.get($interpolationFactory || '$translateDefaultInterpolation'), + pendingLoader = false, + interpolatorHashMap = {}, + langPromises = {}, + fallbackIndex, + startFallbackIteration; + + var $translate = function (translationId, interpolateParams, interpolationId, defaultTranslationText, forceLanguage, sanitizeStrategy) { + if (!$uses && $preferredLanguage) { + $uses = $preferredLanguage; + } + var uses = (forceLanguage && forceLanguage !== $uses) ? // we don't want to re-negotiate $uses + (negotiateLocale(forceLanguage) || forceLanguage) : $uses; + + // Check forceLanguage is present + if (forceLanguage) { + loadTranslationsIfMissing(forceLanguage); + } + + // Duck detection: If the first argument is an array, a bunch of translations was requested. + // The result is an object. + if (angular.isArray(translationId)) { + // Inspired by Q.allSettled by Kris Kowal + // https://github.com/kriskowal/q/blob/b0fa72980717dc202ffc3cbf03b936e10ebbb9d7/q.js#L1553-1563 + // This transforms all promises regardless resolved or rejected + var translateAll = function (translationIds) { + var results = {}; // storing the actual results + var promises = []; // promises to wait for + // Wraps the promise a) being always resolved and b) storing the link id->value + var translate = function (translationId) { + var deferred = $q.defer(); + var regardless = function (value) { + results[translationId] = value; + deferred.resolve([translationId, value]); + }; + // we don't care whether the promise was resolved or rejected; just store the values + $translate(translationId, interpolateParams, interpolationId, defaultTranslationText, forceLanguage, sanitizeStrategy).then(regardless, regardless); + return deferred.promise; + }; + for (var i = 0, c = translationIds.length; i < c; i++) { + promises.push(translate(translationIds[i])); + } + // wait for all (including storing to results) + return $q.all(promises).then(function () { + // return the results + return results; + }); + }; + return translateAll(translationId); + } + + var deferred = $q.defer(); + + // trim off any whitespace + if (translationId) { + translationId = trim.apply(translationId); + } else { + throw new TypeError('translationId must be a not empty string'); + } + + var promiseToWaitFor = (function () { + var promise = langPromises[uses] || langPromises[$preferredLanguage]; + + fallbackIndex = 0; + + if ($storageFactory && !promise) { + // looks like there's no pending promise for $preferredLanguage or + // $uses. Maybe there's one pending for a language that comes from + // storage. + var langKey = Storage.get($storageKey); + promise = langPromises[langKey]; + + if ($fallbackLanguage && $fallbackLanguage.length) { + var index = indexOf($fallbackLanguage, langKey); + // maybe the language from storage is also defined as fallback language + // we increase the fallback language index to not search in that language + // as fallback, since it's probably the first used language + // in that case the index starts after the first element + fallbackIndex = (index === 0) ? 1 : 0; + + // but we can make sure to ALWAYS fallback to preferred language at least + if (indexOf($fallbackLanguage, $preferredLanguage) < 0) { + $fallbackLanguage.push($preferredLanguage); + } + } + } + return promise; + }()); + + if (!promiseToWaitFor) { + // no promise to wait for? okay. Then there's no loader registered + // nor is a one pending for language that comes from storage. + // We can just translate. + determineTranslation(translationId, interpolateParams, interpolationId, defaultTranslationText, uses, sanitizeStrategy).then(deferred.resolve, deferred.reject); + } else { + var promiseResolved = function () { + // $uses may have changed while waiting + if (!forceLanguage) { + uses = $uses; + } + determineTranslation(translationId, interpolateParams, interpolationId, defaultTranslationText, uses, sanitizeStrategy).then(deferred.resolve, deferred.reject); + }; + promiseResolved.displayName = 'promiseResolved'; + + promiseToWaitFor['finally'](promiseResolved)['catch'](angular.noop); // we don't care about errors here, already handled + } + return deferred.promise; + }; + + /** + * @name applyNotFoundIndicators + * @private + * + * @description + * Applies not fount indicators to given translation id, if needed. + * This function gets only executed, if a translation id doesn't exist, + * which is why a translation id is expected as argument. + * + * @param {string} translationId Translation id. + * @returns {string} Same as given translation id but applied with not found + * indicators. + */ + var applyNotFoundIndicators = function (translationId) { + // applying notFoundIndicators + if ($notFoundIndicatorLeft) { + translationId = [$notFoundIndicatorLeft, translationId].join(' '); + } + if ($notFoundIndicatorRight) { + translationId = [translationId, $notFoundIndicatorRight].join(' '); + } + return translationId; + }; + + /** + * @name useLanguage + * @private + * + * @description + * Makes actual use of a language by setting a given language key as used + * language and informs registered interpolators to also use the given + * key as locale. + * + * @param {string} key Locale key. + */ + var useLanguage = function (key) { + $uses = key; + + // make sure to store new language key before triggering success event + if ($storageFactory) { + Storage.put($translate.storageKey(), $uses); + } + + $rootScope.$emit('$translateChangeSuccess', {language : key}); + + // inform default interpolator + defaultInterpolator.setLocale($uses); + + var eachInterpolator = function (interpolator, id) { + interpolatorHashMap[id].setLocale($uses); + }; + eachInterpolator.displayName = 'eachInterpolatorLocaleSetter'; + + // inform all others too! + angular.forEach(interpolatorHashMap, eachInterpolator); + $rootScope.$emit('$translateChangeEnd', {language : key}); + }; + + /** + * @name loadAsync + * @private + * + * @description + * Kicks off registered async loader using `$injector` and applies existing + * loader options. When resolved, it updates translation tables accordingly + * or rejects with given language key. + * + * @param {string} key Language key. + * @return {Promise} A promise. + */ + var loadAsync = function (key) { + if (!key) { + throw 'No language key specified for loading.'; + } + + var deferred = $q.defer(); + + $rootScope.$emit('$translateLoadingStart', {language : key}); + pendingLoader = true; + + var cache = loaderCache; + if (typeof(cache) === 'string') { + // getting on-demand instance of loader + cache = $injector.get(cache); + } + + var loaderOptions = angular.extend({}, $loaderOptions, { + key : key, + $http : angular.extend({}, { + cache : cache + }, $loaderOptions.$http) + }); + + var onLoaderSuccess = function (data) { + var translationTable = {}; + $rootScope.$emit('$translateLoadingSuccess', {language : key}); + + if (angular.isArray(data)) { + angular.forEach(data, function (table) { + angular.extend(translationTable, flatObject(table)); + }); + } else { + angular.extend(translationTable, flatObject(data)); + } + pendingLoader = false; + deferred.resolve({ + key : key, + table : translationTable + }); + $rootScope.$emit('$translateLoadingEnd', {language : key}); + }; + onLoaderSuccess.displayName = 'onLoaderSuccess'; + + var onLoaderError = function (key) { + $rootScope.$emit('$translateLoadingError', {language : key}); + deferred.reject(key); + $rootScope.$emit('$translateLoadingEnd', {language : key}); + }; + onLoaderError.displayName = 'onLoaderError'; + + $injector.get($loaderFactory)(loaderOptions) + .then(onLoaderSuccess, onLoaderError); + + return deferred.promise; + }; + + if ($storageFactory) { + Storage = $injector.get($storageFactory); + + if (!Storage.get || !Storage.put) { + throw new Error('Couldn\'t use storage \'' + $storageFactory + '\', missing get() or put() method!'); + } + } + + // if we have additional interpolations that were added via + // $translateProvider.addInterpolation(), we have to map'em + if ($interpolatorFactories.length) { + var eachInterpolationFactory = function (interpolatorFactory) { + var interpolator = $injector.get(interpolatorFactory); + // setting initial locale for each interpolation service + interpolator.setLocale($preferredLanguage || $uses); + // make'em recognizable through id + interpolatorHashMap[interpolator.getInterpolationIdentifier()] = interpolator; + }; + eachInterpolationFactory.displayName = 'interpolationFactoryAdder'; + + angular.forEach($interpolatorFactories, eachInterpolationFactory); + } + + /** + * @name getTranslationTable + * @private + * + * @description + * Returns a promise that resolves to the translation table + * or is rejected if an error occurred. + * + * @param langKey + * @returns {Q.promise} + */ + var getTranslationTable = function (langKey) { + var deferred = $q.defer(); + if (Object.prototype.hasOwnProperty.call($translationTable, langKey)) { + deferred.resolve($translationTable[langKey]); + } else if (langPromises[langKey]) { + var onResolve = function (data) { + translations(data.key, data.table); + deferred.resolve(data.table); + }; + onResolve.displayName = 'translationTableResolver'; + langPromises[langKey].then(onResolve, deferred.reject); + } else { + deferred.reject(); + } + return deferred.promise; + }; + + /** + * @name getFallbackTranslation + * @private + * + * @description + * Returns a promise that will resolve to the translation + * or be rejected if no translation was found for the language. + * This function is currently only used for fallback language translation. + * + * @param langKey The language to translate to. + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param sanitizeStrategy + * @returns {Q.promise} + */ + var getFallbackTranslation = function (langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy) { + var deferred = $q.defer(); + + var onResolve = function (translationTable) { + if (Object.prototype.hasOwnProperty.call(translationTable, translationId) && translationTable[translationId] !== null) { + Interpolator.setLocale(langKey); + var translation = translationTable[translationId]; + if (translation.substr(0, 2) === '@:') { + getFallbackTranslation(langKey, translation.substr(2), interpolateParams, Interpolator, sanitizeStrategy) + .then(deferred.resolve, deferred.reject); + } else { + var interpolatedValue = Interpolator.interpolate(translationTable[translationId], interpolateParams, 'service', sanitizeStrategy, translationId); + interpolatedValue = applyPostProcessing(translationId, translationTable[translationId], interpolatedValue, interpolateParams, langKey); + + deferred.resolve(interpolatedValue); + + } + Interpolator.setLocale($uses); + } else { + deferred.reject(); + } + }; + onResolve.displayName = 'fallbackTranslationResolver'; + + getTranslationTable(langKey).then(onResolve, deferred.reject); + + return deferred.promise; + }; + + /** + * @name getFallbackTranslationInstant + * @private + * + * @description + * Returns a translation + * This function is currently only used for fallback language translation. + * + * @param langKey The language to translate to. + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param sanitizeStrategy sanitize strategy override + * + * @returns {string} translation + */ + var getFallbackTranslationInstant = function (langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy) { + var result, translationTable = $translationTable[langKey]; + + if (translationTable && Object.prototype.hasOwnProperty.call(translationTable, translationId) && translationTable[translationId] !== null) { + Interpolator.setLocale(langKey); + result = Interpolator.interpolate(translationTable[translationId], interpolateParams, 'filter', sanitizeStrategy, translationId); + result = applyPostProcessing(translationId, translationTable[translationId], result, interpolateParams, langKey, sanitizeStrategy); + // workaround for TrustedValueHolderType + if (!angular.isString(result) && angular.isFunction(result.$$unwrapTrustedValue)) { + var result2 = result.$$unwrapTrustedValue(); + if (result2.substr(0, 2) === '@:') { + return getFallbackTranslationInstant(langKey, result2.substr(2), interpolateParams, Interpolator, sanitizeStrategy); + } + } else if (result.substr(0, 2) === '@:') { + return getFallbackTranslationInstant(langKey, result.substr(2), interpolateParams, Interpolator, sanitizeStrategy); + } + Interpolator.setLocale($uses); + } + + return result; + }; + + + /** + * @name translateByHandler + * @private + * + * Translate by missing translation handler. + * + * @param translationId + * @param interpolateParams + * @param defaultTranslationText + * @param sanitizeStrategy sanitize strategy override + * + * @returns translation created by $missingTranslationHandler or translationId is $missingTranslationHandler is + * absent + */ + var translateByHandler = function (translationId, interpolateParams, defaultTranslationText, sanitizeStrategy) { + // If we have a handler factory - we might also call it here to determine if it provides + // a default text for a translationid that can't be found anywhere in our tables + if ($missingTranslationHandlerFactory) { + return $injector.get($missingTranslationHandlerFactory)(translationId, $uses, interpolateParams, defaultTranslationText, sanitizeStrategy); + } else { + return translationId; + } + }; + + /** + * @name resolveForFallbackLanguage + * @private + * + * Recursive helper function for fallbackTranslation that will sequentially look + * for a translation in the fallbackLanguages starting with fallbackLanguageIndex. + * + * @param fallbackLanguageIndex + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param defaultTranslationText + * @param sanitizeStrategy + * @returns {Q.promise} Promise that will resolve to the translation. + */ + var resolveForFallbackLanguage = function (fallbackLanguageIndex, translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy) { + var deferred = $q.defer(); + + if (fallbackLanguageIndex < $fallbackLanguage.length) { + var langKey = $fallbackLanguage[fallbackLanguageIndex]; + getFallbackTranslation(langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy).then( + function (data) { + deferred.resolve(data); + }, + function () { + // Look in the next fallback language for a translation. + // It delays the resolving by passing another promise to resolve. + return resolveForFallbackLanguage(fallbackLanguageIndex + 1, translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy).then(deferred.resolve, deferred.reject); + } + ); + } else { + // No translation found in any fallback language + // if a default translation text is set in the directive, then return this as a result + if (defaultTranslationText) { + deferred.resolve(defaultTranslationText); + } else { + var missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, defaultTranslationText); + + // if no default translation is set and an error handler is defined, send it to the handler + // and then return the result if it isn't undefined + if ($missingTranslationHandlerFactory && missingTranslationHandlerTranslation) { + deferred.resolve(missingTranslationHandlerTranslation); + } else { + deferred.reject(applyNotFoundIndicators(translationId)); + } + } + } + return deferred.promise; + }; + + /** + * @name resolveForFallbackLanguageInstant + * @private + * + * Recursive helper function for fallbackTranslation that will sequentially look + * for a translation in the fallbackLanguages starting with fallbackLanguageIndex. + * + * @param fallbackLanguageIndex + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param sanitizeStrategy + * @returns {string} translation + */ + var resolveForFallbackLanguageInstant = function (fallbackLanguageIndex, translationId, interpolateParams, Interpolator, sanitizeStrategy) { + var result; + + if (fallbackLanguageIndex < $fallbackLanguage.length) { + var langKey = $fallbackLanguage[fallbackLanguageIndex]; + result = getFallbackTranslationInstant(langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy); + if (!result && result !== '') { + result = resolveForFallbackLanguageInstant(fallbackLanguageIndex + 1, translationId, interpolateParams, Interpolator); + } + } + return result; + }; + + /** + * Translates with the usage of the fallback languages. + * + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param defaultTranslationText + * @param sanitizeStrategy + * @returns {Q.promise} Promise, that resolves to the translation. + */ + var fallbackTranslation = function (translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy) { + // Start with the fallbackLanguage with index 0 + return resolveForFallbackLanguage((startFallbackIteration > 0 ? startFallbackIteration : fallbackIndex), translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy); + }; + + /** + * Translates with the usage of the fallback languages. + * + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param sanitizeStrategy + * @returns {String} translation + */ + var fallbackTranslationInstant = function (translationId, interpolateParams, Interpolator, sanitizeStrategy) { + // Start with the fallbackLanguage with index 0 + return resolveForFallbackLanguageInstant((startFallbackIteration > 0 ? startFallbackIteration : fallbackIndex), translationId, interpolateParams, Interpolator, sanitizeStrategy); + }; + + var determineTranslation = function (translationId, interpolateParams, interpolationId, defaultTranslationText, uses, sanitizeStrategy) { + + var deferred = $q.defer(); + + var table = uses ? $translationTable[uses] : $translationTable, + Interpolator = (interpolationId) ? interpolatorHashMap[interpolationId] : defaultInterpolator; + + // if the translation id exists, we can just interpolate it + if (table && Object.prototype.hasOwnProperty.call(table, translationId) && table[translationId] !== null) { + var translation = table[translationId]; + + // If using link, rerun $translate with linked translationId and return it + if (translation.substr(0, 2) === '@:') { + + $translate(translation.substr(2), interpolateParams, interpolationId, defaultTranslationText, uses, sanitizeStrategy) + .then(deferred.resolve, deferred.reject); + } else { + // + var resolvedTranslation = Interpolator.interpolate(translation, interpolateParams, 'service', sanitizeStrategy, translationId); + resolvedTranslation = applyPostProcessing(translationId, translation, resolvedTranslation, interpolateParams, uses); + deferred.resolve(resolvedTranslation); + } + } else { + var missingTranslationHandlerTranslation; + // for logging purposes only (as in $translateMissingTranslationHandlerLog), value is not returned to promise + if ($missingTranslationHandlerFactory && !pendingLoader) { + missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, defaultTranslationText); + } + + // since we couldn't translate the inital requested translation id, + // we try it now with one or more fallback languages, if fallback language(s) is + // configured. + if (uses && $fallbackLanguage && $fallbackLanguage.length) { + fallbackTranslation(translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy) + .then(function (translation) { + deferred.resolve(translation); + }, function (_translationId) { + deferred.reject(applyNotFoundIndicators(_translationId)); + }); + } else if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) { + // looks like the requested translation id doesn't exists. + // Now, if there is a registered handler for missing translations and no + // asyncLoader is pending, we execute the handler + if (defaultTranslationText) { + deferred.resolve(defaultTranslationText); + } else { + deferred.resolve(missingTranslationHandlerTranslation); + } + } else { + if (defaultTranslationText) { + deferred.resolve(defaultTranslationText); + } else { + deferred.reject(applyNotFoundIndicators(translationId)); + } + } + } + return deferred.promise; + }; + + var determineTranslationInstant = function (translationId, interpolateParams, interpolationId, uses, sanitizeStrategy) { + + var result, table = uses ? $translationTable[uses] : $translationTable, + Interpolator = defaultInterpolator; + + // if the interpolation id exists use custom interpolator + if (interpolatorHashMap && Object.prototype.hasOwnProperty.call(interpolatorHashMap, interpolationId)) { + Interpolator = interpolatorHashMap[interpolationId]; + } + + // if the translation id exists, we can just interpolate it + if (table && Object.prototype.hasOwnProperty.call(table, translationId) && table[translationId] !== null) { + var translation = table[translationId]; + + // If using link, rerun $translate with linked translationId and return it + if (translation.substr(0, 2) === '@:') { + result = determineTranslationInstant(translation.substr(2), interpolateParams, interpolationId, uses, sanitizeStrategy); + } else { + result = Interpolator.interpolate(translation, interpolateParams, 'filter', sanitizeStrategy, translationId); + result = applyPostProcessing(translationId, translation, result, interpolateParams, uses, sanitizeStrategy); + } + } else { + var missingTranslationHandlerTranslation; + // for logging purposes only (as in $translateMissingTranslationHandlerLog), value is not returned to promise + if ($missingTranslationHandlerFactory && !pendingLoader) { + missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, sanitizeStrategy); + } + + // since we couldn't translate the inital requested translation id, + // we try it now with one or more fallback languages, if fallback language(s) is + // configured. + if (uses && $fallbackLanguage && $fallbackLanguage.length) { + fallbackIndex = 0; + result = fallbackTranslationInstant(translationId, interpolateParams, Interpolator, sanitizeStrategy); + } else if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) { + // looks like the requested translation id doesn't exists. + // Now, if there is a registered handler for missing translations and no + // asyncLoader is pending, we execute the handler + result = missingTranslationHandlerTranslation; + } else { + result = applyNotFoundIndicators(translationId); + } + } + + return result; + }; + + var clearNextLangAndPromise = function (key) { + if ($nextLang === key) { + $nextLang = undefined; + } + langPromises[key] = undefined; + }; + + var applyPostProcessing = function (translationId, translation, resolvedTranslation, interpolateParams, uses, sanitizeStrategy) { + var fn = postProcessFn; + + if (fn) { + + if (typeof(fn) === 'string') { + // getting on-demand instance + fn = $injector.get(fn); + } + if (fn) { + return fn(translationId, translation, resolvedTranslation, interpolateParams, uses, sanitizeStrategy); + } + } + + return resolvedTranslation; + }; + + var loadTranslationsIfMissing = function (key) { + if (!$translationTable[key] && $loaderFactory && !langPromises[key]) { + langPromises[key] = loadAsync(key).then(function (translation) { + translations(translation.key, translation.table); + return translation; + }); + } + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#preferredLanguage + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the language key for the preferred language. + * + * @param {string} langKey language String or Array to be used as preferredLanguage (changing at runtime) + * + * @return {string} preferred language key + */ + $translate.preferredLanguage = function (langKey) { + if (langKey) { + setupPreferredLanguage(langKey); + } + return $preferredLanguage; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#cloakClassName + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the configured class name for `translate-cloak` directive. + * + * @return {string} cloakClassName + */ + $translate.cloakClassName = function () { + return $cloakClassName; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#nestedObjectDelimeter + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the configured delimiter for nested namespaces. + * + * @return {string} nestedObjectDelimeter + */ + $translate.nestedObjectDelimeter = function () { + return $nestedObjectDelimeter; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#fallbackLanguage + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the language key for the fallback languages or sets a new fallback stack. + * It is recommended to call this before {@link pascalprecht.translate.$translateProvider#preferredLanguage preferredLanguage()}. + * + * @param {string=} langKey language String or Array of fallback languages to be used (to change stack at runtime) + * + * @return {string||array} fallback language key + */ + $translate.fallbackLanguage = function (langKey) { + if (langKey !== undefined && langKey !== null) { + fallbackStack(langKey); + + // as we might have an async loader initiated and a new translation language might have been defined + // we need to add the promise to the stack also. So - iterate. + if ($loaderFactory) { + if ($fallbackLanguage && $fallbackLanguage.length) { + for (var i = 0, len = $fallbackLanguage.length; i < len; i++) { + if (!langPromises[$fallbackLanguage[i]]) { + langPromises[$fallbackLanguage[i]] = loadAsync($fallbackLanguage[i]); + } + } + } + } + $translate.use($translate.use()); + } + if ($fallbackWasString) { + return $fallbackLanguage[0]; + } else { + return $fallbackLanguage; + } + + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#useFallbackLanguage + * @methodOf pascalprecht.translate.$translate + * + * @description + * Sets the first key of the fallback language stack to be used for translation. + * Therefore all languages in the fallback array BEFORE this key will be skipped! + * + * @param {string=} langKey Contains the langKey the iteration shall start with. Set to false if you want to + * get back to the whole stack + */ + $translate.useFallbackLanguage = function (langKey) { + if (langKey !== undefined && langKey !== null) { + if (!langKey) { + startFallbackIteration = 0; + } else { + var langKeyPosition = indexOf($fallbackLanguage, langKey); + if (langKeyPosition > -1) { + startFallbackIteration = langKeyPosition; + } + } + + } + + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#proposedLanguage + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the language key of language that is currently loaded asynchronously. + * + * @return {string} language key + */ + $translate.proposedLanguage = function () { + return $nextLang; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#storage + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns registered storage. + * + * @return {object} Storage + */ + $translate.storage = function () { + return Storage; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#negotiateLocale + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns a language key based on available languages and language aliases. If a + * language key cannot be resolved, returns undefined. + * + * If no or a falsy key is given, returns undefined. + * + * @param {string} [key] Language key + * @return {string|undefined} Language key or undefined if no language key is found. + */ + $translate.negotiateLocale = negotiateLocale; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#use + * @methodOf pascalprecht.translate.$translate + * + * @description + * Tells angular-translate which language to use by given language key. This method is + * used to change language at runtime. It also takes care of storing the language + * key in a configured store to let your app remember the choosed language. + * + * When trying to 'use' a language which isn't available it tries to load it + * asynchronously with registered loaders. + * + * Returns promise object with loaded language file data or string of the currently used language. + * + * If no or a falsy key is given it returns the currently used language key. + * The returned string will be ```undefined``` if setting up $translate hasn't finished. + * @example + * $translate.use("en_US").then(function(data){ + * $scope.text = $translate("HELLO"); + * }); + * + * @param {string=} key Language key + * @return {object|string} Promise with loaded language data or the language key if a falsy param was given. + */ + $translate.use = function (key) { + if (!key) { + return $uses; + } + + var deferred = $q.defer(); + deferred.promise.then(null, angular.noop); // AJS "Possibly unhandled rejection" + + $rootScope.$emit('$translateChangeStart', {language : key}); + + // Try to get the aliased language key + var aliasedKey = negotiateLocale(key); + // Ensure only registered language keys will be loaded + if ($availableLanguageKeys.length > 0 && !aliasedKey) { + return $q.reject(key); + } + + if (aliasedKey) { + key = aliasedKey; + } + + // if there isn't a translation table for the language we've requested, + // we load it asynchronously + $nextLang = key; + if (($forceAsyncReloadEnabled || !$translationTable[key]) && $loaderFactory && !langPromises[key]) { + langPromises[key] = loadAsync(key).then(function (translation) { + translations(translation.key, translation.table); + deferred.resolve(translation.key); + if ($nextLang === key) { + useLanguage(translation.key); + } + return translation; + }, function (key) { + $rootScope.$emit('$translateChangeError', {language : key}); + deferred.reject(key); + $rootScope.$emit('$translateChangeEnd', {language : key}); + return $q.reject(key); + }); + langPromises[key]['finally'](function () { + clearNextLangAndPromise(key); + })['catch'](angular.noop); // we don't care about errors (clearing) + } else if (langPromises[key]) { + // we are already loading this asynchronously + // resolve our new deferred when the old langPromise is resolved + langPromises[key].then(function (translation) { + if ($nextLang === translation.key) { + useLanguage(translation.key); + } + deferred.resolve(translation.key); + return translation; + }, function (key) { + // find first available fallback language if that request has failed + if (!$uses && $fallbackLanguage && $fallbackLanguage.length > 0 && $fallbackLanguage[0] !== key) { + return $translate.use($fallbackLanguage[0]).then(deferred.resolve, deferred.reject); + } else { + return deferred.reject(key); + } + }); + } else { + deferred.resolve(key); + useLanguage(key); + } + + return deferred.promise; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#resolveClientLocale + * @methodOf pascalprecht.translate.$translate + * + * @description + * This returns the current browser/client's language key. The result is processed with the configured uniform tag resolver. + * + * @returns {string} the current client/browser language key + */ + $translate.resolveClientLocale = function () { + return getLocale(); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#storageKey + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the key for the storage. + * + * @return {string} storage key + */ + $translate.storageKey = function () { + return storageKey(); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#isPostCompilingEnabled + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns whether post compiling is enabled or not + * + * @return {bool} storage key + */ + $translate.isPostCompilingEnabled = function () { + return $postCompilingEnabled; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#isForceAsyncReloadEnabled + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns whether force async reload is enabled or not + * + * @return {boolean} forceAsyncReload value + */ + $translate.isForceAsyncReloadEnabled = function () { + return $forceAsyncReloadEnabled; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#isKeepContent + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns whether keepContent or not + * + * @return {boolean} keepContent value + */ + $translate.isKeepContent = function () { + return $keepContent; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#refresh + * @methodOf pascalprecht.translate.$translate + * + * @description + * Refreshes a translation table pointed by the given langKey. If langKey is not specified, + * the module will drop all existent translation tables and load new version of those which + * are currently in use. + * + * Refresh means that the module will drop target translation table and try to load it again. + * + * In case there are no loaders registered the refresh() method will throw an Error. + * + * If the module is able to refresh translation tables refresh() method will broadcast + * $translateRefreshStart and $translateRefreshEnd events. + * + * @example + * // this will drop all currently existent translation tables and reload those which are + * // currently in use + * $translate.refresh(); + * // this will refresh a translation table for the en_US language + * $translate.refresh('en_US'); + * + * @param {string} langKey A language key of the table, which has to be refreshed + * + * @return {promise} Promise, which will be resolved in case a translation tables refreshing + * process is finished successfully, and reject if not. + */ + $translate.refresh = function (langKey) { + if (!$loaderFactory) { + throw new Error('Couldn\'t refresh translation table, no loader registered!'); + } + + $rootScope.$emit('$translateRefreshStart', {language : langKey}); + + var deferred = $q.defer(), updatedLanguages = {}; + + //private helper + function loadNewData(languageKey) { + var promise = loadAsync(languageKey); + //update the load promise cache for this language + langPromises[languageKey] = promise; + //register a data handler for the promise + promise.then(function (data) { + //clear the cache for this language + $translationTable[languageKey] = {}; + //add the new data for this language + translations(languageKey, data.table); + //track that we updated this language + updatedLanguages[languageKey] = true; + }, + //handle rejection to appease the $q validation + angular.noop); + return promise; + } + + //set up post-processing + deferred.promise.then( + function () { + for (var key in $translationTable) { + if ($translationTable.hasOwnProperty(key)) { + //delete cache entries that were not updated + if (!(key in updatedLanguages)) { + delete $translationTable[key]; + } + } + } + if ($uses) { + useLanguage($uses); + } + }, + //handle rejection to appease the $q validation + angular.noop + )['finally']( + function () { + $rootScope.$emit('$translateRefreshEnd', {language : langKey}); + } + ); + + if (!langKey) { + // if there's no language key specified we refresh ALL THE THINGS! + var languagesToReload = $fallbackLanguage && $fallbackLanguage.slice() || []; + if ($uses && languagesToReload.indexOf($uses) === -1) { + languagesToReload.push($uses); + } + $q.all(languagesToReload.map(loadNewData)).then(deferred.resolve, deferred.reject); + + } else if ($translationTable[langKey]) { + //just refresh the specified language cache + loadNewData(langKey).then(deferred.resolve, deferred.reject); + + } else { + deferred.reject(); + } + + return deferred.promise; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#instant + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns a translation instantly from the internal state of loaded translation. All rules + * regarding the current language, the preferred language of even fallback languages will be + * used except any promise handling. If a language was not found, an asynchronous loading + * will be invoked in the background. + * + * @param {string|array} translationId A token which represents a translation id + * This can be optionally an array of translation ids which + * results that the function's promise returns an object where + * each key is the translation id and the value the translation. + * @param {object=} [interpolateParams={}] Params + * @param {string=} [interpolationId=undefined] The id of the interpolation to use (use default unless set via useInterpolation()) + * @param {string=} [forceLanguage=false] A language to be used instead of the current language + * @param {string=} [sanitizeStrategy=undefined] force sanitize strategy for this call instead of using the configured one (use default unless set) + * + * @return {string|object} translation + */ + $translate.instant = function (translationId, interpolateParams, interpolationId, forceLanguage, sanitizeStrategy) { + + // we don't want to re-negotiate $uses + var uses = (forceLanguage && forceLanguage !== $uses) ? // we don't want to re-negotiate $uses + (negotiateLocale(forceLanguage) || forceLanguage) : $uses; + + // Detect undefined and null values to shorten the execution and prevent exceptions + if (translationId === null || angular.isUndefined(translationId)) { + return translationId; + } + + // Check forceLanguage is present + if (forceLanguage) { + loadTranslationsIfMissing(forceLanguage); + } + + // Duck detection: If the first argument is an array, a bunch of translations was requested. + // The result is an object. + if (angular.isArray(translationId)) { + var results = {}; + for (var i = 0, c = translationId.length; i < c; i++) { + results[translationId[i]] = $translate.instant(translationId[i], interpolateParams, interpolationId, forceLanguage, sanitizeStrategy); + } + return results; + } + + // We discarded unacceptable values. So we just need to verify if translationId is empty String + if (angular.isString(translationId) && translationId.length < 1) { + return translationId; + } + + // trim off any whitespace + if (translationId) { + translationId = trim.apply(translationId); + } + + var result, possibleLangKeys = []; + if ($preferredLanguage) { + possibleLangKeys.push($preferredLanguage); + } + if (uses) { + possibleLangKeys.push(uses); + } + if ($fallbackLanguage && $fallbackLanguage.length) { + possibleLangKeys = possibleLangKeys.concat($fallbackLanguage); + } + for (var j = 0, d = possibleLangKeys.length; j < d; j++) { + var possibleLangKey = possibleLangKeys[j]; + if ($translationTable[possibleLangKey]) { + if (typeof $translationTable[possibleLangKey][translationId] !== 'undefined') { + result = determineTranslationInstant(translationId, interpolateParams, interpolationId, uses, sanitizeStrategy); + } + } + if (typeof result !== 'undefined') { + break; + } + } + + if (!result && result !== '') { + if ($notFoundIndicatorLeft || $notFoundIndicatorRight) { + result = applyNotFoundIndicators(translationId); + } else { + // Return translation of default interpolator if not found anything. + result = defaultInterpolator.interpolate(translationId, interpolateParams, 'filter', sanitizeStrategy); + + // looks like the requested translation id doesn't exists. + // Now, if there is a registered handler for missing translations and no + // asyncLoader is pending, we execute the handler + var missingTranslationHandlerTranslation; + if ($missingTranslationHandlerFactory && !pendingLoader) { + missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, sanitizeStrategy); + } + + if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) { + result = missingTranslationHandlerTranslation; + } + } + } + + return result; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#versionInfo + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the current version information for the angular-translate library + * + * @return {string} angular-translate version + */ + $translate.versionInfo = function () { + return version; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#loaderCache + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the defined loaderCache. + * + * @return {boolean|string|object} current value of loaderCache + */ + $translate.loaderCache = function () { + return loaderCache; + }; + + // internal purpose only + $translate.directivePriority = function () { + return directivePriority; + }; + + // internal purpose only + $translate.statefulFilter = function () { + return statefulFilter; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#isReady + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns whether the service is "ready" to translate (i.e. loading 1st language). + * + * See also {@link pascalprecht.translate.$translate#methods_onReady onReady()}. + * + * @return {boolean} current value of ready + */ + $translate.isReady = function () { + return $isReady; + }; + + var $onReadyDeferred = $q.defer(); + $onReadyDeferred.promise.then(function () { + $isReady = true; + }); + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#onReady + * @methodOf pascalprecht.translate.$translate + * + * @description + * Calls the function provided or resolved the returned promise after the service is "ready" to translate (i.e. loading 1st language). + * + * See also {@link pascalprecht.translate.$translate#methods_isReady isReady()}. + * + * @param {Function=} fn Function to invoke when service is ready + * @return {object} Promise resolved when service is ready + */ + $translate.onReady = function (fn) { + var deferred = $q.defer(); + if (angular.isFunction(fn)) { + deferred.promise.then(fn); + } + if ($isReady) { + deferred.resolve(); + } else { + $onReadyDeferred.promise.then(deferred.resolve); + } + return deferred.promise; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#getAvailableLanguageKeys + * @methodOf pascalprecht.translate.$translate + * + * @description + * This function simply returns the registered language keys being defined before in the config phase + * With this, an application can use the array to provide a language selection dropdown or similar + * without any additional effort + * + * @returns {object} returns the list of possibly registered language keys and mapping or null if not defined + */ + $translate.getAvailableLanguageKeys = function () { + if ($availableLanguageKeys.length > 0) { + return $availableLanguageKeys; + } + return null; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#getTranslationTable + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns translation table by the given language key. + * + * Unless a language is provided it returns a translation table of the current one. + * Note: If translation dictionary is currently downloading or in progress + * it will return null. + * + * @param {string} langKey A token which represents a translation id + * + * @return {object} a copy of angular-translate $translationTable + */ + $translate.getTranslationTable = function (langKey) { + langKey = langKey || $translate.use(); + if (langKey && $translationTable[langKey]) { + return angular.copy($translationTable[langKey]); + } + return null; + }; + + // Whenever $translateReady is being fired, this will ensure the state of $isReady + var globalOnReadyListener = $rootScope.$on('$translateReady', function () { + $onReadyDeferred.resolve(); + globalOnReadyListener(); // one time only + globalOnReadyListener = null; + }); + var globalOnChangeListener = $rootScope.$on('$translateChangeEnd', function () { + $onReadyDeferred.resolve(); + globalOnChangeListener(); // one time only + globalOnChangeListener = null; + }); + + if ($loaderFactory) { + + // If at least one async loader is defined and there are no + // (default) translations available we should try to load them. + if (angular.equals($translationTable, {})) { + if ($translate.use()) { + $translate.use($translate.use()); + } + } + + // Also, if there are any fallback language registered, we start + // loading them asynchronously as soon as we can. + if ($fallbackLanguage && $fallbackLanguage.length) { + var processAsyncResult = function (translation) { + translations(translation.key, translation.table); + $rootScope.$emit('$translateChangeEnd', {language : translation.key}); + return translation; + }; + for (var i = 0, len = $fallbackLanguage.length; i < len; i++) { + var fallbackLanguageId = $fallbackLanguage[i]; + if ($forceAsyncReloadEnabled || !$translationTable[fallbackLanguageId]) { + langPromises[fallbackLanguageId] = loadAsync(fallbackLanguageId).then(processAsyncResult); + } + } + } + } else { + $rootScope.$emit('$translateReady', {language : $translate.use()}); + } + + return $translate; + }]; +} + +$translate.displayName = 'displayName'; + +/** + * @ngdoc object + * @name pascalprecht.translate.$translateDefaultInterpolation + * @requires $interpolate + * + * @description + * Uses angular's `$interpolate` services to interpolate strings against some values. + * + * Be aware to configure a proper sanitization strategy. + * + * See also: + * * {@link pascalprecht.translate.$translateSanitization} + * + * @return {object} $translateDefaultInterpolation Interpolator service + */ +angular.module('pascalprecht.translate').factory('$translateDefaultInterpolation', $translateDefaultInterpolation); + +function $translateDefaultInterpolation ($interpolate, $translateSanitization) { + + 'use strict'; + + var $translateInterpolator = {}, + $locale, + $identifier = 'default'; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateDefaultInterpolation#setLocale + * @methodOf pascalprecht.translate.$translateDefaultInterpolation + * + * @description + * Sets current locale (this is currently not use in this interpolation). + * + * @param {string} locale Language key or locale. + */ + $translateInterpolator.setLocale = function (locale) { + $locale = locale; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateDefaultInterpolation#getInterpolationIdentifier + * @methodOf pascalprecht.translate.$translateDefaultInterpolation + * + * @description + * Returns an identifier for this interpolation service. + * + * @returns {string} $identifier + */ + $translateInterpolator.getInterpolationIdentifier = function () { + return $identifier; + }; + + /** + * @deprecated will be removed in 3.0 + * @see {@link pascalprecht.translate.$translateSanitization} + */ + $translateInterpolator.useSanitizeValueStrategy = function (value) { + $translateSanitization.useStrategy(value); + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateDefaultInterpolation#interpolate + * @methodOf pascalprecht.translate.$translateDefaultInterpolation + * + * @description + * Interpolates given value agains given interpolate params using angulars + * `$interpolate` service. + * + * Since AngularJS 1.5, `value` must not be a string but can be anything input. + * + * @param {string} value translation + * @param {object} [interpolationParams={}] interpolation params + * @param {string} [context=undefined] current context (filter, directive, service) + * @param {string} [sanitizeStrategy=undefined] sanitize strategy (use default unless set) + * @param {string} translationId current translationId + * + * @returns {string} interpolated string + */ + $translateInterpolator.interpolate = function (value, interpolationParams, context, sanitizeStrategy, translationId) { // jshint ignore:line + interpolationParams = interpolationParams || {}; + interpolationParams = $translateSanitization.sanitize(interpolationParams, 'params', sanitizeStrategy, context); + + var interpolatedText; + if (angular.isNumber(value)) { + // numbers are safe + interpolatedText = '' + value; + } else if (angular.isString(value)) { + // strings must be interpolated (that's the job here) + interpolatedText = $interpolate(value)(interpolationParams); + interpolatedText = $translateSanitization.sanitize(interpolatedText, 'text', sanitizeStrategy, context); + } else { + // neither a number or a string, cant interpolate => empty string + interpolatedText = ''; + } + + return interpolatedText; + }; + + return $translateInterpolator; +} + +$translateDefaultInterpolation.displayName = '$translateDefaultInterpolation'; + +angular.module('pascalprecht.translate').constant('$STORAGE_KEY', 'NG_TRANSLATE_LANG_KEY'); + +angular.module('pascalprecht.translate') +/** + * @ngdoc directive + * @name pascalprecht.translate.directive:translate + * @requires $interpolate, + * @requires $compile, + * @requires $parse, + * @requires $rootScope + * @restrict AE + * + * @description + * Translates given translation id either through attribute or DOM content. + * Internally it uses $translate service to translate the translation id. It possible to + * pass an optional `translate-values` object literal as string into translation id. + * + * @param {string=} translate Translation id which could be either string or interpolated string. + * @param {string=} translate-values Values to pass into translation id. Can be passed as object literal string or interpolated object. + * @param {string=} translate-attr-ATTR translate Translation id and put it into ATTR attribute. + * @param {string=} translate-default will be used unless translation was successful + * @param {string=} translate-sanitize-strategy defines locally sanitize strategy + * @param {boolean=} translate-compile (default true if present) defines locally activation of {@link pascalprecht.translate.$translateProvider#methods_usePostCompiling} + * @param {boolean=} translate-keep-content (default true if present) defines that in case a KEY could not be translated, that the existing content is left in the innerHTML} + * + * @example + + +
      + +
      
      +        
      TRANSLATION_ID
      +
      
      +        
      
      +        
      {{translationId}}
      +
      
      +        
      WITH_VALUES
      +
      
      +        
      WITH_VALUES
      +
      
      +        
      
      +
      +      
      +
      + + angular.module('ngView', ['pascalprecht.translate']) + + .config(function ($translateProvider) { + + $translateProvider.translations('en',{ + 'TRANSLATION_ID': 'Hello there!', + 'WITH_VALUES': 'The following value is dynamic: {{value}}', + 'WITH_CAMEL_CASE_KEY': 'The interpolation key is camel cased: {{camelCaseKey}}' + }).preferredLanguage('en'); + + }); + + angular.module('ngView').controller('TranslateCtrl', function ($scope) { + $scope.translationId = 'TRANSLATION_ID'; + + $scope.values = { + value: 78 + }; + }); + + + it('should translate', function () { + inject(function ($rootScope, $compile) { + $rootScope.translationId = 'TRANSLATION_ID'; + + element = $compile('

      ')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('Hello there!'); + + element = $compile('

      ')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('Hello there!'); + + element = $compile('

      TRANSLATION_ID

      ')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('Hello there!'); + + element = $compile('

      {{translationId}}

      ')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('Hello there!'); + + element = $compile('

      ')($rootScope); + $rootScope.$digest(); + expect(element.attr('title')).toBe('Hello there!'); + + element = $compile('

      ')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('The interpolation key is camel cased: Hello'); + }); + }); +
      +
      + */ +.directive('translate', translateDirective); +function translateDirective($translate, $interpolate, $compile, $parse, $rootScope) { + + 'use strict'; + + /** + * @name trim + * @private + * + * @description + * trim polyfill + * + * @returns {string} The string stripped of whitespace from both ends + */ + var trim = function() { + return this.toString().replace(/^\s+|\s+$/g, ''); + }; + + /** + * @name lowercase + * @private + * + * @description + * Return the lowercase string only if the type is string + * + * @returns {string} The string all in lowercase + */ + var lowercase = function (string) { + return angular.isString(string) ? string.toLowerCase() : string; + }; + + return { + restrict: 'AE', + scope: true, + priority: $translate.directivePriority(), + compile: function (tElement, tAttr) { + + var translateValuesExist = (tAttr.translateValues) ? + tAttr.translateValues : undefined; + + var translateInterpolation = (tAttr.translateInterpolation) ? + tAttr.translateInterpolation : undefined; + + var translateSanitizeStrategyExist = (tAttr.translateSanitizeStrategy) ? + tAttr.translateSanitizeStrategy : undefined; + + var translateValueExist = tElement[0].outerHTML.match(/translate-value-+/i); + + var interpolateRegExp = '^(.*)(' + $interpolate.startSymbol() + '.*' + $interpolate.endSymbol() + ')(.*)', + watcherRegExp = '^(.*)' + $interpolate.startSymbol() + '(.*)' + $interpolate.endSymbol() + '(.*)'; + + return function linkFn(scope, iElement, iAttr) { + + scope.interpolateParams = {}; + scope.preText = ''; + scope.postText = ''; + scope.translateNamespace = getTranslateNamespace(scope); + var translationIds = {}; + + var initInterpolationParams = function (interpolateParams, iAttr, tAttr) { + // initial setup + if (iAttr.translateValues) { + angular.extend(interpolateParams, $parse(iAttr.translateValues)(scope.$parent)); + } + // initially fetch all attributes if existing and fill the params + if (translateValueExist) { + for (var attr in tAttr) { + if (Object.prototype.hasOwnProperty.call(iAttr, attr) && attr.substr(0, 14) === 'translateValue' && attr !== 'translateValues') { + var attributeName = lowercase(attr.substr(14, 1)) + attr.substr(15); + interpolateParams[attributeName] = tAttr[attr]; + } + } + } + }; + + // Ensures any change of the attribute "translate" containing the id will + // be re-stored to the scope's "translationId". + // If the attribute has no content, the element's text value (white spaces trimmed off) will be used. + var observeElementTranslation = function (translationId) { + + // Remove any old watcher + if (angular.isFunction(observeElementTranslation._unwatchOld)) { + observeElementTranslation._unwatchOld(); + observeElementTranslation._unwatchOld = undefined; + } + + if (angular.equals(translationId , '') || !angular.isDefined(translationId)) { + var iElementText = trim.apply(iElement.text()).replace(/\n/g, ' '); + + // Resolve translation id by inner html if required + var interpolateMatches = iElementText.match(interpolateRegExp); + // Interpolate translation id if required + if (angular.isArray(interpolateMatches)) { + scope.preText = interpolateMatches[1]; + scope.postText = interpolateMatches[3]; + translationIds.translate = $interpolate(interpolateMatches[2])(scope.$parent); + var watcherMatches = iElementText.match(watcherRegExp); + if (angular.isArray(watcherMatches) && watcherMatches[2] && watcherMatches[2].length) { + observeElementTranslation._unwatchOld = scope.$watch(watcherMatches[2], function (newValue) { + translationIds.translate = newValue; + updateTranslations(); + }); + } + } else { + // do not assigne the translation id if it is empty. + translationIds.translate = !iElementText ? undefined : iElementText; + } + } else { + translationIds.translate = translationId; + } + updateTranslations(); + }; + + var observeAttributeTranslation = function (translateAttr) { + iAttr.$observe(translateAttr, function (translationId) { + translationIds[translateAttr] = translationId; + updateTranslations(); + }); + }; + + // initial setup with values + initInterpolationParams(scope.interpolateParams, iAttr, tAttr); + + var firstAttributeChangedEvent = true; + iAttr.$observe('translate', function (translationId) { + if (typeof translationId === 'undefined') { + // case of element "xyz" + observeElementTranslation(''); + } else { + // case of regular attribute + if (translationId !== '' || !firstAttributeChangedEvent) { + translationIds.translate = translationId; + updateTranslations(); + } + } + firstAttributeChangedEvent = false; + }); + + for (var translateAttr in iAttr) { + if (iAttr.hasOwnProperty(translateAttr) && translateAttr.substr(0, 13) === 'translateAttr' && translateAttr.length > 13) { + observeAttributeTranslation(translateAttr); + } + } + + iAttr.$observe('translateDefault', function (value) { + scope.defaultText = value; + updateTranslations(); + }); + + if (translateSanitizeStrategyExist) { + iAttr.$observe('translateSanitizeStrategy', function (value) { + scope.sanitizeStrategy = $parse(value)(scope.$parent); + updateTranslations(); + }); + } + + if (translateValuesExist) { + iAttr.$observe('translateValues', function (interpolateParams) { + if (interpolateParams) { + scope.$parent.$watch(function () { + angular.extend(scope.interpolateParams, $parse(interpolateParams)(scope.$parent)); + }); + } + }); + } + + if (translateValueExist) { + var observeValueAttribute = function (attrName) { + iAttr.$observe(attrName, function (value) { + var attributeName = lowercase(attrName.substr(14, 1)) + attrName.substr(15); + scope.interpolateParams[attributeName] = value; + }); + }; + for (var attr in iAttr) { + if (Object.prototype.hasOwnProperty.call(iAttr, attr) && attr.substr(0, 14) === 'translateValue' && attr !== 'translateValues') { + observeValueAttribute(attr); + } + } + } + + // Master update function + var updateTranslations = function () { + for (var key in translationIds) { + if (translationIds.hasOwnProperty(key) && translationIds[key] !== undefined) { + updateTranslation(key, translationIds[key], scope, scope.interpolateParams, scope.defaultText, scope.translateNamespace); + } + } + }; + + // Put translation processing function outside loop + var updateTranslation = function(translateAttr, translationId, scope, interpolateParams, defaultTranslationText, translateNamespace) { + if (translationId) { + // if translation id starts with '.' and translateNamespace given, prepend namespace + if (translateNamespace && translationId.charAt(0) === '.') { + translationId = translateNamespace + translationId; + } + + $translate(translationId, interpolateParams, translateInterpolation, defaultTranslationText, scope.translateLanguage, scope.sanitizeStrategy) + .then(function (translation) { + applyTranslation(translation, scope, true, translateAttr); + }, function (translationId) { + applyTranslation(translationId, scope, false, translateAttr); + }); + } else { + // as an empty string cannot be translated, we can solve this using successful=false + applyTranslation(translationId, scope, false, translateAttr); + } + }; + + var applyTranslation = function (value, scope, successful, translateAttr) { + if (!successful) { + if (typeof scope.defaultText !== 'undefined') { + value = scope.defaultText; + } + } + if (translateAttr === 'translate') { + // default translate into innerHTML + if (successful || (!successful && !$translate.isKeepContent() && typeof iAttr.translateKeepContent === 'undefined')) { + iElement.empty().append(scope.preText + value + scope.postText); + } + var globallyEnabled = $translate.isPostCompilingEnabled(); + var locallyDefined = typeof tAttr.translateCompile !== 'undefined'; + var locallyEnabled = locallyDefined && tAttr.translateCompile !== 'false'; + if ((globallyEnabled && !locallyDefined) || locallyEnabled) { + $compile(iElement.contents())(scope); + } + } else { + // translate attribute + var attributeName = iAttr.$attr[translateAttr]; + if (attributeName.substr(0, 5) === 'data-') { + // ensure html5 data prefix is stripped + attributeName = attributeName.substr(5); + } + attributeName = attributeName.substr(15); + iElement.attr(attributeName, value); + } + }; + + if (translateValuesExist || translateValueExist || iAttr.translateDefault) { + scope.$watch('interpolateParams', updateTranslations, true); + } + + // Replaced watcher on translateLanguage with event listener + scope.$on('translateLanguageChanged', updateTranslations); + + // Ensures the text will be refreshed after the current language was changed + // w/ $translate.use(...) + var unbind = $rootScope.$on('$translateChangeSuccess', updateTranslations); + + // ensure translation will be looked up at least one + if (iElement.text().length) { + if (iAttr.translate) { + observeElementTranslation(iAttr.translate); + } else { + observeElementTranslation(''); + } + } else if (iAttr.translate) { + // ensure attribute will be not skipped + observeElementTranslation(iAttr.translate); + } + updateTranslations(); + scope.$on('$destroy', unbind); + }; + } + }; +} + +/** + * Returns the scope's namespace. + * @private + * @param scope + * @returns {string} + */ +function getTranslateNamespace(scope) { + 'use strict'; + if (scope.translateNamespace) { + return scope.translateNamespace; + } + if (scope.$parent) { + return getTranslateNamespace(scope.$parent); + } +} + +translateDirective.displayName = 'translateDirective'; + +angular.module('pascalprecht.translate') +/** + * @ngdoc directive + * @name pascalprecht.translate.directive:translate-attr + * @restrict A + * + * @description + * Translates attributes like translate-attr-ATTR, but with an object like ng-class. + * Internally it uses `translate` service to translate translation id. It possible to + * pass an optional `translate-values` object literal as string into translation id. + * + * @param {string=} translate-attr Object literal mapping attributes to translation ids. + * @param {string=} translate-values Values to pass into the translation ids. Can be passed as object literal string. + * @param {string=} translate-sanitize-strategy defines locally sanitize strategy + * + * @example + + +
      + + + +
      +
      + + angular.module('ngView', ['pascalprecht.translate']) + + .config(function ($translateProvider) { + + $translateProvider.translations('en',{ + 'TRANSLATION_ID': 'Hello there!', + 'WITH_VALUES': 'The following value is dynamic: {{value}}', + }).preferredLanguage('en'); + + }); + + angular.module('ngView').controller('TranslateCtrl', function ($scope) { + $scope.translationId = 'TRANSLATION_ID'; + + $scope.values = { + value: 78 + }; + }); + + + it('should translate', function () { + inject(function ($rootScope, $compile) { + $rootScope.translationId = 'TRANSLATION_ID'; + + element = $compile('')($rootScope); + $rootScope.$digest(); + expect(element.attr('placeholder)).toBe('Hello there!'); + expect(element.attr('title)).toBe('The following value is dynamic: 5'); + }); + }); + +
      + */ +.directive('translateAttr', translateAttrDirective); +function translateAttrDirective($translate, $rootScope) { + + 'use strict'; + + return { + restrict: 'A', + priority: $translate.directivePriority(), + link: function linkFn(scope, element, attr) { + + var translateAttr, + translateValues, + translateSanitizeStrategy, + previousAttributes = {}; + + // Main update translations function + var updateTranslations = function () { + angular.forEach(translateAttr, function (translationId, attributeName) { + if (!translationId) { + return; + } + previousAttributes[attributeName] = true; + + // if translation id starts with '.' and translateNamespace given, prepend namespace + if (scope.translateNamespace && translationId.charAt(0) === '.') { + translationId = scope.translateNamespace + translationId; + } + $translate(translationId, translateValues, attr.translateInterpolation, undefined, scope.translateLanguage, translateSanitizeStrategy) + .then(function (translation) { + element.attr(attributeName, translation); + }, function (translationId) { + element.attr(attributeName, translationId); + }); + }); + + // Removing unused attributes that were previously used + angular.forEach(previousAttributes, function (flag, attributeName) { + if (!translateAttr[attributeName]) { + element.removeAttr(attributeName); + delete previousAttributes[attributeName]; + } + }); + }; + + // Watch for attribute changes + watchAttribute( + scope, + attr.translateAttr, + function (newValue) { translateAttr = newValue; }, + updateTranslations + ); + // Watch for value changes + watchAttribute( + scope, + attr.translateValues, + function (newValue) { translateValues = newValue; }, + updateTranslations + ); + // Watch for sanitize strategy changes + watchAttribute( + scope, + attr.translateSanitizeStrategy, + function (newValue) { translateSanitizeStrategy = newValue; }, + updateTranslations + ); + + if (attr.translateValues) { + scope.$watch(attr.translateValues, updateTranslations, true); + } + + // Replaced watcher on translateLanguage with event listener + scope.$on('translateLanguageChanged', updateTranslations); + + // Ensures the text will be refreshed after the current language was changed + // w/ $translate.use(...) + var unbind = $rootScope.$on('$translateChangeSuccess', updateTranslations); + + updateTranslations(); + scope.$on('$destroy', unbind); + } + }; +} + +function watchAttribute(scope, attribute, valueCallback, changeCallback) { + 'use strict'; + if (!attribute) { + return; + } + if (attribute.substr(0, 2) === '::') { + attribute = attribute.substr(2); + } else { + scope.$watch(attribute, function(newValue) { + valueCallback(newValue); + changeCallback(); + }, true); + } + valueCallback(scope.$eval(attribute)); +} + +translateAttrDirective.displayName = 'translateAttrDirective'; + +angular.module('pascalprecht.translate') +/** + * @ngdoc directive + * @name pascalprecht.translate.directive:translateCloak + * @requires $translate + * @restrict A + * + * $description + * Adds a `translate-cloak` class name to the given element where this directive + * is applied initially and removes it, once a loader has finished loading. + * + * This directive can be used to prevent initial flickering when loading translation + * data asynchronously. + * + * The class name is defined in + * {@link pascalprecht.translate.$translateProvider#cloakClassName $translate.cloakClassName()}. + * + * @param {string=} translate-cloak If a translationId is provided, it will be used for showing + * or hiding the cloak. Basically it relies on the translation + * resolve. + */ +.directive('translateCloak', translateCloakDirective); + +function translateCloakDirective($translate, $rootScope) { + + 'use strict'; + + return { + compile : function (tElement) { + var applyCloak = function (element) { + element.addClass($translate.cloakClassName()); + }, + removeCloak = function (element) { + element.removeClass($translate.cloakClassName()); + }; + applyCloak(tElement); + + return function linkFn(scope, iElement, iAttr) { + //Create bound functions that incorporate the active DOM element. + var iRemoveCloak = removeCloak.bind(this, iElement), iApplyCloak = applyCloak.bind(this, iElement); + if (iAttr.translateCloak && iAttr.translateCloak.length) { + // Register a watcher for the defined translation allowing a fine tuned cloak + iAttr.$observe('translateCloak', function (translationId) { + $translate(translationId).then(iRemoveCloak, iApplyCloak); + }); + $rootScope.$on('$translateChangeSuccess', function () { + $translate(iAttr.translateCloak).then(iRemoveCloak, iApplyCloak); + }); + } else { + $translate.onReady(iRemoveCloak); + } + }; + } + }; +} + +translateCloakDirective.displayName = 'translateCloakDirective'; + +angular.module('pascalprecht.translate') +/** + * @ngdoc directive + * @name pascalprecht.translate.directive:translateNamespace + * @restrict A + * + * @description + * Translates given translation id either through attribute or DOM content. + * Internally it uses `translate` filter to translate translation id. It is possible to + * pass an optional `translate-values` object literal as string into translation id. + * + * @param {string=} translate namespace name which could be either string or interpolated string. + * + * @example + + +
      + +
      +

      .HEADERS.TITLE

      +

      .HEADERS.WELCOME

      +
      + +
      +

      .TITLE

      +

      .WELCOME

      +
      + +
      +
      + + angular.module('ngView', ['pascalprecht.translate']) + + .config(function ($translateProvider) { + + $translateProvider.translations('en',{ + 'TRANSLATION_ID': 'Hello there!', + 'CONTENT': { + 'HEADERS': { + TITLE: 'Title' + } + }, + 'CONTENT.HEADERS.WELCOME': 'Welcome' + }).preferredLanguage('en'); + + }); + + +
      + */ +.directive('translateNamespace', translateNamespaceDirective); + +function translateNamespaceDirective() { + + 'use strict'; + + return { + restrict: 'A', + scope: true, + compile: function () { + return { + pre: function (scope, iElement, iAttrs) { + scope.translateNamespace = _getTranslateNamespace(scope); + + if (scope.translateNamespace && iAttrs.translateNamespace.charAt(0) === '.') { + scope.translateNamespace += iAttrs.translateNamespace; + } else { + scope.translateNamespace = iAttrs.translateNamespace; + } + } + }; + } + }; +} + +/** + * Returns the scope's namespace. + * @private + * @param scope + * @returns {string} + */ +function _getTranslateNamespace(scope) { + 'use strict'; + if (scope.translateNamespace) { + return scope.translateNamespace; + } + if (scope.$parent) { + return _getTranslateNamespace(scope.$parent); + } +} + +translateNamespaceDirective.displayName = 'translateNamespaceDirective'; + +angular.module('pascalprecht.translate') +/** + * @ngdoc directive + * @name pascalprecht.translate.directive:translateLanguage + * @restrict A + * + * @description + * Forces the language to the directives in the underlying scope. + * + * @param {string=} translate language that will be negotiated. + * + * @example + + +
      + +
      +

      HELLO

      +
      + +
      +

      HELLO

      +
      + +
      +
      + + angular.module('ngView', ['pascalprecht.translate']) + + .config(function ($translateProvider) { + + $translateProvider + .translations('en',{ + 'HELLO': 'Hello world!' + }) + .translations('de',{ + 'HELLO': 'Hallo Welt!' + }) + .preferredLanguage('en'); + + }); + + +
      + */ +.directive('translateLanguage', translateLanguageDirective); + +function translateLanguageDirective() { + + 'use strict'; + + return { + restrict: 'A', + scope: true, + compile: function () { + return function linkFn(scope, iElement, iAttrs) { + + iAttrs.$observe('translateLanguage', function (newTranslateLanguage) { + scope.translateLanguage = newTranslateLanguage; + }); + + scope.$watch('translateLanguage', function(){ + scope.$broadcast('translateLanguageChanged'); + }); + }; + } + }; +} + +translateLanguageDirective.displayName = 'translateLanguageDirective'; + +angular.module('pascalprecht.translate') +/** + * @ngdoc filter + * @name pascalprecht.translate.filter:translate + * @requires $parse + * @requires pascalprecht.translate.$translate + * @function + * + * @description + * Uses `$translate` service to translate contents. Accepts interpolate parameters + * to pass dynamized values though translation. + * + * @param {string} translationId A translation id to be translated. + * @param {*=} interpolateParams Optional object literal (as hash or string) to pass values into translation. + * + * @returns {string} Translated text. + * + * @example + + +
      + +
      {{ 'TRANSLATION_ID' | translate }}
      +
      {{ translationId | translate }}
      +
      {{ 'WITH_VALUES' | translate:'{value: 5}' }}
      +
      {{ 'WITH_VALUES' | translate:values }}
      + +
      +
      + + angular.module('ngView', ['pascalprecht.translate']) + + .config(function ($translateProvider) { + + $translateProvider.translations('en', { + 'TRANSLATION_ID': 'Hello there!', + 'WITH_VALUES': 'The following value is dynamic: {{value}}' + }); + $translateProvider.preferredLanguage('en'); + + }); + + angular.module('ngView').controller('TranslateCtrl', function ($scope) { + $scope.translationId = 'TRANSLATION_ID'; + + $scope.values = { + value: 78 + }; + }); + +
      + */ +.filter('translate', translateFilterFactory); + +function translateFilterFactory($parse, $translate) { + + 'use strict'; + + var translateFilter = function (translationId, interpolateParams, interpolation, forceLanguage) { + if (!angular.isObject(interpolateParams)) { + var ctx = this || { + '__SCOPE_IS_NOT_AVAILABLE': 'More info at https://github.com/angular/angular.js/commit/8863b9d04c722b278fa93c5d66ad1e578ad6eb1f' + }; + interpolateParams = $parse(interpolateParams)(ctx); + } + + return $translate.instant(translationId, interpolateParams, interpolation, forceLanguage); + }; + + if ($translate.statefulFilter()) { + translateFilter.$stateful = true; + } + + return translateFilter; +} + +translateFilterFactory.displayName = 'translateFilterFactory'; + +angular.module('pascalprecht.translate') + +/** + * @ngdoc object + * @name pascalprecht.translate.$translationCache + * @requires $cacheFactory + * + * @description + * The first time a translation table is used, it is loaded in the translation cache for quick retrieval. You + * can load translation tables directly into the cache by consuming the + * `$translationCache` service directly. + * + * @return {object} $cacheFactory object. + */ + .factory('$translationCache', $translationCache); + +function $translationCache($cacheFactory) { + + 'use strict'; + + return $cacheFactory('translations'); +} + +$translationCache.displayName = '$translationCache'; +return 'pascalprecht.translate'; + +})); diff --git a/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate.min.js b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate.min.js new file mode 100644 index 0000000..065f7b8 --- /dev/null +++ b/keycloak-themes/keycloak/common/resources/node_modules/angular-translate/dist/angular-translate.min.js @@ -0,0 +1,6 @@ +/*! + * angular-translate - v2.18.2 - 2020-01-04 + * + * Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT + */ +!function(t,e){"function"==typeof define&&define.amd?define([],function(){return e()}):"object"==typeof module&&module.exports?module.exports=e():e()}(0,function(){function t(e){"use strict";var n=e.storageKey(),a=e.storage(),t=function(){var t=e.preferredLanguage();angular.isString(t)?e.use(t):a.put(n,e.use())};t.displayName="fallbackFromIncorrectStorageValue",a?a.get(n)?e.use(a.get(n)).catch(t):t():angular.isString(e.preferredLanguage())&&e.use(e.preferredLanguage())}function e(t,r,e,i){"use strict";var T,c,z,x,F,I,_,n,V,R,D,K,U,M,H,G,q={},Y=[],B=t,J=[],Q="translate-cloak",W=!1,X=!1,Z=".",tt=!1,et=!1,nt=0,at=!0,a="default",s={default:function(t){return(t||"").split("-").join("_")},java:function(t){var e=(t||"").split("-").join("_"),n=e.split("_");return 1
      ");return e.text(t),e.html()},i=function(t){if(!n)throw new Error("pascalprecht.translate.$translateSanitization: Error cannot find $sanitize service. Either include the ngSanitize module (https://docs.angularjs.org/api/ngSanitize) or use a sanitization strategy which does not depend on $sanitize, such as 'escape'.");return n(t)},s=function(t){if(!a)throw new Error("pascalprecht.translate.$translateSanitization: Error cannot find $sce service.");return a.trustAsHtml(t)},o=function(t,n,a){if(angular.isDate(t))return t;if(angular.isObject(t)){var r=angular.isArray(t)?[]:{};if(a){if(-1 .icon {\n height: 16px;\n}\n.tree .node .directory-level .operation {\n display: inline;\n margin-left: 20px;\n visibility: hidden;\n}\n.tree .node .directory-level .operation img {\n height: 16px;\n}\n.tree .node .directory-level:hover .operation {\n visibility: visible;\n}\n.tree .node .sub-node {\n padding-left: 14px;\n}\n", ""]); + + // exports + + +/***/ }, +/* 2 */ +/***/ function(module, exports) { + + /* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra + */ + // css base code, injected by the css-loader + module.exports = function() { + var list = []; + + // return the list of modules as css string + list.toString = function toString() { + var result = []; + for(var i = 0; i < this.length; i++) { + var item = this[i]; + if(item[2]) { + result.push("@media " + item[2] + "{" + item[1] + "}"); + } else { + result.push(item[1]); + } + } + return result.join(""); + }; + + // import a list of modules into the list + list.i = function(modules, mediaQuery) { + if(typeof modules === "string") + modules = [[null, modules, ""]]; + var alreadyImportedModules = {}; + for(var i = 0; i < this.length; i++) { + var id = this[i][0]; + if(typeof id === "number") + alreadyImportedModules[id] = true; + } + for(i = 0; i < modules.length; i++) { + var item = modules[i]; + // skip already imported module + // this implementation is not 100% perfect for weird media query combinations + // when a module is imported multiple times with different media queries. + // I hope this will never occur (Hey this way we have smaller bundles) + if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) { + if(mediaQuery && !item[2]) { + item[2] = mediaQuery; + } else if(mediaQuery) { + item[2] = "(" + item[2] + ") and (" + mediaQuery + ")"; + } + list.push(item); + } + } + }; + return list; + }; + + +/***/ }, +/* 3 */ +/***/ function(module, exports) { + + module.exports = "
      \n
      \n \n {{ adapter(item).text }}\n
      \n \n \n \n \n \n \n \n \n \n
      \n
      \n
      \n \n \n
      \n
      "; + +/***/ }, +/* 4 */ +/***/ function(module, exports) { + + module.exports = "
      \n \n \n
      "; + +/***/ }, +/* 5 */ +/***/ function(module, exports, __webpack_require__) { + + /* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra + */ + var stylesInDom = {}, + memoize = function(fn) { + var memo; + return function () { + if (typeof memo === "undefined") memo = fn.apply(this, arguments); + return memo; + }; + }, + isOldIE = memoize(function() { + return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase()); + }), + getHeadElement = memoize(function () { + return document.head || document.getElementsByTagName("head")[0]; + }), + singletonElement = null, + singletonCounter = 0, + styleElementsInsertedAtTop = []; + + module.exports = function(list, options) { + if(false) { + if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment"); + } + + options = options || {}; + // Force single-tag solution on IE6-9, which has a hard limit on the # of +
      + userType: + Required!
      + userType = {{userType}}
      + myForm.input.$valid = {{myForm.input.$valid}}
      + myForm.input.$error = {{myForm.input.$error}}
      + myForm.$valid = {{myForm.$valid}}
      + myForm.$error.required = {{!!myForm.$error.required}}
      +
      + + + it('should initialize to model', function() { + var userType = element(by.binding('userType')); + var valid = element(by.binding('myForm.input.$valid')); + + expect(userType.getText()).toContain('guest'); + expect(valid.getText()).toContain('true'); + }); + + it('should be invalid if empty', function() { + var userType = element(by.binding('userType')); + var valid = element(by.binding('myForm.input.$valid')); + var userInput = element(by.model('userType')); + + userInput.clear(); + userInput.sendKeys(''); + + expect(userType.getText()).toEqual('userType ='); + expect(valid.getText()).toContain('false'); + }); + + + * + * @param {string=} name Name of the form. If specified, the form controller will be published into + * related scope, under this name. + */ +var formDirectiveFactory = function(isNgForm) { + return ['$timeout', '$parse', function($timeout, $parse) { + var formDirective = { + name: 'form', + restrict: isNgForm ? 'EAC' : 'E', + require: ['form', '^^?form'], //first is the form's own ctrl, second is an optional parent form + controller: FormController, + compile: function ngFormCompile(formElement, attr) { + // Setup initial state of the control + formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS); + + var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false); + + return { + pre: function ngFormPreLink(scope, formElement, attr, ctrls) { + var controller = ctrls[0]; + + // if `action` attr is not present on the form, prevent the default action (submission) + if (!('action' in attr)) { + // we can't use jq events because if a form is destroyed during submission the default + // action is not prevented. see #1238 + // + // IE 9 is not affected because it doesn't fire a submit event and try to do a full + // page reload if the form was destroyed by submission of the form via a click handler + // on a button in the form. Looks like an IE9 specific bug. + var handleFormSubmission = function(event) { + scope.$apply(function() { + controller.$commitViewValue(); + controller.$setSubmitted(); + }); + + event.preventDefault(); + }; + + formElement[0].addEventListener('submit', handleFormSubmission); + + // unregister the preventDefault listener so that we don't not leak memory but in a + // way that will achieve the prevention of the default action. + formElement.on('$destroy', function() { + $timeout(function() { + formElement[0].removeEventListener('submit', handleFormSubmission); + }, 0, false); + }); + } + + var parentFormCtrl = ctrls[1] || controller.$$parentForm; + parentFormCtrl.$addControl(controller); + + var setter = nameAttr ? getSetter(controller.$name) : noop; + + if (nameAttr) { + setter(scope, controller); + attr.$observe(nameAttr, function(newValue) { + if (controller.$name === newValue) return; + setter(scope, undefined); + controller.$$parentForm.$$renameControl(controller, newValue); + setter = getSetter(controller.$name); + setter(scope, controller); + }); + } + formElement.on('$destroy', function() { + controller.$$parentForm.$removeControl(controller); + setter(scope, undefined); + extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards + }); + } + }; + } + }; + + return formDirective; + + function getSetter(expression) { + if (expression === '') { + //create an assignable expression, so forms with an empty name can be renamed later + return $parse('this[""]').assign; + } + return $parse(expression).assign || noop; + } + }]; +}; + +var formDirective = formDirectiveFactory(); +var ngFormDirective = formDirectiveFactory(true); + + + +// helper methods +function setupValidity(instance) { + instance.$$classCache = {}; + instance.$$classCache[INVALID_CLASS] = !(instance.$$classCache[VALID_CLASS] = instance.$$element.hasClass(VALID_CLASS)); +} +function addSetValidityMethod(context) { + var clazz = context.clazz, + set = context.set, + unset = context.unset; + + clazz.prototype.$setValidity = function(validationErrorKey, state, controller) { + if (isUndefined(state)) { + createAndSet(this, '$pending', validationErrorKey, controller); + } else { + unsetAndCleanup(this, '$pending', validationErrorKey, controller); + } + if (!isBoolean(state)) { + unset(this.$error, validationErrorKey, controller); + unset(this.$$success, validationErrorKey, controller); + } else { + if (state) { + unset(this.$error, validationErrorKey, controller); + set(this.$$success, validationErrorKey, controller); + } else { + set(this.$error, validationErrorKey, controller); + unset(this.$$success, validationErrorKey, controller); + } + } + if (this.$pending) { + cachedToggleClass(this, PENDING_CLASS, true); + this.$valid = this.$invalid = undefined; + toggleValidationCss(this, '', null); + } else { + cachedToggleClass(this, PENDING_CLASS, false); + this.$valid = isObjectEmpty(this.$error); + this.$invalid = !this.$valid; + toggleValidationCss(this, '', this.$valid); + } + + // re-read the state as the set/unset methods could have + // combined state in this.$error[validationError] (used for forms), + // where setting/unsetting only increments/decrements the value, + // and does not replace it. + var combinedState; + if (this.$pending && this.$pending[validationErrorKey]) { + combinedState = undefined; + } else if (this.$error[validationErrorKey]) { + combinedState = false; + } else if (this.$$success[validationErrorKey]) { + combinedState = true; + } else { + combinedState = null; + } + + toggleValidationCss(this, validationErrorKey, combinedState); + this.$$parentForm.$setValidity(validationErrorKey, combinedState, this); + }; + + function createAndSet(ctrl, name, value, controller) { + if (!ctrl[name]) { + ctrl[name] = {}; + } + set(ctrl[name], value, controller); + } + + function unsetAndCleanup(ctrl, name, value, controller) { + if (ctrl[name]) { + unset(ctrl[name], value, controller); + } + if (isObjectEmpty(ctrl[name])) { + ctrl[name] = undefined; + } + } + + function cachedToggleClass(ctrl, className, switchValue) { + if (switchValue && !ctrl.$$classCache[className]) { + ctrl.$$animate.addClass(ctrl.$$element, className); + ctrl.$$classCache[className] = true; + } else if (!switchValue && ctrl.$$classCache[className]) { + ctrl.$$animate.removeClass(ctrl.$$element, className); + ctrl.$$classCache[className] = false; + } + } + + function toggleValidationCss(ctrl, validationErrorKey, isValid) { + validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : ''; + + cachedToggleClass(ctrl, VALID_CLASS + validationErrorKey, isValid === true); + cachedToggleClass(ctrl, INVALID_CLASS + validationErrorKey, isValid === false); + } +} + +function isObjectEmpty(obj) { + if (obj) { + for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { + return false; + } + } + } + return true; +} + +/* global + VALID_CLASS: false, + INVALID_CLASS: false, + PRISTINE_CLASS: false, + DIRTY_CLASS: false, + ngModelMinErr: false +*/ + +// Regex code was initially obtained from SO prior to modification: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231 +var ISO_DATE_REGEXP = /^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z)$/; +// See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987) +// Note: We are being more lenient, because browsers are too. +// 1. Scheme +// 2. Slashes +// 3. Username +// 4. Password +// 5. Hostname +// 6. Port +// 7. Path +// 8. Query +// 9. Fragment +// 1111111111111111 222 333333 44444 55555555555555555555555 666 77777777 8888888 999 +var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i; +// eslint-disable-next-line max-len +var EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/; +var NUMBER_REGEXP = /^\s*(-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/; +var DATE_REGEXP = /^(\d{4,})-(\d{2})-(\d{2})$/; +var DATETIMELOCAL_REGEXP = /^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/; +var WEEK_REGEXP = /^(\d{4,})-W(\d\d)$/; +var MONTH_REGEXP = /^(\d{4,})-(\d\d)$/; +var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/; + +var PARTIAL_VALIDATION_EVENTS = 'keydown wheel mousedown'; +var PARTIAL_VALIDATION_TYPES = createMap(); +forEach('date,datetime-local,month,time,week'.split(','), function(type) { + PARTIAL_VALIDATION_TYPES[type] = true; +}); + +var inputType = { + + /** + * @ngdoc input + * @name input[text] + * + * @description + * Standard HTML text input with AngularJS data binding, inherited by most of the `input` elements. + * + * + * @param {string} ngModel Assignable AngularJS expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Adds `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of + * any length. + * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string + * that contains the regular expression body that will be converted to a regular expression + * as in the ngPattern directive. + * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} + * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value. + * If the expression evaluates to a RegExp object, then this is used directly. + * If the expression evaluates to a string, then it will be converted to a RegExp + * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to + * `new RegExp('^abc$')`.
      + * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to + * start at the index of the last search's match, thus not taking the whole input value into + * account. + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user + * interaction with the input element. + * @param {boolean=} [ngTrim=true] If set to false AngularJS will not automatically trim the input. + * This parameter is ignored for input[type=password] controls, which will never trim the + * input. + * + * @example + + + +
      + +
      + + Required! + + Single word only! +
      + text = {{example.text}}
      + myForm.input.$valid = {{myForm.input.$valid}}
      + myForm.input.$error = {{myForm.input.$error}}
      + myForm.$valid = {{myForm.$valid}}
      + myForm.$error.required = {{!!myForm.$error.required}}
      +
      +
      + + var text = element(by.binding('example.text')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('example.text')); + + it('should initialize to model', function() { + expect(text.getText()).toContain('guest'); + expect(valid.getText()).toContain('true'); + }); + + it('should be invalid if empty', function() { + input.clear(); + input.sendKeys(''); + + expect(text.getText()).toEqual('text ='); + expect(valid.getText()).toContain('false'); + }); + + it('should be invalid if multi word', function() { + input.clear(); + input.sendKeys('hello world'); + + expect(valid.getText()).toContain('false'); + }); + +
      + */ + 'text': textInputType, + + /** + * @ngdoc input + * @name input[date] + * + * @description + * Input with date validation and transformation. In browsers that do not yet support + * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601 + * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many + * modern browsers do not yet support this input type, it is important to provide cues to users on the + * expected input format via a placeholder or label. + * + * The model must always be a Date object, otherwise AngularJS will throw an error. + * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. + * + * The timezone to be used to read/write the `Date` instance in the model can be defined using + * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. + * + * @param {string} ngModel Assignable AngularJS expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a + * valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute + * (e.g. `min="{{minDate | date:'yyyy-MM-dd'}}"`). Note that `min` will also add native HTML5 + * constraint validation. + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be + * a valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute + * (e.g. `max="{{maxDate | date:'yyyy-MM-dd'}}"`). Note that `max` will also add native HTML5 + * constraint validation. + * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO date string + * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute. + * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO date string + * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
      + + +
      + + Required! + + Not a valid date! +
      + value = {{example.value | date: "yyyy-MM-dd"}}
      + myForm.input.$valid = {{myForm.input.$valid}}
      + myForm.input.$error = {{myForm.input.$error}}
      + myForm.$valid = {{myForm.$valid}}
      + myForm.$error.required = {{!!myForm.$error.required}}
      +
      +
      + + var value = element(by.binding('example.value | date: "yyyy-MM-dd"')); + var valid = element(by.binding('myForm.input.$valid')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (see https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('2013-10-22'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('2015-01-01'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
      + */ + 'date': createDateInputType('date', DATE_REGEXP, + createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']), + 'yyyy-MM-dd'), + + /** + * @ngdoc input + * @name input[datetime-local] + * + * @description + * Input with datetime validation and transformation. In browsers that do not yet support + * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 + * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`. + * + * The model must always be a Date object, otherwise AngularJS will throw an error. + * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. + * + * The timezone to be used to read/write the `Date` instance in the model can be defined using + * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. + * + * The format of the displayed time can be adjusted with the + * {@link ng.directive:ngModelOptions#ngModelOptions-arguments ngModelOptions} `timeSecondsFormat` + * and `timeStripZeroSeconds`. + * + * @param {string} ngModel Assignable AngularJS expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. + * This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation + * inside this attribute (e.g. `min="{{minDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`). + * Note that `min` will also add native HTML5 constraint validation. + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. + * This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation + * inside this attribute (e.g. `max="{{maxDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`). + * Note that `max` will also add native HTML5 constraint validation. + * @param {(date|string)=} ngMin Sets the `min` validation error key to the Date / ISO datetime string + * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute. + * @param {(date|string)=} ngMax Sets the `max` validation error key to the Date / ISO datetime string + * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
      + + +
      + + Required! + + Not a valid date! +
      + value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}
      + myForm.input.$valid = {{myForm.input.$valid}}
      + myForm.input.$error = {{myForm.input.$error}}
      + myForm.$valid = {{myForm.$valid}}
      + myForm.$error.required = {{!!myForm.$error.required}}
      +
      +
      + + var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"')); + var valid = element(by.binding('myForm.input.$valid')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('2010-12-28T14:57:00'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('2015-01-01T23:59:00'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
      + */ + 'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP, + createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']), + 'yyyy-MM-ddTHH:mm:ss.sss'), + + /** + * @ngdoc input + * @name input[time] + * + * @description + * Input with time validation and transformation. In browsers that do not yet support + * the HTML5 time input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 + * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a + * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`. + * + * The model must always be a Date object, otherwise AngularJS will throw an error. + * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. + * + * The timezone to be used to read/write the `Date` instance in the model can be defined using + * {@link ng.directive:ngModelOptions#ngModelOptions-arguments ngModelOptions}. By default, + * this is the timezone of the browser. + * + * The format of the displayed time can be adjusted with the + * {@link ng.directive:ngModelOptions#ngModelOptions-arguments ngModelOptions} `timeSecondsFormat` + * and `timeStripZeroSeconds`. + * + * @param {string} ngModel Assignable AngularJS expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. + * This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this + * attribute (e.g. `min="{{minTime | date:'HH:mm:ss'}}"`). Note that `min` will also add + * native HTML5 constraint validation. + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. + * This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this + * attribute (e.g. `max="{{maxTime | date:'HH:mm:ss'}}"`). Note that `max` will also add + * native HTML5 constraint validation. + * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO time string the + * `ngMin` expression evaluates to. Note that it does not set the `min` attribute. + * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO time string the + * `ngMax` expression evaluates to. Note that it does not set the `max` attribute. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
      + + +
      + + Required! + + Not a valid date! +
      + value = {{example.value | date: "HH:mm:ss"}}
      + myForm.input.$valid = {{myForm.input.$valid}}
      + myForm.input.$error = {{myForm.input.$error}}
      + myForm.$valid = {{myForm.$valid}}
      + myForm.$error.required = {{!!myForm.$error.required}}
      +
      +
      + + var value = element(by.binding('example.value | date: "HH:mm:ss"')); + var valid = element(by.binding('myForm.input.$valid')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('14:57:00'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('23:59:00'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
      + */ + 'time': createDateInputType('time', TIME_REGEXP, + createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']), + 'HH:mm:ss.sss'), + + /** + * @ngdoc input + * @name input[week] + * + * @description + * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support + * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 + * week format (yyyy-W##), for example: `2013-W02`. + * + * The model must always be a Date object, otherwise AngularJS will throw an error. + * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. + * + * The value of the resulting Date object will be set to Thursday at 00:00:00 of the requested week, + * due to ISO-8601 week numbering standards. Information on ISO's system for numbering the weeks of the + * year can be found at: https://en.wikipedia.org/wiki/ISO_8601#Week_dates + * + * The timezone to be used to read/write the `Date` instance in the model can be defined using + * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. + * + * @param {string} ngModel Assignable AngularJS expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. + * This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this + * attribute (e.g. `min="{{minWeek | date:'yyyy-Www'}}"`). Note that `min` will also add + * native HTML5 constraint validation. + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. + * This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this + * attribute (e.g. `max="{{maxWeek | date:'yyyy-Www'}}"`). Note that `max` will also add + * native HTML5 constraint validation. + * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string + * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute. + * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string + * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
      + +
      + + Required! + + Not a valid date! +
      + value = {{example.value | date: "yyyy-Www"}}
      + myForm.input.$valid = {{myForm.input.$valid}}
      + myForm.input.$error = {{myForm.input.$error}}
      + myForm.$valid = {{myForm.$valid}}
      + myForm.$error.required = {{!!myForm.$error.required}}
      +
      +
      + + var value = element(by.binding('example.value | date: "yyyy-Www"')); + var valid = element(by.binding('myForm.input.$valid')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('2013-W01'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('2015-W01'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
      + */ + 'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'), + + /** + * @ngdoc input + * @name input[month] + * + * @description + * Input with month validation and transformation. In browsers that do not yet support + * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 + * month format (yyyy-MM), for example: `2009-01`. + * + * The model must always be a Date object, otherwise AngularJS will throw an error. + * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. + * If the model is not set to the first of the month, the next view to model update will set it + * to the first of the month. + * + * The timezone to be used to read/write the `Date` instance in the model can be defined using + * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. + * + * @param {string} ngModel Assignable AngularJS expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. + * This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this + * attribute (e.g. `min="{{minMonth | date:'yyyy-MM'}}"`). Note that `min` will also add + * native HTML5 constraint validation. + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. + * This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this + * attribute (e.g. `max="{{maxMonth | date:'yyyy-MM'}}"`). Note that `max` will also add + * native HTML5 constraint validation. + * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string + * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute. + * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string + * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute. + + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
      + + +
      + + Required! + + Not a valid month! +
      + value = {{example.value | date: "yyyy-MM"}}
      + myForm.input.$valid = {{myForm.input.$valid}}
      + myForm.input.$error = {{myForm.input.$error}}
      + myForm.$valid = {{myForm.$valid}}
      + myForm.$error.required = {{!!myForm.$error.required}}
      +
      +
      + + var value = element(by.binding('example.value | date: "yyyy-MM"')); + var valid = element(by.binding('myForm.input.$valid')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('2013-10'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('2015-01'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
      + */ + 'month': createDateInputType('month', MONTH_REGEXP, + createDateParser(MONTH_REGEXP, ['yyyy', 'MM']), + 'yyyy-MM'), + + /** + * @ngdoc input + * @name input[number] + * + * @description + * Text input with number validation and transformation. Sets the `number` validation + * error if not a valid number. + * + *
      + * The model must always be of type `number` otherwise AngularJS will throw an error. + * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt} + * error docs for more information and an example of how to convert your model if necessary. + *
      + * + * + * + * @knownIssue + * + * ### HTML5 constraint validation and `allowInvalid` + * + * In browsers that follow the + * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29), + * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}. + * If a non-number is entered in the input, the browser will report the value as an empty string, + * which means the view / model values in `ngModel` and subsequently the scope value + * will also be an empty string. + * + * @knownIssue + * + * ### Large numbers and `step` validation + * + * The `step` validation will not work correctly for very large numbers (e.g. 9999999999) due to + * Javascript's arithmetic limitations. If you need to handle large numbers, purpose-built + * libraries (e.g. https://github.com/MikeMcl/big.js/), can be included into AngularJS by + * {@link guide/forms#modifying-built-in-validators overwriting the validators} + * for `number` and / or `step`, or by {@link guide/forms#custom-validation applying custom validators} + * to an `input[text]` element. The source for `input[number]` type can be used as a starting + * point for both implementations. + * + * @param {string} ngModel Assignable AngularJS expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. + * Can be interpolated. + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. + * Can be interpolated. + * @param {string=} ngMin Like `min`, sets the `min` validation error key if the value entered is less than `ngMin`, + * but does not trigger HTML5 native validation. Takes an expression. + * @param {string=} ngMax Like `max`, sets the `max` validation error key if the value entered is greater than `ngMax`, + * but does not trigger HTML5 native validation. Takes an expression. + * @param {string=} step Sets the `step` validation error key if the value entered does not fit the `step` constraint. + * Can be interpolated. + * @param {string=} ngStep Like `step`, sets the `step` validation error key if the value entered does not fit the `ngStep` constraint, + * but does not trigger HTML5 native validation. Takes an expression. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of + * any length. + * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string + * that contains the regular expression body that will be converted to a regular expression + * as in the ngPattern directive. + * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} + * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value. + * If the expression evaluates to a RegExp object, then this is used directly. + * If the expression evaluates to a string, then it will be converted to a RegExp + * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to + * `new RegExp('^abc$')`.
      + * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to + * start at the index of the last search's match, thus not taking the whole input value into + * account. + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
      + +
      + + Required! + + Not valid number! +
      + value = {{example.value}}
      + myForm.input.$valid = {{myForm.input.$valid}}
      + myForm.input.$error = {{myForm.input.$error}}
      + myForm.$valid = {{myForm.$valid}}
      + myForm.$error.required = {{!!myForm.$error.required}}
      +
      +
      + + var value = element(by.binding('example.value')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('example.value')); + + it('should initialize to model', function() { + expect(value.getText()).toContain('12'); + expect(valid.getText()).toContain('true'); + }); + + it('should be invalid if empty', function() { + input.clear(); + input.sendKeys(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('false'); + }); + + it('should be invalid if over max', function() { + input.clear(); + input.sendKeys('123'); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('false'); + }); + +
      + */ + 'number': numberInputType, + + + /** + * @ngdoc input + * @name input[url] + * + * @description + * Text input with URL validation. Sets the `url` validation error key if the content is not a + * valid URL. + * + *
      + * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex + * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify + * the built-in validators (see the {@link guide/forms Forms guide}) + *
      + * + * @param {string} ngModel Assignable AngularJS expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of + * any length. + * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string + * that contains the regular expression body that will be converted to a regular expression + * as in the ngPattern directive. + * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} + * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value. + * If the expression evaluates to a RegExp object, then this is used directly. + * If the expression evaluates to a string, then it will be converted to a RegExp + * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to + * `new RegExp('^abc$')`.
      + * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to + * start at the index of the last search's match, thus not taking the whole input value into + * account. + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
      +
      + + var text = element(by.binding('url.text')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('url.text')); + + it('should initialize to model', function() { + expect(text.getText()).toContain('http://google.com'); + expect(valid.getText()).toContain('true'); + }); + + it('should be invalid if empty', function() { + input.clear(); + input.sendKeys(''); + + expect(text.getText()).toEqual('text ='); + expect(valid.getText()).toContain('false'); + }); + + it('should be invalid if not url', function() { + input.clear(); + input.sendKeys('box'); + + expect(valid.getText()).toContain('false'); + }); + +
      + */ + 'url': urlInputType, + + + /** + * @ngdoc input + * @name input[email] + * + * @description + * Text input with email validation. Sets the `email` validation error key if not a valid email + * address. + * + *
      + * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex + * used in Chromium, which may not fulfill your app's requirements. + * If you need stricter (e.g. requiring a top-level domain), or more relaxed validation + * (e.g. allowing IPv6 address literals) you can use `ng-pattern` or + * modify the built-in validators (see the {@link guide/forms Forms guide}). + *
      + * + * @param {string} ngModel Assignable AngularJS expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of + * any length. + * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string + * that contains the regular expression body that will be converted to a regular expression + * as in the ngPattern directive. + * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} + * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value. + * If the expression evaluates to a RegExp object, then this is used directly. + * If the expression evaluates to a string, then it will be converted to a RegExp + * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to + * `new RegExp('^abc$')`.
      + * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to + * start at the index of the last search's match, thus not taking the whole input value into + * account. + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
      + +
      + + Required! + + Not valid email! +
      + text = {{email.text}}
      + myForm.input.$valid = {{myForm.input.$valid}}
      + myForm.input.$error = {{myForm.input.$error}}
      + myForm.$valid = {{myForm.$valid}}
      + myForm.$error.required = {{!!myForm.$error.required}}
      + myForm.$error.email = {{!!myForm.$error.email}}
      +
      +
      + + var text = element(by.binding('email.text')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('email.text')); + + it('should initialize to model', function() { + expect(text.getText()).toContain('me@example.com'); + expect(valid.getText()).toContain('true'); + }); + + it('should be invalid if empty', function() { + input.clear(); + input.sendKeys(''); + expect(text.getText()).toEqual('text ='); + expect(valid.getText()).toContain('false'); + }); + + it('should be invalid if not email', function() { + input.clear(); + input.sendKeys('xxx'); + + expect(valid.getText()).toContain('false'); + }); + +
      + */ + 'email': emailInputType, + + + /** + * @ngdoc input + * @name input[radio] + * + * @description + * HTML radio button. + * + * **Note:**
      + * All inputs controlled by {@link ngModel ngModel} (including those of type `radio`) will use the + * value of their `name` attribute to determine the property under which their + * {@link ngModel.NgModelController NgModelController} will be published on the parent + * {@link form.FormController FormController}. Thus, if you use the same `name` for multiple + * inputs of a form (e.g. a group of radio inputs), only _one_ `NgModelController` will be + * published on the parent `FormController` under that name. The rest of the controllers will + * continue to work as expected, but you won't be able to access them as properties on the parent + * `FormController`. + * + *
      + *

      + * In plain HTML forms, the `name` attribute is used to identify groups of radio inputs, so + * that the browser can manage their state (checked/unchecked) based on the state of other + * inputs in the same group. + *

      + *

      + * In AngularJS forms, this is not necessary. The input's state will be updated based on the + * value of the underlying model data. + *

      + *
      + * + *
      + * If you omit the `name` attribute on a radio input, `ngModel` will automatically assign it a + * unique name. + *
      + * + * @param {string} ngModel Assignable AngularJS expression to data-bind to. + * @param {string} value The value to which the `ngModel` expression should be set when selected. + * Note that `value` only supports `string` values, i.e. the scope model needs to be a string, + * too. Use `ngValue` if you need complex models (`number`, `object`, ...). + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user + * interaction with the input element. + * @param {string} ngValue AngularJS expression to which `ngModel` will be be set when the radio + * is selected. Should be used instead of the `value` attribute if you need + * a non-string `ngModel` (`boolean`, `array`, ...). + * + * @example + + + +
      +
      +
      +
      + color = {{color.name | json}}
      +
      + Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`. +
      + + it('should change state', function() { + var inputs = element.all(by.model('color.name')); + var color = element(by.binding('color.name')); + + expect(color.getText()).toContain('blue'); + + inputs.get(0).click(); + expect(color.getText()).toContain('red'); + + inputs.get(1).click(); + expect(color.getText()).toContain('green'); + }); + +
      + */ + 'radio': radioInputType, + + /** + * @ngdoc input + * @name input[range] + * + * @description + * Native range input with validation and transformation. + * + * The model for the range input must always be a `Number`. + * + * IE9 and other browsers that do not support the `range` type fall back + * to a text input without any default values for `min`, `max` and `step`. Model binding, + * validation and number parsing are nevertheless supported. + * + * Browsers that support range (latest Chrome, Safari, Firefox, Edge) treat `input[range]` + * in a way that never allows the input to hold an invalid value. That means: + * - any non-numerical value is set to `(max + min) / 2`. + * - any numerical value that is less than the current min val, or greater than the current max val + * is set to the min / max val respectively. + * - additionally, the current `step` is respected, so the nearest value that satisfies a step + * is used. + * + * See the [HTML Spec on input[type=range]](https://www.w3.org/TR/html5/forms.html#range-state-(type=range)) + * for more info. + * + * This has the following consequences for AngularJS: + * + * Since the element value should always reflect the current model value, a range input + * will set the bound ngModel expression to the value that the browser has set for the + * input element. For example, in the following input ``, + * if the application sets `model.value = null`, the browser will set the input to `'50'`. + * AngularJS will then set the model to `50`, to prevent input and model value being out of sync. + * + * That means the model for range will immediately be set to `50` after `ngModel` has been + * initialized. It also means a range input can never have the required error. + * + * This does not only affect changes to the model value, but also to the values of the `min`, + * `max`, and `step` attributes. When these change in a way that will cause the browser to modify + * the input value, AngularJS will also update the model value. + * + * Automatic value adjustment also means that a range input element can never have the `required`, + * `min`, or `max` errors. + * + * However, `step` is currently only fully implemented by Firefox. Other browsers have problems + * when the step value changes dynamically - they do not adjust the element value correctly, but + * instead may set the `stepMismatch` error. If that's the case, the AngularJS will set the `step` + * error on the input, and set the model to `undefined`. + * + * Note that `input[range]` is not compatible with`ngMax`, `ngMin`, and `ngStep`, because they do + * not set the `min` and `max` attributes, which means that the browser won't automatically adjust + * the input value based on their values, and will always assume min = 0, max = 100, and step = 1. + * + * @param {string} ngModel Assignable AngularJS expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation to ensure that the value entered is greater + * than `min`. Can be interpolated. + * @param {string=} max Sets the `max` validation to ensure that the value entered is less than `max`. + * Can be interpolated. + * @param {string=} step Sets the `step` validation to ensure that the value entered matches the `step` + * Can be interpolated. + * @param {expression=} ngChange AngularJS expression to be executed when the ngModel value changes due + * to user interaction with the input element. + * @param {expression=} ngChecked If the expression is truthy, then the `checked` attribute will be set on the + * element. **Note** : `ngChecked` should not be used alongside `ngModel`. + * Checkout {@link ng.directive:ngChecked ngChecked} for usage. + * + * @example + + + +
      + + Model as range: +
      + Model as number:
      + Min:
      + Max:
      + value = {{value}}
      + myForm.range.$valid = {{myForm.range.$valid}}
      + myForm.range.$error = {{myForm.range.$error}} +
      +
      +
      + + * ## Range Input with ngMin & ngMax attributes + + * @example + + + +
      + Model as range: +
      + Model as number:
      + Min:
      + Max:
      + value = {{value}}
      + myForm.range.$valid = {{myForm.range.$valid}}
      + myForm.range.$error = {{myForm.range.$error}} +
      +
      +
      + + */ + 'range': rangeInputType, + + /** + * @ngdoc input + * @name input[checkbox] + * + * @description + * HTML checkbox. + * + * @param {string} ngModel Assignable AngularJS expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {expression=} ngTrueValue The value to which the expression should be set when selected. + * @param {expression=} ngFalseValue The value to which the expression should be set when not selected. + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
      +
      +
      + value1 = {{checkboxModel.value1}}
      + value2 = {{checkboxModel.value2}}
      +
      +
      + + it('should change state', function() { + var value1 = element(by.binding('checkboxModel.value1')); + var value2 = element(by.binding('checkboxModel.value2')); + + expect(value1.getText()).toContain('true'); + expect(value2.getText()).toContain('YES'); + + element(by.model('checkboxModel.value1')).click(); + element(by.model('checkboxModel.value2')).click(); + + expect(value1.getText()).toContain('false'); + expect(value2.getText()).toContain('NO'); + }); + +
      + */ + 'checkbox': checkboxInputType, + + 'hidden': noop, + 'button': noop, + 'submit': noop, + 'reset': noop, + 'file': noop +}; + +function stringBasedInputType(ctrl) { + ctrl.$formatters.push(function(value) { + return ctrl.$isEmpty(value) ? value : value.toString(); + }); +} + +function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { + baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + stringBasedInputType(ctrl); +} + +function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) { + var type = lowercase(element[0].type); + + // In composition mode, users are still inputting intermediate text buffer, + // hold the listener until composition is done. + // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent + if (!$sniffer.android) { + var composing = false; + + element.on('compositionstart', function() { + composing = true; + }); + + // Support: IE9+ + element.on('compositionupdate', function(ev) { + // End composition when ev.data is empty string on 'compositionupdate' event. + // When the input de-focusses (e.g. by clicking away), IE triggers 'compositionupdate' + // instead of 'compositionend'. + if (isUndefined(ev.data) || ev.data === '') { + composing = false; + } + }); + + element.on('compositionend', function() { + composing = false; + listener(); + }); + } + + var timeout; + + var listener = function(ev) { + if (timeout) { + $browser.defer.cancel(timeout); + timeout = null; + } + if (composing) return; + var value = element.val(), + event = ev && ev.type; + + // By default we will trim the value + // If the attribute ng-trim exists we will avoid trimming + // If input type is 'password', the value is never trimmed + if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) { + value = trim(value); + } + + // If a control is suffering from bad input (due to native validators), browsers discard its + // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the + // control's value is the same empty value twice in a row. + if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) { + ctrl.$setViewValue(value, event); + } + }; + + // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the + // input event on backspace, delete or cut + if ($sniffer.hasEvent('input')) { + element.on('input', listener); + } else { + var deferListener = function(ev, input, origValue) { + if (!timeout) { + timeout = $browser.defer(function() { + timeout = null; + if (!input || input.value !== origValue) { + listener(ev); + } + }); + } + }; + + element.on('keydown', /** @this */ function(event) { + var key = event.keyCode; + + // ignore + // command modifiers arrows + if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return; + + deferListener(event, this, this.value); + }); + + // if user modifies input value using context menu in IE, we need "paste", "cut" and "drop" events to catch it + if ($sniffer.hasEvent('paste')) { + element.on('paste cut drop', deferListener); + } + } + + // if user paste into input using mouse on older browser + // or form autocomplete on newer browser, we need "change" event to catch it + element.on('change', listener); + + // Some native input types (date-family) have the ability to change validity without + // firing any input/change events. + // For these event types, when native validators are present and the browser supports the type, + // check for validity changes on various DOM events. + if (PARTIAL_VALIDATION_TYPES[type] && ctrl.$$hasNativeValidators && type === attr.type) { + element.on(PARTIAL_VALIDATION_EVENTS, /** @this */ function(ev) { + if (!timeout) { + var validity = this[VALIDITY_STATE_PROPERTY]; + var origBadInput = validity.badInput; + var origTypeMismatch = validity.typeMismatch; + timeout = $browser.defer(function() { + timeout = null; + if (validity.badInput !== origBadInput || validity.typeMismatch !== origTypeMismatch) { + listener(ev); + } + }); + } + }); + } + + ctrl.$render = function() { + // Workaround for Firefox validation #12102. + var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue; + if (element.val() !== value) { + element.val(value); + } + }; +} + +function weekParser(isoWeek, existingDate) { + if (isDate(isoWeek)) { + return isoWeek; + } + + if (isString(isoWeek)) { + WEEK_REGEXP.lastIndex = 0; + var parts = WEEK_REGEXP.exec(isoWeek); + if (parts) { + var year = +parts[1], + week = +parts[2], + hours = 0, + minutes = 0, + seconds = 0, + milliseconds = 0, + firstThurs = getFirstThursdayOfYear(year), + addDays = (week - 1) * 7; + + if (existingDate) { + hours = existingDate.getHours(); + minutes = existingDate.getMinutes(); + seconds = existingDate.getSeconds(); + milliseconds = existingDate.getMilliseconds(); + } + + return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds); + } + } + + return NaN; +} + +function createDateParser(regexp, mapping) { + return function(iso, previousDate) { + var parts, map; + + if (isDate(iso)) { + return iso; + } + + if (isString(iso)) { + // When a date is JSON'ified to wraps itself inside of an extra + // set of double quotes. This makes the date parsing code unable + // to match the date string and parse it as a date. + if (iso.charAt(0) === '"' && iso.charAt(iso.length - 1) === '"') { + iso = iso.substring(1, iso.length - 1); + } + if (ISO_DATE_REGEXP.test(iso)) { + return new Date(iso); + } + regexp.lastIndex = 0; + parts = regexp.exec(iso); + + if (parts) { + parts.shift(); + if (previousDate) { + map = { + yyyy: previousDate.getFullYear(), + MM: previousDate.getMonth() + 1, + dd: previousDate.getDate(), + HH: previousDate.getHours(), + mm: previousDate.getMinutes(), + ss: previousDate.getSeconds(), + sss: previousDate.getMilliseconds() / 1000 + }; + } else { + map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 }; + } + + forEach(parts, function(part, index) { + if (index < mapping.length) { + map[mapping[index]] = +part; + } + }); + + var date = new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0); + if (map.yyyy < 100) { + // In the constructor, 2-digit years map to 1900-1999. + // Use `setFullYear()` to set the correct year. + date.setFullYear(map.yyyy); + } + + return date; + } + } + + return NaN; + }; +} + +function createDateInputType(type, regexp, parseDate, format) { + return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) { + badInputChecker(scope, element, attr, ctrl, type); + baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + + var isTimeType = type === 'time' || type === 'datetimelocal'; + var previousDate; + var previousTimezone; + + ctrl.$parsers.push(function(value) { + if (ctrl.$isEmpty(value)) return null; + + if (regexp.test(value)) { + // Note: We cannot read ctrl.$modelValue, as there might be a different + // parser/formatter in the processing chain so that the model + // contains some different data format! + return parseDateAndConvertTimeZoneToLocal(value, previousDate); + } + ctrl.$$parserName = type; + return undefined; + }); + + ctrl.$formatters.push(function(value) { + if (value && !isDate(value)) { + throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value); + } + if (isValidDate(value)) { + previousDate = value; + var timezone = ctrl.$options.getOption('timezone'); + + if (timezone) { + previousTimezone = timezone; + previousDate = convertTimezoneToLocal(previousDate, timezone, true); + } + + return formatter(value, timezone); + } else { + previousDate = null; + previousTimezone = null; + return ''; + } + }); + + if (isDefined(attr.min) || attr.ngMin) { + var minVal = attr.min || $parse(attr.ngMin)(scope); + var parsedMinVal = parseObservedDateValue(minVal); + + ctrl.$validators.min = function(value) { + return !isValidDate(value) || isUndefined(parsedMinVal) || parseDate(value) >= parsedMinVal; + }; + attr.$observe('min', function(val) { + if (val !== minVal) { + parsedMinVal = parseObservedDateValue(val); + minVal = val; + ctrl.$validate(); + } + }); + } + + if (isDefined(attr.max) || attr.ngMax) { + var maxVal = attr.max || $parse(attr.ngMax)(scope); + var parsedMaxVal = parseObservedDateValue(maxVal); + + ctrl.$validators.max = function(value) { + return !isValidDate(value) || isUndefined(parsedMaxVal) || parseDate(value) <= parsedMaxVal; + }; + attr.$observe('max', function(val) { + if (val !== maxVal) { + parsedMaxVal = parseObservedDateValue(val); + maxVal = val; + ctrl.$validate(); + } + }); + } + + function isValidDate(value) { + // Invalid Date: getTime() returns NaN + return value && !(value.getTime && value.getTime() !== value.getTime()); + } + + function parseObservedDateValue(val) { + return isDefined(val) && !isDate(val) ? parseDateAndConvertTimeZoneToLocal(val) || undefined : val; + } + + function parseDateAndConvertTimeZoneToLocal(value, previousDate) { + var timezone = ctrl.$options.getOption('timezone'); + + if (previousTimezone && previousTimezone !== timezone) { + // If the timezone has changed, adjust the previousDate to the default timezone + // so that the new date is converted with the correct timezone offset + previousDate = addDateMinutes(previousDate, timezoneToOffset(previousTimezone)); + } + + var parsedDate = parseDate(value, previousDate); + + if (!isNaN(parsedDate) && timezone) { + parsedDate = convertTimezoneToLocal(parsedDate, timezone); + } + return parsedDate; + } + + function formatter(value, timezone) { + var targetFormat = format; + + if (isTimeType && isString(ctrl.$options.getOption('timeSecondsFormat'))) { + targetFormat = format + .replace('ss.sss', ctrl.$options.getOption('timeSecondsFormat')) + .replace(/:$/, ''); + } + + var formatted = $filter('date')(value, targetFormat, timezone); + + if (isTimeType && ctrl.$options.getOption('timeStripZeroSeconds')) { + formatted = formatted.replace(/(?::00)?(?:\.000)?$/, ''); + } + + return formatted; + } + }; +} + +function badInputChecker(scope, element, attr, ctrl, parserName) { + var node = element[0]; + var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity); + if (nativeValidation) { + ctrl.$parsers.push(function(value) { + var validity = element.prop(VALIDITY_STATE_PROPERTY) || {}; + if (validity.badInput || validity.typeMismatch) { + ctrl.$$parserName = parserName; + return undefined; + } + + return value; + }); + } +} + +function numberFormatterParser(ctrl) { + ctrl.$parsers.push(function(value) { + if (ctrl.$isEmpty(value)) return null; + if (NUMBER_REGEXP.test(value)) return parseFloat(value); + + ctrl.$$parserName = 'number'; + return undefined; + }); + + ctrl.$formatters.push(function(value) { + if (!ctrl.$isEmpty(value)) { + if (!isNumber(value)) { + throw ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value); + } + value = value.toString(); + } + return value; + }); +} + +function parseNumberAttrVal(val) { + if (isDefined(val) && !isNumber(val)) { + val = parseFloat(val); + } + return !isNumberNaN(val) ? val : undefined; +} + +function isNumberInteger(num) { + // See http://stackoverflow.com/questions/14636536/how-to-check-if-a-variable-is-an-integer-in-javascript#14794066 + // (minus the assumption that `num` is a number) + + // eslint-disable-next-line no-bitwise + return (num | 0) === num; +} + +function countDecimals(num) { + var numString = num.toString(); + var decimalSymbolIndex = numString.indexOf('.'); + + if (decimalSymbolIndex === -1) { + if (-1 < num && num < 1) { + // It may be in the exponential notation format (`1e-X`) + var match = /e-(\d+)$/.exec(numString); + + if (match) { + return Number(match[1]); + } + } + + return 0; + } + + return numString.length - decimalSymbolIndex - 1; +} + +function isValidForStep(viewValue, stepBase, step) { + // At this point `stepBase` and `step` are expected to be non-NaN values + // and `viewValue` is expected to be a valid stringified number. + var value = Number(viewValue); + + var isNonIntegerValue = !isNumberInteger(value); + var isNonIntegerStepBase = !isNumberInteger(stepBase); + var isNonIntegerStep = !isNumberInteger(step); + + // Due to limitations in Floating Point Arithmetic (e.g. `0.3 - 0.2 !== 0.1` or + // `0.5 % 0.1 !== 0`), we need to convert all numbers to integers. + if (isNonIntegerValue || isNonIntegerStepBase || isNonIntegerStep) { + var valueDecimals = isNonIntegerValue ? countDecimals(value) : 0; + var stepBaseDecimals = isNonIntegerStepBase ? countDecimals(stepBase) : 0; + var stepDecimals = isNonIntegerStep ? countDecimals(step) : 0; + + var decimalCount = Math.max(valueDecimals, stepBaseDecimals, stepDecimals); + var multiplier = Math.pow(10, decimalCount); + + value = value * multiplier; + stepBase = stepBase * multiplier; + step = step * multiplier; + + if (isNonIntegerValue) value = Math.round(value); + if (isNonIntegerStepBase) stepBase = Math.round(stepBase); + if (isNonIntegerStep) step = Math.round(step); + } + + return (value - stepBase) % step === 0; +} + +function numberInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) { + badInputChecker(scope, element, attr, ctrl, 'number'); + numberFormatterParser(ctrl); + baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + + var parsedMinVal; + + if (isDefined(attr.min) || attr.ngMin) { + var minVal = attr.min || $parse(attr.ngMin)(scope); + parsedMinVal = parseNumberAttrVal(minVal); + + ctrl.$validators.min = function(modelValue, viewValue) { + return ctrl.$isEmpty(viewValue) || isUndefined(parsedMinVal) || viewValue >= parsedMinVal; + }; + + attr.$observe('min', function(val) { + if (val !== minVal) { + parsedMinVal = parseNumberAttrVal(val); + minVal = val; + // TODO(matsko): implement validateLater to reduce number of validations + ctrl.$validate(); + } + }); + } + + if (isDefined(attr.max) || attr.ngMax) { + var maxVal = attr.max || $parse(attr.ngMax)(scope); + var parsedMaxVal = parseNumberAttrVal(maxVal); + + ctrl.$validators.max = function(modelValue, viewValue) { + return ctrl.$isEmpty(viewValue) || isUndefined(parsedMaxVal) || viewValue <= parsedMaxVal; + }; + + attr.$observe('max', function(val) { + if (val !== maxVal) { + parsedMaxVal = parseNumberAttrVal(val); + maxVal = val; + // TODO(matsko): implement validateLater to reduce number of validations + ctrl.$validate(); + } + }); + } + + if (isDefined(attr.step) || attr.ngStep) { + var stepVal = attr.step || $parse(attr.ngStep)(scope); + var parsedStepVal = parseNumberAttrVal(stepVal); + + ctrl.$validators.step = function(modelValue, viewValue) { + return ctrl.$isEmpty(viewValue) || isUndefined(parsedStepVal) || + isValidForStep(viewValue, parsedMinVal || 0, parsedStepVal); + }; + + attr.$observe('step', function(val) { + // TODO(matsko): implement validateLater to reduce number of validations + if (val !== stepVal) { + parsedStepVal = parseNumberAttrVal(val); + stepVal = val; + ctrl.$validate(); + } + + }); + + } +} + +function rangeInputType(scope, element, attr, ctrl, $sniffer, $browser) { + badInputChecker(scope, element, attr, ctrl, 'range'); + numberFormatterParser(ctrl); + baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + + var supportsRange = ctrl.$$hasNativeValidators && element[0].type === 'range', + minVal = supportsRange ? 0 : undefined, + maxVal = supportsRange ? 100 : undefined, + stepVal = supportsRange ? 1 : undefined, + validity = element[0].validity, + hasMinAttr = isDefined(attr.min), + hasMaxAttr = isDefined(attr.max), + hasStepAttr = isDefined(attr.step); + + var originalRender = ctrl.$render; + + ctrl.$render = supportsRange && isDefined(validity.rangeUnderflow) && isDefined(validity.rangeOverflow) ? + //Browsers that implement range will set these values automatically, but reading the adjusted values after + //$render would cause the min / max validators to be applied with the wrong value + function rangeRender() { + originalRender(); + ctrl.$setViewValue(element.val()); + } : + originalRender; + + if (hasMinAttr) { + minVal = parseNumberAttrVal(attr.min); + + ctrl.$validators.min = supportsRange ? + // Since all browsers set the input to a valid value, we don't need to check validity + function noopMinValidator() { return true; } : + // non-support browsers validate the min val + function minValidator(modelValue, viewValue) { + return ctrl.$isEmpty(viewValue) || isUndefined(minVal) || viewValue >= minVal; + }; + + setInitialValueAndObserver('min', minChange); + } + + if (hasMaxAttr) { + maxVal = parseNumberAttrVal(attr.max); + + ctrl.$validators.max = supportsRange ? + // Since all browsers set the input to a valid value, we don't need to check validity + function noopMaxValidator() { return true; } : + // non-support browsers validate the max val + function maxValidator(modelValue, viewValue) { + return ctrl.$isEmpty(viewValue) || isUndefined(maxVal) || viewValue <= maxVal; + }; + + setInitialValueAndObserver('max', maxChange); + } + + if (hasStepAttr) { + stepVal = parseNumberAttrVal(attr.step); + + ctrl.$validators.step = supportsRange ? + function nativeStepValidator() { + // Currently, only FF implements the spec on step change correctly (i.e. adjusting the + // input element value to a valid value). It's possible that other browsers set the stepMismatch + // validity error instead, so we can at least report an error in that case. + return !validity.stepMismatch; + } : + // ngStep doesn't set the setp attr, so the browser doesn't adjust the input value as setting step would + function stepValidator(modelValue, viewValue) { + return ctrl.$isEmpty(viewValue) || isUndefined(stepVal) || + isValidForStep(viewValue, minVal || 0, stepVal); + }; + + setInitialValueAndObserver('step', stepChange); + } + + function setInitialValueAndObserver(htmlAttrName, changeFn) { + // interpolated attributes set the attribute value only after a digest, but we need the + // attribute value when the input is first rendered, so that the browser can adjust the + // input value based on the min/max value + element.attr(htmlAttrName, attr[htmlAttrName]); + var oldVal = attr[htmlAttrName]; + attr.$observe(htmlAttrName, function wrappedObserver(val) { + if (val !== oldVal) { + oldVal = val; + changeFn(val); + } + }); + } + + function minChange(val) { + minVal = parseNumberAttrVal(val); + // ignore changes before model is initialized + if (isNumberNaN(ctrl.$modelValue)) { + return; + } + + if (supportsRange) { + var elVal = element.val(); + // IE11 doesn't set the el val correctly if the minVal is greater than the element value + if (minVal > elVal) { + elVal = minVal; + element.val(elVal); + } + ctrl.$setViewValue(elVal); + } else { + // TODO(matsko): implement validateLater to reduce number of validations + ctrl.$validate(); + } + } + + function maxChange(val) { + maxVal = parseNumberAttrVal(val); + // ignore changes before model is initialized + if (isNumberNaN(ctrl.$modelValue)) { + return; + } + + if (supportsRange) { + var elVal = element.val(); + // IE11 doesn't set the el val correctly if the maxVal is less than the element value + if (maxVal < elVal) { + element.val(maxVal); + // IE11 and Chrome don't set the value to the minVal when max < min + elVal = maxVal < minVal ? minVal : maxVal; + } + ctrl.$setViewValue(elVal); + } else { + // TODO(matsko): implement validateLater to reduce number of validations + ctrl.$validate(); + } + } + + function stepChange(val) { + stepVal = parseNumberAttrVal(val); + // ignore changes before model is initialized + if (isNumberNaN(ctrl.$modelValue)) { + return; + } + + // Some browsers don't adjust the input value correctly, but set the stepMismatch error + if (!supportsRange) { + // TODO(matsko): implement validateLater to reduce number of validations + ctrl.$validate(); + } else if (ctrl.$viewValue !== element.val()) { + ctrl.$setViewValue(element.val()); + } + } +} + +function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) { + // Note: no badInputChecker here by purpose as `url` is only a validation + // in browsers, i.e. we can always read out input.value even if it is not valid! + baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + stringBasedInputType(ctrl); + + ctrl.$validators.url = function(modelValue, viewValue) { + var value = modelValue || viewValue; + return ctrl.$isEmpty(value) || URL_REGEXP.test(value); + }; +} + +function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) { + // Note: no badInputChecker here by purpose as `url` is only a validation + // in browsers, i.e. we can always read out input.value even if it is not valid! + baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + stringBasedInputType(ctrl); + + ctrl.$validators.email = function(modelValue, viewValue) { + var value = modelValue || viewValue; + return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value); + }; +} + +function radioInputType(scope, element, attr, ctrl) { + var doTrim = !attr.ngTrim || trim(attr.ngTrim) !== 'false'; + // make the name unique, if not defined + if (isUndefined(attr.name)) { + element.attr('name', nextUid()); + } + + var listener = function(ev) { + var value; + if (element[0].checked) { + value = attr.value; + if (doTrim) { + value = trim(value); + } + ctrl.$setViewValue(value, ev && ev.type); + } + }; + + element.on('change', listener); + + ctrl.$render = function() { + var value = attr.value; + if (doTrim) { + value = trim(value); + } + element[0].checked = (value === ctrl.$viewValue); + }; + + attr.$observe('value', ctrl.$render); +} + +function parseConstantExpr($parse, context, name, expression, fallback) { + var parseFn; + if (isDefined(expression)) { + parseFn = $parse(expression); + if (!parseFn.constant) { + throw ngModelMinErr('constexpr', 'Expected constant expression for `{0}`, but saw ' + + '`{1}`.', name, expression); + } + return parseFn(context); + } + return fallback; +} + +function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) { + var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true); + var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false); + + var listener = function(ev) { + ctrl.$setViewValue(element[0].checked, ev && ev.type); + }; + + element.on('change', listener); + + ctrl.$render = function() { + element[0].checked = ctrl.$viewValue; + }; + + // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false` + // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert + // it to a boolean. + ctrl.$isEmpty = function(value) { + return value === false; + }; + + ctrl.$formatters.push(function(value) { + return equals(value, trueValue); + }); + + ctrl.$parsers.push(function(value) { + return value ? trueValue : falseValue; + }); +} + + +/** + * @ngdoc directive + * @name textarea + * @restrict E + * + * @description + * HTML textarea element control with AngularJS data-binding. The data-binding and validation + * properties of this element are exactly the same as those of the + * {@link ng.directive:input input element}. + * + * @param {string} ngModel Assignable AngularJS expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any + * length. + * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} + * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value. + * If the expression evaluates to a RegExp object, then this is used directly. + * If the expression evaluates to a string, then it will be converted to a RegExp + * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to + * `new RegExp('^abc$')`.
      + * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to + * start at the index of the last search's match, thus not taking the whole input value into + * account. + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user + * interaction with the input element. + * @param {boolean=} [ngTrim=true] If set to false AngularJS will not automatically trim the input. + * + * @knownIssue + * + * When specifying the `placeholder` attribute of ` + *
      {{ list | json }}
      + * + * + * it("should split the text by newlines", function() { + * var listInput = element(by.model('list')); + * var output = element(by.binding('list | json')); + * listInput.sendKeys('abc\ndef\nghi'); + * expect(output.getText()).toContain('[\n "abc",\n "def",\n "ghi"\n]'); + * }); + * + * + * + */ +var ngListDirective = function() { + return { + restrict: 'A', + priority: 100, + require: 'ngModel', + link: function(scope, element, attr, ctrl) { + var ngList = attr.ngList || ', '; + var trimValues = attr.ngTrim !== 'false'; + var separator = trimValues ? trim(ngList) : ngList; + + var parse = function(viewValue) { + // If the viewValue is invalid (say required but empty) it will be `undefined` + if (isUndefined(viewValue)) return; + + var list = []; + + if (viewValue) { + forEach(viewValue.split(separator), function(value) { + if (value) list.push(trimValues ? trim(value) : value); + }); + } + + return list; + }; + + ctrl.$parsers.push(parse); + ctrl.$formatters.push(function(value) { + if (isArray(value)) { + return value.join(ngList); + } + + return undefined; + }); + + // Override the standard $isEmpty because an empty array means the input is empty. + ctrl.$isEmpty = function(value) { + return !value || !value.length; + }; + } + }; +}; + +/* global VALID_CLASS: true, + INVALID_CLASS: true, + PRISTINE_CLASS: true, + DIRTY_CLASS: true, + UNTOUCHED_CLASS: true, + TOUCHED_CLASS: true, + PENDING_CLASS: true, + addSetValidityMethod: true, + setupValidity: true, + defaultModelOptions: false +*/ + + +var VALID_CLASS = 'ng-valid', + INVALID_CLASS = 'ng-invalid', + PRISTINE_CLASS = 'ng-pristine', + DIRTY_CLASS = 'ng-dirty', + UNTOUCHED_CLASS = 'ng-untouched', + TOUCHED_CLASS = 'ng-touched', + EMPTY_CLASS = 'ng-empty', + NOT_EMPTY_CLASS = 'ng-not-empty'; + +var ngModelMinErr = minErr('ngModel'); + +/** + * @ngdoc type + * @name ngModel.NgModelController + * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a + * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue + * is set. + * + * @property {*} $modelValue The value in the model that the control is bound to. + * + * @property {Array.} $parsers Array of functions to execute, as a pipeline, whenever + * the control updates the ngModelController with a new {@link ngModel.NgModelController#$viewValue + `$viewValue`} from the DOM, usually via user input. + See {@link ngModel.NgModelController#$setViewValue `$setViewValue()`} for a detailed lifecycle explanation. + Note that the `$parsers` are not called when the bound ngModel expression changes programmatically. + + The functions are called in array order, each passing + its return value through to the next. The last return value is forwarded to the + {@link ngModel.NgModelController#$validators `$validators`} collection. + + Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue + `$viewValue`}. + + Returning `undefined` from a parser means a parse error occurred. In that case, + no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel` + will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`} + is set to `true`. The parse error is stored in `ngModel.$error.parse`. + + This simple example shows a parser that would convert text input value to lowercase: + * ```js + * function parse(value) { + * if (value) { + * return value.toLowerCase(); + * } + * } + * ngModelController.$parsers.push(parse); + * ``` + + * + * @property {Array.} $formatters Array of functions to execute, as a pipeline, whenever + the bound ngModel expression changes programmatically. The `$formatters` are not called when the + value of the control is changed by user interaction. + + Formatters are used to format / convert the {@link ngModel.NgModelController#$modelValue + `$modelValue`} for display in the control. + + The functions are called in reverse array order, each passing the value through to the + next. The last return value is used as the actual DOM value. + + This simple example shows a formatter that would convert the model value to uppercase: + + * ```js + * function format(value) { + * if (value) { + * return value.toUpperCase(); + * } + * } + * ngModel.$formatters.push(format); + * ``` + * + * @property {Object.} $validators A collection of validators that are applied + * whenever the model value changes. The key value within the object refers to the name of the + * validator while the function refers to the validation operation. The validation operation is + * provided with the model value as an argument and must return a true or false value depending + * on the response of that validation. + * + * ```js + * ngModel.$validators.validCharacters = function(modelValue, viewValue) { + * var value = modelValue || viewValue; + * return /[0-9]+/.test(value) && + * /[a-z]+/.test(value) && + * /[A-Z]+/.test(value) && + * /\W+/.test(value); + * }; + * ``` + * + * @property {Object.} $asyncValidators A collection of validations that are expected to + * perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided + * is expected to return a promise when it is run during the model validation process. Once the promise + * is delivered then the validation status will be set to true when fulfilled and false when rejected. + * When the asynchronous validators are triggered, each of the validators will run in parallel and the model + * value will only be updated once all validators have been fulfilled. As long as an asynchronous validator + * is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators + * will only run once all synchronous validators have passed. + * + * Please note that if $http is used then it is important that the server returns a success HTTP response code + * in order to fulfill the validation and a status level of `4xx` in order to reject the validation. + * + * ```js + * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) { + * var value = modelValue || viewValue; + * + * // Lookup user by username + * return $http.get('/api/users/' + value). + * then(function resolved() { + * //username exists, this means validation fails + * return $q.reject('exists'); + * }, function rejected() { + * //username does not exist, therefore this validation passes + * return true; + * }); + * }; + * ``` + * + * @property {Array.} $viewChangeListeners Array of functions to execute whenever + * a change to {@link ngModel.NgModelController#$viewValue `$viewValue`} has caused a change + * to {@link ngModel.NgModelController#$modelValue `$modelValue`}. + * It is called with no arguments, and its return value is ignored. + * This can be used in place of additional $watches against the model value. + * + * @property {Object} $error An object hash with all failing validator ids as keys. + * @property {Object} $pending An object hash with all pending validator ids as keys. + * + * @property {boolean} $untouched True if control has not lost focus yet. + * @property {boolean} $touched True if control has lost focus. + * @property {boolean} $pristine True if user has not interacted with the control yet. + * @property {boolean} $dirty True if user has already interacted with the control. + * @property {boolean} $valid True if there is no error. + * @property {boolean} $invalid True if at least one error on the control. + * @property {string} $name The name attribute of the control. + * + * @description + * + * `NgModelController` provides API for the {@link ngModel `ngModel`} directive. + * The controller contains services for data-binding, validation, CSS updates, and value formatting + * and parsing. It purposefully does not contain any logic which deals with DOM rendering or + * listening to DOM events. + * Such DOM related logic should be provided by other directives which make use of + * `NgModelController` for data-binding to control elements. + * AngularJS provides this DOM logic for most {@link input `input`} elements. + * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example + * custom control example} that uses `ngModelController` to bind to `contenteditable` elements. + * + * @example + * ### Custom Control Example + * This example shows how to use `NgModelController` with a custom control to achieve + * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`) + * collaborate together to achieve the desired result. + * + * `contenteditable` is an HTML5 attribute, which tells the browser to let the element + * contents be edited in place by the user. + * + * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize} + * module to automatically remove "bad" content like inline event listener (e.g. ``). + * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks + * that content using the `$sce` service. + * + * + + [contenteditable] { + border: 1px solid black; + background-color: white; + min-height: 20px; + } + + .ng-invalid { + border: 1px solid red; + } + + + + angular.module('customControl', ['ngSanitize']). + directive('contenteditable', ['$sce', function($sce) { + return { + restrict: 'A', // only activate on element attribute + require: '?ngModel', // get a hold of NgModelController + link: function(scope, element, attrs, ngModel) { + if (!ngModel) return; // do nothing if no ng-model + + // Specify how UI should be updated + ngModel.$render = function() { + element.html($sce.getTrustedHtml(ngModel.$viewValue || '')); + }; + + // Listen for change events to enable binding + element.on('blur keyup change', function() { + scope.$evalAsync(read); + }); + read(); // initialize + + // Write data to the model + function read() { + var html = element.html(); + // When we clear the content editable the browser leaves a
      behind + // If strip-br attribute is provided then we strip this out + if (attrs.stripBr && html === '
      ') { + html = ''; + } + ngModel.$setViewValue(html); + } + } + }; + }]); +
      + +
      +
      Change me!
      + Required! +
      + +
      +
      + + it('should data-bind and become invalid', function() { + if (browser.params.browser === 'safari' || browser.params.browser === 'firefox') { + // SafariDriver can't handle contenteditable + // and Firefox driver can't clear contenteditables very well + return; + } + var contentEditable = element(by.css('[contenteditable]')); + var content = 'Change me!'; + + expect(contentEditable.getText()).toEqual(content); + + contentEditable.clear(); + contentEditable.sendKeys(protractor.Key.BACK_SPACE); + expect(contentEditable.getText()).toEqual(''); + expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/); + }); + + *
      + * + * + */ +NgModelController.$inject = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$q', '$interpolate']; +function NgModelController($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $q, $interpolate) { + this.$viewValue = Number.NaN; + this.$modelValue = Number.NaN; + this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity. + this.$validators = {}; + this.$asyncValidators = {}; + this.$parsers = []; + this.$formatters = []; + this.$viewChangeListeners = []; + this.$untouched = true; + this.$touched = false; + this.$pristine = true; + this.$dirty = false; + this.$valid = true; + this.$invalid = false; + this.$error = {}; // keep invalid keys here + this.$$success = {}; // keep valid keys here + this.$pending = undefined; // keep pending keys here + this.$name = $interpolate($attr.name || '', false)($scope); + this.$$parentForm = nullFormCtrl; + this.$options = defaultModelOptions; + this.$$updateEvents = ''; + // Attach the correct context to the event handler function for updateOn + this.$$updateEventHandler = this.$$updateEventHandler.bind(this); + + this.$$parsedNgModel = $parse($attr.ngModel); + this.$$parsedNgModelAssign = this.$$parsedNgModel.assign; + this.$$ngModelGet = this.$$parsedNgModel; + this.$$ngModelSet = this.$$parsedNgModelAssign; + this.$$pendingDebounce = null; + this.$$parserValid = undefined; + this.$$parserName = 'parse'; + + this.$$currentValidationRunId = 0; + + this.$$scope = $scope; + this.$$rootScope = $scope.$root; + this.$$attr = $attr; + this.$$element = $element; + this.$$animate = $animate; + this.$$timeout = $timeout; + this.$$parse = $parse; + this.$$q = $q; + this.$$exceptionHandler = $exceptionHandler; + + setupValidity(this); + setupModelWatcher(this); +} + +NgModelController.prototype = { + $$initGetterSetters: function() { + if (this.$options.getOption('getterSetter')) { + var invokeModelGetter = this.$$parse(this.$$attr.ngModel + '()'), + invokeModelSetter = this.$$parse(this.$$attr.ngModel + '($$$p)'); + + this.$$ngModelGet = function($scope) { + var modelValue = this.$$parsedNgModel($scope); + if (isFunction(modelValue)) { + modelValue = invokeModelGetter($scope); + } + return modelValue; + }; + this.$$ngModelSet = function($scope, newValue) { + if (isFunction(this.$$parsedNgModel($scope))) { + invokeModelSetter($scope, {$$$p: newValue}); + } else { + this.$$parsedNgModelAssign($scope, newValue); + } + }; + } else if (!this.$$parsedNgModel.assign) { + throw ngModelMinErr('nonassign', 'Expression \'{0}\' is non-assignable. Element: {1}', + this.$$attr.ngModel, startingTag(this.$$element)); + } + }, + + + /** + * @ngdoc method + * @name ngModel.NgModelController#$render + * + * @description + * Called when the view needs to be updated. It is expected that the user of the ng-model + * directive will implement this method. + * + * The `$render()` method is invoked in the following situations: + * + * * `$rollbackViewValue()` is called. If we are rolling back the view value to the last + * committed value then `$render()` is called to update the input control. + * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and + * the `$viewValue` are different from last time. + * + * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of + * `$modelValue` and `$viewValue` are actually different from their previous values. If `$modelValue` + * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be + * invoked if you only change a property on the objects. + */ + $render: noop, + + /** + * @ngdoc method + * @name ngModel.NgModelController#$isEmpty + * + * @description + * This is called when we need to determine if the value of an input is empty. + * + * For instance, the required directive does this to work out if the input has data or not. + * + * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`. + * + * You can override this for input directives whose concept of being empty is different from the + * default. The `checkboxInputType` directive does this because in its case a value of `false` + * implies empty. + * + * @param {*} value The value of the input to check for emptiness. + * @returns {boolean} True if `value` is "empty". + */ + $isEmpty: function(value) { + // eslint-disable-next-line no-self-compare + return isUndefined(value) || value === '' || value === null || value !== value; + }, + + $$updateEmptyClasses: function(value) { + if (this.$isEmpty(value)) { + this.$$animate.removeClass(this.$$element, NOT_EMPTY_CLASS); + this.$$animate.addClass(this.$$element, EMPTY_CLASS); + } else { + this.$$animate.removeClass(this.$$element, EMPTY_CLASS); + this.$$animate.addClass(this.$$element, NOT_EMPTY_CLASS); + } + }, + + /** + * @ngdoc method + * @name ngModel.NgModelController#$setPristine + * + * @description + * Sets the control to its pristine state. + * + * This method can be called to remove the `ng-dirty` class and set the control to its pristine + * state (`ng-pristine` class). A model is considered to be pristine when the control + * has not been changed from when first compiled. + */ + $setPristine: function() { + this.$dirty = false; + this.$pristine = true; + this.$$animate.removeClass(this.$$element, DIRTY_CLASS); + this.$$animate.addClass(this.$$element, PRISTINE_CLASS); + }, + + /** + * @ngdoc method + * @name ngModel.NgModelController#$setDirty + * + * @description + * Sets the control to its dirty state. + * + * This method can be called to remove the `ng-pristine` class and set the control to its dirty + * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed + * from when first compiled. + */ + $setDirty: function() { + this.$dirty = true; + this.$pristine = false; + this.$$animate.removeClass(this.$$element, PRISTINE_CLASS); + this.$$animate.addClass(this.$$element, DIRTY_CLASS); + this.$$parentForm.$setDirty(); + }, + + /** + * @ngdoc method + * @name ngModel.NgModelController#$setUntouched + * + * @description + * Sets the control to its untouched state. + * + * This method can be called to remove the `ng-touched` class and set the control to its + * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched + * by default, however this function can be used to restore that state if the model has + * already been touched by the user. + */ + $setUntouched: function() { + this.$touched = false; + this.$untouched = true; + this.$$animate.setClass(this.$$element, UNTOUCHED_CLASS, TOUCHED_CLASS); + }, + + /** + * @ngdoc method + * @name ngModel.NgModelController#$setTouched + * + * @description + * Sets the control to its touched state. + * + * This method can be called to remove the `ng-untouched` class and set the control to its + * touched state (`ng-touched` class). A model is considered to be touched when the user has + * first focused the control element and then shifted focus away from the control (blur event). + */ + $setTouched: function() { + this.$touched = true; + this.$untouched = false; + this.$$animate.setClass(this.$$element, TOUCHED_CLASS, UNTOUCHED_CLASS); + }, + + /** + * @ngdoc method + * @name ngModel.NgModelController#$rollbackViewValue + * + * @description + * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`, + * which may be caused by a pending debounced event or because the input is waiting for some + * future event. + * + * If you have an input that uses `ng-model-options` to set up debounced updates or updates that + * depend on special events such as `blur`, there can be a period when the `$viewValue` is out of + * sync with the ngModel's `$modelValue`. + * + * In this case, you can use `$rollbackViewValue()` to manually cancel the debounced / future update + * and reset the input to the last committed view value. + * + * It is also possible that you run into difficulties if you try to update the ngModel's `$modelValue` + * programmatically before these debounced/future events have resolved/occurred, because AngularJS's + * dirty checking mechanism is not able to tell whether the model has actually changed or not. + * + * The `$rollbackViewValue()` method should be called before programmatically changing the model of an + * input which may have such events pending. This is important in order to make sure that the + * input field will be updated with the new model value and any pending operations are cancelled. + * + * @example + * + * + * angular.module('cancel-update-example', []) + * + * .controller('CancelUpdateController', ['$scope', function($scope) { + * $scope.model = {value1: '', value2: ''}; + * + * $scope.setEmpty = function(e, value, rollback) { + * if (e.keyCode === 27) { + * e.preventDefault(); + * if (rollback) { + * $scope.myForm[value].$rollbackViewValue(); + * } + * $scope.model[value] = ''; + * } + * }; + * }]); + * + * + *
      + *

      Both of these inputs are only updated if they are blurred. Hitting escape should + * empty them. Follow these steps and observe the difference:

      + *
        + *
      1. Type something in the input. You will see that the model is not yet updated
      2. + *
      3. Press the Escape key. + *
          + *
        1. In the first example, nothing happens, because the model is already '', and no + * update is detected. If you blur the input, the model will be set to the current view. + *
        2. + *
        3. In the second example, the pending update is cancelled, and the input is set back + * to the last committed view value (''). Blurring the input does nothing. + *
        4. + *
        + *
      4. + *
      + * + *
      + *
      + *

      Without $rollbackViewValue():

      + * + * value1: "{{ model.value1 }}" + *
      + * + *
      + *

      With $rollbackViewValue():

      + * + * value2: "{{ model.value2 }}" + *
      + *
      + *
      + *
      + + div { + display: table-cell; + } + div:nth-child(1) { + padding-right: 30px; + } + + + *
      + */ + $rollbackViewValue: function() { + this.$$timeout.cancel(this.$$pendingDebounce); + this.$viewValue = this.$$lastCommittedViewValue; + this.$render(); + }, + + /** + * @ngdoc method + * @name ngModel.NgModelController#$validate + * + * @description + * Runs each of the registered validators (first synchronous validators and then + * asynchronous validators). + * If the validity changes to invalid, the model will be set to `undefined`, + * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`. + * If the validity changes to valid, it will set the model to the last available valid + * `$modelValue`, i.e. either the last parsed value or the last value set from the scope. + */ + $validate: function() { + + // ignore $validate before model is initialized + if (isNumberNaN(this.$modelValue)) { + return; + } + + var viewValue = this.$$lastCommittedViewValue; + // Note: we use the $$rawModelValue as $modelValue might have been + // set to undefined during a view -> model update that found validation + // errors. We can't parse the view here, since that could change + // the model although neither viewValue nor the model on the scope changed + var modelValue = this.$$rawModelValue; + + var prevValid = this.$valid; + var prevModelValue = this.$modelValue; + + var allowInvalid = this.$options.getOption('allowInvalid'); + + var that = this; + this.$$runValidators(modelValue, viewValue, function(allValid) { + // If there was no change in validity, don't update the model + // This prevents changing an invalid modelValue to undefined + if (!allowInvalid && prevValid !== allValid) { + // Note: Don't check this.$valid here, as we could have + // external validators (e.g. calculated on the server), + // that just call $setValidity and need the model value + // to calculate their validity. + that.$modelValue = allValid ? modelValue : undefined; + + if (that.$modelValue !== prevModelValue) { + that.$$writeModelToScope(); + } + } + }); + }, + + $$runValidators: function(modelValue, viewValue, doneCallback) { + this.$$currentValidationRunId++; + var localValidationRunId = this.$$currentValidationRunId; + var that = this; + + // check parser error + if (!processParseErrors()) { + validationDone(false); + return; + } + if (!processSyncValidators()) { + validationDone(false); + return; + } + processAsyncValidators(); + + function processParseErrors() { + var errorKey = that.$$parserName; + + if (isUndefined(that.$$parserValid)) { + setValidity(errorKey, null); + } else { + if (!that.$$parserValid) { + forEach(that.$validators, function(v, name) { + setValidity(name, null); + }); + forEach(that.$asyncValidators, function(v, name) { + setValidity(name, null); + }); + } + + // Set the parse error last, to prevent unsetting it, should a $validators key == parserName + setValidity(errorKey, that.$$parserValid); + return that.$$parserValid; + } + return true; + } + + function processSyncValidators() { + var syncValidatorsValid = true; + forEach(that.$validators, function(validator, name) { + var result = Boolean(validator(modelValue, viewValue)); + syncValidatorsValid = syncValidatorsValid && result; + setValidity(name, result); + }); + if (!syncValidatorsValid) { + forEach(that.$asyncValidators, function(v, name) { + setValidity(name, null); + }); + return false; + } + return true; + } + + function processAsyncValidators() { + var validatorPromises = []; + var allValid = true; + forEach(that.$asyncValidators, function(validator, name) { + var promise = validator(modelValue, viewValue); + if (!isPromiseLike(promise)) { + throw ngModelMinErr('nopromise', + 'Expected asynchronous validator to return a promise but got \'{0}\' instead.', promise); + } + setValidity(name, undefined); + validatorPromises.push(promise.then(function() { + setValidity(name, true); + }, function() { + allValid = false; + setValidity(name, false); + })); + }); + if (!validatorPromises.length) { + validationDone(true); + } else { + that.$$q.all(validatorPromises).then(function() { + validationDone(allValid); + }, noop); + } + } + + function setValidity(name, isValid) { + if (localValidationRunId === that.$$currentValidationRunId) { + that.$setValidity(name, isValid); + } + } + + function validationDone(allValid) { + if (localValidationRunId === that.$$currentValidationRunId) { + + doneCallback(allValid); + } + } + }, + + /** + * @ngdoc method + * @name ngModel.NgModelController#$commitViewValue + * + * @description + * Commit a pending update to the `$modelValue`. + * + * Updates may be pending by a debounced event or because the input is waiting for a some future + * event defined in `ng-model-options`. this method is rarely needed as `NgModelController` + * usually handles calling this in response to input events. + */ + $commitViewValue: function() { + var viewValue = this.$viewValue; + + this.$$timeout.cancel(this.$$pendingDebounce); + + // If the view value has not changed then we should just exit, except in the case where there is + // a native validator on the element. In this case the validation state may have changed even though + // the viewValue has stayed empty. + if (this.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !this.$$hasNativeValidators)) { + return; + } + this.$$updateEmptyClasses(viewValue); + this.$$lastCommittedViewValue = viewValue; + + // change to dirty + if (this.$pristine) { + this.$setDirty(); + } + this.$$parseAndValidate(); + }, + + $$parseAndValidate: function() { + var viewValue = this.$$lastCommittedViewValue; + var modelValue = viewValue; + var that = this; + + this.$$parserValid = isUndefined(modelValue) ? undefined : true; + + // Reset any previous parse error + this.$setValidity(this.$$parserName, null); + this.$$parserName = 'parse'; + + if (this.$$parserValid) { + for (var i = 0; i < this.$parsers.length; i++) { + modelValue = this.$parsers[i](modelValue); + if (isUndefined(modelValue)) { + this.$$parserValid = false; + break; + } + } + } + if (isNumberNaN(this.$modelValue)) { + // this.$modelValue has not been touched yet... + this.$modelValue = this.$$ngModelGet(this.$$scope); + } + var prevModelValue = this.$modelValue; + var allowInvalid = this.$options.getOption('allowInvalid'); + this.$$rawModelValue = modelValue; + + if (allowInvalid) { + this.$modelValue = modelValue; + writeToModelIfNeeded(); + } + + // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date. + // This can happen if e.g. $setViewValue is called from inside a parser + this.$$runValidators(modelValue, this.$$lastCommittedViewValue, function(allValid) { + if (!allowInvalid) { + // Note: Don't check this.$valid here, as we could have + // external validators (e.g. calculated on the server), + // that just call $setValidity and need the model value + // to calculate their validity. + that.$modelValue = allValid ? modelValue : undefined; + writeToModelIfNeeded(); + } + }); + + function writeToModelIfNeeded() { + if (that.$modelValue !== prevModelValue) { + that.$$writeModelToScope(); + } + } + }, + + $$writeModelToScope: function() { + this.$$ngModelSet(this.$$scope, this.$modelValue); + forEach(this.$viewChangeListeners, function(listener) { + try { + listener(); + } catch (e) { + // eslint-disable-next-line no-invalid-this + this.$$exceptionHandler(e); + } + }, this); + }, + + /** + * @ngdoc method + * @name ngModel.NgModelController#$setViewValue + * + * @description + * Update the view value. + * + * This method should be called when a control wants to change the view value; typically, + * this is done from within a DOM event handler. For example, the {@link ng.directive:input input} + * directive calls it when the value of the input changes and {@link ng.directive:select select} + * calls it when an option is selected. + * + * When `$setViewValue` is called, the new `value` will be staged for committing through the `$parsers` + * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged + * value is sent directly for processing through the `$parsers` pipeline. After this, the `$validators` and + * `$asyncValidators` are called and the value is applied to `$modelValue`. + * Finally, the value is set to the **expression** specified in the `ng-model` attribute and + * all the registered change listeners, in the `$viewChangeListeners` list are called. + * + * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn` + * and the `default` trigger is not listed, all those actions will remain pending until one of the + * `updateOn` events is triggered on the DOM element. + * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions} + * directive is used with a custom debounce for this particular event. + * Note that a `$digest` is only triggered once the `updateOn` events are fired, or if `debounce` + * is specified, once the timer runs out. + * + * When used with standard inputs, the view value will always be a string (which is in some cases + * parsed into another type, such as a `Date` object for `input[date]`.) + * However, custom controls might also pass objects to this method. In this case, we should make + * a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not + * perform a deep watch of objects, it only looks for a change of identity. If you only change + * the property of the object then ngModel will not realize that the object has changed and + * will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should + * not change properties of the copy once it has been passed to `$setViewValue`. + * Otherwise you may cause the model value on the scope to change incorrectly. + * + *
      + * In any case, the value passed to the method should always reflect the current value + * of the control. For example, if you are calling `$setViewValue` for an input element, + * you should pass the input DOM value. Otherwise, the control and the scope model become + * out of sync. It's also important to note that `$setViewValue` does not call `$render` or change + * the control's DOM value in any way. If we want to change the control's DOM value + * programmatically, we should update the `ngModel` scope expression. Its new value will be + * picked up by the model controller, which will run it through the `$formatters`, `$render` it + * to update the DOM, and finally call `$validate` on it. + *
      + * + * @param {*} value value from the view. + * @param {string} trigger Event that triggered the update. + */ + $setViewValue: function(value, trigger) { + this.$viewValue = value; + if (this.$options.getOption('updateOnDefault')) { + this.$$debounceViewValueCommit(trigger); + } + }, + + $$debounceViewValueCommit: function(trigger) { + var debounceDelay = this.$options.getOption('debounce'); + + if (isNumber(debounceDelay[trigger])) { + debounceDelay = debounceDelay[trigger]; + } else if (isNumber(debounceDelay['default']) && + this.$options.getOption('updateOn').indexOf(trigger) === -1 + ) { + debounceDelay = debounceDelay['default']; + } else if (isNumber(debounceDelay['*'])) { + debounceDelay = debounceDelay['*']; + } + + this.$$timeout.cancel(this.$$pendingDebounce); + var that = this; + if (debounceDelay > 0) { // this fails if debounceDelay is an object + this.$$pendingDebounce = this.$$timeout(function() { + that.$commitViewValue(); + }, debounceDelay); + } else if (this.$$rootScope.$$phase) { + this.$commitViewValue(); + } else { + this.$$scope.$apply(function() { + that.$commitViewValue(); + }); + } + }, + + /** + * @ngdoc method + * + * @name ngModel.NgModelController#$overrideModelOptions + * + * @description + * + * Override the current model options settings programmatically. + * + * The previous `ModelOptions` value will not be modified. Instead, a + * new `ModelOptions` object will inherit from the previous one overriding + * or inheriting settings that are defined in the given parameter. + * + * See {@link ngModelOptions} for information about what options can be specified + * and how model option inheritance works. + * + *
      + * **Note:** this function only affects the options set on the `ngModelController`, + * and not the options on the {@link ngModelOptions} directive from which they might have been + * obtained initially. + *
      + * + *
      + * **Note:** it is not possible to override the `getterSetter` option. + *
      + * + * @param {Object} options a hash of settings to override the previous options + * + */ + $overrideModelOptions: function(options) { + this.$options = this.$options.createChild(options); + this.$$setUpdateOnEvents(); + }, + + /** + * @ngdoc method + * + * @name ngModel.NgModelController#$processModelValue + + * @description + * + * Runs the model -> view pipeline on the current + * {@link ngModel.NgModelController#$modelValue $modelValue}. + * + * The following actions are performed by this method: + * + * - the `$modelValue` is run through the {@link ngModel.NgModelController#$formatters $formatters} + * and the result is set to the {@link ngModel.NgModelController#$viewValue $viewValue} + * - the `ng-empty` or `ng-not-empty` class is set on the element + * - if the `$viewValue` has changed: + * - {@link ngModel.NgModelController#$render $render} is called on the control + * - the {@link ngModel.NgModelController#$validators $validators} are run and + * the validation status is set. + * + * This method is called by ngModel internally when the bound scope value changes. + * Application developers usually do not have to call this function themselves. + * + * This function can be used when the `$viewValue` or the rendered DOM value are not correctly + * formatted and the `$modelValue` must be run through the `$formatters` again. + * + * @example + * Consider a text input with an autocomplete list (for fruit), where the items are + * objects with a name and an id. + * A user enters `ap` and then selects `Apricot` from the list. + * Based on this, the autocomplete widget will call `$setViewValue({name: 'Apricot', id: 443})`, + * but the rendered value will still be `ap`. + * The widget can then call `ctrl.$processModelValue()` to run the model -> view + * pipeline again, which formats the object to the string `Apricot`, + * then updates the `$viewValue`, and finally renders it in the DOM. + * + * + +
      +
      + Search Fruit: + +
      +
      + Model:
      +
      {{selectedFruit | json}}
      +
      +
      +
      + + angular.module('inputExample', []) + .controller('inputController', function($scope) { + $scope.items = [ + {name: 'Apricot', id: 443}, + {name: 'Clementine', id: 972}, + {name: 'Durian', id: 169}, + {name: 'Jackfruit', id: 982}, + {name: 'Strawberry', id: 863} + ]; + }) + .component('basicAutocomplete', { + bindings: { + items: '<', + onSelect: '&' + }, + templateUrl: 'autocomplete.html', + controller: function($element, $scope) { + var that = this; + var ngModel; + + that.$postLink = function() { + ngModel = $element.find('input').controller('ngModel'); + + ngModel.$formatters.push(function(value) { + return (value && value.name) || value; + }); + + ngModel.$parsers.push(function(value) { + var match = value; + for (var i = 0; i < that.items.length; i++) { + if (that.items[i].name === value) { + match = that.items[i]; + break; + } + } + + return match; + }); + }; + + that.selectItem = function(item) { + ngModel.$setViewValue(item); + ngModel.$processModelValue(); + that.onSelect({item: item}); + }; + } + }); + + +
      + +
        +
      • + +
      • +
      +
      +
      + *
      + * + */ + $processModelValue: function() { + var viewValue = this.$$format(); + + if (this.$viewValue !== viewValue) { + this.$$updateEmptyClasses(viewValue); + this.$viewValue = this.$$lastCommittedViewValue = viewValue; + this.$render(); + // It is possible that model and view value have been updated during render + this.$$runValidators(this.$modelValue, this.$viewValue, noop); + } + }, + + /** + * This method is called internally to run the $formatters on the $modelValue + */ + $$format: function() { + var formatters = this.$formatters, + idx = formatters.length; + + var viewValue = this.$modelValue; + while (idx--) { + viewValue = formatters[idx](viewValue); + } + + return viewValue; + }, + + /** + * This method is called internally when the bound scope value changes. + */ + $$setModelValue: function(modelValue) { + this.$modelValue = this.$$rawModelValue = modelValue; + this.$$parserValid = undefined; + this.$processModelValue(); + }, + + $$setUpdateOnEvents: function() { + if (this.$$updateEvents) { + this.$$element.off(this.$$updateEvents, this.$$updateEventHandler); + } + + this.$$updateEvents = this.$options.getOption('updateOn'); + if (this.$$updateEvents) { + this.$$element.on(this.$$updateEvents, this.$$updateEventHandler); + } + }, + + $$updateEventHandler: function(ev) { + this.$$debounceViewValueCommit(ev && ev.type); + } +}; + +function setupModelWatcher(ctrl) { + // model -> value + // Note: we cannot use a normal scope.$watch as we want to detect the following: + // 1. scope value is 'a' + // 2. user enters 'b' + // 3. ng-change kicks in and reverts scope value to 'a' + // -> scope value did not change since the last digest as + // ng-change executes in apply phase + // 4. view should be changed back to 'a' + ctrl.$$scope.$watch(function ngModelWatch(scope) { + var modelValue = ctrl.$$ngModelGet(scope); + + // if scope model value and ngModel value are out of sync + // This cannot be moved to the action function, because it would not catch the + // case where the model is changed in the ngChange function or the model setter + if (modelValue !== ctrl.$modelValue && + // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator + // eslint-disable-next-line no-self-compare + (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue) + ) { + ctrl.$$setModelValue(modelValue); + } + + return modelValue; + }); +} + +/** + * @ngdoc method + * @name ngModel.NgModelController#$setValidity + * + * @description + * Change the validity state, and notify the form. + * + * This method can be called within $parsers/$formatters or a custom validation implementation. + * However, in most cases it should be sufficient to use the `ngModel.$validators` and + * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically. + * + * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned + * to either `$error[validationErrorKey]` or `$pending[validationErrorKey]` + * (for unfulfilled `$asyncValidators`), so that it is available for data-binding. + * The `validationErrorKey` should be in camelCase and will get converted into dash-case + * for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error` + * classes and can be bound to as `{{ someForm.someControl.$error.myError }}`. + * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined), + * or skipped (null). Pending is used for unfulfilled `$asyncValidators`. + * Skipped is used by AngularJS when validators do not run because of parse errors and + * when `$asyncValidators` do not run because any of the `$validators` failed. + */ +addSetValidityMethod({ + clazz: NgModelController, + set: function(object, property) { + object[property] = true; + }, + unset: function(object, property) { + delete object[property]; + } +}); + + +/** + * @ngdoc directive + * @name ngModel + * @restrict A + * @priority 1 + * @param {expression} ngModel assignable {@link guide/expression Expression} to bind to. + * + * @description + * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a + * property on the scope using {@link ngModel.NgModelController NgModelController}, + * which is created and exposed by this directive. + * + * `ngModel` is responsible for: + * + * - Binding the view into the model, which other directives such as `input`, `textarea` or `select` + * require. + * - Providing validation behavior (i.e. required, number, email, url). + * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors). + * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`, + * `ng-untouched`, `ng-empty`, `ng-not-empty`) including animations. + * - Registering the control with its parent {@link ng.directive:form form}. + * + * Note: `ngModel` will try to bind to the property given by evaluating the expression on the + * current scope. If the property doesn't already exist on this scope, it will be created + * implicitly and added to the scope. + * + * For best practices on using `ngModel`, see: + * + * - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes) + * + * For basic examples, how to use `ngModel`, see: + * + * - {@link ng.directive:input input} + * - {@link input[text] text} + * - {@link input[checkbox] checkbox} + * - {@link input[radio] radio} + * - {@link input[number] number} + * - {@link input[email] email} + * - {@link input[url] url} + * - {@link input[date] date} + * - {@link input[datetime-local] datetime-local} + * - {@link input[time] time} + * - {@link input[month] month} + * - {@link input[week] week} + * - {@link ng.directive:select select} + * - {@link ng.directive:textarea textarea} + * + * ## Complex Models (objects or collections) + * + * By default, `ngModel` watches the model by reference, not value. This is important to know when + * binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the + * object or collection change, `ngModel` will not be notified and so the input will not be re-rendered. + * + * The model must be assigned an entirely new object or collection before a re-rendering will occur. + * + * Some directives have options that will cause them to use a custom `$watchCollection` on the model expression + * - for example, `ngOptions` will do so when a `track by` clause is included in the comprehension expression or + * if the select is given the `multiple` attribute. + * + * The `$watchCollection()` method only does a shallow comparison, meaning that changing properties deeper than the + * first level of the object (or only changing the properties of an item in the collection if it's an array) will still + * not trigger a re-rendering of the model. + * + * ## CSS classes + * The following CSS classes are added and removed on the associated input/select/textarea element + * depending on the validity of the model. + * + * - `ng-valid`: the model is valid + * - `ng-invalid`: the model is invalid + * - `ng-valid-[key]`: for each valid key added by `$setValidity` + * - `ng-invalid-[key]`: for each invalid key added by `$setValidity` + * - `ng-pristine`: the control hasn't been interacted with yet + * - `ng-dirty`: the control has been interacted with + * - `ng-touched`: the control has been blurred + * - `ng-untouched`: the control hasn't been blurred + * - `ng-pending`: any `$asyncValidators` are unfulfilled + * - `ng-empty`: the view does not contain a value or the value is deemed "empty", as defined + * by the {@link ngModel.NgModelController#$isEmpty} method + * - `ng-not-empty`: the view contains a non-empty value + * + * Keep in mind that ngAnimate can detect each of these classes when added and removed. + * + * @animations + * Animations within models are triggered when any of the associated CSS classes are added and removed + * on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`, + * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself. + * The animations that are triggered within ngModel are similar to how they work in ngClass and + * animations can be hooked into using CSS transitions, keyframes as well as JS animations. + * + * The following example shows a simple way to utilize CSS transitions to style an input element + * that has been rendered as invalid after it has been validated: + * + *
      + * //be sure to include ngAnimate as a module to hook into more
      + * //advanced animations
      + * .my-input {
      + *   transition:0.5s linear all;
      + *   background: white;
      + * }
      + * .my-input.ng-invalid {
      + *   background: red;
      + *   color:white;
      + * }
      + * 
      + * + * @example + * ### Basic Usage + * + + + +

      + Update input to see transitions when valid/invalid. + Integer is a valid value. +

      +
      + +
      +
      + *
      + * + * @example + * ### Binding to a getter/setter + * + * Sometimes it's helpful to bind `ngModel` to a getter/setter function. A getter/setter is a + * function that returns a representation of the model when called with zero arguments, and sets + * the internal state of a model when called with an argument. It's sometimes useful to use this + * for models that have an internal representation that's different from what the model exposes + * to the view. + * + *
      + * **Best Practice:** It's best to keep getters fast because AngularJS is likely to call them more + * frequently than other parts of your code. + *
      + * + * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that + * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to + * a `
      `, which will enable this behavior for all ``s within it. See + * {@link ng.directive:ngModelOptions `ngModelOptions`} for more. + * + * The following example shows how to use `ngModel` with a getter/setter: + * + * @example + * + +
      + + + +
      user.name = 
      +
      +
      + + angular.module('getterSetterExample', []) + .controller('ExampleController', ['$scope', function($scope) { + var _name = 'Brian'; + $scope.user = { + name: function(newName) { + // Note that newName can be undefined for two reasons: + // 1. Because it is called as a getter and thus called with no arguments + // 2. Because the property should actually be set to undefined. This happens e.g. if the + // input is invalid + return arguments.length ? (_name = newName) : _name; + } + }; + }]); + + *
      + */ +var ngModelDirective = ['$rootScope', function($rootScope) { + return { + restrict: 'A', + require: ['ngModel', '^?form', '^?ngModelOptions'], + controller: NgModelController, + // Prelink needs to run before any input directive + // so that we can set the NgModelOptions in NgModelController + // before anyone else uses it. + priority: 1, + compile: function ngModelCompile(element) { + // Setup initial state of the control + element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS); + + return { + pre: function ngModelPreLink(scope, element, attr, ctrls) { + var modelCtrl = ctrls[0], + formCtrl = ctrls[1] || modelCtrl.$$parentForm, + optionsCtrl = ctrls[2]; + + if (optionsCtrl) { + modelCtrl.$options = optionsCtrl.$options; + } + + modelCtrl.$$initGetterSetters(); + + // notify others, especially parent forms + formCtrl.$addControl(modelCtrl); + + attr.$observe('name', function(newValue) { + if (modelCtrl.$name !== newValue) { + modelCtrl.$$parentForm.$$renameControl(modelCtrl, newValue); + } + }); + + scope.$on('$destroy', function() { + modelCtrl.$$parentForm.$removeControl(modelCtrl); + }); + }, + post: function ngModelPostLink(scope, element, attr, ctrls) { + var modelCtrl = ctrls[0]; + modelCtrl.$$setUpdateOnEvents(); + + function setTouched() { + modelCtrl.$setTouched(); + } + + element.on('blur', function() { + if (modelCtrl.$touched) return; + + if ($rootScope.$$phase) { + scope.$evalAsync(setTouched); + } else { + scope.$apply(setTouched); + } + }); + } + }; + } + }; +}]; + +/* exported defaultModelOptions */ +var defaultModelOptions; +var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/; + +/** + * @ngdoc type + * @name ModelOptions + * @description + * A container for the options set by the {@link ngModelOptions} directive + */ +function ModelOptions(options) { + this.$$options = options; +} + +ModelOptions.prototype = { + + /** + * @ngdoc method + * @name ModelOptions#getOption + * @param {string} name the name of the option to retrieve + * @returns {*} the value of the option + * @description + * Returns the value of the given option + */ + getOption: function(name) { + return this.$$options[name]; + }, + + /** + * @ngdoc method + * @name ModelOptions#createChild + * @param {Object} options a hash of options for the new child that will override the parent's options + * @return {ModelOptions} a new `ModelOptions` object initialized with the given options. + */ + createChild: function(options) { + var inheritAll = false; + + // make a shallow copy + options = extend({}, options); + + // Inherit options from the parent if specified by the value `"$inherit"` + forEach(options, /** @this */ function(option, key) { + if (option === '$inherit') { + if (key === '*') { + inheritAll = true; + } else { + options[key] = this.$$options[key]; + // `updateOn` is special so we must also inherit the `updateOnDefault` option + if (key === 'updateOn') { + options.updateOnDefault = this.$$options.updateOnDefault; + } + } + } else { + if (key === 'updateOn') { + // If the `updateOn` property contains the `default` event then we have to remove + // it from the event list and set the `updateOnDefault` flag. + options.updateOnDefault = false; + options[key] = trim(option.replace(DEFAULT_REGEXP, function() { + options.updateOnDefault = true; + return ' '; + })); + } + } + }, this); + + if (inheritAll) { + // We have a property of the form: `"*": "$inherit"` + delete options['*']; + defaults(options, this.$$options); + } + + // Finally add in any missing defaults + defaults(options, defaultModelOptions.$$options); + + return new ModelOptions(options); + } +}; + + +defaultModelOptions = new ModelOptions({ + updateOn: '', + updateOnDefault: true, + debounce: 0, + getterSetter: false, + allowInvalid: false, + timezone: null +}); + + +/** + * @ngdoc directive + * @name ngModelOptions + * @restrict A + * @priority 10 + * + * @description + * This directive allows you to modify the behaviour of {@link ngModel} directives within your + * application. You can specify an `ngModelOptions` directive on any element. All {@link ngModel} + * directives will use the options of their nearest `ngModelOptions` ancestor. + * + * The `ngModelOptions` settings are found by evaluating the value of the attribute directive as + * an AngularJS expression. This expression should evaluate to an object, whose properties contain + * the settings. For example: `
      + *
      + * + *
      + *
      + * ``` + * + * the `input` element will have the following settings + * + * ```js + * { allowInvalid: true, updateOn: 'default', debounce: 0 } + * ``` + * + * Notice that the `debounce` setting was not inherited and used the default value instead. + * + * You can specify that all undefined settings are automatically inherited from an ancestor by + * including a property with key of `"*"` and value of `"$inherit"`. + * + * For example given the following fragment of HTML + * + * + * ```html + *
      + *
      + * + *
      + *
      + * ``` + * + * the `input` element will have the following settings + * + * ```js + * { allowInvalid: true, updateOn: 'default', debounce: 200 } + * ``` + * + * Notice that the `debounce` setting now inherits the value from the outer `
      ` element. + * + * If you are creating a reusable component then you should be careful when using `"*": "$inherit"` + * since you may inadvertently inherit a setting in the future that changes the behavior of your component. + * + * + * ## Triggering and debouncing model updates + * + * The `updateOn` and `debounce` properties allow you to specify a custom list of events that will + * trigger a model update and/or a debouncing delay so that the actual update only takes place when + * a timer expires; this timer will be reset after another change takes place. + * + * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might + * be different from the value in the actual model. This means that if you update the model you + * should also invoke {@link ngModel.NgModelController#$rollbackViewValue} on the relevant input field in + * order to make sure it is synchronized with the model and that any debounced action is canceled. + * + * The easiest way to reference the control's {@link ngModel.NgModelController#$rollbackViewValue} + * method is by making sure the input is placed inside a form that has a `name` attribute. This is + * important because `form` controllers are published to the related scope under the name in their + * `name` attribute. + * + * Any pending changes will take place immediately when an enclosing form is submitted via the + * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit` + * to have access to the updated model. + * + * ### Overriding immediate updates + * + * The following example shows how to override immediate updates. Changes on the inputs within the + * form will update the model only when the control loses focus (blur event). If `escape` key is + * pressed while the input field is focused, the value is reset to the value in the current model. + * + * + * + *
      + *
      + *
      + *
      + *
      + *
      user.name = 
      + *
      + *
      + * + * angular.module('optionsExample', []) + * .controller('ExampleController', ['$scope', function($scope) { + * $scope.user = { name: 'say', data: '' }; + * + * $scope.cancel = function(e) { + * if (e.keyCode === 27) { + * $scope.userForm.userName.$rollbackViewValue(); + * } + * }; + * }]); + * + * + * var model = element(by.binding('user.name')); + * var input = element(by.model('user.name')); + * var other = element(by.model('user.data')); + * + * it('should allow custom events', function() { + * input.sendKeys(' hello'); + * input.click(); + * expect(model.getText()).toEqual('say'); + * other.click(); + * expect(model.getText()).toEqual('say hello'); + * }); + * + * it('should $rollbackViewValue when model changes', function() { + * input.sendKeys(' hello'); + * expect(input.getAttribute('value')).toEqual('say hello'); + * input.sendKeys(protractor.Key.ESCAPE); + * expect(input.getAttribute('value')).toEqual('say'); + * other.click(); + * expect(model.getText()).toEqual('say'); + * }); + * + *
      + * + * ### Debouncing updates + * + * The next example shows how to debounce model changes. Model will be updated only 1 sec after last change. + * If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty. + * + * + * + *
      + *
      + * Name: + * + *
      + *
      + *
      user.name = 
      + *
      + *
      + * + * angular.module('optionsExample', []) + * .controller('ExampleController', ['$scope', function($scope) { + * $scope.user = { name: 'say' }; + * }]); + * + *
      + * + * ### Default events, extra triggers, and catch-all debounce values + * + * This example shows the relationship between "default" update events and + * additional `updateOn` triggers. + * + * `default` events are those that are bound to the control, and when fired, update the `$viewValue` + * via {@link ngModel.NgModelController#$setViewValue $setViewValue}. Every event that is not listed + * in `updateOn` is considered a "default" event, since different control types have different + * default events. + * + * The control in this example updates by "default", "click", and "blur", with different `debounce` + * values. You can see that "click" doesn't have an individual `debounce` value - + * therefore it uses the `*` debounce value. + * + * There is also a button that calls {@link ngModel.NgModelController#$setViewValue $setViewValue} + * directly with a "custom" event. Since "custom" is not defined in the `updateOn` list, + * it is considered a "default" event and will update the + * control if "default" is defined in `updateOn`, and will receive the "default" debounce value. + * Note that this is just to illustrate how custom controls would possibly call `$setViewValue`. + * + * You can change the `updateOn` and `debounce` configuration to test different scenarios. This + * is done with {@link ngModel.NgModelController#$overrideModelOptions $overrideModelOptions}. + * + + + + + + angular.module('optionsExample', []) + .component('modelUpdateDemo', { + templateUrl: 'template.html', + controller: function() { + this.name = 'Chinua'; + + this.options = { + updateOn: 'default blur click', + debounce: { + default: 2000, + blur: 0, + '*': 1000 + } + }; + + this.updateEvents = function() { + var eventList = this.options.updateOn.split(' '); + eventList.push('*'); + var events = {}; + + for (var i = 0; i < eventList.length; i++) { + events[eventList[i]] = this.options.debounce[eventList[i]]; + } + + this.events = events; + }; + + this.updateOptions = function() { + var options = angular.extend(this.options, { + updateOn: Object.keys(this.events).join(' ').replace('*', ''), + debounce: this.events + }); + + this.form.input.$overrideModelOptions(options); + }; + + // Initialize the event form + this.updateEvents(); + } + }); + + +
      + Input: +
      + Model: {{$ctrl.name}} +
      + + +
      +
      + updateOn
      + + + + + + + + + + + +
      OptionDebounce value
      {{key}}
      + +
      + +
      +
      +
      + * + * + * ## Model updates and validation + * + * The default behaviour in `ngModel` is that the model value is set to `undefined` when the + * validation determines that the value is invalid. By setting the `allowInvalid` property to true, + * the model will still be updated even if the value is invalid. + * + * + * ## Connecting to the scope + * + * By setting the `getterSetter` property to true you are telling ngModel that the `ngModel` expression + * on the scope refers to a "getter/setter" function rather than the value itself. + * + * The following example shows how to bind to getter/setters: + * + * + * + *
      + *
      + * + *
      + *
      user.name = 
      + *
      + *
      + * + * angular.module('getterSetterExample', []) + * .controller('ExampleController', ['$scope', function($scope) { + * var _name = 'Brian'; + * $scope.user = { + * name: function(newName) { + * return angular.isDefined(newName) ? (_name = newName) : _name; + * } + * }; + * }]); + * + *
      + * + * + * ## Programmatically changing options + * + * The `ngModelOptions` expression is only evaluated once when the directive is linked; it is not + * watched for changes. However, it is possible to override the options on a single + * {@link ngModel.NgModelController} instance with + * {@link ngModel.NgModelController#$overrideModelOptions `NgModelController#$overrideModelOptions()`}. + * See also the example for + * {@link ngModelOptions#default-events-extra-triggers-and-catch-all-debounce-values + * Default events, extra triggers, and catch-all debounce values}. + * + * + * ## Specifying timezones + * + * You can specify the timezone that date/time input directives expect by providing its name in the + * `timezone` property. + * + * + * ## Formatting the value of `time` and `datetime-local` + * + * With the options `timeSecondsFormat` and `timeStripZeroSeconds` it is possible to adjust the value + * that is displayed in the control. Note that browsers may apply their own formatting + * in the user interface. + * + + + + + + angular.module('timeExample', []) + .component('timeExample', { + templateUrl: 'timeExample.html', + controller: function() { + this.time = new Date(1970, 0, 1, 14, 57, 0); + + this.options = { + timeSecondsFormat: 'ss', + timeStripZeroSeconds: true + }; + + this.optionChange = function() { + this.timeForm.timeFormatted.$overrideModelOptions(this.options); + this.time = new Date(this.time); + }; + } + }); + + +
      + Default: +
      + With options: + +
      + + Options:
      + timeSecondsFormat: + +
      + timeStripZeroSeconds: + +
      +
      + *
      + * + * @param {Object} ngModelOptions options to apply to {@link ngModel} directives on this element and + * and its descendents. + * + * **General options**: + * + * - `updateOn`: string specifying which event should the input be bound to. You can set several + * events using an space delimited list. There is a special event called `default` that + * matches the default events belonging to the control. These are the events that are bound to + * the control, and when fired, update the `$viewValue` via `$setViewValue`. + * + * `ngModelOptions` considers every event that is not listed in `updateOn` a "default" event, + * since different control types use different default events. + * + * See also the section {@link ngModelOptions#triggering-and-debouncing-model-updates + * Triggering and debouncing model updates}. + * + * - `debounce`: integer value which contains the debounce model update value in milliseconds. A + * value of 0 triggers an immediate update. If an object is supplied instead, you can specify a + * custom value for each event. For example: + * ``` + * ng-model-options="{ + * updateOn: 'default blur', + * debounce: { 'default': 500, 'blur': 0 } + * }" + * ``` + * You can use the `*` key to specify a debounce value that applies to all events that are not + * specifically listed. In the following example, `mouseup` would have a debounce delay of 1000: + * ``` + * ng-model-options="{ + * updateOn: 'default blur mouseup', + * debounce: { 'default': 500, 'blur': 0, '*': 1000 } + * }" + * ``` + * - `allowInvalid`: boolean value which indicates that the model can be set with values that did + * not validate correctly instead of the default behavior of setting the model to undefined. + * - `getterSetter`: boolean value which determines whether or not to treat functions bound to + * `ngModel` as getters/setters. + * + * + * **Input-type specific options**: + * + * - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for + * ``, ``, ... . It understands UTC/GMT and the + * continental US time zone abbreviations, but for general use, use a time zone offset, for + * example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian) + * If not specified, the timezone of the browser will be used. + * Note that changing the timezone will have no effect on the current date, and is only applied after + * the next input / model change. + * + * - `timeSecondsFormat`: Defines if the `time` and `datetime-local` types should show seconds and + * milliseconds. The option follows the format string of {@link date date filter}. + * By default, the options is `undefined` which is equal to `'ss.sss'` (seconds and milliseconds). + * The other options are `'ss'` (strips milliseconds), and `''` (empty string), which strips both + * seconds and milliseconds. + * Note that browsers that support `time` and `datetime-local` require the hour and minutes + * part of the time string, and may show the value differently in the user interface. + * {@link ngModelOptions#formatting-the-value-of-time-and-datetime-local- See the example}. + * + * - `timeStripZeroSeconds`: Defines if the `time` and `datetime-local` types should strip the + * seconds and milliseconds from the formatted value if they are zero. This option is applied + * after `timeSecondsFormat`. + * This option can be used to make the formatting consistent over different browsers, as some + * browsers with support for `time` will natively hide the milliseconds and + * seconds if they are zero, but others won't, and browsers that don't implement these input + * types will always show the full string. + * {@link ngModelOptions#formatting-the-value-of-time-and-datetime-local- See the example}. + * + */ +var ngModelOptionsDirective = function() { + NgModelOptionsController.$inject = ['$attrs', '$scope']; + function NgModelOptionsController($attrs, $scope) { + this.$$attrs = $attrs; + this.$$scope = $scope; + } + NgModelOptionsController.prototype = { + $onInit: function() { + var parentOptions = this.parentCtrl ? this.parentCtrl.$options : defaultModelOptions; + var modelOptionsDefinition = this.$$scope.$eval(this.$$attrs.ngModelOptions); + + this.$options = parentOptions.createChild(modelOptionsDefinition); + } + }; + + return { + restrict: 'A', + // ngModelOptions needs to run before ngModel and input directives + priority: 10, + require: {parentCtrl: '?^^ngModelOptions'}, + bindToController: true, + controller: NgModelOptionsController + }; +}; + + +// shallow copy over values from `src` that are not already specified on `dst` +function defaults(dst, src) { + forEach(src, function(value, key) { + if (!isDefined(dst[key])) { + dst[key] = value; + } + }); +} + +/** + * @ngdoc directive + * @name ngNonBindable + * @restrict AC + * @priority 1000 + * @element ANY + * + * @description + * The `ngNonBindable` directive tells AngularJS not to compile or bind the contents of the current + * DOM element, including directives on the element itself that have a lower priority than + * `ngNonBindable`. This is useful if the element contains what appears to be AngularJS directives + * and bindings but which should be ignored by AngularJS. This could be the case if you have a site + * that displays snippets of code, for instance. + * + * @example + * In this example there are two locations where a simple interpolation binding (`{{}}`) is present, + * but the one wrapped in `ngNonBindable` is left alone. + * + + +
      Normal: {{1 + 2}}
      +
      Ignored: {{1 + 2}}
      +
      + + it('should check ng-non-bindable', function() { + expect(element(by.binding('1 + 2')).getText()).toContain('3'); + expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/); + }); + +
      + */ +var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 }); + +/* exported ngOptionsDirective */ + +/* global jqLiteRemove */ + +var ngOptionsMinErr = minErr('ngOptions'); + +/** + * @ngdoc directive + * @name ngOptions + * @restrict A + * + * @description + * + * The `ngOptions` attribute can be used to dynamically generate a list of `` + * DOM element. + * * `disable`: The result of this expression will be used to disable the rendered `