Skip to content

Commit

Permalink
feat: add RuleTable to SiteEditPage (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
love98ooo authored Aug 4, 2024
1 parent f5aae96 commit c626055
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 1 deletion.
2 changes: 1 addition & 1 deletion object/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ type Site struct {
OtherDomains []string `xorm:"varchar(500)" json:"otherDomains"`
NeedRedirect bool `json:"needRedirect"`
DisableVerbose bool `json:"disableVerbose"`
Rules []string `xorm:"varchar(500)" json:"wafRuleIds"`
Rules []string `xorm:"varchar(500)" json:"rules"`
Challenges []string `xorm:"mediumtext" json:"challenges"`
Host string `xorm:"varchar(100)" json:"host"`
Port int `json:"port"`
Expand Down
5 changes: 5 additions & 0 deletions web/src/Setting.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,8 @@ export function getVersionInfo(text, siteName) {

return {text: versionText, link: link};
}

export function getDeduplicatedArray(sourceTable, filterTable, key) {
const res = sourceTable.filter(item => !filterTable.some(arrayItem => arrayItem[key] === item[key]));
return res;
}
31 changes: 31 additions & 0 deletions web/src/SiteEditPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ import {Button, Card, Col, Input, InputNumber, Row, Select, Switch} from "antd";
import {LinkOutlined} from "@ant-design/icons";
import * as SiteBackend from "./backend/SiteBackend";
import * as CertBackend from "./backend/CertBackend";
import * as RuleBackend from "./backend/RuleBackend";
import * as ApplicationBackend from "./backend/ApplicationBackend";
import * as Setting from "./Setting";
import i18next from "i18next";
import NodeTable from "./NodeTable";
import RuleTable from "./components/RuleTable";

const {Option} = Select;

Expand All @@ -31,6 +33,7 @@ class SiteEditPage extends React.Component {
classes: props,
owner: props.match.params.owner,
siteName: props.match.params.siteName,
rules: [],
site: null,
certs: null,
applications: null,
Expand All @@ -40,6 +43,7 @@ class SiteEditPage extends React.Component {
UNSAFE_componentWillMount() {
this.getSite();
this.getCerts();
this.getRules();
this.getApplications();
}

Expand Down Expand Up @@ -69,6 +73,19 @@ class SiteEditPage extends React.Component {
});
}

getRules() {
RuleBackend.getRules(this.props.account.name)
.then((res) => {
if (res.status === "ok") {
this.setState({
rules: res.data,
});
} else {
Setting.showMessage("error", `Failed to get rules: ${res.msg}`);
}
});
}

getApplications() {
ApplicationBackend.getApplications(this.props.account.name)
.then((res) => {
Expand Down Expand Up @@ -179,6 +196,20 @@ class SiteEditPage extends React.Component {
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={2}>
{i18next.t("site:Rules")}:
</Col>
<Col span={22} >
<RuleTable
title={"Rules"}
account={this.props.account}
sources={this.state.rules}
rules={this.state.site.rules}
onUpdateRules={(value) => this.updateSiteField("rules", value)}
/>
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={2}>
{i18next.t("site:Challenges")}:
Expand Down
136 changes: 136 additions & 0 deletions web/src/components/RuleTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright 2023 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 {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Row, Select, Table, Tooltip} from "antd";
import * as Setting from "../Setting";

const {Option} = Select;

class RuleTable extends React.Component {
constructor(props) {
super(props);
this.state = {
classes: props,
};
}

updateTable(table) {
const rules = [];
for (let i = 0; i < table.length; i++) {
rules.push(table[i].owner + "/" + table[i].name);
}
this.props.onUpdateRules(rules);
}

updateField(table, index, key, value) {
table[index][key] = value;
this.updateTable(table);
}

addRow(table) {
const row = {owner: this.props.account.name, name: ""};
if (table === undefined) {
table = [];
}

table = Setting.addRow(table, row);
this.updateTable(table);
}

deleteRow(table, i) {
table = Setting.deleteRow(table, i);
this.updateTable(table);
}

upRow(table, i) {
table = Setting.swapRow(table, i - 1, i);
this.updateTable(table);
}

downRow(table, i) {
table = Setting.swapRow(table, i, i + 1);
this.updateTable(table);
}

renderTable(table) {
const columns = [
{
title: "Name",
dataIndex: "name",
key: "name",
width: "180px",
render: (text, record, index) => (
<Select value={text} virtual={false} style={{width: "100%"}} onChange={value => {
this.updateField(table, index, "name", value);
}}>
{
Setting.getDeduplicatedArray(this.props.sources, table, "name").map((record, index) => {
return <Option key={record.name} value={record.name}>{record.name}</Option>;
})
}
</Select>
),
},
{
title: "Action",
key: "action",
width: "100px",
render: (text, record, index) => (
<div>
<Tooltip placement="bottomLeft" title={"Up"}>
<Button style={{marginRight: "5px"}} disabled={index === 0} icon={<UpOutlined />} size="small" onClick={() => this.upRow(table, index)} />
</Tooltip>
<Tooltip placement="topLeft" title={"Down"}>
<Button style={{marginRight: "5px"}} disabled={index === table.length - 1} icon={<DownOutlined />} size="small" onClick={() => this.downRow(table, index)} />
</Tooltip>
<Tooltip placement="topLeft" title={"Delete"}>
<Button icon={<DeleteOutlined />} size="small" onClick={() => this.deleteRow(table, index)} />
</Tooltip>
</div>
),
},
];
return (
<Table rowKey="index" columns={columns} dataSource={table} size="middle" bordered pagination={false}
title={() => (
<div>
{this.props.title}&nbsp;&nbsp;&nbsp;&nbsp;
<Button style={{marginRight: "5px"}} type="primary" size="small" onClick={() => this.addRow(table)}>{"Add"}</Button>
</div>
)}
/>
);
}

render() {
return (
<div>
<Row style={{marginTop: "20px"}} >
<Col span={24}>
{
this.renderTable(this.props.rules.map((item, index) => {
const values = item.split("/");
return {owner: values[0], name: values[1]};
}))
}
</Col>
</Row>
</div>
);
}
}

export default RuleTable;

0 comments on commit c626055

Please sign in to comment.