diff --git a/object/syncer.go b/object/syncer.go index e9de4511..71f50008 100644 --- a/object/syncer.go +++ b/object/syncer.go @@ -21,6 +21,13 @@ import ( "xorm.io/core" ) +type TableColumn struct { + Name string `json:"name"` + Type string `json:"type"` + CasdoorName string `json:"casdoorName"` + Values []string `json:"values"` +} + type Syncer struct { Owner string `xorm:"varchar(100) notnull pk" json:"owner"` Name string `xorm:"varchar(100) notnull pk" json:"name"` @@ -29,16 +36,17 @@ type Syncer struct { Organization string `xorm:"varchar(100)" json:"organization"` Type string `xorm:"varchar(100)" json:"type"` - Host string `xorm:"varchar(100)" json:"host"` - Port int `json:"port"` - User string `xorm:"varchar(100)" json:"user"` - Password string `xorm:"varchar(100)" json:"password"` - Database string `xorm:"varchar(100)" json:"database"` - Table string `xorm:"varchar(100)" json:"table"` - AffiliationTable string `xorm:"varchar(100)" json:"affiliationTable"` - AvatarBaseUrl string `xorm:"varchar(100)" json:"avatarBaseUrl"` - SyncInterval int `json:"syncInterval"` - IsEnabled bool `json:"isEnabled"` + Host string `xorm:"varchar(100)" json:"host"` + Port int `json:"port"` + User string `xorm:"varchar(100)" json:"user"` + Password string `xorm:"varchar(100)" json:"password"` + Database string `xorm:"varchar(100)" json:"database"` + Table string `xorm:"varchar(100)" json:"table"` + TableColumns []*TableColumn `xorm:"mediumtext" json:"tableColumns"` + AffiliationTable string `xorm:"varchar(100)" json:"affiliationTable"` + AvatarBaseUrl string `xorm:"varchar(100)" json:"avatarBaseUrl"` + SyncInterval int `json:"syncInterval"` + IsEnabled bool `json:"isEnabled"` Adapter *Adapter `xorm:"-" json:"-"` } diff --git a/web/src/SyncerEditPage.js b/web/src/SyncerEditPage.js index fbfefffc..39c6d4dc 100644 --- a/web/src/SyncerEditPage.js +++ b/web/src/SyncerEditPage.js @@ -19,6 +19,7 @@ import * as SyncerBackend from "./backend/SyncerBackend"; import * as OrganizationBackend from "./backend/OrganizationBackend"; import * as Setting from "./Setting"; import i18next from "i18next"; +import SyncerTableColumnTable from "./SyncerTableColumnTable"; const { Option } = Select; @@ -177,6 +178,18 @@ class SyncerEditPage extends React.Component { }} /> + + + {Setting.getLabel(i18next.t("syncer:Table columns"), i18next.t("syncer:Table columns - Tooltip"))} : + + + { this.updateSyncerField('tableColumns', value)}} + /> + + {Setting.getLabel(i18next.t("syncer:Affiliation table"), i18next.t("syncer:Affiliation table - Tooltip"))} : diff --git a/web/src/SyncerListPage.js b/web/src/SyncerListPage.js index d66426a3..f13ca121 100644 --- a/web/src/SyncerListPage.js +++ b/web/src/SyncerListPage.js @@ -60,7 +60,11 @@ class SyncerListPage extends React.Component { password: "123456", database: "dbName", table: "tableName", + tableColumns: [], + affiliationTable: "", + avatarBaseUrl: "", syncInterval: 1, + isEnabled: true, } } diff --git a/web/src/SyncerTableColumnTable.js b/web/src/SyncerTableColumnTable.js new file mode 100644 index 00000000..304ddea6 --- /dev/null +++ b/web/src/SyncerTableColumnTable.js @@ -0,0 +1,159 @@ +// Copyright 2021 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 {DownOutlined, DeleteOutlined, UpOutlined} from '@ant-design/icons'; +import {Button, Col, Input, Row, Select, Table, Tooltip} from 'antd'; +import * as Setting from "./Setting"; +import i18next from "i18next"; + +const { Option } = Select; + +class SyncerTableColumnTable extends React.Component { + constructor(props) { + super(props); + this.state = { + classes: props, + }; + } + + updateTable(table) { + this.props.onUpdateTable(table); + } + + updateField(table, index, key, value) { + table[index][key] = value; + this.updateTable(table); + } + + addRow(table) { + let row = {name: `column${table.length}`, type: "string", values: []}; + 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: i18next.t("syncer:Column name"), + dataIndex: 'name', + key: 'name', + render: (text, record, index) => { + return ( + { + this.updateField(table, index, 'name', e.target.value); + }} /> + ) + } + }, + { + title: i18next.t("syncer:Column type"), + dataIndex: 'type', + key: 'type', + render: (text, record, index) => { + return ( + + ) + } + }, + { + title: i18next.t("syncer:Casdoor column"), + dataIndex: 'casdoorName', + key: 'casdoorName', + render: (text, record, index) => { + return ( + + ) + } + }, + { + title: i18next.t("general:Action"), + key: 'action', + width: '100px', + render: (text, record, index) => { + return ( +
+ +
+ ); + } + }, + ]; + + return ( + ( +
+ {this.props.title}     + +
+ )} + /> + ); + } + + render() { + return ( +
+ +
+ { + this.renderTable(this.props.table) + } + + + + ) + } +} + +export default SyncerTableColumnTable;