| @@ -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> | |||