feat: move policy table from adapter to enforcer and improve it (#2228)

* feat: improve policiy table

* feat: add connection test in AdapterEditPage.js

* feat: update button style
This commit is contained in:
Yaodong Yu
2023-08-18 18:35:56 +08:00
committed by Yang Luo
parent d12117324c
commit a41f6880a2
10 changed files with 280 additions and 347 deletions

View File

@ -19,11 +19,6 @@ import * as OrganizationBackend from "./backend/OrganizationBackend";
import * as Setting from "./Setting";
import i18next from "i18next";
import "codemirror/lib/codemirror.css";
import PolicyTable from "./table/PoliciyTable";
require("codemirror/theme/material-darker.css");
require("codemirror/mode/javascript/javascript");
const {Option} = Select;
class AdapterEditPage extends React.Component {
@ -232,10 +227,23 @@ class AdapterEditPage extends React.Component {
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("adapter:Policies"), i18next.t("adapter:Policies - Tooltip"))} :
{Setting.getLabel(i18next.t("provider:DB Test"), i18next.t("provider:DB Test - Tooltip"))} :
</Col>
<Col span={22}>
<PolicyTable owner={this.state.organizationName} name={this.state.adapterName} mode={this.state.mode} />
<Col span={2} >
<Button type={"primary"} onClick={() => {
AdapterBackend.getPolicies("", "", `${this.state.organizationName}/${this.state.adapterName}`)
.then((res) => {
if (res.status === "ok") {
Setting.showMessage("success", i18next.t("syncer:Connect successfully"));
} else {
Setting.showMessage("error", i18next.t("syncer:Failed to connect") + ": " + res.msg);
}
})
.catch(error => {
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
});
}
}>{i18next.t("syncer:Test DB Connection")}</Button>
</Col>
</Row>
<Row style={{marginTop: "20px"}} >

View File

@ -18,6 +18,7 @@ import * as AdapterBackend from "./backend/AdapterBackend";
import * as EnforcerBackend from "./backend/EnforcerBackend";
import * as ModelBackend from "./backend/ModelBackend";
import * as OrganizationBackend from "./backend/OrganizationBackend";
import PolicyTable from "./table/PolicyTable";
import * as Setting from "./Setting";
import i18next from "i18next";
@ -42,7 +43,7 @@ class EnforcerEditPage extends React.Component {
}
getEnforcer() {
EnforcerBackend.getEnforcer(this.state.organizationName, this.state.enforcerName)
EnforcerBackend.getEnforcer(this.state.organizationName, this.state.enforcerName, true)
.then((res) => {
if (res.data === null) {
this.props.history.push("/404");
@ -185,6 +186,14 @@ class EnforcerEditPage extends React.Component {
} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("adapter:Policies"), i18next.t("adapter:Policies - Tooltip"))} :
</Col>
<Col span={22}>
<PolicyTable enforcer={this.state.enforcer} modelCfg={this.state.enforcer?.modelCfg} mode={this.state.mode} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
{Setting.getLabel(i18next.t("general:Is enabled"), i18next.t("general:Is enabled - Tooltip"))} :

View File

@ -103,8 +103,8 @@ export function RemovePolicy(owner, name, policy) {
}).then(res => res.json());
}
export function getPolicies(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-policies?id=${owner}/${encodeURIComponent(name)}`, {
export function getPolicies(owner, name, adapterId = "") {
return fetch(`${Setting.ServerUrl}/api/get-policies?id=${owner}/${encodeURIComponent(name)}&adapterId=${adapterId}`, {
method: "GET",
credentials: "include",
headers: {

View File

@ -24,8 +24,8 @@ export function getEnforcers(owner, page = "", pageSize = "", field = "", value
}).then(res => res.json());
}
export function getEnforcer(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-enforcer?id=${owner}/${encodeURIComponent(name)}`, {
export function getEnforcer(owner, name, loadModelCfg = false) {
return fetch(`${Setting.ServerUrl}/api/get-enforcer?id=${owner}/${encodeURIComponent(name)}&loadModelCfg=${loadModelCfg}`, {
method: "GET",
credentials: "include",
headers: {

View File

@ -14,7 +14,7 @@
import React from "react";
import {DeleteOutlined, EditOutlined} from "@ant-design/icons";
import {Button, Input, Popconfirm, Table, Tooltip} from "antd";
import {Button, Input, Popconfirm, Select, Table, Tooltip} from "antd";
import * as Setting from "../Setting";
import * as AdapterBackend from "../backend/AdapterBackend";
import i18next from "i18next";
@ -42,7 +42,7 @@ class PolicyTable extends React.Component {
UNSAFE_componentWillMount() {
if (this.props.mode === "edit") {
this.synPolicies();
this.getPolicies();
}
}
@ -100,9 +100,9 @@ class PolicyTable extends React.Component {
this.state.add ? this.addPolicy(table, i) : this.updatePolicy(table, i);
}
synPolicies() {
getPolicies() {
this.setState({loading: true});
AdapterBackend.getPolicies(this.props.owner, this.props.name)
AdapterBackend.getPolicies(this.props.enforcer.owner, this.props.enforcer.name)
.then((res) => {
if (res.status === "ok") {
Setting.showMessage("success", i18next.t("adapter:Sync policies successfully"));
@ -124,7 +124,7 @@ class PolicyTable extends React.Component {
}
updatePolicy(table, i) {
AdapterBackend.UpdatePolicy(this.props.owner, this.props.name, [this.state.oldPolicy, table[i]]).then(res => {
AdapterBackend.UpdatePolicy(this.props.enforcer.owner, this.props.enforcer.name, [this.state.oldPolicy, table[i]]).then(res => {
if (res.status === "ok") {
this.setState({editingIndex: "", oldPolicy: ""});
Setting.showMessage("success", i18next.t("general:Successfully saved"));
@ -135,7 +135,7 @@ class PolicyTable extends React.Component {
}
addPolicy(table, i) {
AdapterBackend.AddPolicy(this.props.owner, this.props.name, table[i]).then(res => {
AdapterBackend.AddPolicy(this.props.enforcer.owner, this.props.enforcer.name, table[i]).then(res => {
if (res.status === "ok") {
this.setState({editingIndex: "", oldPolicy: "", add: false});
if (res.data !== "Affected") {
@ -151,7 +151,7 @@ class PolicyTable extends React.Component {
}
deletePolicy(table, index) {
AdapterBackend.RemovePolicy(this.props.owner, this.props.name, table[this.getIndex(index)]).then(res => {
AdapterBackend.RemovePolicy(this.props.enforcer.owner, this.props.enforcer.name, table[this.getIndex(index)]).then(res => {
if (res.status === "ok") {
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
@ -163,140 +163,76 @@ class PolicyTable extends React.Component {
}
renderTable(table) {
if (this.props.modelCfg === undefined) {
return null;
}
const columns = [
{
title: i18next.t("adapter:Rule type"),
dataIndex: "Ptype",
width: "100px",
// render: (text, record, index) => {
// const editing = this.isEditing(index);
// return (
// editing ?
// <Input value={text} onChange={e => {
// this.updateField(table, index, "Ptype", e.target.value);
// }} />
// : text
// );
// },
},
{
title: "V0",
dataIndex: "V0",
width: "100px",
render: (text, record, index) => {
const editing = this.isEditing(index);
return (
editing ?
<Input value={text} onChange={e => {
this.updateField(table, index, "V0", e.target.value);
<Select options={Object.keys(this.props.modelCfg).map(item => Setting.getOption(item, item))} value={text} onChange={value => {
this.updateField(table, index, "Ptype", value);
}} />
: text
);
},
},
{
title: "V1",
dataIndex: "V1",
width: "100px",
];
const columnKeys = ["V0", "V1", "V2", "V3", "V4", "V5"];
const columnTitles = this.props.modelCfg["p"].split(",");
columnTitles.forEach((title, i) => {
columns.push({
title: title,
dataIndex: columnKeys[i],
width: "200px",
render: (text, record, index) => {
const editing = this.isEditing(index);
return (
editing ?
<Input value={text} onChange={e => {
this.updateField(table, index, "V1", e.target.value);
this.updateField(table, index, columnKeys[i], e.target.value);
}} />
: text
);
},
},
{
title: "V2",
dataIndex: "V2",
width: "100px",
render: (text, record, index) => {
const editing = this.isEditing(index);
return (
editing ?
<Input value={text} onChange={e => {
this.updateField(table, index, "V2", e.target.value);
}} />
: text
);
},
},
{
title: "V3",
dataIndex: "V3",
width: "100px",
render: (text, record, index) => {
const editing = this.isEditing(index);
return (
editing ?
<Input value={text} onChange={e => {
this.updateField(table, index, "V3", e.target.value);
}} />
: text
);
},
},
{
title: "V4",
dataIndex: "V4",
width: "100px",
render: (text, record, index) => {
const editing = this.isEditing(index);
return (
editing ?
<Input value={text} onChange={e => {
this.updateField(table, index, "V4", e.target.value);
}} />
: text
);
},
},
{
title: "V5",
dataIndex: "V5",
width: "100px",
render: (text, record, index) => {
const editing = this.isEditing(index);
return (
editing ?
<Input value={text} onChange={e => {
this.updateField(table, index, "V5", e.target.value);
}} />
: text
);
},
},
{
title: i18next.t("general:Action"),
dataIndex: "",
key: "op",
width: "100px",
render: (text, record, index) => {
const editable = this.isEditing(index);
return editable ? (
<span>
<Button style={{marginRight: 8}} onClick={() => this.save(table, index)}>
});
});
columns.push({
title: i18next.t("general:Action"),
dataIndex: "",
key: "op",
width: "100px",
render: (text, record, index) => {
const editable = this.isEditing(index);
return editable ? (
<span>
<Button style={{marginRight: 8}} onClick={() => this.save(table, index)}>
Save
</Button>
<Popconfirm title="Sure to cancel?" onConfirm={() => this.cancel(table, index)}>
<a>Cancel</a>
</Popconfirm>
</span>
) : (
<div>
<Tooltip placement="topLeft" title="Edit">
<Button disabled={this.state.editingIndex !== "" || Setting.builtInObject({owner: this.props.owner, name: this.props.name})} style={{marginRight: "5px"}} icon={<EditOutlined />} size="small" onClick={() => this.edit(record, index)} />
</Tooltip>
<Tooltip placement="topLeft" title="Delete">
<Button disabled={this.state.editingIndex !== "" || Setting.builtInObject({owner: this.props.owner, name: this.props.name})} style={{marginRight: "5px"}} icon={<DeleteOutlined />} size="small" onClick={() => this.deletePolicy(table, index)} />
</Tooltip>
</div>
);
},
}];
</Button>
<Popconfirm title="Sure to cancel?" onConfirm={() => this.cancel(table, index)}>
<a>Cancel</a>
</Popconfirm>
</span>
) : (
<div>
<Tooltip placement="topLeft" title="Edit">
<Button disabled={this.state.editingIndex !== "" || Setting.builtInObject(this.props.enforcer)} style={{marginRight: "5px"}} icon={<EditOutlined />} size="small" onClick={() => this.edit(record, index)} />
</Tooltip>
<Tooltip placement="topLeft" title="Delete">
<Button disabled={this.state.editingIndex !== "" || Setting.builtInObject(this.props.enforcer)} style={{marginRight: "5px"}} icon={<DeleteOutlined />} size="small" onClick={() => this.deletePolicy(table, index)} />
</Tooltip>
</div>
);
},
});
return (
<Table
@ -311,7 +247,7 @@ class PolicyTable extends React.Component {
loading={this.state.loading}
title={() => (
<div>
<Button disabled={this.state.editingIndex !== "" || Setting.builtInObject({owner: this.props.owner, name: this.props.name})} style={{marginRight: "5px"}} type="primary" size="small" onClick={() => this.addRow(table)}>{i18next.t("general:Add")}</Button>
<Button disabled={this.state.editingIndex !== "" || Setting.builtInObject(this.props.enforcer)} style={{marginRight: "5px"}} type="primary" size="small" onClick={() => this.addRow(table)}>{i18next.t("general:Add")}</Button>
</div>
)}
/>
@ -321,7 +257,7 @@ class PolicyTable extends React.Component {
render() {
return (
<React.Fragment>
<Button type="primary" disabled={this.state.editingIndex !== ""} onClick={() => {this.synPolicies();}}>
<Button type="primary" disabled={this.state.editingIndex !== ""} onClick={() => {this.getPolicies();}}>
{i18next.t("general:Sync")}
</Button>
{