diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..da994f4f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,63 @@ +name: "Bug Report" +description: Report a bug to help improve the project. +title: "bug: " +body: + - type: markdown + attributes: + value: | + Thank you for taking the time to report this bug! + + _The more information you share, the faster we can identify and fix the bug._ + + Prior to opening the issue, please make sure that you: + + - Use English to communicate. + - Search the [open issues](https://github.com/APIParkLab/APIPark/issues) and [discussion forum](https://github.com/APIParkLab/APIPark/discussions) to avoid duplicating the issue. + + - type: textarea + id: current-behavior + attributes: + label: Current Behavior + description: Describe the issue you are facing. + placeholder: | + What is the issue with the current behavior? + validations: + required: true + - type: textarea + id: expected-behavior + attributes: + label: Expected Behavior + description: Describe what you expected to happen. + placeholder: | + What did you expect to happen instead? + validations: + required: false + - type: textarea + id: error + attributes: + label: Error Logs + description: Paste the error logs if any. + validations: + required: false + - type: textarea + id: steps + attributes: + label: Steps to Reproduce + description: Share the steps you took so that we can reproduce the issue. Reports without proper steps details will likely be closed. + placeholder: | + 1. Run apinto via the Docker image. + 2. Create a Route with the Admin API. + 3. Try configuring ... + 4. ... + validations: + required: true + - type: textarea + id: environment + attributes: + label: Environment + description: Share your environment details. Reports without proper environment details will likely be closed. + value: | + - APINTO Dashboard version (run `apinto dashboard version`): + - Operating system (run `uname -a`): + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..05531c1e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: APIPark Discussion Forum + url: https://github.com/APIParkLab/APIPark/discussions + about: Please ask and answer questions here. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/docs_issue.yml b/.github/ISSUE_TEMPLATE/docs_issue.yml new file mode 100644 index 00000000..e14c4876 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/docs_issue.yml @@ -0,0 +1,33 @@ +name: "Documentation Issue" +description: Issues related to documentation. +title: "docs: " +labels: [doc] +body: + - type: markdown + attributes: + value: | + _The more information you share, the faster we can help you._ + + Prior to opening the issue, please make sure that you: + + - Use English to communicate. + - Search the [open issues](https://github.com/APIParkLab/APIPark/issues) and [discussion forum](https://github.com/APIParkLab/APIPark/discussions) to avoid duplicating the issue. + + - type: textarea + id: current-state + attributes: + label: Current State + description: Describe the current state of the documentation. + placeholder: | + The documentation for the API in this page (url) is missing ... + validations: + required: true + - type: textarea + id: desired-state + attributes: + label: Desired State + description: Describe the desired state the documentation should be in. + placeholder: | + There should be line mentioning how the API behaves when ... + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000..d08cecf9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,23 @@ +name: "Feature Request" +description: Suggest an enhancement to APINTO. +title: "feat: As a user, I want to ..., so that ..." +body: + - type: markdown + attributes: + value: | + _The more information you share, the faster we can help you._ + + Prior to opening the issue, please make sure that you: + + - Use English to communicate. + - Search the [open issues](https://github.com/APIParkLab/APIPark/issues) and [discussion forum](https://github.com/APIParkLab/APIPark/discussions) to avoid duplicating the issue. + + - type: textarea + id: description + attributes: + label: Description + description: Describe the feature you would like to see. + placeholder: | + As a user, I want to ..., so that... + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/request_help.yml b/.github/ISSUE_TEMPLATE/request_help.yml new file mode 100644 index 00000000..076cbb92 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/request_help.yml @@ -0,0 +1,31 @@ +name: "Request Help" +description: Stuck? Ask for help! +title: "help request: " +body: + - type: markdown + attributes: + value: | + _The more information you share, the faster we can help you._ + + Prior to opening the issue, please make sure that you: + + - Use English to communicate. + - Search the [open issues](https://github.com/APIParkLab/APIPark/issues) and [discussion forum](https://github.com/APIParkLab/APIPark/discussions) to avoid duplicating the issue. + + - type: textarea + id: description + attributes: + label: Description + description: Describe the issue you are facing and what you need help with. + validations: + required: true + - type: textarea + id: environment + attributes: + label: Environment + description: Share your environment details. Reports without proper environment details will likely be closed. + value: | + - APIPark version (run `apinto dashboard version`): + - Operating system (run `uname -a`): + validations: + required: true \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..9766a8d5 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,86 @@ +name: release +#触发机制,当创建tag时 +on: + release: + types: + - published +jobs: + frontend-builder: + name: frontend-builder + runs-on: ubuntu-latest + steps: + - name: SetOutput + id: vars + run: echo "tag=${GITHUB_REF#refs/*/v}" >> $GITHUB_OUTPUT + - name: Checkout #Checkout代码 + uses: actions/checkout@v3 + - name: Set up Node + uses: actions/setup-node@v3.0.0 + with: + node-version: '18.12' + - name: Pnpm install and build + run: | + npm install -g pnpm + pnpm install --registry https://registry.npmmirror.com --dir ./frontend + echo "Build frontend..." + cd ./frontend && pnpm run build + - name: upload frontend release + uses: actions/upload-artifact@v2 + with: + name: frontend-package + path: frontend/dist + release: + needs: [frontend-builder] + name: release + runs-on: ubuntu-latest + steps: + - name: SetOutput #处理Tag字符串并存进outputs + id: vars + run: | + echo "tag=${GITHUB_REF#refs/*/v}" >> $GITHUB_OUTPUT + - name: Checkout #Checkout代码 + uses: actions/checkout@v3 + - name: download frontend release + uses: actions/download-artifact@v2 + with: + name: frontend-package + path: frontend/dist + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: '1.21.1' + - name: Go tidy + run: | + go mod tidy + echo "GOVERSION=$(go version)" >> $GITHUB_ENV + - name: Create archives on Release #创建各种系统架构下的二进制包并上传至release assets + uses: goreleaser/goreleaser-action@v3.1.0 + with: + version: 1.9.2 + args: release --rm-dist + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + docker-push: + needs: [frontend-builder] + name: docker-push + runs-on: ubuntu-latest + steps: + - name: SetOutput + id: vars + run: echo "tag=${GITHUB_REF#refs/*/v}" >> $GITHUB_OUTPUT + - uses: actions/checkout@v3 + + - name: download frontend release + uses: actions/download-artifact@v2 + with: + name: frontend-package + path: frontend/dist + - name: Login Docker #登录docker + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + + - name: build + run: cd scripts && ./docker_publish.sh ${{ secrets.DOCKER_USERNAME }} "backend" + diff --git a/.gitignore b/.gitignore index b0f3cbe2..17943495 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *.DS_Store /.idea/ /config.yml +/build/ +/apipark diff --git a/controller/dynamic-module/dynamic-module.go b/controller/dynamic-module/dynamic-module.go index 820216bd..2c26549c 100644 --- a/controller/dynamic-module/dynamic-module.go +++ b/controller/dynamic-module/dynamic-module.go @@ -16,8 +16,8 @@ type IDynamicModuleController interface { List(ctx *gin.Context, module string, keyword string, cluster string, page string, pageSize string) ([]map[string]interface{}, *dynamic_module_dto.PluginInfo, int64, error) Render(ctx *gin.Context, module string) (*dynamic_module_dto.PluginBasic, map[string]interface{}, error) ModuleDrivers(ctx *gin.Context, group string) ([]*dynamic_module_dto.ModuleDriver, error) - Online(ctx *gin.Context, module string, id string, partitionInput *dynamic_module_dto.ClusterInput) error - Offline(ctx *gin.Context, module string, id string, partitionInput *dynamic_module_dto.ClusterInput) error + Online(ctx *gin.Context, module string, id string) error + Offline(ctx *gin.Context, module string, id string) error //PartitionStatuses(ctx *gin.Context, module string, keyword string, page string, pageSize string) (map[string]map[string]string, error) //PartitionStatus(ctx *gin.Context, module string, id string) (*dynamic_module_dto.OnlineInfo, error) } diff --git a/controller/dynamic-module/iml.go b/controller/dynamic-module/iml.go index 3c51cd73..fa6ce0e1 100644 --- a/controller/dynamic-module/iml.go +++ b/controller/dynamic-module/iml.go @@ -15,12 +15,12 @@ type imlDynamicModuleController struct { module dynamic_module.IDynamicModuleModule `autowired:""` } -func (i *imlDynamicModuleController) Online(ctx *gin.Context, module string, id string, partitionInput *dynamic_module_dto.ClusterInput) error { - return i.module.Online(ctx, module, id, partitionInput) +func (i *imlDynamicModuleController) Online(ctx *gin.Context, module string, id string) error { + return i.module.Online(ctx, module, id) } -func (i *imlDynamicModuleController) Offline(ctx *gin.Context, module string, id string, partitionInput *dynamic_module_dto.ClusterInput) error { - return i.module.Offline(ctx, module, id, partitionInput) +func (i *imlDynamicModuleController) Offline(ctx *gin.Context, module string, id string) error { + return i.module.Offline(ctx, module, id) } //func (i *imlDynamicModuleController) PartitionStatuses(ctx *gin.Context, module string, keyword string, page string, pageSize string) (map[string]map[string]string, error) { diff --git a/controller/my_team/iml.go b/controller/my_team/iml.go index a5438e8f..bbe9bccb 100644 --- a/controller/my_team/iml.go +++ b/controller/my_team/iml.go @@ -14,6 +14,10 @@ type imlTeamController struct { module my_team.ITeamModule `autowired:""` } +func (c *imlTeamController) SimpleTeams(ctx *gin.Context, keyword string) ([]*team_dto.SimpleTeam, error) { + return c.module.SimpleTeams(ctx, keyword) +} + func (c *imlTeamController) UpdateMemberRole(ctx *gin.Context, id string, input *team_dto.UpdateMemberRole) error { return c.module.UpdateMemberRole(ctx, id, input) } @@ -23,7 +27,7 @@ func (c *imlTeamController) GetTeam(ctx *gin.Context, id string) (*team_dto.Team } func (c *imlTeamController) Search(ctx *gin.Context, keyword string) ([]*team_dto.Item, error) { - + return c.module.Search(ctx, keyword) } @@ -31,8 +35,8 @@ func (c *imlTeamController) EditTeam(ctx *gin.Context, id string, team *team_dto return c.module.Edit(ctx, id, team) } -func (c *imlTeamController) SimpleTeams(ctx *gin.Context, keyword string) ([]*team_dto.SimpleTeam, error) { - return c.module.SimpleTeams(ctx, keyword) +func (c *imlTeamController) MySimpleTeams(ctx *gin.Context, keyword string) ([]*team_dto.SimpleTeam, error) { + return c.module.MySimpleTeams(ctx, keyword) } func (c *imlTeamController) AddMember(ctx *gin.Context, id string, users *team_dto.UserIDs) error { diff --git a/controller/my_team/team.go b/controller/my_team/team.go index a755f67c..d6de899c 100644 --- a/controller/my_team/team.go +++ b/controller/my_team/team.go @@ -2,7 +2,7 @@ package my_team import ( "reflect" - + team_dto "github.com/APIParkLab/APIPark/module/my-team/dto" "github.com/eolinker/go-common/autowire" "github.com/gin-gonic/gin" @@ -13,6 +13,7 @@ type ITeamController interface { GetTeam(ctx *gin.Context, id string) (*team_dto.Team, error) Search(ctx *gin.Context, keyword string) ([]*team_dto.Item, error) EditTeam(ctx *gin.Context, id string, team *team_dto.EditTeam) (*team_dto.Team, error) + MySimpleTeams(ctx *gin.Context, keyword string) ([]*team_dto.SimpleTeam, error) SimpleTeams(ctx *gin.Context, keyword string) ([]*team_dto.SimpleTeam, error) AddMember(ctx *gin.Context, id string, users *team_dto.UserIDs) error RemoveMember(ctx *gin.Context, id string, uuid string) error diff --git a/frontend/package.json b/frontend/package.json index bcd484ac..3ab17211 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -29,6 +29,7 @@ "@vitejs/plugin-react": "^4.2.0", "autoprefixer": "^10.4.16", "dayjs": "^1.11.10", + "dompurify": "^3.1.6", "js-base64": "^3.7.5", "moment": "^2.29.4", "postcss": "^8.4.31", diff --git a/frontend/packages/businessEntry/tsconfig.json b/frontend/packages/businessEntry/tsconfig.json index 4bc7c38f..bfb0e8fa 100644 --- a/frontend/packages/businessEntry/tsconfig.json +++ b/frontend/packages/businessEntry/tsconfig.json @@ -28,6 +28,6 @@ "@businessEntry/*": ["./src/*"], }, }, - "include": ["src", "public/iconpark_eolink.js", "public/iconpark_apinto.js", "../common/src/component/aoplatform/EditableTableWithModal.tsx", "../common/src/components/aoplatform/TransferTable.tsx", "../common/src/components/aoplatform/TreeWithMore.tsx", "../common/src/components/aoplatform/DatePicker.tsx", "../common/src/components/aoplatform/TimeRangeSelector.tsx", "../common/src/components/aoplatform/TimePicker.tsx", "../common/src/components/aoplatform/MemberTransfer.tsx", "../common/src/components/aoplatform/Navigation.tsx", "../common/src/components/aoplatform/PageList.tsx", "../common/src/components/aoplatform/GroupTree.tsx", "../common/src/components/aoplatform/ErrorBoundary.tsx", "../common/src/components/aoplatform/ScrollableSection.tsx", "../common/src/utils/postcat.tsx", "../common/src/utils/curl.ts", "../common/src/components/aoplatform/ResetPsw.tsx", "../common/src/components/aoplatform/SubscribeApprovalModalContent.tsx", "../common/src/components/aoplatform/InsidePageForHub.tsx", "src/components/aoplatform/RenderRoutes.tsx", "../common/src/components/aoplatform/PublishApprovalModalContent.tsx", "../common/src/components/aoplatform/InsidePage.tsx", "../common/src/const/type.ts", "../common/src/components/aoplatform/intelligent-plugin", "../common/src/const/domain"], + "include": ["src", "public/iconpark_eolink.js", "public/iconpark_apinto.js", "../common/src/component/aoplatform/EditableTableWithModal.tsx", "../common/src/components/aoplatform/TransferTable.tsx", "../common/src/components/aoplatform/TreeWithMore.tsx", "../common/src/components/aoplatform/DatePicker.tsx", "../common/src/components/aoplatform/TimeRangeSelector.tsx", "../common/src/components/aoplatform/TimePicker.tsx", "../common/src/components/aoplatform/MemberTransfer.tsx", "../common/src/components/aoplatform/Navigation.tsx", "../common/src/components/aoplatform/PageList.tsx", "../common/src/components/aoplatform/GroupTree.tsx", "../common/src/components/aoplatform/ErrorBoundary.tsx", "../common/src/components/aoplatform/ScrollableSection.tsx", "../common/src/utils/postcat.tsx", "../common/src/utils/curl.ts", "../common/src/components/aoplatform/ResetPsw.tsx", "../common/src/components/aoplatform/SubscribeApprovalModalContent.tsx", "src/components/aoplatform/RenderRoutes.tsx", "../common/src/components/aoplatform/PublishApprovalModalContent.tsx", "../common/src/components/aoplatform/InsidePage.tsx", "../common/src/const/type.ts", "../common/src/components/aoplatform/intelligent-plugin", "../common/src/const/domain"], "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/frontend/packages/common/src/assets/avatar_default.svg b/frontend/packages/common/src/assets/avatar_default.svg deleted file mode 100644 index 44331dce..00000000 --- a/frontend/packages/common/src/assets/avatar_default.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/frontend/packages/common/src/assets/default-avatar.png b/frontend/packages/common/src/assets/default-avatar.png new file mode 100644 index 00000000..62f745ec Binary files /dev/null and b/frontend/packages/common/src/assets/default-avatar.png differ diff --git a/frontend/packages/common/src/assets/layout-logo.png b/frontend/packages/common/src/assets/layout-logo.png index f60191cc..a02984ea 100644 Binary files a/frontend/packages/common/src/assets/layout-logo.png and b/frontend/packages/common/src/assets/layout-logo.png differ diff --git a/frontend/packages/common/src/assets/logo.png b/frontend/packages/common/src/assets/logo.png index a6895b8c..5c6dc52d 100644 Binary files a/frontend/packages/common/src/assets/logo.png and b/frontend/packages/common/src/assets/logo.png differ diff --git a/frontend/packages/common/src/components/aoplatform/BasicLayout.tsx b/frontend/packages/common/src/components/aoplatform/BasicLayout.tsx index 256f4eaa..34c003a6 100644 --- a/frontend/packages/common/src/components/aoplatform/BasicLayout.tsx +++ b/frontend/packages/common/src/components/aoplatform/BasicLayout.tsx @@ -2,9 +2,10 @@ import { ConfigProvider, Dropdown, MenuProps, - App} from 'antd'; + App, + Button} from 'antd'; import Logo from '@common/assets/layout-logo.png'; -import AvatarPic from '@common/assets/avatar_default.svg' +import AvatarPic from '@common/assets/default-avatar.png' import { routerKeyMap, TOTAL_MENU_ITEMS } from "./Navigation"; import {Outlet, useLocation, useNavigate} from "react-router-dom"; import {useEffect, useMemo, useRef, useState} from "react"; @@ -19,6 +20,8 @@ import { ResetPsw, ResetPswHandle } from './ResetPsw.tsx'; import { BasicResponse, STATUS_CODE } from '@common/const/const.ts'; import { UserInfoType, UserProfileHandle } from '@common/const/type.ts'; import { useFetch } from '@common/hooks/http.ts'; +import { QuestionCircleOutlined } from '@ant-design/icons'; +import { Icon } from '@iconify/react/dist/iconify.js'; const themeToken = { bgLayout:'#17163E;', @@ -122,13 +125,19 @@ const themeToken = { } const items: MenuProps['items'] = [ + { + key: '2', + label: ( + ) + }, { key: '3', label: ( - - 退出登录 - - ), + ) }, ]; @@ -210,19 +219,19 @@ const themeToken = { ); }, }} - // actionsRender={(props) => { - // if (props.isMobile) return []; - // if (typeof window === 'undefined') return []; - // return [ - // - // ]; - // }} + actionsRender={(props) => { + if (props.isMobile) return []; + if (typeof window === 'undefined') return []; + return [ + + ]; + }} headerTitleRender={() => (
navigator(mainPage)} /> @@ -259,7 +268,7 @@ const themeToken = { collapsed={false} collapsedButtonRender={false} > -
+
diff --git a/frontend/packages/common/src/components/aoplatform/DrawerWithFooter.tsx b/frontend/packages/common/src/components/aoplatform/DrawerWithFooter.tsx index 87531dac..bc392c79 100644 --- a/frontend/packages/common/src/components/aoplatform/DrawerWithFooter.tsx +++ b/frontend/packages/common/src/components/aoplatform/DrawerWithFooter.tsx @@ -34,8 +34,11 @@ export function DrawerWithFooter(props:DrawerWithFooterProps){ width="60%" destroyOnClose={true} maskClosable={false} + classNames={ + {footer:'text-right'} + } footer={ - + {showOkBtn && -
} -
-
-

{pageTitle}

- {tagList && tagList?.length > 0 && tagList?.map((tag)=>{ - return ( {tag.label}) - })} +
+ { showBanner &&
+
+ {backUrl &&
+ +
} +
+
+

{pageTitle}

+ {tagList && tagList?.length > 0 && tagList?.map((tag)=>{ + return ( {tag.label}) + })} +
+ {showBtn && }
- {showBtn && } +

+ {description} +

-

- {description} -

} -
{children}
+
{children}
) } diff --git a/frontend/packages/common/src/components/aoplatform/InsidePageForHub.tsx b/frontend/packages/common/src/components/aoplatform/InsidePageForHub.tsx deleted file mode 100644 index 833c717a..00000000 --- a/frontend/packages/common/src/components/aoplatform/InsidePageForHub.tsx +++ /dev/null @@ -1,54 +0,0 @@ - -import { Button, Tag } from "antd" -import {useNavigate} from "react-router-dom"; -import WithPermission from "@common/components/aoplatform/WithPermission"; -import { FC, ReactNode } from "react"; -import { ArrowLeftOutlined } from "@ant-design/icons"; - - -class InsidePageProps { - showBanner?:boolean = true - pageTitle:string = '' - tagList?:Array<{label:string|ReactNode}> = [] - children:React.ReactNode - showBtn?:boolean = false - btnTitle?:string = '' - description?:string = '' - onBtnClick?:()=>void - backUrl:string = '/' - btnAccess?:string -} - -const InsidePageForHub:FC = ({showBanner=true,pageTitle,tagList,showBtn,btnTitle,btnAccess,description,children,onBtnClick,backUrl})=>{ - const navigate = useNavigate(); - - const goBack = () => { - navigate(backUrl); - }; - return ( -
- { showBanner &&
-
- -
-
-
- {pageTitle} - {tagList && tagList?.length > 0 && tagList?.map((tag)=>{ - return ( {tag.label}) - })} -
- {showBtn && } -
-

- {description} -

-
} -
{children}
-
- ) -} - -export default InsidePageForHub \ No newline at end of file diff --git a/frontend/packages/common/src/components/aoplatform/PageList.module.css b/frontend/packages/common/src/components/aoplatform/PageList.module.css index a5b0918f..06bbac7e 100644 --- a/frontend/packages/common/src/components/aoplatform/PageList.module.css +++ b/frontend/packages/common/src/components/aoplatform/PageList.module.css @@ -4,7 +4,6 @@ } :global .eo_page_list .ant-pro-table-list-toolbar-container{ - padding:10px 20px 10px 10px !important; .ant-pro-table-list-toolbar-right{ justify-content: flex-start; diff --git a/frontend/packages/common/src/components/aoplatform/PageList.tsx b/frontend/packages/common/src/components/aoplatform/PageList.tsx index bf06ea5d..7ea5b927 100644 --- a/frontend/packages/common/src/components/aoplatform/PageList.tsx +++ b/frontend/packages/common/src/components/aoplatform/PageList.tsx @@ -77,8 +77,9 @@ const PageList = >(props: React.PropsWithChild const handleResize = () => { if (parentRef.current && !noScroll) { const res = parentRef.current.getBoundingClientRect(); - const height = res.height - ((noTop ? 0 : 52) + 40 + (showPagination && !dragSortKey ? 52 : 0) +( besidesTableHeight ?? 0)); // 减去顶部按钮、底部分页、表头高度 - setTableWidth(minTableWidth > res.width ? minTableWidth : undefined); + const height = res.height - ((noTop ? 0 : 59) + 54 + (showPagination && !dragSortKey ? 52 : 0) +( besidesTableHeight ?? 0) + 1); // 减去顶部按钮、底部分页、表头高度 + setTableWidth(minTableWidth - 5> res.width ? minTableWidth : undefined); + console.log(minTableWidth,res.width ) height && setTableHeight(minVirtualHeight === undefined ? height : (height > minVirtualHeight ? height : minVirtualHeight)); } }; @@ -112,11 +113,11 @@ const PageList = >(props: React.PropsWithChild const newColumns = useMemo(()=>{ let width:number = 0 const res = columns?.map( - (x)=>{ + (x, index)=>{ width += Number(x.width ?? ((x.filters || x.sorter) ? 120 : 100)) - x.copyable = x.copyable === false? false: true const sorter = localStorage.getItem(`${id}_sorter`) const filters = localStorage.getItem(`${id}_filters`) + x.copyable = x.copyable ?? (index === 0 || x.dataIndex === 'id' || x.dataIndex === 'email') if(sorter && x.sorter){ const sorterObj = JSON.parse(sorter) const xName = Array.isArray(x.dataIndex) ? x.dataIndex.join(','):x.dataIndex @@ -137,7 +138,7 @@ const PageList = >(props: React.PropsWithChild return ( <>{ tableTitle ? {tableTitle} : ( - addNewBtnTitle ? : undefined + addNewBtnTitle ? : undefined ) } @@ -191,7 +192,7 @@ const PageList = >(props: React.PropsWithChild ):null, ]} toolbar={{ - actions:[...[beforeSearchNode],...[searchPlaceholder? debounce(onSearchWordChange, 100)(e) : undefined } onPressEnter={()=>manualReloadTable ? manualReloadTable():actionRef.current?.reload?.()} allowClear placeholder={searchPlaceholder} prefix={{actionRef.current?.reload?.()}}/>}/>:null]], + actions:[...[beforeSearchNode],...[searchPlaceholder? debounce(onSearchWordChange, 100)(e) : undefined } onPressEnter={()=>manualReloadTable ? manualReloadTable():actionRef.current?.reload?.()} allowClear placeholder={searchPlaceholder} prefix={{actionRef.current?.reload?.()}}/>}/>:null]], }} options={{ reload: false, diff --git a/frontend/packages/common/src/components/aoplatform/PublishApprovalModalContent.tsx b/frontend/packages/common/src/components/aoplatform/PublishApprovalModalContent.tsx index c8e6a8c9..2128cc7a 100644 --- a/frontend/packages/common/src/components/aoplatform/PublishApprovalModalContent.tsx +++ b/frontend/packages/common/src/components/aoplatform/PublishApprovalModalContent.tsx @@ -26,19 +26,16 @@ const apiColumns = [ { title:'API 名称', dataIndex:'name', - copyable: true, ellipsis:true }, { title:'请求方式', dataIndex:'method', - copyable: true, ellipsis:true }, { title:'路径', dataIndex:'path', - copyable: true, ellipsis:true }, { @@ -77,7 +74,6 @@ const upstreamColumns = [ title:'地址', dataIndex:'addr', render:(text:string[])=>(<>{text.join(',')}), - copyable: true, ellipsis:true }, { @@ -265,7 +261,7 @@ export const PublishApprovalModalContent = forwardRef - +{/* {type !== 'add' && type !== 'publish' && - } + } */} {['error','done'].indexOf(data.status) !== -1 && data.clusterPublishStatus &&data.clusterPublishStatus.length > 0 && <> 上线情况: diff --git a/frontend/packages/common/src/components/aoplatform/ResetPsw.tsx b/frontend/packages/common/src/components/aoplatform/ResetPsw.tsx index b45e71c6..f3eb8d32 100644 --- a/frontend/packages/common/src/components/aoplatform/ResetPsw.tsx +++ b/frontend/packages/common/src/components/aoplatform/ResetPsw.tsx @@ -73,7 +73,7 @@ export const ResetPsw = forwardRef((props,ref)=>{ layout='vertical' form={form} scrollToFirstError - className="mx-auto mt-mbase " + className="mx-auto mt-mbase ml-mbase" name="resetPsw" // labelCol={{ span: 8 }} // wrapperCol={{ span: 10}} diff --git a/frontend/packages/common/src/components/aoplatform/UserAvatar.tsx b/frontend/packages/common/src/components/aoplatform/UserAvatar.tsx index 7748c443..ade60c0c 100644 --- a/frontend/packages/common/src/components/aoplatform/UserAvatar.tsx +++ b/frontend/packages/common/src/components/aoplatform/UserAvatar.tsx @@ -70,7 +70,7 @@ const UserAvatar: FC = () => { { key: '3', label: ( - + 退出登录 ), diff --git a/frontend/packages/common/src/components/aoplatform/WithPermission.tsx b/frontend/packages/common/src/components/aoplatform/WithPermission.tsx index c094cd55..4e02581d 100644 --- a/frontend/packages/common/src/components/aoplatform/WithPermission.tsx +++ b/frontend/packages/common/src/components/aoplatform/WithPermission.tsx @@ -9,9 +9,10 @@ type WithPermissionProps = { tooltip?:string children:ReactElement disabled?:boolean + showDisabled?:boolean } // 权限控制的高阶组件 -const WithPermission = ({access, tooltip, children,disabled}:WithPermissionProps) => { +const WithPermission = ({access, tooltip, children,disabled, showDisabled = true}:WithPermissionProps) => { const [editAccess, setEditAccess] = useState(access ? false:true) const {accessData,checkPermission} = useGlobalContext() @@ -24,16 +25,21 @@ const WithPermission = ({access, tooltip, children,disabled}:WithPermissionProps useEffect(()=>{ // 先判断权限,无论权限是否为true,如果disabled为true时则必须为ture access && setEditAccess(lastAccess) - disabled && setEditAccess(false) + console.log('editAccess',editAccess, children,children?.type?.displayName,showDisabled, children?.type?.displayName !== 'Button' && showDisabled) },[lastAccess,disabled]) + + return ( <> - {editAccess ? cloneElement(children): - - { cloneElement(children, {disabled:true})} - - } + {editAccess && !disabled && cloneElement(children)} + {editAccess && disabled && + { cloneElement(children, {disabled:true})} + } + {!editAccess && (children?.type?.displayName !== 'Button' && showDisabled ) && + { cloneElement(children, {disabled:true})} + } + ); } diff --git a/frontend/packages/common/src/components/aoplatform/intelligent-plugin/IntelligentPluginConfig.tsx b/frontend/packages/common/src/components/aoplatform/intelligent-plugin/IntelligentPluginConfig.tsx index 9f9c5a74..fc959714 100644 --- a/frontend/packages/common/src/components/aoplatform/intelligent-plugin/IntelligentPluginConfig.tsx +++ b/frontend/packages/common/src/components/aoplatform/intelligent-plugin/IntelligentPluginConfig.tsx @@ -46,6 +46,7 @@ import {createSchemaField, FormProvider, RecursionField, useField, useForm} from import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; import {useFetch} from "@common/hooks/http.ts"; import {App} from "antd"; +import { config } from "process"; @@ -218,8 +219,8 @@ export const IntelligentPluginConfig = forwardRef({ + setColumns(res.data.basic.fields.map((field:DynamicTableField, index:number)=>({ title:field.title, dataIndex:field.name, - copyable: true, fixed:field.name === 'title' ? 'left' : undefined, ellipsis:true, width:field.name === 'title' ? 150 : undefined, @@ -227,7 +226,7 @@ export default function IntelligentPluginList(){ const openDrawer = async (type:'add'|'edit', entity?:DynamicTableItem)=>{ switch (type){ case 'add': - setCurDetail({driver:driverOptions[0].value || '',config:{'c3ebd745-f7d5-45cd-8d3e-e0e43099d20e':{scopes:[]},'550e2537-8436-48e4-ab84-f9f58faf1b18':{scopes:[]}}}) + setCurDetail({driver:driverOptions[0].value || '',config:{}}) break; case 'edit':{ setDrawerLoading(true) @@ -237,9 +236,6 @@ export default function IntelligentPluginList(){ const {code, data, msg } = res if(code === STATUS_CODE.SUCCESS){ if(data.info.config){ - for (const tab in data.info.config) { - data.info.config[tab]._apinto_show = true - } } setCurDetail(data.info) }else{ @@ -276,7 +272,7 @@ export default function IntelligentPluginList(){ return;} case 'delete': title='删除' - content=确定删除成员?此操作无法恢复,确认操作? + content=确定删除?此操作无法恢复,确认操作? break; } diff --git a/frontend/packages/common/src/const/approval/const.tsx b/frontend/packages/common/src/const/approval/const.tsx index fe7181b2..859660df 100644 --- a/frontend/packages/common/src/const/approval/const.tsx +++ b/frontend/packages/common/src/const/approval/const.tsx @@ -19,25 +19,21 @@ export const SUBSCRIBE_APPROVAL_TABLE_COLUMN : ProColumns { title: '申请方-应用', dataIndex: ['application','name'], - copyable: true, ellipsis:true }, { title: '申请服务', dataIndex: ['service','name'], - copyable: true, ellipsis:true }, { title: '服务所属系统', dataIndex: ['service','name'], - copyable: true, ellipsis:true }, { title: '服务所属团队', dataIndex: ['team','name'], - copyable: true, ellipsis:true }, { @@ -74,7 +70,6 @@ export const SUBSCRIBE_APPROVAL_INNER_TODO_TABLE_COLUMN : ProColumns[] { title: '申请时间', dataIndex: 'applyTime', - copyable: true, ellipsis:true, width:182, fixed:'left', @@ -368,13 +351,11 @@ export const PUBLISH_APPROVAL_TABLE_COLUMN : ProColumns[] { title: '申请系统', dataIndex: ['service','name'], - copyable: true, ellipsis:true }, { title: '所属团队', dataIndex: ['team','name'], - copyable: true, ellipsis:true }, { diff --git a/frontend/packages/common/src/contexts/GlobalStateContext.tsx b/frontend/packages/common/src/contexts/GlobalStateContext.tsx index 287bf3c2..d9c0480f 100644 --- a/frontend/packages/common/src/contexts/GlobalStateContext.tsx +++ b/frontend/packages/common/src/contexts/GlobalStateContext.tsx @@ -109,17 +109,22 @@ export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => { const [pluginAccessDictionary, setPluginAccessDictionary] = useState<{[k:string]:string}>({}) const [teamDataFlushed, setTeamDataFlushed] = useState(false) const [accessInit, setAccessInit] = useState(false) + let getGlobalAccessPromise: Promise> | null = null const getGlobalAccessData = ()=>{ - fetchData>('profile/permission/system',{method:'GET'},).then(response=>{ + getGlobalAccessPromise = new Promise((resolve, reject) => fetchData>('profile/permission/system',{method:'GET'},).then(response=>{ const {code,data,msg} = response if(code === STATUS_CODE.SUCCESS){ setAccessInit(true) setAccessData(prevData => new Map(prevData).set('system', data.access)) + resolve(data.response) }else{ message.error(msg || '操作失败') + reject(data.msg || '操作失败') } }) + ) + return getGlobalAccessData } const getTeamAccessData = (teamId:string)=>{ @@ -149,7 +154,13 @@ export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => { setPluginAccessDictionary({}) } - const checkPermission = (access:keyof typeof PERMISSION_DEFINITION[0] | Array)=>{ + const checkPermission = async (access:keyof typeof PERMISSION_DEFINITION[0] | Array)=>{ + if( !accessInit && getGlobalAccessPromise){ + await getGlobalAccessPromise + } + if( !accessInit && !getGlobalAccessPromise){ + await getGlobalAccessData() + } let revs = false; if (Array.isArray(access)) { revs = access.some(item => checkAccess(item, accessData)); diff --git a/frontend/packages/common/tailwind.config.js b/frontend/packages/common/tailwind.config.js index 1f606491..33c2e2c7 100644 --- a/frontend/packages/common/tailwind.config.js +++ b/frontend/packages/common/tailwind.config.js @@ -75,6 +75,10 @@ module.exports = { DEFAULT_BORDER_RADIUS: 'var(--border-radius)', TREE_TITLE:'var(--small-padding) var(--LAYOUT_PADDING);', 'navbar-height': 'var(--layout-header-height)', + TAG_LEFT:'10px', + PAGE_INSIDE_X:'40px', + PAGE_INSIDE_T:'30px', + PAGE_INSIDE_B:'20px', }, borderColor: { 'color-base': 'var(--border-color)' diff --git a/frontend/packages/core/public/favicon.ico b/frontend/packages/core/public/favicon.ico index 2c1de84c..312a0fad 100644 Binary files a/frontend/packages/core/public/favicon.ico and b/frontend/packages/core/public/favicon.ico differ diff --git a/frontend/packages/core/src/App.css b/frontend/packages/core/src/App.css index 583b5ad5..db6ae5ce 100644 --- a/frontend/packages/core/src/App.css +++ b/frontend/packages/core/src/App.css @@ -80,7 +80,7 @@ .apipark-layout-layout{ .apipark-layout-layout-bg-list{ - background:#17163E; + background-image: radial-gradient(circle farthest-corner at 450px 350px, #050eb7, #17163e 500px); } .ant-layout-header.apipark-layout-layout-header{ backdrop-filter: unset !important; diff --git a/frontend/packages/core/src/components/aoplatform/RenderRoutes.tsx b/frontend/packages/core/src/components/aoplatform/RenderRoutes.tsx index 7f014904..0eba5332 100644 --- a/frontend/packages/core/src/components/aoplatform/RenderRoutes.tsx +++ b/frontend/packages/core/src/components/aoplatform/RenderRoutes.tsx @@ -379,6 +379,16 @@ const PUBLIC_ROUTES:RouteConfig[] = [ key:uuidv4() }] + }, + { + path:'userProfile/*', + lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/userProfile/UserProfile.tsx')), + key:uuidv4(), + children:[{ + path:'changepsw', + lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/userProfile/ChangePsw.tsx')), + key:uuidv4() + }] } ] }, diff --git a/frontend/packages/core/src/const/member/const.tsx b/frontend/packages/core/src/const/member/const.tsx index db321600..ed2bb056 100644 --- a/frontend/packages/core/src/const/member/const.tsx +++ b/frontend/packages/core/src/const/member/const.tsx @@ -7,7 +7,6 @@ export const MEMBER_TABLE_COLUMNS: ProColumns[] = [ { title: '用户名', dataIndex: 'name', - copyable: true, ellipsis:true, width:160, fixed:'left', @@ -18,13 +17,11 @@ export const MEMBER_TABLE_COLUMNS: ProColumns[] = [ { title: '邮箱', dataIndex: 'email', - copyable: true, ellipsis:true, }, { title: '部门', dataIndex: 'department', - copyable: true, ellipsis:true, filterMode:'tree', renderText:(_,entity:MemberTableListItem)=>(entity.department?.map(x=>x.name).join(',') || '-'), @@ -36,7 +33,6 @@ export const MEMBER_TABLE_COLUMNS: ProColumns[] = [ { title: '角色', dataIndex: 'roles', - copyable: true, ellipsis:true, width:200 }, diff --git a/frontend/packages/core/src/const/partitions/const.tsx b/frontend/packages/core/src/const/partitions/const.tsx index dae636db..1dd04fe5 100644 --- a/frontend/packages/core/src/const/partitions/const.tsx +++ b/frontend/packages/core/src/const/partitions/const.tsx @@ -8,7 +8,6 @@ export const PARTITION_CERT_TABLE_COLUMNS: ProColumns( entity.domains.join(',') ), - copyable: true, ellipsis:true }, { - title: '证书有效期', + title: '过期日期', ellipsis: true, dataIndex: 'notAfter', - copyable: true, - width:320, - renderText: (value:string,entity:PartitionCertTableListItem) => { - return `${entity.notBefore} - ${entity.notAfter}` + width:100, + renderText: (value: string) => value ? value.split(' ')?.[0] : '-', + sorter: (a,b)=> { + return a.notAfter.localeCompare(b.notAfter) }, }, { @@ -60,7 +58,6 @@ export const PARTITION_CLUSTER_TABLE_COLUMNS : ProColumns { @@ -159,7 +153,6 @@ export const PARTITION_LIST_COLUMNS: ProColumns[] = [ { title: '环境名称', dataIndex: 'name', - copyable: true, ellipsis:true, fixed:'left', sorter: (a,b)=> { @@ -169,7 +162,6 @@ export const PARTITION_LIST_COLUMNS: ProColumns[] = [ { title: 'ID', dataIndex: 'id', - copyable: true, ellipsis:true, width:140, }, diff --git a/frontend/packages/core/src/const/partitions/types.ts b/frontend/packages/core/src/const/partitions/types.ts index dab84baa..fb721e33 100644 --- a/frontend/packages/core/src/const/partitions/types.ts +++ b/frontend/packages/core/src/const/partitions/types.ts @@ -86,9 +86,15 @@ export type NodeModalFieldType = { export type NodeModalHandle = { - save:()=>Promise + save:()=>void +} +export type NodeModalPropsType = { + changeStatus:(status:ClusterPageShowStatus)=>void + getClusterInfo:()=>void + status:ClusterPageShowStatus } +export type ClusterPageShowStatus = 'view'|'preview'|'edit' export type PartitionTableListItem = { id:string; name: string; diff --git a/frontend/packages/core/src/const/role/const.tsx b/frontend/packages/core/src/const/role/const.tsx index 18afbf5d..58093888 100644 --- a/frontend/packages/core/src/const/role/const.tsx +++ b/frontend/packages/core/src/const/role/const.tsx @@ -3,7 +3,6 @@ export const ROLE_TABLE_COLUMNS = [ { title: '角色名称', dataIndex: 'name', - copyable: true, ellipsis:true, fixed:'left', sorter: (a,b)=> { diff --git a/frontend/packages/core/src/const/system/const.tsx b/frontend/packages/core/src/const/system/const.tsx index 0054011e..eff6113f 100644 --- a/frontend/packages/core/src/const/system/const.tsx +++ b/frontend/packages/core/src/const/system/const.tsx @@ -74,7 +74,6 @@ export const SYSTEM_TABLE_COLUMNS: ProColumns[] = [ { title: '服务名称', dataIndex: 'name', - copyable: true, ellipsis:true, width:160, fixed:'left', @@ -86,13 +85,11 @@ export const SYSTEM_TABLE_COLUMNS: ProColumns[] = [ title: '服务 ID', dataIndex: 'id', width: 140, - copyable: true, ellipsis:true, }, { title: '所属团队', dataIndex: ['team','name'], - copyable: true, ellipsis:true, // filters: true, // onFilter: true, @@ -134,7 +131,6 @@ export const SYSTEM_SUBSERVICE_TABLE_COLUMNS: ProColumns[] { title: '用户名', dataIndex: ['user','name'], - copyable: true, ellipsis:true, width:160, fixed:'left', @@ -318,13 +306,11 @@ export const SYSTEM_MEMBER_TABLE_COLUMN: ProColumns[] { title: '邮箱', dataIndex: 'email', - copyable: true, ellipsis:true }, { title: '角色', dataIndex: ['roles','name'], - copyable: true, ellipsis:true } @@ -374,7 +360,6 @@ export const SYSTEM_API_TABLE_COLUMNS: ProColumns[] = [ { title: '名称', dataIndex: 'name', - copyable: true, ellipsis:true, width:160, fixed:'left', @@ -401,7 +386,6 @@ export const SYSTEM_API_TABLE_COLUMNS: ProColumns[] = [ { title: 'URL', dataIndex: 'requestPath', - copyable: true, ellipsis:true }, { @@ -429,7 +413,6 @@ export const SYSTEM_UPSTREAM_TABLE_COLUMNS: ProColumns[ { title: '服务名称', dataIndex: 'name', - copyable: true, ellipsis:true, width:160, fixed:'left', @@ -714,7 +691,6 @@ export const SYSTEM_MYSERVICE_TABLE_COLUMNS: ProColumns[ title: '服务ID', dataIndex: 'id', width: 140, - copyable: true, ellipsis:true }, { @@ -796,7 +772,6 @@ export const SYSTEM_UPSTREAM_GLOBAL_CONFIG_TABLE_COLUMNS: ProColumnsAPI, 'api',undefined,undefined,undefined,'team.service.api.view'), getItem(上游, 'upstream',undefined,undefined,undefined,'team.service.upstream.view'), @@ -936,7 +911,7 @@ const APP_MODE = import.meta.env.VITE_APP_MODE; getItem(发布, 'publish',undefined,undefined,undefined,'team.service.release.view'), ], 'group'), - getItem('提供服务', 'provideSer', null, + getItem('订阅管理', 'provideSer', null, [ getItem(订阅审批, 'approval',undefined,undefined,undefined,'team.service.subscription.view'), getItem(订阅方管理, 'subscriber',undefined,undefined,undefined,'team.service.subscription.view'), diff --git a/frontend/packages/core/src/const/system/type.ts b/frontend/packages/core/src/const/system/type.ts index 2a15aa74..3ab4f8c6 100644 --- a/frontend/packages/core/src/const/system/type.ts +++ b/frontend/packages/core/src/const/system/type.ts @@ -56,8 +56,7 @@ export type SystemSubscriberTableListItem = { }; export type SystemSubscriberConfigFieldType = { - service:string - subscriber:string + application:string applier:string }; diff --git a/frontend/packages/core/src/const/team/const.tsx b/frontend/packages/core/src/const/team/const.tsx index 294ed9e1..76d2d8f9 100644 --- a/frontend/packages/core/src/const/team/const.tsx +++ b/frontend/packages/core/src/const/team/const.tsx @@ -12,7 +12,6 @@ export const TEAM_TABLE_COLUMNS: ProColumns[] = [ { title: '名称', dataIndex: 'name', - copyable: true, ellipsis:true, width:160, fixed:'left', @@ -24,13 +23,11 @@ export const TEAM_TABLE_COLUMNS: ProColumns[] = [ title: 'ID', dataIndex: 'id', width: 140, - copyable: true, ellipsis:true }, { title: '描述', dataIndex: 'description', - copyable: true, ellipsis:true }, { @@ -67,7 +64,6 @@ export const TEAM_SYSTEM_TABLE_COLUMNS: ProColumns[] = [ { title: '服务名称', dataIndex: 'name', - copyable: true, ellipsis:true, width:160, fixed:'left', @@ -79,13 +75,11 @@ export const TEAM_SYSTEM_TABLE_COLUMNS: ProColumns[] = [ title: '服务 ID', dataIndex: 'id', width: 140, - copyable: true, ellipsis:true }, { title: '所属团队', dataIndex: ['team','name'], - copyable: true, ellipsis:true }, { @@ -128,7 +122,6 @@ export const TEAM_MEMBER_TABLE_COLUMNS: ProColumns[] = { title: '姓名', dataIndex: ['user','name'], - copyable: true, ellipsis:true, width:160, fixed:'left', @@ -139,7 +132,6 @@ export const TEAM_MEMBER_TABLE_COLUMNS: ProColumns[] = { title: '团队角色', dataIndex: 'roles', - copyable: true, ellipsis:true, }, { diff --git a/frontend/packages/core/src/const/user/const.tsx b/frontend/packages/core/src/const/user/const.tsx index 7b06d0d4..a4e87916 100644 --- a/frontend/packages/core/src/const/user/const.tsx +++ b/frontend/packages/core/src/const/user/const.tsx @@ -8,7 +8,6 @@ export const USER_LIST_COLUMNS: ProColumns[]= [ { title: '用户名', dataIndex: 'name', - copyable: true, ellipsis:true, width:160, fixed:'left', @@ -19,7 +18,6 @@ export const USER_LIST_COLUMNS: ProColumns[]= [ { title: '邮箱', dataIndex: 'email', - copyable: true, ellipsis:true, }, { diff --git a/frontend/packages/core/src/index.css b/frontend/packages/core/src/index.css index baf2543b..8707926c 100644 --- a/frontend/packages/core/src/index.css +++ b/frontend/packages/core/src/index.css @@ -727,13 +727,22 @@ p{ padding-left:0 !important; padding-top:0 !important; } + .pr-PAGE_INSIDE_X{ + padding-right: 0 !important; + } } + .ant-drawer-footer{ padding:16px 20px !important } } + +.ant-modal-body .pr-PAGE_INSIDE_X{ + padding-right: 0 !important; +} + .g6-tooltip { padding: 10px 6px; color: #444; @@ -754,12 +763,22 @@ p{ height:10px !important; } -/* 生产环境无法获取到下列样式,先写在这里 */ +.eo_page_list .ant-pro-card{ + margin-top: -1px; + margin-bottom: -1px; +} + .eo_page_list .ant-pro-card .ant-pro-card-body{ padding:0 !important; } .eo_page_list .ant-pro-table-list-toolbar-container{ - padding:12px 20px 12px 12px !important; + /* padding:12px 20px 12px 12px !important; */ + padding-block:0px !important; + flex-direction: row-reverse; + + .ant-pro-table-list-toolbar-left{ + justify-content: flex-end !important; + } .ant-pro-table-list-toolbar-right{ flex:unset !important; @@ -836,9 +855,10 @@ p{ } } -/* .ant-dropdown .ant-dropdown-menu{ - border-radius: 10px; - padding: 10px; + +.ant-dropdown .ant-dropdown-menu{ + /* border-radius: 10px; + padding: 10px; */ li.ant-dropdown-menu-item{ padding:0 !important; >button.ant-btn{ @@ -848,13 +868,14 @@ p{ } >span.ant-dropdown-menu-title-content{ padding:0px !important; - min-width: 80px; - /* padding:0px 12px !important; + /* min-width: 80px; */ + /* padding:0px 12px !important; */ height:32px !important; line-height: 32px !important; .ant-btn{ width:100%; padding:0px 12px !important; + justify-content:flex-start; } .ant-btn-default:not(:disabled):not(.ant-btn-disabled):hover{ color:var(--text-color) !important; @@ -862,7 +883,7 @@ p{ } } -} */ +} .ant-dropdown-button{ .ant-btn-link{ color:var(--text-color) !important; @@ -1161,11 +1182,6 @@ p{ padding-bottom:60px !important; } -/* .padding-top-20 .virtuoso-grid-list{ - padding-bottom:60px !important; - padding:20px 40px 40px !important; -} */ - .ant-form-item-control-input-content{ .ant-pro-card-body{ padding-bottom: 0px !important; @@ -1198,4 +1214,14 @@ p{ /* .eo_page_list.role_table .ant-pro-table-list-toolbar-container{ padding-left:0 !important; padding-right:0 !important; -} */ \ No newline at end of file +} */ + + +div.preview-document{ + p{ + margin-block-start: 1em; + margin-block-end: 1em;} +} +.ant-table-wrapper .ant-table-thead th.ant-table-column-has-sorters{ + transition:none !important; +} \ No newline at end of file diff --git a/frontend/packages/core/src/pages/auditLog/AuditLog.tsx b/frontend/packages/core/src/pages/auditLog/AuditLog.tsx index 62fc17e6..4d950a01 100644 --- a/frontend/packages/core/src/pages/auditLog/AuditLog.tsx +++ b/frontend/packages/core/src/pages/auditLog/AuditLog.tsx @@ -27,7 +27,6 @@ const AUDIT_LOG_COLUMNS_CONFIG: ProColumns{ mode="inline" items={menuItems} /> -
+
diff --git a/frontend/packages/core/src/pages/member/MemberList.tsx b/frontend/packages/core/src/pages/member/MemberList.tsx index 93adb4aa..c1b7ebf0 100644 --- a/frontend/packages/core/src/pages/member/MemberList.tsx +++ b/frontend/packages/core/src/pages/member/MemberList.tsx @@ -232,7 +232,7 @@ const MemberList = ()=>{ return !checkAccess(permission, accessData); }; - const openModal = (type:'addMember'|'editMember'|'removeFromDep'|'addToDep'|'blocked'|'activate'|'delete',entity?:MemberTableListItem)=>{ + const openModal = (type:'addMember'|'editMember'|'addToDep'|'delete',entity?:MemberTableListItem)=>{ let title:string = '' let content:string|React.ReactNode = '' switch (type){ @@ -244,10 +244,6 @@ const MemberList = ()=>{ title='编辑成员信息' content= break; - case 'removeFromDep': - title='移出当前部门' - content=确定将成员从当前部门中移除?此操作无法恢复,确认操作? - break; case 'addToDep': title='加入部门' content= @@ -256,14 +252,6 @@ const MemberList = ()=>{ title='删除' content=确定删除成员?此操作无法恢复,确认操作? break; - case 'blocked': - title='禁用成员' - content=确定禁用成员?此操作无法恢复,确认操作? - break; - case 'activate': - title='启用成员' - content=确定启用成员?此操作无法恢复,确认操作? - break; } modal.confirm({ @@ -274,18 +262,9 @@ const MemberList = ()=>{ case 'addMember': return AddMemberRef.current?.save().then((res)=>{if(res === true) {refreshGroup && refreshGroup();manualReloadTable()}}) case 'editMember': - //console.log('addChild') return EditMemberRef.current?.save().then((res)=>{if(res === true){refreshGroup && refreshGroup();manualReloadTable()}}) - case 'removeFromDep': - //console.log('addChild') - return handleMemberAction('removeFromDep').then((res)=>{if(res === true){refreshGroup && refreshGroup();manualReloadTable()}}) case 'addToDep': - //console.log('addToDep') return AddToDepRef.current?.save().then((res)=>{if(res === true) {refreshGroup && refreshGroup();manualReloadTable()}}) - case 'activate': - return handleMemberAction('activate').then((res)=>{if(res === true){refreshGroup && refreshGroup();manualReloadTable()}}) - case 'blocked': - return handleMemberAction('blocked').then((res)=>{if(res === true){refreshGroup && refreshGroup();manualReloadTable()}}) case 'delete': return handleMemberAction('delete').then((res)=>{if(res === true){refreshGroup && refreshGroup();manualReloadTable()}}) } @@ -376,7 +355,7 @@ const MemberList = ()=>{ return ( <> - { onRowClick={handleRowClick} tableClickAccess="system.organization.member.edit" afterNewBtn={[ - memberGroupId &&, - memberGroupId &&, - memberGroupId !== 'disable' &&, - , - , + selectedRowKeys.length > 0 && memberGroupId &&, + selectedRowKeys.length > 0 && memberGroupId &&, + selectedRowKeys.length > 0 && memberGroupId !== 'disable' &&, + selectedRowKeys.length > 0 && , + selectedRowKeys.length > 0 &&, ]} onSearchWordChange={(e) => { setSearchWord(e.target.value) diff --git a/frontend/packages/core/src/pages/member/MemberPage.tsx b/frontend/packages/core/src/pages/member/MemberPage.tsx index fb26cd81..4d7b1378 100644 --- a/frontend/packages/core/src/pages/member/MemberPage.tsx +++ b/frontend/packages/core/src/pages/member/MemberPage.tsx @@ -17,6 +17,7 @@ import { checkAccess } from "@common/utils/permission.ts"; import { RenameDepModal } from "./Modal/RenameDepModal.tsx"; import { AddDepModal } from "./Modal/AddDepModal.tsx"; import { EditMemberModal } from "./Modal/EditMember.tsx"; +import InsidePage from "@common/components/aoplatform/InsidePage.tsx"; const MemberPage = ()=>{ const [searchWord, setSearchWord] = useState('') @@ -244,56 +245,41 @@ const MemberPage = ()=>{ },[memberGroupId]) return ( - -
-
-

成员

-

设置成员和对应的角色,成员只能够看到权限范围内的功能和数据。

-
- -
-
-
- debounce(onSearchWordChange, 100)(e.target.value)} - allowClear placeholder="搜索部门" - prefix={}/> -
-
-
- } - blockNode={true} - treeData={treeData} - selectedKeys={[selectedDepartmentId]} - expandedKeys={expandedKeys} - onExpand={(expandedKeys:Key[])=>{setExpandedKeys(expandedKeys)}} - onSelect={(selectedKeys,selectedRow) => { - if(selectedKeys.length > 0 ){ - setSelectedDepartmentIds((selectedRow.node as unknown).departmentIds || []) - navigate(`/member/list${selectedKeys[0] === '-1'? '' : `/${selectedKeys[0]}`}`) - } - }} - /> - {/* } + +
+
+
+ debounce(onSearchWordChange, 100)(e.target.value)} + allowClear placeholder="搜索部门" + prefix={}/> +
+
+
+ } blockNode={true} treeData={treeData} selectedKeys={[selectedDepartmentId]} expandedKeys={expandedKeys} - onExpand={(expandedKeys:string[])=>{setExpandedKeys(expandedKeys)}} + onExpand={(expandedKeys:Key[])=>{setExpandedKeys(expandedKeys)}} onSelect={(selectedKeys,selectedRow) => { + if(selectedKeys.length > 0 ){ setSelectedDepartmentIds((selectedRow.node as unknown).departmentIds || []) - navigate(`/member/list${selectedKeys[0] === '-1' ? '' : `/${selectedKeys[0]}`}`) + navigate(`/member/list${selectedKeys[0] === '-1'? '' : `/${selectedKeys[0]}`}`) + } }} - /> */} + /> +
+
+ getDepartmentList()}}/> +
-
- getDepartmentList()}}/> -
-
-
); + ); } export default MemberPage; \ No newline at end of file diff --git a/frontend/packages/core/src/pages/partitions/PartitionInsideCert.tsx b/frontend/packages/core/src/pages/partitions/PartitionInsideCert.tsx index 17693386..cec416da 100644 --- a/frontend/packages/core/src/pages/partitions/PartitionInsideCert.tsx +++ b/frontend/packages/core/src/pages/partitions/PartitionInsideCert.tsx @@ -16,6 +16,7 @@ import TableBtnWithPermission from "@common/components/aoplatform/TableBtnWithPe import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx"; import { checkAccess } from "@common/utils/permission.ts"; import { PERMISSION_DEFINITION } from "@common/const/permissions.ts"; +import InsidePage from "@common/components/aoplatform/InsidePage.tsx"; const CertConfigModal = forwardRef((props, ref) => { const { message } = App.useApp() @@ -282,11 +283,12 @@ const PartitionInsideCert:FC = ()=>{ },[memberValueEnum]) return ( -
-
-

证书

-

通过为 API 服务配置和管理 SSL 证书,企业可以加密数据传输,防止敏感信息被窃取或篡改。

-
+ { onRowClick={(row:PartitionCertTableListItem)=>openModal('edit',row)} tableClickAccess="system.devops.ssl_certificate.edit" /> -
+ ) } diff --git a/frontend/packages/core/src/pages/partitions/PartitionInsideCluster.tsx b/frontend/packages/core/src/pages/partitions/PartitionInsideCluster.tsx index a41aa03d..2a9773f2 100644 --- a/frontend/packages/core/src/pages/partitions/PartitionInsideCluster.tsx +++ b/frontend/packages/core/src/pages/partitions/PartitionInsideCluster.tsx @@ -1,33 +1,30 @@ import { FC, useEffect, useRef, useState} from "react"; import {useBreadcrumb} from "@common/contexts/BreadcrumbContext.tsx"; -import {App, Button, Col, Collapse, Empty, Row, Spin, Tag} from "antd"; +import {App, Button, Card, Col, Row, Spin, Tag} from "antd"; import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; import {useFetch} from "@common/hooks/http.ts"; -import { NodeModalHandle, PartitionClusterNodeTableListItem } from "../../const/partitions/types.ts"; +import { ClusterPageShowStatus, NodeModalHandle, PartitionClusterNodeTableListItem } from "../../const/partitions/types.ts"; import WithPermission from "@common/components/aoplatform/WithPermission.tsx"; -import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx"; import { ClusterNodeModal } from "./PartitionInsideClusterNode.tsx"; -import { DownOutlined, LoadingOutlined, UpOutlined } from "@ant-design/icons"; -import { checkAccess } from "@common/utils/permission.ts"; +import { LoadingOutlined } from "@ant-design/icons"; +import InsidePage from "@common/components/aoplatform/InsidePage.tsx"; const PartitionInsideCluster:FC = ()=> { const {setBreadcrumb} = useBreadcrumb() const {modal, message} = App.useApp() const {fetchData} = useFetch() - const [nodesList, setNodesList] = useState() + const [nodeData, setNodeData] = useState() const [loading, setLoading] = useState(false) - const {accessData} = useGlobalContext() - const [activeKey, setActiveKey] = useState([]) const editNodeRef = useRef(null) + const [showStatus, setShowStatus] = useState('view') const getPartitionClusterInfo = () => { - setNodesList([]) setLoading(true) return fetchData>('cluster/nodes', {method: 'GET',eoTransformKeys:['manager_address','service_address','peer_address']}).then(response => { const {code, data, msg} = response if (code === STATUS_CODE.SUCCESS) { - setNodesList(data.nodes) - setActiveKey(data.nodes.map((x:PartitionClusterNodeTableListItem)=>x.id)) + data.nodes && data.nodes.length > 0 && setNodeData(data.nodes[0]) + setShowStatus('view') } else { message.error(msg || '操作失败') } @@ -38,37 +35,6 @@ const PartitionInsideCluster:FC = ()=> { }) } - const openModal = async (type:'editNode')=>{ - let title:string = '' - let content:string|React.ReactNode = '' - - switch(type){ - case 'editNode': { - title = '重置配置' - content = - } - break; - } - - modal.confirm({ - title, - content, - onOk:()=> { - switch (type){ - case 'editNode': - return editNodeRef.current?.save().then((res:boolean)=>{if(res === true) getPartitionClusterInfo(); return false}) - } - }, - width:type === 'editNode' ? 900 : 600, - okText:'确认', - okButtonProps:{ - disabled:!checkAccess('system.devops.cluster.edit', accessData) - }, - cancelText:'取消', - closable:true, - icon:<>, - }) - } useEffect(() => { setBreadcrumb([ @@ -77,41 +43,53 @@ const PartitionInsideCluster:FC = ()=> { getPartitionClusterInfo() }, []); + const setClusterBtn = ()=>{ + return (<> + {showStatus === 'view' && + + } + ) + } + return ( <> -
- -
-

集群

-

设置访问 API 的集群,让 API 在分布式环境中稳定运行,并且能够根据业务需求进行灵活扩展和优化。

+ +
+ } spinning={loading}> +
+ APIPark Node + {!loading && + { !nodeData && '未配置'} + { nodeData?.status === 1 && '正常' } + { nodeData?.status === 0 && '异常'} + }
} + extra={setClusterBtn()}> + {showStatus === 'view'&& nodeData && ClusterConfigPreview(nodeData) } + {showStatus !== 'view' && } + +
+
- -
- } spinning={loading}> -
- {nodesList && nodesList.length > 0 ? - (isActive? : )} - items={nodesList?.map(x=>{ - return { - label:
{x.status === 1 ? '正常' : '异常'}{x.managerAddress.join(',')}
, - key:x.id, - children:
- 管理地址:{x.managerAddress.map(m=>(

{m}

))}
- 服务地址:{x.serviceAddress.map(m=>(

{m}

))}
- 同步地址:

{x.peerAddress}

-
- } - })} - activeKey={activeKey} - onChange={(val)=>{setActiveKey(val as string[])}} - />: - } -
-
-
+ ) } +export function ClusterConfigPreview (x:PartitionClusterNodeTableListItem){ + return
+ 管理地址:{x.managerAddress.map(m=>(

{m}

))}
+ 服务地址:{x.serviceAddress.map(m=>(

{m}

))}
+ 同步地址:

{x.peerAddress}

+
} + export default PartitionInsideCluster \ No newline at end of file diff --git a/frontend/packages/core/src/pages/partitions/PartitionInsideClusterNode.tsx b/frontend/packages/core/src/pages/partitions/PartitionInsideClusterNode.tsx index 81eb676d..a9d23ca2 100644 --- a/frontend/packages/core/src/pages/partitions/PartitionInsideClusterNode.tsx +++ b/frontend/packages/core/src/pages/partitions/PartitionInsideClusterNode.tsx @@ -4,45 +4,54 @@ import {App, Button, Form, Input, Table} from "antd"; import {useFetch} from "@common/hooks/http.ts"; import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; import { NODE_MODAL_COLUMNS } from "../../const/partitions/const.tsx"; -import { NodeModalHandle, PartitionClusterNodeModalTableListItem, PartitionClusterNodeTableListItem, NodeModalFieldType } from "../../const/partitions/types.ts"; +import { NodeModalHandle, PartitionClusterNodeModalTableListItem, PartitionClusterNodeTableListItem, NodeModalFieldType, NodeModalPropsType } from "../../const/partitions/types.ts"; import WithPermission from "@common/components/aoplatform/WithPermission.tsx"; +import { ClusterConfigPreview } from "./PartitionInsideCluster.tsx"; +import { set, values } from "lodash-es"; -export const ClusterNodeModal = forwardRef((_,ref)=>{ +export const ClusterNodeModal = forwardRef((props,ref)=>{ const { message } = App.useApp() + const {changeStatus,getClusterInfo, status} = props const [form] = Form.useForm(); const [dataSource,setDataSource] = useState([]) const {fetchData} = useFetch() + const [addressError, setAddressError] = useState<'' | 'error'>('') const test = ()=>{ setDataSource([]) - return new Promise((resolve, reject)=>{ - form.validateFields().then((value)=> { + form.validateFields().then((value)=> { + if(!value.address) { + setAddressError('error') + return + } fetchData>('cluster/check', {method: 'POST', eoBody: (value),eoTransformKeys:['manager_address','service_address','peer_address']}).then(response => { const {code,data, msg} = response if (code === STATUS_CODE.SUCCESS) { message.success(msg || '操作成功') setDataSource(data.nodes) + changeStatus('preview') } else { - message.error(msg || '操作失败') + message.error(msg || '无法连接集群,请检查集群地址是否正确或防火墙配置') + setAddressError('error') + } - }).catch((errorInfo)=> reject(errorInfo)) - }).catch((errorInfo)=> reject(errorInfo)) + }).catch((errorInfo)=>{ + console.warn(errorInfo) + }) })} - const save:()=>Promise = ()=>{ - return new Promise((resolve, reject)=>{ + const save = ()=>{ form.validateFields().then(()=> { fetchData>('cluster/reset',{method:'PUT' ,eoBody:({managerAddress:form.getFieldValue('address')}), eoTransformKeys:['managerAddress']}).then(response=>{ const {code,msg} = response if(code === STATUS_CODE.SUCCESS){ message.success(msg || '操作成功!') - resolve(true) + getClusterInfo() }else{ message.error(msg || '操作失败') - reject(msg || '操作失败') } - }).catch((errorInfo)=> reject(errorInfo)) - }).catch((errorInfo)=> reject(errorInfo)) + }).catch((errorInfo)=> + console.warn(errorInfo)) }) } @@ -61,32 +70,25 @@ export const ClusterNodeModal = forwardRef((_,ref)=>{ className="mx-auto " autoComplete="off" name="partitionInsideClusterNode" + > -
+ {status === 'edit' ? + label="集群地址" name="address" - className="p-0 bg-transparent rounded-none border-none flex-1" - rules={[{ required: true, message: '必填项' }]} + className="mb-0" + validateStatus={addressError} + help={addressError ? form.getFieldValue('address')? '无法连接集群,请检查集群地址是否正确或防火墙配置' : '必填项' : ''} > - test()}/> - -
- -
-
- { - dataSource.length > 0 && - - } + test()} onChange={(e)=>setAddressError(e.target?.value ? '' : 'error')}/> + : dataSource && ClusterConfigPreview(dataSource?.[0] as unknown as PartitionClusterNodeTableListItem)} + +
+ { status === 'edit' && } + { status === 'preview' && } + +
) diff --git a/frontend/packages/core/src/pages/role/RoleConfig.tsx b/frontend/packages/core/src/pages/role/RoleConfig.tsx index 21aab980..6b0756e5 100644 --- a/frontend/packages/core/src/pages/role/RoleConfig.tsx +++ b/frontend/packages/core/src/pages/role/RoleConfig.tsx @@ -152,9 +152,7 @@ const RoleConfig = ()=>{ const newPermits = generateNewPermit(data.permits) generateDependenciesMap(newPermits) setPermissionTemplate(newPermits) - console.log(newPermits) }else{ - console.log(message) message.error(msg || '获取权限模板失败') } }) @@ -196,7 +194,7 @@ const RoleConfig = ()=>{ }).catch((errInfo)=>Promise.reject(errInfo)) }; - return (
+ return (
@@ -214,7 +212,7 @@ const RoleConfig = ()=>{ >
@@ -222,7 +220,7 @@ const RoleConfig = ()=>{ diff --git a/frontend/packages/core/src/pages/role/RoleList.tsx b/frontend/packages/core/src/pages/role/RoleList.tsx index 1af89ffc..9bf88d3d 100644 --- a/frontend/packages/core/src/pages/role/RoleList.tsx +++ b/frontend/packages/core/src/pages/role/RoleList.tsx @@ -1,4 +1,4 @@ -import { App, Divider} from "antd"; +import { App} from "antd"; import PageList from "@common/components/aoplatform/PageList.tsx"; import { useEffect, useRef,} from "react"; import {ActionType, ProColumns} from "@ant-design/pro-components"; @@ -12,6 +12,7 @@ import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx"; import { checkAccess } from "@common/utils/permission.ts"; import { useNavigate } from "react-router-dom"; import { RoleTableListItem } from "@core/const/role/type.ts"; +import InsidePage from "@common/components/aoplatform/InsidePage.tsx"; const RoleList = ()=>{ @@ -116,46 +117,50 @@ const RoleList = ()=>{ }, []); return (<> -
-
-

角色

-

设置角色的权限范围。

-
-

系统级别角色

- [], ...operation('system')]} - request={()=>getRoleList('system')} - addNewBtnTitle="添加角色" - showPagination={false} - onAddNewBtnClick={() => { - navigateTo(`/role/system/config`) - }} - noScroll={true} - addNewBtnAccess="system.organization.role.system.add" - onRowClick={(row:RoleTableListItem)=> navigateTo(`/role/system/config/${row.id}`)} - tableClickAccess="system.organization.role.system.edit" - /> -

团队级别角色

- [], ...operation('team')]} - request={()=>getRoleList('team')} - showPagination={false} - addNewBtnTitle="添加角色" - onAddNewBtnClick={() => { - navigateTo(`/role/team/config`) - }} - noScroll={true} - addNewBtnAccess="system.organization.role.team.add" - onRowClick={(row:RoleTableListItem)=> navigateTo(`/role/team/config/${row.id}`)} - tableClickAccess="system.organization.role.team.edit" - /> -
+ +
+

