@@ -0,0 +1,94 @@ | |||||
package controllers | |||||
import ( | |||||
"encoding/json" | |||||
"github.com/casbin/casibase/object" | |||||
) | |||||
func (c *ApiController) GetGlobalProviders() { | |||||
providers, err := object.GetGlobalProviders() | |||||
if err != nil { | |||||
c.ResponseError(err.Error()) | |||||
return | |||||
} | |||||
c.ResponseOk(providers) | |||||
} | |||||
func (c *ApiController) GetProviders() { | |||||
owner := c.Input().Get("owner") | |||||
providers, err := object.GetProviders(owner) | |||||
if err != nil { | |||||
c.ResponseError(err.Error()) | |||||
return | |||||
} | |||||
c.ResponseOk(providers) | |||||
} | |||||
func (c *ApiController) GetProvider() { | |||||
id := c.Input().Get("id") | |||||
provider, err := object.GetProvider(id) | |||||
if err != nil { | |||||
c.ResponseError(err.Error()) | |||||
return | |||||
} | |||||
c.ResponseOk(provider) | |||||
} | |||||
func (c *ApiController) UpdateProvider() { | |||||
id := c.Input().Get("id") | |||||
var provider object.Provider | |||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider) | |||||
if err != nil { | |||||
c.ResponseError(err.Error()) | |||||
return | |||||
} | |||||
success, err := object.UpdateProvider(id, &provider) | |||||
if err != nil { | |||||
c.ResponseError(err.Error()) | |||||
return | |||||
} | |||||
c.ResponseOk(success) | |||||
} | |||||
func (c *ApiController) AddProvider() { | |||||
var provider object.Provider | |||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider) | |||||
if err != nil { | |||||
c.ResponseError(err.Error()) | |||||
return | |||||
} | |||||
success, err := object.AddProvider(&provider) | |||||
if err != nil { | |||||
c.ResponseError(err.Error()) | |||||
return | |||||
} | |||||
c.ResponseOk(success) | |||||
} | |||||
func (c *ApiController) DeleteProvider() { | |||||
var provider object.Provider | |||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider) | |||||
if err != nil { | |||||
c.ResponseError(err.Error()) | |||||
return | |||||
} | |||||
success, err := object.DeleteProvider(&provider) | |||||
if err != nil { | |||||
c.ResponseError(err.Error()) | |||||
return | |||||
} | |||||
c.ResponseOk(success) | |||||
} |
@@ -108,4 +108,9 @@ func (a *Adapter) createTable() { | |||||
if err != nil { | if err != nil { | ||||
panic(err) | panic(err) | ||||
} | } | ||||
err = a.engine.Sync2(new(Provider)) | |||||
if err != nil { | |||||
panic(err) | |||||
} | |||||
} | } |
@@ -0,0 +1,101 @@ | |||||
package object | |||||
import ( | |||||
"fmt" | |||||
"github.com/casbin/casibase/util" | |||||
"xorm.io/core" | |||||
) | |||||
type Provider struct { | |||||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"` | |||||
Name string `xorm:"varchar(100) notnull pk" json:"name"` | |||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"` | |||||
DisplayName string `xorm:"varchar(100)" json:"displayName"` | |||||
Category string `xorm:"varchar(100)" json:"category"` | |||||
Type string `xorm:"varchar(100)" json:"type"` | |||||
ClientId string `xorm:"varchar(100)" json:"clientId"` | |||||
ClientSecret string `xorm:"varchar(2000)" json:"clientSecret"` | |||||
ProviderUrl string `xorm:"varchar(200)" json:"providerUrl"` | |||||
} | |||||
func GetGlobalProviders() ([]*Provider, error) { | |||||
providers := []*Provider{} | |||||
err := adapter.engine.Asc("owner").Desc("created_time").Find(&providers) | |||||
if err != nil { | |||||
return providers, err | |||||
} | |||||
return providers, nil | |||||
} | |||||
func GetProviders(owner string) ([]*Provider, error) { | |||||
providers := []*Provider{} | |||||
err := adapter.engine.Desc("created_time").Find(&providers, &Provider{Owner: owner}) | |||||
if err != nil { | |||||
return providers, err | |||||
} | |||||
return providers, nil | |||||
} | |||||
func getProvider(owner string, name string) (*Provider, error) { | |||||
provider := Provider{Owner: owner, Name: name} | |||||
existed, err := adapter.engine.Get(&provider) | |||||
if err != nil { | |||||
return &provider, err | |||||
} | |||||
if existed { | |||||
return &provider, nil | |||||
} else { | |||||
return nil, nil | |||||
} | |||||
} | |||||
func GetProvider(id string) (*Provider, error) { | |||||
owner, name := util.GetOwnerAndNameFromId(id) | |||||
return getProvider(owner, name) | |||||
} | |||||
func UpdateProvider(id string, provider *Provider) (bool, error) { | |||||
owner, name := util.GetOwnerAndNameFromId(id) | |||||
_, err := getProvider(owner, name) | |||||
if err != nil { | |||||
return false, err | |||||
} | |||||
if provider == nil { | |||||
return false, nil | |||||
} | |||||
_, err = adapter.engine.ID(core.PK{owner, name}).AllCols().Update(provider) | |||||
if err != nil { | |||||
return false, err | |||||
} | |||||
//return affected != 0 | |||||
return true, nil | |||||
} | |||||
func AddProvider(provider *Provider) (bool, error) { | |||||
affected, err := adapter.engine.Insert(provider) | |||||
if err != nil { | |||||
return false, err | |||||
} | |||||
return affected != 0, nil | |||||
} | |||||
func DeleteProvider(provider *Provider) (bool, error) { | |||||
affected, err := adapter.engine.ID(core.PK{provider.Owner, provider.Name}).Delete(&Provider{}) | |||||
if err != nil { | |||||
return false, err | |||||
} | |||||
return affected != 0, nil | |||||
} | |||||
func (provider *Provider) GetId() string { | |||||
return fmt.Sprintf("%s/%s", provider.Owner, provider.Name) | |||||
} |
@@ -53,6 +53,13 @@ func initAPI() { | |||||
beego.Router("/api/add-store", &controllers.ApiController{}, "POST:AddStore") | beego.Router("/api/add-store", &controllers.ApiController{}, "POST:AddStore") | ||||
beego.Router("/api/delete-store", &controllers.ApiController{}, "POST:DeleteStore") | beego.Router("/api/delete-store", &controllers.ApiController{}, "POST:DeleteStore") | ||||
beego.Router("/api/get-global-providers", &controllers.ApiController{}, "GET:GetGlobalProviders") | |||||
beego.Router("/api/get-providers", &controllers.ApiController{}, "GET:GetProviders") | |||||
beego.Router("/api/get-provider", &controllers.ApiController{}, "GET:GetProvider") | |||||
beego.Router("/api/update-provider", &controllers.ApiController{}, "POST:UpdateProvider") | |||||
beego.Router("/api/add-provider", &controllers.ApiController{}, "POST:AddProvider") | |||||
beego.Router("/api/delete-provider", &controllers.ApiController{}, "POST:DeleteProvider") | |||||
beego.Router("/api/update-file", &controllers.ApiController{}, "POST:UpdateFile") | beego.Router("/api/update-file", &controllers.ApiController{}, "POST:UpdateFile") | ||||
beego.Router("/api/add-file", &controllers.ApiController{}, "POST:AddFile") | beego.Router("/api/add-file", &controllers.ApiController{}, "POST:AddFile") | ||||
beego.Router("/api/delete-file", &controllers.ApiController{}, "POST:DeleteFile") | beego.Router("/api/delete-file", &controllers.ApiController{}, "POST:DeleteFile") | ||||
@@ -19,6 +19,8 @@ import VectorsetListPage from "./VectorsetListPage"; | |||||
import VectorsetEditPage from "./VectorsetEditPage"; | import VectorsetEditPage from "./VectorsetEditPage"; | ||||
import VideoListPage from "./VideoListPage"; | import VideoListPage from "./VideoListPage"; | ||||
import VideoEditPage from "./VideoEditPage"; | import VideoEditPage from "./VideoEditPage"; | ||||
import ProviderListPage from "./ProviderListPage"; | |||||
import ProviderEditPage from "./ProviderEditPage"; | |||||
import SigninPage from "./SigninPage"; | import SigninPage from "./SigninPage"; | ||||
import i18next from "i18next"; | import i18next from "i18next"; | ||||
import LanguageSelect from "./LanguageSelect"; | import LanguageSelect from "./LanguageSelect"; | ||||
@@ -70,6 +72,8 @@ class App extends Component { | |||||
this.setState({selectedMenuKey: "/vectorsets"}); | this.setState({selectedMenuKey: "/vectorsets"}); | ||||
} else if (uri.includes("/videos")) { | } else if (uri.includes("/videos")) { | ||||
this.setState({selectedMenuKey: "/videos"}); | this.setState({selectedMenuKey: "/videos"}); | ||||
} else if (uri.includes("/providers")) { | |||||
this.setState({selectedMenuKey: "/providers"}); | |||||
} else { | } else { | ||||
this.setState({selectedMenuKey: "null"}); | this.setState({selectedMenuKey: "null"}); | ||||
} | } | ||||
@@ -289,6 +293,13 @@ class App extends Component { | |||||
</Link> | </Link> | ||||
</Menu.Item> | </Menu.Item> | ||||
); | ); | ||||
res.push( | |||||
<Menu.Item key="/providers"> | |||||
<Link to="/providers"> | |||||
{i18next.t("general:Providers")} | |||||
</Link> | |||||
</Menu.Item> | |||||
); | |||||
if (Setting.isLocalAdminUser(this.state.account)) { | if (Setting.isLocalAdminUser(this.state.account)) { | ||||
res.push( | res.push( | ||||
@@ -363,6 +374,8 @@ class App extends Component { | |||||
<Route exact path="/vectorsets/:vectorsetName" render={(props) => this.renderSigninIfNotSignedIn(<VectorsetEditPage account={this.state.account} {...props} />)} /> | <Route exact path="/vectorsets/:vectorsetName" render={(props) => this.renderSigninIfNotSignedIn(<VectorsetEditPage account={this.state.account} {...props} />)} /> | ||||
<Route exact path="/videos" render={(props) => this.renderSigninIfNotSignedIn(<VideoListPage account={this.state.account} {...props} />)} /> | <Route exact path="/videos" render={(props) => this.renderSigninIfNotSignedIn(<VideoListPage account={this.state.account} {...props} />)} /> | ||||
<Route exact path="/videos/:videoName" render={(props) => this.renderSigninIfNotSignedIn(<VideoEditPage account={this.state.account} {...props} />)} /> | <Route exact path="/videos/:videoName" render={(props) => this.renderSigninIfNotSignedIn(<VideoEditPage account={this.state.account} {...props} />)} /> | ||||
<Route exact path="/providers" render={(props) => this.renderSigninIfNotSignedIn(<ProviderListPage account={this.state.account} {...props} />)} /> | |||||
<Route exact path="/providers/:providerName" render={(props) => this.renderSigninIfNotSignedIn(<ProviderEditPage account={this.state.account} {...props} />)} /> | |||||
</Switch> | </Switch> | ||||
</div> | </div> | ||||
); | ); | ||||
@@ -0,0 +1,185 @@ | |||||
import React from "react"; | |||||
import {Button, Card, Col, Input, Row, Select} from "antd"; | |||||
import * as ProviderBackend from "./backend/ProviderBackend"; | |||||
import * as Setting from "./Setting"; | |||||
import i18next from "i18next"; | |||||
import {LinkOutlined} from "@ant-design/icons"; | |||||
const {Option} = Select; | |||||
class ProviderEditPage extends React.Component { | |||||
constructor(props) { | |||||
super(props); | |||||
this.state = { | |||||
classes: props, | |||||
providerName: props.match.params.providerName, | |||||
provider: null, | |||||
}; | |||||
} | |||||
UNSAFE_componentWillMount() { | |||||
this.getProvider(); | |||||
} | |||||
getProvider() { | |||||
ProviderBackend.getProvider(this.props.account.name, this.state.providerName) | |||||
.then((provider) => { | |||||
if (provider.status === "ok") { | |||||
this.setState({ | |||||
provider: provider.data, | |||||
}); | |||||
} else { | |||||
Setting.showMessage("error", `Failed to get provider: ${provider.msg}`); | |||||
} | |||||
}); | |||||
} | |||||
parseProviderField(key, value) { | |||||
if ([""].includes(key)) { | |||||
value = Setting.myParseInt(value); | |||||
} | |||||
return value; | |||||
} | |||||
updateProviderField(key, value) { | |||||
value = this.parseProviderField(key, value); | |||||
const provider = this.state.provider; | |||||
provider[key] = value; | |||||
this.setState({ | |||||
provider: provider, | |||||
}); | |||||
} | |||||
renderProvider() { | |||||
return ( | |||||
<Card size="small" title={ | |||||
<div> | |||||
{i18next.t("provider:Edit Provider")} | |||||
<Button type="primary" onClick={this.submitProviderEdit.bind(this)}>{i18next.t("general:Save")}</Button> | |||||
</div> | |||||
} style={{marginLeft: "5px"}} type="inner"> | |||||
<Row style={{marginTop: "10px"}} > | |||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> | |||||
{i18next.t("general:Name")}: | |||||
</Col> | |||||
<Col span={22} > | |||||
<Input value={this.state.provider.name} onChange={e => { | |||||
this.updateProviderField("name", e.target.value); | |||||
}} /> | |||||
</Col> | |||||
</Row> | |||||
<Row style={{marginTop: "20px"}} > | |||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> | |||||
{i18next.t("general:Display name")}: | |||||
</Col> | |||||
<Col span={22} > | |||||
<Input value={this.state.provider.displayName} onChange={e => { | |||||
this.updateProviderField("displayName", e.target.value); | |||||
}} /> | |||||
</Col> | |||||
</Row> | |||||
<Row style={{marginTop: "20px"}} > | |||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> | |||||
{i18next.t("provider:Category")}: | |||||
</Col> | |||||
<Col span={22} > | |||||
<Select virtual={false} style={{width: "100%"}} value={this.state.provider.category} onChange={(value => {this.updateProviderField("category", value);})}> | |||||
{ | |||||
[ | |||||
{id: "AI", name: "AI"}, | |||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>) | |||||
} | |||||
</Select> | |||||
</Col> | |||||
</Row> | |||||
<Row style={{marginTop: "20px"}} > | |||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> | |||||
{i18next.t("provider:Type")}: | |||||
</Col> | |||||
<Col span={22} > | |||||
<Select virtual={false} style={{width: "100%"}} value={this.state.provider.type} onChange={(value => {this.updateProviderField("type", value);})}> | |||||
{ | |||||
[ | |||||
{id: "OpenAI API - GPT 3.5", name: "OpenAI API - GPT 3.5"}, | |||||
{id: "OpenAI API - GPT 4", name: "OpenAI API - GPT 4"}, | |||||
].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>) | |||||
} | |||||
</Select> | |||||
</Col> | |||||
</Row> | |||||
<Row style={{marginTop: "20px"}} > | |||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> | |||||
{i18next.t("provider:Secret key")}: | |||||
</Col> | |||||
<Col span={22} > | |||||
<Input value={this.state.provider.clientSecret} onChange={e => { | |||||
this.updateProviderField("clientSecret", e.target.value); | |||||
}} /> | |||||
</Col> | |||||
</Row> | |||||
<Row style={{marginTop: "20px"}} > | |||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> | |||||
{i18next.t("general:Provider URL")}: | |||||
</Col> | |||||
<Col span={22} > | |||||
<Input prefix={<LinkOutlined />} value={this.state.provider.providerUrl} onChange={e => { | |||||
this.updateProviderField("providerUrl", e.target.value); | |||||
}} /> | |||||
</Col> | |||||
</Row> | |||||
</Card> | |||||
); | |||||
} | |||||
submitProviderEdit() { | |||||
const provider = Setting.deepCopy(this.state.provider); | |||||
ProviderBackend.updateProvider(this.state.provider.owner, this.state.providerName, provider) | |||||
.then((res) => { | |||||
if (res.status === "ok") { | |||||
if (res.data) { | |||||
Setting.showMessage("success", "Successfully saved"); | |||||
this.setState({ | |||||
providerName: this.state.provider.name, | |||||
}); | |||||
this.props.history.push(`/providers/${this.state.provider.name}`); | |||||
} else { | |||||
Setting.showMessage("error", "failed to save: server side failure"); | |||||
this.updateProviderField("name", this.state.providerName); | |||||
} | |||||
} else { | |||||
Setting.showMessage("error", `failed to save: ${res.msg}`); | |||||
} | |||||
}) | |||||
.catch(error => { | |||||
Setting.showMessage("error", `failed to save: ${error}`); | |||||
}); | |||||
} | |||||
render() { | |||||
return ( | |||||
<div> | |||||
<Row style={{width: "100%"}}> | |||||
<Col span={1}> | |||||
</Col> | |||||
<Col span={22}> | |||||
{ | |||||
this.state.provider !== null ? this.renderProvider() : null | |||||
} | |||||
</Col> | |||||
<Col span={1}> | |||||
</Col> | |||||
</Row> | |||||
<Row style={{margin: 10}}> | |||||
<Col span={2}> | |||||
</Col> | |||||
<Col span={18}> | |||||
<Button type="primary" size="large" onClick={this.submitProviderEdit.bind(this)}>{i18next.t("general:Save")}</Button> | |||||
</Col> | |||||
</Row> | |||||
</div> | |||||
); | |||||
} | |||||
} | |||||
export default ProviderEditPage; |
@@ -0,0 +1,202 @@ | |||||
import React from "react"; | |||||
import {Link} from "react-router-dom"; | |||||
import {Button, Col, Popconfirm, Row, Table} from "antd"; | |||||
import moment from "moment"; | |||||
import * as Setting from "./Setting"; | |||||
import * as ProviderBackend from "./backend/ProviderBackend"; | |||||
import i18next from "i18next"; | |||||
class ProviderListPage extends React.Component { | |||||
constructor(props) { | |||||
super(props); | |||||
this.state = { | |||||
classes: props, | |||||
providers: null, | |||||
}; | |||||
} | |||||
UNSAFE_componentWillMount() { | |||||
this.getProviders(); | |||||
} | |||||
getProviders() { | |||||
ProviderBackend.getProviders(this.props.account.name) | |||||
.then((res) => { | |||||
if (res.status === "ok") { | |||||
this.setState({ | |||||
providers: res.data, | |||||
}); | |||||
} else { | |||||
Setting.showMessage("error", `Failed to get providers: ${res.msg}`); | |||||
} | |||||
}); | |||||
} | |||||
newProvider() { | |||||
const randomName = Setting.getRandomName(); | |||||
return { | |||||
owner: this.props.account.name, | |||||
name: `provider_${randomName}`, | |||||
createdTime: moment().format(), | |||||
displayName: `New Provider - ${randomName}`, | |||||
category: "AI", | |||||
type: "OpenAI API - GPT 3.5", | |||||
clientId: "", | |||||
clientSecret: "", | |||||
providerUrl: "https://platform.openai.com/account/api-keys", | |||||
}; | |||||
} | |||||
addProvider() { | |||||
const newProvider = this.newProvider(); | |||||
ProviderBackend.addProvider(newProvider) | |||||
.then((res) => { | |||||
if (res.status === "ok") { | |||||
Setting.showMessage("success", "Provider added successfully"); | |||||
this.setState({ | |||||
providers: Setting.prependRow(this.state.providers, newProvider), | |||||
}); | |||||
} else { | |||||
Setting.showMessage("error", `Failed to add provider: ${res.msg}`); | |||||
} | |||||
}) | |||||
.catch(error => { | |||||
Setting.showMessage("error", `Provider failed to add: ${error}`); | |||||
}); | |||||
} | |||||
deleteProvider(i) { | |||||
ProviderBackend.deleteProvider(this.state.providers[i]) | |||||
.then((res) => { | |||||
if (res.status === "ok") { | |||||
Setting.showMessage("success", "Provider deleted successfully"); | |||||
this.setState({ | |||||
providers: Setting.deleteRow(this.state.providers, i), | |||||
}); | |||||
} else { | |||||
Setting.showMessage("error", `Provider failed to delete: ${res.msg}`); | |||||
} | |||||
}) | |||||
.catch(error => { | |||||
Setting.showMessage("error", `Provider failed to delete: ${error}`); | |||||
}); | |||||
} | |||||
renderTable(providers) { | |||||
const columns = [ | |||||
{ | |||||
title: i18next.t("general:Name"), | |||||
dataIndex: "name", | |||||
key: "name", | |||||
width: "140px", | |||||
sorter: (a, b) => a.name.localeCompare(b.name), | |||||
render: (text, record, index) => { | |||||
return ( | |||||
<Link to={`/providers/${text}`}> | |||||
{text} | |||||
</Link> | |||||
); | |||||
}, | |||||
}, | |||||
{ | |||||
title: i18next.t("general:Display name"), | |||||
dataIndex: "displayName", | |||||
key: "displayName", | |||||
width: "200px", | |||||
sorter: (a, b) => a.displayName.localeCompare(b.displayName), | |||||
}, | |||||
{ | |||||
title: i18next.t("provider:Category"), | |||||
dataIndex: "category", | |||||
key: "category", | |||||
width: "200px", | |||||
sorter: (a, b) => a.category.localeCompare(b.category), | |||||
}, | |||||
{ | |||||
title: i18next.t("provider:Type"), | |||||
dataIndex: "type", | |||||
key: "type", | |||||
width: "200px", | |||||
sorter: (a, b) => a.type.localeCompare(b.type), | |||||
}, | |||||
{ | |||||
title: i18next.t("provider:Secret key"), | |||||
dataIndex: "clientSecret", | |||||
key: "clientSecret", | |||||
width: "200px", | |||||
sorter: (a, b) => a.clientSecret.localeCompare(b.clientSecret), | |||||
}, | |||||
{ | |||||
title: i18next.t("provider:Provider URL"), | |||||
dataIndex: "providerUrl", | |||||
key: "providerUrl", | |||||
width: "250px", | |||||
sorter: (a, b) => a.providerUrl.localeCompare(b.providerUrl), | |||||
render: (text, record, index) => { | |||||
return ( | |||||
<a target="_blank" rel="noreferrer" href={text}> | |||||
{ | |||||
Setting.getShortText(text) | |||||
} | |||||
</a> | |||||
); | |||||
}, | |||||
}, | |||||
{ | |||||
title: i18next.t("general:Action"), | |||||
dataIndex: "action", | |||||
key: "action", | |||||
width: "180px", | |||||
render: (text, record, index) => { | |||||
return ( | |||||
<div> | |||||
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/providers/${record.name}`)}>{i18next.t("general:Edit")}</Button> | |||||
<Popconfirm | |||||
title={`Sure to delete provider: ${record.name} ?`} | |||||
onConfirm={() => this.deleteProvider(index)} | |||||
okText="OK" | |||||
cancelText="Cancel" | |||||
> | |||||
<Button style={{marginBottom: "10px"}} type="danger">{i18next.t("general:Delete")}</Button> | |||||
</Popconfirm> | |||||
</div> | |||||
); | |||||
}, | |||||
}, | |||||
]; | |||||
return ( | |||||
<div> | |||||
<Table columns={columns} dataSource={providers} rowKey="name" size="middle" bordered pagination={{pageSize: 100}} | |||||
title={() => ( | |||||
<div> | |||||
{i18next.t("general:Providers")} | |||||
<Button type="primary" size="small" onClick={this.addProvider.bind(this)}>{i18next.t("general:Add")}</Button> | |||||
</div> | |||||
)} | |||||
loading={providers === null} | |||||
/> | |||||
</div> | |||||
); | |||||
} | |||||
render() { | |||||
return ( | |||||
<div> | |||||
<Row style={{width: "100%"}}> | |||||
<Col span={1}> | |||||
</Col> | |||||
<Col span={22}> | |||||
{ | |||||
this.renderTable(this.state.providers) | |||||
} | |||||
</Col> | |||||
<Col span={1}> | |||||
</Col> | |||||
</Row> | |||||
</div> | |||||
); | |||||
} | |||||
} | |||||
export default ProviderListPage; |
@@ -0,0 +1,56 @@ | |||||
import * as Setting from "../Setting"; | |||||
export function getGlobalProviders() { | |||||
return fetch(`${Setting.ServerUrl}/api/get-global-providers`, { | |||||
method: "GET", | |||||
credentials: "include", | |||||
}).then(res => res.json()); | |||||
} | |||||
export function getProviders(owner) { | |||||
return fetch(`${Setting.ServerUrl}/api/get-providers?owner=${owner}`, { | |||||
method: "GET", | |||||
credentials: "include", | |||||
}).then(res => res.json()); | |||||
} | |||||
export function getProvider(owner, name) { | |||||
return fetch(`${Setting.ServerUrl}/api/get-provider?id=${owner}/${encodeURIComponent(name)}`, { | |||||
method: "GET", | |||||
credentials: "include", | |||||
}).then(res => res.json()); | |||||
} | |||||
export function getProviderGraph(owner, name, clusterNumber, distanceLimit) { | |||||
return fetch(`${Setting.ServerUrl}/api/get-provider-graph?id=${owner}/${encodeURIComponent(name)}&clusterNumber=${clusterNumber}&distanceLimit=${distanceLimit}`, { | |||||
method: "GET", | |||||
credentials: "include", | |||||
}).then(res => res.json()); | |||||
} | |||||
export function updateProvider(owner, name, provider) { | |||||
const newProvider = Setting.deepCopy(provider); | |||||
return fetch(`${Setting.ServerUrl}/api/update-provider?id=${owner}/${encodeURIComponent(name)}`, { | |||||
method: "POST", | |||||
credentials: "include", | |||||
body: JSON.stringify(newProvider), | |||||
}).then(res => res.json()); | |||||
} | |||||
export function addProvider(provider) { | |||||
const newProvider = Setting.deepCopy(provider); | |||||
return fetch(`${Setting.ServerUrl}/api/add-provider`, { | |||||
method: "POST", | |||||
credentials: "include", | |||||
body: JSON.stringify(newProvider), | |||||
}).then(res => res.json()); | |||||
} | |||||
export function deleteProvider(provider) { | |||||
const newProvider = Setting.deepCopy(provider); | |||||
return fetch(`${Setting.ServerUrl}/api/delete-provider`, { | |||||
method: "POST", | |||||
credentials: "include", | |||||
body: JSON.stringify(newProvider), | |||||
}).then(res => res.json()); | |||||
} |