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

@ -20,7 +20,6 @@ import (
"github.com/beego/beego/utils/pagination" "github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
xormadapter "github.com/casdoor/xorm-adapter/v3"
) )
// GetAdapters // GetAdapters
@ -144,92 +143,3 @@ func (c *ApiController) DeleteAdapter() {
c.Data["json"] = wrapActionResponse(object.DeleteAdapter(&adapter)) c.Data["json"] = wrapActionResponse(object.DeleteAdapter(&adapter))
c.ServeJSON() c.ServeJSON()
} }
func (c *ApiController) GetPolicies() {
id := c.Input().Get("id")
adapter, err := object.GetAdapter(id)
if err != nil {
c.ResponseError(err.Error())
return
}
policies, err := object.GetPolicies(adapter)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(policies)
}
func (c *ApiController) UpdatePolicy() {
id := c.Input().Get("id")
adapter, err := object.GetAdapter(id)
if err != nil {
c.ResponseError(err.Error())
return
}
var policies []xormadapter.CasbinRule
err = json.Unmarshal(c.Ctx.Input.RequestBody, &policies)
if err != nil {
c.ResponseError(err.Error())
return
}
affected, err := object.UpdatePolicy(util.CasbinToSlice(policies[0]), util.CasbinToSlice(policies[1]), adapter)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(affected)
c.ServeJSON()
}
func (c *ApiController) AddPolicy() {
id := c.Input().Get("id")
adapter, err := object.GetAdapter(id)
if err != nil {
c.ResponseError(err.Error())
return
}
var policy xormadapter.CasbinRule
err = json.Unmarshal(c.Ctx.Input.RequestBody, &policy)
if err != nil {
c.ResponseError(err.Error())
return
}
affected, err := object.AddPolicy(util.CasbinToSlice(policy), adapter)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(affected)
c.ServeJSON()
}
func (c *ApiController) RemovePolicy() {
id := c.Input().Get("id")
adapter, err := object.GetAdapter(id)
if err != nil {
c.ResponseError(err.Error())
return
}
var policy xormadapter.CasbinRule
err = json.Unmarshal(c.Ctx.Input.RequestBody, &policy)
if err != nil {
c.ResponseError(err.Error())
return
}
affected, err := object.RemovePolicy(util.CasbinToSlice(policy), adapter)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(affected)
c.ServeJSON()
}

View File

