diff --git a/object/application.go b/object/application.go
index 1b96bd9e..237e8f3f 100644
--- a/object/application.go
+++ b/object/application.go
@@ -105,6 +105,7 @@ type Application struct {
SignupHtml string `xorm:"mediumtext" json:"signupHtml"`
SigninHtml string `xorm:"mediumtext" json:"signinHtml"`
ThemeData *ThemeData `xorm:"json" json:"themeData"`
+ FooterHtml string `xorm:"mediumtext" json:"footerHtml"`
FormCss string `xorm:"text" json:"formCss"`
FormCssMobile string `xorm:"text" json:"formCssMobile"`
FormOffset int `json:"formOffset"`
diff --git a/web/src/App.js b/web/src/App.js
index bd90d2c5..be05c1bc 100644
--- a/web/src/App.js
+++ b/web/src/App.js
@@ -34,6 +34,7 @@ const ManagementPage = lazy(() => import("./ManagementPage"));
const {Footer, Content} = Layout;
import {setTwoToneColor} from "@ant-design/icons";
+import * as ApplicationBackend from "./backend/ApplicationBackend";
setTwoToneColor("rgb(87,52,211)");
@@ -56,6 +57,7 @@ class App extends Component {
logo: this.getLogo(storageThemeAlgorithm),
requiredEnableMfa: false,
isAiAssistantOpen: false,
+ application: undefined,
};
Setting.initServerUrl();
Auth.initAuthWithConfig({
@@ -67,6 +69,7 @@ class App extends Component {
UNSAFE_componentWillMount() {
this.updateMenuKey();
this.getAccount();
+ this.getApplication();
}
componentDidUpdate(prevProps, prevState, snapshot) {
@@ -190,6 +193,24 @@ class App extends Component {
}
};
+ getApplication() {
+ const applicationName = localStorage.getItem("applicationName");
+ if (!applicationName) {
+ return;
+ }
+ ApplicationBackend.getApplication("admin", applicationName)
+ .then((res) => {
+ if (res.status === "error") {
+ Setting.showMessage("error", res.msg);
+ return;
+ }
+
+ this.setState({
+ application: res.data,
+ });
+ });
+ }
+
getAccount() {
const params = new URLSearchParams(this.props.location.search);
@@ -245,11 +266,17 @@ class App extends Component {
}
}>
{
- Conf.CustomFooter !== null ? Conf.CustomFooter : (
+ this.state.application?.footerHtml && this.state.application.footerHtml !== "" ?
- Powered by
+
- )
+ : (
+ Conf.CustomFooter !== null ? Conf.CustomFooter : (
+
+ Powered by
+
+ )
+ )
}
@@ -330,6 +357,11 @@ class App extends Component {
{
+ this.setState({
+ application: application,
+ });
+ }}
onLoginSuccess={(redirectUrl) => {
if (redirectUrl) {
localStorage.setItem("mfaRedirectUrl", redirectUrl);
diff --git a/web/src/ApplicationEditPage.js b/web/src/ApplicationEditPage.js
index 499754ba..45a373e5 100644
--- a/web/src/ApplicationEditPage.js
+++ b/web/src/ApplicationEditPage.js
@@ -887,6 +887,38 @@ class ApplicationEditPage extends React.Component {
+
+
+ {Setting.getLabel(i18next.t("application:Footer HTML"), i18next.t("application:Footer HTML - Tooltip"))} :
+
+
+
+ {
+ this.updateApplicationField("footerHtml", value);
+ }}
+ />
+
+ } title={i18next.t("application:Footer HTML - Edit")} trigger="click">
+ {
+ this.updateApplicationField("footerHtml", e.target.value);
+ }} />
+
+
+
+
+
+
+
+
+
{
diff --git a/web/src/EntryPage.js b/web/src/EntryPage.js
index 13f495eb..b6fa155c 100644
--- a/web/src/EntryPage.js
+++ b/web/src/EntryPage.js
@@ -69,6 +69,9 @@ class EntryPage extends React.Component {
});
const themeData = application !== null ? Setting.getThemeData(application.organizationObj, application) : Conf.ThemeDefault;
this.props.updataThemeData(themeData);
+ this.props.updateApplication(application);
+
+ localStorage.setItem("applicationName", application.name);
};
const onUpdatePricing = (pricing) => {
diff --git a/web/src/Setting.js b/web/src/Setting.js
index 462c5c81..ed764cdf 100644
--- a/web/src/Setting.js
+++ b/web/src/Setting.js
@@ -1467,6 +1467,19 @@ export function getUserCommonFields() {
"PreferredMfaType", "TotpSecret", "SignupApplication"];
}
+export function getDefaultFooterContent() {
+ return "Powered by
";
+}
+
+export function getEmptyFooterContent() {
+ return `