mirror of https://github.com/casbin/casnode.git
544 lines
18 KiB
JavaScript
544 lines
18 KiB
JavaScript
// Copyright 2020 The casbin 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 {withRouter} from "react-router-dom";
|
||
import * as TabBackend from "../backend/TabBackend.js";
|
||
import * as Setting from "../Setting";
|
||
import Select2 from "react-select2-wrapper";
|
||
import $ from "jquery";
|
||
import i18next from "i18next";
|
||
|
||
class AdminTab extends React.Component {
|
||
constructor(props) {
|
||
super(props);
|
||
this.state = {
|
||
classes: props,
|
||
nodes: [],
|
||
tabs: [],
|
||
message: "",
|
||
errorMessage: "",
|
||
form: {},
|
||
tab: [],
|
||
//event: props.match.params.event,
|
||
tabId: props.match.params.tabId,
|
||
width: "",
|
||
event: "basic",
|
||
Management_LIST: [
|
||
{label: "Basic Info", value: "basic"},
|
||
],
|
||
};
|
||
}
|
||
|
||
componentDidMount() {
|
||
this.getTabNodes();
|
||
this.getTab();
|
||
this.getTabs();
|
||
}
|
||
|
||
getTabs() {
|
||
TabBackend.getTabsAdmin()
|
||
.then((res) => {
|
||
this.setState({
|
||
tabs: res,
|
||
});
|
||
});
|
||
}
|
||
|
||
getTabNodes() {
|
||
if (this.state.tabId === undefined && this.props.event !== "new") {
|
||
return;
|
||
}
|
||
|
||
TabBackend.getTabWithNode(this.state.tabId)
|
||
.then((res) => {
|
||
this.setState({
|
||
nodes: res?.data2,
|
||
});
|
||
});
|
||
}
|
||
|
||
getTab() {
|
||
if (this.state.tabId === undefined && this.props.event !== "new") {
|
||
return;
|
||
}
|
||
|
||
TabBackend.getTabAdmin(this.state.tabId)
|
||
.then((res) => {
|
||
this.setState({
|
||
tab: res,
|
||
}, () => {
|
||
this.initForm();
|
||
});
|
||
});
|
||
}
|
||
|
||
initForm() {
|
||
let form = this.state.form;
|
||
if (this.props.event === "new") {
|
||
form["sorter"] = 1;
|
||
form["homePage"] = false;
|
||
} else {
|
||
form["id"] = this.state.tab?.id;
|
||
form["name"] = this.state.tab?.name;
|
||
form["createdTime"] = this.state.tab?.createdTime;
|
||
form["sorter"] = this.state.tab?.sorter;
|
||
form["defaultNode"] = this.state.tab?.defaultNode;
|
||
form["homePage"] = this.state.tab?.homePage;
|
||
}
|
||
this.setState({
|
||
form: form,
|
||
});
|
||
}
|
||
|
||
updateFormField(key, value) {
|
||
let form = this.state.form;
|
||
form[key] = value;
|
||
this.setState({
|
||
form: form,
|
||
});
|
||
}
|
||
|
||
getIndexFromNodeId(nodeId) {
|
||
for (let i = 0; i < this.state.nodes.length; i++) {
|
||
if (this.state.nodes[i].id === nodeId) {
|
||
return i;
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
deleteTab(tab, topicsNum, nodesNum) {
|
||
if (window.confirm(`${i18next.t(`tab:Are you sure to delete tab`)} ${tab} ?`)) {
|
||
if (topicsNum !== 0 || nodesNum !== 0) {
|
||
alert(`
|
||
${i18next.t("tab:Please delete all the nodes and posts under the tab before deleting the tab")}
|
||
${i18next.t("tab:Currently the number of nodes under the tab is")} ${nodesNum} ${i18next.t("tab:, the number of posts is")} ${nodesNum}
|
||
`);
|
||
} else {
|
||
TabBackend.deleteTab(tab)
|
||
.then((res) => {
|
||
if (res.status === 'ok') {
|
||
this.setState({
|
||
message: `${i18next.t("tab:Delete tab")} ${tab} ${i18next.t("tab:success")}`,
|
||
});
|
||
this.getTabs();
|
||
} else {
|
||
this.setState({
|
||
errorMessage: res?.msg,
|
||
});
|
||
}
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
updateTabInfo() {
|
||
TabBackend.updateTab(this.state.tabId, this.state.form)
|
||
.then((res) => {
|
||
if (res.status === 'ok') {
|
||
this.getTab();
|
||
this.getTabNodes();
|
||
this.setState({
|
||
message: i18next.t("tab:Update tab information success"),
|
||
});
|
||
} else {
|
||
this.setState({
|
||
message: res?.msg,
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
postNewTab() {
|
||
if (this.state.form.id === undefined || this.state.form.id === "") {
|
||
this.setState({
|
||
errorMessage: "Please input tab ID",
|
||
});
|
||
return;
|
||
}
|
||
if (this.state.form.name === "" || this.state.form.name === undefined) {
|
||
this.setState({
|
||
errorMessage: "Please input tab name",
|
||
});
|
||
return;
|
||
}
|
||
|
||
TabBackend.addTab(this.state.form)
|
||
.then((res) => {
|
||
if (res.status === 'ok') {
|
||
this.getTab();
|
||
this.setState({
|
||
errorMessage: "",
|
||
message: i18next.t("tab:Creat tab success"),
|
||
}, () => {
|
||
setTimeout(() => Setting.goToLink(`/admin/tab/edit/${this.state.form.id}`), 1600);
|
||
});
|
||
} else {
|
||
this.setState({
|
||
errorMessage: res?.msg,
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
clearMessage() {
|
||
this.setState({
|
||
message: "",
|
||
});
|
||
}
|
||
|
||
clearErrorMessage() {
|
||
this.setState({
|
||
errorMessage: "",
|
||
});
|
||
}
|
||
|
||
changeEvent(event) {
|
||
this.setState({
|
||
event: event,
|
||
message: "",
|
||
});
|
||
if (this.props.event !== "new") {
|
||
this.initForm();
|
||
}
|
||
}
|
||
|
||
renderProblem() {
|
||
let problems = [];
|
||
|
||
if (this.state.errorMessage !== "") {
|
||
problems.push(i18next.t(`error:${this.state.errorMessage}`));
|
||
}
|
||
|
||
if (problems.length === 0) {
|
||
return null;
|
||
}
|
||
|
||
return (
|
||
<div className="problem" onClick={() => this.clearErrorMessage()}>
|
||
{i18next.t("error:Please resolve the following issues before submitting")}
|
||
<ul>
|
||
{
|
||
problems.map((problem, i) => {
|
||
return <li>{problem}</li>;
|
||
})
|
||
}
|
||
</ul>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
renderManagementList(item){
|
||
return (
|
||
<a href="javascript:void(0);" className={this.state.event === item.value ? "tab_current" : "tab"} onClick={() => this.changeEvent(item.value)}>{i18next.t(`tab:${item.label}`)}</a>
|
||
);
|
||
}
|
||
|
||
renderHeader() {
|
||
return (
|
||
<div className="box">
|
||
<div className="header"><a href="/">{Setting.getForumName()}</a>
|
||
{" "}<span className="chevron"> › </span>
|
||
<a href={`/admin`}>{i18next.t("admin:Backstage management")}</a>
|
||
{" "}<span className="chevron"> › </span>
|
||
<a href={`/admin/tab`}>{i18next.t("tab:Tab management")}</a>
|
||
{" "}<span className="chevron"> › </span>
|
||
<span>
|
||
{
|
||
this.props.event === "new" ?
|
||
i18next.t("tab:New tab") : this.state.tabId
|
||
}
|
||
</span>
|
||
</div>
|
||
<div className="cell">
|
||
{
|
||
this.state.Management_LIST.map((item) => {
|
||
return this.renderManagementList(item);
|
||
})
|
||
}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
renderTabs(tab) {
|
||
const pcBrowser = Setting.PcBrowser;
|
||
|
||
return (
|
||
<div className="cell">
|
||
<table cellPadding="0" cellSpacing="0" border="0" width="100%">
|
||
<tbody>
|
||
<tr>
|
||
<td width={pcBrowser ? "200" : "auto"} align="left">
|
||
<span className="gray">
|
||
{tab?.name}
|
||
</span>
|
||
</td>
|
||
<td width={pcBrowser ? "100" : "auto"} align="center">
|
||
<a href={`/admin/tab/edit/${tab?.id}`}>
|
||
{i18next.t("tab:Manage")}
|
||
</a>
|
||
</td>
|
||
<td width="10"></td>
|
||
<td width={pcBrowser ? "120" : "80"} valign="middle" style={{textAlign: "center"}}>
|
||
<span style={{fontSize: "13px"}}>
|
||
{tab?.topicsNum}{" "}{i18next.t("tab:topics")}
|
||
</span>
|
||
</td>
|
||
<td width={pcBrowser ? "120" : "80"} align="left" style={{textAlign: "center"}}>
|
||
{tab?.nodesNum}{" "}{i18next.t("tab:nodes")}
|
||
</td>
|
||
<td width="50" align="left" style={{textAlign: "right"}}>
|
||
<a href="#" onClick={() => this.deleteTab(tab?.id, tab?.topicsNum, tab?.nodesNum)}>
|
||
{i18next.t("tab:Delete")}
|
||
</a>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
render() {
|
||
const newTab = (this.props.event === "new");
|
||
|
||
if (this.state.tabId !== undefined || newTab) {
|
||
if (this.state.tabId !== undefined) {
|
||
if (this.state.tab !== null && this.state.tab.length === 0) {
|
||
return (
|
||
<div className="box">
|
||
<div className="header"><a href="/">{Setting.getForumName()}</a><span className="chevron"> › </span>{" "}{i18next.t("loading:Page is loading")}</div>
|
||
<div className="cell"><span className="gray bigger">{i18next.t("loading:Please wait patiently...")}</span></div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
if (this.state.tab === null) {
|
||
return (
|
||
<div class="box">
|
||
<div class="header">
|
||
<a href="/">{Setting.getForumName()}</a>
|
||
<span className="chevron"> › </span>{" "}{i18next.t("error:Tab not found")}</div>
|
||
<div class="cell">
|
||
{i18next.t("error:The tab you are trying to view does not exist")}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
}
|
||
|
||
const tab = this.state.tab;
|
||
|
||
return (
|
||
<div>
|
||
{this.renderHeader()}
|
||
<div className="box">
|
||
{this.renderProblem()}
|
||
{
|
||
this.state.message !== "" ?
|
||
<div className="message" onClick={() => this.clearMessage()}>
|
||
<li className="fa fa-exclamation-triangle"></li>
|
||
{" "}
|
||
{this.state.message}
|
||
</div> : null
|
||
}
|
||
<div className="inner">
|
||
<table cellPadding="5" cellSpacing="0" border="0" width="100%">
|
||
<tbody>
|
||
{
|
||
newTab ?
|
||
<tr>
|
||
<td width="120" align="right">{i18next.t("tab:Tab ID")}</td>
|
||
<td width="auto" align="left">
|
||
<input type="text" className="sl" name="id" id="tab_id" value={this.state.form?.id} onChange={event => this.updateFormField("id", event.target.value)} autoComplete="off" />
|
||
</td>
|
||
</tr> : null
|
||
}
|
||
<tr>
|
||
<td width="120" align="right">{i18next.t("tab:Tab name")}</td>
|
||
<td width="auto" align="left">
|
||
<input type="text" className="sl" name="name" id="tab_name" value={this.state.form?.name===undefined ? "" : this.state.form?.name} onChange={event => this.updateFormField("name", event.target.value)} autoComplete="off" />
|
||
</td>
|
||
</tr>
|
||
{
|
||
!newTab ?
|
||
<tr>
|
||
<td width="120" align="right">{i18next.t("tab:Created time")}</td>
|
||
<td width="auto" align="left">
|
||
<span className="gray">
|
||
{tab?.createdTime}
|
||
</span>
|
||
</td>
|
||
</tr> : null
|
||
}
|
||
{
|
||
!newTab ?
|
||
<tr>
|
||
<td width="120" align="right">{i18next.t("tab:Total topics")}</td>
|
||
<td width="auto" align="left">
|
||
<span className="gray">
|
||
{tab?.topicsNum}
|
||
</span>
|
||
</td>
|
||
</tr> : null
|
||
}
|
||
{
|
||
!newTab ?
|
||
<tr>
|
||
<td width="120" align="right">{i18next.t("tab:Total nodes")}</td>
|
||
<td width="auto" align="left">
|
||
<span className="gray">
|
||
{tab?.nodesNum}
|
||
</span>
|
||
</td>
|
||
</tr> : null
|
||
}
|
||
<tr>
|
||
<td width="120" align="right">{i18next.t("tab:Sorter")}</td>
|
||
<td width="auto" align="left">
|
||
<input type="range" min="1" max="1000" step="1" value={this.state.form?.sorter === undefined ? 1 : this.state.form?.sorter} onChange={event => this.updateFormField("sorter", parseInt(event.target.value))}/>
|
||
{" "} {" "}
|
||
<input type="number" name="sorter" min="1" max="1000" step="1" value={this.state.form?.sorter} style={{width: "50px"}} onChange={event => this.updateFormField("sorter", parseInt(event.target.value))} />
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td width="120" align="right"></td>
|
||
<td width="auto" align="left">
|
||
<span className="gray">
|
||
{i18next.t("tab:Decide the order of node navigation and homepage")}
|
||
</span>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td width="120" align="right">{i18next.t("tab:Home page")}</td>
|
||
<td width="auto" align="left">
|
||
<input type="radio" onClick={() => this.updateFormField("homePage", true)} checked={this.state.form?.homePage} name="homePage" />{i18next.t("tab:show")}{" "}
|
||
<input type="radio" onClick={() => this.updateFormField("homePage", false)} checked={!this.state.form?.homePage} name="homePage" />{i18next.t("tab:hidden")}
|
||
</td>
|
||
</tr>
|
||
{
|
||
this.state.form?.homePage ?
|
||
<tr>
|
||
<td width="120" align="right">{i18next.t("tab:Default node")}</td>
|
||
<td width="auto" align="left">
|
||
{
|
||
tab?.nodesNum !== 0 && tab?.nodesNum !== undefined ?
|
||
<Select2
|
||
value={this.getIndexFromNodeId(this.state.form?.defaultNode)}
|
||
style={{width: "300px", fontSize: "14px"}}
|
||
data={
|
||
this.state.nodes.map((node, i) => {
|
||
return {text: `${node.name} / ${node.id}`, id: i};
|
||
})
|
||
}
|
||
onSelect={event => {
|
||
const s = $(event.target).val();
|
||
if (s === null) {
|
||
return;
|
||
}
|
||
|
||
const index = parseInt(s);
|
||
const nodeId = this.state.nodes[index].id;
|
||
this.updateFormField("defaultNode", nodeId);
|
||
}}
|
||
options={
|
||
{
|
||
placeholder: i18next.t("tab:Please select a default node"),
|
||
}
|
||
}
|
||
/> :
|
||
<span className="gray">
|
||
{i18next.t("tab:No node exists in this tab")}
|
||
</span>
|
||
}
|
||
</td>
|
||
</tr> : null
|
||
}
|
||
{
|
||
this.state.form?.homePage ?
|
||
<tr>
|
||
<td width="120" align="right"></td>
|
||
<td width="auto" align="left">
|
||
<span className="gray">
|
||
{i18next.t("tab:The default node when creating a topic on the homepage")}
|
||
</span>
|
||
</td>
|
||
</tr> : null
|
||
}
|
||
<tr>
|
||
<td width="120" align="right"></td>
|
||
<td width="auto" align="left">
|
||
{
|
||
!newTab ?
|
||
<input type="submit" className="super normal button" value={i18next.t("tab:Save")} onClick={() => this.updateTabInfo()}/> :
|
||
<input type="submit" className="super normal button" value={i18next.t("tab:Create")} onClick={() => this.postNewTab()}/>
|
||
}
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div className="box">
|
||
<div className="header">
|
||
<a href="/">{Setting.getForumName()}</a>
|
||
{" "}<span className="chevron"> › </span>
|
||
<a href={`/admin`}>{i18next.t("admin:Backstage management")}</a>
|
||
<span className="chevron"> › </span>{" "}{i18next.t("tab:Tab management")}
|
||
<div className="fr f12">
|
||
<span className="snow">{i18next.t("tab:Total tabs")}{" "} </span>
|
||
<strong className="gray">{this.state.tabs === null ? 0 : this.state.tabs.length}</strong>
|
||
</div>
|
||
<div className="fr f12">
|
||
<strong className="gray">
|
||
<a href="tab/new">{i18next.t("tab:Add new tab")}</a>
|
||
{" "}
|
||
</strong>
|
||
</div>
|
||
</div>
|
||
{
|
||
this.state.message !== "" ?
|
||
<div className="message" onClick={() => this.clearMessage()}>
|
||
<li className="fa fa-exclamation-triangle"></li>
|
||
{" "}
|
||
{this.state.message}
|
||
</div> : null
|
||
}
|
||
<div id="all-tabs">
|
||
{
|
||
this.state.tabs !== null && this.state.tabs.length !== 0 ?
|
||
this.state.tabs.map(tab => this.renderTabs(tab)) :
|
||
<div className="cell" style={{textAlign: "center", height: "100px", lineHeight: "100px"}}>
|
||
{
|
||
this.state.tabs === null ?
|
||
i18next.t("tab:No tab yet") : i18next.t("loading:Data is loading...")
|
||
}
|
||
</div>
|
||
}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
}
|
||
|
||
export default withRouter(AdminTab);
|