@ -20,6 +20,7 @@ import (
"github.com/beego/beego/utils/pagination" "github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
xormadapter "github.com/casdoor/xorm-adapter/v3"
) )
// GetEnforcers // GetEnforcers
@ -74,6 +75,7 @@ func (c *ApiController) GetEnforcers() {
// @router /get-enforcer [get] // @router /get-enforcer [get]
func (c *ApiController) GetEnforcer() { func (c *ApiController) GetEnforcer() {
id := c.Input().Get("id") id := c.Input().Get("id")
loadModelCfg := c.Input().Get("loadModelCfg")
enforcer, err := object.GetEnforcer(id) enforcer, err := object.GetEnforcer(id)
if err != nil { if err != nil {
@ -81,6 +83,13 @@ func (c *ApiController) GetEnforcer() {
return return
} }
if loadModelCfg == "true" {
err := enforcer.LoadModelCfg()
if err != nil {
return
}
}
c.ResponseOk(enforcer) c.ResponseOk(enforcer)
} }
@ -143,3 +152,88 @@ func (c *ApiController) DeleteEnforcer() {
c.Data["json"] = wrapActionResponse(object.DeleteEnforcer(&enforcer)) c.Data["json"] = wrapActionResponse(object.DeleteEnforcer(&enforcer))
c.ServeJSON() c.ServeJSON()
} }
func (c *ApiController) GetPolicies() {
id := c.Input().Get("id")
adapterId := c.Input().Get("adapterId")
if adapterId != "" {
adapter, err := object.GetAdapter(adapterId)
if err != nil {
c.ResponseError(err.Error())
return
}
err = adapter.InitAdapter()
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk()
return
}
policies, err := object.GetPolicies(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(policies)
}
func (c *ApiController) UpdatePolicy() {
id := c.Input().Get("id")
var policies []xormadapter.CasbinRule
err := json.Unmarshal(c.Ctx.Input.RequestBody, &policies)
if err != nil {
c.ResponseError(err.Error())
return
}
affected, err := object.UpdatePolicy(id, util.CasbinToSlice(policies[0]), util.CasbinToSlice(policies[1]))
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(affected)
c.ServeJSON()
}
func (c *ApiController) AddPolicy() {
id := c.Input().Get("id")
var policy xormadapter.CasbinRule
err := json.Unmarshal(c.Ctx.Input.RequestBody, &policy)
if err != nil {
c.ResponseError(err.Error())
return
}
affected, err := object.AddPolicy(id, util.CasbinToSlice(policy))
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(affected)
c.ServeJSON()
}
func (c *ApiController) RemovePolicy() {
id := c.Input().Get("id")
var policy xormadapter.CasbinRule
err := json.Unmarshal(c.Ctx.Input.RequestBody, &policy)
if err != nil {
c.ResponseError(err.Error())
return
}
affected, err := object.RemovePolicy(id, util.CasbinToSlice(policy))
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(affected)
c.ServeJSON()
}

View File

@ -18,7 +18,6 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/casbin/casbin/v2/model"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
xormadapter "github.com/casdoor/xorm-adapter/v3" xormadapter "github.com/casdoor/xorm-adapter/v3"
@ -150,7 +149,7 @@ func (adapter *Adapter) getTable() string {
} }
} }
func (adapter *Adapter) initAdapter() error { func (adapter *Adapter) InitAdapter() error {
if adapter.Adapter == nil { if adapter.Adapter == nil {
var dataSourceName string var dataSourceName string
@ -214,119 +213,6 @@ func adapterChangeTrigger(oldName string, newName string) error {
return session.Commit() return session.Commit()
} }
func safeReturn(policy []string, i int) string {
if len(policy) > i {
return policy[i]
} else {
return ""
}
}
func matrixToCasbinRules(Ptype string, policies [][]string) []*xormadapter.CasbinRule {
res := []*xormadapter.CasbinRule{}
for _, policy := range policies {
line := xormadapter.CasbinRule{
Ptype: Ptype,
V0: safeReturn(policy, 0),
V1: safeReturn(policy, 1),
V2: safeReturn(policy, 2),
V3: safeReturn(policy, 3),
V4: safeReturn(policy, 4),
V5: safeReturn(policy, 5),
}
res = append(res, &line)
}
return res
}
func GetPolicies(adapter *Adapter) ([]*xormadapter.CasbinRule, error) {
err := adapter.initAdapter()
if err != nil {
return nil, err
}
casbinModel := getModelDef()
err = adapter.LoadPolicy(casbinModel)
if err != nil {
return nil, err
}
policies := matrixToCasbinRules("p", casbinModel.GetPolicy("p", "p"))
policies = append(policies, matrixToCasbinRules("g", casbinModel.GetPolicy("g", "g"))...)
return policies, nil
}
func UpdatePolicy(oldPolicy, newPolicy []string, adapter *Adapter) (bool, error) {
err := adapter.initAdapter()
if err != nil {
return false, err
}
casbinModel := getModelDef()
err = adapter.LoadPolicy(casbinModel)
if err != nil {
return false, err
}
affected := casbinModel.UpdatePolicy("p", "p", oldPolicy, newPolicy)
if err != nil {
return affected, err
}
err = adapter.SavePolicy(casbinModel)
if err != nil {
return false, err
}
return affected, nil
}
func AddPolicy(policy []string, adapter *Adapter) (bool, error) {
err := adapter.initAdapter()
if err != nil {
return false, err
}
casbinModel := getModelDef()
err = adapter.LoadPolicy(casbinModel)
if err != nil {
return false, err
}
casbinModel.AddPolicy("p", "p", policy)
err = adapter.SavePolicy(casbinModel)
if err != nil {
return false, err
}
return true, nil
}
func RemovePolicy(policy []string, adapter *Adapter) (bool, error) {
err := adapter.initAdapter()
if err != nil {
return false, err
}
casbinModel := getModelDef()
err = adapter.LoadPolicy(casbinModel)
if err != nil {
return false, err
}
affected := casbinModel.RemovePolicy("p", "p", policy)
if err != nil {
return affected, err
}
err = adapter.SavePolicy(casbinModel)
if err != nil {
return false, err
}
return affected, nil
}
func (adapter *Adapter) builtInAdapter() bool { func (adapter *Adapter) builtInAdapter() bool {
if adapter.Owner != "built-in" { if adapter.Owner != "built-in" {
return false return false
@ -334,10 +220,3 @@ func (adapter *Adapter) builtInAdapter() bool {
return adapter.Name == "user-adapter-built-in" || adapter.Name == "api-adapter-built-in" return adapter.Name == "user-adapter-built-in" || adapter.Name == "api-adapter-built-in"
} }
func getModelDef() model.Model {
casbinModel := model.NewModel()
casbinModel.AddDef("p", "p", "_, _, _, _, _, _")
casbinModel.AddDef("g", "g", "_, _, _, _, _, _")
return casbinModel
}

View File

@ -18,7 +18,9 @@ import (
"fmt" "fmt"
"github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/config"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
xormadapter "github.com/casdoor/xorm-adapter/v3"
"github.com/xorm-io/core" "github.com/xorm-io/core"
) )
@ -34,6 +36,7 @@ type Enforcer struct {
Adapter string `xorm:"varchar(100)" json:"adapter"` Adapter string `xorm:"varchar(100)" json:"adapter"`
IsEnabled bool `json:"isEnabled"` IsEnabled bool `json:"isEnabled"`
ModelCfg map[string]string `xorm:"-" json:"modelCfg"`
*casbin.Enforcer *casbin.Enforcer
} }
@ -120,8 +123,8 @@ func DeleteEnforcer(enforcer *Enforcer) (bool, error) {
return affected != 0, nil return affected != 0, nil
} }
func (p *Enforcer) GetId() string { func (enforcer *Enforcer) GetId() string {
return fmt.Sprintf("%s/%s", p.Owner, p.Name) return fmt.Sprintf("%s/%s", enforcer.Owner, enforcer.Name)
} }
func (enforcer *Enforcer) InitEnforcer() error { func (enforcer *Enforcer) InitEnforcer() error {
@ -154,7 +157,7 @@ func (enforcer *Enforcer) InitEnforcer() error {
if err != nil { if err != nil {
return err return err
} }
err = a.initAdapter() err = a.InitAdapter()
if err != nil { if err != nil {
return err return err
} }
@ -182,3 +185,70 @@ func GetInitializedEnforcer(enforcerId string) (*Enforcer, error) {
} }
return enforcer, nil return enforcer, nil
} }
func GetPolicies(id string) ([]*xormadapter.CasbinRule, error) {
enforcer, err := GetInitializedEnforcer(id)
if err != nil {
return nil, err
}
policies := util.MatrixToCasbinRules("p", enforcer.GetPolicy())
if enforcer.GetModel()["g"] != nil {
policies = append(policies, util.MatrixToCasbinRules("g", enforcer.GetGroupingPolicy())...)
}
return policies, nil
}
func UpdatePolicy(id string, oldPolicy, newPolicy []string) (bool, error) {
enforcer, err := GetInitializedEnforcer(id)
if err != nil {
return false, err
}
return enforcer.UpdatePolicy(oldPolicy, newPolicy)
}
func AddPolicy(id string, policy []string) (bool, error) {
enforcer, err := GetInitializedEnforcer(id)
if err != nil {
return false, err
}
return enforcer.AddPolicy(policy)
}
func RemovePolicy(id string, policy []string) (bool, error) {
enforcer, err := GetInitializedEnforcer(id)
if err != nil {
return false, err
}
return enforcer.RemovePolicy(policy)
}
func (enforcer *Enforcer) LoadModelCfg() error {
if enforcer.ModelCfg != nil {
return nil
}
model, err := GetModel(enforcer.Model)
if err != nil {
return err
} else if model == nil {
return fmt.Errorf("the model: %s for enforcer: %s is not found", enforcer.Model, enforcer.GetId())
}
cfg, err := config.NewConfigFromText(model.ModelText)
if err != nil {
return err
}
enforcer.ModelCfg = make(map[string]string)
enforcer.ModelCfg["p"] = cfg.String("policy_definition::p")
if cfg.String("role_definition::g") != "" {
enforcer.ModelCfg["g"] = cfg.String("role_definition::g")
}
return nil
}

View File

@ -34,3 +34,30 @@ func CasbinToSlice(casbinRule xormadapter.CasbinRule) []string {
} }
return s return s
} }
func safeReturn(policy []string, i int) string {
if len(policy) > i {
return policy[i]
} else {
return ""
}
}
func MatrixToCasbinRules(Ptype string, policies [][]string) []*xormadapter.CasbinRule {
res := []*xormadapter.CasbinRule{}
for _, policy := range policies {
line := xormadapter.CasbinRule{
Ptype: Ptype,
V0: safeReturn(policy, 0),
V1: safeReturn(policy, 1),
V2: safeReturn(policy, 2),
V3: safeReturn(policy, 3),
V4: safeReturn(policy, 4),
V5: safeReturn(policy, 5),
}
res = append(res, &line)
}
return res
}

