forked from casdoor/casdoor
Compare commits
25 Commits
copilot/im
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8ee37cc90 | ||
|
|
e3d9a69dd0 | ||
|
|
5ce6bac529 | ||
|
|
0621f35665 | ||
|
|
1ac2490419 | ||
|
|
8c50ada494 | ||
|
|
22da90576e | ||
|
|
b00404cb3a | ||
|
|
2ed27f4f0a | ||
|
|
bf538d5260 | ||
|
|
13ee5fd150 | ||
|
|
04cdd5a012 | ||
|
|
7b4873734b | ||
|
|
8d2290944a | ||
|
|
6a2bba1627 | ||
|
|
07554bbbe5 | ||
|
|
a050403ee5 | ||
|
|
118eb0af80 | ||
|
|
c16aebe642 | ||
|
|
3b8e7c9da2 | ||
|
|
4d5de767b0 | ||
|
|
54bf8eae5c | ||
|
|
1731b74fa0 | ||
|
|
6e1e5dd569 | ||
|
|
b183359daf |
@@ -1,5 +1,5 @@
|
||||
<h1 align="center" style="border-bottom: none;">📦⚡️ Casdoor</h1>
|
||||
<h3 align="center">An open-source UI-first Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML, CAS, LDAP, SCIM, WebAuthn, TOTP, MFA and RADIUS</h3>
|
||||
<h3 align="center">An open-source AI-first Identity and Access Management (IAM) /AI MCP gateway and auth server with web UI supporting MCP, A2A, OAuth 2.1, OIDC, SAML, CAS, LDAP, SCIM, WebAuthn, TOTP, MFA, Face ID, Google Workspace, Azure AD</h3>
|
||||
<p align="center">
|
||||
<a href="#badge">
|
||||
<img alt="semantic-release" src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg">
|
||||
|
||||
@@ -185,10 +185,14 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
} else {
|
||||
scope := c.Ctx.Input.Query("scope")
|
||||
nonce := c.Ctx.Input.Query("nonce")
|
||||
token, _ := object.GetTokenByUser(application, user, scope, nonce, c.Ctx.Request.Host)
|
||||
resp = tokenToResponse(token)
|
||||
if !object.IsScopeValid(scope, application) {
|
||||
resp = &Response{Status: "error", Msg: "error: invalid_scope", Data: ""}
|
||||
} else {
|
||||
token, _ := object.GetTokenByUser(application, user, scope, nonce, c.Ctx.Request.Host)
|
||||
resp = tokenToResponse(token)
|
||||
|
||||
resp.Data3 = user.NeedUpdatePassword
|
||||
resp.Data3 = user.NeedUpdatePassword
|
||||
}
|
||||
}
|
||||
} else if form.Type == ResponseTypeDevice {
|
||||
authCache, ok := object.DeviceAuthMap.LoadAndDelete(form.UserCode)
|
||||
@@ -739,7 +743,11 @@ func (c *ApiController) Login() {
|
||||
}
|
||||
} else if provider.Category == "OAuth" || provider.Category == "Web3" {
|
||||
// OAuth
|
||||
idpInfo := object.FromProviderToIdpInfo(c.Ctx, provider)
|
||||
idpInfo, err := object.FromProviderToIdpInfo(c.Ctx, provider)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
idpInfo.CodeVerifier = authForm.CodeVerifier
|
||||
var idProvider idp.IdProvider
|
||||
idProvider, err = idp.GetIdProvider(idpInfo, authForm.RedirectUri)
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s wird von dieser Anwendung nicht unterstützt",
|
||||
"Invalid application or wrong clientSecret": "Ungültige Anwendung oder falsches clientSecret",
|
||||
"Invalid client_id": "Ungültige client_id",
|
||||
"Invalid scope": "Ungültiger Scope",
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Weiterleitungs-URI: %s ist nicht in der Liste erlaubter Weiterleitungs-URIs vorhanden",
|
||||
"Token not found, invalid accessToken": "Token nicht gefunden, ungültiger Zugriffs-Token"
|
||||
},
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||
"Invalid client_id": "Invalid client_id",
|
||||
"Invalid scope": "Invalid scope",
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
|
||||
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
|
||||
},
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
"Grant_type: %s is not supported in this application": "El tipo de subvención: %s no es compatible con esta aplicación",
|
||||
"Invalid application or wrong clientSecret": "Solicitud inválida o clientSecret incorrecto",
|
||||
"Invalid client_id": "Identificador de cliente no válido",
|
||||
"Invalid scope": "Alcance no válido",
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "El URI de redirección: %s no existe en la lista de URI de redirección permitidos",
|
||||
"Token not found, invalid accessToken": "Token no encontrado, accessToken inválido"
|
||||
},
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
"Grant_type: %s is not supported in this application": "Type_de_subvention : %s n'est pas pris en charge dans cette application",
|
||||
"Invalid application or wrong clientSecret": "Application invalide ou clientSecret incorrect",
|
||||
"Invalid client_id": "Identifiant de client invalide",
|
||||
"Invalid scope": "Portée invalide",
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "URI de redirection: %s n'existe pas dans la liste des URI de redirection autorisés",
|
||||
"Token not found, invalid accessToken": "Jeton non trouvé, accessToken invalide"
|
||||
},
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
"Grant_type: %s is not supported in this application": "grant_type:%sはこのアプリケーションでサポートされていません",
|
||||
"Invalid application or wrong clientSecret": "無効なアプリケーションまたは誤ったクライアントシークレットです",
|
||||
"Invalid client_id": "client_idが無効です",
|
||||
"Invalid scope": "スコープが無効です",
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "リダイレクトURI:%sは許可されたリダイレクトURIリストに存在しません",
|
||||
"Token not found, invalid accessToken": "トークンが見つかりません。無効なアクセストークンです"
|
||||
},
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s nie jest obsługiwany w tej aplikacji",
|
||||
"Invalid application or wrong clientSecret": "Nieprawidłowa aplikacja lub błędny clientSecret",
|
||||
"Invalid client_id": "Nieprawidłowy client_id",
|
||||
"Invalid scope": "Nieprawidłowy zakres",
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s nie istnieje na liście dozwolonych Redirect URI",
|
||||
"Token not found, invalid accessToken": "Token nie znaleziony, nieprawidłowy accessToken"
|
||||
},
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s não é suportado neste aplicativo",
|
||||
"Invalid application or wrong clientSecret": "Aplicativo inválido ou clientSecret incorreto",
|
||||
"Invalid client_id": "client_id inválido",
|
||||
"Invalid scope": "Escopo inválido",
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "O URI de redirecionamento: %s não existe na lista de URIs permitidos",
|
||||
"Token not found, invalid accessToken": "Token não encontrado, accessToken inválido"
|
||||
},
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s bu uygulamada desteklenmiyor",
|
||||
"Invalid application or wrong clientSecret": "Geçersiz uygulama veya yanlış clientSecret",
|
||||
"Invalid client_id": "Geçersiz client_id",
|
||||
"Invalid scope": "Geçersiz kapsam",
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s izin verilen Redirect URI listesinde yok",
|
||||
"Token not found, invalid accessToken": "Token bulunamadı, geçersiz accessToken"
|
||||
},
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s не підтримується в цьому додатку",
|
||||
"Invalid application or wrong clientSecret": "Недійсний додаток або неправильний clientSecret",
|
||||
"Invalid client_id": "Недійсний client_id",
|
||||
"Invalid scope": "Недійсний scope",
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s відсутній у списку дозволених",
|
||||
"Token not found, invalid accessToken": "Токен не знайдено, недійсний accessToken"
|
||||
},
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
"Grant_type: %s is not supported in this application": "Loại cấp phép: %s không được hỗ trợ trong ứng dụng này",
|
||||
"Invalid application or wrong clientSecret": "Đơn đăng ký không hợp lệ hoặc sai clientSecret",
|
||||
"Invalid client_id": "Client_id không hợp lệ",
|
||||
"Invalid scope": "Phạm vi không hợp lệ",
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Đường dẫn chuyển hướng URI: %s không tồn tại trong danh sách URI được phép chuyển hướng",
|
||||
"Token not found, invalid accessToken": "Token không tìm thấy, accessToken không hợp lệ"
|
||||
},
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
"Grant_type: %s is not supported in this application": "该应用不支持Grant_type: %s",
|
||||
"Invalid application or wrong clientSecret": "无效应用或错误的clientSecret",
|
||||
"Invalid client_id": "无效的ClientId",
|
||||
"Invalid scope": "无效的scope",
|
||||
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "重定向 URI:%s在许可跳转列表中未找到",
|
||||
"Token not found, invalid accessToken": "未查询到对应token, accessToken无效"
|
||||
},
|
||||
|
||||
@@ -264,27 +264,31 @@ func rsaSignWithRSA256(signContent string, privateKey string) (string, error) {
|
||||
|
||||
// privateKey in database is a string, format it to PEM style
|
||||
func formatPrivateKey(privateKey string) string {
|
||||
// each line length is 64
|
||||
preFmtPrivateKey := ""
|
||||
for i := 0; ; {
|
||||
if i+64 <= len(privateKey) {
|
||||
preFmtPrivateKey = preFmtPrivateKey + privateKey[i:i+64] + "\n"
|
||||
i += 64
|
||||
} else {
|
||||
preFmtPrivateKey = preFmtPrivateKey + privateKey[i:]
|
||||
break
|
||||
// Check if the key is already in PEM format
|
||||
if strings.HasPrefix(privateKey, "-----BEGIN PRIVATE KEY-----") ||
|
||||
strings.HasPrefix(privateKey, "-----BEGIN RSA PRIVATE KEY-----") {
|
||||
// Key is already in PEM format, return as is
|
||||
return privateKey
|
||||
}
|
||||
|
||||
// Remove any whitespace from the key
|
||||
privateKey = strings.ReplaceAll(privateKey, "\n", "")
|
||||
privateKey = strings.ReplaceAll(privateKey, "\r", "")
|
||||
privateKey = strings.ReplaceAll(privateKey, " ", "")
|
||||
|
||||
// Format the key with line breaks every 64 characters using strings.Builder
|
||||
var builder strings.Builder
|
||||
for i := 0; i < len(privateKey); i += 64 {
|
||||
end := i + 64
|
||||
if end > len(privateKey) {
|
||||
end = len(privateKey)
|
||||
}
|
||||
builder.WriteString(privateKey[i:end])
|
||||
if end < len(privateKey) {
|
||||
builder.WriteString("\n")
|
||||
}
|
||||
}
|
||||
privateKey = strings.Trim(preFmtPrivateKey, "\n")
|
||||
|
||||
// add pkcs#8 BEGIN and END
|
||||
PemBegin := "-----BEGIN PRIVATE KEY-----\n"
|
||||
PemEnd := "\n-----END PRIVATE KEY-----"
|
||||
if !strings.HasPrefix(privateKey, PemBegin) {
|
||||
privateKey = PemBegin + privateKey
|
||||
}
|
||||
if !strings.HasSuffix(privateKey, PemEnd) {
|
||||
privateKey = privateKey + PemEnd
|
||||
}
|
||||
return privateKey
|
||||
return "-----BEGIN PRIVATE KEY-----\n" + builder.String() + "\n-----END PRIVATE KEY-----"
|
||||
}
|
||||
|
||||
@@ -67,6 +67,8 @@
|
||||
{"name": "ID", "visible": true, "viewRule": "Public", "modifyRule": "Immutable"},
|
||||
{"name": "Name", "visible": true, "viewRule": "Public", "modifyRule": "Admin"},
|
||||
{"name": "Display name", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "First name", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "Last name", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "Avatar", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "User type", "visible": true, "viewRule": "Public", "modifyRule": "Admin"},
|
||||
{"name": "Password", "visible": true, "viewRule": "Self", "modifyRule": "Self"},
|
||||
@@ -81,6 +83,7 @@
|
||||
{"name": "Title", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "ID card type", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "ID card", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "ID card info", "visible": true, "viewRule": "Self", "modifyRule": "Self"},
|
||||
{"name": "Real name", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
{"name": "ID verification", "visible": true, "viewRule": "Self", "modifyRule": "Self"},
|
||||
{"name": "Homepage", "visible": true, "viewRule": "Public", "modifyRule": "Self"},
|
||||
@@ -101,6 +104,7 @@
|
||||
{"name": "Signup application", "visible": true, "viewRule": "Public", "modifyRule": "Admin"},
|
||||
{"name": "Register type", "visible": true, "viewRule": "Public", "modifyRule": "Admin"},
|
||||
{"name": "Register source", "visible": true, "viewRule": "Public", "modifyRule": "Admin"},
|
||||
{"name": "API key", "visible": true, "viewRule": "Self", "modifyRule": "Self"},
|
||||
{"name": "Roles", "visible": true, "viewRule": "Public", "modifyRule": "Immutable"},
|
||||
{"name": "Permissions", "visible": true, "viewRule": "Public", "modifyRule": "Immutable"},
|
||||
{"name": "Groups", "visible": true, "viewRule": "Public", "modifyRule": "Admin"},
|
||||
@@ -110,9 +114,14 @@
|
||||
{"name": "Is forbidden", "visible": true, "viewRule": "Admin", "modifyRule": "Admin"},
|
||||
{"name": "Is deleted", "visible": true, "viewRule": "Admin", "modifyRule": "Admin"},
|
||||
{"name": "Multi-factor authentication", "visible": true, "viewRule": "Self", "modifyRule": "Self"},
|
||||
{"name": "MFA items", "visible": true, "viewRule": "Self", "modifyRule": "Self"},
|
||||
{"name": "WebAuthn credentials", "visible": true, "viewRule": "Self", "modifyRule": "Self"},
|
||||
{"name": "Last change password time", "visible": true, "viewRule": "Admin", "modifyRule": "Admin"},
|
||||
{"name": "Managed accounts", "visible": true, "viewRule": "Self", "modifyRule": "Self"},
|
||||
{"name": "MFA accounts", "visible": true, "viewRule": "Self", "modifyRule": "Self"}
|
||||
{"name": "Face ID", "visible": true, "viewRule": "Self", "modifyRule": "Self"},
|
||||
{"name": "MFA accounts", "visible": true, "viewRule": "Self", "modifyRule": "Self"},
|
||||
{"name": "Need update password", "visible": true, "viewRule": "Admin", "modifyRule": "Admin"},
|
||||
{"name": "IP whitelist", "visible": true, "viewRule": "Admin", "modifyRule": "Admin"}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -154,6 +154,13 @@ type Application struct {
|
||||
FailedSigninLimit int `json:"failedSigninLimit"`
|
||||
FailedSigninFrozenTime int `json:"failedSigninFrozenTime"`
|
||||
CodeResendTimeout int `json:"codeResendTimeout"`
|
||||
|
||||
// Reverse proxy fields
|
||||
Domain string `xorm:"varchar(100)" json:"domain"`
|
||||
OtherDomains []string `xorm:"varchar(1000)" json:"otherDomains"`
|
||||
UpstreamHost string `xorm:"varchar(100)" json:"upstreamHost"`
|
||||
SslMode string `xorm:"varchar(100)" json:"sslMode"`
|
||||
SslCert string `xorm:"varchar(100)" json:"sslCert"`
|
||||
}
|
||||
|
||||
func GetApplicationCount(owner, field, value string) (int64, error) {
|
||||
|
||||
@@ -53,6 +53,8 @@ func getBuiltInAccountItems() []*AccountItem {
|
||||
{Name: "ID", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
|
||||
{Name: "Name", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "Display name", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "First name", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Last name", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "Avatar", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "User type", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "Password", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
@@ -67,6 +69,7 @@ func getBuiltInAccountItems() []*AccountItem {
|
||||
{Name: "Title", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "ID card type", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "ID card", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "ID card info", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "Real name", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
{Name: "ID verification", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "Homepage", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
|
||||
@@ -87,6 +90,7 @@ func getBuiltInAccountItems() []*AccountItem {
|
||||
{Name: "Signup application", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "Register type", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "Register source", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "API key", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "Roles", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
|
||||
{Name: "Permissions", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
|
||||
{Name: "Groups", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
@@ -96,9 +100,14 @@ func getBuiltInAccountItems() []*AccountItem {
|
||||
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
{Name: "Multi-factor authentication", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "MFA items", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "WebAuthn credentials", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "Last change password time", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
{Name: "Managed accounts", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "Face ID", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "MFA accounts", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "Need update password", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
{Name: "IP whitelist", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,12 @@ func InitFlag() {
|
||||
configPath = *configPathPtr
|
||||
exportData = *exportDataPtr
|
||||
exportFilePath = *exportFilePathPtr
|
||||
|
||||
// Load beego config from the specified config path
|
||||
err := web.LoadAppConfig("ini", configPath)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to load config from %s: %v", configPath, err))
|
||||
}
|
||||
}
|
||||
|
||||
func ShouldExportData() bool {
|
||||
|
||||
@@ -33,6 +33,8 @@ type Payment struct {
|
||||
// Product Info
|
||||
Products []string `xorm:"varchar(1000)" json:"products"`
|
||||
ProductsDisplayName string `xorm:"varchar(1000)" json:"productsDisplayName"`
|
||||
ProductName string `xorm:"varchar(1000)" json:"productName"`
|
||||
ProductDisplayName string `xorm:"varchar(1000)" json:"productDisplayName"`
|
||||
Detail string `xorm:"varchar(255)" json:"detail"`
|
||||
Currency string `xorm:"varchar(100)" json:"currency"`
|
||||
Price float64 `json:"price"`
|
||||
@@ -303,7 +305,7 @@ func NotifyPayment(body []byte, owner string, paymentName string, lang string) (
|
||||
order.Message = "Payment successful"
|
||||
order.UpdateTime = util.GetCurrentTime()
|
||||
} else if payment.State == pp.PaymentStateError {
|
||||
order.State = "PaymentFailed"
|
||||
order.State = "Failed"
|
||||
order.Message = payment.Message
|
||||
order.UpdateTime = util.GetCurrentTime()
|
||||
} else if payment.State == pp.PaymentStateCanceled {
|
||||
|
||||
@@ -564,7 +564,7 @@ func providerChangeTrigger(oldName string, newName string) error {
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func FromProviderToIdpInfo(ctx *context.Context, provider *Provider) *idp.ProviderInfo {
|
||||
func FromProviderToIdpInfo(ctx *context.Context, provider *Provider) (*idp.ProviderInfo, error) {
|
||||
providerInfo := &idp.ProviderInfo{
|
||||
Type: provider.Type,
|
||||
SubType: provider.SubType,
|
||||
@@ -588,9 +588,19 @@ func FromProviderToIdpInfo(ctx *context.Context, provider *Provider) *idp.Provid
|
||||
}
|
||||
} else if provider.Type == "ADFS" || provider.Type == "AzureAD" || provider.Type == "AzureADB2C" || provider.Type == "Casdoor" || provider.Type == "Okta" {
|
||||
providerInfo.HostUrl = provider.Domain
|
||||
} else if provider.Type == "Alipay" && provider.Cert != "" {
|
||||
// For Alipay with certificate mode, load private key from certificate
|
||||
cert, err := GetCert(util.GetId(provider.Owner, provider.Cert))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load certificate for Alipay provider %s: %w", provider.Name, err)
|
||||
}
|
||||
if cert == nil {
|
||||
return nil, fmt.Errorf("certificate not found for Alipay provider %s", provider.Name)
|
||||
}
|
||||
providerInfo.ClientSecret = cert.PrivateKey
|
||||
}
|
||||
|
||||
return providerInfo
|
||||
return providerInfo, nil
|
||||
}
|
||||
|
||||
func GetIdvProviderFromProvider(provider *Provider) idv.IdvProvider {
|
||||
|
||||
@@ -154,6 +154,10 @@ func CheckOAuthLogin(clientId string, responseType string, redirectUri string, s
|
||||
return fmt.Sprintf(i18n.Translate(lang, "token:Redirect URI: %s doesn't exist in the allowed Redirect URI list"), redirectUri), application, nil
|
||||
}
|
||||
|
||||
if !IsScopeValid(scope, application) {
|
||||
return i18n.Translate(lang, "token:Invalid scope"), application, nil
|
||||
}
|
||||
|
||||
// Mask application for /api/get-app-login
|
||||
application.ClientSecret = ""
|
||||
return "", application, nil
|
||||
@@ -486,6 +490,28 @@ func IsGrantTypeValid(method string, grantTypes []string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsScopeValid checks whether all space-separated scopes in the scope string
|
||||
// are defined in the application's Scopes list.
|
||||
// If the application has no defined scopes, every scope is considered valid
|
||||
// (backward-compatible behaviour).
|
||||
func IsScopeValid(scope string, application *Application) bool {
|
||||
if len(application.Scopes) == 0 || scope == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
allowed := make(map[string]bool, len(application.Scopes))
|
||||
for _, s := range application.Scopes {
|
||||
allowed[s.Name] = true
|
||||
}
|
||||
|
||||
for _, s := range strings.Fields(scope) {
|
||||
if !allowed[s] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// createGuestUserToken creates a new guest user and returns a token for them
|
||||
func createGuestUserToken(application *Application, clientSecret string, verifier string) (*Token, *TokenError, error) {
|
||||
// Verify client secret if provided
|
||||
@@ -715,6 +741,13 @@ func GetAuthorizationCodeToken(application *Application, clientSecret string, co
|
||||
// GetPasswordToken
|
||||
// Resource Owner Password Credentials flow
|
||||
func GetPasswordToken(application *Application, username string, password string, scope string, host string) (*Token, *TokenError, error) {
|
||||
if !IsScopeValid(scope, application) {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidScope,
|
||||
ErrorDescription: "the requested scope is invalid or not defined in the application",
|
||||
}, nil
|
||||
}
|
||||
|
||||
user, err := GetUserByFields(application.Organization, username)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -796,6 +829,12 @@ func GetClientCredentialsToken(application *Application, clientSecret string, sc
|
||||
ErrorDescription: "client_secret is invalid",
|
||||
}, nil
|
||||
}
|
||||
if !IsScopeValid(scope, application) {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidScope,
|
||||
ErrorDescription: "the requested scope is invalid or not defined in the application",
|
||||
}, nil
|
||||
}
|
||||
nullUser := &User{
|
||||
Owner: application.Owner,
|
||||
Id: application.GetId(),
|
||||
@@ -835,6 +874,13 @@ func GetClientCredentialsToken(application *Application, clientSecret string, sc
|
||||
// GetImplicitToken
|
||||
// Implicit flow
|
||||
func GetImplicitToken(application *Application, username string, scope string, nonce string, host string) (*Token, *TokenError, error) {
|
||||
if !IsScopeValid(scope, application) {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidScope,
|
||||
ErrorDescription: "the requested scope is invalid or not defined in the application",
|
||||
}, nil
|
||||
}
|
||||
|
||||
user, err := GetUserByFields(application.Organization, username)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
||||
@@ -860,16 +860,16 @@ func UpdateUser(id string, user *User, columns []string, isAdmin bool) (bool, er
|
||||
if len(columns) == 0 {
|
||||
columns = []string{
|
||||
"owner", "display_name", "avatar", "first_name", "last_name",
|
||||
"location", "address", "country_code", "region", "language", "affiliation", "title", "id_card_type", "id_card", "homepage", "bio", "tag", "language", "gender", "birthday", "education", "score", "karma", "ranking", "signup_application",
|
||||
"is_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts", "face_ids", "mfaAccounts",
|
||||
"signin_wrong_times", "last_change_password_time", "last_signin_wrong_time", "groups", "access_key", "access_secret", "mfa_phone_enabled", "mfa_email_enabled", "email_verified",
|
||||
"location", "address", "addresses", "country_code", "region", "language", "affiliation", "title", "id_card_type", "id_card", "homepage", "bio", "tag", "language", "gender", "birthday", "education", "score", "karma", "ranking", "signup_application", "register_type", "register_source",
|
||||
"is_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "mfa_items", "last_change_password_time", "managedAccounts", "face_ids", "mfaAccounts",
|
||||
"signin_wrong_times", "last_signin_wrong_time", "groups", "access_key", "access_secret", "mfa_phone_enabled", "mfa_email_enabled", "email_verified",
|
||||
"github", "google", "qq", "wechat", "facebook", "dingtalk", "weibo", "gitee", "linkedin", "wecom", "lark", "gitlab", "adfs",
|
||||
"baidu", "alipay", "casdoor", "infoflow", "apple", "azuread", "azureadb2c", "slack", "steam", "bilibili", "okta", "douyin", "kwai", "line", "amazon",
|
||||
"auth0", "battlenet", "bitbucket", "box", "cloudfoundry", "dailymotion", "deezer", "digitalocean", "discord", "dropbox",
|
||||
"eveonline", "fitbit", "gitea", "heroku", "influxcloud", "instagram", "intercom", "kakao", "lastfm", "mailru", "meetup",
|
||||
"microsoftonline", "naver", "nextcloud", "onedrive", "oura", "patreon", "paypal", "salesforce", "shopify", "soundcloud",
|
||||
"spotify", "strava", "stripe", "type", "tiktok", "tumblr", "twitch", "twitter", "typetalk", "uber", "vk", "wepay", "xero", "yahoo",
|
||||
"yammer", "yandex", "zoom", "custom", "need_update_password", "ip_whitelist", "mfa_items", "mfa_remember_deadline",
|
||||
"yammer", "yandex", "zoom", "custom", "need_update_password", "ip_whitelist", "mfa_remember_deadline",
|
||||
"cart",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func (pp *DummyPaymentProvider) Pay(r *PayReq) (*PayResp, error) {
|
||||
orderInfo := DummyOrderInfo{
|
||||
Price: r.Price,
|
||||
Currency: r.Currency,
|
||||
ProductDisplayName: r.ProductDisplayName,
|
||||
ProductDisplayName: "",
|
||||
}
|
||||
orderInfoBytes, err := json.Marshal(orderInfo)
|
||||
if err != nil {
|
||||
|
||||
@@ -158,7 +158,7 @@ class AdapterEditPage extends React.Component {
|
||||
<React.Fragment>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Type"), i18next.t("cert:Type - Tooltip"))} :
|
||||
{Setting.getLabel(i18next.t("general:Type"), i18next.t("general:Type - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} disabled={Setting.builtInObject(this.state.adapter)} style={{width: "100%"}} value={this.state.adapter.type} onChange={(value => {
|
||||
|
||||
@@ -505,6 +505,160 @@ class ApplicationEditPage extends React.Component {
|
||||
</React.Fragment>
|
||||
)}
|
||||
{this.state.activeMenuKey === "authentication" && (
|
||||
<React.Fragment>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("application:Cookie expire"), i18next.t("application:Cookie expire - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<InputNumber style={{width: "150px"}} value={this.state.application.cookieExpireInHours || 720} min={1} step={1} precision={0} addonAfter="Hours" onChange={value => {
|
||||
this.updateApplicationField("cookieExpireInHours", value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("ldap:Default group"), i18next.t("ldap:Default group - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21}>
|
||||
<PaginateSelect
|
||||
virtual
|
||||
style={{width: "100%"}}
|
||||
allowClear
|
||||
placeholder={i18next.t("general:Default")}
|
||||
value={this.state.application.defaultGroup || undefined}
|
||||
fetchPage={GroupBackend.getGroups}
|
||||
buildFetchArgs={({page, pageSize, searchText}) => {
|
||||
const field = searchText ? "name" : "";
|
||||
return [this.state.owner, false, page, pageSize, field, searchText, "", ""];
|
||||
}}
|
||||
reloadKey={this.state.owner}
|
||||
optionMapper={(group) => Setting.getOption(
|
||||
<Space>
|
||||
{group.type === "Physical" ? <UsergroupAddOutlined /> : <HolderOutlined />}
|
||||
{group.displayName}
|
||||
</Space>,
|
||||
`${group.owner}/${group.name}`
|
||||
)}
|
||||
filterOption={false}
|
||||
onChange={(value) => {
|
||||
this.updateApplicationField("defaultGroup", value || "");
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Enable signup"), i18next.t("application:Enable signup - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.application.enableSignUp} onChange={checked => {
|
||||
this.updateApplicationField("enableSignUp", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Disable signin"), i18next.t("application:Disable signin - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.application.disableSignin} onChange={checked => {
|
||||
this.updateApplicationField("disableSignin", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Enable exclusive signin"), i18next.t("application:Enable exclusive signin - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.application.enableExclusiveSignin} onChange={checked => {
|
||||
this.updateApplicationField("enableExclusiveSignin", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Signin session"), i18next.t("application:Enable signin session - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.application.enableSigninSession} onChange={checked => {
|
||||
if (!checked) {
|
||||
this.updateApplicationField("enableAutoSignin", false);
|
||||
}
|
||||
|
||||
this.updateApplicationField("enableSigninSession", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Auto signin"), i18next.t("application:Auto signin - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.application.enableAutoSignin} onChange={checked => {
|
||||
if (!this.state.application.enableSigninSession && checked) {
|
||||
Setting.showMessage("error", i18next.t("application:Please enable \"Signin session\" first before enabling \"Auto signin\""));
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateApplicationField("enableAutoSignin", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Enable Email linking"), i18next.t("application:Enable Email linking - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.application.enableLinkWithEmail} onChange={checked => {
|
||||
this.updateApplicationField("enableLinkWithEmail", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("general:Signup URL"), i18next.t("general:Signup URL - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<Input prefix={<LinkOutlined />} value={this.state.application.signupUrl} onChange={e => {
|
||||
this.updateApplicationField("signupUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("general:Signin URL"), i18next.t("general:Signin URL - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<Input prefix={<LinkOutlined />} value={this.state.application.signinUrl} onChange={e => {
|
||||
this.updateApplicationField("signinUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("general:Forget URL"), i18next.t("general:Forget URL - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<Input prefix={<LinkOutlined />} value={this.state.application.forgetUrl} onChange={e => {
|
||||
this.updateApplicationField("forgetUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("general:Affiliation URL"), i18next.t("general:Affiliation URL - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<Input prefix={<LinkOutlined />} value={this.state.application.affiliationUrl} onChange={e => {
|
||||
this.updateApplicationField("affiliationUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
</React.Fragment>
|
||||
)}
|
||||
{this.state.activeMenuKey === "oidc-oauth" && (
|
||||
<React.Fragment>
|
||||
<Row style={{marginTop: "10px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
@@ -657,157 +811,11 @@ class ApplicationEditPage extends React.Component {
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("application:Cookie expire"), i18next.t("application:Cookie expire - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<InputNumber style={{width: "150px"}} value={this.state.application.cookieExpireInHours || 720} min={1} step={1} precision={0} addonAfter="Hours" onChange={value => {
|
||||
this.updateApplicationField("cookieExpireInHours", value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("ldap:Default group"), i18next.t("ldap:Default group - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21}>
|
||||
<PaginateSelect
|
||||
virtual
|
||||
style={{width: "100%"}}
|
||||
allowClear
|
||||
placeholder={i18next.t("general:Default")}
|
||||
value={this.state.application.defaultGroup || undefined}
|
||||
fetchPage={GroupBackend.getGroups}
|
||||
buildFetchArgs={({page, pageSize, searchText}) => {
|
||||
const field = searchText ? "name" : "";
|
||||
return [this.state.owner, false, page, pageSize, field, searchText, "", ""];
|
||||
}}
|
||||
reloadKey={this.state.owner}
|
||||
optionMapper={(group) => Setting.getOption(
|
||||
<Space>
|
||||
{group.type === "Physical" ? <UsergroupAddOutlined /> : <HolderOutlined />}
|
||||
{group.displayName}
|
||||
</Space>,
|
||||
`${group.owner}/${group.name}`
|
||||
)}
|
||||
filterOption={false}
|
||||
onChange={(value) => {
|
||||
this.updateApplicationField("defaultGroup", value || "");
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Enable signup"), i18next.t("application:Enable signup - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.application.enableSignUp} onChange={checked => {
|
||||
this.updateApplicationField("enableSignUp", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Disable signin"), i18next.t("application:Disable signin - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.application.disableSignin} onChange={checked => {
|
||||
this.updateApplicationField("disableSignin", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Enable exclusive signin"), i18next.t("application:Enable exclusive signin - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.application.enableExclusiveSignin} onChange={checked => {
|
||||
this.updateApplicationField("enableExclusiveSignin", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Signin session"), i18next.t("application:Enable signin session - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.application.enableSigninSession} onChange={checked => {
|
||||
if (!checked) {
|
||||
this.updateApplicationField("enableAutoSignin", false);
|
||||
}
|
||||
|
||||
this.updateApplicationField("enableSigninSession", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Auto signin"), i18next.t("application:Auto signin - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.application.enableAutoSignin} onChange={checked => {
|
||||
if (!this.state.application.enableSigninSession && checked) {
|
||||
Setting.showMessage("error", i18next.t("application:Please enable \"Signin session\" first before enabling \"Auto signin\""));
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateApplicationField("enableAutoSignin", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Enable Email linking"), i18next.t("application:Enable Email linking - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.application.enableLinkWithEmail} onChange={checked => {
|
||||
this.updateApplicationField("enableLinkWithEmail", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("general:Signup URL"), i18next.t("general:Signup URL - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<Input prefix={<LinkOutlined />} value={this.state.application.signupUrl} onChange={e => {
|
||||
this.updateApplicationField("signupUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("general:Signin URL"), i18next.t("general:Signin URL - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<Input prefix={<LinkOutlined />} value={this.state.application.signinUrl} onChange={e => {
|
||||
this.updateApplicationField("signinUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("general:Forget URL"), i18next.t("general:Forget URL - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<Input prefix={<LinkOutlined />} value={this.state.application.forgetUrl} onChange={e => {
|
||||
this.updateApplicationField("forgetUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("general:Affiliation URL"), i18next.t("general:Affiliation URL - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<Input prefix={<LinkOutlined />} value={this.state.application.affiliationUrl} onChange={e => {
|
||||
this.updateApplicationField("affiliationUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
</React.Fragment>
|
||||
)}
|
||||
{this.state.activeMenuKey === "saml" && (
|
||||
<React.Fragment>
|
||||
<Row style={{marginTop: "10px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("application:SAML reply URL"), i18next.t("application:Redirect URL (Assertion Consumer Service POST Binding URL) - Tooltip"))} :
|
||||
</Col>
|
||||
@@ -1373,6 +1381,68 @@ class ApplicationEditPage extends React.Component {
|
||||
</Col>
|
||||
</Row>
|
||||
</React.Fragment>
|
||||
)}
|
||||
{this.state.activeMenuKey === "reverse-proxy" && (
|
||||
<React.Fragment>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("provider:Domain"), i18next.t("provider:Domain - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<Input value={this.state.application.domain} placeholder="e.g., blog.example.com" onChange={e => {
|
||||
this.updateApplicationField("domain", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("application:Other domains"), i18next.t("application:Other domains - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<UrlTable
|
||||
title={i18next.t("application:Other domains")}
|
||||
table={this.state.application.otherDomains}
|
||||
onUpdateTable={(value) => {this.updateApplicationField("otherDomains", value);}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("application:Upstream host"), i18next.t("application:Upstream host - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<Input value={this.state.application.upstreamHost} placeholder="e.g., localhost:8080 or 192.168.1.100:3000" onChange={e => {
|
||||
this.updateApplicationField("upstreamHost", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("provider:SSL mode"), i18next.t("provider:SSL mode - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<Select virtual={false} style={{width: "100%"}} value={this.state.application.sslMode} onChange={(value => {this.updateApplicationField("sslMode", value);})}>
|
||||
<Option value="">{i18next.t("general:None")}</Option>
|
||||
<Option value="HTTP">HTTP</Option>
|
||||
<Option value="HTTPS and HTTP">HTTPS and HTTP</Option>
|
||||
<Option value="HTTPS Only">HTTPS Only</Option>
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 3}>
|
||||
{Setting.getLabel(i18next.t("application:SSL cert"), i18next.t("application:SSL cert - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<Select virtual={false} style={{width: "100%"}} value={this.state.application.sslCert} onChange={(value => {this.updateApplicationField("sslCert", value);})}>
|
||||
<Option value="">{i18next.t("general:None")}</Option>
|
||||
{
|
||||
this.state.certs.map((cert, index) => <Option key={index} value={cert.name}>{cert.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
</React.Fragment>
|
||||
)}</>;
|
||||
}
|
||||
|
||||
@@ -1390,7 +1460,7 @@ class ApplicationEditPage extends React.Component {
|
||||
<Layout style={{background: "inherit", height: "100%", overflow: "auto"}}>
|
||||
{
|
||||
this.state.menuMode === "horizontal" || !this.state.menuMode ? (
|
||||
<Header style={{background: "inherit", padding: "0px", position: "sticky", top: 0}}>
|
||||
<Header style={{background: "inherit", padding: "0px", position: "sticky", top: 0, height: 38, minHeight: 38}}>
|
||||
<div className="demo-logo" />
|
||||
<Tabs
|
||||
onChange={(key) => {
|
||||
@@ -1399,12 +1469,16 @@ class ApplicationEditPage extends React.Component {
|
||||
}}
|
||||
type="card"
|
||||
activeKey={this.state.activeMenuKey}
|
||||
tabBarStyle={{marginBottom: 0}}
|
||||
items={[
|
||||
{label: i18next.t("application:Basic"), key: "basic"},
|
||||
{label: i18next.t("application:Authentication"), key: "authentication"},
|
||||
{label: "OIDC/OAuth", key: "oidc-oauth"},
|
||||
{label: "SAML", key: "saml"},
|
||||
{label: i18next.t("application:Providers"), key: "providers"},
|
||||
{label: i18next.t("application:UI Customization"), key: "ui-customization"},
|
||||
{label: i18next.t("application:Security"), key: "security"},
|
||||
{label: i18next.t("application:Reverse Proxy"), key: "reverse-proxy"},
|
||||
]}
|
||||
/>
|
||||
</Header>
|
||||
@@ -1425,9 +1499,12 @@ class ApplicationEditPage extends React.Component {
|
||||
>
|
||||
<Menu.Item key="basic">{i18next.t("application:Basic")}</Menu.Item>
|
||||
<Menu.Item key="authentication">{i18next.t("application:Authentication")}</Menu.Item>
|
||||
<Menu.Item key="oidc-oauth">OIDC/OAuth</Menu.Item>
|
||||
<Menu.Item key="saml">SAML</Menu.Item>
|
||||
<Menu.Item key="providers">{i18next.t("application:Providers")}</Menu.Item>
|
||||
<Menu.Item key="ui-customization">{i18next.t("application:UI Customization")}</Menu.Item>
|
||||
<Menu.Item key="security">{i18next.t("application:Security")}</Menu.Item>
|
||||
<Menu.Item key="reverse-proxy">{i18next.t("application:Reverse Proxy")}</Menu.Item>
|
||||
</Menu>
|
||||
</Sider>) : null
|
||||
}
|
||||
|
||||
@@ -190,19 +190,15 @@ class ApplicationListPage extends BaseListPage {
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("category"),
|
||||
render: (text, record, index) => {
|
||||
const category = text;
|
||||
const tagColor = category === "Agent" ? "green" : "blue";
|
||||
return (
|
||||
<span style={{
|
||||
padding: "4px 8px",
|
||||
borderRadius: "4px",
|
||||
backgroundColor: tagColor,
|
||||
color: "white",
|
||||
fontWeight: "500",
|
||||
}}>
|
||||
{category}
|
||||
</span>
|
||||
);
|
||||
if (!text) {
|
||||
text = "Default";
|
||||
}
|
||||
|
||||
if (text === "Agent") {
|
||||
return Setting.getTag("success", text);
|
||||
} else {
|
||||
return Setting.getTag("default", text);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -133,7 +133,7 @@ class CertEditPage extends React.Component {
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Scope"), i18next.t("cert:Scope - Tooltip"))} :
|
||||
{Setting.getLabel(i18next.t("provider:Scope"), i18next.t("provider:Scope - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: "100%"}} value={this.state.cert.scope} onChange={(value => {
|
||||
@@ -149,7 +149,7 @@ class CertEditPage extends React.Component {
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Type"), i18next.t("cert:Type - Tooltip"))} :
|
||||
{Setting.getLabel(i18next.t("general:Type"), i18next.t("general:Type - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: "100%"}} value={this.state.cert.type} onChange={(value => {
|
||||
|
||||
@@ -93,7 +93,7 @@ class FormEditPage extends React.Component {
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}}>
|
||||
<Col style={{marginTop: "5px"}} span={Setting.isMobile() ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Type"), i18next.t("cert:Type - Tooltip"))} :
|
||||
{Setting.getLabel(i18next.t("general:Type"), i18next.t("general:Type - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<Select
|
||||
|
||||
@@ -148,7 +148,7 @@ class GroupEditPage extends React.Component {
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Type"), i18next.t("cert:Type - Tooltip"))} :
|
||||
{Setting.getLabel(i18next.t("general:Type"), i18next.t("general:Type - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select style={{width: "100%"}}
|
||||
|
||||
@@ -236,6 +236,13 @@ class OrderListPage extends BaseListPage {
|
||||
width: "120px",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("state"),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Tooltip title={record.message || ""}>
|
||||
<span>{text}</span>
|
||||
</Tooltip>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Action"),
|
||||
@@ -248,7 +255,7 @@ class OrderListPage extends BaseListPage {
|
||||
return (
|
||||
<div style={{display: "flex", flexWrap: "wrap", gap: "8px"}}>
|
||||
<Button onClick={() => this.props.history.push(`/orders/${record.owner}/${record.name}/pay`)}>
|
||||
{record.state === "Created" ? i18next.t("order:Pay") : i18next.t("general:Detail")}
|
||||
{(record.state === "Created" || record.state === "Failed") ? i18next.t("order:Pay") : i18next.t("general:Detail")}
|
||||
</Button>
|
||||
<Button danger onClick={() => this.cancelOrder(record)} disabled={record.state !== "Created" || !isAdmin}>
|
||||
{i18next.t("general:Cancel")}
|
||||
|
||||
@@ -272,7 +272,7 @@ class OrderPayPage extends React.Component {
|
||||
const updateTimeMap = {
|
||||
Paid: i18next.t("order:Payment time"),
|
||||
Canceled: i18next.t("order:Cancel time"),
|
||||
PaymentFailed: i18next.t("order:Payment failed time"),
|
||||
Failed: i18next.t("order:Payment failed time"),
|
||||
Timeout: i18next.t("order:Timeout time"),
|
||||
};
|
||||
const updateTimeLabel = updateTimeMap[state] || i18next.t("general:Updated time");
|
||||
|
||||
@@ -57,6 +57,8 @@ class OrganizationListPage extends BaseListPage {
|
||||
{name: "ID", visible: true, viewRule: "Public", modifyRule: "Immutable"},
|
||||
{name: "Name", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
||||
{name: "Display name", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||
{name: "First name", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||
{name: "Last name", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||
{name: "Avatar", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||
{name: "User type", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
||||
{name: "Password", visible: true, viewRule: "Self", modifyRule: "Self"},
|
||||
@@ -66,6 +68,7 @@ class OrganizationListPage extends BaseListPage {
|
||||
{name: "Country/Region", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||
{name: "Location", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||
{name: "Address", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||
{name: "Addresses", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||
{name: "Affiliation", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||
{name: "Title", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||
{name: "ID card type", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||
@@ -86,6 +89,8 @@ class OrganizationListPage extends BaseListPage {
|
||||
{name: "Balance", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
||||
{name: "Balance credit", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
||||
{name: "Balance currency", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
||||
{name: "Cart", visible: true, viewRule: "Self", modifyRule: "Self"},
|
||||
{name: "Transactions", visible: true, viewRule: "Self", modifyRule: "Self"},
|
||||
{name: "Signup application", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
||||
{name: "Register type", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
||||
{name: "Register source", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
||||
@@ -99,10 +104,15 @@ class OrganizationListPage extends BaseListPage {
|
||||
{name: "Is admin", visible: true, viewRule: "Admin", modifyRule: "Admin"},
|
||||
{name: "Is forbidden", visible: true, viewRule: "Admin", modifyRule: "Admin"},
|
||||
{name: "Is deleted", visible: true, viewRule: "Admin", modifyRule: "Admin"},
|
||||
{Name: "Multi-factor authentication", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "WebAuthn credentials", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "Managed accounts", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "MFA accounts", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{name: "Multi-factor authentication", visible: true, viewRule: "Self", modifyRule: "Self"},
|
||||
{name: "MFA items", visible: true, viewRule: "Self", modifyRule: "Self"},
|
||||
{name: "WebAuthn credentials", visible: true, viewRule: "Self", modifyRule: "Self"},
|
||||
{name: "Last change password time", visible: true, viewRule: "Admin", modifyRule: "Admin"},
|
||||
{name: "Managed accounts", visible: true, viewRule: "Self", modifyRule: "Self"},
|
||||
{name: "Face ID", visible: true, viewRule: "Self", modifyRule: "Self"},
|
||||
{name: "MFA accounts", visible: true, viewRule: "Self", modifyRule: "Self"},
|
||||
{name: "Need update password", visible: true, viewRule: "Admin", modifyRule: "Admin"},
|
||||
{name: "IP whitelist", visible: true, viewRule: "Admin", modifyRule: "Admin"},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import {InfoCircleTwoTone} from "@ant-design/icons";
|
||||
import * as PaymentBackend from "./backend/PaymentBackend";
|
||||
import * as Setting from "./Setting";
|
||||
import i18next from "i18next";
|
||||
import * as ProductBackend from "./backend/ProductBackend";
|
||||
|
||||
const {Option} = Select;
|
||||
|
||||
@@ -30,7 +29,6 @@ class PaymentEditPage extends React.Component {
|
||||
organizationName: props.organizationName !== undefined ? props.organizationName : props.match.params.organizationName,
|
||||
paymentName: props.match.params.paymentName,
|
||||
payment: null,
|
||||
products: [],
|
||||
isModalVisible: false,
|
||||
isInvoiceLoading: false,
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
@@ -39,7 +37,6 @@ class PaymentEditPage extends React.Component {
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this.getPayment();
|
||||
this.getProducts();
|
||||
}
|
||||
|
||||
getPayment() {
|
||||
@@ -58,19 +55,6 @@ class PaymentEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
getProducts() {
|
||||
ProductBackend.getProducts(this.state.organizationName)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.setState({
|
||||
products: res.data,
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `Failed to get products: ${res.msg}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
goToViewOrder() {
|
||||
const payment = this.state.payment;
|
||||
if (payment && payment.order) {
|
||||
@@ -232,7 +216,7 @@ class PaymentEditPage extends React.Component {
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Type"), i18next.t("cert:Type - Tooltip"))} :
|
||||
{Setting.getLabel(i18next.t("general:Type"), i18next.t("general:Type - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.payment.type} onChange={e => {
|
||||
@@ -240,29 +224,6 @@ class PaymentEditPage extends React.Component {
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Products"), i18next.t("payment:Products - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select
|
||||
mode="multiple"
|
||||
style={{width: "100%"}}
|
||||
value={this.state.payment?.products || []}
|
||||
disabled={isViewMode}
|
||||
allowClear
|
||||
options={(this.state.products || [])
|
||||
.map((p) => ({
|
||||
label: Setting.getLanguageText(p?.displayName) || p?.name,
|
||||
value: p?.name,
|
||||
}))
|
||||
.filter((o) => o.value)}
|
||||
onChange={(value) => {
|
||||
this.updatePaymentField("products", value);
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("order:Price"), i18next.t("plan:Price - Tooltip"))} :
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
import React from "react";
|
||||
import {Link} from "react-router-dom";
|
||||
import {Button, List, Table, Tooltip} from "antd";
|
||||
import {Button, Col, List, Row, Table, Tooltip} from "antd";
|
||||
import moment from "moment";
|
||||
import * as Setting from "./Setting";
|
||||
import * as PaymentBackend from "./backend/PaymentBackend";
|
||||
@@ -195,21 +195,31 @@ class PaymentListPage extends BaseListPage {
|
||||
paddingBottom: 8,
|
||||
}}
|
||||
renderItem={(productInfo, i) => {
|
||||
const price = productInfo.price * (productInfo.quantity || 1);
|
||||
const price = productInfo.price || 0;
|
||||
const number = productInfo.quantity || 1;
|
||||
const currency = record.currency || "USD";
|
||||
const productName = productInfo.displayName || productInfo.name;
|
||||
return (
|
||||
<List.Item>
|
||||
<div style={{display: "inline"}}>
|
||||
<Tooltip placement="topLeft" title={i18next.t("general:Edit")}>
|
||||
<Button style={{marginRight: "5px"}} icon={<EditOutlined />} size="small" onClick={() => Setting.goToLinkSoft(this, `/products/${record.owner}/${productInfo.name}`)} />
|
||||
</Tooltip>
|
||||
<Link to={`/products/${record.owner}/${productInfo.name}`}>
|
||||
{productInfo.displayName || productInfo.name}
|
||||
</Link>
|
||||
<span style={{marginLeft: "8px", color: "#666"}}>
|
||||
{Setting.getPriceDisplay(price, currency)}
|
||||
</span>
|
||||
</div>
|
||||
<Row style={{width: "100%"}} wrap={false} gutter={[12, 0]}>
|
||||
<Col flex="auto" style={{minWidth: 0}}>
|
||||
<div style={{display: "flex", alignItems: "center", minWidth: 0}}>
|
||||
<Tooltip placement="topLeft" title={i18next.t("general:Edit")}>
|
||||
<Button style={{marginRight: "5px"}} icon={<EditOutlined />} size="small" onClick={() => Setting.goToLinkSoft(this, `/products/${record.owner}/${productInfo.name}`)} />
|
||||
</Tooltip>
|
||||
<Tooltip placement="topLeft" title={productName}>
|
||||
<Link to={`/products/${record.owner}/${productInfo.name}`} style={{display: "inline-block", maxWidth: "100%", minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap"}}>
|
||||
{productName}
|
||||
</Link>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Col>
|
||||
<Col flex="none" style={{whiteSpace: "nowrap"}}>
|
||||
<span style={{color: "#666"}}>
|
||||
{Setting.getCurrencySymbol(currency)}{price} ({Setting.getCurrencyText(currency)}) × {number}
|
||||
</span>
|
||||
</Col>
|
||||
</Row>
|
||||
</List.Item>
|
||||
);
|
||||
}}
|
||||
|
||||
@@ -309,7 +309,7 @@ class PermissionEditPage extends React.Component {
|
||||
}
|
||||
const data = res.data.map((role) => Setting.getOption(`${role.owner}/${role.name}`, `${role.owner}/${role.name}`));
|
||||
if (args?.[1] === 1 && Array.isArray(res?.data)) {
|
||||
// res.data = [{owner: i18next.t("organization:All"), name: "*"}, ...res.data];
|
||||
// res.data = [{owner: i18next.t("general:All"), name: "*"}, ...res.data];
|
||||
res.data = [
|
||||
Setting.getOption(i18next.t("general:All"), "*"),
|
||||
...data,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -139,7 +139,7 @@ class ProviderListPage extends BaseListPage {
|
||||
...this.getColumnSearchProps("displayName"),
|
||||
},
|
||||
{
|
||||
title: i18next.t("provider:Category"),
|
||||
title: i18next.t("general:Category"),
|
||||
dataIndex: "category",
|
||||
key: "category",
|
||||
filterMultiple: false,
|
||||
|
||||
@@ -137,7 +137,7 @@ class RecordListPage extends BaseListPage {
|
||||
title: i18next.t("record:Status code"),
|
||||
dataIndex: "statusCode",
|
||||
key: "statusCode",
|
||||
width: "120px",
|
||||
width: "140px",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("statusCode"),
|
||||
},
|
||||
|
||||
@@ -457,8 +457,8 @@ export const UserFields = ["owner", "name", "password", "display_name", "id", "t
|
||||
"is_admin", "homepage", "birthday", "gender", "password_type", "password_salt", "external_id", "avatar", "first_name", "last_name",
|
||||
"avatar_type", "permanent_avatar", "email_verified", "region", "location", "address",
|
||||
"affiliation", "title", "id_card_type", "id_card", "real_name", "is_verified", "bio", "tag", "language",
|
||||
"education", "score", "karma", "ranking", "balance", "currency", "is_default_avatar", "is_online",
|
||||
"is_forbidden", "is_deleted", "signup_application", "hash", "pre_hash", "access_key", "access_secret", "access_token",
|
||||
"education", "score", "karma", "ranking", "balance", "balance_credit", "balance_currency", "currency", "is_default_avatar", "is_online",
|
||||
"is_forbidden", "is_deleted", "signup_application", "register_type", "register_source", "hash", "pre_hash", "access_key", "access_secret", "access_token",
|
||||
"created_ip", "last_signin_time", "last_signin_ip", "github", "google", "qq", "wechat", "facebook", "dingtalk",
|
||||
"weibo", "gitee", "linkedin", "wecom", "lark", "gitlab", "adfs", "baidu", "alipay", "casdoor", "infoflow", "apple",
|
||||
"azuread", "azureadb2c", "slack", "steam", "bilibili", "okta", "douyin", "kwai", "line", "amazon", "auth0",
|
||||
@@ -469,7 +469,7 @@ export const UserFields = ["owner", "name", "password", "display_name", "id", "t
|
||||
"wepay", "xero", "yahoo", "yammer", "yandex", "zoom", "metamask", "web3onboard", "custom", "webauthnCredentials",
|
||||
"preferred_mfa_type", "recovery_codes", "totp_secret", "mfa_phone_enabled", "mfa_email_enabled", "invitation",
|
||||
"invitation_code", "face_ids", "ldap", "properties", "roles", "permissions", "groups", "last_change_password_time",
|
||||
"last_signin_wrong_time", "signin_wrong_times", "managedAccounts", "mfaAccounts", "need_update_password",
|
||||
"last_signin_wrong_time", "signin_wrong_times", "managedAccounts", "mfaAccounts", "mfaItems", "need_update_password",
|
||||
"created_time", "updated_time", "deleted_time",
|
||||
"ip_whitelist"];
|
||||
|
||||
@@ -500,6 +500,7 @@ export const GetTranslatedUserItems = () => {
|
||||
{name: "Country/Region", label: i18next.t("user:Country/Region")},
|
||||
{name: "Location", label: i18next.t("user:Location")},
|
||||
{name: "Address", label: i18next.t("user:Address")},
|
||||
{name: "Addresses", label: i18next.t("user:Addresses")},
|
||||
{name: "Affiliation", label: i18next.t("user:Affiliation")},
|
||||
{name: "Title", label: i18next.t("general:Title")},
|
||||
{name: "ID card type", label: i18next.t("user:ID card type")},
|
||||
@@ -523,6 +524,8 @@ export const GetTranslatedUserItems = () => {
|
||||
{name: "Karma", label: i18next.t("user:Karma")},
|
||||
{name: "Ranking", label: i18next.t("user:Ranking")},
|
||||
{name: "Signup application", label: i18next.t("general:Signup application")},
|
||||
{name: "Register type", label: i18next.t("user:Register type")},
|
||||
{name: "Register source", label: i18next.t("user:Register source")},
|
||||
{name: "API key", label: i18next.t("general:API key")},
|
||||
{name: "Groups", label: i18next.t("general:Groups")},
|
||||
{name: "Roles", label: i18next.t("general:Roles")},
|
||||
@@ -537,6 +540,7 @@ export const GetTranslatedUserItems = () => {
|
||||
{name: "IP whitelist", label: i18next.t("general:IP whitelist")},
|
||||
{name: "Multi-factor authentication", label: i18next.t("mfa:Multi-factor authentication")},
|
||||
{name: "WebAuthn credentials", label: i18next.t("user:WebAuthn credentials")},
|
||||
{name: "Last change password time", label: i18next.t("user:Last change password time")},
|
||||
{name: "Managed accounts", label: i18next.t("user:Managed accounts")},
|
||||
{name: "Face ID", label: i18next.t("login:Face ID")},
|
||||
{name: "MFA accounts", label: i18next.t("user:MFA accounts")},
|
||||
@@ -554,6 +558,8 @@ export function getUserColumns() {
|
||||
transField = "Country/Region";
|
||||
} else if (field === "mfaAccounts") {
|
||||
transField = "MFA accounts";
|
||||
} else if (field === "mfaItems") {
|
||||
transField = "MFA items";
|
||||
} else if (field === "face_ids") {
|
||||
transField = "Face ID";
|
||||
} else if (field === "managedAccounts") {
|
||||
@@ -2267,7 +2273,7 @@ export function getFormTypeItems(formType) {
|
||||
{name: "owner", label: "general:Organization", visible: true, width: "150"},
|
||||
{name: "createdTime", label: "general:Created time", visible: true, width: "180"},
|
||||
{name: "displayName", label: "general:Display name", visible: true, width: "150"},
|
||||
{name: "category", label: "provider:Category", visible: true, width: "110"},
|
||||
{name: "category", label: "general:Category", visible: true, width: "110"},
|
||||
{name: "type", label: "general:Type", visible: true, width: "110"},
|
||||
{name: "clientId", label: "provider:Client ID", visible: true, width: "100"},
|
||||
{name: "providerUrl", label: "provider:Provider URL", visible: true, width: "150"},
|
||||
|
||||
@@ -826,7 +826,7 @@ class SyncerEditPage extends React.Component {
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Type"), i18next.t("cert:Type - Tooltip"))} :
|
||||
{Setting.getLabel(i18next.t("general:Type"), i18next.t("general:Type - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: "100%"}} value={this.state.syncer.type} onChange={(value => {
|
||||
@@ -878,7 +878,7 @@ class SyncerEditPage extends React.Component {
|
||||
this.state.syncer.databaseType !== "postgres" ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("syncer:SSL mode"), i18next.t("syncer:SSL mode - Tooltip"))} :
|
||||
{Setting.getLabel(i18next.t("provider:SSL mode"), i18next.t("provider:SSL mode - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: "100%"}} value={this.state.syncer.sslMode} onChange={(value => {this.updateSyncerField("sslMode", value);})}>
|
||||
|
||||
@@ -158,7 +158,7 @@ class TokenEditPage extends React.Component {
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Scope"), i18next.t("cert:Scope - Tooltip"))}
|
||||
{Setting.getLabel(i18next.t("provider:Scope"), i18next.t("provider:Scope - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.token.scope} onChange={e => {
|
||||
|
||||
@@ -261,7 +261,7 @@ class TransactionEditPage extends React.Component {
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Category"), i18next.t("provider:Category - Tooltip"))} :
|
||||
{Setting.getLabel(i18next.t("general:Category"), i18next.t("general:Category - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.category} />
|
||||
@@ -269,7 +269,7 @@ class TransactionEditPage extends React.Component {
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Type"), i18next.t("cert:Type - Tooltip"))} :
|
||||
{Setting.getLabel(i18next.t("general:Type"), i18next.t("general:Type - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.type} onChange={e => {
|
||||
|
||||
@@ -609,13 +609,20 @@ class UserEditPage extends React.Component {
|
||||
);
|
||||
} else if (accountItem.name === "Addresses") {
|
||||
return (
|
||||
<AddressTable
|
||||
title={i18next.t("user:Addresses")}
|
||||
table={this.state.user.addresses}
|
||||
onUpdateTable={(value) => {
|
||||
this.updateUserField("addresses", value);
|
||||
}}
|
||||
/>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("user:Addresses"), i18next.t("user:Addresses"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<AddressTable
|
||||
title={i18next.t("user:Addresses")}
|
||||
table={this.state.user.addresses}
|
||||
onUpdateTable={(value) => {
|
||||
this.updateUserField("addresses", value);
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
} else if (accountItem.name === "Affiliation") {
|
||||
return (
|
||||
@@ -880,7 +887,7 @@ class UserEditPage extends React.Component {
|
||||
{Setting.getLabel(i18next.t("general:Transactions"), i18next.t("general:Transactions"))} :
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<TransactionTable transactions={this.state.transactions} hideTag={true} />
|
||||
<TransactionTable title={i18next.t("general:Transactions")} transactions={this.state.transactions} hideTag={true} />
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
@@ -1130,15 +1137,21 @@ class UserEditPage extends React.Component {
|
||||
{Setting.getLabel(i18next.t("mfa:Multi-factor authentication"), i18next.t("mfa:Multi-factor authentication - Tooltip "))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Card size="small" title={i18next.t("mfa:Multi-factor methods")}
|
||||
extra={this.state.multiFactorAuths?.some(mfaProps => mfaProps.enabled) ?
|
||||
<PopconfirmModal
|
||||
text={i18next.t("general:Disable")}
|
||||
title={i18next.t("general:Sure to disable") + "?"}
|
||||
onConfirm={() => this.deleteMfa()}
|
||||
/> : null
|
||||
}>
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{i18next.t("mfa:Multi-factor methods")}
|
||||
{this.state.multiFactorAuths?.some(mfaProps => mfaProps.enabled) ?
|
||||
<PopconfirmModal
|
||||
text={i18next.t("general:Disable")}
|
||||
title={i18next.t("general:Sure to disable") + "?"}
|
||||
onConfirm={() => this.deleteMfa()}
|
||||
size="small"
|
||||
/> : null
|
||||
}
|
||||
</div>
|
||||
}>
|
||||
<List
|
||||
size="small"
|
||||
rowKey="mfaType"
|
||||
itemLayout="horizontal"
|
||||
dataSource={this.state.multiFactorAuths}
|
||||
|
||||
@@ -44,20 +44,15 @@ function generateCodeChallenge(verifier) {
|
||||
}
|
||||
|
||||
function storeCodeVerifier(state, verifier) {
|
||||
localStorage.setItem("pkce_verifier", `${state}#${verifier}`);
|
||||
localStorage.setItem(`pkce_verifier_${state}`, verifier);
|
||||
}
|
||||
|
||||
export function getCodeVerifier(state) {
|
||||
const verifierStore = localStorage.getItem("pkce_verifier");
|
||||
const [storedState, verifier] = verifierStore ? verifierStore.split("#") : [null, null];
|
||||
if (storedState !== state) {
|
||||
return null;
|
||||
}
|
||||
return verifier;
|
||||
return localStorage.getItem(`pkce_verifier_${state}`);
|
||||
}
|
||||
|
||||
export function clearCodeVerifier(state) {
|
||||
localStorage.removeItem("pkce_verifier");
|
||||
localStorage.removeItem(`pkce_verifier_${state}`);
|
||||
}
|
||||
|
||||
const authInfo = {
|
||||
@@ -407,24 +402,27 @@ export function getProviderUrl(provider) {
|
||||
}
|
||||
}
|
||||
|
||||
export function getProviderLogoWidget(provider) {
|
||||
export function getProviderLogoWidget(provider, options = {}) {
|
||||
if (provider === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const url = getProviderUrl(provider);
|
||||
if (url !== "") {
|
||||
const disableLink = options.disableLink === true;
|
||||
const imgEl = <img width={36} height={36} src={Setting.getProviderLogoURL(provider)} alt={provider.displayName} />;
|
||||
|
||||
if (url !== "" && !disableLink) {
|
||||
return (
|
||||
<Tooltip title={provider.type}>
|
||||
<a target="_blank" rel="noreferrer" href={getProviderUrl(provider)}>
|
||||
<img width={36} height={36} src={Setting.getProviderLogoURL(provider)} alt={provider.displayName} />
|
||||
{imgEl}
|
||||
</a>
|
||||
</Tooltip>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Tooltip title={provider.type}>
|
||||
<img width={36} height={36} src={Setting.getProviderLogoURL(provider)} alt={provider.displayName} />
|
||||
{imgEl}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -23,24 +23,24 @@ class RegionSelect extends React.Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
value: "",
|
||||
};
|
||||
}
|
||||
|
||||
onChange(e) {
|
||||
this.props.onChange(e);
|
||||
this.setState({value: e});
|
||||
}
|
||||
|
||||
render() {
|
||||
const value = this.props.value !== undefined && this.props.value !== "" ? this.props.value : (this.props.defaultValue !== undefined && this.props.defaultValue !== "" ? this.props.defaultValue : undefined);
|
||||
return (
|
||||
<Select virtual={false}
|
||||
size={this.props.size}
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
style={{width: "100%"}}
|
||||
defaultValue={this.props.defaultValue || undefined}
|
||||
value={value}
|
||||
placeholder="Please select country/region"
|
||||
onChange={(value => {this.onChange(value);})}
|
||||
onChange={(val) => {this.onChange(val);}}
|
||||
filterOption={(input, option) => (option?.label ?? "").toLowerCase().includes(input.toLowerCase())}
|
||||
filterSort={(optionA, optionB) =>
|
||||
(optionA?.label ?? "").toLowerCase().localeCompare((optionB?.label ?? "").toLowerCase())
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"Enable signin session - Tooltip": "Ob Casdoor eine Sitzung aufrechterhält, nachdem man sich von der Anwendung aus bei Casdoor angemeldet hat",
|
||||
"Enable signup": "Registrierung aktivieren",
|
||||
"Enable signup - Tooltip": "Ob Benutzern erlaubt werden soll, ein neues Konto zu registrieren",
|
||||
"Existing Field": "Existing Field",
|
||||
"Failed signin frozen time": "Sperrzeit bei fehlgeschlagenem Login",
|
||||
"Failed signin frozen time - Tooltip": "Zeit, für die das Konto nach fehlgeschlagenen Anmeldeversuchen gesperrt wird",
|
||||
"Failed signin limit": "Limit für fehlgeschlagene Logins",
|
||||
@@ -151,6 +152,7 @@
|
||||
"Signup items - Tooltip": "Elemente für Benutzer, die beim Registrieren neuer Konten ausgefüllt werden müssen - Hinweis",
|
||||
"Single Choice": "Einfachauswahl",
|
||||
"Small icon": "Kleines Symbol",
|
||||
"Static Value": "Static Value",
|
||||
"String": "String",
|
||||
"Tags - Tooltip": "Nur Benutzer mit einem Tag, das in den Anwendungstags aufgeführt ist, können sich anmelden",
|
||||
"The application does not allow to sign up new account": "Die Anwendung erlaubt es nicht, ein neues Konto zu registrieren",
|
||||
@@ -184,9 +186,7 @@
|
||||
"Expire in years - Tooltip": "Gültigkeitsdauer des Zertifikats in Jahren",
|
||||
"New Cert": "Neues Zertifikat",
|
||||
"Private key": "Private-Key",
|
||||
"Private key - Tooltip": "Privater Schlüssel, der zum öffentlichen Schlüsselzertifikat gehört",
|
||||
"Scope - Tooltip": "Nutzungsszenarien des Zertifikats",
|
||||
"Type - Tooltip": "Art des Zertifikats"
|
||||
"Private key - Tooltip": "Privater Schlüssel, der zum öffentlichen Schlüsselzertifikat gehört"
|
||||
},
|
||||
"code": {
|
||||
"Code you received": "Der Code, den Sie erhalten haben",
|
||||
@@ -275,6 +275,7 @@
|
||||
"Applications that require authentication": "Anwendungen, die eine Authentifizierung erfordern",
|
||||
"Apps": "Anwendungen",
|
||||
"Authorization": "Autorisierung",
|
||||
"Auto": "Auto",
|
||||
"Avatar": "Profilbild",
|
||||
"Avatar - Tooltip": "Öffentliches Avatarbild für den Benutzer",
|
||||
"Back": "Zurück",
|
||||
@@ -283,6 +284,8 @@
|
||||
"Cancel": "Abbrechen",
|
||||
"Captcha": "Captcha",
|
||||
"Cart": "Warenkorb",
|
||||
"Category": "Category",
|
||||
"Category - Tooltip": "Category - Tooltip",
|
||||
"Cert": "Zertifikat",
|
||||
"Cert - Tooltip": "Das Public-Key-Zertifikat, das vom Client-SDK, das mit dieser Anwendung korrespondiert, verifiziert werden muss",
|
||||
"Certs": "Zertifikate",
|
||||
@@ -476,6 +479,8 @@
|
||||
"SSH type - Tooltip": "Der Authentifizierungstyp für SSH-Verbindungen",
|
||||
"Save": "Speichern",
|
||||
"Save & Exit": "Speichern und verlassen",
|
||||
"Scopes": "Scopes",
|
||||
"Scopes - Tooltip": "Scopes - Tooltip",
|
||||
"Search": "Suchen",
|
||||
"Send": "Senden",
|
||||
"Session ID": "Session-ID",
|
||||
@@ -530,6 +535,7 @@
|
||||
"Transactions": "Transaktionen",
|
||||
"True": "Wahr",
|
||||
"Type": "Typ",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL-Link",
|
||||
"Unknown application name": "Unbekannter Anwendungsname",
|
||||
@@ -867,6 +873,8 @@
|
||||
},
|
||||
"plan": {
|
||||
"Edit Plan": "Plan bearbeiten",
|
||||
"Is exclusive": "Is exclusive",
|
||||
"Is exclusive - Tooltip": "Is exclusive - Tooltip",
|
||||
"New Plan": "Neuer Plan",
|
||||
"Period": "Zeitraum",
|
||||
"Period - Tooltip": "Zeitraum",
|
||||
@@ -897,6 +905,7 @@
|
||||
"Amount": "Betrag",
|
||||
"Buy": "Kaufen",
|
||||
"Buy Product": "Produkt kaufen",
|
||||
"Cart contains invalid products, please delete them before placing an order": "Cart contains invalid products, please delete them before placing an order",
|
||||
"Custom amount available": "Benutzerdefinierter Betrag verfügbar",
|
||||
"Custom price should be greater than zero": "Benutzerdefinierter Preis muss größer als null sein",
|
||||
"Detail - Tooltip": "Detail des Produkts",
|
||||
@@ -909,9 +918,11 @@
|
||||
"Image": "Bild",
|
||||
"Image - Tooltip": "Bild des Produkts",
|
||||
"Information": "Information",
|
||||
"Invalid product": "Invalid product",
|
||||
"Is recharge": "Ist Aufladung",
|
||||
"Is recharge - Tooltip": "Ob das Produkt zum Aufladen des Guthabens dient",
|
||||
"New Product": "Neues Produkt",
|
||||
"No recharge options available": "No recharge options available",
|
||||
"Order created successfully": "Bestellung erfolgreich erstellt",
|
||||
"PayPal": "PayPal",
|
||||
"Payment cancelled": "Zahlung storniert",
|
||||
@@ -924,10 +935,12 @@
|
||||
"Please select at least one payment provider": "Bitte wählen Sie mindestens einen Zahlungsanbieter aus",
|
||||
"Processing payment...": "Zahlung wird verarbeitet...",
|
||||
"Product list cannot be empty": "Produktliste darf nicht leer sein",
|
||||
"Product not found or invalid": "Product not found or invalid",
|
||||
"Quantity": "Menge",
|
||||
"Quantity - Tooltip": "Menge des Produkts",
|
||||
"Recharge options": "Aufladeoptionen",
|
||||
"Recharge options - Tooltip": "Aufladeoptionen - Tooltip",
|
||||
"Recharge products need to go to the product detail page to set custom amount": "Recharge products need to go to the product detail page to set custom amount",
|
||||
"Return URL": "Rückkeht-URL",
|
||||
"Return URL - Tooltip": "URL für die Rückkehr nach einem erfolgreichen Kauf",
|
||||
"SKU": "SKU",
|
||||
@@ -972,8 +985,6 @@
|
||||
"Can signin": "Kann sich einloggen",
|
||||
"Can signup": "Kann sich registrieren",
|
||||
"Can unlink": "Entlinken möglich",
|
||||
"Category": "Kategorie",
|
||||
"Category - Tooltip": "Kennung zur Kategorisierung und Gruppierung von Elementen oder Inhalten, erleichtert Filterung und Verwaltung",
|
||||
"Channel No.": "Kanal Nr.",
|
||||
"Channel No. - Tooltip": "Eindeutige Nummer zur Identifizierung eines Kommunikations- oder Datenübertragungskanals, verwendet zur Unterscheidung verschiedener Übertragungswege",
|
||||
"Chat ID": "Chat-ID",
|
||||
@@ -990,8 +1001,6 @@
|
||||
"Content - Tooltip": "Spezifische Informationen oder Daten in Nachrichten, Benachrichtigungen oder Dokumenten",
|
||||
"DB test": "DB-Test",
|
||||
"DB test - Tooltip": "DB-Test - Tooltip",
|
||||
"Disable SSL": "SSL deaktivieren",
|
||||
"Disable SSL - Tooltip": "Ob die Deaktivierung des SSL-Protokolls bei der Kommunikation mit dem STMP-Server erfolgen soll",
|
||||
"Domain": "Domäne",
|
||||
"Domain - Tooltip": "Benutzerdefinierte Domain für Objektspeicher",
|
||||
"Edit Provider": "Provider bearbeiten",
|
||||
@@ -1074,9 +1083,12 @@
|
||||
"SP ACS URL": "SP-ACS-URL",
|
||||
"SP ACS URL - Tooltip": "SP ACS URL",
|
||||
"SP Entity ID": "SP-Entitäts-ID",
|
||||
"SSL mode": "SSL mode",
|
||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||
"Scene": "Szene",
|
||||
"Scene - Tooltip": "Spezifisches Geschäftsszenario, in dem die Funktion oder Operation angewendet wird, verwendet zur Anpassung der logischen Verarbeitung für verschiedene Szenarien",
|
||||
"Scope": "Umfang",
|
||||
"Scope - Tooltip": "Scope - Tooltip",
|
||||
"Secret access key": "Secret-Access-Key",
|
||||
"Secret access key - Tooltip": "Privater Schlüssel, der mit dem Zugriffsschlüssel gepaart ist, verwendet zum Signieren sensibler Operationen zur Verbesserung der Zugriffssicherheit",
|
||||
"Secret key": "Secret-Key",
|
||||
@@ -1238,6 +1250,9 @@
|
||||
},
|
||||
"syncer": {
|
||||
"API Token / Password": "API Token / Password",
|
||||
"AWS Access Key ID": "AWS Access Key ID",
|
||||
"AWS Region": "AWS Region",
|
||||
"AWS Secret Access Key": "AWS Secret Access Key",
|
||||
"Admin Email": "Admin-E-Mail",
|
||||
"Affiliation table": "Zuordnungstabelle",
|
||||
"Affiliation table - Tooltip": "Datenbanktabellenname der Arbeitseinheit",
|
||||
@@ -1269,8 +1284,6 @@
|
||||
"SSH password": "SSH-Passwort",
|
||||
"SSH port": "SSH-Port",
|
||||
"SSH user": "SSH-Benutzer",
|
||||
"SSL mode": "SSL-Modus",
|
||||
"SSL mode - Tooltip": "SSL-Modus",
|
||||
"Service account key": "Service-Account-Schlüssel",
|
||||
"Sync interval": "Synchronisierungsintervall",
|
||||
"Sync interval - Tooltip": "Einheit in Sekunden",
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"Enable signin session - Tooltip": "Whether Casdoor maintains a session after logging into Casdoor from the application",
|
||||
"Enable signup": "Enable signup",
|
||||
"Enable signup - Tooltip": "Whether to allow users to register a new account",
|
||||
"Existing Field": "Existing Field",
|
||||
"Failed signin frozen time": "Failed signin frozen time",
|
||||
"Failed signin frozen time - Tooltip": "Waiting time after exceeding the number of failed login attempts. Users can only log in again after the waiting time expires. Default value is 15 minutes. The set value must be a positive integer",
|
||||
"Failed signin limit": "Failed signin limit",
|
||||
@@ -151,6 +152,7 @@
|
||||
"Signup items - Tooltip": "Items for users to fill in when registering new accounts",
|
||||
"Single Choice": "Single Choice",
|
||||
"Small icon": "Small icon",
|
||||
"Static Value": "Static Value",
|
||||
"String": "String",
|
||||
"Tags - Tooltip": "Only users with the tag that is listed in the application tags can login",
|
||||
"The application does not allow to sign up new account": "The application does not allow to sign up new account",
|
||||
@@ -184,9 +186,7 @@
|
||||
"Expire in years - Tooltip": "Validity period of the certificate, in years",
|
||||
"New Cert": "New Cert",
|
||||
"Private key": "Private key",
|
||||
"Private key - Tooltip": "Private key corresponding to the public key certificate",
|
||||
"Scope - Tooltip": "Usage scenarios of the certificate",
|
||||
"Type - Tooltip": "Type of certificate"
|
||||
"Private key - Tooltip": "Private key corresponding to the public key certificate"
|
||||
},
|
||||
"code": {
|
||||
"Code you received": "Code you received",
|
||||
@@ -275,6 +275,7 @@
|
||||
"Applications that require authentication": "Applications that require authentication",
|
||||
"Apps": "Apps",
|
||||
"Authorization": "Authorization",
|
||||
"Auto": "Auto",
|
||||
"Avatar": "Avatar",
|
||||
"Avatar - Tooltip": "Public avatar image for the user",
|
||||
"Back": "Back",
|
||||
@@ -283,6 +284,8 @@
|
||||
"Cancel": "Cancel",
|
||||
"Captcha": "Captcha",
|
||||
"Cart": "Cart",
|
||||
"Category": "Category",
|
||||
"Category - Tooltip": "Category - Tooltip",
|
||||
"Cert": "Cert",
|
||||
"Cert - Tooltip": "The public key certificate that needs to be verified by the client SDK corresponding to this application",
|
||||
"Certs": "Certs",
|
||||
@@ -476,6 +479,8 @@
|
||||
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||
"Save": "Save",
|
||||
"Save & Exit": "Save & Exit",
|
||||
"Scopes": "Scopes",
|
||||
"Scopes - Tooltip": "Scopes - Tooltip",
|
||||
"Search": "Search",
|
||||
"Send": "Send",
|
||||
"Session ID": "Session ID",
|
||||
@@ -530,6 +535,7 @@
|
||||
"Transactions": "Transactions",
|
||||
"True": "True",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL link",
|
||||
"Unknown application name": "Unknown application name",
|
||||
@@ -867,6 +873,8 @@
|
||||
},
|
||||
"plan": {
|
||||
"Edit Plan": "Edit Plan",
|
||||
"Is exclusive": "Is exclusive",
|
||||
"Is exclusive - Tooltip": "Is exclusive - Tooltip",
|
||||
"New Plan": "New Plan",
|
||||
"Period": "Period",
|
||||
"Period - Tooltip": "Period for the plan",
|
||||
@@ -897,6 +905,7 @@
|
||||
"Amount": "Amount",
|
||||
"Buy": "Buy",
|
||||
"Buy Product": "Buy Product",
|
||||
"Cart contains invalid products, please delete them before placing an order": "Cart contains invalid products, please delete them before placing an order",
|
||||
"Custom amount available": "Custom amount available",
|
||||
"Custom price should be greater than zero": "Custom price should be greater than zero",
|
||||
"Detail - Tooltip": "Detail of product",
|
||||
@@ -909,9 +918,11 @@
|
||||
"Image": "Image",
|
||||
"Image - Tooltip": "Image of product",
|
||||
"Information": "Information",
|
||||
"Invalid product": "Invalid product",
|
||||
"Is recharge": "Is recharge",
|
||||
"Is recharge - Tooltip": "Whether the current product is to recharge balance",
|
||||
"New Product": "New Product",
|
||||
"No recharge options available": "No recharge options available",
|
||||
"Order created successfully": "Order created successfully",
|
||||
"PayPal": "PayPal",
|
||||
"Payment cancelled": "Payment cancelled",
|
||||
@@ -924,10 +935,12 @@
|
||||
"Please select at least one payment provider": "Please select at least one payment provider",
|
||||
"Processing payment...": "Processing payment...",
|
||||
"Product list cannot be empty": "Product list cannot be empty",
|
||||
"Product not found or invalid": "Product not found or invalid",
|
||||
"Quantity": "Quantity",
|
||||
"Quantity - Tooltip": "Quantity of product",
|
||||
"Recharge options": "Recharge options",
|
||||
"Recharge options - Tooltip": "Preset recharge amounts",
|
||||
"Recharge products need to go to the product detail page to set custom amount": "Recharge products need to go to the product detail page to set custom amount",
|
||||
"Return URL": "Return URL",
|
||||
"Return URL - Tooltip": "URL to return to after successful purchase",
|
||||
"SKU": "SKU",
|
||||
@@ -972,8 +985,6 @@
|
||||
"Can signin": "Can signin",
|
||||
"Can signup": "Can signup",
|
||||
"Can unlink": "Can unlink",
|
||||
"Category": "Category",
|
||||
"Category - Tooltip": "Identifier for categorizing and grouping items or content, facilitating filtering and management",
|
||||
"Channel No.": "Channel No.",
|
||||
"Channel No. - Tooltip": "Unique number identifying a communication or data transmission channel, used to distinguish different transmission paths",
|
||||
"Chat ID": "Chat ID",
|
||||
@@ -990,8 +1001,6 @@
|
||||
"Content - Tooltip": "Specific information or data contained in messages, notifications, or documents",
|
||||
"DB test": "DB test",
|
||||
"DB test - Tooltip": "DB test - Tooltip",
|
||||
"Disable SSL": "Disable SSL",
|
||||
"Disable SSL - Tooltip": "Whether to disable SSL protocol when communicating with STMP server",
|
||||
"Domain": "Domain",
|
||||
"Domain - Tooltip": "Custom domain for object storage",
|
||||
"Edit Provider": "Edit Provider",
|
||||
@@ -1074,9 +1083,12 @@
|
||||
"SP ACS URL": "SP ACS URL",
|
||||
"SP ACS URL - Tooltip": "SP ACS URL",
|
||||
"SP Entity ID": "SP Entity ID",
|
||||
"SSL mode": "SSL mode",
|
||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||
"Scene": "Scene",
|
||||
"Scene - Tooltip": "Specific business scenario where the function or operation applies, used to adapt logic processing for different scenarios",
|
||||
"Scope": "Scope",
|
||||
"Scope - Tooltip": "Scope - Tooltip",
|
||||
"Secret access key": "Secret access key",
|
||||
"Secret access key - Tooltip": "Private key paired with the access key, used for signing sensitive operations to enhance access security",
|
||||
"Secret key": "Secret key",
|
||||
@@ -1238,6 +1250,9 @@
|
||||
},
|
||||
"syncer": {
|
||||
"API Token / Password": "API Token / Password",
|
||||
"AWS Access Key ID": "AWS Access Key ID",
|
||||
"AWS Region": "AWS Region",
|
||||
"AWS Secret Access Key": "AWS Secret Access Key",
|
||||
"Admin Email": "Admin Email",
|
||||
"Affiliation table": "Affiliation table",
|
||||
"Affiliation table - Tooltip": "Database table name of the work unit",
|
||||
@@ -1269,8 +1284,6 @@
|
||||
"SSH password": "SSH password",
|
||||
"SSH port": "SSH port",
|
||||
"SSH user": "SSH user",
|
||||
"SSL mode": "SSL mode",
|
||||
"SSL mode - Tooltip": "The SSL mode used when connecting to the database",
|
||||
"Service account key": "Service account key",
|
||||
"Sync interval": "Sync interval",
|
||||
"Sync interval - Tooltip": "Unit in seconds",
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"Enable signin session - Tooltip": "Si Casdoor mantiene una sesión después de iniciar sesión en Casdoor desde la aplicación",
|
||||
"Enable signup": "Habilitar registro",
|
||||
"Enable signup - Tooltip": "Ya sea permitir que los usuarios registren una nueva cuenta",
|
||||
"Existing Field": "Existing Field",
|
||||
"Failed signin frozen time": "Tiempo de congelación tras inicio fallido",
|
||||
"Failed signin frozen time - Tooltip": "Tiempo durante el cual la cuenta está congelada después de intentos fallidos de inicio de sesión",
|
||||
"Failed signin limit": "Límite de intentos fallidos de inicio",
|
||||
@@ -134,7 +135,6 @@
|
||||
"SAML metadata": "Metadatos de SAML",
|
||||
"SAML metadata - Tooltip": "Los metadatos del protocolo SAML - Sugerencia",
|
||||
"SAML reply URL": "URL de respuesta SAML",
|
||||
"SAML reply URL - Tooltip": "Personalizar el código HTML del panel lateral de la página de inicio de sesión - Sugerencia",
|
||||
"Security": "Seguridad",
|
||||
"Select": "Seleccionar",
|
||||
"Side panel HTML": "Panel lateral HTML",
|
||||
@@ -152,6 +152,7 @@
|
||||
"Signup items - Tooltip": "Elementos para que los usuarios completen al registrar nuevas cuentas - Sugerencia",
|
||||
"Single Choice": "Opción única",
|
||||
"Small icon": "Icono pequeño",
|
||||
"Static Value": "Static Value",
|
||||
"String": "Cadena",
|
||||
"Tags - Tooltip": "Solo los usuarios con la etiqueta que esté listada en las etiquetas de la aplicación pueden iniciar sesión - Sugerencia",
|
||||
"The application does not allow to sign up new account": "La aplicación no permite registrarse una cuenta nueva",
|
||||
@@ -185,9 +186,7 @@
|
||||
"Expire in years - Tooltip": "Período de validez del certificado, en años",
|
||||
"New Cert": "Nuevo certificado",
|
||||
"Private key": "Clave privada",
|
||||
"Private key - Tooltip": "Clave privada correspondiente al certificado de clave pública",
|
||||
"Scope - Tooltip": "Escenarios de uso del certificado",
|
||||
"Type - Tooltip": "Tipo de certificado"
|
||||
"Private key - Tooltip": "Clave privada correspondiente al certificado de clave pública"
|
||||
},
|
||||
"code": {
|
||||
"Code you received": "Código que recibió",
|
||||
@@ -276,6 +275,7 @@
|
||||
"Applications that require authentication": "Aplicaciones que requieren autenticación",
|
||||
"Apps": "Aplicaciones",
|
||||
"Authorization": "Autorización",
|
||||
"Auto": "Auto",
|
||||
"Avatar": "Avatar",
|
||||
"Avatar - Tooltip": "Imagen de avatar pública para el usuario",
|
||||
"Back": "Atrás",
|
||||
@@ -284,6 +284,8 @@
|
||||
"Cancel": "Cancelar",
|
||||
"Captcha": "Captcha",
|
||||
"Cart": "Carrito",
|
||||
"Category": "Category",
|
||||
"Category - Tooltip": "Category - Tooltip",
|
||||
"Cert": "Certificado",
|
||||
"Cert - Tooltip": "El certificado de clave pública que necesita ser verificado por el SDK del cliente correspondiente a esta aplicación",
|
||||
"Certs": "Certificaciones",
|
||||
@@ -477,6 +479,8 @@
|
||||
"SSH type - Tooltip": "El tipo de autenticación de conexión SSH",
|
||||
"Save": "Guardar",
|
||||
"Save & Exit": "Guardar y salir",
|
||||
"Scopes": "Scopes",
|
||||
"Scopes - Tooltip": "Scopes - Tooltip",
|
||||
"Search": "Buscar",
|
||||
"Send": "Enviar",
|
||||
"Session ID": "ID de sesión",
|
||||
@@ -531,6 +535,7 @@
|
||||
"Transactions": "Transacciones",
|
||||
"True": "Verdadero",
|
||||
"Type": "Tipo",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "Enlace de URL",
|
||||
"Unknown application name": "Nombre de aplicación desconocido",
|
||||
@@ -868,6 +873,8 @@
|
||||
},
|
||||
"plan": {
|
||||
"Edit Plan": "Editar plan",
|
||||
"Is exclusive": "Is exclusive",
|
||||
"Is exclusive - Tooltip": "Is exclusive - Tooltip",
|
||||
"New Plan": "Nuevo plan",
|
||||
"Period": "Período",
|
||||
"Period - Tooltip": "Período",
|
||||
@@ -898,6 +905,7 @@
|
||||
"Amount": "Importe",
|
||||
"Buy": "Comprar",
|
||||
"Buy Product": "Comprar producto",
|
||||
"Cart contains invalid products, please delete them before placing an order": "Cart contains invalid products, please delete them before placing an order",
|
||||
"Custom amount available": "Importe personalizado disponible",
|
||||
"Custom price should be greater than zero": "El precio personalizado debe ser mayor que cero",
|
||||
"Detail - Tooltip": "Detalle del producto",
|
||||
@@ -910,9 +918,11 @@
|
||||
"Image": "Imagen",
|
||||
"Image - Tooltip": "Imagen del producto",
|
||||
"Information": "Información",
|
||||
"Invalid product": "Invalid product",
|
||||
"Is recharge": "Es recarga",
|
||||
"Is recharge - Tooltip": "Indica si el producto actual es para recargar saldo",
|
||||
"New Product": "Nuevo producto",
|
||||
"No recharge options available": "No recharge options available",
|
||||
"Order created successfully": "Pedido creado con éxito",
|
||||
"PayPal": "PayPal",
|
||||
"Payment cancelled": "Pago cancelado",
|
||||
@@ -925,10 +935,12 @@
|
||||
"Please select at least one payment provider": "Por favor, selecciona al menos un proveedor de pago",
|
||||
"Processing payment...": "Procesando el pago...",
|
||||
"Product list cannot be empty": "La lista de productos no puede estar vacía",
|
||||
"Product not found or invalid": "Product not found or invalid",
|
||||
"Quantity": "Cantidad",
|
||||
"Quantity - Tooltip": "Cantidad de producto",
|
||||
"Recharge options": "Opciones de recarga",
|
||||
"Recharge options - Tooltip": "Opciones de recarga - Tooltip",
|
||||
"Recharge products need to go to the product detail page to set custom amount": "Recharge products need to go to the product detail page to set custom amount",
|
||||
"Return URL": "URL de retorno",
|
||||
"Return URL - Tooltip": "URL para regresar después de una compra exitosa",
|
||||
"SKU": "SKU",
|
||||
@@ -973,8 +985,6 @@
|
||||
"Can signin": "¿Puedes iniciar sesión?",
|
||||
"Can signup": "Puede registrarse",
|
||||
"Can unlink": "Desvincular",
|
||||
"Category": "Categoría",
|
||||
"Category - Tooltip": "Identificador para categorizar y agrupar elementos o contenido, facilitando el filtrado y la gestión",
|
||||
"Channel No.": "Canal No.",
|
||||
"Channel No. - Tooltip": "Número único que identifica un canal de comunicación o transmisión de datos, utilizado para distinguir diferentes rutas de transmisión",
|
||||
"Chat ID": "ID de chat",
|
||||
@@ -991,8 +1001,6 @@
|
||||
"Content - Tooltip": "Contenido - Información adicional",
|
||||
"DB test": "Prueba de BD",
|
||||
"DB test - Tooltip": "Prueba de BD - Tooltip",
|
||||
"Disable SSL": "Desactivar SSL",
|
||||
"Disable SSL - Tooltip": "¿Hay que desactivar el protocolo SSL al comunicarse con el servidor STMP?",
|
||||
"Domain": "Dominio",
|
||||
"Domain - Tooltip": "Dominio personalizado para almacenamiento de objetos",
|
||||
"Edit Provider": "Editar proveedor",
|
||||
@@ -1075,9 +1083,12 @@
|
||||
"SP ACS URL": "URL de ACS de SP",
|
||||
"SP ACS URL - Tooltip": "URL del ACS de SP",
|
||||
"SP Entity ID": "ID de entidad SP",
|
||||
"SSL mode": "SSL mode",
|
||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||
"Scene": "Escena",
|
||||
"Scene - Tooltip": "Escena",
|
||||
"Scope": "Alcance",
|
||||
"Scope - Tooltip": "Scope - Tooltip",
|
||||
"Secret access key": "Clave de acceso secreta",
|
||||
"Secret access key - Tooltip": "Clave de acceso secreta",
|
||||
"Secret key": "Clave secreta",
|
||||
@@ -1239,6 +1250,9 @@
|
||||
},
|
||||
"syncer": {
|
||||
"API Token / Password": "Token API / Contraseña",
|
||||
"AWS Access Key ID": "AWS Access Key ID",
|
||||
"AWS Region": "AWS Region",
|
||||
"AWS Secret Access Key": "AWS Secret Access Key",
|
||||
"Admin Email": "Correo del administrador",
|
||||
"Affiliation table": "Tabla de afiliación",
|
||||
"Affiliation table - Tooltip": "Nombre de la tabla de base de datos de la unidad de trabajo",
|
||||
@@ -1270,8 +1284,6 @@
|
||||
"SSH password": "Contraseña SSH",
|
||||
"SSH port": "Puerto SSH",
|
||||
"SSH user": "Usuario SSH",
|
||||
"SSL mode": "Modo SSL",
|
||||
"SSL mode - Tooltip": "Modo SSL",
|
||||
"Service account key": "Clave de la cuenta de servicio",
|
||||
"Sync interval": "Intervalo de sincronización",
|
||||
"Sync interval - Tooltip": "Unidad en segundos",
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"Enable signin session - Tooltip": "Conserver une session après la connexion à Casdoor à partir de l'application",
|
||||
"Enable signup": "Activer l'inscription",
|
||||
"Enable signup - Tooltip": "Autoriser la création de nouveaux comptes",
|
||||
"Existing Field": "Existing Field",
|
||||
"Failed signin frozen time": "Temps de blocage après échec de connexion",
|
||||
"Failed signin frozen time - Tooltip": "Durée pendant laquelle le compte est gelé après des tentatives de connexion échouées",
|
||||
"Failed signin limit": "Limite d'échecs de connexion",
|
||||
@@ -151,6 +152,7 @@
|
||||
"Signup items - Tooltip": "Éléments à remplir par les utilisateurs lors de la création de nouveaux comptes - Info-bulle",
|
||||
"Single Choice": "Choix unique",
|
||||
"Small icon": "Petite icône",
|
||||
"Static Value": "Static Value",
|
||||
"String": "String",
|
||||
"Tags - Tooltip": "Seuls les utilisateurs avec le tag listé dans les tags de l'application peuvent se connecter - Info-bulle",
|
||||
"The application does not allow to sign up new account": "L'application ne permet pas de créer un nouveau compte",
|
||||
@@ -184,9 +186,7 @@
|
||||
"Expire in years - Tooltip": "Période de validité du certificat, en années",
|
||||
"New Cert": "Nouveau Certificat",
|
||||
"Private key": "Clé privée",
|
||||
"Private key - Tooltip": "Clé privée correspondant au certificat de la clé publique",
|
||||
"Scope - Tooltip": "Scénarios d'utilisation du certificat",
|
||||
"Type - Tooltip": "Type de certificat"
|
||||
"Private key - Tooltip": "Clé privée correspondant au certificat de la clé publique"
|
||||
},
|
||||
"code": {
|
||||
"Code you received": "Le code que vous avez reçu",
|
||||
@@ -275,6 +275,7 @@
|
||||
"Applications that require authentication": "Applications qui nécessitent une authentification",
|
||||
"Apps": "Applications",
|
||||
"Authorization": "Autorisation",
|
||||
"Auto": "Auto",
|
||||
"Avatar": "Avatar",
|
||||
"Avatar - Tooltip": "Image d'avatar publique pour le compte",
|
||||
"Back": "Retour",
|
||||
@@ -283,6 +284,8 @@
|
||||
"Cancel": "Annuler",
|
||||
"Captcha": "Captcha",
|
||||
"Cart": "Panier",
|
||||
"Category": "Category",
|
||||
"Category - Tooltip": "Category - Tooltip",
|
||||
"Cert": "Certificat",
|
||||
"Cert - Tooltip": "La clé publique du certificat qui doit être vérifiée par le kit de développement client correspondant à cette application",
|
||||
"Certs": "Certificats",
|
||||
@@ -476,6 +479,8 @@
|
||||
"SSH type - Tooltip": "Type d'authentification de connexion SSH",
|
||||
"Save": "Enregistrer",
|
||||
"Save & Exit": "Enregistrer et quitter",
|
||||
"Scopes": "Scopes",
|
||||
"Scopes - Tooltip": "Scopes - Tooltip",
|
||||
"Search": "Rechercher",
|
||||
"Send": "Envoyer",
|
||||
"Session ID": "Identifiant de session",
|
||||
@@ -530,6 +535,7 @@
|
||||
"Transactions": "Transactions",
|
||||
"True": "Vrai",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "Lien de l'URL",
|
||||
"Unknown application name": "Nom d'application inconnu",
|
||||
@@ -867,6 +873,8 @@
|
||||
},
|
||||
"plan": {
|
||||
"Edit Plan": "Modifier le plan",
|
||||
"Is exclusive": "Is exclusive",
|
||||
"Is exclusive - Tooltip": "Is exclusive - Tooltip",
|
||||
"New Plan": "Nouveau plan",
|
||||
"Period": "Période",
|
||||
"Period - Tooltip": "Période",
|
||||
@@ -897,6 +905,7 @@
|
||||
"Amount": "Montant",
|
||||
"Buy": "Acheter",
|
||||
"Buy Product": "Acheter un produit",
|
||||
"Cart contains invalid products, please delete them before placing an order": "Cart contains invalid products, please delete them before placing an order",
|
||||
"Custom amount available": "Montant personnalisé disponible",
|
||||
"Custom price should be greater than zero": "Le prix personnalisé doit être supérieur à zéro",
|
||||
"Detail - Tooltip": "Détail du produit - Infobulle",
|
||||
@@ -909,9 +918,11 @@
|
||||
"Image": "Image",
|
||||
"Image - Tooltip": "Image du produit",
|
||||
"Information": "Informations",
|
||||
"Invalid product": "Invalid product",
|
||||
"Is recharge": "Est un rechargement",
|
||||
"Is recharge - Tooltip": "Indique si le produit actuel permet de recharger le solde",
|
||||
"New Product": "Nouveau produit",
|
||||
"No recharge options available": "No recharge options available",
|
||||
"Order created successfully": "Commande créée avec succès",
|
||||
"PayPal": "PayPal",
|
||||
"Payment cancelled": "Paiement annulé",
|
||||
@@ -924,10 +935,12 @@
|
||||
"Please select at least one payment provider": "Veuillez sélectionner au moins un fournisseur de paiement",
|
||||
"Processing payment...": "Traitement du paiement...",
|
||||
"Product list cannot be empty": "La liste des produits ne peut pas être vide",
|
||||
"Product not found or invalid": "Product not found or invalid",
|
||||
"Quantity": "Quantité",
|
||||
"Quantity - Tooltip": "Quantité du produit",
|
||||
"Recharge options": "Options de recharge",
|
||||
"Recharge options - Tooltip": "Recharge options - Tooltip",
|
||||
"Recharge products need to go to the product detail page to set custom amount": "Recharge products need to go to the product detail page to set custom amount",
|
||||
"Return URL": "URL de retour",
|
||||
"Return URL - Tooltip": "URL de retour après l'achat réussi",
|
||||
"SKU": "SKU",
|
||||
@@ -972,8 +985,6 @@
|
||||
"Can signin": "Pouvez-vous vous connecter?",
|
||||
"Can signup": "Peut s'inscrire",
|
||||
"Can unlink": "Peut annuler le lien",
|
||||
"Category": "Catégorie",
|
||||
"Category - Tooltip": "Sélectionnez une catégorie",
|
||||
"Channel No.": "chaîne n°",
|
||||
"Channel No. - Tooltip": "Canal N°",
|
||||
"Chat ID": "ID de chat",
|
||||
@@ -990,8 +1001,6 @@
|
||||
"Content - Tooltip": "Contenu - Infobulle",
|
||||
"DB test": "Test BD",
|
||||
"DB test - Tooltip": "Test BD - Infobulle",
|
||||
"Disable SSL": "Désactiver SSL",
|
||||
"Disable SSL - Tooltip": "Désactiver le protocole SSL lors de la communication avec le serveur STMP",
|
||||
"Domain": "Domaine",
|
||||
"Domain - Tooltip": "Domaine personnalisé pour le stockage d'objets",
|
||||
"Edit Provider": "Modifier le fournisseur",
|
||||
@@ -1074,9 +1083,12 @@
|
||||
"SP ACS URL": "URL du SP ACS",
|
||||
"SP ACS URL - Tooltip": "URL de l'ACS du fournisseur de service",
|
||||
"SP Entity ID": "Identifiant d'entité SP",
|
||||
"SSL mode": "SSL mode",
|
||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||
"Scene": "Scène",
|
||||
"Scene - Tooltip": "Scène",
|
||||
"Scope": "Portée",
|
||||
"Scope - Tooltip": "Scope - Tooltip",
|
||||
"Secret access key": "Clé d'accès secrète",
|
||||
"Secret access key - Tooltip": "Clé d'accès secrète",
|
||||
"Secret key": "Clé secrète",
|
||||
@@ -1238,6 +1250,9 @@
|
||||
},
|
||||
"syncer": {
|
||||
"API Token / Password": "Jeton API / Mot de passe",
|
||||
"AWS Access Key ID": "AWS Access Key ID",
|
||||
"AWS Region": "AWS Region",
|
||||
"AWS Secret Access Key": "AWS Secret Access Key",
|
||||
"Admin Email": "E-mail admin",
|
||||
"Affiliation table": "Table d'affiliation",
|
||||
"Affiliation table - Tooltip": "Nom de la table de la base de données de l'unité de travail",
|
||||
@@ -1269,8 +1284,6 @@
|
||||
"SSH password": "Mot de passe SSH",
|
||||
"SSH port": "Port SSH",
|
||||
"SSH user": "Utilisateur SSH",
|
||||
"SSL mode": "Mode SSL",
|
||||
"SSL mode - Tooltip": "Mode SSL",
|
||||
"Service account key": "Clé du compte de service",
|
||||
"Sync interval": "Intervalle de synchronisation",
|
||||
"Sync interval - Tooltip": "Unité en secondes",
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"Enable signin session - Tooltip": "アプリケーションから Casdoor にログイン後、Casdoor がセッションを維持しているかどうか",
|
||||
"Enable signup": "サインアップを有効にする",
|
||||
"Enable signup - Tooltip": "新しいアカウントの登録をユーザーに許可するかどうか",
|
||||
"Existing Field": "Existing Field",
|
||||
"Failed signin frozen time": "サインイン失敗時の凍結時間",
|
||||
"Failed signin frozen time - Tooltip": "サインイン失敗後にアカウントが凍結される時間",
|
||||
"Failed signin limit": "サインイン失敗回数制限",
|
||||
@@ -117,7 +118,6 @@
|
||||
"Please input your organization!": "あなたの組織を入力してください!",
|
||||
"Please select a HTML file": "HTMLファイルを選択してください",
|
||||
"Pop up": "ポップアップ",
|
||||
"Pop up - Tooltip": "ポップアップ - ヒント",
|
||||
"Providers": "プロバイダー",
|
||||
"Random": "ランダム",
|
||||
"Real name": "本名",
|
||||
@@ -135,7 +135,6 @@
|
||||
"SAML metadata": "SAMLメタデータ",
|
||||
"SAML metadata - Tooltip": "SAMLプロトコルのメタデータ - ヒント",
|
||||
"SAML reply URL": "SAMLリプライURL",
|
||||
"SAML reply URL - Tooltip": "SAMLリプライURL - ヒント",
|
||||
"Security": "セキュリティ",
|
||||
"Select": "選択",
|
||||
"Side panel HTML": "サイドパネルのHTML",
|
||||
@@ -153,6 +152,7 @@
|
||||
"Signup items - Tooltip": "新しいアカウントを登録する際にユーザーが入力するアイテム",
|
||||
"Single Choice": "単一選択",
|
||||
"Small icon": "小さいアイコン",
|
||||
"Static Value": "Static Value",
|
||||
"String": "文字列",
|
||||
"Tags - Tooltip": "アプリケーションタグに含まれるタグを持つユーザーのみログイン可能です",
|
||||
"The application does not allow to sign up new account": "アプリケーションでは新しいアカウントの登録ができません",
|
||||
@@ -186,9 +186,7 @@
|
||||
"Expire in years - Tooltip": "証明書の有効期間、年数で",
|
||||
"New Cert": "新しい証明書",
|
||||
"Private key": "プライベートキー",
|
||||
"Private key - Tooltip": "公開鍵証明書に対応する秘密鍵",
|
||||
"Scope - Tooltip": "証明書の使用シナリオ",
|
||||
"Type - Tooltip": "証明書の種類"
|
||||
"Private key - Tooltip": "公開鍵証明書に対応する秘密鍵"
|
||||
},
|
||||
"code": {
|
||||
"Code you received": "受け取ったコード",
|
||||
@@ -277,6 +275,7 @@
|
||||
"Applications that require authentication": "認証が必要なアプリケーション",
|
||||
"Apps": "アプリ",
|
||||
"Authorization": "認可",
|
||||
"Auto": "Auto",
|
||||
"Avatar": "アバター",
|
||||
"Avatar - Tooltip": "ユーザーのパブリックアバター画像",
|
||||
"Back": "戻る",
|
||||
@@ -285,6 +284,8 @@
|
||||
"Cancel": "キャンセルします",
|
||||
"Captcha": "キャプチャ",
|
||||
"Cart": "カート",
|
||||
"Category": "Category",
|
||||
"Category - Tooltip": "Category - Tooltip",
|
||||
"Cert": "証明書",
|
||||
"Cert - Tooltip": "このアプリケーションに対応するクライアントSDKによって検証する必要がある公開鍵証明書",
|
||||
"Certs": "証明書",
|
||||
@@ -478,6 +479,8 @@
|
||||
"SSH type - Tooltip": "SSH接続の認証タイプ",
|
||||
"Save": "保存",
|
||||
"Save & Exit": "保存して終了",
|
||||
"Scopes": "Scopes",
|
||||
"Scopes - Tooltip": "Scopes - Tooltip",
|
||||
"Search": "検索",
|
||||
"Send": "送信",
|
||||
"Session ID": "セッションID",
|
||||
@@ -532,6 +535,7 @@
|
||||
"Transactions": "取引",
|
||||
"True": "真",
|
||||
"Type": "タイプ",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URLリンク",
|
||||
"Unknown application name": "不明なアプリケーション名",
|
||||
@@ -869,6 +873,8 @@
|
||||
},
|
||||
"plan": {
|
||||
"Edit Plan": "プランを編集",
|
||||
"Is exclusive": "Is exclusive",
|
||||
"Is exclusive - Tooltip": "Is exclusive - Tooltip",
|
||||
"New Plan": "新しいプラン",
|
||||
"Period": "期間",
|
||||
"Period - Tooltip": "期間",
|
||||
@@ -899,6 +905,7 @@
|
||||
"Amount": "金額",
|
||||
"Buy": "購入",
|
||||
"Buy Product": "製品を購入する",
|
||||
"Cart contains invalid products, please delete them before placing an order": "Cart contains invalid products, please delete them before placing an order",
|
||||
"Custom amount available": "任意金額を利用可能",
|
||||
"Custom price should be greater than zero": "カスタム価格は0より大きくする必要があります",
|
||||
"Detail - Tooltip": "製品の詳細",
|
||||
@@ -911,9 +918,11 @@
|
||||
"Image": "画像",
|
||||
"Image - Tooltip": "製品のイメージ",
|
||||
"Information": "情報",
|
||||
"Invalid product": "Invalid product",
|
||||
"Is recharge": "チャージ用か",
|
||||
"Is recharge - Tooltip": "現在の製品が残高をチャージするためかどうか",
|
||||
"New Product": "新製品",
|
||||
"No recharge options available": "No recharge options available",
|
||||
"Order created successfully": "注文が正常に作成されました",
|
||||
"PayPal": "ペイパル",
|
||||
"Payment cancelled": "支払いキャンセル",
|
||||
@@ -926,10 +935,12 @@
|
||||
"Please select at least one payment provider": "少なくとも1つの支払いプロバイダーを選択してください",
|
||||
"Processing payment...": "支払い処理中...",
|
||||
"Product list cannot be empty": "商品リストを空にできません",
|
||||
"Product not found or invalid": "Product not found or invalid",
|
||||
"Quantity": "量",
|
||||
"Quantity - Tooltip": "製品の量",
|
||||
"Recharge options": "チャージオプション",
|
||||
"Recharge options - Tooltip": "チャージオプション - ツールチップ",
|
||||
"Recharge products need to go to the product detail page to set custom amount": "Recharge products need to go to the product detail page to set custom amount",
|
||||
"Return URL": "戻りURL",
|
||||
"Return URL - Tooltip": "成功した購入後に戻るURL",
|
||||
"SKU": "SKU",
|
||||
@@ -974,8 +985,6 @@
|
||||
"Can signin": "サインインできますか?",
|
||||
"Can signup": "サインアップできますか?",
|
||||
"Can unlink": "アンリンクすることができます",
|
||||
"Category": "カテゴリー",
|
||||
"Category - Tooltip": "カテゴリーを選択してください",
|
||||
"Channel No.": "チャンネル番号",
|
||||
"Channel No. - Tooltip": "チャンネル番号",
|
||||
"Chat ID": "チャットID",
|
||||
@@ -992,8 +1001,6 @@
|
||||
"Content - Tooltip": "コンテンツ - ツールチップ",
|
||||
"DB test": "DBテスト",
|
||||
"DB test - Tooltip": "DBテスト - ツールチップ",
|
||||
"Disable SSL": "SSLを無効にする",
|
||||
"Disable SSL - Tooltip": "SMTPサーバーと通信する場合にSSLプロトコルを無効にするかどうか",
|
||||
"Domain": "ドメイン",
|
||||
"Domain - Tooltip": "オブジェクトストレージのカスタムドメイン",
|
||||
"Edit Provider": "編集プロバイダー",
|
||||
@@ -1076,9 +1083,12 @@
|
||||
"SP ACS URL": "SP ACS URL",
|
||||
"SP ACS URL - Tooltip": "SP ACS URL - ツールチップ",
|
||||
"SP Entity ID": "SPエンティティID",
|
||||
"SSL mode": "SSL mode",
|
||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||
"Scene": "シーン",
|
||||
"Scene - Tooltip": "シーン",
|
||||
"Scope": "範囲",
|
||||
"Scope - Tooltip": "Scope - Tooltip",
|
||||
"Secret access key": "秘密のアクセスキー",
|
||||
"Secret access key - Tooltip": "秘密のアクセスキー",
|
||||
"Secret key": "秘密鍵",
|
||||
@@ -1240,6 +1250,9 @@
|
||||
},
|
||||
"syncer": {
|
||||
"API Token / Password": "APIトークン / パスワード",
|
||||
"AWS Access Key ID": "AWS Access Key ID",
|
||||
"AWS Region": "AWS Region",
|
||||
"AWS Secret Access Key": "AWS Secret Access Key",
|
||||
"Admin Email": "管理者メール",
|
||||
"Affiliation table": "所属テーブル",
|
||||
"Affiliation table - Tooltip": "作業単位のデータベーステーブル名",
|
||||
@@ -1271,8 +1284,6 @@
|
||||
"SSH password": "SSHパスワード",
|
||||
"SSH port": "SSHポート",
|
||||
"SSH user": "SSHユーザー",
|
||||
"SSL mode": "SSLモード",
|
||||
"SSL mode - Tooltip": "SSLモード",
|
||||
"Service account key": "サービスアカウントキー",
|
||||
"Sync interval": "同期の間隔",
|
||||
"Sync interval - Tooltip": "単位は秒です",
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"Enable signin session - Tooltip": "Czy Casdoor utrzymuje sesję po zalogowaniu do Casdoor z poziomu aplikacji",
|
||||
"Enable signup": "Włącz rejestrację",
|
||||
"Enable signup - Tooltip": "Czy zezwolić użytkownikom na rejestrację nowych kont",
|
||||
"Existing Field": "Existing Field",
|
||||
"Failed signin frozen time": "Czas blokady po nieudanym logowaniu",
|
||||
"Failed signin frozen time - Tooltip": "Czas w którym konto jest zablokowane po nieudanych próbach logowania - Podpowiedź",
|
||||
"Failed signin limit": "Limit nieudanych logowań",
|
||||
@@ -151,6 +152,7 @@
|
||||
"Signup items - Tooltip": "Elementy, które użytkownicy muszą wypełnić podczas rejestracji nowych kont",
|
||||
"Single Choice": "Jednokrotny wybór",
|
||||
"Small icon": "Mała ikona",
|
||||
"Static Value": "Static Value",
|
||||
"String": "Ciąg",
|
||||
"Tags - Tooltip": "Tylko użytkownicy z tagiem wymienionym w tagach aplikacji mogą się zalogować",
|
||||
"The application does not allow to sign up new account": "Aplikacja nie zezwala na rejestrację nowego konta",
|
||||
@@ -184,9 +186,7 @@
|
||||
"Expire in years - Tooltip": "Okres ważności certyfikatu, w latach",
|
||||
"New Cert": "Nowy certyfikat",
|
||||
"Private key": "Klucz prywatny",
|
||||
"Private key - Tooltip": "Klucz prywatny odpowiadający certyfikatowi klucza publicznego",
|
||||
"Scope - Tooltip": "Scenariusze użycia certyfikatu",
|
||||
"Type - Tooltip": "Typ certyfikatu"
|
||||
"Private key - Tooltip": "Klucz prywatny odpowiadający certyfikatowi klucza publicznego"
|
||||
},
|
||||
"code": {
|
||||
"Code you received": "Kod, który otrzymałeś",
|
||||
@@ -275,6 +275,7 @@
|
||||
"Applications that require authentication": "Aplikacje wymagające uwierzytelniania",
|
||||
"Apps": "Aplikacje",
|
||||
"Authorization": "Autoryzacja",
|
||||
"Auto": "Auto",
|
||||
"Avatar": "Awatar",
|
||||
"Avatar - Tooltip": "Publiczny obraz awatara użytkownika",
|
||||
"Back": "Wstecz",
|
||||
@@ -283,6 +284,8 @@
|
||||
"Cancel": "Anuluj",
|
||||
"Captcha": "Captcha",
|
||||
"Cart": "Koszyk",
|
||||
"Category": "Category",
|
||||
"Category - Tooltip": "Category - Tooltip",
|
||||
"Cert": "Certyfikat",
|
||||
"Cert - Tooltip": "Certyfikat klucza publicznego, który musi być zweryfikowany przez odpowiednią aplikację SDK po stronie klienta",
|
||||
"Certs": "Certyfikaty",
|
||||
@@ -476,6 +479,8 @@
|
||||
"SSH type - Tooltip": "Typ uwierzytelniania połączenia SSH",
|
||||
"Save": "Zapisz",
|
||||
"Save & Exit": "Zapisz i wyjdź",
|
||||
"Scopes": "Scopes",
|
||||
"Scopes - Tooltip": "Scopes - Tooltip",
|
||||
"Search": "Szukaj",
|
||||
"Send": "Wyślij",
|
||||
"Session ID": "ID sesji",
|
||||
@@ -530,6 +535,7 @@
|
||||
"Transactions": "Transakcje",
|
||||
"True": "Prawda",
|
||||
"Type": "Typ",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "Link URL",
|
||||
"Unknown application name": "Nieznana nazwa aplikacji",
|
||||
@@ -867,6 +873,8 @@
|
||||
},
|
||||
"plan": {
|
||||
"Edit Plan": "Edytuj plan",
|
||||
"Is exclusive": "Is exclusive",
|
||||
"Is exclusive - Tooltip": "Is exclusive - Tooltip",
|
||||
"New Plan": "Nowy plan",
|
||||
"Period": "Okres",
|
||||
"Period - Tooltip": "Okres",
|
||||
@@ -897,6 +905,7 @@
|
||||
"Amount": "Kwota",
|
||||
"Buy": "Kup",
|
||||
"Buy Product": "Kup produkt",
|
||||
"Cart contains invalid products, please delete them before placing an order": "Cart contains invalid products, please delete them before placing an order",
|
||||
"Custom amount available": "Dostępna kwota niestandardowa",
|
||||
"Custom price should be greater than zero": "Cena niestandardowa musi być większa od zera",
|
||||
"Detail - Tooltip": "Szczegóły produktu",
|
||||
@@ -909,9 +918,11 @@
|
||||
"Image": "Obrazek",
|
||||
"Image - Tooltip": "Obrazek produktu",
|
||||
"Information": "Informacje",
|
||||
"Invalid product": "Invalid product",
|
||||
"Is recharge": "Jest doładowaniem",
|
||||
"Is recharge - Tooltip": "Czy bieżący produkt służy do doładowania salda",
|
||||
"New Product": "Nowy produkt",
|
||||
"No recharge options available": "No recharge options available",
|
||||
"Order created successfully": "Zamówienie utworzone pomyślnie",
|
||||
"PayPal": "PayPal",
|
||||
"Payment cancelled": "Płatność anulowana",
|
||||
@@ -924,10 +935,12 @@
|
||||
"Please select at least one payment provider": "Wybierz co najmniej jednego dostawcę płatności",
|
||||
"Processing payment...": "Przetwarzanie płatności...",
|
||||
"Product list cannot be empty": "Lista produktów nie może być pusta",
|
||||
"Product not found or invalid": "Product not found or invalid",
|
||||
"Quantity": "Ilość",
|
||||
"Quantity - Tooltip": "Ilość produktu",
|
||||
"Recharge options": "Opcje doładowania",
|
||||
"Recharge options - Tooltip": "Opcje doładowania - Podpowiedź",
|
||||
"Recharge products need to go to the product detail page to set custom amount": "Recharge products need to go to the product detail page to set custom amount",
|
||||
"Return URL": "Adres powrotu",
|
||||
"Return URL - Tooltip": "Adres do powrotu po udanym zakupie",
|
||||
"SKU": "SKU",
|
||||
@@ -972,8 +985,10 @@
|
||||
"Can signin": "Można się zalogować",
|
||||
"Can signup": "Można się zarejestrować",
|
||||
"Can unlink": "Można odłączyć",
|
||||
"Category": "Kategoria",
|
||||
"Category - Tooltip": "Wybierz kategorię",
|
||||
"Channel No.": "Channel No.",
|
||||
"Channel No. - Tooltip": "Channel No. - Tooltip",
|
||||
"Chat ID": "Chat ID",
|
||||
"Chat ID - Tooltip": "Chat ID - Tooltip",
|
||||
"Client ID": "ID klienta",
|
||||
"Client ID - Tooltip": "ID klienta",
|
||||
"Client ID 2": "ID klienta 2",
|
||||
@@ -986,6 +1001,37 @@
|
||||
"Content - Tooltip": "Treść",
|
||||
"DB test": "Test bazy danych",
|
||||
"DB test - Tooltip": "Test bazy danych",
|
||||
"Domain": "Domain",
|
||||
"Domain - Tooltip": "Domain - Tooltip",
|
||||
"Edit Provider": "Edit Provider",
|
||||
"Email content": "Email content",
|
||||
"Email content - Tooltip": "Email content - Tooltip",
|
||||
"Email regex": "Email regex",
|
||||
"Email regex - Tooltip": "Email regex - Tooltip",
|
||||
"Email title": "Email title",
|
||||
"Email title - Tooltip": "Email title - Tooltip",
|
||||
"Enable PKCE": "Enable PKCE",
|
||||
"Enable PKCE - Tooltip": "Enable PKCE - Tooltip",
|
||||
"Enable proxy": "Enable proxy",
|
||||
"Enable proxy - Tooltip": "Enable proxy - Tooltip",
|
||||
"Endpoint": "Endpoint",
|
||||
"Endpoint (Intranet)": "Endpoint (Intranet)",
|
||||
"Endpoint - Tooltip": "Endpoint - Tooltip",
|
||||
"Follow-up action": "Follow-up action",
|
||||
"Follow-up action - Tooltip": "Follow-up action - Tooltip",
|
||||
"From address": "From address",
|
||||
"From address - Tooltip": "From address - Tooltip",
|
||||
"From name": "From name",
|
||||
"From name - Tooltip": "From name - Tooltip",
|
||||
"Get phone number": "Get phone number",
|
||||
"Get phone number - Tooltip": "Get phone number - Tooltip",
|
||||
"HTTP body mapping": "HTTP body mapping",
|
||||
"HTTP body mapping - Tooltip": "HTTP body mapping - Tooltip",
|
||||
"HTTP header": "HTTP header",
|
||||
"HTTP header - Tooltip": "HTTP header - Tooltip",
|
||||
"Host": "Host",
|
||||
"Host - Tooltip": "Host - Tooltip",
|
||||
"IdP": "IdP",
|
||||
"IdP certificate": "Certyfikat IdP",
|
||||
"Internal": "Wewnętrzny",
|
||||
"Issuer URL": "Adres URL wystawcy",
|
||||
@@ -1037,9 +1083,12 @@
|
||||
"SP ACS URL": "Adres URL SP ACS",
|
||||
"SP ACS URL - Tooltip": "Adres URL SP ACS",
|
||||
"SP Entity ID": "ID jednostki SP",
|
||||
"SSL mode": "SSL mode",
|
||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||
"Scene": "Scena",
|
||||
"Scene - Tooltip": "Scena",
|
||||
"Scope": "Zakres",
|
||||
"Scope - Tooltip": "Scope - Tooltip",
|
||||
"Secret access key": "Tajny klucz dostępu",
|
||||
"Secret access key - Tooltip": "Tajny klucz dostępu",
|
||||
"Secret key": "Tajny klucz",
|
||||
@@ -1201,6 +1250,9 @@
|
||||
},
|
||||
"syncer": {
|
||||
"API Token / Password": "API Token / Password",
|
||||
"AWS Access Key ID": "AWS Access Key ID",
|
||||
"AWS Region": "AWS Region",
|
||||
"AWS Secret Access Key": "AWS Secret Access Key",
|
||||
"Admin Email": "Admin Email",
|
||||
"Affiliation table": "Tabela przynależności",
|
||||
"Affiliation table - Tooltip": "Nazwa tabeli bazy danych jednostki pracy",
|
||||
@@ -1232,8 +1284,6 @@
|
||||
"SSH password": "Hasło SSH",
|
||||
"SSH port": "Port SSH",
|
||||
"SSH user": "Użytkownik SSH",
|
||||
"SSL mode": "Tryb SSL",
|
||||
"SSL mode - Tooltip": "Tryb SSL - etykietka",
|
||||
"Service account key": "Klucz konta usługi",
|
||||
"Sync interval": "Interwał synchronizacji",
|
||||
"Sync interval - Tooltip": "Jednostka w sekundach",
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"Enable signin session - Tooltip": "Se o Casdoor mantém uma sessão depois de fazer login no Casdoor a partir da aplicação",
|
||||
"Enable signup": "Ativar registro",
|
||||
"Enable signup - Tooltip": "Se permite que os usuários registrem uma nova conta",
|
||||
"Existing Field": "Existing Field",
|
||||
"Failed signin frozen time": "Tempo de bloqueio após falha de login",
|
||||
"Failed signin frozen time - Tooltip": "Tempo em que a conta fica congelada após tentativas de login falhadas",
|
||||
"Failed signin limit": "Limite de tentativas de login falhadas",
|
||||
@@ -151,6 +152,7 @@
|
||||
"Signup items - Tooltip": "Itens para os usuários preencherem ao fazer login - Dica",
|
||||
"Single Choice": "Escolha única",
|
||||
"Small icon": "Ícone pequeno",
|
||||
"Static Value": "Static Value",
|
||||
"String": "String",
|
||||
"Tags - Tooltip": "Apenas usuários com a tag listada nas tags da aplicação podem fazer login - Dica",
|
||||
"The application does not allow to sign up new account": "A aplicação não permite o registro de novas contas",
|
||||
@@ -184,9 +186,7 @@
|
||||
"Expire in years - Tooltip": "Período de validade do certificado, em anos",
|
||||
"New Cert": "Novo Certificado",
|
||||
"Private key": "Chave privada",
|
||||
"Private key - Tooltip": "Chave privada correspondente ao certificado de chave pública",
|
||||
"Scope - Tooltip": "Cenários de uso do certificado",
|
||||
"Type - Tooltip": "Tipo de certificado"
|
||||
"Private key - Tooltip": "Chave privada correspondente ao certificado de chave pública"
|
||||
},
|
||||
"code": {
|
||||
"Code you received": "Código que você recebeu",
|
||||
@@ -275,6 +275,7 @@
|
||||
"Applications that require authentication": "Aplicações que requerem autenticação",
|
||||
"Apps": "Aplicativos",
|
||||
"Authorization": "Autorização",
|
||||
"Auto": "Auto",
|
||||
"Avatar": "Avatar",
|
||||
"Avatar - Tooltip": "Imagem de avatar pública do usuário",
|
||||
"Back": "Voltar",
|
||||
@@ -283,6 +284,8 @@
|
||||
"Cancel": "Cancelar",
|
||||
"Captcha": "Captcha",
|
||||
"Cart": "Carrinho",
|
||||
"Category": "Category",
|
||||
"Category - Tooltip": "Category - Tooltip",
|
||||
"Cert": "Certificado",
|
||||
"Cert - Tooltip": "O certificado da chave pública que precisa ser verificado pelo SDK do cliente correspondente a esta aplicação",
|
||||
"Certs": "Certificados",
|
||||
@@ -476,6 +479,8 @@
|
||||
"SSH type - Tooltip": "Tipo de autenticação para conexão SSH",
|
||||
"Save": "Salvar",
|
||||
"Save & Exit": "Salvar e Sair",
|
||||
"Scopes": "Scopes",
|
||||
"Scopes - Tooltip": "Scopes - Tooltip",
|
||||
"Search": "Buscar",
|
||||
"Send": "Enviar",
|
||||
"Session ID": "ID da sessão",
|
||||
@@ -530,6 +535,7 @@
|
||||
"Transactions": "Transações",
|
||||
"True": "Verdadeiro",
|
||||
"Type": "Tipo",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "Link da URL",
|
||||
"Unknown application name": "Nome de aplicação desconhecido",
|
||||
@@ -867,6 +873,8 @@
|
||||
},
|
||||
"plan": {
|
||||
"Edit Plan": "Editar Plano",
|
||||
"Is exclusive": "Is exclusive",
|
||||
"Is exclusive - Tooltip": "Is exclusive - Tooltip",
|
||||
"New Plan": "Novo Plano",
|
||||
"Period": "Período",
|
||||
"Period - Tooltip": "Período",
|
||||
@@ -897,6 +905,7 @@
|
||||
"Amount": "Valor",
|
||||
"Buy": "Comprar",
|
||||
"Buy Product": "Comprar Produto",
|
||||
"Cart contains invalid products, please delete them before placing an order": "Cart contains invalid products, please delete them before placing an order",
|
||||
"Custom amount available": "Valor personalizado disponível",
|
||||
"Custom price should be greater than zero": "O preço personalizado deve ser maior que zero",
|
||||
"Detail - Tooltip": "Detalhes do produto",
|
||||
@@ -909,9 +918,11 @@
|
||||
"Image": "Imagem",
|
||||
"Image - Tooltip": "Imagem do produto",
|
||||
"Information": "Informações",
|
||||
"Invalid product": "Invalid product",
|
||||
"Is recharge": "É recarga",
|
||||
"Is recharge - Tooltip": "Se o produto atual é para recarregar saldo",
|
||||
"New Product": "Novo Produto",
|
||||
"No recharge options available": "No recharge options available",
|
||||
"Order created successfully": "Pedido criado com sucesso",
|
||||
"PayPal": "PayPal",
|
||||
"Payment cancelled": "Pagamento cancelado",
|
||||
@@ -924,10 +935,12 @@
|
||||
"Please select at least one payment provider": "Por favor, selecione pelo menos um provedor de pagamento",
|
||||
"Processing payment...": "Processando pagamento...",
|
||||
"Product list cannot be empty": "A lista de produtos não pode estar vazia",
|
||||
"Product not found or invalid": "Product not found or invalid",
|
||||
"Quantity": "Quantidade",
|
||||
"Quantity - Tooltip": "Quantidade do produto",
|
||||
"Recharge options": "Opções de recarga",
|
||||
"Recharge options - Tooltip": "Dica: opções de recarga",
|
||||
"Recharge products need to go to the product detail page to set custom amount": "Recharge products need to go to the product detail page to set custom amount",
|
||||
"Return URL": "URL de Retorno",
|
||||
"Return URL - Tooltip": "URL para retornar após a compra bem-sucedida",
|
||||
"SKU": "SKU",
|
||||
@@ -972,8 +985,6 @@
|
||||
"Can signin": "Pode fazer login",
|
||||
"Can signup": "Pode se inscrever",
|
||||
"Can unlink": "Pode desvincular",
|
||||
"Category": "Categoria",
|
||||
"Category - Tooltip": "Selecione uma categoria",
|
||||
"Channel No.": "Número do canal",
|
||||
"Channel No. - Tooltip": "Número do canal",
|
||||
"Chat ID": "ID do chat",
|
||||
@@ -990,8 +1001,6 @@
|
||||
"Content - Tooltip": "Dica: conteúdo",
|
||||
"DB test": "Teste do banco de dados",
|
||||
"DB test - Tooltip": "Dica: teste do banco de dados",
|
||||
"Disable SSL": "Desabilitar SSL",
|
||||
"Disable SSL - Tooltip": "Se deve desabilitar o protocolo SSL ao comunicar com o servidor SMTP",
|
||||
"Domain": "Domínio",
|
||||
"Domain - Tooltip": "Domínio personalizado para armazenamento de objetos",
|
||||
"Edit Provider": "Editar Provedor",
|
||||
@@ -1074,9 +1083,12 @@
|
||||
"SP ACS URL": "URL SP ACS",
|
||||
"SP ACS URL - Tooltip": "URL SP ACS",
|
||||
"SP Entity ID": "ID da Entidade SP",
|
||||
"SSL mode": "SSL mode",
|
||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||
"Scene": "Cenário",
|
||||
"Scene - Tooltip": "Cenário",
|
||||
"Scope": "Escopo",
|
||||
"Scope - Tooltip": "Scope - Tooltip",
|
||||
"Secret access key": "Chave de acesso secreta",
|
||||
"Secret access key - Tooltip": "Chave de acesso secreta",
|
||||
"Secret key": "Chave secreta",
|
||||
@@ -1238,6 +1250,9 @@
|
||||
},
|
||||
"syncer": {
|
||||
"API Token / Password": "Token de API / Senha",
|
||||
"AWS Access Key ID": "AWS Access Key ID",
|
||||
"AWS Region": "AWS Region",
|
||||
"AWS Secret Access Key": "AWS Secret Access Key",
|
||||
"Admin Email": "E-mail do administrador",
|
||||
"Affiliation table": "Tabela de Afiliação",
|
||||
"Affiliation table - Tooltip": "Nome da tabela no banco de dados da unidade de trabalho",
|
||||
@@ -1269,8 +1284,6 @@
|
||||
"SSH password": "Senha SSH",
|
||||
"SSH port": "Porta SSH",
|
||||
"SSH user": "Usuário SSH",
|
||||
"SSL mode": "Modo SSL",
|
||||
"SSL mode - Tooltip": "Dica: modo SSL",
|
||||
"Service account key": "Chave da conta de serviço",
|
||||
"Sync interval": "Intervalo de sincronização",
|
||||
"Sync interval - Tooltip": "Unidade em segundos",
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"Enable signin session - Tooltip": "Uygulamadan Casdoor'a giriş yaptıktan sonra Casdoor'un bir oturum sürdürüp sürdürmeyeceği",
|
||||
"Enable signup": "Kayıtı Etkinleştir",
|
||||
"Enable signup - Tooltip": "Kullanıcıların yeni bir hesap kaydetmesine izin verilip verilmeyeceği",
|
||||
"Existing Field": "Existing Field",
|
||||
"Failed signin frozen time": "Başarısız giriş dondurma süresi",
|
||||
"Failed signin frozen time - Tooltip": "Başarısız giriş denemelerinden sonra hesabın dondurulduğu süre",
|
||||
"Failed signin limit": "Başarısız giriş limiti",
|
||||
@@ -151,6 +152,7 @@
|
||||
"Signup items - Tooltip": "Kullanıcıların yeni hesaplar kaydederken doldurması gereken öğeler - İpucu",
|
||||
"Single Choice": "Tek Seçim",
|
||||
"Small icon": "Küçük simge",
|
||||
"Static Value": "Static Value",
|
||||
"String": "Dize",
|
||||
"Tags - Tooltip": "Yalnızca uygulama etiketlerinde listelenen etikete sahip kullanıcılar giriş yapabilir - İpucu",
|
||||
"The application does not allow to sign up new account": "Uygulama yeni hesap kaydetmeyi izin vermemektedir",
|
||||
@@ -184,9 +186,7 @@
|
||||
"Expire in years - Tooltip": "Sertifikanın geçerlilik süresi, yıllarda",
|
||||
"New Cert": "Yeni Sertifika",
|
||||
"Private key": "Özel anahtar",
|
||||
"Private key - Tooltip": "Genel anahtar sertifikasına karşılık gelen özel anahtar",
|
||||
"Scope - Tooltip": "Sertifikanın kullanım senaryoları",
|
||||
"Type - Tooltip": "Sertifika türü"
|
||||
"Private key - Tooltip": "Genel anahtar sertifikasına karşılık gelen özel anahtar"
|
||||
},
|
||||
"code": {
|
||||
"Code you received": "Aldığınız kod",
|
||||
@@ -275,6 +275,7 @@
|
||||
"Applications that require authentication": "Kimlik doğrulaması gerektiren uygulamalar",
|
||||
"Apps": "Uygulamalar",
|
||||
"Authorization": "Yetkilendirme",
|
||||
"Auto": "Auto",
|
||||
"Avatar": "Avatar",
|
||||
"Avatar - Tooltip": "Kullanıcı için genel avatar resmi",
|
||||
"Back": "Geri",
|
||||
@@ -283,6 +284,8 @@
|
||||
"Cancel": "Vazgeç",
|
||||
"Captcha": "Captcha",
|
||||
"Cart": "Sepet",
|
||||
"Category": "Category",
|
||||
"Category - Tooltip": "Category - Tooltip",
|
||||
"Cert": "Sertifika",
|
||||
"Cert - Tooltip": "Bu uygulamaya karşılık gelen istemci SDK tarafından doğrulanması gereken genel anahtar sertifikası",
|
||||
"Certs": "Sertifikalar",
|
||||
@@ -476,6 +479,8 @@
|
||||
"SSH type - Tooltip": "SSH bağlantısının kimlik doğrulama türü",
|
||||
"Save": "Kaydet",
|
||||
"Save & Exit": "Kaydet ve Çık",
|
||||
"Scopes": "Scopes",
|
||||
"Scopes - Tooltip": "Scopes - Tooltip",
|
||||
"Search": "Ara",
|
||||
"Send": "Gönder",
|
||||
"Session ID": "Oturum ID",
|
||||
@@ -530,6 +535,7 @@
|
||||
"Transactions": "İşlemler",
|
||||
"True": "Doğru",
|
||||
"Type": "Tür",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL bağlantısı",
|
||||
"Unknown application name": "Bilinmeyen uygulama adı",
|
||||
@@ -867,6 +873,8 @@
|
||||
},
|
||||
"plan": {
|
||||
"Edit Plan": "Planı Düzenle",
|
||||
"Is exclusive": "Is exclusive",
|
||||
"Is exclusive - Tooltip": "Is exclusive - Tooltip",
|
||||
"New Plan": "Yeni Plan",
|
||||
"Period": "Dönem",
|
||||
"Period - Tooltip": "Dönem",
|
||||
@@ -897,6 +905,7 @@
|
||||
"Amount": "Tutar",
|
||||
"Buy": "Satın Al",
|
||||
"Buy Product": "Ürün Satın Al",
|
||||
"Cart contains invalid products, please delete them before placing an order": "Cart contains invalid products, please delete them before placing an order",
|
||||
"Custom amount available": "Özel tutar kullanılabilir",
|
||||
"Custom price should be greater than zero": "Özel fiyat sıfırdan büyük olmalıdır",
|
||||
"Detail - Tooltip": "Ürün detayı",
|
||||
@@ -909,9 +918,11 @@
|
||||
"Image": "Resim",
|
||||
"Image - Tooltip": "Ürün resmi",
|
||||
"Information": "Bilgi",
|
||||
"Invalid product": "Invalid product",
|
||||
"Is recharge": "Yeniden yükleme mi",
|
||||
"Is recharge - Tooltip": "Mevcut ürün bakiye yeniden yüklemesi ise",
|
||||
"New Product": "Yeni Ürün",
|
||||
"No recharge options available": "No recharge options available",
|
||||
"Order created successfully": "Sipariş başarıyla oluşturuldu",
|
||||
"PayPal": "PayPal",
|
||||
"Payment cancelled": "Ödeme iptal edildi",
|
||||
@@ -924,10 +935,12 @@
|
||||
"Please select at least one payment provider": "Lütfen en az bir ödeme sağlayıcısı seçin",
|
||||
"Processing payment...": "Ödeme işleniyor...",
|
||||
"Product list cannot be empty": "Ürün listesi boş olamaz",
|
||||
"Product not found or invalid": "Product not found or invalid",
|
||||
"Quantity": "Miktar",
|
||||
"Quantity - Tooltip": "Ürün miktarı",
|
||||
"Recharge options": "Yeniden yükleme seçenekleri",
|
||||
"Recharge options - Tooltip": "Yeniden yükleme seçenekleri - Araç ipucu",
|
||||
"Recharge products need to go to the product detail page to set custom amount": "Recharge products need to go to the product detail page to set custom amount",
|
||||
"Return URL": "Dönüş URL'si",
|
||||
"Return URL - Tooltip": "Satın alımdan sonra dönülecek URL",
|
||||
"SKU": "SKU",
|
||||
@@ -972,8 +985,6 @@
|
||||
"Can signin": "Giriş yapabilir",
|
||||
"Can signup": "Kayıt yapabilir",
|
||||
"Can unlink": "Bağlantıyı kesebilir",
|
||||
"Category": "Kategori",
|
||||
"Category - Tooltip": "Bir kategori seçin",
|
||||
"Channel No.": "Kanal Numarası",
|
||||
"Channel No. - Tooltip": "Kanal Numarası",
|
||||
"Chat ID": "Sohbet Kimliği",
|
||||
@@ -990,8 +1001,6 @@
|
||||
"Content - Tooltip": "İçerik - Araç ipucu",
|
||||
"DB test": "Veritabanı testi",
|
||||
"DB test - Tooltip": "Veritabanı testi - Araç ipucu",
|
||||
"Disable SSL": "SSL'yi Devre Dışı Bırak",
|
||||
"Disable SSL - Tooltip": "STMP sunucusu ile iletişim kurarken SSL protokolünü devre dışı bırakıp bırakmayacağı",
|
||||
"Domain": "Alan adı",
|
||||
"Domain - Tooltip": "Nesne depolama için özel alan adı",
|
||||
"Edit Provider": "Sağlayıcıyı Düzenle",
|
||||
@@ -1074,9 +1083,12 @@
|
||||
"SP ACS URL": "SP ACS URL'si",
|
||||
"SP ACS URL - Tooltip": "SP ACS URL'si",
|
||||
"SP Entity ID": "SP Varlık ID'si",
|
||||
"SSL mode": "SSL mode",
|
||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||
"Scene": "Senaryo",
|
||||
"Scene - Tooltip": "Senaryo",
|
||||
"Scope": "Kapsam",
|
||||
"Scope - Tooltip": "Scope - Tooltip",
|
||||
"Secret access key": "Gizli erişim anahtarı",
|
||||
"Secret access key - Tooltip": "Gizli erişim anahtarı",
|
||||
"Secret key": "Gizli anahtar",
|
||||
@@ -1238,6 +1250,9 @@
|
||||
},
|
||||
"syncer": {
|
||||
"API Token / Password": "API Token / Password",
|
||||
"AWS Access Key ID": "AWS Access Key ID",
|
||||
"AWS Region": "AWS Region",
|
||||
"AWS Secret Access Key": "AWS Secret Access Key",
|
||||
"Admin Email": "Admin Email",
|
||||
"Affiliation table": "İlişki tablosu",
|
||||
"Affiliation table - Tooltip": "Çalışma biriminin veritabanı tablo adı",
|
||||
@@ -1269,8 +1284,6 @@
|
||||
"SSH password": "SSH şifresi",
|
||||
"SSH port": "SSH portu",
|
||||
"SSH user": "SSH kullanıcısı",
|
||||
"SSL mode": "SSL modu",
|
||||
"SSL mode - Tooltip": "SSL modu - İpucu",
|
||||
"Service account key": "Service account key",
|
||||
"Sync interval": "Senkronizasyon aralığı",
|
||||
"Sync interval - Tooltip": "Birimi saniye cinsinden",
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"Enable signin session - Tooltip": "Чи підтримує Casdoor сеанс після входу в Casdoor із програми",
|
||||
"Enable signup": "Увімкнути реєстрацію",
|
||||
"Enable signup - Tooltip": "Чи дозволяти користувачам реєструвати новий обліковий запис",
|
||||
"Existing Field": "Existing Field",
|
||||
"Failed signin frozen time": "Помилка входу заморожений час",
|
||||
"Failed signin frozen time - Tooltip": "Час після якого обліковий запис заморожується після невдалих спроб входу - Підказка",
|
||||
"Failed signin limit": "Обмеження невдалого входу",
|
||||
@@ -151,6 +152,7 @@
|
||||
"Signup items - Tooltip": "Пункти, які користувачі повинні заповнити під час реєстрації нових облікових записів",
|
||||
"Single Choice": "Один варіант",
|
||||
"Small icon": "Маленький значок",
|
||||
"Static Value": "Static Value",
|
||||
"String": "Рядок",
|
||||
"Tags - Tooltip": "Увійти можуть лише користувачі з тегом, указаним у тегах програми",
|
||||
"The application does not allow to sign up new account": "Програма не дозволяє зареєструвати новий обліковий запис",
|
||||
@@ -184,9 +186,7 @@
|
||||
"Expire in years - Tooltip": "Термін дії сертифіката, років",
|
||||
"New Cert": "Новий сертифікат",
|
||||
"Private key": "Приватний ключ",
|
||||
"Private key - Tooltip": "Закритий ключ, що відповідає сертифікату відкритого ключа",
|
||||
"Scope - Tooltip": "Сценарії використання сертифіката",
|
||||
"Type - Tooltip": "Тип сертифіката"
|
||||
"Private key - Tooltip": "Закритий ключ, що відповідає сертифікату відкритого ключа"
|
||||
},
|
||||
"code": {
|
||||
"Code you received": "Код, який ви отримали",
|
||||
@@ -275,6 +275,7 @@
|
||||
"Applications that require authentication": "Програми, які потребують автентифікації",
|
||||
"Apps": "програми",
|
||||
"Authorization": "Авторизація",
|
||||
"Auto": "Auto",
|
||||
"Avatar": "Аватар",
|
||||
"Avatar - Tooltip": "Публічний аватар користувача",
|
||||
"Back": "Назад",
|
||||
@@ -283,6 +284,8 @@
|
||||
"Cancel": "Скасувати",
|
||||
"Captcha": "Капча",
|
||||
"Cart": "Кошик",
|
||||
"Category": "Category",
|
||||
"Category - Tooltip": "Category - Tooltip",
|
||||
"Cert": "сертифікат",
|
||||
"Cert - Tooltip": "Сертифікат відкритого ключа, який потрібно перевірити клієнтським SDK, що відповідає цій програмі",
|
||||
"Certs": "Сертифікати",
|
||||
@@ -476,6 +479,8 @@
|
||||
"SSH type - Tooltip": "Тип авторизації підключення SSH",
|
||||
"Save": "зберегти",
|
||||
"Save & Exit": "зберегти",
|
||||
"Scopes": "Scopes",
|
||||
"Scopes - Tooltip": "Scopes - Tooltip",
|
||||
"Search": "Пошук",
|
||||
"Send": "Надіслати",
|
||||
"Session ID": "Ідентифікатор сеансу",
|
||||
@@ -530,6 +535,7 @@
|
||||
"Transactions": "транзакції",
|
||||
"True": "Так",
|
||||
"Type": "Тип",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "URL-посилання",
|
||||
"Unknown application name": "Невідома назва програми",
|
||||
@@ -737,48 +743,59 @@
|
||||
"New Order": "Нове замовлення",
|
||||
"Order not found": "Замовлення не знайдено",
|
||||
"Pay": "Оплатити",
|
||||
"Account menu - Tooltip": "Меню облікового запису - підказка",
|
||||
"Admin navbar items": "Пункти панелі навігації адміністратора",
|
||||
"Admin navbar items - Tooltip": "Пункти панелі навігації адміністратора - підказка",
|
||||
"Balance credit": "Баланс кредиту",
|
||||
"Balance credit - Tooltip": "Баланс кредиту - підказка",
|
||||
"Balance currency": "Валюта балансу",
|
||||
"Balance currency - Tooltip": "Валюта балансу - підказка",
|
||||
"Edit Organization": "Редагувати організацію",
|
||||
"Follow global theme": "Дотримуйтеся глобальної теми",
|
||||
"Has privilege consent": "Має згоду на привілеї",
|
||||
"Has privilege consent - Tooltip": "Заборонити додавання користувачів до вбудованої організації, якщо HasPrivilegeConsent встановлено в false",
|
||||
"Has privilege consent warning": "Додавання нового користувача до організації «built-in» (вбудованої) на даний момент вимкнено. Зауважте: усі користувачі в організації «built-in» є глобальними адміністраторами в Casdoor. Дивіться документацію: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. Якщо ви все ще хочете створити користувача для організації «built-in», перейдіть на сторінку налаштувань організації та увімкніть опцію «Має згоду на привілеї».",
|
||||
"Init score": "Початкова оцінка",
|
||||
"Init score - Tooltip": "Початкові бали, нараховані користувачам під час реєстрації",
|
||||
"Is profile public": "Профіль загальнодоступний",
|
||||
"Is profile public - Tooltip": "Після закриття лише глобальні адміністратори або користувачі в одній організації можуть отримати доступ до сторінки профілю користувача",
|
||||
"Modify rule": "Змінити правило",
|
||||
"New Organization": "Нова організація",
|
||||
"Optional": "Додатково",
|
||||
"Org balance": "Баланс організації",
|
||||
"Org balance - Tooltip": "Баланс організації - підказка",
|
||||
"Password expire days": "Кількість днів дії паролю",
|
||||
"Password expire days - Tooltip": "Кількість днів дії паролю - підказка",
|
||||
"Prompt": "Підкажіть",
|
||||
"Required": "вимагається",
|
||||
"Soft deletion": "М'яке видалення",
|
||||
"Soft deletion - Tooltip": "Якщо ввімкнено, видалення користувачів не призведе до їх повного видалення з бази даних. ",
|
||||
"Tags": "Теги",
|
||||
"Use Email as username": "Використовувати Email як ім'я користувача",
|
||||
"Use Email as username - Tooltip": "Використовувати Email як ім'я користувача, якщо поле імені користувача не відображається під час реєстрації",
|
||||
"User balance": "Баланс користувача",
|
||||
"User balance - Tooltip": "Баланс користувача - підказка",
|
||||
"User navbar items": "Пункти панелі навігації користувача",
|
||||
"User navbar items - Tooltip": "Пункти панелі навігації користувача - підказка",
|
||||
"User types": "Типи користувачів",
|
||||
"User types - Tooltip": "Типи користувачів - підказка",
|
||||
"View rule": "Переглянути правило",
|
||||
"Visible": "Видно",
|
||||
"Website URL": "адреса вебсайту",
|
||||
"Website URL - Tooltip": "URL-адреса домашньої сторінки організації. ",
|
||||
"Widget items": "Елементи віджета",
|
||||
"Widget items - Tooltip": "Елементи віджета - підказка"
|
||||
"Payment failed time": "Payment failed time",
|
||||
"Payment time": "Payment time",
|
||||
"Price": "Price",
|
||||
"Return to Order List": "Return to Order List",
|
||||
"Timeout time": "Timeout time",
|
||||
"View Order": "View Order"
|
||||
},
|
||||
"organization": {
|
||||
"Account items": "Account items",
|
||||
"Account items - Tooltip": "Account items - Tooltip",
|
||||
"Account menu": "Account menu",
|
||||
"Account menu - Tooltip": "Account menu - Tooltip",
|
||||
"Admin navbar items": "Admin navbar items",
|
||||
"Admin navbar items - Tooltip": "Admin navbar items - Tooltip",
|
||||
"Balance credit": "Balance credit",
|
||||
"Balance credit - Tooltip": "Balance credit - Tooltip",
|
||||
"Balance currency": "Balance currency",
|
||||
"Balance currency - Tooltip": "Balance currency - Tooltip",
|
||||
"Edit Organization": "Edit Organization",
|
||||
"Follow global theme": "Follow global theme",
|
||||
"Has privilege consent": "Has privilege consent",
|
||||
"Has privilege consent - Tooltip": "Has privilege consent - Tooltip",
|
||||
"Has privilege consent warning": "Has privilege consent warning",
|
||||
"Init score": "Init score",
|
||||
"Init score - Tooltip": "Init score - Tooltip",
|
||||
"Is profile public": "Is profile public",
|
||||
"Is profile public - Tooltip": "Is profile public - Tooltip",
|
||||
"Modify rule": "Modify rule",
|
||||
"New Organization": "New Organization",
|
||||
"Optional": "Optional",
|
||||
"Org balance": "Org balance",
|
||||
"Org balance - Tooltip": "Org balance - Tooltip",
|
||||
"Password expire days": "Password expire days",
|
||||
"Password expire days - Tooltip": "Password expire days - Tooltip",
|
||||
"Prompt": "Prompt",
|
||||
"Required": "Required",
|
||||
"Soft deletion": "Soft deletion",
|
||||
"Soft deletion - Tooltip": "Soft deletion - Tooltip",
|
||||
"Tags": "Tags",
|
||||
"Use Email as username": "Use Email as username",
|
||||
"Use Email as username - Tooltip": "Use Email as username - Tooltip",
|
||||
"User balance": "User balance",
|
||||
"User balance - Tooltip": "User balance - Tooltip",
|
||||
"User navbar items": "User navbar items",
|
||||
"User navbar items - Tooltip": "User navbar items - Tooltip",
|
||||
"User types": "User types",
|
||||
"User types - Tooltip": "User types - Tooltip",
|
||||
"View rule": "View rule",
|
||||
"Visible": "Visible",
|
||||
"Website URL": "Website URL",
|
||||
"Website URL - Tooltip": "Website URL - Tooltip",
|
||||
"Widget items": "Widget items",
|
||||
"Widget items - Tooltip": "Widget items - Tooltip"
|
||||
},
|
||||
"payment": {
|
||||
"Confirm your invoice information": "Підтвердьте інформацію про рахунок",
|
||||
@@ -856,6 +873,8 @@
|
||||
},
|
||||
"plan": {
|
||||
"Edit Plan": "Редагувати план",
|
||||
"Is exclusive": "Is exclusive",
|
||||
"Is exclusive - Tooltip": "Is exclusive - Tooltip",
|
||||
"New Plan": "Новий план",
|
||||
"Period": "Крапка",
|
||||
"Period - Tooltip": "Період",
|
||||
@@ -886,6 +905,7 @@
|
||||
"Amount": "Amount",
|
||||
"Buy": "купити",
|
||||
"Buy Product": "Купити товар",
|
||||
"Cart contains invalid products, please delete them before placing an order": "Cart contains invalid products, please delete them before placing an order",
|
||||
"Custom amount available": "Custom amount available",
|
||||
"Custom price should be greater than zero": "Custom price should be greater than zero",
|
||||
"Detail - Tooltip": "Деталь продукту",
|
||||
@@ -898,9 +918,11 @@
|
||||
"Image": "Зображення",
|
||||
"Image - Tooltip": "Зображення товару",
|
||||
"Information": "Information",
|
||||
"Invalid product": "Invalid product",
|
||||
"Is recharge": "Чи є поповненням",
|
||||
"Is recharge - Tooltip": "Чи є поточний продукт для поповнення балансу",
|
||||
"New Product": "Новий продукт",
|
||||
"No recharge options available": "No recharge options available",
|
||||
"Order created successfully": "Order created successfully",
|
||||
"PayPal": "Пейпал",
|
||||
"Payment cancelled": "Платіж скасовано",
|
||||
@@ -913,10 +935,12 @@
|
||||
"Please select at least one payment provider": "Please select at least one payment provider",
|
||||
"Processing payment...": "Processing payment...",
|
||||
"Product list cannot be empty": "Product list cannot be empty",
|
||||
"Product not found or invalid": "Product not found or invalid",
|
||||
"Quantity": "Кількість",
|
||||
"Quantity - Tooltip": "Кількість товару",
|
||||
"Recharge options": "Recharge options",
|
||||
"Recharge options - Tooltip": "Варіанти поповнення - Підказка",
|
||||
"Recharge products need to go to the product detail page to set custom amount": "Recharge products need to go to the product detail page to set custom amount",
|
||||
"Return URL": "Повернута URL-адреса",
|
||||
"Return URL - Tooltip": "URL-адреса для повернення після успішної покупки",
|
||||
"SKU": "SKU",
|
||||
@@ -961,8 +985,6 @@
|
||||
"Can signin": "Можна ввійти",
|
||||
"Can signup": "Можна записатися",
|
||||
"Can unlink": "Можна від’єднати",
|
||||
"Category": "Категорія",
|
||||
"Category - Tooltip": "Ідентифікатор для категоризації та групування елементів або контенту, що полегшує фільтрацію та управління",
|
||||
"Channel No.": "Номер каналу",
|
||||
"Channel No. - Tooltip": "Унікальний номер, що ідентифікує канал зв'язку або передачі даних, використовується для розрізнення різних шляхів передачі",
|
||||
"Chat ID": "Ідентифікатор чату",
|
||||
@@ -979,8 +1001,6 @@
|
||||
"Content - Tooltip": "Вміст – підказка",
|
||||
"DB test": "Тест БД",
|
||||
"DB test - Tooltip": "Тест бази даних - підказка",
|
||||
"Disable SSL": "Вимкнути SSL",
|
||||
"Disable SSL - Tooltip": "Чи вимикати протокол SSL під час зв’язку із сервером STMP",
|
||||
"Domain": "Домен",
|
||||
"Domain - Tooltip": "Спеціальний домен для зберігання об'єктів",
|
||||
"Edit Provider": "Редагувати постачальника",
|
||||
@@ -1063,9 +1083,12 @@
|
||||
"SP ACS URL": "URL ACS СП",
|
||||
"SP ACS URL - Tooltip": "URL ACS СП",
|
||||
"SP Entity ID": "Ідентифікатор особи SP",
|
||||
"SSL mode": "SSL mode",
|
||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||
"Scene": "Сцена",
|
||||
"Scene - Tooltip": "Сцена",
|
||||
"Scope": "Область застосування",
|
||||
"Scope - Tooltip": "Scope - Tooltip",
|
||||
"Secret access key": "Секретний ключ доступу",
|
||||
"Secret access key - Tooltip": "Секретний ключ доступу",
|
||||
"Secret key": "Секретний ключ",
|
||||
@@ -1227,6 +1250,9 @@
|
||||
},
|
||||
"syncer": {
|
||||
"API Token / Password": "API Token / Password",
|
||||
"AWS Access Key ID": "AWS Access Key ID",
|
||||
"AWS Region": "AWS Region",
|
||||
"AWS Secret Access Key": "AWS Secret Access Key",
|
||||
"Admin Email": "Admin Email",
|
||||
"Affiliation table": "Таблиця приналежності",
|
||||
"Affiliation table - Tooltip": "Назва робочої одиниці таблиці бази даних",
|
||||
@@ -1258,8 +1284,6 @@
|
||||
"SSH password": "пароль SSH",
|
||||
"SSH port": "порт SSH",
|
||||
"SSH user": "Користувач SSH",
|
||||
"SSL mode": "Режим SSL",
|
||||
"SSL mode - Tooltip": "Режим SSL – підказка",
|
||||
"Service account key": "Service account key",
|
||||
"Sync interval": "Інтервал синхронізації",
|
||||
"Sync interval - Tooltip": "Одиниця в секундах",
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"Enable signin session - Tooltip": "Có phải Casdoor duy trì phiên sau khi đăng nhập vào Casdoor từ ứng dụng không?",
|
||||
"Enable signup": "Kích hoạt đăng ký",
|
||||
"Enable signup - Tooltip": "Có cho phép người dùng đăng ký tài khoản mới không?",
|
||||
"Existing Field": "Existing Field",
|
||||
"Failed signin frozen time": "Thời gian khóa khi đăng nhập thất bại",
|
||||
"Failed signin frozen time - Tooltip": "Thời gian tài khoản bị đóng băng sau các lần đăng nhập thất bại",
|
||||
"Failed signin limit": "Giới hạn đăng nhập thất bại",
|
||||
@@ -151,6 +152,7 @@
|
||||
"Signup items - Tooltip": "Mục cho người dùng đề điền khi đăng nhập - Gợi ý",
|
||||
"Single Choice": "Lựa chọn đơn",
|
||||
"Small icon": "Biểu tượng nhỏ",
|
||||
"Static Value": "Static Value",
|
||||
"String": "Chuỗi",
|
||||
"Tags - Tooltip": "Chỉ người dùng có thẻ được liệt kê trong thẻ ứng dụng mới có thể đăng nhập - Gợi ý",
|
||||
"The application does not allow to sign up new account": "Ứng dụng không cho phép đăng ký tài khoản mới",
|
||||
@@ -184,9 +186,7 @@
|
||||
"Expire in years - Tooltip": "Thời hạn hiệu lực của chứng chỉ, tính bằng năm",
|
||||
"New Cert": "Chứng chỉ mới",
|
||||
"Private key": "Khóa bí mật",
|
||||
"Private key - Tooltip": "Khóa riêng tương ứng với chứng thư khóa công khai",
|
||||
"Scope - Tooltip": "Các kịch bản sử dụng của giấy chứng nhận",
|
||||
"Type - Tooltip": "Loại chứng chỉ"
|
||||
"Private key - Tooltip": "Khóa riêng tương ứng với chứng thư khóa công khai"
|
||||
},
|
||||
"code": {
|
||||
"Code you received": "Mã bạn nhận được",
|
||||
@@ -275,6 +275,7 @@
|
||||
"Applications that require authentication": "Các ứng dụng yêu cầu xác thực",
|
||||
"Apps": "Ứng dụng",
|
||||
"Authorization": "Ủy quyền",
|
||||
"Auto": "Auto",
|
||||
"Avatar": "Ảnh đại diện",
|
||||
"Avatar - Tooltip": "Ảnh đại diện công khai cho người dùng",
|
||||
"Back": "Quay lại",
|
||||
@@ -283,6 +284,8 @@
|
||||
"Cancel": "Hủy bỏ",
|
||||
"Captcha": "Mã xác nhận",
|
||||
"Cart": "Giỏ hàng",
|
||||
"Category": "Category",
|
||||
"Category - Tooltip": "Category - Tooltip",
|
||||
"Cert": "Chứng chỉ",
|
||||
"Cert - Tooltip": "Chứng chỉ khóa công khai cần được xác minh bởi SDK khách hàng tương ứng với ứng dụng này",
|
||||
"Certs": "Chứng chỉ",
|
||||
@@ -476,6 +479,8 @@
|
||||
"SSH type - Tooltip": "Loại xác thực kết nối SSH",
|
||||
"Save": "Lưu",
|
||||
"Save & Exit": "Lưu và Thoát",
|
||||
"Scopes": "Scopes",
|
||||
"Scopes - Tooltip": "Scopes - Tooltip",
|
||||
"Search": "Tìm kiếm",
|
||||
"Send": "Gửi",
|
||||
"Session ID": "ID phiên làm việc",
|
||||
@@ -530,6 +535,7 @@
|
||||
"Transactions": "Giao dịch",
|
||||
"True": "Đúng",
|
||||
"Type": "Loại",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
"URL - Tooltip": "Đường dẫn URL",
|
||||
"Unknown application name": "Tên ứng dụng không xác định",
|
||||
@@ -867,6 +873,8 @@
|
||||
},
|
||||
"plan": {
|
||||
"Edit Plan": "Chỉnh sửa gói",
|
||||
"Is exclusive": "Is exclusive",
|
||||
"Is exclusive - Tooltip": "Is exclusive - Tooltip",
|
||||
"New Plan": "Gói mới",
|
||||
"Period": "Kỳ",
|
||||
"Period - Tooltip": "Thời kỳ",
|
||||
@@ -897,6 +905,7 @@
|
||||
"Amount": "Số tiền",
|
||||
"Buy": "Mua",
|
||||
"Buy Product": "Mua sản phẩm",
|
||||
"Cart contains invalid products, please delete them before placing an order": "Cart contains invalid products, please delete them before placing an order",
|
||||
"Custom amount available": "Số tiền tùy chỉnh có sẵn",
|
||||
"Custom price should be greater than zero": "Giá tùy chỉnh phải lớn hơn không",
|
||||
"Detail - Tooltip": "Chi tiết sản phẩm",
|
||||
@@ -909,9 +918,11 @@
|
||||
"Image": "Ảnh",
|
||||
"Image - Tooltip": "Hình ảnh sản phẩm",
|
||||
"Information": "Thông tin",
|
||||
"Invalid product": "Invalid product",
|
||||
"Is recharge": "Là nạp tiền",
|
||||
"Is recharge - Tooltip": "Sản phẩm hiện tại có phải để nạp số dư",
|
||||
"New Product": "Sản phẩm mới",
|
||||
"No recharge options available": "No recharge options available",
|
||||
"Order created successfully": "Tạo đơn hàng thành công",
|
||||
"PayPal": "PayPal",
|
||||
"Payment cancelled": "Thanh toán đã bị hủy",
|
||||
@@ -924,10 +935,12 @@
|
||||
"Please select at least one payment provider": "Vui lòng chọn ít nhất một nhà cung cấp thanh toán",
|
||||
"Processing payment...": "Đang xử lý thanh toán...",
|
||||
"Product list cannot be empty": "Danh sách sản phẩm không thể trống",
|
||||
"Product not found or invalid": "Product not found or invalid",
|
||||
"Quantity": "Số lượng",
|
||||
"Quantity - Tooltip": "Số lượng sản phẩm",
|
||||
"Recharge options": "Tùy chọn nạp tiền",
|
||||
"Recharge options - Tooltip": "Tùy chọn nạp tiền - Gợi ý",
|
||||
"Recharge products need to go to the product detail page to set custom amount": "Recharge products need to go to the product detail page to set custom amount",
|
||||
"Return URL": "Địa chỉ URL trở lại",
|
||||
"Return URL - Tooltip": "URL để quay lại sau khi mua hàng thành công",
|
||||
"SKU": "SKU",
|
||||
@@ -972,8 +985,6 @@
|
||||
"Can signin": "Đăng nhập được không?",
|
||||
"Can signup": "Đăng ký có thể được thực hiện",
|
||||
"Can unlink": "Không liên kết được",
|
||||
"Category": "Thể loại",
|
||||
"Category - Tooltip": "Chọn một danh mục",
|
||||
"Channel No.": "Kênh số.",
|
||||
"Channel No. - Tooltip": "Kênh Số.",
|
||||
"Chat ID": "ID trò chuyện",
|
||||
@@ -990,8 +1001,6 @@
|
||||
"Content - Tooltip": "Gợi ý nội dung",
|
||||
"DB test": "DB test",
|
||||
"DB test - Tooltip": "Kiểm tra DB - Gợi ý",
|
||||
"Disable SSL": "Vô hiệu hóa SSL",
|
||||
"Disable SSL - Tooltip": "Có nên vô hiệu hóa giao thức SSL khi giao tiếp với máy chủ STMP hay không?",
|
||||
"Domain": "Miền",
|
||||
"Domain - Tooltip": "Tên miền tùy chỉnh cho lưu trữ đối tượng",
|
||||
"Edit Provider": "Chỉnh sửa nhà cung cấp",
|
||||
@@ -1074,9 +1083,12 @@
|
||||
"SP ACS URL": "SP ACC URL",
|
||||
"SP ACS URL - Tooltip": "URL ACS của SP - Gợi ý",
|
||||
"SP Entity ID": "SP Entity ID: Định danh thực thể SP",
|
||||
"SSL mode": "SSL mode",
|
||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||
"Scene": "Cảnh",
|
||||
"Scene - Tooltip": "Cảnh",
|
||||
"Scope": "Phạm vi",
|
||||
"Scope - Tooltip": "Scope - Tooltip",
|
||||
"Secret access key": "Chìa khóa truy cập bí mật",
|
||||
"Secret access key - Tooltip": "Khóa truy cập bí mật",
|
||||
"Secret key": "Chìa khóa bí mật",
|
||||
@@ -1238,6 +1250,9 @@
|
||||
},
|
||||
"syncer": {
|
||||
"API Token / Password": "Mã thông báo API / Mật khẩu",
|
||||
"AWS Access Key ID": "AWS Access Key ID",
|
||||
"AWS Region": "AWS Region",
|
||||
"AWS Secret Access Key": "AWS Secret Access Key",
|
||||
"Admin Email": "Email quản trị viên",
|
||||
"Affiliation table": "Bảng liên kết",
|
||||
"Affiliation table - Tooltip": "Bảng liên kết - Gợi ý",
|
||||
@@ -1245,11 +1260,8 @@
|
||||
"Avatar base URL - Tooltip": "Địa chỉ cơ sở URL ảnh đại diện - Gợi ý",
|
||||
"Bind DN": "Kết nối DN",
|
||||
"Casdoor column": "Cột Casdoor",
|
||||
"Casdoor column - Tooltip": "Tên cột trong bảng Casdoor tương ứng",
|
||||
"Column name": "Tên cột",
|
||||
"Column name - Tooltip": "Tên cột trong bảng cơ sở dữ liệu",
|
||||
"Column type": "Loại cột",
|
||||
"Column type - Tooltip": "Kiểu dữ liệu của cột",
|
||||
"Connect successfully": "Kết nối thành công",
|
||||
"Corp ID": "Mã doanh nghiệp",
|
||||
"Corp secret": "Bí mật doanh nghiệp",
|
||||
@@ -1268,15 +1280,11 @@
|
||||
"New Syncer": "Đồng bộ mới",
|
||||
"Paste your Google Workspace service account JSON key here": "Dán khóa JSON tài khoản dịch vụ Google Workspace của bạn tại đây",
|
||||
"SCIM Server URL": "URL máy chủ SCIM",
|
||||
"SCIM Server URL - Tooltip": "Địa chỉ URL của máy chủ SCIM",
|
||||
"SSH host": "Máy chủ SSH",
|
||||
"SSH password": "Mật khẩu SSH",
|
||||
"SSH port": "Cổng SSH",
|
||||
"SSH user": "Người dùng SSH",
|
||||
"SSL mode": "Chế độ SSL",
|
||||
"SSL mode - Tooltip": "Chế độ kết nối SSL với cơ sở dữ liệu",
|
||||
"Service account key": "Khóa tài khoản dịch vụ",
|
||||
"Service account key - Tooltip": "Khóa JSON của tài khoản dịch vụ",
|
||||
"Sync interval": "Khoảng thời gian đồng bộ",
|
||||
"Sync interval - Tooltip": "Khoảng thời gian giữa các lần đồng bộ (tính bằng giây)",
|
||||
"Table": "Bảng",
|
||||
@@ -1291,7 +1299,6 @@
|
||||
"API Latency": "Độ trễ API",
|
||||
"API Throughput": "Thông lượng API",
|
||||
"About Casdoor": "Về Casdoor",
|
||||
"About Casdoor - Tooltip": "Thông tin về nền tảng Casdoor",
|
||||
"An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS": "Một nền tảng Quản lý Danh tính và Truy cập (IAM) / Đăng nhập Một lần (SSO) với giao diện người dùng web hỗ trợ OAuth 2.0, OIDC, SAML và CAS",
|
||||
"CPU Usage": "Sử dụng CPU",
|
||||
"Community": "Cộng đồng",
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"Enable signin session - Tooltip": "从应用登录Casdoor后,Casdoor是否保持会话",
|
||||
"Enable signup": "启用注册",
|
||||
"Enable signup - Tooltip": "是否允许用户注册",
|
||||
"Existing Field": "Existing Field",
|
||||
"Failed signin frozen time": "登入重试等待时间",
|
||||
"Failed signin frozen time - Tooltip": "超过登入错误重试次数后的等待时间,只有超过等待时间后用户才能重新登入,默认值为15分钟,设置的值需为正整数",
|
||||
"Failed signin limit": "登入错误次数限制",
|
||||
@@ -151,6 +152,7 @@
|
||||
"Signup items - Tooltip": "注册用户注册时需要填写的项目",
|
||||
"Single Choice": "单选",
|
||||
"Small icon": "小图标",
|
||||
"Static Value": "Static Value",
|
||||
"String": "字符串",
|
||||
"Tags - Tooltip": "用户的标签在应用的标签集合中时,用户才可以登录该应用",
|
||||
"The application does not allow to sign up new account": "该应用不允许注册新账户",
|
||||
@@ -184,9 +186,7 @@
|
||||
"Expire in years - Tooltip": "公钥证书的有效期,以年为单位",
|
||||
"New Cert": "添加证书",
|
||||
"Private key": "私钥",
|
||||
"Private key - Tooltip": "公钥证书对应的私钥",
|
||||
"Scope - Tooltip": "公钥证书的使用场景",
|
||||
"Type - Tooltip": "公钥证书的类型"
|
||||
"Private key - Tooltip": "公钥证书对应的私钥"
|
||||
},
|
||||
"code": {
|
||||
"Code you received": "验证码",
|
||||
@@ -268,13 +268,14 @@
|
||||
"Admin": "管理工具",
|
||||
"Affiliation URL": "工作单位URL",
|
||||
"Affiliation URL - Tooltip": "工作单位的官网URL",
|
||||
"All": "全部允许",
|
||||
"All": "全部",
|
||||
"Application": "应用",
|
||||
"Application - Tooltip": "可以访问的应用",
|
||||
"Applications": "应用",
|
||||
"Applications that require authentication": "需要认证和鉴权的应用",
|
||||
"Apps": "应用列表",
|
||||
"Authorization": "Casbin权限管理",
|
||||
"Auto": "Auto",
|
||||
"Avatar": "头像",
|
||||
"Avatar - Tooltip": "公开展示的用户头像",
|
||||
"Back": "返回",
|
||||
@@ -283,6 +284,8 @@
|
||||
"Cancel": "取消",
|
||||
"Captcha": "人机验证码",
|
||||
"Cart": "购物车",
|
||||
"Category": "Category",
|
||||
"Category - Tooltip": "Category - Tooltip",
|
||||
"Cert": "证书",
|
||||
"Cert - Tooltip": "该应用所对应的客户端SDK需要验证的公钥证书",
|
||||
"Certs": "证书",
|
||||
@@ -476,6 +479,8 @@
|
||||
"SSH type - Tooltip": "SSH连接的认证类型",
|
||||
"Save": "保存",
|
||||
"Save & Exit": "保存 & 退出",
|
||||
"Scopes": "Scopes",
|
||||
"Scopes - Tooltip": "Scopes - Tooltip",
|
||||
"Search": "搜索",
|
||||
"Send": "发送",
|
||||
"Session ID": "会话ID",
|
||||
@@ -530,6 +535,7 @@
|
||||
"Transactions": "交易",
|
||||
"True": "真",
|
||||
"Type": "类型",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "链接",
|
||||
"URL - Tooltip": "URL链接",
|
||||
"Unknown application name": "未知的应用程序名称",
|
||||
@@ -867,6 +873,8 @@
|
||||
},
|
||||
"plan": {
|
||||
"Edit Plan": "编辑计划",
|
||||
"Is exclusive": "Is exclusive",
|
||||
"Is exclusive - Tooltip": "Is exclusive - Tooltip",
|
||||
"New Plan": "添加计划",
|
||||
"Period": "期限",
|
||||
"Period - Tooltip": "计划对应的期限",
|
||||
@@ -897,6 +905,7 @@
|
||||
"Amount": "金额",
|
||||
"Buy": "购买",
|
||||
"Buy Product": "购买商品",
|
||||
"Cart contains invalid products, please delete them before placing an order": "Cart contains invalid products, please delete them before placing an order",
|
||||
"Custom amount available": "可自定义金额",
|
||||
"Custom price should be greater than zero": "自定义价格必须大于零",
|
||||
"Detail - Tooltip": "商品详情",
|
||||
@@ -909,9 +918,11 @@
|
||||
"Image": "图片",
|
||||
"Image - Tooltip": "商品图片",
|
||||
"Information": "信息",
|
||||
"Invalid product": "Invalid product",
|
||||
"Is recharge": "充值",
|
||||
"Is recharge - Tooltip": "当前商品是否为充值商品",
|
||||
"New Product": "添加商品",
|
||||
"No recharge options available": "No recharge options available",
|
||||
"Order created successfully": "订单创建成功",
|
||||
"PayPal": "PayPal",
|
||||
"Payment cancelled": "支付取消",
|
||||
@@ -924,10 +935,12 @@
|
||||
"Please select at least one payment provider": "请至少选择一个支付提供商",
|
||||
"Processing payment...": "正在处理支付...",
|
||||
"Product list cannot be empty": "商品列表不能为空",
|
||||
"Product not found or invalid": "Product not found or invalid",
|
||||
"Quantity": "库存",
|
||||
"Quantity - Tooltip": "库存的数量",
|
||||
"Recharge options": "充值选项",
|
||||
"Recharge options - Tooltip": "预设充值金额",
|
||||
"Recharge products need to go to the product detail page to set custom amount": "Recharge products need to go to the product detail page to set custom amount",
|
||||
"Return URL": "返回URL",
|
||||
"Return URL - Tooltip": "购买成功后返回的URL",
|
||||
"SKU": "货号",
|
||||
@@ -972,8 +985,6 @@
|
||||
"Can signin": "可用于登录",
|
||||
"Can signup": "可用于注册",
|
||||
"Can unlink": "可解绑定",
|
||||
"Category": "分类",
|
||||
"Category - Tooltip": "用于对项目或内容进行归类分组的标识",
|
||||
"Channel No.": "Channel号码",
|
||||
"Channel No. - Tooltip": "标识通信或数据传输通道的唯一编号",
|
||||
"Chat ID": "聊天ID",
|
||||
@@ -990,8 +1001,6 @@
|
||||
"Content - Tooltip": "消息、通知或文档中包含的具体信息或数据内容",
|
||||
"DB test": "数据库测试",
|
||||
"DB test - Tooltip": "测试数据库连接是否正常",
|
||||
"Disable SSL": "禁用SSL",
|
||||
"Disable SSL - Tooltip": "与STMP服务器通信时是否禁用SSL协议",
|
||||
"Domain": "域名",
|
||||
"Domain - Tooltip": "对象存储的自定义域名",
|
||||
"Edit Provider": "编辑提供商",
|
||||
@@ -1074,9 +1083,12 @@
|
||||
"SP ACS URL": "SP ACS 网址",
|
||||
"SP ACS URL - Tooltip": "服务提供商(SP)的断言消费者服务(ACS)地址",
|
||||
"SP Entity ID": "SP 实体 ID",
|
||||
"SSL mode": "SSL mode",
|
||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||
"Scene": "场景",
|
||||
"Scene - Tooltip": "表示功能或操作适用的具体业务场景,用于适配不同场景下的逻辑处理",
|
||||
"Scope": "范围",
|
||||
"Scope - Tooltip": "Scope - Tooltip",
|
||||
"Secret access key": "秘密访问密钥",
|
||||
"Secret access key - Tooltip": "与访问密钥配套的私密密钥",
|
||||
"Secret key": "密钥",
|
||||
@@ -1238,6 +1250,9 @@
|
||||
},
|
||||
"syncer": {
|
||||
"API Token / Password": "API Token / Password",
|
||||
"AWS Access Key ID": "AWS Access Key ID",
|
||||
"AWS Region": "AWS Region",
|
||||
"AWS Secret Access Key": "AWS Secret Access Key",
|
||||
"Admin Email": "Admin Email",
|
||||
"Affiliation table": "工作单位表",
|
||||
"Affiliation table - Tooltip": "工作单位的数据库表名",
|
||||
@@ -1269,8 +1284,6 @@
|
||||
"SSH password": "SSH密码",
|
||||
"SSH port": "SSH端口",
|
||||
"SSH user": "SSH用户",
|
||||
"SSL mode": "SSL模式",
|
||||
"SSL mode - Tooltip": "连接数据库采用哪种SSL模式",
|
||||
"Service account key": "Service account key",
|
||||
"Sync interval": "同步间隔",
|
||||
"Sync interval - Tooltip": "单位为秒",
|
||||
|
||||
44
web/src/provider/CaptchaProviderFields.js
Normal file
44
web/src/provider/CaptchaProviderFields.js
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2026 The Casdoor Authors. 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 React from "react";
|
||||
import {Col, Row} from "antd";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import {CaptchaPreview} from "../common/CaptchaPreview";
|
||||
|
||||
export function renderCaptchaProviderFields(provider, providerName) {
|
||||
return (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Preview"), i18next.t("general:Preview - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<CaptchaPreview
|
||||
owner={provider.owner}
|
||||
name={provider.name}
|
||||
provider={provider}
|
||||
providerName={providerName}
|
||||
captchaType={provider.type}
|
||||
subType={provider.subType}
|
||||
clientId={provider.clientId}
|
||||
clientSecret={provider.clientSecret}
|
||||
clientId2={provider.clientId2}
|
||||
clientSecret2={provider.clientSecret2}
|
||||
providerUrl={provider.providerUrl}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
255
web/src/provider/EmailProviderFields.js
Normal file
255
web/src/provider/EmailProviderFields.js
Normal file
@@ -0,0 +1,255 @@
|
||||
// Copyright 2026 The Casdoor Authors. 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 React from "react";
|
||||
import {Button, Col, Input, InputNumber, Row, Select, Switch} from "antd";
|
||||
import {LinkOutlined} from "@ant-design/icons";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import * as ProviderEditTestEmail from "../common/TestEmailWidget";
|
||||
import Editor from "../common/Editor";
|
||||
import HttpHeaderTable from "../table/HttpHeaderTable";
|
||||
|
||||
const {Option} = Select;
|
||||
|
||||
export function renderEmailProviderFields(provider, updateProviderField, renderEmailMappingInput, account) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{
|
||||
["Custom HTTP Email", "SendGrid"].includes(provider.type) ? (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{Setting.getLabel(i18next.t("provider:Endpoint"), i18next.t("provider:Region endpoint for Internet"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input prefix={<LinkOutlined />} value={provider.endpoint} onChange={e => {
|
||||
updateProviderField("endpoint", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>) : null
|
||||
}
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Host"), i18next.t("provider:Host - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input prefix={<LinkOutlined />} value={provider.host} onChange={e => {
|
||||
updateProviderField("host", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
{["Azure ACS", "SendGrid"].includes(provider.type) ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Port"), i18next.t("provider:Port - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<InputNumber value={provider.port} onChange={value => {
|
||||
updateProviderField("port", value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
{["Azure ACS", "SendGrid"].includes(provider.type) ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:SSL mode"), i18next.t("provider:SSL mode - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: "200px"}} value={provider.sslMode || "Auto"} onChange={value => {
|
||||
updateProviderField("sslMode", value);
|
||||
}}>
|
||||
<Option value="Auto">{i18next.t("general:Auto")}</Option>
|
||||
<Option value="Enable">{i18next.t("general:Enable")}</Option>
|
||||
<Option value="Disable">{i18next.t("general:Disable")}</Option>
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Enable proxy"), i18next.t("provider:Enable proxy - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={provider.enableProxy} onChange={checked => {
|
||||
updateProviderField("enableProxy", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
{
|
||||
provider.type === "Custom HTTP Email" ? (
|
||||
<React.Fragment>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Method"), i18next.t("provider:Method - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: "100%"}} value={provider.method} onChange={value => {
|
||||
updateProviderField("method", value);
|
||||
}}>
|
||||
{
|
||||
[
|
||||
{id: "GET", name: "GET"},
|
||||
{id: "POST", name: "POST"},
|
||||
{id: "PUT", name: "PUT"},
|
||||
{id: "DELETE", name: "DELETE"},
|
||||
].map((method, index) => <Option key={index} value={method.id}>{method.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
{
|
||||
provider.method !== "GET" ? (<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("webhook:Content type"), i18next.t("webhook:Content type - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: "100%"}} value={provider.issuerUrl === "" ? "application/x-www-form-urlencoded" : provider.issuerUrl} onChange={value => {
|
||||
updateProviderField("issuerUrl", value);
|
||||
}}>
|
||||
{
|
||||
[
|
||||
{id: "application/json", name: "application/json"},
|
||||
{id: "application/x-www-form-urlencoded", name: "application/x-www-form-urlencoded"},
|
||||
].map((method, index) => <Option key={index} value={method.id}>{method.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>) : null
|
||||
}
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:HTTP header"), i18next.t("provider:HTTP header - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<HttpHeaderTable httpHeaders={provider.httpHeaders} onUpdateTable={(value) => {updateProviderField("httpHeaders", value);}} />
|
||||
</Col>
|
||||
</Row>
|
||||
{provider.method !== "GET" ? <Row style={{marginTop: "20px"}}>
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:HTTP body mapping"), i18next.t("provider:HTTP body mapping - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
{renderEmailMappingInput()}
|
||||
</Col>
|
||||
</Row> : null}
|
||||
</React.Fragment>
|
||||
) : null
|
||||
}
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Email title"), i18next.t("provider:Email title - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.title} onChange={e => {
|
||||
updateProviderField("title", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Email content"), i18next.t("provider:Email content - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Button style={{marginLeft: "10px", marginBottom: "5px"}} onClick={() => updateProviderField("content", "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes. <reset-link>Or click %link to reset</reset-link>")} >
|
||||
{i18next.t("general:Reset to Default")} (Text)
|
||||
</Button>
|
||||
<Button style={{marginLeft: "10px", marginBottom: "5px"}} type="primary" onClick={() => updateProviderField("content", Setting.getDefaultHtmlEmailContent())} >
|
||||
{i18next.t("general:Reset to Default")} (HTML)
|
||||
</Button>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col span={Setting.isMobile() ? 22 : 11}>
|
||||
<div style={{height: "300px", margin: "10px"}}>
|
||||
<Editor
|
||||
value={provider.content}
|
||||
fillHeight
|
||||
dark
|
||||
lang="html"
|
||||
onChange={value => {
|
||||
updateProviderField("content", value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={1} />
|
||||
<Col span={Setting.isMobile() ? 22 : 11}>
|
||||
<div style={{margin: "10px"}}>
|
||||
<div dangerouslySetInnerHTML={{__html: provider.content.replace("%s", "123456").replace("%{user.friendlyName}", Setting.getFriendlyUserName(account))}} />
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(`${i18next.t("provider:Email content")}-${i18next.t("general:Invitations")}`, i18next.t("provider:Email content - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Button style={{marginLeft: "10px", marginBottom: "5px"}} onClick={() => updateProviderField("metadata", "You have invited to join Casdoor. Here is your invitation code: %s, please enter in 5 minutes. Or click %link to signup")} >
|
||||
{i18next.t("general:Reset to Default")} (Text)
|
||||
</Button>
|
||||
<Button style={{marginLeft: "10px", marginBottom: "5px"}} type="primary" onClick={() => updateProviderField("metadata", Setting.getDefaultInvitationHtmlEmailContent())} >
|
||||
{i18next.t("general:Reset to Default")} (HTML)
|
||||
</Button>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col span={Setting.isMobile() ? 22 : 11}>
|
||||
<div style={{height: "300px", margin: "10px"}}>
|
||||
<Editor
|
||||
value={provider.metadata}
|
||||
fillHeight
|
||||
dark
|
||||
lang="html"
|
||||
onChange={value => {
|
||||
updateProviderField("metadata", value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={1} />
|
||||
<Col span={Setting.isMobile() ? 22 : 11}>
|
||||
<div style={{margin: "10px"}}>
|
||||
<div dangerouslySetInnerHTML={{__html: provider.metadata.replace("%code", "123456").replace("%s", "123456")}} />
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}}>
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Test Email"), i18next.t("provider:Test Email - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={4}>
|
||||
<Input value={provider.receiver} placeholder={i18next.t("user:Input your email")}
|
||||
onChange={e => {
|
||||
updateProviderField("receiver", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
{["Azure ACS", "SendGrid"].includes(provider.type) ? null : (
|
||||
<Button style={{marginLeft: "10px", marginBottom: "5px"}} onClick={() => ProviderEditTestEmail.connectSmtpServer(provider)} >
|
||||
{i18next.t("provider:Test SMTP Connection")}
|
||||
</Button>
|
||||
)}
|
||||
<Button style={{marginLeft: "10px", marginBottom: "5px"}} type="primary"
|
||||
disabled={!Setting.isValidEmail(provider.receiver)}
|
||||
onClick={() => ProviderEditTestEmail.sendTestEmail(provider, provider.receiver)} >
|
||||
{i18next.t("provider:Send Testing Email")}
|
||||
</Button>
|
||||
</Row>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
48
web/src/provider/FaceIDProviderFields.js
Normal file
48
web/src/provider/FaceIDProviderFields.js
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2026 The Casdoor Authors. 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 React from "react";
|
||||
import {Col, Input, Row} from "antd";
|
||||
import {LinkOutlined} from "@ant-design/icons";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
|
||||
export function renderFaceIdProviderFields(provider, updateProviderField) {
|
||||
return (
|
||||
<>
|
||||
{["Alibaba Cloud Facebody"].includes(provider.type) ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{Setting.getLabel(i18next.t("provider:Endpoint (Intranet)"), i18next.t("provider:Region endpoint for Intranet"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input prefix={<LinkOutlined />} value={provider.intranetEndpoint} onChange={e => {
|
||||
updateProviderField("intranetEndpoint", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{Setting.getLabel(i18next.t("provider:Endpoint"), i18next.t("provider:Region endpoint for Internet"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input prefix={<LinkOutlined />} value={provider.endpoint} onChange={e => {
|
||||
updateProviderField("endpoint", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
</>
|
||||
);
|
||||
}
|
||||
34
web/src/provider/IDVerificationProviderFields.js
Normal file
34
web/src/provider/IDVerificationProviderFields.js
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2026 The Casdoor Authors. 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 React from "react";
|
||||
import {Col, Input, Row} from "antd";
|
||||
import {LinkOutlined} from "@ant-design/icons";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
|
||||
export function renderIDVerificationProviderFields(provider, updateProviderField) {
|
||||
return (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{Setting.getLabel(i18next.t("provider:Endpoint"), i18next.t("provider:Region endpoint for Internet"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input prefix={<LinkOutlined />} value={provider.endpoint} onChange={e => {
|
||||
updateProviderField("endpoint", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
56
web/src/provider/MfaProviderFields.js
Normal file
56
web/src/provider/MfaProviderFields.js
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2026 The Casdoor Authors. 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 React from "react";
|
||||
import {Col, Input, InputNumber, Row} from "antd";
|
||||
import {LinkOutlined} from "@ant-design/icons";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
|
||||
export function renderMfaProviderFields(provider, updateProviderField) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Host"), i18next.t("provider:Host - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input prefix={<LinkOutlined />} value={provider.host} placeholder="10.10.10.10" onChange={e => {
|
||||
updateProviderField("host", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Port"), i18next.t("provider:Port - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<InputNumber value={provider.port} onChange={value => {
|
||||
updateProviderField("port", value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Client secret"), i18next.t("provider:RADIUS Shared Secret - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.clientSecret} placeholder="Shared secret" onChange={e => {
|
||||
updateProviderField("clientSecret", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
103
web/src/provider/NotificationProviderFields.js
Normal file
103
web/src/provider/NotificationProviderFields.js
Normal file
@@ -0,0 +1,103 @@
|
||||
// Copyright 2026 The Casdoor Authors. 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 React from "react";
|
||||
import {Button, Col, Input, Row, Select} from "antd";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import * as ProviderNotification from "../common/TestNotificationWidget";
|
||||
|
||||
const {Option} = Select;
|
||||
const {TextArea} = Input;
|
||||
|
||||
export function renderNotificationProviderFields(provider, updateProviderField, getReceiverRow) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{["CUCloud"].includes(provider.type) ? (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{["Casdoor"].includes(provider.type) ?
|
||||
Setting.getLabel(i18next.t("general:Application"), i18next.t("general:Application - Tooltip")) :
|
||||
Setting.getLabel(i18next.t("provider:Region ID"), i18next.t("provider:Region ID - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.regionId} onChange={e => {
|
||||
updateProviderField("regionId", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
) : null}
|
||||
{["Custom HTTP"].includes(provider.type) ? (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Method"), i18next.t("provider:Method - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: "100%"}} value={provider.method} onChange={value => {
|
||||
updateProviderField("method", value);
|
||||
}}>
|
||||
{
|
||||
[
|
||||
{id: "GET", name: "GET"},
|
||||
{id: "POST", name: "POST"},
|
||||
].map((method, index) => <Option key={index} value={method.id}>{method.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
) : null}
|
||||
{["Custom HTTP", "CUCloud"].includes(provider.type) ? (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Parameter"), i18next.t("provider:Parameter - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.title} onChange={e => {
|
||||
updateProviderField("title", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
) : null}
|
||||
{["Google Chat", "CUCloud"].includes(provider.type) ? (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Metadata"), i18next.t("provider:Metadata - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<TextArea rows={4} value={provider.metadata} onChange={e => {
|
||||
updateProviderField("metadata", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
) : null}
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Content"), i18next.t("provider:Content - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<TextArea autoSize={{minRows: 3, maxRows: 100}} value={provider.content} onChange={e => {
|
||||
updateProviderField("content", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
{getReceiverRow(provider)}
|
||||
<Button style={{marginLeft: "10px", marginBottom: "5px"}} type="primary"
|
||||
onClick={() => ProviderNotification.sendTestNotification(provider)} >
|
||||
{i18next.t("provider:Send Testing Notification")}
|
||||
</Button>
|
||||
</Row>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
218
web/src/provider/OAuthProviderFields.js
Normal file
218
web/src/provider/OAuthProviderFields.js
Normal file
@@ -0,0 +1,218 @@
|
||||
// Copyright 2026 The Casdoor Authors. 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 React from "react";
|
||||
import {Col, Input, Radio, Row, Switch} from "antd";
|
||||
import {LinkOutlined} from "@ant-design/icons";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
|
||||
const {TextArea} = Input;
|
||||
|
||||
export function renderOAuthProviderFields(provider, updateProviderField, renderUserMappingInput) {
|
||||
const getDomainLabel = provider => {
|
||||
switch (provider.category) {
|
||||
case "OAuth":
|
||||
if (provider.type === "AzureAD" || provider.type === "AzureADB2C") {
|
||||
return Setting.getLabel(i18next.t("provider:Tenant ID"), i18next.t("provider:Tenant ID - Tooltip"));
|
||||
} else {
|
||||
return Setting.getLabel(i18next.t("provider:Domain"), i18next.t("provider:Domain - Tooltip"));
|
||||
}
|
||||
default:
|
||||
return Setting.getLabel(i18next.t("provider:Domain"), i18next.t("provider:Domain - Tooltip"));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Email regex"), i18next.t("provider:Email regex - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<TextArea rows={4} value={provider.emailRegex} onChange={e => {
|
||||
updateProviderField("emailRegex", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
{
|
||||
provider.type !== "WeChat" ? null : (
|
||||
<React.Fragment>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Use WeChat Media Platform in PC"), i18next.t("provider:Use WeChat Media Platform in PC - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch disabled={!provider.clientId} checked={provider.disableSsl} onChange={checked => {
|
||||
updateProviderField("disableSsl", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("token:Access token"), i18next.t("token:Access token - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.content} disabled={!provider.disableSsl || !provider.clientId2} onChange={e => {
|
||||
updateProviderField("content", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Follow-up action"), i18next.t("provider:Follow-up action - Tooltip"))} :
|
||||
</Col>
|
||||
<Col>
|
||||
<Radio.Group value={provider.signName}
|
||||
disabled={!provider.disableSsl || !provider.clientId || !provider.clientId2}
|
||||
buttonStyle="solid"
|
||||
onChange={e => {
|
||||
updateProviderField("signName", e.target.value);
|
||||
}}>
|
||||
<Radio.Button value="open">{i18next.t("provider:Use WeChat Open Platform to login")}</Radio.Button>
|
||||
<Radio.Button value="media">{i18next.t("provider:Use WeChat Media Platform to login")}</Radio.Button>
|
||||
</Radio.Group>
|
||||
</Col>
|
||||
</Row>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
{
|
||||
provider.type !== "ADFS" && provider.type !== "AzureAD"
|
||||
&& provider.type !== "AzureADB2C" && (provider.type !== "Casdoor" && provider.category !== "Storage")
|
||||
&& provider.type !== "Okta" && provider.type !== "Nextcloud" ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{getDomainLabel(provider)} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input prefix={<LinkOutlined />} value={provider.domain} onChange={e => {
|
||||
updateProviderField("domain", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
{
|
||||
provider.type !== "Google" && provider.type !== "Lark" ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{provider.type === "Google" ?
|
||||
Setting.getLabel(i18next.t("provider:Get phone number"), i18next.t("provider:Get phone number - Tooltip"))
|
||||
: Setting.getLabel(i18next.t("provider:Use global endpoint"), i18next.t("provider:Use global endpoint - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch disabled={!provider.clientId} checked={provider.disableSsl} onChange={checked => {
|
||||
updateProviderField("disableSsl", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
{
|
||||
provider.type.startsWith("Custom") ? (
|
||||
<React.Fragment>
|
||||
<Col>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Auth URL"), i18next.t("provider:Auth URL - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.customAuthUrl} onChange={e => {
|
||||
updateProviderField("customAuthUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Token URL"), i18next.t("provider:Token URL - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.customTokenUrl} onChange={e => {
|
||||
updateProviderField("customTokenUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Scope"), i18next.t("provider:Scope - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.scopes} onChange={e => {
|
||||
updateProviderField("scopes", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:UserInfo URL"), i18next.t("provider:UserInfo URL - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.customUserInfoUrl} onChange={e => {
|
||||
updateProviderField("customUserInfoUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Enable PKCE"), i18next.t("provider:Enable PKCE - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Switch checked={provider.enablePkce} onChange={checked => {
|
||||
updateProviderField("enablePkce", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:User mapping"), i18next.t("provider:User mapping - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
{renderUserMappingInput()}
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Favicon"), i18next.t("general:Favicon - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 1}>
|
||||
{Setting.getLabel(i18next.t("general:URL"), i18next.t("general:URL - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={23} >
|
||||
<Input prefix={<LinkOutlined />} value={provider.customLogo} onChange={e => {
|
||||
updateProviderField("customLogo", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 1}>
|
||||
{i18next.t("general:Preview")}:
|
||||
</Col>
|
||||
<Col span={23} >
|
||||
<a target="_blank" rel="noreferrer" href={provider.customLogo}>
|
||||
<img src={provider.customLogo} alt={provider.customLogo} height={90} style={{marginBottom: "20px"}} />
|
||||
</a>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</React.Fragment>
|
||||
) : null
|
||||
}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
72
web/src/provider/PaymentProviderFields.js
Normal file
72
web/src/provider/PaymentProviderFields.js
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2026 The Casdoor Authors. 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 React from "react";
|
||||
import {Col, Input, Row, Select} from "antd";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import {LinkOutlined} from "@ant-design/icons";
|
||||
|
||||
const {Option} = Select;
|
||||
|
||||
export function renderPaymentProviderFields(provider, updateProviderField, certs) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{
|
||||
(provider.type === "Alipay" || provider.type === "WeChat Pay" || provider.type === "Casdoor") ? (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Cert"), i18next.t("general:Cert - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: "100%"}} value={provider.cert} onChange={(value => {updateProviderField("cert", value);})}>
|
||||
{
|
||||
certs.map((cert, index) => <Option key={index} value={cert.name}>{cert.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
) : null
|
||||
}
|
||||
{
|
||||
(provider.type === "Alipay") ? (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Root cert"), i18next.t("general:Root cert - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: "100%"}} value={provider.metadata} onChange={(value => {updateProviderField("metadata", value);})}>
|
||||
{
|
||||
certs.map((cert, index) => <Option key={index} value={cert.name}>{cert.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
) : null
|
||||
}
|
||||
{(provider.type === "GC" || provider.type === "FastSpring") ? (
|
||||
<Row style={{marginTop: "20px"}}>
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Host"), i18next.t("provider:Host - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<Input prefix={<LinkOutlined />} value={provider.host} onChange={e => {
|
||||
updateProviderField("host", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
) : null}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
133
web/src/provider/SamlProviderFields.js
Normal file
133
web/src/provider/SamlProviderFields.js
Normal file
@@ -0,0 +1,133 @@
|
||||
// Copyright 2026 The Casdoor Authors. 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 React from "react";
|
||||
import {Button, Col, Input, Row, Switch} from "antd";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import {authConfig} from "../auth/Auth";
|
||||
import copy from "copy-to-clipboard";
|
||||
|
||||
const {TextArea} = Input;
|
||||
|
||||
export function renderSamlProviderFields(provider, updateProviderField, metadataConfig) {
|
||||
const {requestUrl, setRequestUrl, metadataLoading, fetchSamlMetadata, parseSamlMetadata} = metadataConfig;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Sign request"), i18next.t("provider:Sign request - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Switch checked={provider.enableSignAuthnRequest} onChange={checked => {
|
||||
updateProviderField("enableSignAuthnRequest", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Metadata url"), i18next.t("provider:Metadata url - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={6} >
|
||||
<Input value={requestUrl} onChange={e => {
|
||||
setRequestUrl(e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
<Col span={16} >
|
||||
<Button style={{marginLeft: "10px"}} type="primary" loading={metadataLoading} onClick={() => {fetchSamlMetadata();}}>{i18next.t("general:Request")}</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Metadata"), i18next.t("provider:Metadata - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<TextArea rows={4} value={provider.metadata} onChange={e => {
|
||||
updateProviderField("metadata", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}}>
|
||||
<Col style={{marginTop: "5px"}} span={2} />
|
||||
<Col span={2}>
|
||||
<Button type="primary" onClick={() => {parseSamlMetadata();}}>
|
||||
{i18next.t("provider:Parse")}
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Endpoint"), i18next.t("provider:SAML 2.0 Endpoint (HTTP)"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.endpoint} onChange={e => {
|
||||
updateProviderField("endpoint", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:IdP"), i18next.t("provider:IdP certificate"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.idP} onChange={e => {
|
||||
updateProviderField("idP", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Issuer URL"), i18next.t("provider:Issuer URL - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.issuerUrl} onChange={e => {
|
||||
updateProviderField("issuerUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:SP ACS URL"), i18next.t("provider:SP ACS URL - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<Input value={`${authConfig.serverUrl}/api/acs`} readOnly="readonly" />
|
||||
</Col>
|
||||
<Col span={1}>
|
||||
<Button type="primary" onClick={() => {
|
||||
copy(`${authConfig.serverUrl}/api/acs`);
|
||||
Setting.showMessage("success", i18next.t("general:Copied to clipboard successfully"));
|
||||
}}>
|
||||
{i18next.t("general:Copy")}
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:SP Entity ID"), i18next.t("provider:SP Entity ID - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={21} >
|
||||
<Input value={`${authConfig.serverUrl}/api/acs`} readOnly="readonly" />
|
||||
</Col>
|
||||
<Col span={1}>
|
||||
<Button type="primary" onClick={() => {
|
||||
copy(`${authConfig.serverUrl}/api/acs`);
|
||||
Setting.showMessage("success", i18next.t("general:Copied to clipboard successfully"));
|
||||
}}>
|
||||
{i18next.t("general:Copy")}
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
182
web/src/provider/SmsProviderFields.js
Normal file
182
web/src/provider/SmsProviderFields.js
Normal file
@@ -0,0 +1,182 @@
|
||||
// Copyright 2026 The Casdoor Authors. 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 React from "react";
|
||||
import {Button, Col, Input, Row, Select, Switch} from "antd";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import * as ProviderEditTestSms from "../common/TestSmsWidget";
|
||||
import {CountryCodeSelect} from "../common/select/CountryCodeSelect";
|
||||
import HttpHeaderTable from "../table/HttpHeaderTable";
|
||||
import {LinkOutlined} from "@ant-design/icons";
|
||||
|
||||
const {Option} = Select;
|
||||
|
||||
const SMS_PROVIDERS_WITHOUT_SIGN_NAME = ["Custom HTTP SMS", "Twilio SMS", "Amazon SNS", "Msg91 SMS", "Infobip SMS"];
|
||||
const SMS_PROVIDERS_WITHOUT_TEMPLATE_CODE = ["Infobip SMS", "Custom HTTP SMS"];
|
||||
|
||||
export function renderSmsProviderFields(provider, updateProviderField, renderSmsMappingInput, account) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{SMS_PROVIDERS_WITHOUT_SIGN_NAME.includes(provider.type) ?
|
||||
null :
|
||||
(<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Sign Name"), i18next.t("provider:Sign Name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.signName} onChange={e => {
|
||||
updateProviderField("signName", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
{SMS_PROVIDERS_WITHOUT_TEMPLATE_CODE.includes(provider.type) ?
|
||||
null :
|
||||
(<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Template code"), i18next.t("provider:Template code - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.templateCode} onChange={e => {
|
||||
updateProviderField("templateCode", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
{
|
||||
provider.type === "Custom HTTP SMS" ? (
|
||||
<React.Fragment>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{Setting.getLabel(i18next.t("provider:Endpoint"), i18next.t("provider:Region endpoint for Internet"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input prefix={<LinkOutlined />} value={provider.endpoint} onChange={e => {
|
||||
updateProviderField("endpoint", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Method"), i18next.t("provider:Method - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: "100%"}} value={provider.method} onChange={value => {
|
||||
updateProviderField("method", value);
|
||||
}}>
|
||||
{
|
||||
[
|
||||
{id: "GET", name: "GET"},
|
||||
{id: "POST", name: "POST"},
|
||||
{id: "PUT", name: "PUT"},
|
||||
{id: "DELETE", name: "DELETE"},
|
||||
].map((method, index) => <Option key={index} value={method.id}>{method.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
{
|
||||
provider.method !== "GET" ? (<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("webhook:Content type"), i18next.t("webhook:Content type - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: "100%"}} value={provider.issuerUrl === "" ? "application/x-www-form-urlencoded" : provider.issuerUrl} onChange={value => {
|
||||
updateProviderField("issuerUrl", value);
|
||||
}}>
|
||||
{
|
||||
[
|
||||
{id: "application/json", name: "application/json"},
|
||||
{id: "application/x-www-form-urlencoded", name: "application/x-www-form-urlencoded"},
|
||||
].map((method, index) => <Option key={index} value={method.id}>{method.name}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>) : null
|
||||
}
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:HTTP header"), i18next.t("provider:HTTP header - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<HttpHeaderTable httpHeaders={provider.httpHeaders} onUpdateTable={(value) => {updateProviderField("httpHeaders", value);}} />
|
||||
</Col>
|
||||
</Row>
|
||||
{provider.method !== "GET" ? <Row style={{marginTop: "20px"}}>
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:HTTP body mapping"), i18next.t("provider:HTTP body mapping - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
{renderSmsMappingInput()}
|
||||
</Col>
|
||||
</Row> : null}
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Parameter"), i18next.t("provider:Parameter - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.title} onChange={e => {
|
||||
updateProviderField("title", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
</React.Fragment>
|
||||
) : null
|
||||
}
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Enable proxy"), i18next.t("provider:Enable proxy - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={provider.enableProxy} onChange={checked => {
|
||||
updateProviderField("enableProxy", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:SMS Test"), i18next.t("provider:SMS Test - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={4} >
|
||||
<Input.Group compact>
|
||||
<CountryCodeSelect
|
||||
style={{width: "90px"}}
|
||||
initValue={provider.content}
|
||||
onChange={(value) => {
|
||||
updateProviderField("content", value);
|
||||
}}
|
||||
countryCodes={account.organization.countryCodes}
|
||||
/>
|
||||
<Input value={provider.receiver}
|
||||
style={{width: "150px"}}
|
||||
placeholder = {i18next.t("user:Input your phone number")}
|
||||
onChange={e => {
|
||||
updateProviderField("receiver", e.target.value);
|
||||
}} />
|
||||
</Input.Group>
|
||||
</Col>
|
||||
<Col span={2} >
|
||||
<Button style={{marginLeft: "10px", marginBottom: "5px"}} type="primary"
|
||||
disabled={!Setting.isValidPhone(provider.receiver) || (provider.type === "Custom HTTP SMS" && provider.endpoint === "")}
|
||||
onClick={() => ProviderEditTestSms.sendTestSms(provider, "+" + Setting.getCountryCode(provider.content) + provider.receiver)} >
|
||||
{i18next.t("provider:Send Testing SMS")}
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
112
web/src/provider/StorageProviderFields.js
Normal file
112
web/src/provider/StorageProviderFields.js
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright 2026 The Casdoor Authors. 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 React from "react";
|
||||
import {Col, Input, Row} from "antd";
|
||||
import {LinkOutlined} from "@ant-design/icons";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
|
||||
export function renderStorageProviderFields(provider, updateProviderField) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{["Local File System", "MinIO", "Tencent Cloud COS", "Google Cloud Storage", "Qiniu Cloud Kodo", "Synology", "Casdoor"].includes(provider.type) ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{Setting.getLabel(i18next.t("provider:Endpoint (Intranet)"), i18next.t("provider:Region endpoint for Intranet"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input prefix={<LinkOutlined />} value={provider.intranetEndpoint} onChange={e => {
|
||||
updateProviderField("intranetEndpoint", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
{["Local File System"].includes(provider.type) ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{Setting.getLabel(i18next.t("provider:Endpoint"), i18next.t("provider:Region endpoint for Internet"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input prefix={<LinkOutlined />} value={provider.endpoint} onChange={e => {
|
||||
updateProviderField("endpoint", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
{["Local File System"].includes(provider.type) ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{["Casdoor"].includes(provider.type) ?
|
||||
Setting.getLabel(i18next.t("general:Provider"), i18next.t("general:Provider - Tooltip"))
|
||||
: Setting.getLabel(i18next.t("provider:Bucket"), i18next.t("provider:Bucket - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.bucket} onChange={e => {
|
||||
updateProviderField("bucket", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{Setting.getLabel(i18next.t("provider:Path prefix"), i18next.t("provider:Path prefix - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.pathPrefix} onChange={e => {
|
||||
updateProviderField("pathPrefix", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
{["Synology", "Casdoor"].includes(provider.type) ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{Setting.getLabel(i18next.t("provider:Domain"), i18next.t("provider:Domain - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input prefix={<LinkOutlined />} value={provider.domain} disabled={provider.type === "Local File System"} onChange={e => {
|
||||
updateProviderField("domain", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
{["Casdoor"].includes(provider.type) ? (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.content} onChange={e => {
|
||||
updateProviderField("content", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
) : null}
|
||||
{["AWS S3", "Tencent Cloud COS", "Qiniu Cloud Kodo", "Casdoor", "CUCloud OSS", "MinIO"].includes(provider.type) ? (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={2}>
|
||||
{["Casdoor"].includes(provider.type) ?
|
||||
Setting.getLabel(i18next.t("general:Application"), i18next.t("general:Application - Tooltip")) :
|
||||
Setting.getLabel(i18next.t("provider:Region ID"), i18next.t("provider:Region ID - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.regionId} onChange={e => {
|
||||
updateProviderField("regionId", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
) : null}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
48
web/src/provider/Web3ProviderFields.js
Normal file
48
web/src/provider/Web3ProviderFields.js
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2026 The Casdoor Authors. 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 React from "react";
|
||||
import {Checkbox, Col, Row} from "antd";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import * as Web3Auth from "../auth/Web3Auth";
|
||||
|
||||
export function renderWeb3ProviderFields(provider, updateProviderField) {
|
||||
const getWalletValue = () => {
|
||||
try {
|
||||
return JSON.parse(provider.metadata);
|
||||
} catch {
|
||||
return ["injected"];
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
provider.type === "Web3Onboard" ? (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Wallets"), i18next.t("provider:Wallets - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<Checkbox.Group
|
||||
options={Web3Auth.getWeb3OnboardWalletsOptions()}
|
||||
value={getWalletValue()}
|
||||
onChange={options => {
|
||||
updateProviderField("metadata", JSON.stringify(options));
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
) : null
|
||||
);
|
||||
}
|
||||
@@ -14,12 +14,16 @@
|
||||
|
||||
import React from "react";
|
||||
import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
|
||||
import {Button, Col, Input, Row, Select, Table, Tooltip} from "antd";
|
||||
import {AutoComplete, Button, Col, Input, Row, Table, Tooltip} from "antd";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import RegionSelect from "../common/select/RegionSelect";
|
||||
|
||||
const {Option} = Select;
|
||||
const TAG_OPTIONS = [
|
||||
{value: "Home", label: "Home"},
|
||||
{value: "Work", label: "Work"},
|
||||
{value: "Other", label: "Other"},
|
||||
];
|
||||
|
||||
class AddressTable extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -86,16 +90,20 @@ class AddressTable extends React.Component {
|
||||
key: "tag",
|
||||
width: "100px",
|
||||
render: (text, record, index) => {
|
||||
const tagOptions = TAG_OPTIONS.map(opt => ({...opt, label: opt.value === "Home" ? i18next.t("general:Home") : opt.value === "Work" ? i18next.t("user:Work") : i18next.t("user:Other")}));
|
||||
return (
|
||||
<Select virtual={false} style={{width: "100%"}}
|
||||
value={text}
|
||||
<AutoComplete
|
||||
size="small"
|
||||
style={{width: "100%"}}
|
||||
value={text || ""}
|
||||
options={tagOptions}
|
||||
onChange={value => {
|
||||
this.updateField(table, index, "tag", value);
|
||||
}} >
|
||||
<Option value="Home">{i18next.t("general:Home")}</Option>
|
||||
<Option value="Work">{i18next.t("user:Work")}</Option>
|
||||
<Option value="Other">{i18next.t("user:Other")}</Option>
|
||||
</Select>
|
||||
}}
|
||||
onSelect={value => {
|
||||
this.updateField(table, index, "tag", value);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
@@ -106,7 +114,7 @@ class AddressTable extends React.Component {
|
||||
width: "150px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Input value={text} onChange={e => {
|
||||
<Input size="small" value={text} onChange={e => {
|
||||
this.updateField(table, index, "line1", e.target.value);
|
||||
}} />
|
||||
);
|
||||
@@ -119,7 +127,7 @@ class AddressTable extends React.Component {
|
||||
width: "150px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Input value={text} onChange={e => {
|
||||
<Input size="small" value={text} onChange={e => {
|
||||
this.updateField(table, index, "line2", e.target.value);
|
||||
}} />
|
||||
);
|
||||
@@ -132,7 +140,7 @@ class AddressTable extends React.Component {
|
||||
width: "120px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Input value={text} onChange={e => {
|
||||
<Input size="small" value={text} onChange={e => {
|
||||
this.updateField(table, index, "city", e.target.value);
|
||||
}} />
|
||||
);
|
||||
@@ -145,7 +153,7 @@ class AddressTable extends React.Component {
|
||||
width: "100px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Input value={text} onChange={e => {
|
||||
<Input size="small" value={text} onChange={e => {
|
||||
this.updateField(table, index, "state", e.target.value);
|
||||
}} />
|
||||
);
|
||||
@@ -158,7 +166,7 @@ class AddressTable extends React.Component {
|
||||
width: "100px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Input value={text} onChange={e => {
|
||||
<Input size="small" value={text} onChange={e => {
|
||||
this.updateField(table, index, "zipCode", e.target.value);
|
||||
}} />
|
||||
);
|
||||
@@ -172,6 +180,7 @@ class AddressTable extends React.Component {
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<RegionSelect
|
||||
size="small"
|
||||
value={text}
|
||||
onChange={value => {
|
||||
this.updateField(table, index, "region", value);
|
||||
|
||||
@@ -21,7 +21,7 @@ class CartTable extends React.Component {
|
||||
render() {
|
||||
const columns = [
|
||||
{
|
||||
title: i18next.t("product:Name"),
|
||||
title: i18next.t("general:Name"),
|
||||
dataIndex: "displayName",
|
||||
key: "displayName",
|
||||
width: "200px",
|
||||
@@ -43,7 +43,7 @@ class CartTable extends React.Component {
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("product:Price"),
|
||||
title: i18next.t("order:Price"),
|
||||
dataIndex: "price",
|
||||
key: "price",
|
||||
width: "120px",
|
||||
|
||||
@@ -86,7 +86,7 @@ class ManagedAccountTable extends React.Component {
|
||||
render: (text, record, index) => {
|
||||
const items = this.props.applications;
|
||||
return (
|
||||
<Select virtual={false} style={{width: "100%"}}
|
||||
<Select virtual={false} size="small" style={{width: "100%"}}
|
||||
value={text}
|
||||
onChange={value => {
|
||||
this.updateField(table, index, "application", value);
|
||||
@@ -105,7 +105,7 @@ class ManagedAccountTable extends React.Component {
|
||||
// width: "420px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Input prefix={<LinkOutlined />} value={text} onChange={e => {
|
||||
<Input size="small" prefix={<LinkOutlined />} value={text} onChange={e => {
|
||||
this.updateField(table, index, "signinUrl", e.target.value);
|
||||
}} />
|
||||
);
|
||||
@@ -118,7 +118,7 @@ class ManagedAccountTable extends React.Component {
|
||||
width: "200px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Input value={text} onChange={e => {
|
||||
<Input size="small" value={text} onChange={e => {
|
||||
this.updateField(table, index, "username", e.target.value);
|
||||
}} />
|
||||
);
|
||||
@@ -131,7 +131,7 @@ class ManagedAccountTable extends React.Component {
|
||||
width: "200px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Input.Password value={text} onChange={e => {
|
||||
<Input.Password size="small" value={text} onChange={e => {
|
||||
this.updateField(table, index, "password", e.target.value);
|
||||
}} />
|
||||
);
|
||||
|
||||
@@ -86,7 +86,7 @@ class MfaAccountTable extends React.Component {
|
||||
width: "400px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Input value={text} onChange={e => {
|
||||
<Input size="small" value={text} onChange={e => {
|
||||
this.updateField(table, index, "accountName", e.target.value);
|
||||
}} />
|
||||
);
|
||||
@@ -99,7 +99,7 @@ class MfaAccountTable extends React.Component {
|
||||
width: "300px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Input value={text} onChange={e => {
|
||||
<Input size="small" value={text} onChange={e => {
|
||||
this.updateField(table, index, "issuer", e.target.value);
|
||||
}} />
|
||||
);
|
||||
@@ -111,7 +111,7 @@ class MfaAccountTable extends React.Component {
|
||||
key: "origin",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Input value={text} onChange={e => {
|
||||
<Input size="small" value={text} onChange={e => {
|
||||
this.updateField(table, index, "origin", e.target.value);
|
||||
}} />
|
||||
);
|
||||
@@ -123,7 +123,7 @@ class MfaAccountTable extends React.Component {
|
||||
key: "secretKey",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Input.Password value={text} onChange={e => {
|
||||
<Input.Password size="small" value={text} onChange={e => {
|
||||
this.updateField(table, index, "secretKey", e.target.value);
|
||||
}} />
|
||||
);
|
||||
|
||||
@@ -84,7 +84,7 @@ class MfaTable extends React.Component {
|
||||
key: "name",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Select virtual={false} style={{width: "100%"}}
|
||||
<Select virtual={false} size="small" style={{width: "100%"}}
|
||||
value={text}
|
||||
onChange={value => {
|
||||
this.updateField(table, index, "name", value);
|
||||
@@ -103,7 +103,7 @@ class MfaTable extends React.Component {
|
||||
width: "100px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Select virtual={false} style={{width: "100%"}}
|
||||
<Select virtual={false} size="small" style={{width: "100%"}}
|
||||
value={text}
|
||||
defaultValue="Optional"
|
||||
options={RuleItems.map((item) =>
|
||||
|
||||
@@ -104,13 +104,23 @@ class ProviderTable extends React.Component {
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("provider:Category"),
|
||||
title: i18next.t("general:Category"),
|
||||
dataIndex: "category",
|
||||
key: "category",
|
||||
width: "100px",
|
||||
render: (text, record, index) => {
|
||||
const provider = Setting.getArrayItem(this.props.providers, "name", record.name);
|
||||
return provider?.category;
|
||||
const owner = provider?.owner || this.getUserOrganization()?.name;
|
||||
const editUrl = provider && owner && provider.name ? `/providers/${owner}/${provider.name}` : null;
|
||||
const categoryText = provider?.category;
|
||||
if (editUrl && categoryText) {
|
||||
return (
|
||||
<a href={editUrl} target="_blank" rel="noopener noreferrer">
|
||||
{categoryText}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
return categoryText;
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -120,7 +130,17 @@ class ProviderTable extends React.Component {
|
||||
width: "80px",
|
||||
render: (text, record, index) => {
|
||||
const provider = Setting.getArrayItem(this.props.providers, "name", record.name);
|
||||
return Provider.getProviderLogoWidget(provider);
|
||||
const owner = provider?.owner || this.getUserOrganization()?.name;
|
||||
const editUrl = provider && owner && provider.name ? `/providers/${owner}/${provider.name}` : null;
|
||||
const typeWidget = Provider.getProviderLogoWidget(provider, {disableLink: !!editUrl});
|
||||
if (editUrl && typeWidget) {
|
||||
return (
|
||||
<a href={editUrl} target="_blank" rel="noopener noreferrer">
|
||||
{typeWidget}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
return typeWidget;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -131,13 +131,18 @@ class TransactionTable extends React.Component {
|
||||
columns={columns}
|
||||
dataSource={this.props.transactions}
|
||||
rowKey={(record) => `${record.owner}/${record.name}`}
|
||||
size="small"
|
||||
size="middle"
|
||||
bordered
|
||||
pagination={{
|
||||
pageSize: 10,
|
||||
showSizeChanger: true,
|
||||
pageSizeOptions: ["10", "20", "50", "100"],
|
||||
}}
|
||||
title={this.props.title ? () => (
|
||||
<div>
|
||||
{this.props.title}
|
||||
</div>
|
||||
) : undefined}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ export function getTransactionTableColumns(options = {}) {
|
||||
});
|
||||
|
||||
columns.push({
|
||||
title: i18next.t("provider:Category"),
|
||||
title: i18next.t("general:Category"),
|
||||
dataIndex: "category",
|
||||
key: "category",
|
||||
width: "120px",
|
||||
|
||||
Reference in New Issue
Block a user