From c626055edf712bc0d0b5fe155c5464c2fcc1181e Mon Sep 17 00:00:00 2001 From: Love98 <77888749+love98ooo@users.noreply.github.com> Date: Mon, 5 Aug 2024 00:03:06 +0800 Subject: [PATCH] feat: add RuleTable to SiteEditPage (#55) --- object/site.go | 2 +- web/src/Setting.js | 5 ++ web/src/SiteEditPage.js | 31 ++++++++ web/src/components/RuleTable.js | 136 ++++++++++++++++++++++++++++++++ 4 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 web/src/components/RuleTable.js diff --git a/object/site.go b/object/site.go index b1a74c7..ee670cd 100644 --- a/object/site.go +++ b/object/site.go @@ -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"` diff --git a/web/src/Setting.js b/web/src/Setting.js index 5aa8a3e..38267ff 100644 --- a/web/src/Setting.js +++ b/web/src/Setting.js @@ -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; +} diff --git a/web/src/SiteEditPage.js b/web/src/SiteEditPage.js index 5c9d6ce..1eef9ce 100644 --- a/web/src/SiteEditPage.js +++ b/web/src/SiteEditPage.js @@ -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; @@ -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, @@ -40,6 +43,7 @@ class SiteEditPage extends React.Component { UNSAFE_componentWillMount() { this.getSite(); this.getCerts(); + this.getRules(); this.getApplications(); } @@ -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) => { @@ -179,6 +196,20 @@ class SiteEditPage extends React.Component { }} /> + + + {i18next.t("site:Rules")}: + + + this.updateSiteField("rules", value)} + /> + + {i18next.t("site:Challenges")}: diff --git a/web/src/components/RuleTable.js b/web/src/components/RuleTable.js new file mode 100644 index 0000000..53f0e71 --- /dev/null +++ b/web/src/components/RuleTable.js @@ -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) => ( + + ), + }, + { + title: "Action", + key: "action", + width: "100px", + render: (text, record, index) => ( +
+ +
+ ), + }, + ]; + return ( + ( +
+ {this.props.title}     + +
+ )} + /> + ); + } + + render() { + return ( +
+ +
+ { + this.renderTable(this.props.rules.map((item, index) => { + const values = item.split("/"); + return {owner: values[0], name: values[1]}; + })) + } + + + + ); + } +} + +export default RuleTable;