View File

@ -19,11 +19,6 @@ import * as OrganizationBackend from "./backend/OrganizationBackend";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import i18next from "i18next"; 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; const {Option} = Select;
class AdapterEditPage extends React.Component { class AdapterEditPage extends React.Component {
@ -232,10 +227,23 @@ class AdapterEditPage extends React.Component {
</Row> </Row>
<Row style={{marginTop: "20px"}} > <Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> <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>
<Col span={22}> <Col span={2} >
<PolicyTable owner={this.state.organizationName} name={this.state.adapterName} mode={this.state.mode} /> <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> </Col>
</Row> </Row>
<Row style={{marginTop: "20px"}} > <Row style={{marginTop: "20px"}} >

View File

@ -18,6 +18,7 @@ import * as AdapterBackend from "./backend/AdapterBackend";
import * as EnforcerBackend from "./backend/EnforcerBackend"; import * as EnforcerBackend from "./backend/EnforcerBackend";
import * as ModelBackend from "./backend/ModelBackend"; import * as ModelBackend from "./backend/ModelBackend";
import * as OrganizationBackend from "./backend/OrganizationBackend"; import * as OrganizationBackend from "./backend/OrganizationBackend";
import PolicyTable from "./table/PolicyTable";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import i18next from "i18next"; import i18next from "i18next";
@ -42,7 +43,7 @@ class EnforcerEditPage extends React.Component {
} }
getEnforcer() { getEnforcer() {
EnforcerBackend.getEnforcer(this.state.organizationName, this.state.enforcerName) EnforcerBackend.getEnforcer(this.state.organizationName, this.state.enforcerName, true)
.then((res) => { .then((res) => {
if (res.data === null) { if (res.data === null) {
this.props.history.push("/404"); this.props.history.push("/404");
@ -185,6 +186,14 @@ class EnforcerEditPage extends React.Component {
} /> } />
</Col> </Col>
</Row> </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"}} > <Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}> <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
{Setting.getLabel(i18next.t("general:Is enabled"), i18next.t("general:Is enabled - Tooltip"))} : {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()); }).then(res => res.json());
} }
export function getPolicies(owner, name) { export function getPolicies(owner, name, adapterId = "") {
return fetch(`${Setting.ServerUrl}/api/get-policies?id=${owner}/${encodeURIComponent(name)}`, { return fetch(`${Setting.ServerUrl}/api/get-policies?id=${owner}/${encodeURIComponent(name)}&adapterId=${adapterId}`, {
method: "GET", method: "GET",
credentials: "include", credentials: "include",
headers: { headers: {

View File

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

View File

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