// Copyright 2021 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, {Component} from "react"; import "./App.less"; import {Helmet} from "react-helmet"; import EnableMfaNotification from "./common/notifaction/EnableMfaNotification"; import GroupTreePage from "./GroupTreePage"; import GroupEditPage from "./GroupEdit"; import GroupListPage from "./GroupList"; import {MfaRuleRequired} from "./Setting"; import * as Setting from "./Setting"; import {StyleProvider, legacyLogicalPropertiesTransformer} from "@ant-design/cssinjs"; import {BarsOutlined, CommentOutlined, DownOutlined, InfoCircleFilled, LogoutOutlined, SettingOutlined} from "@ant-design/icons"; import {Alert, Avatar, Button, Card, ConfigProvider, Drawer, Dropdown, FloatButton, Layout, Menu, Result} from "antd"; import {Link, Redirect, Route, Switch, withRouter} from "react-router-dom"; import OrganizationListPage from "./OrganizationListPage"; import OrganizationEditPage from "./OrganizationEditPage"; import UserListPage from "./UserListPage"; import UserEditPage from "./UserEditPage"; import RoleListPage from "./RoleListPage"; import RoleEditPage from "./RoleEditPage"; import PermissionListPage from "./PermissionListPage"; import PermissionEditPage from "./PermissionEditPage"; import ProviderListPage from "./ProviderListPage"; import ProviderEditPage from "./ProviderEditPage"; import ApplicationListPage from "./ApplicationListPage"; import ApplicationEditPage from "./ApplicationEditPage"; import ResourceListPage from "./ResourceListPage"; import LdapEditPage from "./LdapEditPage"; import LdapSyncPage from "./LdapSyncPage"; import TokenListPage from "./TokenListPage"; import TokenEditPage from "./TokenEditPage"; import RecordListPage from "./RecordListPage"; import WebhookListPage from "./WebhookListPage"; import WebhookEditPage from "./WebhookEditPage"; import SyncerListPage from "./SyncerListPage"; import SyncerEditPage from "./SyncerEditPage"; import CertListPage from "./CertListPage"; import CertEditPage from "./CertEditPage"; import SubscriptionListPage from "./SubscriptionListPage"; import SubscriptionEditPage from "./SubscriptionEditPage"; import PricingListPage from "./PricingListPage"; import PricingEditPage from "./PricingEditPage"; import PlanListPage from "./PlanListPage"; import PlanEditPage from "./PlanEditPage"; import ChatListPage from "./ChatListPage"; import ChatEditPage from "./ChatEditPage"; import ChatPage from "./ChatPage"; import MessageEditPage from "./MessageEditPage"; import MessageListPage from "./MessageListPage"; import ProductListPage from "./ProductListPage"; import ProductEditPage from "./ProductEditPage"; import ProductBuyPage from "./ProductBuyPage"; import PaymentListPage from "./PaymentListPage"; import PaymentEditPage from "./PaymentEditPage"; import PaymentResultPage from "./PaymentResultPage"; import ModelListPage from "./ModelListPage"; import ModelEditPage from "./ModelEditPage"; import AdapterListPage from "./AdapterListPage"; import AdapterEditPage from "./AdapterEditPage"; import SessionListPage from "./SessionListPage"; import MfaSetupPage from "./auth/MfaSetupPage"; import SystemInfo from "./SystemInfo"; import AccountPage from "./account/AccountPage"; import HomePage from "./basic/HomePage"; import CustomGithubCorner from "./common/CustomGithubCorner"; import * as Conf from "./Conf"; import * as Auth from "./auth/Auth"; import EntryPage from "./EntryPage"; import * as AuthBackend from "./auth/AuthBackend"; import AuthCallback from "./auth/AuthCallback"; import OdicDiscoveryPage from "./auth/OidcDiscoveryPage"; import SamlCallback from "./auth/SamlCallback"; import i18next from "i18next"; import {withTranslation} from "react-i18next"; import LanguageSelect from "./common/select/LanguageSelect"; import ThemeSelect from "./common/select/ThemeSelect"; import OrganizationSelect from "./common/select/OrganizationSelect"; const {Header, Footer, Content} = Layout; class App extends Component { constructor(props) { super(props); this.state = { classes: props, selectedMenuKey: 0, account: undefined, uri: null, menuVisible: false, themeAlgorithm: ["default"], themeData: Conf.ThemeDefault, logo: this.getLogo(Setting.getAlgorithmNames(Conf.ThemeDefault)), requiredEnableMfa: false, }; Setting.initServerUrl(); Auth.initAuthWithConfig({ serverUrl: Setting.ServerUrl, appName: Conf.DefaultApplication, // the application used in Casdoor root path: "/" }); } UNSAFE_componentWillMount() { this.updateMenuKey(); this.getAccount(); } componentDidUpdate(prevProps, prevState, snapshot) { const uri = location.pathname; if (this.state.uri !== uri) { this.updateMenuKey(); } if (this.state.account !== prevState.account) { const requiredEnableMfa = Setting.isRequiredEnableMfa(this.state.account, this.state.account?.organization); this.setState({ requiredEnableMfa: requiredEnableMfa, }); if (requiredEnableMfa === true) { const mfaType = Setting.getMfaItemsByRules(this.state.account, this.state.account?.organization, [MfaRuleRequired]) .find((item) => item.rule === MfaRuleRequired)?.name; if (mfaType !== undefined) { this.props.history.push(`/mfa/setup?mfaType=${mfaType}`, {from: "/login"}); } } } } updateMenuKey() { const uri = location.pathname; this.setState({ uri: uri, }); if (uri === "/") { this.setState({selectedMenuKey: "/"}); } else if (uri.includes("/organizations") || uri.includes("/trees")) { this.setState({selectedMenuKey: "/organizations"}); } else if (uri.includes("/users")) { this.setState({selectedMenuKey: "/users"}); } else if (uri.includes("/groups")) { this.setState({selectedMenuKey: "/groups"}); } else if (uri.includes("/roles")) { this.setState({selectedMenuKey: "/roles"}); } else if (uri.includes("/permissions")) { this.setState({selectedMenuKey: "/permissions"}); } else if (uri.includes("/models")) { this.setState({selectedMenuKey: "/models"}); } else if (uri.includes("/adapters")) { this.setState({selectedMenuKey: "/adapters"}); } else if (uri.includes("/providers")) { this.setState({selectedMenuKey: "/providers"}); } else if (uri.includes("/applications")) { this.setState({selectedMenuKey: "/applications"}); } else if (uri.includes("/resources")) { this.setState({selectedMenuKey: "/resources"}); } else if (uri.includes("/records")) { this.setState({selectedMenuKey: "/records"}); } else if (uri.includes("/tokens")) { this.setState({selectedMenuKey: "/tokens"}); } else if (uri.includes("/sessions")) { this.setState({selectedMenuKey: "/sessions"}); } else if (uri.includes("/webhooks")) { this.setState({selectedMenuKey: "/webhooks"}); } else if (uri.includes("/syncers")) { this.setState({selectedMenuKey: "/syncers"}); } else if (uri.includes("/certs")) { this.setState({selectedMenuKey: "/certs"}); } else if (uri.includes("/chats")) { this.setState({selectedMenuKey: "/chats"}); } else if (uri.includes("/messages")) { this.setState({selectedMenuKey: "/messages"}); } else if (uri.includes("/products")) { this.setState({selectedMenuKey: "/products"}); } else if (uri.includes("/payments")) { this.setState({selectedMenuKey: "/payments"}); } else if (uri.includes("/signup")) { this.setState({selectedMenuKey: "/signup"}); } else if (uri.includes("/login")) { this.setState({selectedMenuKey: "/login"}); } else if (uri.includes("/result")) { this.setState({selectedMenuKey: "/result"}); } else if (uri.includes("/sysinfo")) { this.setState({selectedMenuKey: "/sysinfo"}); } else if (uri.includes("/subscriptions")) { this.setState({selectedMenuKey: "/subscriptions"}); } else if (uri.includes("/plans")) { this.setState({selectedMenuKey: "/plans"}); } else if (uri.includes("/pricings")) { this.setState({selectedMenuKey: "/pricings"}); } else { this.setState({selectedMenuKey: -1}); } } getAccessTokenParam(params) { // "/page?access_token=123" const accessToken = params.get("access_token"); return accessToken === null ? "" : `?accessToken=${accessToken}`; } getCredentialParams(params) { // "/page?username=abc&password=123" if (params.get("username") === null || params.get("password") === null) { return ""; } return `?username=${params.get("username")}&password=${params.get("password")}`; } getUrlWithoutQuery() { return window.location.toString().replace(window.location.search, ""); } getLanguageParam(params) { // "/page?language=en" const language = params.get("language"); if (language !== null) { Setting.setLanguage(language); return `language=${language}`; } return ""; } getLogo(themes) { if (themes.includes("dark")) { return `${Setting.StaticBaseUrl}/img/casdoor-logo_1185x256_dark.png`; } else { return `${Setting.StaticBaseUrl}/img/casdoor-logo_1185x256.png`; } } setLanguage(account) { const language = account?.language; if (language !== null && language !== "" && language !== i18next.language) { Setting.setLanguage(language); } } setTheme = (theme, initThemeAlgorithm) => { this.setState({ themeData: theme, }); if (initThemeAlgorithm) { this.setState({ logo: this.getLogo(Setting.getAlgorithmNames(theme)), themeAlgorithm: Setting.getAlgorithmNames(theme), }); } }; getAccount() { const params = new URLSearchParams(this.props.location.search); let query = this.getAccessTokenParam(params); if (query === "") { query = this.getCredentialParams(params); } const query2 = this.getLanguageParam(params); if (query2 !== "") { const url = window.location.toString().replace(new RegExp(`[?&]${query2}`), ""); window.history.replaceState({}, document.title, url); } if (query !== "") { window.history.replaceState({}, document.title, this.getUrlWithoutQuery()); } AuthBackend.getAccount(query) .then((res) => { let account = null; if (res.status === "ok") { account = res.data; account.organization = res.data2; this.setLanguage(account); this.setTheme(Setting.getThemeData(account.organization), Conf.InitThemeAlgorithm); } else { if (res.data !== "Please login first") { Setting.showMessage("error", `${i18next.t("application:Failed to sign in")}: ${res.msg}`); } } this.setState({ account: account, }); }); } logout() { this.setState({ expired: false, submitted: false, }); AuthBackend.logout() .then((res) => { if (res.status === "ok") { const owner = this.state.account.owner; this.setState({ account: null, themeAlgorithm: ["default"], }); Setting.showMessage("success", i18next.t("application:Logged out successfully")); const redirectUri = res.data2; if (redirectUri !== null && redirectUri !== undefined && redirectUri !== "") { Setting.goToLink(redirectUri); } else if (owner !== "built-in") { Setting.goToLink(`${window.location.origin}/login/${owner}`); } else { Setting.goToLinkSoft(this, "/"); } } else { Setting.showMessage("error", `Failed to log out: ${res.msg}`); } }); } onUpdateAccount(account) { this.setState({ account: account, }); } renderAvatar() { if (this.state.account.avatar === "") { return ( {Setting.getShortName(this.state.account.name)} ); } else { return ( {Setting.getShortName(this.state.account.name)} ); } } renderRightDropdown() { const items = []; if (this.state.requiredEnableMfa === false) { items.push(Setting.getItem(<>  {i18next.t("account:My Account")}, "/account" )); if (Conf.EnableChatPages) { items.push(Setting.getItem(<>  {i18next.t("account:Chats & Messages")}, "/chat" )); } } items.push(Setting.getItem(<>  {i18next.t("account:Logout")}, "/logout")); const onClick = (e) => { if (e.key === "/account") { this.props.history.push("/account"); } else if (e.key === "/subscription") { this.props.history.push("/subscription"); } else if (e.key === "/chat") { this.props.history.push("/chat"); } else if (e.key === "/logout") { this.logout(); } }; return (
{ this.renderAvatar() }     {Setting.isMobile() ? null : Setting.getNameAtLeast(this.state.account.displayName)}        
); } renderAccountMenu() { if (this.state.account === undefined) { return null; } else if (this.state.account === null) { return null; } else { return ( {this.renderRightDropdown()} { this.setState({ themeAlgorithm: nextThemeAlgorithm, logo: this.getLogo(nextThemeAlgorithm), }); }} /> {Setting.isAdminUser(this.state.account) && !Setting.isMobile() && { Setting.setOrganization(value); }} className="select-box" /> } ); } } getMenuItems() { const res = []; if (this.state.account === null || this.state.account === undefined) { return []; } res.push(Setting.getItem({i18next.t("general:Home")}, "/")); if (Setting.isLocalAdminUser(this.state.account)) { if (Conf.ShowGithubCorner) { res.push(Setting.getItem( 🚀 SaaS Hosting 🔥 , "#")); } res.push(Setting.getItem({i18next.t("general:Organizations")}, "/organizations")); res.push(Setting.getItem({i18next.t("general:Groups")}, "/groups")); res.push(Setting.getItem({i18next.t("general:Users")}, "/users" )); res.push(Setting.getItem({i18next.t("general:Roles")}, "/roles" )); res.push(Setting.getItem({i18next.t("general:Permissions")}, "/permissions" )); } if (Setting.isLocalAdminUser(this.state.account)) { res.push(Setting.getItem({i18next.t("general:Models")}, "/models" )); res.push(Setting.getItem({i18next.t("general:Adapters")}, "/adapters" )); } if (Setting.isLocalAdminUser(this.state.account)) { res.push(Setting.getItem({i18next.t("general:Applications")}, "/applications" )); res.push(Setting.getItem({i18next.t("general:Providers")}, "/providers" )); if (Conf.EnableChatPages) { res.push(Setting.getItem({i18next.t("general:Chats")}, "/chats" )); res.push(Setting.getItem({i18next.t("general:Messages")}, "/messages" )); } res.push(Setting.getItem({i18next.t("general:Resources")}, "/resources" )); res.push(Setting.getItem({i18next.t("general:Records")}, "/records" )); res.push(Setting.getItem({i18next.t("general:Plans")}, "/plans" )); res.push(Setting.getItem({i18next.t("general:Pricings")}, "/pricings" )); res.push(Setting.getItem({i18next.t("general:Subscriptions")}, "/subscriptions" )); } if (Setting.isLocalAdminUser(this.state.account)) { res.push(Setting.getItem({i18next.t("general:Tokens")}, "/tokens" )); res.push(Setting.getItem({i18next.t("general:Sessions")}, "/sessions" )); res.push(Setting.getItem({i18next.t("general:Webhooks")}, "/webhooks" )); res.push(Setting.getItem({i18next.t("general:Syncers")}, "/syncers" )); res.push(Setting.getItem({i18next.t("general:Certs")}, "/certs" )); if (Conf.EnableExtraPages) { res.push(Setting.getItem({i18next.t("general:Products")}, "/products" )); res.push(Setting.getItem({i18next.t("general:Payments")}, "/payments" )); } } if (Setting.isAdminUser(this.state.account)) { res.push(Setting.getItem({i18next.t("general:System Info")}, "/sysinfo" )); res.push(Setting.getItem({i18next.t("general:Swagger")}, "/swagger" )); } return res; } renderLoginIfNotLoggedIn(component) { if (this.state.account === null) { sessionStorage.setItem("from", window.location.pathname); return ; } else if (this.state.account === undefined) { return null; } else { return component; } } renderRouter() { return ( this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> } /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> {/* this.renderLoginIfNotLoggedIn()}/>*/} this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn( this.setState({requiredEnableMfa: false})} {...props} />)} /> } /> this.renderLoginIfNotLoggedIn()} /> } />} /> ); } onClose = () => { this.setState({ menuVisible: false, }); }; showMenu = () => { this.setState({ menuVisible: true, }); }; isWithoutCard() { return Setting.isMobile() || window.location.pathname === "/chat" || window.location.pathname.startsWith("/trees"); } renderContent() { const onClick = ({key}) => { if (key === "/swagger") { window.open(Setting.isLocalhost() ? `${Setting.ServerUrl}/swagger` : "/swagger", "_blank"); } else { if (this.state.requiredEnableMfa) { Setting.showMessage("info", "Please enable MFA first!"); } else { this.props.history.push(key); } } }; const menuStyleRight = Setting.isAdminUser(this.state.account) && !Setting.isMobile() ? "calc(180px + 260px)" : "260px"; return (
{Setting.isMobile() ? null : (
)} {this.state.requiredEnableMfa || (Setting.isMobile() ? : )} { this.renderAccountMenu() }
{this.isWithoutCard() ? this.renderRouter() : {this.renderRouter()} } {this.renderFooter()}
); } renderFooter() { return ( {!this.state.account ? null :
}
{ Conf.CustomFooter !== null ? Conf.CustomFooter : ( Powered by {"Casdoor"} ) }
); } isDoorPages() { return this.isEntryPages() || window.location.pathname.startsWith("/callback"); } isEntryPages() { return window.location.pathname.startsWith("/signup") || window.location.pathname.startsWith("/login") || window.location.pathname.startsWith("/forget") || window.location.pathname.startsWith("/prompt") || window.location.pathname.startsWith("/result") || window.location.pathname.startsWith("/cas") || window.location.pathname.startsWith("/auto-signup") || window.location.pathname.startsWith("/select-plan"); } renderPage() { if (this.isDoorPages()) { return ( { this.isEntryPages() ? { localStorage.setItem("mfaRedirectUrl", redirectUrl); this.getAccount(); }} onUpdateAccount={(account) => this.onUpdateAccount(account)} updataThemeData={this.setTheme} /> : } />} /> } { this.renderFooter() } ); } return ( {/* { */} {/* this.renderBanner() */} {/* } */} { this.renderContent() } ); } renderBanner() { if (!Conf.IsDemoMode) { return null; } const language = Setting.getLanguage(); if (language === "en" || language === "zh") { return null; } return (    {i18next.t("general:Found some texts still not translated? Please help us translate at")}   Crowdin  ! 🙏
} /> ); } render() { return ( {(this.state.account === undefined || this.state.account === null) ? : {this.state.account.organization?.displayName} } { this.renderPage() } ); } } export default withRouter(withTranslation()(App));