Compare commits

...

5 Commits

Author SHA1 Message Date
a8699d0b87 feat: use React routing to remove spin between signup and signin pages (#2740)
* fix: Regarding the color of loading

* fix: use goToLinkSoft and use same code format with result and forget psw

* fix: update signup url
2024-02-24 12:59:09 +08:00
6621d693de feat: revert "feat: use i18next-resources-to-backend to lazy load i18n" (#2739)
This reverts commit dc3131c683.
2024-02-23 23:38:49 +08:00
dc3131c683 feat: use i18next-resources-to-backend to lazy load i18n (#2738)
* feat: use i18next-resources-to-backend to lazy load i18n file

* feat: change source in yarn.lock
2024-02-23 22:35:59 +08:00
042a8d0ad6 feat: add rule for SMS and Email provider (#2733)
* add phonecoderule

* feat:add phone code rule

* feat: add email rule

* fix: merge
2024-02-23 00:09:37 +08:00
44abfb3430 feat: support custom header HTML in entry pages (#2731) 2024-02-22 17:56:47 +08:00
34 changed files with 225 additions and 45 deletions

View File

@ -164,7 +164,7 @@ func (c *ApiController) SendVerificationCode() {
c.SetSession(MfaDestSession, vform.Dest)
}
provider, err = application.GetEmailProvider()
provider, err = application.GetEmailProvider(vform.Method)
if err != nil {
c.ResponseError(err.Error())
return
@ -210,7 +210,7 @@ func (c *ApiController) SendVerificationCode() {
vform.CountryCode = mfaProps.CountryCode
}
provider, err = application.GetSmsProvider()
provider, err = application.GetSmsProvider(vform.Method)
if err != nil {
c.ResponseError(err.Error())
return

View File

@ -66,6 +66,7 @@ type Application struct {
Description string `xorm:"varchar(100)" json:"description"`
Organization string `xorm:"varchar(100)" json:"organization"`
Cert string `xorm:"varchar(100)" json:"cert"`
HeaderHtml string `xorm:"mediumtext" json:"headerHtml"`
EnablePassword bool `json:"enablePassword"`
EnableSignUp bool `json:"enableSignUp"`
EnableSigninSession bool `json:"enableSigninSession"`

View File

@ -38,12 +38,38 @@ func (application *Application) GetProviderByCategory(category string) (*Provide
return nil, nil
}
func (application *Application) GetEmailProvider() (*Provider, error) {
return application.GetProviderByCategory("Email")
func (application *Application) GetProviderByCategoryAndRule(category string, method string) (*Provider, error) {
providers, err := GetProviders(application.Organization)
if err != nil {
return nil, err
}
m := map[string]*Provider{}
for _, provider := range providers {
if provider.Category != category {
continue
}
m[provider.Name] = provider
}
for _, providerItem := range application.Providers {
if providerItem.Rule == method || providerItem.Rule == "all" {
if provider, ok := m[providerItem.Name]; ok {
return provider, nil
}
}
}
return nil, nil
}
func (application *Application) GetSmsProvider() (*Provider, error) {
return application.GetProviderByCategory("SMS")
func (application *Application) GetEmailProvider(method string) (*Provider, error) {
return application.GetProviderByCategoryAndRule("Email", method)
}
func (application *Application) GetSmsProvider(method string) (*Provider, error) {
return application.GetProviderByCategoryAndRule("SMS", method)
}
func (application *Application) GetStorageProvider() (*Provider, error) {

View File

@ -865,6 +865,28 @@ class ApplicationEditPage extends React.Component {
}
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("application:Header HTML"), i18next.t("application:Header HTML - Tooltip"))} :
</Col>
<Col span={22} >
<Popover placement="right" content={
<div style={{width: "900px", height: "300px"}} >
<CodeMirror
value={this.state.application.headerHtml}
options={{mode: "htmlmixed", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {
this.updateApplicationField("headerHtml", value);
}}
/>
</div>
} title={i18next.t("application:Header HTML - Edit")} trigger="click">
<Input value={this.state.application.headerHtml} style={{marginBottom: "10px"}} onChange={e => {
this.updateApplicationField("headerHtml", e.target.value);
}} />
</Popover>
</Col>
</Row>
{
<React.Fragment>
<Row style={{marginTop: "20px"}} >

View File

@ -32,6 +32,7 @@ import {authConfig} from "./auth/Auth";
import ProductBuyPage from "./ProductBuyPage";
import PaymentResultPage from "./PaymentResultPage";
import QrCodePage from "./QrCodePage";
import CustomHead from "./basic/CustomHead";
class EntryPage extends React.Component {
constructor(props) {
@ -66,7 +67,6 @@ class EntryPage extends React.Component {
this.setState({
application: application,
});
const themeData = application !== null ? Setting.getThemeData(application.organizationObj, application) : Conf.ThemeDefault;
this.props.updataThemeData(themeData);
};
@ -82,7 +82,6 @@ class EntryPage extends React.Component {
Setting.showMessage("error", res.msg);
return;
}
const application = res.data;
const themeData = application !== null ? Setting.getThemeData(application.organizationObj, application) : Conf.ThemeDefault;
this.props.updataThemeData(themeData);
@ -90,32 +89,35 @@ class EntryPage extends React.Component {
};
return (
<div className="loginBackground"
style={{backgroundImage: Setting.inIframe() || Setting.isMobile() ? null : `url(${this.state.application?.formBackgroundUrl})`}}>
<Spin size="large" spinning={this.state.application === undefined && this.state.pricing === undefined} tip={i18next.t("login:Loading")}
style={{margin: "0 auto"}} />
<Switch>
<Route exact path="/signup" render={(props) => this.renderHomeIfLoggedIn(<SignupPage {...this.props} application={this.state.application} applicationName={authConfig.appName} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/signup/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<SignupPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/login" render={(props) => this.renderHomeIfLoggedIn(<SelfLoginPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/login/:owner" render={(props) => this.renderHomeIfLoggedIn(<SelfLoginPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/signup/oauth/authorize" render={(props) => <SignupPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />} />
<Route exact path="/login/oauth/authorize" render={(props) => <LoginPage {...this.props} application={this.state.application} type={"code"} mode={"signin"} onUpdateApplication={onUpdateApplication} {...props} />} />
<Route exact path="/login/saml/authorize/:owner/:applicationName" render={(props) => <LoginPage {...this.props} application={this.state.application} type={"saml"} mode={"signin"} onUpdateApplication={onUpdateApplication} {...props} />} />
<Route exact path="/forget" render={(props) => this.renderHomeIfLoggedIn(<SelfForgetPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/forget/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<ForgetPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/prompt" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/prompt/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/result" render={(props) => this.renderHomeIfLoggedIn(<ResultPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/result/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<ResultPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/cas/:owner/:casApplicationName/logout" render={(props) => this.renderHomeIfLoggedIn(<CasLogout {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/cas/:owner/:casApplicationName/login" render={(props) => {return (<LoginPage {...this.props} application={this.state.application} type={"cas"} mode={"signin"} onUpdateApplication={onUpdateApplication} {...props} />);}} />
<Route exact path="/select-plan/:owner/:pricingName" render={(props) => <PricingPage {...this.props} pricing={this.state.pricing} onUpdatePricing={onUpdatePricing} {...props} />} />
<Route exact path="/buy-plan/:owner/:pricingName" render={(props) => <ProductBuyPage {...this.props} pricing={this.state.pricing} onUpdatePricing={onUpdatePricing} {...props} />} />
<Route exact path="/buy-plan/:owner/:pricingName/result" render={(props) => <PaymentResultPage {...this.props} pricing={this.state.pricing} onUpdatePricing={onUpdatePricing} {...props} />} />
<Route exact path="/qrcode/:owner/:paymentName" render={(props) => <QrCodePage {...this.props} onUpdateApplication={onUpdateApplication} {...props} />} />
</Switch>
</div>
<React.Fragment>
<CustomHead headerHtml={this.state.application?.headerHtml} />
<div className="loginBackground"
style={{backgroundImage: Setting.inIframe() || Setting.isMobile() ? null : `url(${this.state.application?.formBackgroundUrl})`}}>
<Spin size="large" spinning={this.state.application === undefined && this.state.pricing === undefined} tip={i18next.t("login:Loading")}
style={{margin: "0 auto"}} />
<Switch>
<Route exact path="/signup" render={(props) => this.renderHomeIfLoggedIn(<SignupPage {...this.props} application={this.state.application} applicationName={authConfig.appName} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/signup/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<SignupPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/login" render={(props) => this.renderHomeIfLoggedIn(<SelfLoginPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/login/:owner" render={(props) => this.renderHomeIfLoggedIn(<SelfLoginPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/signup/oauth/authorize" render={(props) => <SignupPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />} />
<Route exact path="/login/oauth/authorize" render={(props) => <LoginPage {...this.props} application={this.state.application} type={"code"} mode={"signin"} onUpdateApplication={onUpdateApplication} {...props} />} />
<Route exact path="/login/saml/authorize/:owner/:applicationName" render={(props) => <LoginPage {...this.props} application={this.state.application} type={"saml"} mode={"signin"} onUpdateApplication={onUpdateApplication} {...props} />} />
<Route exact path="/forget" render={(props) => this.renderHomeIfLoggedIn(<SelfForgetPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/forget/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<ForgetPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/prompt" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/prompt/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/result" render={(props) => this.renderHomeIfLoggedIn(<ResultPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/result/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<ResultPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/cas/:owner/:casApplicationName/logout" render={(props) => this.renderHomeIfLoggedIn(<CasLogout {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/cas/:owner/:casApplicationName/login" render={(props) => {return (<LoginPage {...this.props} application={this.state.application} type={"cas"} mode={"signin"} onUpdateApplication={onUpdateApplication} {...props} />);}} />
<Route exact path="/select-plan/:owner/:pricingName" render={(props) => <PricingPage {...this.props} pricing={this.state.pricing} onUpdatePricing={onUpdatePricing} {...props} />} />
<Route exact path="/buy-plan/:owner/:pricingName" render={(props) => <ProductBuyPage {...this.props} pricing={this.state.pricing} onUpdatePricing={onUpdatePricing} {...props} />} />
<Route exact path="/buy-plan/:owner/:pricingName/result" render={(props) => <PaymentResultPage {...this.props} pricing={this.state.pricing} onUpdatePricing={onUpdatePricing} {...props} />} />
<Route exact path="/qrcode/:owner/:paymentName" render={(props) => <QrCodePage {...this.props} onUpdateApplication={onUpdateApplication} {...props} />} />
</Switch>
</div>
</React.Fragment>
);
}
}

View File

@ -1165,7 +1165,7 @@ export function getLoginLink(application) {
if (application === null) {
url = null;
} else if (window.location.pathname.includes("/signup/oauth/authorize")) {
url = window.location.href.replace("/signup/oauth/authorize", "/login/oauth/authorize");
url = window.location.pathname.replace("/signup/oauth/authorize", "/login/oauth/authorize");
} else if (authConfig.appName === application.name) {
url = "/login";
} else if (application.signinUrl === "") {
@ -1173,7 +1173,7 @@ export function getLoginLink(application) {
} else {
url = application.signinUrl;
}
return url;
return url + window.location.search;
}
export function redirectToLoginPage(application, history) {
@ -1216,7 +1216,7 @@ export function renderSignupLink(application, text) {
if (application === null) {
url = null;
} else if (window.location.pathname.includes("/login/oauth/authorize")) {
url = window.location.href.replace("/login/oauth/authorize", "/signup/oauth/authorize");
url = window.location.pathname.replace("/login/oauth/authorize", "/signup/oauth/authorize");
} else if (authConfig.appName === application.name) {
url = "/signup";
} else {
@ -1228,10 +1228,10 @@ export function renderSignupLink(application, text) {
}
const storeSigninUrl = () => {
sessionStorage.setItem("signinUrl", window.location.href);
sessionStorage.setItem("signinUrl", window.location.pathname + window.location.search);
};
return renderLink(url, text, storeSigninUrl);
return renderLink(url + window.location.search, text, storeSigninUrl);
}
export function renderForgetLink(application, text) {
@ -1249,7 +1249,7 @@ export function renderForgetLink(application, text) {
}
const storeSigninUrl = () => {
sessionStorage.setItem("signinUrl", window.location.href);
sessionStorage.setItem("signinUrl", window.location.pathname + window.location.search);
};
return renderLink(url, text, storeSigninUrl);

View File

@ -156,7 +156,7 @@ class ForgetPage extends React.Component {
if (res.status === "ok") {
const linkInStorage = sessionStorage.getItem("signinUrl");
if (linkInStorage !== null && linkInStorage !== "") {
Setting.goToLink(linkInStorage);
Setting.goToLinkSoft(linkInStorage);
} else {
Setting.redirectToLoginPage(this.getApplicationObj(), this.props.history);
}

View File

@ -92,7 +92,7 @@ class ResultPage extends React.Component {
<Button type="primary" key="login" onClick={() => {
const linkInStorage = sessionStorage.getItem("signinUrl");
if (linkInStorage !== null && linkInStorage !== "") {
Setting.goToLink(linkInStorage);
Setting.goToLinkSoft(this, linkInStorage);
} else {
Setting.redirectToLoginPage(application, this.props.history);
}

View File

@ -87,8 +87,8 @@ class SignupPage extends React.Component {
componentDidMount() {
const oAuthParams = Util.getOAuthGetParameters();
if (oAuthParams !== null) {
const signinUrl = window.location.href.replace("/signup/oauth/authorize", "/login/oauth/authorize");
sessionStorage.setItem("signinUrl", signinUrl);
const signinUrl = window.location.pathname.replace("/signup/oauth/authorize", "/login/oauth/authorize");
sessionStorage.setItem("signinUrl", signinUrl + window.location.search);
}
if (this.getApplicationObj() === undefined) {
@ -639,7 +639,7 @@ class SignupPage extends React.Component {
<a onClick={() => {
const linkInStorage = sessionStorage.getItem("signinUrl");
if (linkInStorage !== null && linkInStorage !== "") {
Setting.goToLink(linkInStorage);
Setting.goToLinkSoft(this, linkInStorage);
} else {
Setting.redirectToLoginPage(application, this.props.history);
}

View File

@ -0,0 +1,40 @@
// Copyright 2024 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 {useEffect} from "react";
function CustomHead(props) {
useEffect(() => {
const suffix = new Date().getTime().toString();
if (!props.headerHtml) {return;}
const node = document.createElement("div");
node.innerHTML = props.headerHtml;
node.childNodes.forEach(el => {
el.setAttribute("app-custom-head" + suffix, "");
document.head.appendChild(el);
});
return () => {
for (const el of document.head.children) {
if (el.getAttribute("app-custom-head" + suffix) !== null) {
document.head.removeChild(el);
}
}
};
});
}
export default CustomHead;

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Location of the signup, signin and forget password forms",
"Grant types": "Grant types",
"Grant types - Tooltip": "Select which grant types are allowed in the OAuth protocol",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Position der Anmelde-, Registrierungs- und Passwort-vergessen-Formulare",
"Grant types": "Grant-Typen",
"Grant types - Tooltip": "Wählen Sie aus, welche Grant-Typen im OAuth-Protokoll zulässig sind",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Location of the signup, signin and forget password forms",
"Grant types": "Grant types",
"Grant types - Tooltip": "Select which grant types are allowed in the OAuth protocol",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Ubicación de los formularios de registro, inicio de sesión y olvido de contraseña",
"Grant types": "Tipos de subvenciones",
"Grant types - Tooltip": "Selecciona cuáles tipos de subvenciones están permitidas en el protocolo OAuth",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Location of the signup, signin and forget password forms",
"Grant types": "Grant types",
"Grant types - Tooltip": "Select which grant types are allowed in the OAuth protocol",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Location of the signup, signin and forget password forms",
"Grant types": "Grant types",
"Grant types - Tooltip": "Select which grant types are allowed in the OAuth protocol",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Emplacement des formulaires d'inscription, de connexion et de récupération de mot de passe",
"Grant types": "Types d'autorisation",
"Grant types - Tooltip": "Sélectionnez les types d'autorisations autorisés dans le protocole OAuth",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incrémentale",
"Input": "Saisie",
"Invitation code": "Code d'invitation",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Location of the signup, signin and forget password forms",
"Grant types": "Grant types",
"Grant types - Tooltip": "Select which grant types are allowed in the OAuth protocol",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Tempat pendaftaran, masuk, dan lupa kata sandi",
"Grant types": "Jenis-jenis hibah",
"Grant types - Tooltip": "Pilih jenis hibah apa yang diperbolehkan dalam protokol OAuth",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Location of the signup, signin and forget password forms",
"Grant types": "Grant types",
"Grant types - Tooltip": "Select which grant types are allowed in the OAuth protocol",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "登録、ログイン、パスワード忘れフォームの位置",
"Grant types": "グラント種類",
"Grant types - Tooltip": "OAuthプロトコルで許可されているグラントタイプを選択してください",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Location of the signup, signin and forget password forms",
"Grant types": "Grant types",
"Grant types - Tooltip": "Select which grant types are allowed in the OAuth protocol",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "가입, 로그인 및 비밀번호 재설정 양식의 위치",
"Grant types": "Grant types: 부여 유형",
"Grant types - Tooltip": "OAuth 프로토콜에서 허용되는 그란트 유형을 선택하십시오",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Location of the signup, signin and forget password forms",
"Grant types": "Grant types",
"Grant types - Tooltip": "Select which grant types are allowed in the OAuth protocol",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Location of the signup, signin and forget password forms",
"Grant types": "Grant types",
"Grant types - Tooltip": "Select which grant types are allowed in the OAuth protocol",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Location of the signup, signin and forget password forms",
"Grant types": "Grant types",
"Grant types - Tooltip": "Select which grant types are allowed in the OAuth protocol",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Localização dos formulários de registro, login e recuperação de senha",
"Grant types": "Tipos de concessão",
"Grant types - Tooltip": "Selecione quais tipos de concessão são permitidos no protocolo OAuth",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Código de convite",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Местоположение форм регистрации, входа и восстановления пароля",
"Grant types": "Типы грантов",
"Grant types - Tooltip": "Выберите, какие типы грантов разрешены в протоколе OAuth",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Последовательный",
"Input": "Input",
"Invitation code": "Код приглашения",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Location of the signup, signin and forget password forms",
"Grant types": "Grant types",
"Grant types - Tooltip": "Select which grant types are allowed in the OAuth protocol",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Location of the signup, signin and forget password forms",
"Grant types": "Grant types",
"Grant types - Tooltip": "Select which grant types are allowed in the OAuth protocol",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Davet Kodu",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Location of the signup, signin and forget password forms",
"Grant types": "Grant types",
"Grant types - Tooltip": "Select which grant types are allowed in the OAuth protocol",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "Vị trí của các biểu mẫu đăng ký, đăng nhập và quên mật khẩu",
"Grant types": "Loại hỗ trợ",
"Grant types - Tooltip": "Chọn loại hỗ trợ được cho phép trong giao thức OAuth",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - Edit",
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Tăng",
"Input": "Input",
"Invitation code": "Invitation code",

View File

@ -62,6 +62,9 @@
"Form position - Tooltip": "注册、登录、忘记密码等表单的位置",
"Grant types": "OAuth授权类型",
"Grant types - Tooltip": "选择允许哪些OAuth协议中的grant types",
"Header HTML": "Header HTML",
"Header HTML - Edit": "Header HTML - 编辑",
"Header HTML - Tooltip": "自定义应用页面的head标签",
"Incremental": "递增",
"Input": "输入",
"Invitation code": "邀请码",

View File

@ -223,6 +223,26 @@ class ProviderTable extends React.Component {
<Option key="Always" value="Always">{i18next.t("application:Always")}</Option>
</Select>
);
} else if (record.provider?.category === "SMS" || record.provider?.category === "Email") {
if (text === "None") {
text = "all";
}
return (
<Select virtual={false} style={{width: "100%"}}
value={text}
defaultValue="all"
onChange={value => {
this.updateField(table, index, "rule", value);
}}>
<Option key="all" value="all">{"All"}</Option>
<Option key="signup" value="signup">{"Signup"}</Option>
<Option key="login" value="login">{"Login"}</Option>
<Option key="forget" value="forget">{"Forget Password"}</Option>
<Option key="reset" value="reset">{"Reset Password"}</Option>
<Option key="mfaSetup" value="mfaSetup">{"Set MFA"}</Option>
<Option key="mfaAuth" value="mfaAuth">{"MFA Auth"}</Option>
</Select>
);
} else {
return null;
}