系统级别角色

+ [], ...operation('system')]} + request={()=>getRoleList('system')} + addNewBtnTitle="添加角色" + showPagination={false} + onAddNewBtnClick={() => { + navigateTo(`/role/system/config`) + }} + noScroll={true} + addNewBtnAccess="system.organization.role.system.add" + onRowClick={(row:RoleTableListItem)=> navigateTo(`/role/system/config/${row.id}`)} + tableClickAccess="system.organization.role.system.edit" + /> +

团队级别角色

+ [], ...operation('team')]} + request={()=>getRoleList('team')} + showPagination={false} + addNewBtnTitle="添加角色" + onAddNewBtnClick={() => { + navigateTo(`/role/team/config`) + }} + noScroll={true} + addNewBtnAccess="system.organization.role.team.add" + onRowClick={(row:RoleTableListItem)=> navigateTo(`/role/team/config/${row.id}`)} + tableClickAccess="system.organization.role.team.edit" + /> +
+
) } export default RoleList; \ No newline at end of file diff --git a/frontend/packages/core/src/pages/serviceCategory/ServiceCategory.tsx b/frontend/packages/core/src/pages/serviceCategory/ServiceCategory.tsx index 60449f2a..8834d662 100644 --- a/frontend/packages/core/src/pages/serviceCategory/ServiceCategory.tsx +++ b/frontend/packages/core/src/pages/serviceCategory/ServiceCategory.tsx @@ -5,7 +5,7 @@ import { PERMISSION_DEFINITION } from "@common/const/permissions"; import { useFetch } from "@common/hooks/http"; import { checkAccess } from "@common/utils/permission"; import { CategorizesType, ServiceHubCategoryConfigHandle } from "@market/const/serviceHub/type"; -import { App, Button, Spin, TagType, Tree, TreeDataNode, TreeProps } from "antd"; +import { App, Button, Spin, Tree, TreeDataNode, TreeProps } from "antd"; import { DataNode } from "antd/es/tree"; import { Key, useEffect, useMemo, useRef, useState } from "react"; import { ServiceHubCategoryConfig } from "./ServiceHubCategoryConfig"; @@ -14,6 +14,8 @@ import { useBreadcrumb } from "@common/contexts/BreadcrumbContext"; import { LoadingOutlined } from "@ant-design/icons"; import { cloneDeep } from "lodash-es"; import { Icon } from "@iconify/react/dist/iconify.js"; +import InsidePage from "@common/components/aoplatform/InsidePage"; +import { EntityItem } from "@common/const/type"; export default function ServiceCategory(){ const [gData, setGData] = useState([]); @@ -227,7 +229,7 @@ export default function ServiceCategory(){ const getCategoryList = ()=>{ setLoading(true) - fetchData>('catalogues',{method:'GET'}).then(response=>{ + fetchData>('catalogues',{method:'GET'}).then(response=>{ const {code,data,msg} = response if(code === STATUS_CODE.SUCCESS){ setGData(data.catalogues) @@ -246,12 +248,14 @@ export default function ServiceCategory(){ },[]) return ( -
-
-

服务分类管理

-

设置服务可选择的分类,方便团队成员快速找到API。

-
-
+ +
} spinning={loading} className=''>
-
+ ) } \ No newline at end of file diff --git a/frontend/packages/core/src/pages/system/SystemConfig.tsx b/frontend/packages/core/src/pages/system/SystemConfig.tsx index af588182..21c6bd34 100644 --- a/frontend/packages/core/src/pages/system/SystemConfig.tsx +++ b/frontend/packages/core/src/pages/system/SystemConfig.tsx @@ -1,6 +1,6 @@ import {forwardRef, useEffect, useImperativeHandle, useState} from "react"; -import {App, Button, Divider, Form, Input, Radio, Row, Select, TagType, TreeSelect, Upload} from "antd"; +import {App, Button, Form, Input, Radio, Row, Select, TreeSelect, Upload} from "antd"; import { Link, useNavigate, useParams} from "react-router-dom"; import {RouterParams} from "@core/components/aoplatform/RenderRoutes.tsx"; import {BasicResponse, STATUS_CODE} from "@common/const/const.ts"; @@ -20,6 +20,7 @@ import { getImgBase64 } from "@common/utils/dataTransfer.ts"; import { CategorizesType } from "@market/const/serviceHub/type.ts"; import WithPermission from "@common/components/aoplatform/WithPermission.tsx"; import { Icon } from "@iconify/react/dist/iconify.js"; +import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx"; const MAX_SIZE = 2 * 1024; // 1KB @@ -38,6 +39,7 @@ const SystemConfig = forwardRef((_,ref) => { const [tagOptionList, setTagOptionList] = useState([]) const [serviceClassifyOptionList, setServiceClassifyOptionList] = useState() const [uploadLoading, setUploadLoading] = useState(false) + const {checkPermission} = useGlobalContext() useImperativeHandle(ref, () => ({ save:onFinish @@ -93,11 +95,11 @@ const SystemConfig = forwardRef((_,ref) => { const getTagAndServiceClassifyList = ()=>{ setTagOptionList([]) setServiceClassifyOptionList([]) - fetchData>('catalogues',{method:'GET'}).then(response=>{ + fetchData>('catalogues',{method:'GET'}).then(response=>{ const {code,data,msg} = response if(code === STATUS_CODE.SUCCESS){ - setTagOptionList(data.tags?.map((x:TagType)=>{return { - label:x.name, value:x.name + setTagOptionList(data.tags?.map((x:EntityItem)=>{return { + label:x.name, value:x.id }})||[]) setServiceClassifyOptionList(data.catalogues) @@ -127,19 +129,6 @@ const SystemConfig = forwardRef((_,ref) => { } ] }) - console.log({ - ...data.service, - team:data.service.team.id, - catalogue:data.service.catalogue?.id, - logoFile:[ - { - uid: '-1', // 文件唯一标识 - name: 'image.png', // 文件名 - status: 'done', // 状态有:uploading, done, error, removed - url: data.service?.logo || '', // 图片 Base64 数据 - } - ] - }) setImageBase64(data.service.logo) setShowClassify(data.service.serviceType === 'public') },0) @@ -170,7 +159,8 @@ const SystemConfig = forwardRef((_,ref) => { const getTeamOptionList = ()=>{ setTeamOptionList([]) - fetchData>('simple/teams/mine',{method:'GET',eoTransformKeys:['available_partitions']}).then(response=>{ + + fetchData>(!checkPermission('system.workspace.team.view_all') ?'simple/teams/mine' :'simple/teams',{method:'GET',eoTransformKeys:[]}).then(response=>{ const {code,data,msg} = response if(code === STATUS_CODE.SUCCESS){ setTeamOptionList(data.teams?.map((x:MemberItem)=>{return {...x, @@ -202,7 +192,7 @@ const SystemConfig = forwardRef((_,ref) => { getSystemInfo(); setBreadcrumb([ { - title: 内部数据服务 + title: 服务 }, { title: '设置' @@ -238,14 +228,13 @@ const SystemConfig = forwardRef((_,ref) => { return ( <> -
((_,ref) => { label="服务ID" name="id" - extra="服务ID(sys_id)可用于检索服务或日志" rules={[{ required: true, message: '必填项' ,whitespace:true }]} > @@ -271,7 +259,7 @@ const SystemConfig = forwardRef((_,ref) => { label="API 调用前缀" name="prefix" - extra="选填,作为服务内所有服务的API的前缀,比如host/{sys_name}/{service_name}/{api_path},一旦保存无法修改" + extra="选填,作为服务内所有API的前缀,比如host/{service_name}/{api_path},一旦保存无法修改" rules={[ { validator: validateUrlSlash, @@ -376,18 +364,19 @@ const SystemConfig = forwardRef((_,ref) => { }
{onEdit && <> -
-

删除服务:删除操作不可恢复,请谨慎操作!

-
- - - + +
+

删除服务:删除操作不可恢复,请谨慎操作!

+
+ + + +
-
+ } -
) }) diff --git a/frontend/packages/core/src/pages/system/SystemInsideDocument.tsx b/frontend/packages/core/src/pages/system/SystemInsideDocument.tsx index 83c34a6b..16d8eb9d 100644 --- a/frontend/packages/core/src/pages/system/SystemInsideDocument.tsx +++ b/frontend/packages/core/src/pages/system/SystemInsideDocument.tsx @@ -67,7 +67,7 @@ const ServiceInsideDocument = ()=>{ }, []); return ( -
+
{ }; useEffect(() => { - console.log(apiId, serviceId, currentUrl) if(apiId !== undefined){ setActiveMenu('api') }else if(serviceId !== currentUrl.split('/')[currentUrl.split('/').length - 1]){ @@ -84,7 +83,6 @@ const SystemInsidePage:FC = ()=> { }else{ setActiveMenu('api') } - console.log(activeMenu) }, [currentUrl]); useEffect(()=>{ @@ -119,7 +117,7 @@ const SystemInsidePage:FC = ()=> { mode="inline" items={menuData as unknown as ItemType[] } /> -
+
diff --git a/frontend/packages/core/src/pages/system/SystemInsideSubscriber.tsx b/frontend/packages/core/src/pages/system/SystemInsideSubscriber.tsx index d04123df..f7e7a631 100644 --- a/frontend/packages/core/src/pages/system/SystemInsideSubscriber.tsx +++ b/frontend/packages/core/src/pages/system/SystemInsideSubscriber.tsx @@ -126,7 +126,7 @@ const SystemInsideSubscriber:FC = ()=>{ useEffect(() => { setBreadcrumb([ { - title:内部数据服务 + title:服务 }, { title:'订阅方管理' @@ -151,6 +151,7 @@ const SystemInsideSubscriber:FC = ()=>{ addNewBtnTitle="新增订阅方" onAddNewBtnClick={()=>{openModal('add')}} addNewBtnAccess="team.service.subscription.add" + tableClass="pr-PAGE_INSIDE_X" /> ) } @@ -164,12 +165,10 @@ export const SystemSubscriberConfig = forwardRef() - const [memberOptionList, setMemberOptionList] = useState() - const [subscriberTeamId, setSubscriberTeamId] = useState() const save:()=>Promise = ()=>{ return new Promise((resolve, reject)=>{ form.validateFields().then((value)=>{ - fetchData>('service/subscriber',{method:'POST',eoBody:({...value,service:serviceId}), eoParams:{service:serviceId,team:teamId}}).then(response=>{ + fetchData>('service/subscriber',{method:'POST',eoBody:({...value}), eoParams:{service:serviceId,team:teamId}}).then(response=>{ const {code,msg} = response if(code === STATUS_CODE.SUCCESS){ message.success(msg || '操作成功!') @@ -195,7 +194,6 @@ export const SystemSubscriberConfig = forwardRef(); - data.apps .filter((x:SimpleSystemItem)=>x.id !== serviceId) .forEach((item:SimpleSystemItem) => { @@ -225,24 +223,6 @@ export const SystemSubscriberConfig = forwardRef{ - subscriberTeamId && getMemberList() - form.setFieldValue('applier',null) - },[subscriberTeamId]) - - const getMemberList = ()=>{ - setMemberOptionList([]) - fetchData>('team/members/simple',{method:'GET',eoParams:{team:subscriberTeamId}}).then(response=>{ - const {code,data,msg} = response - if(code === STATUS_CODE.SUCCESS){ - setMemberOptionList(data.members?.map((x:NewSimpleMemberItem)=>{return { - label:x.user.name, value:x.user.id - }})) - }else{ - message.error(msg || '操作失败') - } - }) - } useEffect(() => { getSystemList() @@ -262,7 +242,7 @@ export const SystemSubscriberConfig = forwardRef label="订阅方" - name="subscriber" + name="application" rules={[{ required: true, message: '必填项' }]} > {setSubscriberTeamId(_)}} /> - - @@ -168,14 +167,16 @@ const ManagementConfig = forwardRef -
-

删除应用:删除操作不可恢复,请谨慎操作!

-
- - + +
+

删除应用:删除操作不可恢复,请谨慎操作!

+
+ + + +
+
-
-
} diff --git a/frontend/packages/market/src/pages/serviceHub/management/ServiceHubManagement.tsx b/frontend/packages/market/src/pages/serviceHub/management/ServiceHubManagement.tsx index 66a1f3de..0501c20b 100644 --- a/frontend/packages/market/src/pages/serviceHub/management/ServiceHubManagement.tsx +++ b/frontend/packages/market/src/pages/serviceHub/management/ServiceHubManagement.tsx @@ -25,14 +25,14 @@ export default function ServiceHubManagement() { const [teamList, setTeamList] = useState([]) const {setAppName} = useTenantManagementContext() const navigateTo = useNavigate() - const {getTeamAccessData,cleanTeamAccessData} = useGlobalContext() + const {getTeamAccessData,cleanTeamAccessData,checkPermission} = useGlobalContext() type MenuItem = Required['items'][number]; const getServiceList = ()=>{ //console.log(pagination,sorter,categoryId,tagId) setServiceLoading(true) - fetchData>('my_apps',{method:'GET', eoParams:{ team:teamId,keyword:''},eoTransformKeys:['api_num','subscribe_num','subscribe_verify_num']}).then(response=>{ + return fetchData>(!checkPermission('system.workspace.application.view_all') ? 'my_apps':'apps',{method:'GET',eoParams:{ team:teamId,keyword:''},eoTransformKeys:['api_num','subscribe_num','subscribe_verify_num']}).then(response=>{ const {code,data,msg} = response if(code === STATUS_CODE.SUCCESS){ setServiceList([...data.apps,{type:'addNewItem'}]) @@ -51,7 +51,7 @@ const getServiceList = ()=>{ const getTeamsList = ()=>{ setPageLoading(true) - fetchData>('simple/teams/mine',{method:'GET',eoTransformKeys:['app_num','subscribe_num']}).then(response=>{ + fetchData>(!checkPermission('system.workspace.team.view_all') ?'simple/teams/mine' :'simple/teams',{method:'GET',eoTransformKeys:['app_num','subscribe_num']}).then(response=>{ const {code,data,msg} = response if(code === STATUS_CODE.SUCCESS){ setTeamList(data.teams.map((x:SimpleTeamItem)=>({label:
{x.name}{x.appNum || 0}
, key:x.id}))) @@ -200,7 +200,7 @@ useEffect(() => { const CardTitle = (service:ServiceHubAppListItem)=>{ return(
- } /> + } />

{service.name}

diff --git a/frontend/packages/systemRunning/src/pages/SystemRunningInstruction.tsx b/frontend/packages/systemRunning/src/pages/SystemRunningInstruction.tsx index 4eb94599..9c72500a 100644 --- a/frontend/packages/systemRunning/src/pages/SystemRunningInstruction.tsx +++ b/frontend/packages/systemRunning/src/pages/SystemRunningInstruction.tsx @@ -19,9 +19,9 @@ export default function SystemRunningInstruction() {

*/}
-

内部数据服务设置

+

服务设置

支持根据权限,拆分人员对 API 添加 、上游设置、鉴权设置等信息发布及管理;同时支持管理 API 调用服务(包含第三方调用)及订阅;

-

添加内部数据服务信息

+

添加服务信息

diff --git a/go.mod b/go.mod index e644fc25..c667d359 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,9 @@ go 1.21 //toolchain go1.21.1 require ( - github.com/eolinker/ap-account v1.0.6 + github.com/eolinker/ap-account v1.0.9 github.com/eolinker/eosc v0.17.3 - github.com/eolinker/go-common v1.0.1 + github.com/eolinker/go-common v1.0.4 github.com/gabriel-vasile/mimetype v1.4.4 github.com/gin-gonic/gin v1.10.0 github.com/google/uuid v1.6.0 @@ -66,4 +66,5 @@ require ( gorm.io/driver/mysql v1.5.2 // indirect ) -//replace github.com/eolinker/ap-account v1.0.4 => ../ap-account +//replace github.com/eolinker/ap-account => ../../eolinker/ap-account +//replace github.com/eolinker/go-common => ../../eolinker/go-common diff --git a/go.sum b/go.sum index 3a935b8c..813d7dc4 100644 --- a/go.sum +++ b/go.sum @@ -23,12 +23,12 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eolinker/ap-account v1.0.6 h1:lzkmaItUoIguEKneUbP387qdgsUgjonKjHDnXsu6lTc= -github.com/eolinker/ap-account v1.0.6/go.mod h1:MViCOvUaS2QrVift1Be3yGjjMywzICL9317eOxoixSI= +github.com/eolinker/ap-account v1.0.9 h1:tW345b1wsn0V8pfMMlZOMfpbjxQhMWBVfgsClFTJGLk= +github.com/eolinker/ap-account v1.0.9/go.mod h1:5lsZwkQfnHO5YJ3Cu6X1PZwZ0gbmJBUcix0hxG8aEsY= github.com/eolinker/eosc v0.17.3 h1:sr2yT+v/AsqEdciRaaZZj0zL9pTufR5RvDW6+65hraQ= github.com/eolinker/eosc v0.17.3/go.mod h1:xgq816hpanlMXFtZw7Ztdctb1eEk9UPHchY4NfFO6Cw= -github.com/eolinker/go-common v1.0.1 h1:Uan6QmXAlPiX6hc1ptSIHWvaWXNA+VlBjC4gCaDEiz0= -github.com/eolinker/go-common v1.0.1/go.mod h1:Kb/jENMN1mApnodvRgV4YwO9FJby1Jkt2EUjrBjvSX4= +github.com/eolinker/go-common v1.0.4 h1:F0akjnzJfIFOVmK30fD0SsCLU7DAKPXuY21MeyMmQ7w= +github.com/eolinker/go-common v1.0.4/go.mod h1:Kb/jENMN1mApnodvRgV4YwO9FJby1Jkt2EUjrBjvSX4= github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= diff --git a/go_build_github_com_APIParkLab_APIPark b/go_build_github_com_APIParkLab_APIPark deleted file mode 100755 index fc90ab0b..00000000 Binary files a/go_build_github_com_APIParkLab_APIPark and /dev/null differ diff --git a/middleware/permit/identity/identity.go b/middleware/permit/identity/identity.go index ab11078d..3922c6eb 100644 --- a/middleware/permit/identity/identity.go +++ b/middleware/permit/identity/identity.go @@ -5,9 +5,8 @@ import ( ) const ( - SystemGroup = "system" - TeamGroup = "team" - ProjectGroup = "project" + SystemGroup = "system" + TeamGroup = "team" ) type IdentityTeamService interface { diff --git a/middleware/permit/permit.go b/middleware/permit/permit.go index a82574e9..41880740 100644 --- a/middleware/permit/permit.go +++ b/middleware/permit/permit.go @@ -51,6 +51,7 @@ func (p *PermitMiddleware) Check(method string, path string) (bool, []gin.Handle func(ginCtx *gin.Context) { userId := utils.UserId(ginCtx) if userId == "" { + // 未开启游客模式 ginCtx.AbortWithStatusJSON(http.StatusForbidden, gin.H{"code": http.StatusForbidden, "msg": "not login", "success": "fail"}) ginCtx.Abort() return @@ -67,6 +68,7 @@ func (p *PermitMiddleware) Check(method string, path string) (bool, []gin.Handle // 当前分组没有配置权限 continue } + domainHandler, has := permit.SelectDomain(group) if !has { // 当前分组没有配置身份handler diff --git a/module/catalogue/dto/output.go b/module/catalogue/dto/output.go index 309aa068..f3ca59b4 100644 --- a/module/catalogue/dto/output.go +++ b/module/catalogue/dto/output.go @@ -6,6 +6,7 @@ type Item struct { Id string `json:"id"` Name string `json:"name"` Children []*Item `json:"children"` + Sort int `json:"-"` } type ServiceItem struct { diff --git a/module/catalogue/iml.go b/module/catalogue/iml.go index 9e6be241..6a98f17c 100644 --- a/module/catalogue/iml.go +++ b/module/catalogue/iml.go @@ -347,9 +347,10 @@ func (i *imlCatalogueModule) Services(ctx context.Context, keyword string) ([]*c func (i *imlCatalogueModule) recurseUpdateSort(ctx context.Context, parent string, sorts []*catalogue_dto.SortItem) error { for index, item := range sorts { + s := index err := i.catalogueService.Save(ctx, item.Id, &catalogue.EditCatalogue{ Parent: &parent, - Sort: &index, + Sort: &s, }) if err != nil { return err @@ -488,8 +489,12 @@ func treeItems(parentId string, parentMap map[string][]*catalogue.Catalogue) []* Id: v.Id, Name: v.Name, Children: childItems, + Sort: v.Sort, }) } } + sort.Slice(items, func(i, j int) bool { + return items[i].Sort < items[j].Sort + }) return items } diff --git a/module/catalogue/tree.go b/module/catalogue/tree.go index ac25b6c8..bdf4a7f3 100644 --- a/module/catalogue/tree.go +++ b/module/catalogue/tree.go @@ -55,6 +55,7 @@ func NewRoot(list []*catalogue.Catalogue) *Root { Name: i.Name, Depth: 0, children: nil, + sort: i.Sort, } l = append(l, g) m[g.Uuid] = g @@ -137,7 +138,7 @@ func (g Groups) Less(i, j int) bool { } return g[i].sort < g[j].sort } - return g[i].Parent < g[i].Parent + return g[i].Parent < g[j].Parent } return g[i].Depth < g[j].Depth } diff --git a/module/dynamic-module/dynamic_module.go b/module/dynamic-module/dynamic_module.go index 8e678d79..80980baf 100644 --- a/module/dynamic-module/dynamic_module.go +++ b/module/dynamic-module/dynamic_module.go @@ -21,8 +21,8 @@ type IDynamicModuleModule interface { Render(ctx context.Context, module string) (map[string]interface{}, error) ModuleDrivers(ctx context.Context, group string) ([]*dynamic_module_dto.ModuleDriver, error) - Online(ctx context.Context, module string, id string, clusterInput *dynamic_module_dto.ClusterInput) error - Offline(ctx context.Context, module string, id string, clusterInput *dynamic_module_dto.ClusterInput) error + Online(ctx context.Context, module string, id string) error + Offline(ctx context.Context, module string, id string) error //PartitionStatuses(ctx context.Context, module string, keyword string, page int, pageSize int) (map[string]map[string]string, error) //PartitionStatus(ctx context.Context, module string, id string) (*dynamic_module_dto.OnlineInfo, error) } diff --git a/module/dynamic-module/iml.go b/module/dynamic-module/iml.go index 02e696e1..35eb60cf 100644 --- a/module/dynamic-module/iml.go +++ b/module/dynamic-module/iml.go @@ -42,7 +42,7 @@ func (i *imlDynamicModule) initGateway(ctx context.Context, clusterId string, cl return nil } -func (i *imlDynamicModule) Online(ctx context.Context, module string, id string, clusterInput *dynamic_module_dto.ClusterInput) error { +func (i *imlDynamicModule) Online(ctx context.Context, module string, id string) error { _, has := driver.Get(module) if !has { return fmt.Errorf("模块【%s】不存在", module) @@ -56,7 +56,7 @@ func (i *imlDynamicModule) Online(ctx context.Context, module string, id string, if err != nil { return fmt.Errorf("上线失败,配置不存在") } - clusters, err := i.clusterService.List(ctx, clusterInput.Clusters...) + clusters, err := i.clusterService.List(ctx) if err != nil || len(clusters) == 0 { return fmt.Errorf("上线失败,集群不存在") } @@ -102,28 +102,21 @@ func (i *imlDynamicModule) Online(ctx context.Context, module string, id string, }) } -func (i *imlDynamicModule) Offline(ctx context.Context, module string, id string, clusterInput *dynamic_module_dto.ClusterInput) error { +func (i *imlDynamicModule) Offline(ctx context.Context, module string, id string) error { _, has := driver.Get(module) if !has { return fmt.Errorf("模块【%s】不存在", module) } - //if len(clusterInput.Clusters) == 0 { - // return fmt.Errorf("下线分区失败,分区为空") - //} - return i.transaction.Transaction(ctx, func(ctx context.Context) error { id = strings.ToLower(fmt.Sprintf("%s_%s", id, module)) - if len(clusterInput.Clusters) == 0 { - clusters, err := i.clusterService.List(ctx) - if err != nil { - return err - } - clusterInput.Clusters = make([]string, 0) - for _, c := range clusters { - clusterInput.Clusters = append(clusterInput.Clusters, c.Uuid) - } + clusters, err := i.clusterService.List(ctx) + if err != nil { + return err } - for _, clusterId := range clusterInput.Clusters { + clusterIds := utils.SliceToSlice(clusters, func(s *cluster.Cluster) string { + return s.Uuid + }) + for _, clusterId := range clusterIds { err := i.dynamicClient(ctx, clusterId, module, func(dynamicClient gateway.IDynamicClient) error { return dynamicClient.Offline(ctx, &gateway.DynamicRelease{ BasicItem: &gateway.BasicItem{ diff --git a/module/my-team/dto/output.go b/module/my-team/dto/output.go index d5232631..fad66bc8 100644 --- a/module/my-team/dto/output.go +++ b/module/my-team/dto/output.go @@ -64,14 +64,16 @@ type Member struct { User auto.Label `json:"user" aolabel:"user"` Roles []auto.Label `json:"roles" aolabel:"role"` AttachTime auto.TimeLabel `json:"attach_time"` + IsDelete bool `json:"is_delete"` } -func ToMember(model *team_member.Member, roles ...string) *Member { - +func ToMember(model *team_member.Member, userId string, roles ...string) *Member { + return &Member{ User: auto.UUID(model.UID), Roles: auto.List(roles), AttachTime: auto.TimeLabel(model.CreateTime), + IsDelete: userId != model.UID, } } diff --git a/module/my-team/iml.go b/module/my-team/iml.go index 016866a5..31f818c5 100644 --- a/module/my-team/iml.go +++ b/module/my-team/iml.go @@ -4,21 +4,21 @@ import ( "context" "errors" "fmt" - + "github.com/eolinker/ap-account/service/role" - + "gorm.io/gorm" - + department_member "github.com/eolinker/ap-account/service/department-member" "github.com/eolinker/go-common/auto" - + "github.com/eolinker/ap-account/service/user" - + "github.com/eolinker/go-common/store" - + "github.com/APIParkLab/APIPark/service/service" team_member "github.com/APIParkLab/APIPark/service/team-member" - + team_dto "github.com/APIParkLab/APIPark/module/my-team/dto" "github.com/APIParkLab/APIPark/service/team" "github.com/eolinker/go-common/utils" @@ -39,15 +39,54 @@ type imlTeamModule struct { transaction store.ITransaction `autowired:""` } +func (m *imlTeamModule) SimpleTeams(ctx context.Context, keyword string) ([]*team_dto.SimpleTeam, error) { + teams, err := m.teamService.Search(ctx, keyword, nil) + if err != nil { + return nil, err + } + projects, err := m.serviceService.Search(ctx, "", nil) + projectCount := make(map[string]int64) + appCount := make(map[string]int64) + for _, p := range projects { + if p.AsServer { + if _, ok := projectCount[p.Team]; !ok { + projectCount[p.Team] = 0 + } + projectCount[p.Team]++ + } + if p.AsApp { + if _, ok := appCount[p.Team]; !ok { + appCount[p.Team] = 0 + } + appCount[p.Team]++ + } + } + + return utils.SliceToSlice(teams, func(s *team.Team) *team_dto.SimpleTeam { + return &team_dto.SimpleTeam{ + Id: s.Id, + Name: s.Name, + Description: s.Description, + ServiceNum: projectCount[s.Id], + AppNum: appCount[s.Id], + } + }), nil +} + func (m *imlTeamModule) UpdateMemberRole(ctx context.Context, id string, input *team_dto.UpdateMemberRole) error { _, err := m.teamService.Get(ctx, id) if err != nil { return err } + supperRole, err := m.roleService.GetSupperRole(ctx, role.GroupTeam) + if err != nil { + return err + } return m.transaction.Transaction(ctx, func(ctx context.Context) error { if len(input.Roles) < 1 { return errors.New("at least one role") } + err = m.roleMemberService.RemoveUserRole(ctx, role.TeamTarget(id), input.Users...) if err != nil { return err @@ -64,6 +103,14 @@ func (m *imlTeamModule) UpdateMemberRole(ctx context.Context, id string, input * } } } + + count, err := m.roleMemberService.CountByRole(ctx, role.TeamTarget(id), supperRole.Id) + if err != nil { + return err + } + if count < 1 { + return fmt.Errorf("role(%s) must have at least one member", supperRole.Name) + } return nil }) } @@ -73,7 +120,7 @@ func (m *imlTeamModule) GetTeam(ctx context.Context, id string) (*team_dto.Team, if err != nil { return nil, err } - + return &team_dto.Team{ Id: tv.Id, Name: tv.Name, @@ -109,7 +156,7 @@ func (m *imlTeamModule) Search(ctx context.Context, keyword string) ([]*team_dto if err != nil { return nil, err } - + outList := make([]*team_dto.Item, 0, len(list)) for _, v := range list { outList = append(outList, team_dto.ToItem(v, serviceNumMap[v.Id], appNumMap[v.Id])) @@ -137,14 +184,14 @@ func (m *imlTeamModule) Edit(ctx context.Context, id string, input *team_dto.Edi Description: input.Description, }) }) - + if err != nil { return nil, err } return m.GetTeam(ctx, id) } -func (m *imlTeamModule) SimpleTeams(ctx context.Context, keyword string) ([]*team_dto.SimpleTeam, error) { +func (m *imlTeamModule) MySimpleTeams(ctx context.Context, keyword string) ([]*team_dto.SimpleTeam, error) { userID := utils.UserId(ctx) memberMap, err := m.teamMemberService.FilterMembersForUser(ctx, userID) if err != nil { @@ -160,7 +207,7 @@ func (m *imlTeamModule) SimpleTeams(ctx context.Context, keyword string) ([]*tea if err != nil { return nil, err } - + projects, err := m.serviceService.Search(ctx, "", map[string]interface{}{ "team": teamIDs, }) @@ -180,7 +227,7 @@ func (m *imlTeamModule) SimpleTeams(ctx context.Context, keyword string) ([]*tea appCount[p.Team]++ } } - + outList := utils.SliceToSlice(list, func(s *team.Team) *team_dto.SimpleTeam { return &team_dto.SimpleTeam{ Id: s.Id, @@ -215,7 +262,7 @@ func (m *imlTeamModule) AddMember(ctx context.Context, id string, uuids ...strin } return nil }) - + } func (m *imlTeamModule) RemoveMember(ctx context.Context, id string, uuids ...string) error { @@ -223,7 +270,7 @@ func (m *imlTeamModule) RemoveMember(ctx context.Context, id string, uuids ...st if err != nil { return err } - + supperRole, err := m.roleService.GetSupperRole(ctx, role.GroupTeam) if err != nil { return err @@ -243,12 +290,12 @@ func (m *imlTeamModule) RemoveMember(ctx context.Context, id string, uuids ...st supperRoleCount++ } } - + if supperRoleCount == int(count) { return errors.New("can not delete all team admin") } } - + return m.transaction.Transaction(ctx, func(ctx context.Context) error { err = m.roleMemberService.RemoveUserRole(ctx, role.TeamTarget(id), uuids...) if err != nil { @@ -256,7 +303,7 @@ func (m *imlTeamModule) RemoveMember(ctx context.Context, id string, uuids ...st } return m.teamMemberService.RemoveMemberFrom(ctx, id, uuids...) }) - + } func (m *imlTeamModule) Members(ctx context.Context, id string, keyword string) ([]*team_dto.Member, error) { @@ -285,12 +332,12 @@ func (m *imlTeamModule) Members(ctx context.Context, id string, keyword string) roleMemberMap := utils.SliceToMapArrayO(roleMembers, func(r *role.Member) (string, string) { return r.User, r.Role }) - + uId := utils.UserId(ctx) out := make([]*team_dto.Member, 0, len(members)) for _, member := range members { - out = append(out, team_dto.ToMember(member, roleMemberMap[member.UID]...)) + out = append(out, team_dto.ToMember(member, uId, roleMemberMap[member.UID]...)) } - + return out, nil } @@ -330,20 +377,20 @@ func (m *imlTeamModule) SimpleMembers(ctx context.Context, id string, keyword st } departmentMemberMap[member.UID] = append(departmentMemberMap[member.UID], member.Come) } - + out := make([]*team_dto.SimpleMember, 0, len(teamMembers)) for _, member := range teamMembers { u, ok := userMap[member.UID] if !ok { continue } - + out = append(out, &team_dto.SimpleMember{ User: auto.UUID(u.UID), Mail: u.Email, Department: auto.List(departmentMemberMap[member.UID]), }) } - + return out, nil } diff --git a/module/my-team/team.go b/module/my-team/team.go index 59b302d8..f6079db9 100644 --- a/module/my-team/team.go +++ b/module/my-team/team.go @@ -3,9 +3,9 @@ package my_team import ( "context" "reflect" - + "github.com/eolinker/go-common/autowire" - + team_dto "github.com/APIParkLab/APIPark/module/my-team/dto" ) @@ -16,6 +16,8 @@ type ITeamModule interface { Search(ctx context.Context, keyword string) ([]*team_dto.Item, error) // Edit 编辑团队 Edit(ctx context.Context, id string, input *team_dto.EditTeam) (*team_dto.Team, error) + // MySimpleTeams 简易搜索团队 + MySimpleTeams(ctx context.Context, keyword string) ([]*team_dto.SimpleTeam, error) // SimpleTeams 简易搜索团队 SimpleTeams(ctx context.Context, keyword string) ([]*team_dto.SimpleTeam, error) // AddMember 添加团队成员 @@ -26,7 +28,7 @@ type ITeamModule interface { Members(ctx context.Context, id string, keyword string) ([]*team_dto.Member, error) // SimpleMembers 获取团队成员简易列表 SimpleMembers(ctx context.Context, id string, keyword string) ([]*team_dto.SimpleMember, error) - + // UpdateMemberRole 更新成员角色 UpdateMemberRole(ctx context.Context, id string, input *team_dto.UpdateMemberRole) error } diff --git a/module/permit/system/iml.go b/module/permit/system/iml.go index 2cd4d3c5..c7695dc4 100644 --- a/module/permit/system/iml.go +++ b/module/permit/system/iml.go @@ -2,7 +2,7 @@ package system import ( "context" - "errors" + "github.com/eolinker/go-common/access" "reflect" "github.com/gin-gonic/gin" @@ -25,10 +25,12 @@ type imlSystemPermitModule struct { } func (m *imlSystemPermitModule) accesses(ctx context.Context) ([]string, error) { - uid := utils.UserId(ctx) - if uid == "" { - return nil, errors.New("not login") + + // 判断是否是访客,如果是,直接返回访客权限 + if utils.GuestAllow() && utils.IsGuest(ctx) { + return access.GuestAccess(role.SystemTarget()), nil } + uid := utils.UserId(ctx) roleMembers, err := m.roleMemberService.List(ctx, role.SystemTarget(), uid) if err != nil { return nil, err diff --git a/module/permit/team/iml.go b/module/permit/team/iml.go index a624f804..f8d3e214 100644 --- a/module/permit/team/iml.go +++ b/module/permit/team/iml.go @@ -2,8 +2,7 @@ package team import ( "context" - "errors" - + "github.com/eolinker/go-common/access" "github.com/eolinker/go-common/permit" "github.com/gin-gonic/gin" @@ -25,31 +24,32 @@ type imlTeamPermitModule struct { func (m *imlTeamPermitModule) Permissions(ctx context.Context, teamId string) ([]string, error) { - uid := utils.UserId(ctx) - roleMembers, err := m.roleMemberService.List(ctx, role.TeamTarget(teamId), uid) - if err != nil { - return nil, err - } - roleIds := utils.SliceToSlice(roleMembers, func(rm *role.Member) string { - return rm.Role - }) - if len(roleMembers) == 0 { - return []string{}, nil - } - roles, err := m.roleService.List(ctx, roleIds...) - if err != nil { - return nil, err - } - permits := make(map[string]struct{}) - for _, r := range roles { - for _, p := range r.Permit { - permits[p] = struct{}{} - } - } - - return utils.MapToSlice(permits, func(k string, v struct{}) string { - return k - }), nil + //uid := utils.UserId(ctx) + //roleMembers, err := m.roleMemberService.List(ctx, role.TeamTarget(teamId), uid) + //if err != nil { + // return nil, err + //} + //roleIds := utils.SliceToSlice(roleMembers, func(rm *role.Member) string { + // return rm.Role + //}) + //if len(roleMembers) == 0 { + // return []string{}, nil + //} + //roles, err := m.roleService.List(ctx, roleIds...) + //if err != nil { + // return nil, err + //} + //permits := make(map[string]struct{}) + //for _, r := range roles { + // for _, p := range r.Permit { + // permits[p] = struct{}{} + // } + //} + // + //return utils.MapToSlice(permits, func(k string, v struct{}) string { + // return k + //}), nil + return m.accesses(ctx, teamId) } func (m *imlTeamPermitModule) OnComplete() { @@ -57,10 +57,12 @@ func (m *imlTeamPermitModule) OnComplete() { } func (m *imlTeamPermitModule) accesses(ctx context.Context, teamId string) ([]string, error) { - uid := utils.UserId(ctx) - if uid == "" { - return nil, errors.New("not login") + + // 判断是否是访客,如果是,直接返回访客权限 + if utils.GuestAllow() && utils.IsGuest(ctx) { + return access.GuestAccess(role.GroupTeam), nil } + uid := utils.UserId(ctx) roleMembers, err := m.roleMemberService.List(ctx, role.TeamTarget(teamId), uid) if err != nil { return nil, err diff --git a/module/subscribe/dto/input.go b/module/subscribe/dto/input.go index 56b4d6ad..0cde871a 100644 --- a/module/subscribe/dto/input.go +++ b/module/subscribe/dto/input.go @@ -2,7 +2,7 @@ package subscribe_dto type AddSubscriber struct { Application string `json:"application" aocheck:"service"` - Applier string `json:"applier" aocheck:"user"` + //Applier string `json:"applier" aocheck:"user"` //Cluster []string `json:"partition" aocheck:"partition"` } diff --git a/module/subscribe/iml.go b/module/subscribe/iml.go index afa6f1d4..115df2e1 100644 --- a/module/subscribe/iml.go +++ b/module/subscribe/iml.go @@ -3,25 +3,25 @@ package subscribe import ( "context" "fmt" - + "github.com/google/uuid" - + "github.com/eolinker/eosc/log" - + "github.com/APIParkLab/APIPark/gateway" - + "github.com/APIParkLab/APIPark/service/cluster" - + "github.com/eolinker/go-common/utils" - + "github.com/APIParkLab/APIPark/service/service" - + "github.com/eolinker/go-common/store" - + "github.com/eolinker/go-common/auto" - + "github.com/APIParkLab/APIPark/service/subscribe" - + subscribe_dto "github.com/APIParkLab/APIPark/module/subscribe/dto" ) @@ -52,7 +52,7 @@ func (i *imlSubscribeModule) getSubscribers(ctx context.Context, serviceIds []st } func (i *imlSubscribeModule) initGateway(ctx context.Context, clientDriver gateway.IClientDriver) error { - + projects, err := i.serviceService.List(ctx) if err != nil { return err @@ -64,7 +64,7 @@ func (i *imlSubscribeModule) initGateway(ctx context.Context, clientDriver gatew if err != nil { return err } - + return clientDriver.Subscribe().Online(ctx, releases...) } @@ -76,7 +76,7 @@ func (i *imlSubscribeModule) SearchSubscriptions(ctx context.Context, appId stri if !info.AsApp { return nil, fmt.Errorf("service %s is not an application", appId) } - + // 获取当前订阅服务列表 subscriptions, err := i.subscribeService.MySubscribeServices(ctx, appId, nil) if err != nil { @@ -92,7 +92,7 @@ func (i *imlSubscribeModule) SearchSubscriptions(ctx context.Context, appId stri serviceMap := utils.SliceToMapArray(services, func(s *service.Service) string { return s.Id }) - + return utils.SliceToSlice(subscriptions, func(s *subscribe.Subscribe) *subscribe_dto.SubscriptionItem { return &subscribe_dto.SubscriptionItem{ Id: s.Id, @@ -126,7 +126,7 @@ func (i *imlSubscribeModule) RevokeSubscription(ctx context.Context, pid string, if subscription.ApplyStatus != subscribe.ApplyStatusSubscribe { return fmt.Errorf("subscription can not be revoked") } - + clusters, err := i.clusterService.List(ctx) if err != nil { return err @@ -148,10 +148,10 @@ func (i *imlSubscribeModule) RevokeSubscription(ctx context.Context, pid string, return err } } - + return nil }) - + } func (i *imlSubscribeModule) DeleteSubscription(ctx context.Context, pid string, uuid string) error { @@ -192,7 +192,12 @@ func (i *imlSubscribeModule) AddSubscriber(ctx context.Context, serviceId string if err != nil { return err } - + _, err = i.subscribeService.GetByServiceAndApplication(ctx, serviceId, input.Application) + if err == nil { + // 订阅方已存在 + return fmt.Errorf("subscriber is already exists") + } + sub := &gateway.SubscribeRelease{ Service: serviceId, Application: input.Application, @@ -202,7 +207,7 @@ func (i *imlSubscribeModule) AddSubscriber(ctx context.Context, serviceId string if err != nil { return err } - + return i.transaction.Transaction(ctx, func(ctx context.Context) error { err = i.subscribeService.Create(ctx, &subscribe.CreateSubscribe{ Uuid: uuid.New().String(), @@ -210,7 +215,6 @@ func (i *imlSubscribeModule) AddSubscriber(ctx context.Context, serviceId string Application: input.Application, ApplyStatus: subscribe.ApplyStatusSubscribe, From: subscribe.FromUser, - Applier: input.Applier, }) if err != nil { return err @@ -221,14 +225,14 @@ func (i *imlSubscribeModule) AddSubscriber(ctx context.Context, serviceId string return fmt.Errorf("add subscriber for cluster[%s] %v", c.Uuid, err) } } - + return nil }) - + } func (i *imlSubscribeModule) onlineSubscriber(ctx context.Context, clusterId string, subscriber *gateway.SubscribeRelease) error { - + client, err := i.clusterService.GatewayClient(ctx, clusterId) if err != nil { return err @@ -237,7 +241,7 @@ func (i *imlSubscribeModule) onlineSubscriber(ctx context.Context, clusterId str _ = client.Close(ctx) }() return client.Subscribe().Online(ctx, subscriber) - + } func (i *imlSubscribeModule) DeleteSubscriber(ctx context.Context, service string, serviceId string, applicationId string) error { @@ -249,7 +253,7 @@ func (i *imlSubscribeModule) DeleteSubscriber(ctx context.Context, service strin if err != nil { return err } - + return i.transaction.Transaction(ctx, func(ctx context.Context) error { list, err := i.subscribeService.ListByApplication(ctx, serviceId, applicationId) if err != nil { @@ -275,7 +279,7 @@ func (i *imlSubscribeModule) DeleteSubscriber(ctx context.Context, service strin }) } func (i *imlSubscribeModule) offlineForCluster(ctx context.Context, clusterId string, config *gateway.SubscribeRelease) error { - + client, err := i.clusterService.GatewayClient(ctx, clusterId) if err != nil { return err @@ -291,13 +295,13 @@ func (i *imlSubscribeModule) SearchSubscribers(ctx context.Context, serviceId st if err != nil { return nil, err } - + // 获取当前项目所有订阅方 list, err := i.subscribeService.ListBySubscribeStatus(ctx, serviceId, subscribe.ApplyStatusSubscribe) if err != nil { return nil, err } - + if keyword == "" { items := make([]*subscribe_dto.Subscriber, 0, len(list)) for _, subscriber := range list { @@ -324,7 +328,7 @@ func (i *imlSubscribeModule) SearchSubscribers(ctx context.Context, serviceId st }) items := make([]*subscribe_dto.Subscriber, 0, len(list)) for _, subscriber := range list { - + if _, ok := serviceMap[subscriber.Service]; ok { items = append(items, &subscribe_dto.Subscriber{ Id: subscriber.Id, @@ -354,7 +358,7 @@ func (i *imlSubscribeApprovalModule) Pass(ctx context.Context, pid string, id st if err != nil { return err } - + return i.transaction.Transaction(ctx, func(ctx context.Context) error { userID := utils.UserId(ctx) status := subscribe.ApplyStatusSubscribe @@ -375,16 +379,16 @@ func (i *imlSubscribeApprovalModule) Pass(ctx context.Context, pid string, id st return err } for _, c := range cs { - + err := i.onlineSubscriber(ctx, c.Uuid, &gateway.SubscribeRelease{ Service: applyInfo.Service, Application: applyInfo.Application, Expired: "0", }) - + if err != nil { log.Warnf("online subscriber for cluster[%s] %v", c.Uuid, err) - + } } return nil @@ -405,7 +409,7 @@ func (i *imlSubscribeApprovalModule) Reject(ctx context.Context, pid string, id if err != nil { return err } - + return i.transaction.Transaction(ctx, func(ctx context.Context) error { userID := utils.UserId(ctx) status := subscribe.ApplyStatusRefuse @@ -460,7 +464,7 @@ func (i *imlSubscribeApprovalModule) GetApprovalDetail(ctx context.Context, pid if err != nil { return nil, err } - + return &subscribe_dto.Approval{ Id: item.Id, Service: auto.UUID(item.Service), diff --git a/plugins/core/core.go b/plugins/core/core.go index 55c97a16..647d14dd 100644 --- a/plugins/core/core.go +++ b/plugins/core/core.go @@ -2,33 +2,33 @@ package core import ( "net/http" - + plugin_cluster "github.com/APIParkLab/APIPark/controller/plugin-cluster" - + "github.com/APIParkLab/APIPark/controller/cluster" - + "github.com/eolinker/ap-account/controller/role" - + "github.com/APIParkLab/APIPark/controller/common" - + dynamic_module "github.com/APIParkLab/APIPark/controller/dynamic-module" - + "github.com/APIParkLab/APIPark/controller/release" - + application_authorization "github.com/APIParkLab/APIPark/controller/application-authorization" - + "github.com/APIParkLab/APIPark/controller/subscribe" - + "github.com/APIParkLab/APIPark/controller/api" - + "github.com/APIParkLab/APIPark/controller/upstream" - + "github.com/APIParkLab/APIPark/controller/service" - + "github.com/APIParkLab/APIPark/controller/catalogue" - + "github.com/APIParkLab/APIPark/controller/my_team" - + "github.com/APIParkLab/APIPark/controller/certificate" "github.com/APIParkLab/APIPark/controller/team_manager" "github.com/eolinker/go-common/autowire" @@ -47,7 +47,7 @@ func (d *Driver) Access() map[string][]string { } func (d *Driver) Create() (pm3.IPlugin, error) { - + p := new(plugin) autowire.Autowired(p) return p, nil @@ -76,7 +76,6 @@ type plugin struct { } func (p *plugin) OnComplete() { - p.apis = append(p.apis, p.partitionApi()...) p.apis = append(p.apis, p.certificateApi()...) p.apis = append(p.apis, p.clusterApi()...) p.apis = append(p.apis, p.TeamManagerApi()...) @@ -89,7 +88,7 @@ func (p *plugin) OnComplete() { p.apis = append(p.apis, p.projectAuthorizationApis()...) p.apis = append(p.apis, p.releaseApis()...) p.apis = append(p.apis, p.DynamicModuleApis()...) - + p.apis = append(p.apis, p.PartitionPluginApi()...) p.apis = append(p.apis, p.commonApis()...) } diff --git a/plugins/core/dynamic-module.go b/plugins/core/dynamic-module.go index a37cdadc..0c4e4305 100644 --- a/plugins/core/dynamic-module.go +++ b/plugins/core/dynamic-module.go @@ -2,7 +2,7 @@ package core import ( "net/http" - + "github.com/eolinker/go-common/pm3" ) @@ -15,7 +15,7 @@ func (p *plugin) DynamicModuleApis() []pm3.Api { pm3.CreateApiWidthDoc(http.MethodDelete, "/api/v1/dynamic/:name/batch", []string{"context", "rest:name", "query:ids"}, nil, p.dynamicModuleController.Delete), pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/dynamic/:name/render", []string{"context", "rest:name"}, []string{"basic", "render"}, p.dynamicModuleController.Render), pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/simple/dynamics/:group", []string{"context", "rest:group"}, []string{"dynamics"}, p.dynamicModuleController.ModuleDrivers), - pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/dynamic/:name/online", []string{"context", "rest:name", "query:id", "body"}, nil, p.dynamicModuleController.Online), - pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/dynamic/:name/offline", []string{"context", "rest:name", "query:id", "body"}, nil, p.dynamicModuleController.Offline), + pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/dynamic/:name/online", []string{"context", "rest:name", "query:id"}, nil, p.dynamicModuleController.Online), + pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/dynamic/:name/offline", []string{"context", "rest:name", "query:id"}, nil, p.dynamicModuleController.Offline), } } diff --git a/plugins/core/my-team.go b/plugins/core/my-team.go index a21ea05b..68ef6c4f 100644 --- a/plugins/core/my-team.go +++ b/plugins/core/my-team.go @@ -10,7 +10,8 @@ func (p *plugin) MyTeamApi() []pm3.Api { return []pm3.Api{ pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/team", []string{"context", "query:team"}, []string{"team"}, p.myTeamController.GetTeam), pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/teams", []string{"context", "query:keyword"}, []string{"teams"}, p.myTeamController.Search), - pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/simple/teams/mine", []string{"context", "query:keyword"}, []string{"teams"}, p.myTeamController.SimpleTeams), + pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/simple/teams/mine", []string{"context", "query:keyword"}, []string{"teams"}, p.myTeamController.MySimpleTeams), + pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/simple/teams", []string{"context", "query:keyword"}, []string{"teams"}, p.myTeamController.SimpleTeams), pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/team/members/simple", []string{"context", "query:team", "query:keyword"}, []string{"teams"}, p.myTeamController.SimpleMembers), pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/team", []string{"context", "query:team", "body"}, []string{"team"}, p.myTeamController.EditTeam), pm3.CreateApiWidthDoc(http.MethodPost, "/api/v1/team/member", []string{"context", "query:team", "body"}, nil, p.myTeamController.AddMember), diff --git a/plugins/core/partition.go b/plugins/core/partition.go deleted file mode 100644 index a1a663e8..00000000 --- a/plugins/core/partition.go +++ /dev/null @@ -1,17 +0,0 @@ -package core - -import ( - "github.com/eolinker/go-common/pm3" -) - -func (p *plugin) partitionApi() []pm3.Api { - return []pm3.Api{ - //pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/partitions", []string{"context", "query:keyword"}, []string{"partitions"}, p.partitionController.Search), - //pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/partition", []string{"context", "query:id"}, []string{"partition"}, p.partitionController.Info), - //pm3.CreateApiWidthDoc(http.MethodPost, "/api/v1/partition", []string{"context", "body"}, []string{"partition", "id", "update_time"}, p.partitionController.Create), - //pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/partition", []string{"context", "query:id", "body"}, []string{"partition"}, p.partitionController.Update), - //pm3.CreateApiWidthDoc(http.MethodDelete, "/api/v1/partition", []string{"context", "query:id"}, []string{"id"}, p.partitionController.Delete), - //pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/simple/partitions", []string{"context"}, []string{"partitions"}, p.partitionController.Simple), - //pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/simple/partitions/cluster", []string{"context"}, []string{"partitions"}, p.partitionController.SimpleWithCluster), - } -} diff --git a/resources/access/access.yaml b/resources/access/access.yaml index fbed5b8b..7085e997 100644 --- a/resources/access/access.yaml +++ b/resources/access/access.yaml @@ -10,6 +10,7 @@ system: - name: view cname: '查看' value: 'view' + guest_allow: true apis: - "GET:/api/v1/user/accounts" - "GET:/api/v1/user/departments" @@ -38,6 +39,7 @@ system: - name: view cname: '查看' value: 'view' + guest_allow: true apis: - "GET:/api/v1/manager/teams" - "GET:/api/v1/manager/team" @@ -56,12 +58,14 @@ system: children: - name: view system role cname: '查看系统角色' + guest_allow: true value: 'view_system_role' apis: - "GET:/api/v1/system/roles" - "GET:/api/v1/system/role" - name: view team role cname: '查看团队角色' + guest_allow: true value: 'view_team_role' apis: - "GET:/api/v1/team/roles" @@ -77,6 +81,7 @@ system: - name: view cname: '查看' value: 'view' + guest_allow: true # apis: # - "GET:/api/v1/catalogues" - name: manager @@ -100,6 +105,7 @@ system: - name: view cname: 查看 value: 'view' + guest_allow: true apis: - "GET:/api/v1/cluster/nodes" - name: manager @@ -115,6 +121,7 @@ system: - name: view cname: 查看 value: 'view' + guest_allow: true apis: - "GET:/api/v1/certificates" - "GET:/api/v1/certificate" @@ -133,6 +140,7 @@ system: - name: view cname: 查看 value: 'view' + guest_allow: true apis: - "GET:/api/v1/dynamic/{name}/info" - "GET:/api/v1/dynamic/{name}/list" @@ -157,6 +165,7 @@ system: - name: view all cname: 查看所有应用 value: 'view_all' + guest_allow: true apis: - "GET:/api/v1/apps" - name: service @@ -166,6 +175,7 @@ system: - name: view all cname: 查看所有服务 value: 'view_all' + guest_allow: true apis: - "GET:/api/v1/services" - name: team @@ -175,6 +185,7 @@ system: - name: view all cname: 查看所有团队 value: 'view_all' + guest_allow: true apis: - "GET:/api/v1/manager/teams" - name: api market @@ -184,6 +195,7 @@ system: - name: view cname: 查看 value: 'view' + guest_allow: true apis: - "GET:/api/v1/catalogue/services" - "GET:/api/v1/catalogue/service" @@ -199,6 +211,7 @@ team: - name: view cname: 查看 value: 'view' + guest_allow: true apis: - "GET:/api/v1/service/apis" - "GET:/api/v1/service/api/detail" @@ -220,6 +233,7 @@ team: - name: view cname: 查看 value: 'view' + guest_allow: true apis: - "GET:/api/v1/service/upstream" - name: manager @@ -234,6 +248,7 @@ team: - name: view cname: 查看 value: 'view' + guest_allow: true apis: - "GET:/api/v1/service/releases" - "GET:/api/v1/service/release" @@ -255,6 +270,7 @@ team: - name: view cname: 查看 value: 'view' + guest_allow: true apis: - "GET:/api/v1/service/approval/subscribes" - "GET:/api/v1/service/approval/subscribe" @@ -274,7 +290,6 @@ team: cname: 管理 value: 'manager' apis: - - "GET:/api/v1/service/info" - "PUT:/api/v1/service/info" - "POST:/api/v1/team/service" - "DELETE:/api/v1/team/service" @@ -289,6 +304,7 @@ team: - name: view cname: 查看 value: 'view' + guest_allow: true apis: - "GET:/api/v1/application/subscriptions" - name: manager @@ -305,6 +321,7 @@ team: - name: view cname: 查看 value: 'view' + guest_allow: true apis: - "GET:/api/v1/app/authorization" - "GET:/api/v1/app/authorizations" @@ -324,7 +341,6 @@ team: cname: 管理 value: 'manager' apis: - - "GET:/api/v1/app/info" - "PUT:/api/v1/app/info" - "POST:/api/v1/team/app" - "DELETE:/api/v1/app" @@ -339,6 +355,7 @@ team: - name: view cname: 查看 value: 'view' + guest_allow: true apis: - "GET:/api/v1/team/members" - "GET:/api/v1/team/members/toadd" @@ -356,6 +373,7 @@ team: - name: view cname: '查看' value: 'view' + guest_allow: true apis: - "GET:/api/v1/manager/teams" - "GET:/api/v1/manager/team" diff --git a/resources/access/role.yaml b/resources/access/role.yaml index 05d8898d..f4e7233d 100644 --- a/resources/access/role.yaml +++ b/resources/access/role.yaml @@ -51,6 +51,21 @@ system: permits: - system.workspace.api_market.view default: true + - name: guest + cname: 只读成员 + permits: + - system.api_market.service_classification.view + - system.devops.cluster.view + - system.devops.log_configuration.view + - system.devops.ssl_certificate.view + - system.organization.member.view + - system.organization.role.view_system_role + - system.organization.role.view_team_role + - system.organization.team.view + - system.workspace.api_market.view + - system.workspace.application.view_all + - system.workspace.service.view_all + - system.workspace.team.view_all team: - name: team_admin cname: 团队管理员 @@ -113,4 +128,15 @@ team: - team.application.subscription.manager - team.application.subscription.view - team.team.member.view - default: true \ No newline at end of file + default: true + - name: guest + cname: 只读成员 + permits: + - team.application.authorization.view + - team.application.subscription.view + - team.service.api.view + - team.service.release.view + - team.service.subscription.view + - team.service.upstream.view + - team.team.member.view + - team.team.team.view \ No newline at end of file diff --git a/scripts/docker_build.sh b/scripts/docker_build.sh new file mode 100755 index 00000000..2a43ba84 --- /dev/null +++ b/scripts/docker_build.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +set -e + +cd "$(dirname "$0")/../" +LOCAL_PATH=$(pwd) +ARCH=$1 +User=$2 +BuildMode=$3 +if [[ "${BuildMode}" == "" ]];then + BuildMode="all" +fi +# 编译可执行文件 +./scripts/build.sh "cmd" "" "${BuildMode}" ${ARCH} + +source ./scripts/common.sh +APP="apipark" + + +mkdir -p scripts/cmd/ && cp cmd/${APP} scripts/cmd/ + +VERSION=$(gen_version) + + +if [[ "${ARCH}" == "" ]];then + ARCH="amd64" +fi + +OPTIONS="" +if [[ "${ARCH}" == "arm" ]];then + OPTIONS="--platform=linux/arm64" +fi + +if [[ "${User}" == "" ]];then + User="eolinker" +fi + +imageName=${User}/${APP}:${VERSION}-${ARCH} +docker rmi -f ${imageName} + +echo "docker build ${OPTIONS} -t ${imageName} --build-arg VERSION=${VERSION} --build-arg APP=${APP} -f ./scripts/Dockerfile ./scripts/" +docker build ${OPTIONS} -t ${imageName} --build-arg VERSION=${VERSION} --build-arg APP=${APP} -f ./scripts/Dockerfile ./scripts/ + + diff --git a/scripts/docker_publish.sh b/scripts/docker_publish.sh new file mode 100755 index 00000000..c899b178 --- /dev/null +++ b/scripts/docker_publish.sh @@ -0,0 +1,48 @@ +#!/bin/bash + + + +cd "$(dirname "$0")/../" +LOCAL_PATH=$(pwd) + +source ./scripts/common.sh + +User=$1 +App="apipark" +if [[ "${User}" == "" ]];then + User="eolinker" +fi +BuildMode=$2 +if [[ "${BuildMode}" == "" ]];then + BuildMode="all" +fi +Version=$(gen_version) +ImageName="${User}/${App}" +echo "docker manifest rm \"${ImageName}:${Version}\"" +docker manifest rm "${ImageName}:${Version}" + +set -e +./scripts/docker_build.sh amd64 ${User} "${BuildMode}" + +./scripts/docker_build.sh arm64 ${User} "${BuildMode}" + + + +echo "docker push \"${ImageName}:${Version}-amd64\"" +docker push "${ImageName}:${Version}-amd64" +echo "docker push \"${ImageName}:${Version}-arm64\"" +docker push "${ImageName}:${Version}-arm64" + +echo "Create manifest ${ImageName}:${Version}" +docker manifest create "${ImageName}:${Version}" "${ImageName}:${Version}-amd64" "${ImageName}:${Version}-arm64" + +echo "Annotate manifest ${ImageName}:${Version} ${ImageName}:${Version}-amd64 --os linux --arch amd64" +docker manifest annotate "${ImageName}:${Version}" "${ImageName}:${Version}-amd64" --os linux --arch amd64 + +echo "Annotate manifest ${ImageName}:${Version} ${ImageName}:${Version}-arm64 --os linux --arch arm64" +docker manifest annotate "${ImageName}:${Version}" "${ImageName}:${Version}-arm64" --os linux --arch arm64 + +echo "Push manifest ${ImageName}:${Version}" +docker manifest push "${ImageName}:${Version}" + + diff --git a/service/subscribe/iml.go b/service/subscribe/iml.go index 1d6cd329..9d18f562 100644 --- a/service/subscribe/iml.go +++ b/service/subscribe/iml.go @@ -3,9 +3,9 @@ package subscribe import ( "context" "time" - + "github.com/eolinker/go-common/utils" - + "github.com/APIParkLab/APIPark/service/universally" "github.com/APIParkLab/APIPark/stores/subscribe" ) @@ -42,12 +42,20 @@ type imlSubscribeService struct { universally.IServiceEdit[UpdateSubscribe] } +func (i *imlSubscribeService) GetByServiceAndApplication(ctx context.Context, serviceId string, applicationId string) (*Subscribe, error) { + info, err := i.store.First(ctx, map[string]interface{}{"service": serviceId, "application": applicationId}) + if err != nil { + return nil, err + } + return FromEntity(info), nil +} + func (i *imlSubscribeService) CountMapByService(ctx context.Context, status int, service ...string) (map[string]int64, error) { w := make(map[string]interface{}) if len(service) > 0 { w["service"] = service } - + w["apply_status"] = status return i.store.CountByGroup(ctx, "", w, "service") } @@ -69,7 +77,7 @@ func (i *imlSubscribeService) SubscriptionsByApplication(ctx context.Context, ap if len(applicationIds) > 0 { w["application"] = applicationIds } - + //w["apply_status"] = ApplyStatusSubscribe list, err := i.store.List(ctx, w, "create_at desc") if err != nil { @@ -88,7 +96,7 @@ func (i *imlSubscribeService) SubscribersByProject(ctx context.Context, serviceI if len(serviceIds) > 0 { w["service"] = serviceIds } - + w["apply_status"] = ApplyStatusSubscribe list, err := i.store.List(ctx, w, "create_at desc") if err != nil { @@ -131,7 +139,7 @@ func (i *imlSubscribeService) UpdateSubscribeStatus(ctx context.Context, applica func (i *imlSubscribeService) MySubscribeServices(ctx context.Context, application string, serviceIDs []string) ([]*Subscribe, error) { w := make(map[string]interface{}) - + if len(serviceIDs) > 0 { w["service"] = serviceIDs } @@ -194,7 +202,7 @@ func (i *imlSubscribeService) updateHandler(e *subscribe.Subscribe, t *UpdateSub if t.ApplyStatus != nil { e.ApplyStatus = *t.ApplyStatus } - + //if t.ApplyID != nil { // e.ApplyID = *t.ApplyID //} @@ -295,5 +303,5 @@ func (i *imlSubscribeApplyService) updateHandler(e *subscribe.Apply, t *EditAppl e.Applier = *t.Applier e.ApplyAt = time.Now() } - + } diff --git a/service/subscribe/service.go b/service/subscribe/service.go index 5aec3017..6cc0f903 100644 --- a/service/subscribe/service.go +++ b/service/subscribe/service.go @@ -3,7 +3,7 @@ package subscribe import ( "context" "reflect" - + "github.com/APIParkLab/APIPark/service/universally" "github.com/eolinker/go-common/autowire" ) @@ -17,7 +17,8 @@ type ISubscribeService interface { DeleteByApplication(ctx context.Context, service string, application string) error ListByApplication(ctx context.Context, service string, application ...string) ([]*Subscribe, error) ListByServices(ctx context.Context, serviceIds ...string) ([]*Subscribe, error) - + GetByServiceAndApplication(ctx context.Context, serviceId string, applicationId string) (*Subscribe, error) + MySubscribeServices(ctx context.Context, application string, serviceIDs []string) ([]*Subscribe, error) UpdateSubscribeStatus(ctx context.Context, application string, service string, status int) error ListBySubscribeStatus(ctx context.Context, projectId string, status int) ([]*Subscribe, error) @@ -41,7 +42,7 @@ func init() { autowire.Auto[ISubscribeService](func() reflect.Value { return reflect.ValueOf(new(imlSubscribeService)) }) - + autowire.Auto[ISubscribeApplyService](func() reflect.Value { return reflect.ValueOf(new(imlSubscribeApplyService)) })