| @@ -45,7 +45,13 @@ func (c *ApiController) GetStores() { | |||||
| func (c *ApiController) GetStore() { | func (c *ApiController) GetStore() { | ||||
| id := c.Input().Get("id") | 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 { | if err != nil { | ||||
| c.ResponseError(err.Error()) | c.ResponseError(err.Error()) | ||||
| return | return | ||||
| @@ -57,7 +63,8 @@ func (c *ApiController) GetStore() { | |||||
| err = store.Populate() | err = store.Populate() | ||||
| if err != nil { | if err != nil { | ||||
| c.ResponseError(err.Error()) | |||||
| // gentle error | |||||
| c.ResponseOk(store, err.Error()) | |||||
| return | return | ||||
| } | } | ||||
| @@ -70,7 +70,7 @@ func GetStores(owner string) ([]*Store, error) { | |||||
| return stores, nil | return stores, nil | ||||
| } | } | ||||
| func getCurrentStore(owner string) (*Store, error) { | |||||
| func GetDefaultStore(owner string) (*Store, error) { | |||||
| stores, err := GetStores(owner) | stores, err := GetStores(owner) | ||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| @@ -81,6 +81,11 @@ func getCurrentStore(owner string) (*Store, error) { | |||||
| return store, nil | return store, nil | ||||
| } | } | ||||
| } | } | ||||
| if len(stores) > 0 { | |||||
| return stores[0], nil | |||||
| } | |||||
| return nil, nil | return nil, nil | ||||
| } | } | ||||
| @@ -129,7 +129,7 @@ func (video *Video) GetId() string { | |||||
| } | } | ||||
| func (video *Video) Populate() error { | func (video *Video) Populate() error { | ||||
| store, err := getCurrentStore("admin") | |||||
| store, err := GetDefaultStore("admin") | |||||
| if err != nil { | if err != nil { | ||||
| return err | return err | ||||
| } | } | ||||
| @@ -84,8 +84,8 @@ class App extends Component { | |||||
| this.setState({ | this.setState({ | ||||
| uri: uri, | uri: uri, | ||||
| }); | }); | ||||
| if (uri === "/home") { | |||||
| this.setState({selectedMenuKey: "/home"}); | |||||
| if (uri === "/" || uri === "/home") { | |||||
| this.setState({selectedMenuKey: "/"}); | |||||
| } else if (uri.includes("/stores")) { | } else if (uri.includes("/stores")) { | ||||
| this.setState({selectedMenuKey: "/stores"}); | this.setState({selectedMenuKey: "/stores"}); | ||||
| } else if (uri.includes("/clustering")) { | } else if (uri.includes("/clustering")) { | ||||
| @@ -13,7 +13,8 @@ | |||||
| // limitations under the License. | // limitations under the License. | ||||
| import React from "react"; | 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 {CloudUploadOutlined, DeleteOutlined, DownloadOutlined, FileDoneOutlined, FolderAddOutlined, InfoCircleTwoTone, createFromIconfontCN} from "@ant-design/icons"; | ||||
| import moment from "moment"; | import moment from "moment"; | ||||
| import * as Setting from "./Setting"; | import * as Setting from "./Setting"; | ||||
| @@ -847,29 +848,49 @@ class FileTree extends React.Component { | |||||
| } | } | ||||
| render() { | 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 ( | return ( | ||||
| <div style={{backgroundColor: "white", borderTop: "1px solid rgb(232,232,232)", borderLeft: "1px solid rgb(232,232,232)"}}> | |||||
| <div> | |||||
| <Row> | <Row> | ||||
| <Col span={8}> | <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> | </Card> | ||||
| </Col> | </Col> | ||||
| <Col span={16}> | <Col span={16}> | ||||
| <Card className="content-warp-card-filetreeright"> | <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> | </div> | ||||
| { | |||||
| this.renderProperties() | |||||
| } | |||||
| </Card> | </Card> | ||||
| </Col> | </Col> | ||||
| </Row> | </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() { | getStore() { | ||||
| StoreBackend.getStore(this.state.owner, this.state.storeName) | 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({ | this.setState({ | ||||
| store: res.data, | |||||
| store: store.data, | |||||
| }); | }); | ||||
| } else { | } 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 React from "react"; | ||||
| import FileTreePage from "./FileTreePage"; | import FileTreePage from "./FileTreePage"; | ||||
| import {Redirect} from "react-router-dom"; | import {Redirect} from "react-router-dom"; | ||||
| @@ -28,22 +28,22 @@ class HomePage extends React.Component { | |||||
| } | } | ||||
| UNSAFE_componentWillMount() { | 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 { | } 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) | StoreBackend.getStore(this.state.owner, this.state.storeName) | ||||
| .then((store) => { | .then((store) => { | ||||
| if (store.status === "ok") { | if (store.status === "ok") { | ||||
| if (store.data2 !== null && store.data2.includes("error")) { | |||||
| store.data.error = store.data2; | |||||
| } | |||||
| this.setState({ | this.setState({ | ||||
| store: store.data, | store: store.data, | ||||
| }); | }); | ||||
| @@ -114,14 +114,14 @@ class StoreListPage extends React.Component { | |||||
| title: i18next.t("general:Display name"), | title: i18next.t("general:Display name"), | ||||
| dataIndex: "displayName", | dataIndex: "displayName", | ||||
| key: "displayName", | key: "displayName", | ||||
| width: "600px", | |||||
| // width: "600px", | |||||
| sorter: (a, b) => a.displayName.localeCompare(b.displayName), | sorter: (a, b) => a.displayName.localeCompare(b.displayName), | ||||
| }, | }, | ||||
| { | { | ||||
| title: i18next.t("general:Action"), | title: i18next.t("general:Action"), | ||||
| dataIndex: "action", | dataIndex: "action", | ||||
| key: "action", | key: "action", | ||||
| width: "240px", | |||||
| width: "300px", | |||||
| render: (text, record, index) => { | render: (text, record, index) => { | ||||
| return ( | return ( | ||||
| <div> | <div> | ||||