casnode/web/src/admin/AdminPlane.js

724 lines
25 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 PlaneBackend from "../backend/PlaneBackend.js";
import * as Setting from "../Setting";
import Zmage from "react-zmage";
import {SketchPicker} from "react-color";
import i18next from "i18next";
class AdminPlane extends React.Component {
constructor(props) {
super(props);
this.state = {
classes: props,
nodes: [],
planes: [],
message: "",
errorMessage: "",
form: {},
plane: [],
//event: props.match.params.event,
planeId: props.match.params.planeId,
width: "",
event: "basic",
Management_LIST: [
{label: "Basic Info", value: "basic"},
{label: "Display", value: "display"},
],
color: "",
backgroundColor: "",
displayColorPicker: false,
displayBackgroundColorPicker: false,
};
}
componentDidMount() {
this.getPlane();
this.getPlanes();
}
getPlanes() {
PlaneBackend.getPlanesAdmin()
.then((res) => {
this.setState({
planes: res,
});
});
}
getPlane() {
if (this.state.planeId === undefined && this.props.event !== "new") {
return;
}
PlaneBackend.getPlaneAdmin(this.state.planeId)
.then((res) => {
this.setState({
plane: res,
color: res?.color,
backgroundColor: res?.backgroundColor,
}, () => {
this.initForm();
});
});
}
initForm() {
let form = this.state.form;
if (this.props.event === "new") {
form["sorter"] = 1;
form["visible"] = true;
} else {
form["id"] = this.state.plane?.id;
form["name"] = this.state.plane?.name;
form["createdTime"] = this.state.plane?.createdTime;
form["sorter"] = this.state.plane?.sorter;
form["image"] = this.state.plane?.image;
form["backgroundColor"] = this.state.plane?.backgroundColor;
form["color"] = this.state.plane?.color;
form["visible"] = this.state.plane?.visible;
}
this.setState({
form: form,
});
}
updateFormField(key, value) {
let form = this.state.form;
form[key] = value;
this.setState({
form: form,
});
}
deletePlane(plane, planeId, nodesNum) {
if (window.confirm(`${i18next.t(`plane:Are you sure to delete plane`)} ${plane} ?`)) {
if (nodesNum !== 0) {
alert(`
${i18next.t("plane:Please delete all the nodes or move to another plane before deleting the plane")}
${i18next.t("plane:Currently the number of nodes under the plane is")} ${nodesNum}
`);
} else {
PlaneBackend.deletePlane(planeId)
.then((res) => {
if (res.status === 'ok') {
this.setState({
message: `${i18next.t("plane:Delete plane")} ${plane} ${i18next.t("plane:success")}`,
});
this.getPlanes();
} else {
this.setState({
errorMessage: res?.msg,
});
}
});
}
}
}
updatePlaneInfo() {
PlaneBackend.updatePlane(this.state.planeId, this.state.form)
.then((res) => {
if (res.status === 'ok') {
this.getPlane();
this.setState({
message: i18next.t("plane:Update plane information success"),
});
} else {
this.setState({
message: res?.msg,
});
}
});
}
postNewPlane() {
if (this.state.form.id === undefined || this.state.form.id === "") {
this.setState({
errorMessage: "Please input plane ID",
});
return;
}
if (this.state.form.name === "" || this.state.form.name === undefined) {
this.setState({
errorMessage: "Please input plane name",
});
return;
}
PlaneBackend.addPlane(this.state.form)
.then((res) => {
if (res.status === 'ok') {
this.getPlane();
this.setState({
errorMessage: "",
message: i18next.t("plane:Creat plane success"),
}, () => {
setTimeout(() => Setting.goToLink(`/admin/plane/edit/${this.state.form.id}`), 1600);
});
} else {
this.setState({
errorMessage: res?.msg,
});
}
});
}
clearMessage() {
this.setState({
message: "",
});
}
clearErrorMessage() {
this.setState({
errorMessage: "",
});
}
handleColorChange = (color, event) => {
if (event === "color") {
this.updateFormField("color", color.hex);
return;
}
this.updateFormField("backgroundColor", color.hex);
};
handleColorClick = (event) => {
if (event === "color") {
this.setState({
displayColorPicker: !this.state.displayColorPicker,
});
return;
}
this.setState({
displayBackgroundColorPicker: !this.state.displayBackgroundColorPicker,
});
};
handleColorClose = (event) => {
if (event === "color") {
this.setState({
displayColorPicker: false,
});
return;
}
this.setState({
displayBackgroundColorPicker: false,
});
};
changeEvent(event) {
this.setState({
event: event,
message: "",
});
if (this.props.event !== "new") {
this.initForm();
}
}
resetColor(event) {
if (event === "color") {
this.updateFormField("color", this.state.color);
return;
}
this.updateFormField("backgroundColor", this.state.backgroundColor);
}
renderColorPicker(event) {
return (
<div style={{
padding: '5px',
background: '#fff',
borderRadius: '1px',
boxShadow: '0 0 0 1px rgba(0,0,0,.1)',
display: 'inline-block',
cursor: 'pointer'
}} onClick={() => this.handleColorClick(event)} >
<div style={{
width: '36px',
height: '14px',
borderRadius: '2px',
background: event === "color" ? `${this.state.form.color}` : `${this.state.form.backgroundColor}`
}} />
</div>
);
}
renderNode(node) {
return (
<span>
<a href={`/go/${node.id}`}>
{node.name}
</a>{" "}&nbsp;{" "}
</span>
);
}
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(`plane:${item.label}`)}</a>
);
}
renderHeader() {
return (
<div className="box">
<div className="header"><a href="/">{Setting.getForumName()}</a>
{" "}<span className="chevron">&nbsp;&nbsp;</span>
<a href={`/admin`}>{i18next.t("admin:Backstage management")}</a>
{" "}<span className="chevron">&nbsp;&nbsp;</span>
<a href={`/admin/plane`}>{i18next.t("plane:Plane management")}</a>
{" "}<span className="chevron">&nbsp;&nbsp;</span>
<span>
{
this.props.event === "new" ?
i18next.t("plane:New plane") : this.state.planeId
}
</span>
</div>
<div className="cell">
{
this.state.Management_LIST.map((item) => {
return this.renderManagementList(item);
})
}
</div>
</div>
);
}
renderPlanes(plane) {
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">
{plane?.name}
</span>
</td>
<td width={pcBrowser ? "100" : "auto"} align="center">
<a href={`/admin/plane/edit/${plane?.id}`}>
{i18next.t("plane:Manage")}
</a>
</td>
<td width="10"></td>
<td width={pcBrowser ? "120" : "80"} valign="middle" style={{textAlign: "center"}}>
<span style={{fontSize: "13px"}}>
{plane?.nodesNum}{" "}{i18next.t("plane:nodes")}
</span>
</td>
<td width={pcBrowser ? "120" : "80"} align="left" style={{textAlign: "center"}}>
{
plane?.visible ?
<span className="positive">
{i18next.t("plane:Visible")}
</span> :
<span className="gray">
{i18next.t("plane:Invisible")}
</span>
}
</td>
<td width="50" align="left" style={{textAlign: "right"}}>
<a href="#" onClick={() => this.deletePlane(plane?.name, plane?.id, plane?.nodesNum)}>
{i18next.t("plane:Delete")}
</a>
</td>
</tr>
</tbody>
</table>
</div>
);
}
render() {
const newPlane = (this.props.event === "new");
if (this.state.planeId !== undefined || newPlane) {
if (this.state.planeId !== undefined) {
if (this.state.plane !== null && this.state.plane.length === 0) {
return (
<div className="box">
<div className="header"><a href="/">{Setting.getForumName()}</a><span className="chevron">&nbsp;&nbsp;</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.plane === null) {
return (
<div class="box">
<div class="header">
<a href="/">{Setting.getForumName()}</a>
<span className="chevron">&nbsp;&nbsp;</span>{" "}{i18next.t("error:Plane not found")}</div>
<div class="cell">
{i18next.t("error:The plane you are trying to view does not exist")}
</div>
</div>
);
}
}
const plane = this.state.plane;
if (this.state.event === "basic") {
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>
&nbsp;{" "}
{this.state.message}
</div> : null
}
<div className="inner">
<table cellPadding="5" cellSpacing="0" border="0" width="100%">
<tbody>
{
newPlane ?
<tr>
<td width="120" align="right">{i18next.t("plane:Plane ID")}</td>
<td width="auto" align="left">
<input type="text" className="sl" name="id" id="plane_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("plane:Plane name")}</td>
<td width="auto" align="left">
<input type="text" className="sl" name="name" id="plane_name" value={this.state.form?.name===undefined ? "" : this.state.form?.name} onChange={event => this.updateFormField("name", event.target.value)} autoComplete="off" />
</td>
</tr>
{
!newPlane ?
<tr>
<td width="120" align="right">{i18next.t("plane:Created time")}</td>
<td width="auto" align="left">
<span className="gray">
{plane?.createdTime}
</span>
</td>
</tr> : null
}
{
!newPlane ?
<tr>
<td width="120" align="right">{i18next.t("plane:Total nodes")}</td>
<td width="auto" align="left">
<span className="gray">
{plane?.nodesNum}
</span>
</td>
</tr> : null
}
{
!newPlane ?
<tr>
<td width="120" align="right">{i18next.t("plane:Nodes")}</td>
<td width="auto" align="left">
<span className="gray">
{
this.state.plane?.nodes.length !== 0 ?
this.state.plane?.nodes.map(node => this.renderNode(node)) :
i18next.t("plane:No node yet")
}
</span>
</td>
</tr> : null
}
<tr>
<td width="120" align="right">{i18next.t("plane: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))}/>
&nbsp;{" "}&nbsp;{" "}
<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("plane:Decide the order of node navigation")}
</span>
</td>
</tr>
<tr>
<td width="120" align="right">{i18next.t("plane:Visible")}</td>
<td width="auto" align="left">
<input type="radio" onClick={() => this.updateFormField("visible", true)} checked={this.state.form?.visible} name="visible" />{i18next.t("plane:Visible")}{" "}
<input type="radio" onClick={() => this.updateFormField("visible", false)} checked={!this.state.form?.visible} name="visible" />{i18next.t("plane:Invisible")}
</td>
</tr>
{
!this.state.form.visible ?
<tr>
<td width="120" align="right"></td>
<td width="auto" align="left">
<span className="gray">
{i18next.t("plane:This plane will not appear on the node navigation")}
</span>
</td>
</tr> : null
}
<tr>
<td width="120" align="right"></td>
<td width="auto" align="left">
{
!newPlane ?
<input type="submit" className="super normal button" value={i18next.t("plane:Save")} onClick={() => this.updatePlaneInfo()}/> : null
}
</td>
</tr>
{
newPlane ?
<tr>
<td width="120" align="right"></td>
<td width="auto" align="left">
<span className="gray">
{i18next.t("plane:Please go to the display page to continue to improve the information and submit")}
</span>
</td>
</tr> : null
}
</tbody>
</table>
</div>
</div>
</div>
);
}
// display
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>
&nbsp;{" "}
{this.state.message}
</div> : null
}
<div className="inner">
<table cellPadding="5" cellSpacing="0" border="0" width="100%">
<tbody>
<tr>
<td width="120" align="right">{i18next.t("plane:Image")}</td>
<td width="auto" align="left">
{
this.state.form?.image === undefined || this.state.form?.image === "" ?
<span className="gray">
{i18next.t("plane:Not set")}
</span> :
<Zmage
src={this.state.form?.image} alt={this.state.form?.id} style={{maxWidth: "48px", maxHeight: "48px"}}
/>
}
</td>
</tr>
<tr>
<td width="120" align="right">
{
newPlane ?
i18next.t("plane:Set image") :
i18next.t("plane:Change image")
}
</td>
<td width="auto" align="left">
<input type="text" className="sl" name="image" id="change_image" value={this.state.form?.image===undefined ? "" : this.state.form?.image} onChange={event => this.updateFormField("image", event.target.value)} autoComplete="off" />
</td>
</tr>
<tr>
<td width="120" align="right">{i18next.t("plane:Font color")}</td>
<td width="auto" align="left">
{this.renderColorPicker("color")}
{
this.state.displayColorPicker ?
<div style={{
position: 'absolute',
zIndex: '2'}}
>
<div style={{
position: 'fixed',
top: '0px',
right: '0px',
bottom: '0px',
left: '0px'
}} onClick={() => this.handleColorClose("color")} />
<SketchPicker color={this.state.form.color} onChange={(color) => this.handleColorChange(color, "color")} />
</div> : null
}
{" "}&nbsp;{" "}
{
!newPlane ?
<a href="#" onClick={() => this.resetColor("color")}>
{i18next.t("plane:Restore")}
</a> : null
}
</td>
</tr>
<tr>
<td width="120" align="right">{i18next.t("plane:Background color")}</td>
<td width="auto" align="left">
{this.renderColorPicker("backgroundColor")}
{
this.state.displayBackgroundColorPicker ?
<div style={{
position: 'absolute',
zIndex: '2'}}
>
<div style={{
position: 'fixed',
top: '0px',
right: '0px',
bottom: '0px',
left: '0px'
}} onClick={() => this.handleColorClose("backgroundColor")} />
<SketchPicker color={this.state.form.backgroundColor} onChange={(color) => this.handleColorChange(color, "backgroundColor")} />
</div> : null
}
{" "}&nbsp;{" "}
{
!newPlane ?
<a href="#" onClick={() => this.resetColor("backgroundColor")}>
{i18next.t("plane:Restore")}
</a> : null
}
</td>
</tr>
<tr>
<td width="120" align="right">{i18next.t("plane:Preview")}</td>
<td width="auto" align="left">
<div className="header" style={{backgroundColor: this.state.form?.backgroundColor, color: this.state.form?.color, fontSize: Setting.PcBrowser ? "" : "13px"}}>
<img src={this.state.form?.image} border="0" align="absmiddle" width="24"/>
{" "}&nbsp;{" "}{this.state.form?.name}
<span className="fr" style={{color: this.state.form?.color, lineHeight: "20px"}}>
{this.state.form?.id}{" "}{" "}
{
!newPlane ?
<span className="small">
{plane?.nodesNum}{" "}nodes
</span> : null
}
</span>
</div>
</td>
</tr>
<tr>
<td width="120" align="right"></td>
<td width="auto" align="left">
{
newPlane ?
<input type="submit" className="super normal button" value={i18next.t("plane:Create")} onClick={() => this.postNewPlane()}/> :
<input type="submit" className="super normal button" value={i18next.t("plane:Save")} onClick={() => this.updatePlaneInfo()}/>
}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
);
}
return (
<div className="box">
<div className="header">
<a href="/">{Setting.getForumName()}</a>
{" "}<span className="chevron">&nbsp;&nbsp;</span>
<a href={`/admin`}>{i18next.t("admin:Backstage management")}</a>
<span className="chevron">&nbsp;&nbsp;</span>{" "}{i18next.t("plane:Plane management")}
<div className="fr f12">
<span className="snow">{i18next.t("plane:Total planes")}{" "}&nbsp;</span>
<strong className="gray">{this.state.planes === null ? 0 : this.state.planes.length}</strong>
</div>
<div className="fr f12">
<strong className="gray">
<a href="plane/new">{i18next.t("plane:Add new plane")}</a>
{" "}&nbsp;
</strong>
</div>
</div>
{
this.state.message !== "" ?
<div className="message" onClick={() => this.clearMessage()}>
<li className="fa fa-exclamation-triangle"></li>
&nbsp;{" "}
{this.state.message}
</div> : null
}
<div id="all-planes">
{
this.state.planes !== null && this.state.planes.length !== 0 ?
this.state.planes.map(plane => this.renderPlanes(plane)) :
<div className="cell" style={{textAlign: "center", height: "100px", lineHeight: "100px"}}>
{
this.state.planes === null ?
i18next.t("plane:No plant yet") : i18next.t("loading:Data is loading...")
}
</div>
}
</div>
</div>
);
}
}
export default withRouter(AdminPlane);