feat: update to antd 5.0 (#1362)

* feat: update to ant5.X

* fix: incompatible styles

* fix: adjust the style
This commit is contained in:
Yaodong Yu
2022-12-04 23:05:30 +08:00
committed by GitHub
parent a44a4b0300
commit 0856977b92
37 changed files with 409 additions and 376 deletions

View File

@ -208,7 +208,7 @@ class AdapterListPage extends BaseListPage {
title={`Sure to delete adapter: ${record.name} ?`}
onConfirm={() => this.deleteAdapter(index)}
>
<Button style={{marginBottom: "10px"}} type="danger">{i18next.t("general:Delete")}</Button>
<Button style={{marginBottom: "10px"}} type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -17,7 +17,7 @@ import "./App.less";
import {Helmet} from "react-helmet";
import * as Setting from "./Setting";
import {BarsOutlined, DownOutlined, LogoutOutlined, SettingOutlined} from "@ant-design/icons";
import {Avatar, BackTop, Button, Card, Drawer, Dropdown, Layout, Menu, Result} from "antd";
import {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";
@ -295,23 +295,16 @@ class App extends Component {
}
renderRightDropdown() {
const menu = (
<Menu onClick={this.handleRightDropdownClick.bind(this)}>
<Menu.Item key="/account">
<SettingOutlined />
&nbsp;&nbsp;
{i18next.t("account:My Account")}
</Menu.Item>
<Menu.Item key="/logout">
<LogoutOutlined />
&nbsp;&nbsp;
{i18next.t("account:Logout")}
</Menu.Item>
</Menu>
);
const items = [];
items.push(Setting.getItem(<><SettingOutlined />&nbsp;&nbsp;{i18next.t("account:My Account")}</>,
"/account"
));
items.push(Setting.getItem(<><LogoutOutlined />&nbsp;&nbsp;{i18next.t("account:Logout")}</>,
"/logout"));
const onClick = this.handleRightDropdownClick.bind(this);
return (
<Dropdown key="/rightDropDown" overlay={menu} className="rightDropDown">
<Dropdown key="/rightDropDown" menu={{items, onClick}} className="rightDropDown">
<div className="ant-dropdown-link" style={{float: "right", cursor: "pointer"}}>
&nbsp;
&nbsp;
@ -363,155 +356,89 @@ class App extends Component {
return [];
}
res.push(
<Menu.Item key="/">
<Link to="/">
{i18next.t("general:Home")}
</Link>
</Menu.Item>
);
res.push(Setting.getItem(<Link to="/">{i18next.t("general:Home")}</Link>, "/"));
if (Setting.isAdminUser(this.state.account)) {
res.push(
<Menu.Item key="/organizations">
<Link to="/organizations">
{i18next.t("general:Organizations")}
</Link>
</Menu.Item>
);
res.push(Setting.getItem(<Link to="/organizations">{i18next.t("general:Organizations")}</Link>,
"/organizations"));
}
if (Setting.isLocalAdminUser(this.state.account)) {
res.push(
<Menu.Item key="/users">
<Link to="/users">
{i18next.t("general:Users")}
</Link>
</Menu.Item>
);
res.push(
<Menu.Item key="/roles">
<Link to="/roles">
{i18next.t("general:Roles")}
</Link>
</Menu.Item>
);
res.push(
<Menu.Item key="/permissions">
<Link to="/permissions">
{i18next.t("general:Permissions")}
</Link>
</Menu.Item>
);
res.push(Setting.getItem(<Link to="/users">{i18next.t("general:Users")}</Link>,
"/users"
));
res.push(Setting.getItem(<Link to="/roles">{i18next.t("general:Roles")}</Link>,
"/roles"
));
res.push(Setting.getItem(<Link to="/permissions">{i18next.t("general:Permissions")}</Link>,
"/permissions"
));
}
if (Setting.isAdminUser(this.state.account)) {
res.push(
<Menu.Item key="/models">
<Link to="/models">
{i18next.t("general:Models")}
</Link>
</Menu.Item>
);
res.push(
<Menu.Item key="/adapters">
<Link to="/adapters">
{i18next.t("general:Adapters")}
</Link>
</Menu.Item>
);
res.push(Setting.getItem(<Link to="/models">{i18next.t("general:Models")}</Link>,
"/models"
));
res.push(Setting.getItem(<Link to="/adapters">{i18next.t("general:Adapters")}</Link>,
"/adapters"
));
}
if (Setting.isLocalAdminUser(this.state.account)) {
res.push(
<Menu.Item key="/applications">
<Link to="/applications">
{i18next.t("general:Applications")}
</Link>
</Menu.Item>
);
res.push(
<Menu.Item key="/providers">
<Link to="/providers">
{i18next.t("general:Providers")}
</Link>
</Menu.Item>
);
res.push(
<Menu.Item key="/resources">
<Link to="/resources">
{i18next.t("general:Resources")}
</Link>
</Menu.Item>
);
res.push(
<Menu.Item key="/records">
<Link to="/records">
{i18next.t("general:Records")}
</Link>
</Menu.Item>
);
res.push(Setting.getItem(<Link to="/applications">{i18next.t("general:Applications")}</Link>,
"/applications"
));
res.push(Setting.getItem(<Link to="/providers">{i18next.t("general:Providers")}</Link>,
"/providers"
));
res.push(Setting.getItem(<Link to="/resources">{i18next.t("general:Resources")}</Link>,
"/resources"
));
res.push(Setting.getItem(<Link to="/records">{i18next.t("general:Records")}</Link>,
"/records"
));
}
if (Setting.isAdminUser(this.state.account)) {
res.push(
<Menu.Item key="/tokens">
<Link to="/tokens">
{i18next.t("general:Tokens")}
</Link>
</Menu.Item>
);
res.push(
<Menu.Item key="/webhooks">
<Link to="/webhooks">
{i18next.t("general:Webhooks")}
</Link>
</Menu.Item>
);
res.push(
<Menu.Item key="/syncers">
<Link to="/syncers">
{i18next.t("general:Syncers")}
</Link>
</Menu.Item>
);
res.push(
<Menu.Item key="/certs">
<Link to="/certs">
{i18next.t("general:Certs")}
</Link>
</Menu.Item>
);
res.push(Setting.getItem(<Link to="/tokens">{i18next.t("general:Tokens")}</Link>,
"/tokens"
));
res.push(Setting.getItem(<Link to="/webhooks">{i18next.t("general:Webhooks")}</Link>,
"/webhooks"
));
res.push(Setting.getItem(<Link to="/syncers">{i18next.t("general:Syncers")}</Link>,
"/syncers"
));
res.push(Setting.getItem(<Link to="/certs">{i18next.t("general:Certs")}</Link>,
"/certs"
));
if (Conf.EnableExtraPages) {
res.push(
<Menu.Item key="/products">
<Link to="/products">
{i18next.t("general:Products")}
</Link>
</Menu.Item>
);
res.push(
<Menu.Item key="/payments">
<Link to="/payments">
{i18next.t("general:Payments")}
</Link>
</Menu.Item>
);
res.push(
<Menu.Item key="/sysinfo">
<Link to="/sysinfo">
{i18next.t("general:SysInfo")}
</Link>
</Menu.Item>
);
res.push(Setting.getItem(<Link to="/products">{i18next.t("general:Products")}</Link>,
"/products"
));
res.push(Setting.getItem(<Link to="/payments">{i18next.t("general:Payments")}</Link>,
"/payments"
));
res.push(Setting.getItem(<Link to="/sysinfo">{i18next.t("general:SysInfo")}</Link>,
"/sysinfo"
));
}
res.push(
<Menu.Item key="/swagger">
<a target="_blank" rel="noreferrer" href={Setting.isLocalhost() ? `${Setting.ServerUrl}/swagger` : "/swagger"}>
{i18next.t("general:Swagger")}
</a>
</Menu.Item>
);
res.push(Setting.getItem(<a target="_blank" rel="noreferrer"
href={Setting.isLocalhost() ? `${Setting.ServerUrl}/swagger` : "/swagger"}>{i18next.t("general:Swagger")}</a>,
"/swagger"
));
}
return res;
@ -623,13 +550,11 @@ class App extends Component {
<div>
<Menu
// theme="dark"
items={this.renderMenu()}
mode={(Setting.isMobile() && this.isStartPages()) ? "inline" : "horizontal"}
selectedKeys={[`${this.state.selectedMenuKey}`]}
style={{lineHeight: "64px", position: "absolute", left: "145px", right: "200px"}}
>
{
this.renderMenu()
}
</Menu>
{
this.renderAccount()
@ -661,14 +586,12 @@ class App extends Component {
<Drawer title={i18next.t("general:Close")} placement="left" visible={this.state.menuVisible} onClose={this.onClose}>
<Menu
// theme="dark"
items={this.renderMenu()}
mode={(Setting.isMobile()) ? "inline" : "horizontal"}
selectedKeys={[`${this.state.selectedMenuKey}`]}
style={{lineHeight: "64px"}}
onClick={this.onClose}
>
{
this.renderMenu()
}
</Menu>
</Drawer>
<Button icon={<BarsOutlined />} onClick={this.showMenu} type="text">
@ -754,7 +677,7 @@ class App extends Component {
return (
<div id="parent-area">
<BackTop />
<FloatButton.BackTop />
<CustomGithubCorner />
<div id="content-wrap" style={{flexDirection: "column"}}>
{
@ -775,9 +698,16 @@ class App extends Component {
<Helmet>
<link rel="icon" href={"https://cdn.casdoor.com/static/favicon.png"} />
</Helmet>
{
this.renderPage()
}
<ConfigProvider theme={{
token: {
colorPrimary: "rgb(89,54,213)",
colorInfo: "rgb(89,54,213)",
},
}}>
{
this.renderPage()
}
</ConfigProvider>
</React.Fragment>
);
}
@ -789,9 +719,16 @@ class App extends Component {
<title>{organization.displayName}</title>
<link rel="icon" href={organization.favicon} />
</Helmet>
{
this.renderPage()
}
<ConfigProvider theme={{
token: {
colorPrimary: "rgb(89,54,213)",
colorInfo: "rgb(89,54,213)",
},
}}>
{
this.renderPage()
}
</ConfigProvider>
</React.Fragment>
);
}

View File

@ -1,6 +1,5 @@
/* stylelint-disable at-rule-name-case */
/* stylelint-disable selector-class-pattern */
@import "~antd/dist/antd.less";
@StaticBaseUrl: "https://cdn.casbin.org";
@ -32,6 +31,11 @@
height: 100%;
}
img {
border-style: none;
vertical-align: middle;
}
#parent-area {
display: flex;
flex-direction: column;
@ -56,7 +60,7 @@
#footer {
bottom: 0;
width: 100%;
height: 70px; /* Footer height */
padding: 24px 50px;
}
.language-box {

View File

@ -70,7 +70,7 @@ class ApplicationListPage extends BaseListPage {
redirectUris: ["http://localhost:9000/callback"],
tokenFormat: "JWT",
expireInHours: 24 * 7,
formOffset: 8,
formOffset: 2,
};
}
@ -243,7 +243,7 @@ class ApplicationListPage extends BaseListPage {
onConfirm={() => this.deleteApplication(index)}
disabled={record.name === "app-built-in"}
>
<Button style={{marginBottom: "10px"}} disabled={record.name === "app-built-in"} type="danger">{i18next.t("general:Delete")}</Button>
<Button style={{marginBottom: "10px"}} disabled={record.name === "app-built-in"} type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -87,7 +87,7 @@ class BaseListPage extends React.Component {
record[dataIndex]
? record[dataIndex].toString().toLowerCase().includes(value.toLowerCase())
: "",
onFilterDropdownVisibleChange: visible => {
onFilterDropdownOpenChange: visible => {
if (visible) {
setTimeout(() => this.searchInput.select(), 100);
}

View File

@ -172,7 +172,7 @@ class CertListPage extends BaseListPage {
title={`Sure to delete cert: ${record.name} ?`}
onConfirm={() => this.deleteCert(index)}
>
<Button style={{marginBottom: "10px"}} type="danger">{i18next.t("general:Delete")}</Button>
<Button style={{marginBottom: "10px"}} type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -140,7 +140,7 @@ export const CropperDiv = (props) => {
<Modal
maskClosable={false}
title={title}
visible={visible}
open={visible}
okText={i18next.t("user:Upload a photo")}
confirmLoading={confirmLoading}
onCancel={handleCancel}

View File

@ -144,7 +144,7 @@ class LdapListPage extends React.Component {
onConfirm={() => this.deleteLdap(index)}
>
<Button style={{marginBottom: "10px"}}
type="danger">{i18next.t("general:Delete")}</Button>
type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -162,7 +162,7 @@ class LdapTable extends React.Component {
onConfirm={() => this.deleteRow(table, index)}
>
<Button style={{marginBottom: "10px"}}
type="danger">{i18next.t("general:Delete")}</Button>
type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -146,7 +146,7 @@ class ModelListPage extends BaseListPage {
title={`Sure to delete model: ${record.name} ?`}
onConfirm={() => this.deleteModel(index)}
>
<Button style={{marginBottom: "10px"}} type="danger">{i18next.t("general:Delete")}</Button>
<Button style={{marginBottom: "10px"}} type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -231,7 +231,7 @@ class OrganizationListPage extends BaseListPage {
onConfirm={() => this.deleteOrganization(index)}
disabled={record.name === "built-in"}
>
<Button style={{marginBottom: "10px"}} disabled={record.name === "built-in"} type="danger">{i18next.t("general:Delete")}</Button>
<Button style={{marginBottom: "10px"}} disabled={record.name === "built-in"} type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -64,7 +64,7 @@ export const PasswordModal = (props) => {
<Modal
maskClosable={false}
title={i18next.t("user:Password")}
visible={visible}
open={visible}
okText={i18next.t("user:Set Password")}
cancelText={i18next.t("user:Cancel")}
confirmLoading={confirmLoading}

View File

@ -117,7 +117,7 @@ class PaymentEditPage extends React.Component {
{" " + i18next.t("payment:Confirm your invoice information")}
</div>
}
visible={this.state.isModalVisible}
open={this.state.isModalVisible}
onOk={handleIssueInvoice}
onCancel={handleCancel}
okText={i18next.t("payment:Issue Invoice")}

View File

@ -226,7 +226,7 @@ class PaymentListPage extends BaseListPage {
title={`Sure to delete payment: ${record.name} ?`}
onConfirm={() => this.deletePayment(index)}
>
<Button style={{marginBottom: "10px"}} type="danger">{i18next.t("general:Delete")}</Button>
<Button style={{marginBottom: "10px"}} type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -304,7 +304,7 @@ class PermissionListPage extends BaseListPage {
title={`Sure to delete permission: ${record.name} ?`}
onConfirm={() => this.deletePermission(index)}
>
<Button style={{marginBottom: "10px"}} type="danger">{i18next.t("general:Delete")}</Button>
<Button style={{marginBottom: "10px"}} type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -243,7 +243,7 @@ class ProductListPage extends BaseListPage {
title={`Sure to delete product: ${record.name} ?`}
onConfirm={() => this.deleteProduct(index)}
>
<Button style={{marginBottom: "10px"}} type="danger">{i18next.t("general:Delete")}</Button>
<Button style={{marginBottom: "10px"}} type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -212,7 +212,7 @@ class ProviderListPage extends BaseListPage {
title={`Sure to delete provider: ${record.name} ?`}
onConfirm={() => this.deleteProvider(index)}
>
<Button disabled={!Setting.isAdminUser(this.props.account) && (record.owner !== this.props.account.owner)} style={{marginBottom: "10px"}} type="danger">{i18next.t("general:Delete")}</Button>
<Button disabled={!Setting.isAdminUser(this.props.account) && (record.owner !== this.props.account.owner)} style={{marginBottom: "10px"}} type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -71,7 +71,7 @@ export const ResetModal = (props) => {
<Modal
maskClosable={false}
title={buttonText}
visible={visible}
open={visible}
okText={buttonText}
cancelText={i18next.t("user:Cancel")}
confirmLoading={confirmLoading}

View File

@ -257,7 +257,7 @@ class ResourceListPage extends BaseListPage {
okText={i18next.t("user:OK")}
cancelText={i18next.t("user:Cancel")}
>
<Button type="danger">{i18next.t("general:Delete")}</Button>
<Button type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -179,7 +179,7 @@ class RoleListPage extends BaseListPage {
title={`Sure to delete role: ${record.name} ?`}
onConfirm={() => this.deleteRole(index)}
>
<Button style={{marginBottom: "10px"}} type="danger">{i18next.t("general:Delete")}</Button>
<Button style={{marginBottom: "10px"}} type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -33,14 +33,14 @@ class SelectLanguageBox extends React.Component {
}
items = [
this.getItem("English", "en", flagIcon("US", "English")),
this.getItem("简体中文", "zh", flagIcon("CN", "简体中文")),
this.getItem("Español", "es", flagIcon("ES", "Español")),
this.getItem("Français", "fr", flagIcon("FR", "Français")),
this.getItem("Deutsch", "de", flagIcon("DE", "Deutsch")),
this.getItem("日本語", "ja", flagIcon("JP", "日本語")),
this.getItem("한국어", "ko", flagIcon("KR", "한국어")),
this.getItem("Русский", "ru", flagIcon("RU", "Русский")),
Setting.getItem("English", "en", flagIcon("US", "English")),
Setting.getItem("简体中文", "zh", flagIcon("CN", "简体中文")),
Setting.getItem("Español", "es", flagIcon("ES", "Español")),
Setting.getItem("Français", "fr", flagIcon("FR", "Français")),
Setting.getItem("Deutsch", "de", flagIcon("DE", "Deutsch")),
Setting.getItem("日本語", "ja", flagIcon("JP", "日本語")),
Setting.getItem("한국어", "ko", flagIcon("KR", "한국어")),
Setting.getItem("Русский", "ru", flagIcon("RU", "Русский")),
];
getOrganizationLanguages(languages) {
@ -51,10 +51,6 @@ class SelectLanguageBox extends React.Component {
return select;
}
getItem(label, key, icon) {
return {key, icon, label};
}
render() {
const languageItems = this.getOrganizationLanguages(this.state.languages);
const menu = (

View File

@ -858,6 +858,15 @@ export function getLabel(text, tooltip) {
);
}
export function getItem(label, key, icon, children, type) {
return {
key,
icon,
children,
label,
type,
};
}
function repeat(str, len) {
while (str.length < len) {
str += str.substr(0, len - str.length);

View File

@ -236,7 +236,7 @@ class SyncerListPage extends BaseListPage {
title={`Sure to delete syncer: ${record.name} ?`}
onConfirm={() => this.deleteSyncer(index)}
>
<Button style={{marginBottom: "10px"}} type="danger">{i18next.t("general:Delete")}</Button>
<Button style={{marginBottom: "10px"}} type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -205,7 +205,7 @@ class TokenListPage extends BaseListPage {
title={`Sure to delete token: ${record.name} ?`}
onConfirm={() => this.deleteToken(index)}
>
<Button style={{marginBottom: "10px"}} type="danger">{i18next.t("general:Delete")}</Button>
<Button style={{marginBottom: "10px"}} type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -353,7 +353,7 @@ class UserListPage extends BaseListPage {
title={`Sure to delete user: ${record.name} ?`}
onConfirm={() => this.deleteUser(index)}
>
<Button disabled={disabled} style={{marginBottom: "10px"}} type="danger">{i18next.t("general:Delete")}</Button>
<Button disabled={disabled} style={{marginBottom: "10px"}} type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -51,7 +51,7 @@ class WebAuthnCredentialTable extends React.Component {
width: "170px",
render: (text, record, index) => {
return (
<Button style={{marginTop: "5px", marginBottom: "5px", marginRight: "5px"}} type="danger" onClick={() => {this.deleteRow(this.props.table, index);}}>
<Button style={{marginTop: "5px", marginBottom: "5px", marginRight: "5px"}} type="primary" danger onClick={() => {this.deleteRow(this.props.table, index);}}>
{i18next.t("general:Delete")}
</Button>
);

View File

@ -201,7 +201,7 @@ class WebhookListPage extends BaseListPage {
title={`Sure to delete webhook: ${record.name} ?`}
onConfirm={() => this.deleteWebhook(index)}
>
<Button style={{marginBottom: "10px"}} type="danger">{i18next.t("general:Delete")}</Button>
<Button style={{marginBottom: "10px"}} type="primary" danger>{i18next.t("general:Delete")}</Button>
</Popconfirm>
</div>
);

View File

@ -30,8 +30,6 @@ import {CountDownInput} from "../common/CountDownInput";
import SelectLanguageBox from "../SelectLanguageBox";
import {CaptchaModal} from "../common/CaptchaModal";
const {TabPane} = Tabs;
class LoginPage extends React.Component {
constructor(props) {
super(props);
@ -734,21 +732,16 @@ class LoginPage extends React.Component {
renderMethodChoiceBox() {
const application = this.getApplicationObj();
const items = [
{label: i18next.t("login:Password"), key: "password"},
];
application.enableCodeSignin ? items.push({label: i18next.t("login:Verification Code"), key: "verificationCode"}) : null;
application.enableWebAuthn ? items.push({label: i18next.t("login:WebAuthn"), key: "webAuthn"}) : null;
if (application.enableCodeSignin || application.enableWebAuthn) {
return (
<div>
<Tabs size={"small"} defaultActiveKey="password" onChange={(key) => {this.setState({loginMethod: key});}} centered>
<TabPane tab={i18next.t("login:Password")} key="password" />
{
!application.enableCodeSignin ? null : (
<TabPane tab={i18next.t("login:Verification Code")} key="verificationCode" />
)
}
{
!application.enableWebAuthn ? null : (
<TabPane tab={i18next.t("login:WebAuthn")} key="webAuthn" />
)
}
<Tabs items={items} size={"small"} defaultActiveKey="password" onChange={(key) => {this.setState({loginMethod: key});}} centered>
</Tabs>
</div>
);

View File

@ -510,7 +510,7 @@ class SignupPage extends React.Component {
return (
<Modal
title={i18next.t("signup:Terms of Use")}
visible={this.state.isTermsOfUseVisible}
open={this.state.isTermsOfUseVisible}
width={"55vw"}
closable={false}
okText={i18next.t("signup:Accept")}

View File

@ -28,7 +28,7 @@ export function renderMessage(msg) {
description={msg}
type="error"
action={
<Button size="small" danger>
<Button size="small" type="primary" danger>
Detail
</Button>
}

View File

@ -148,7 +148,7 @@ export const CaptchaModal = ({
maskClosable={false}
destroyOnClose={true}
title={i18next.t("general:Captcha")}
visible={visible}
open={visible}
width={348}
footer={renderFooter()}
>

View File

@ -156,7 +156,7 @@ export const CountDownInput = (props) => {
maskClosable={false}
destroyOnClose={true}
title={i18next.t("general:Captcha")}
visible={visible}
open={visible}
okText={i18next.t("user:OK")}
cancelText={i18next.t("user:Cancel")}
onOk={handleOk}

View File

@ -93,7 +93,7 @@ class PolicyTable extends React.Component {
if (res.status === "ok") {
this.setState({policyLists: res});
} else {
Setting.showMessage("error", i18next.t("adapter:Failed to sync policies: ") + res.msg);
Setting.showMessage("error", `${i18next.t("adapter:Failed to sync policies")}: ${res.msg}`);
}
this.setState({loading: false});
})

View File

@ -18,6 +18,7 @@ import "react-app-polyfill/stable";
import React from "react";
import {createRoot} from "react-dom/client";
import "./index.css";
import "./App.less";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import {BrowserRouter} from "react-router-dom";