@@ -45,7 +45,13 @@ func (c *ApiController) GetStores() { | |||
func (c *ApiController) GetStore() { | |||
id := c.Input().Get("id") | |||
store, err := object.GetStore(id) | |||
var store *object.Store | |||
var err error | |||
if id == "admin/_casibase_default_store_" { | |||
store, err = object.GetDefaultStore("admin") | |||
} else { | |||
store, err = object.GetStore(id) | |||
} | |||
if err != nil { | |||
c.ResponseError(err.Error()) | |||
return | |||
@@ -57,7 +63,8 @@ func (c *ApiController) GetStore() { | |||
err = store.Populate() | |||
if err != nil { | |||
c.ResponseError(err.Error()) | |||
// gentle error | |||
c.ResponseOk(store, err.Error()) | |||
return | |||
} | |||
@@ -70,7 +70,7 @@ func GetStores(owner string) ([]*Store, error) { | |||
return stores, nil | |||
} | |||
func getCurrentStore(owner string) (*Store, error) { | |||
func GetDefaultStore(owner string) (*Store, error) { | |||
stores, err := GetStores(owner) | |||
if err != nil { | |||
return nil, err | |||
@@ -81,6 +81,11 @@ func getCurrentStore(owner string) (*Store, error) { | |||
return store, nil | |||
} | |||
} | |||
if len(stores) > 0 { | |||
return stores[0], nil | |||
} | |||
return nil, nil | |||
} | |||
@@ -129,7 +129,7 @@ func (video *Video) GetId() string { | |||
} | |||
func (video *Video) Populate() error { | |||
store, err := getCurrentStore("admin") | |||
store, err := GetDefaultStore("admin") | |||
if err != nil { | |||
return err | |||
} | |||
@@ -84,8 +84,8 @@ class App extends Component { | |||
this.setState({ | |||
uri: uri, | |||
}); | |||
if (uri === "/home") { | |||
this.setState({selectedMenuKey: "/home"}); | |||
if (uri === "/" || uri === "/home") { | |||
this.setState({selectedMenuKey: "/"}); | |||
} else if (uri.includes("/stores")) { | |||
this.setState({selectedMenuKey: "/stores"}); | |||
} else if (uri.includes("/clustering")) { | |||
@@ -13,7 +13,8 @@ | |||
// limitations under the License. | |||
import React from "react"; | |||
import {Button, Card, Col, DatePicker, Descriptions, Empty, Input, Modal, Popconfirm, Radio, Row, Select, Spin, Tooltip, Tree, Upload} from "antd"; | |||
import {withRouter} from "react-router-dom"; | |||
import {Button, Card, Col, DatePicker, Descriptions, Empty, Input, Modal, Popconfirm, Radio, Result, Row, Select, Spin, Tooltip, Tree, Upload} from "antd"; | |||
import {CloudUploadOutlined, DeleteOutlined, DownloadOutlined, FileDoneOutlined, FolderAddOutlined, InfoCircleTwoTone, createFromIconfontCN} from "@ant-design/icons"; | |||
import moment from "moment"; | |||
import * as Setting from "./Setting"; | |||
@@ -847,29 +848,49 @@ class FileTree extends React.Component { | |||
} | |||
render() { | |||
if (this.props.store.fileTree === null) { | |||
return ( | |||
<div className="App"> | |||
<Result | |||
status="error" | |||
title={`${this.props.store.error}`} | |||
extra={ | |||
<Button type="primary" onClick={() => this.props.history.push(`/stores/${this.props.store.owner}/${this.props.store.name}`)}> | |||
Go to Store | |||
</Button> | |||
} | |||
/> | |||
</div> | |||
); | |||
} | |||
return ( | |||
<div style={{backgroundColor: "white", borderTop: "1px solid rgb(232,232,232)", borderLeft: "1px solid rgb(232,232,232)"}}> | |||
<div> | |||
<Row> | |||
<Col span={8}> | |||
<Card className="content-warp-card-filetreeleft"> | |||
{ | |||
this.renderSearch(this.props.store) | |||
} | |||
{ | |||
this.renderTree(this.props.store) | |||
} | |||
<Card className="content-warp-card-filetreeleft" style={{marginRight: "10px"}}> | |||
<div style={{margin: "-25px"}}> | |||
{ | |||
this.renderSearch(this.props.store) | |||
} | |||
{ | |||
this.renderTree(this.props.store) | |||
} | |||
</div> | |||
</Card> | |||
</Col> | |||
<Col span={16}> | |||
<Card className="content-warp-card-filetreeright"> | |||
<div style={{height: this.getEditorHeightCss()}}> | |||
<div style={{margin: "-25px"}}> | |||
<div style={{height: this.getEditorHeightCss()}}> | |||
{ | |||
this.renderFileViewer(this.props.store) | |||
} | |||
</div> | |||
{ | |||
this.renderFileViewer(this.props.store) | |||
this.renderProperties() | |||
} | |||
</div> | |||
{ | |||
this.renderProperties() | |||
} | |||
</Card> | |||
</Col> | |||
</Row> | |||
@@ -881,4 +902,4 @@ class FileTree extends React.Component { | |||
} | |||
} | |||
export default FileTree; | |||
export default withRouter(FileTree); |
@@ -36,13 +36,17 @@ class FileTreePage extends React.Component { | |||
getStore() { | |||
StoreBackend.getStore(this.state.owner, this.state.storeName) | |||
.then((res) => { | |||
if (res?.status !== "error") { | |||
.then((store) => { | |||
if (store.status === "ok") { | |||
if (store.data2 !== null && store.data?.includes("error")) { | |||
store.data.error = store.data2; | |||
} | |||
this.setState({ | |||
store: res.data, | |||
store: store.data, | |||
}); | |||
} else { | |||
Setting.showMessage("error", res.msg); | |||
Setting.showMessage("error", `Failed to get store: ${store.msg}`); | |||
} | |||
}); | |||
} | |||
@@ -1,17 +1,17 @@ | |||
// 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. | |||
// 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 FileTreePage from "./FileTreePage"; | |||
import {Redirect} from "react-router-dom"; | |||
@@ -28,22 +28,22 @@ class HomePage extends React.Component { | |||
} | |||
UNSAFE_componentWillMount() { | |||
this.getStores(); | |||
this.getStore(); | |||
} | |||
getStores() { | |||
StoreBackend.getGlobalStores() | |||
.then((res) => { | |||
if (res.status === "ok") { | |||
const stores = res.data; | |||
const store = stores.filter(store => store.domain !== "https://cdn.example.com")[0]; | |||
if (store !== undefined) { | |||
this.setState({ | |||
store: store, | |||
}); | |||
getStore() { | |||
StoreBackend.getStore("admin", "_casibase_default_store_") | |||
.then((store) => { | |||
if (store.status === "ok") { | |||
if (store.data2 !== null && store.data2.includes("error")) { | |||
store.data.error = store.data2; | |||
} | |||
this.setState({ | |||
store: store.data, | |||
}); | |||
} else { | |||
Setting.showMessage("error", `Failed to get stores: ${res.msg}`); | |||
Setting.showMessage("error", `Failed to get store: ${store.msg}`); | |||
} | |||
}); | |||
} | |||
@@ -39,6 +39,10 @@ class StoreEditPage extends React.Component { | |||
StoreBackend.getStore(this.state.owner, this.state.storeName) | |||
.then((store) => { | |||
if (store.status === "ok") { | |||
if (store.data2 !== null && store.data2.includes("error")) { | |||
store.data.error = store.data2; | |||
} | |||
this.setState({ | |||
store: store.data, | |||
}); | |||
@@ -114,14 +114,14 @@ class StoreListPage extends React.Component { | |||
title: i18next.t("general:Display name"), | |||
dataIndex: "displayName", | |||
key: "displayName", | |||
width: "600px", | |||
// width: "600px", | |||
sorter: (a, b) => a.displayName.localeCompare(b.displayName), | |||
}, | |||
{ | |||
title: i18next.t("general:Action"), | |||
dataIndex: "action", | |||
key: "action", | |||
width: "240px", | |||
width: "300px", | |||
render: (text, record, index) => { | |||
return ( | |||
<div> | |||