From febb64b8bbad408e20abc23072353755e8c268cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A2=A6=E6=B4=81?= Date: Wed, 27 Nov 2024 18:21:43 +0800 Subject: [PATCH] fix: data-masking bugs --- .../src/components/aoplatform/InsidePage.tsx | 10 +- .../packages/common/src/const/permissions.ts | 50 +++++ .../common/src/const/permissions.yaml | 204 ------------------ .../packages/common/src/const/policy/type.ts | 12 +- .../src/contexts/GlobalStateContext.tsx | 18 +- .../components/aoplatform/RenderRoutes.tsx | 13 +- frontend/packages/core/src/const/const.tsx | 58 ++++- frontend/packages/core/src/pages/Login.tsx | 13 +- frontend/packages/core/src/pages/Root.tsx | 14 ++ .../core/src/pages/member/MemberPage.tsx | 4 +- .../core/src/pages/policy/FilterForm.tsx | 49 +++-- .../core/src/pages/policy/FilterTable.tsx | 31 +-- .../src/pages/policy/ServicePolicyLayout.tsx | 15 ++ .../pages/policy/dataMasking/DataMasking.tsx | 83 +++++-- .../policy/dataMasking/DataMaskingColumn.tsx | 2 +- .../policy/dataMasking/DataMaskingConfig.tsx | 26 ++- .../dataMasking/DataMaskingRuleForm.tsx | 4 +- .../core/src/pages/policy/globalPolicy.tsx | 6 +- .../core/src/pages/policy/servicePolicy.tsx | 6 +- .../src/pages/system/SystemInsidePage.tsx | 4 +- .../packages/dashboard/src/const/const.tsx | 2 +- 21 files changed, 315 insertions(+), 309 deletions(-) delete mode 100644 frontend/packages/common/src/const/permissions.yaml create mode 100644 frontend/packages/core/src/pages/Root.tsx create mode 100644 frontend/packages/core/src/pages/policy/ServicePolicyLayout.tsx diff --git a/frontend/packages/common/src/components/aoplatform/InsidePage.tsx b/frontend/packages/common/src/components/aoplatform/InsidePage.tsx index dc97b7fc..696fcee4 100644 --- a/frontend/packages/common/src/components/aoplatform/InsidePage.tsx +++ b/frontend/packages/common/src/components/aoplatform/InsidePage.tsx @@ -37,13 +37,13 @@ const InsidePage:FC = ({showBanner=true,pageTitle,tagList,showB //
{ showBanner &&
-
+ {!pageTitle && !description && !backUrl &&!customBtn ? <>:
{backUrl &&
}
-

{pageTitle}

+
{pageTitle}
{tagList && tagList?.length > 0 && tagList?.map((tag)=>{ return ( {tag.label}) })} @@ -53,10 +53,10 @@ const InsidePage:FC = ({showBanner=true,pageTitle,tagList,showB }}>{btnTitle}} {customBtn}
-

+

{description} -

-
+
+
}
}
{children}
diff --git a/frontend/packages/common/src/const/permissions.ts b/frontend/packages/common/src/const/permissions.ts index a8121a7d..f1e6f43c 100644 --- a/frontend/packages/common/src/const/permissions.ts +++ b/frontend/packages/common/src/const/permissions.ts @@ -239,6 +239,31 @@ export const PERMISSION_DEFINITION = [ "anyOf": [{ "backend": ["system.settings.log_configuration.manager"] }] } }, + "system.devops.policy.view": { + "granted": { + "anyOf": [{ "backend": ["system.settings.strategy.view"] }] + } + }, + "system.devops.policy.add": { + "granted": { + "anyOf": [{ "backend": ["system.settings.strategy.manager"] }] + } + }, + "system.devops.policy.edit": { + "granted": { + "anyOf": [{ "backend": ["system.settings.strategy.manager"] }] + } + }, + "system.devops.policy.publish": { + "granted": { + "anyOf": [{ "backend": ["system.settings.strategy.manager"] }] + } + }, + "system.devops.policy.delete": { + "granted": { + "anyOf": [{ "backend": ["system.settings.strategy.manager"] }] + } + }, "system.workspace.application.view_all": { "granted": { "anyOf": [{ "backend": ["system.workspace.application.view_all"] }] @@ -429,6 +454,31 @@ export const PERMISSION_DEFINITION = [ "anyOf": [{ "backend": ["system.workspace.service.manager_all","team.team.service.manager","team.service.service.manager"] }] } }, + "team.service.policy.view": { + "granted": { + "anyOf": [{ "backend": ["team.service.strategy.view"] }] + } + }, + "team.service.policy.add": { + "granted": { + "anyOf": [{ "backend": ["team.service.strategy.manager"] }] + } + }, + "team.service.policy.edit": { + "granted": { + "anyOf": [{ "backend": ["team.service.strategy.manager"] }] + } + }, + "team.service.policy.publish": { + "granted": { + "anyOf": [{ "backend": ["team.service.strategy.manager"] }] + } + }, + "team.service.policy.delete": { + "granted": { + "anyOf": [{ "backend": ["team.service.strategy.manager"] }] + } + }, "team.application.subscription.view": { "granted": { "anyOf": [{ "backend": ["system.workspace.application.view_all","team.consumer.subscription.view_subscribed_service"] }] diff --git a/frontend/packages/common/src/const/permissions.yaml b/frontend/packages/common/src/const/permissions.yaml deleted file mode 100644 index f81d25ca..00000000 --- a/frontend/packages/common/src/const/permissions.yaml +++ /dev/null @@ -1,204 +0,0 @@ -system: - - name: organization - cname: '组织管理' - value: 'organization' - children: - - name: member - cname: '成员' - value: 'member' - access: - - system.settings.account.view - - system.organization.member.add - - system.organization.member.edit - - system.organization.member.delete - - system.organization.member.block - - system.organization.member.department.add - - system.organization.member.department.edit - - system.organization.member.department.delete - - name: team_manager - cname: '团队管理' - desc: '团队管理' - - system.workspace.team.view_all - - system.organization.team.add - - system.organization.team.edit - - system.organization.team.delete - - system.organization.team.running - - name: role_manager - cname: '角色管理' - desc: '角色管理' - - system.organization.role.view - - system.organization.role.system.view - - system.organization.role.system.add - - system.organization.role.system.edit - - system.organization.role.system.delete - - system.organization.role.team.view - - system.organization.role.team.add - - system.organization.role.team.edit - - system.organization.role.team.delete - - name: API Market - cname: 'API市场' - value: 'api_market' - children: - - name: service classification - cname: '服务分类' - value: 'service_classification' - children: - - system.api_market.service_classification.view - - system.api_market.service_classification.add - - system.api_market.service_classification.edit - - system.api_market.service_classification.delete - - name: devops - cname: 运维 - value: 'devops' - children: - - name: cluster - cname: 集群 - value: 'cluster' - children: - - system.settings.api_gateway.view - - system.devops.cluster.add - - system.devops.cluster.edit - - system.devops.cluster.delete - - name: ssl certificate - cname: 证书 - value: 'ssl_certificate' - children: - - system.settings.ssl_certificate.view - - system.devops.ssl_certificate.add - - system.devops.ssl_certificate.edit - - system.devops.ssl_certificate.delete - - name: log configuration - cname: 日志 - value: 'log_configuration' - children: - - system.settings.log_configuration.view - - system.devops.log_configuration.add - - system.devops.log_configuration.edit - - system.devops.log_configuration.publish - - system.devops.log_configuration.delete - - name: workspace - cname: 工作空间 - value: 'workspace' - children: - - name: application - cname: 应用 - value: 'application' - children: - - system.workspace.application.view_all - - name: service - cname: 服务 - value: 'service' - children: - - system.workspace.service.view_all - - name: team - cname: 团队 - value: 'team' - children: - - system.workspace.team.view_all - - name: api market - cname: API市场 - value: 'api_market' - children: - - system.api_portal.api_portal.view -team: - - name: service - cname: 服务 - value: 'service' - children: - - name: api - cname: API - value: 'api' - children: - - team.service.api_doc.view - - team.service.api_doc.add - - team.service.api_doc.edit - - name: route - cname: route - value: 'route' - children: - - team.service.router.view - - team.service.router.add - - team.service.router.edit - - team.service.router.delete - - name: upstream - cname: 上游 - value: 'upstream' - children: - - team.service.upstream.view - - team.service.upstream.add - - team.service.upstream.edit - - team.service.upstream.delete - - name: release - cname: 发布 - value: 'release' - children: - - team.service.release.view - - team.service.release.add - - team.service.release.rollback - - team.service.release.delete - - team.service.release.approval - - team.service.release.online - - team.service.release.cancel - - team.service.release.stop - - name: subscription management - cname: 订阅方管理 - value: 'subscription' - children: - - team.service.subscription.view - - team.service.subscription.approval - - team.service.subscription.add - - team.service.subscription.delete - - name: service - cname: 服务管理 - value: 'service' - children: - - team.service.service.view - - team.service.service.add - - team.service.service.edit - - team.service.service.delete - - name: application - cname: 应用 - value: 'application' - children: - - name: subscription Service - cname: 订阅服务 - value: 'subscription' - children: - - team.application.subscription.view - - team.application.subscription.add - - team.application.subscription.edit - - team.application.subscription.delete - - name: authorization - cname: 访问授权 - value: 'authorization' - children: - - team.consumer.authorization.view - - team.consumer.authorization.manager - - team.application.authorization.add - - team.application.authorization.edit - - team.application.authorization.delete - - name: application - cname: 应用 - value: 'application' - children: - - team.application.application.view - - team.application.application.add - - team.application.application.edit - - team.application.application.delete - - name: team - cname: 团队 - value: 'team' - children: - - name: member - cname: 成员 - value: 'member' - children: - - team.team.member.view - - team.team.member.add - - team.team.member.edit - - name: team - cname: 团队管理 - value: 'team' - children: - - team.team.team.view - - team.team.team.edit diff --git a/frontend/packages/common/src/const/policy/type.ts b/frontend/packages/common/src/const/policy/type.ts index f91403aa..084d5f90 100644 --- a/frontend/packages/common/src/const/policy/type.ts +++ b/frontend/packages/common/src/const/policy/type.ts @@ -1,5 +1,6 @@ import { DefaultOptionType } from "antd/es/select"; import { StrategyStatusEnum } from "./consts"; +import { EntityItem } from "../type"; export type DataMaskRuleTableProps = { disabled?: boolean; @@ -58,18 +59,18 @@ export type DataMaskStrategyItem = { name:string priority:number isStop:boolean - isDeleted:boolean + isDelete:boolean publishStatus:keyof typeof StrategyStatusEnum filters:string conf:string - operator:string + updater:EntityItem updateTime:string } export type FilterFormField= { name: string; - value:string[] |string; + values:string[] |string; label:string title:string } @@ -92,7 +93,8 @@ export type FilterFormField= { export type FilterFormType = { name:string - value:unknown + values:unknown + type?:string } export type FilterFormProps = { @@ -102,6 +104,7 @@ export type FilterFormType = { disabled: boolean; onFilterFormChange: (form: FilterFormType) => void; setFormCanSubmit:(canSubmit:boolean)=>void + serviceId?:string } export type FilterFormHandle = { @@ -115,6 +118,7 @@ export type FilterFormType = { disabled:boolean option:unknown onShowValueChange?:(value:string)=>void + serviceId?:string } export type RemoteTitleType = { diff --git a/frontend/packages/common/src/contexts/GlobalStateContext.tsx b/frontend/packages/common/src/contexts/GlobalStateContext.tsx index 8fa8215e..f370b316 100644 --- a/frontend/packages/common/src/contexts/GlobalStateContext.tsx +++ b/frontend/packages/common/src/contexts/GlobalStateContext.tsx @@ -12,7 +12,7 @@ import { RouteConfig } from "@common/const/type"; import { ProtectedRoute } from "@core/components/aoplatform/RenderRoutes"; import Login from "@core/pages/Login"; import { useLocaleContext } from "./LocaleContext"; - +import Root from "@core/pages/Root" interface GlobalState { isAuthenticated: boolean; userData: UserData | null; @@ -21,6 +21,7 @@ interface GlobalState { powered:string; mainPage:string; language:string; + pluginsLoaded:boolean } interface UserData { @@ -36,6 +37,7 @@ export type GlobalAction = | { type: 'UPDATE_POWER'; powered: string } | { type: 'UPDATE_MAIN_PAGE'; mainPage: string } | { type: 'UPDATE_LANGUAGE'; language: string } + | { type: 'SET_PLUGINS_LOADED'; pluginsLoaded: boolean } const mockData = [ @@ -230,11 +232,13 @@ export const GlobalContext = createContext<{ const globalReducer = (state: GlobalState, action: GlobalAction): GlobalState => { switch (action.type) { case 'LOGIN': + console.log('login') return { ...state, isAuthenticated: true, }; case 'LOGOUT': + console.log('login') return { ...state, isAuthenticated: false, @@ -270,6 +274,11 @@ const globalReducer = (state: GlobalState, action: GlobalAction): GlobalState => ...state, language: action.language, }; + case 'SET_PLUGINS_LOADED': + return { + ...state, + pluginsLoaded: action.pluginsLoaded, + }; default: return state; } @@ -277,7 +286,7 @@ const globalReducer = (state: GlobalState, action: GlobalAction): GlobalState => export const DefaultRouteConfig = [ - { path: '/', pathMatch: 'full', component: ,key:'root',}, + { path: '/', pathMatch: 'full', component: ,key:'root',}, { path: '/login', component: ,key:'login'}, { path: '/', pathMatch:'prefix',component: ,key:'basciLayout',children:[ { path: '*', component: , key: 'errorBoundary' } @@ -288,13 +297,14 @@ export const GlobalProvider: FC<{children:ReactNode}> = ({ children }) => { const { message } = App.useApp() const { setLocale } = useLocaleContext(); const [state, dispatch] = useReducer(globalReducer, { - isAuthenticated: true, //mock用 + isAuthenticated: false, //mock用 userData: null, version: '1.0.0', updateDate: '2024-07-01', powered:'Powered by https://apipark.com', mainPage:'/guide/page', - language:'en-US' + language:'en-US', + pluginsLoaded:false }); const [accessData,setAccessData] = useState>(new Map()) const [pluginAccessDictionary, setPluginAccessDictionary] = useState<{[k:string]:string}>({}) diff --git a/frontend/packages/core/src/components/aoplatform/RenderRoutes.tsx b/frontend/packages/core/src/components/aoplatform/RenderRoutes.tsx index 29ae48b1..9f66e989 100644 --- a/frontend/packages/core/src/components/aoplatform/RenderRoutes.tsx +++ b/frontend/packages/core/src/components/aoplatform/RenderRoutes.tsx @@ -15,7 +15,7 @@ import { LoadingOutlined } from '@ant-design/icons'; const RenderRoutes = ()=> { const { loadPlugins,loadExecutedPlugin } = usePluginLoader(ApiparkPluginDriver(routerMap), routerMap) - const { routeConfig } = useGlobalContext(); + const { routeConfig,dispatch,state } = useGlobalContext(); const [router, setRouter] = useState(null); useEffect(()=>{ @@ -28,10 +28,11 @@ const RenderRoutes = ()=> { if (routeConfig && routeConfig.length > 0) { const routerInstance = createBrowserRouter(generateRoutes(routeConfig)); setRouter(routerInstance); + dispatch({ type: 'SET_PLUGINS_LOADED', pluginsLoaded: true }); } }, [routeConfig]); - if (!router) { + if (!router || !state?.pluginsLoaded) { return } spinning={true} className='w-full h-full flex items-center justify-center'>; } @@ -77,7 +78,9 @@ const generateRoutes = (routerConfig: RouteConfig[]):RouteObject[] => { { path: route.path, element: {routeElement} , - children: route.children ? generateRoutes(route.children as RouteConfig[]) : undefined,} + children: route.children ? generateRoutes(route.children as RouteConfig[]) : undefined, + exact:route?.pathMatch === 'full' + } ); } ) @@ -85,8 +88,8 @@ const generateRoutes = (routerConfig: RouteConfig[]):RouteObject[] => { // 保护的路由组件 export function ProtectedRoute() { - const {state} = useGlobalContext() - return state.isAuthenticated? : ; + // return state.isAuthenticated? : ; + return } export default RenderRoutes diff --git a/frontend/packages/core/src/const/const.tsx b/frontend/packages/core/src/const/const.tsx index 5428b72a..bf4b7923 100644 --- a/frontend/packages/core/src/const/const.tsx +++ b/frontend/packages/core/src/const/const.tsx @@ -1,3 +1,4 @@ +import component from '@common/components/aoplatform/prompt-editor/plugins/workflow-variable-block/component'; import { RouterMapConfig } from '@common/const/type'; import { ProtectedRoute } from '@core/components/aoplatform/RenderRoutes'; import { AiServiceProvider } from '@core/contexts/AiServiceContext'; @@ -6,6 +7,7 @@ import { TeamProvider } from '@core/contexts/TeamContext'; import AiServiceOutlet from '@core/pages/aiService/AiServiceOutlet'; import Guide from '@core/pages/guide/Guide'; import Login from '@core/pages/Login'; +import ServicePolicyLayout from '@core/pages/policy/ServicePolicyLayout'; import SystemOutlet from '@core/pages/system/SystemOutlet'; import { TenantManagementProvider } from '@market/contexts/TenantManagementContext'; import { lazy } from 'react'; @@ -171,10 +173,29 @@ import { Outlet, Navigate } from 'react-router-dom'; }, { path:'servicepolicy', - key: 'servicePolicy', - lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/servicePolicy')), - children:[ - + key: 'servicepolicy', + component:, + children:[{ + path:'datamasking', + component:, + key:'dataMasking', + children:[ + { + path:'list', + lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/servicePolicy')), + key:'dataMaskingList' + }, + { + path:'create', + lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/dataMasking/DataMaskingConfig')), + key:'dataMaskingAdd' + }, + { + path:':policyId', + lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/dataMasking/DataMaskingConfig')), + key:'dataMaskingAdd' + }] + } ] }, ] @@ -265,11 +286,30 @@ import { Outlet, Navigate } from 'react-router-dom'; }, { path:'servicepolicy', - key: 'servicePolicy', - lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/servicePolicy')), - children:[ - - ] + key: 'servicepolicy', + component:, + children:[{ + path:'datamasking', + component:, + key:'dataMasking', + children:[ + { + path:'list', + lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/servicePolicy')), + key:'dataMaskingList' + }, + { + path:'create', + lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/dataMasking/DataMaskingConfig')), + key:'dataMaskingAdd' + }, + { + path:':policyId', + lazy:lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/policy/dataMasking/DataMaskingConfig')), + key:'dataMaskingAdd' + }] + } + ] }, ] } diff --git a/frontend/packages/core/src/pages/Login.tsx b/frontend/packages/core/src/pages/Login.tsx index 120b28f2..83c834ae 100644 --- a/frontend/packages/core/src/pages/Login.tsx +++ b/frontend/packages/core/src/pages/Login.tsx @@ -1,5 +1,5 @@ import {FC, useCallback, useEffect, useRef, useState} from "react"; -import {App, Button, Divider, Form, FormInstance, Input, Tooltip} from "antd"; +import {App, Button, Divider, Form, FormInstance, Input, Spin, Tooltip} from "antd"; import {useGlobalContext} from "@common/contexts/GlobalStateContext.tsx"; import {useFetch} from "@common/hooks/http.ts"; import {BasicResponse, STATUS_CODE} from "@common/const/const.tsx"; @@ -9,6 +9,7 @@ import Logo from '@common/assets/layout-logo.png' import { $t } from "@common/locales"; import { Icon } from "@iconify/react/dist/iconify.js"; import LanguageSetting from "@common/components/aoplatform/LanguageSetting"; +import { LoadingOutlined } from "@ant-design/icons"; const Login:FC = ()=> { const {state, dispatch} = useGlobalContext() @@ -17,20 +18,21 @@ const Login:FC = ()=> { const navigate = useNavigate(); const formRef = useRef(null); const [loading,setLoading] = useState() - // const { encryptByEnAES } = useCrypto(); const [allowGuest, setAllowGuest] = useState(false) + const [spinning,setSpinning] = useState(false) const check = useCallback(()=>{ + state.isAuthenticated &&setSpinning(true) fetchData, status:string}>>('account/login',{method:'GET'}).then(response=>{ const {code,data} = response - if(code === STATUS_CODE.SUCCESS && data.status !== 'anonymous'){ dispatch({type:'LOGIN'}) - navigate(state.mainPage) + navigate(state.mainPage,{replace:true}) }else{ dispatch({type:'LOGOUT'}) setAllowGuest(data.channel.filter(x=>x.name === 'guest_access').length > 0) + setSpinning(false) } }) },[]) @@ -65,6 +67,7 @@ const Login:FC = ()=> { if (code === STATUS_CODE.SUCCESS) { dispatch({type:'LOGIN'}) + console.log('1') // message.success($t(RESPONSE_TIPS.loginSuccess)); const callbackUrl = new URLSearchParams(window.location.search).get('callbackUrl'); if (callbackUrl && callbackUrl !== 'null') { @@ -100,6 +103,8 @@ const Login:FC = ()=> { }, []); return ( + spinning? + } spinning={spinning} className='w-full h-full flex items-center justify-center'> :
) } - ],[state.language]) + ],[state.language,handleDeleteFilter]) useEffect(()=>{ getFilterOptions() },[state.language]) + useEffect(()=>{ + setSelectedOptionNameSet(new Set(value?.map(x=>x.name) || [])) + console.log('valuechange',value) + },[value]) return (
{ @@ -116,7 +122,7 @@ const FilterTable: React.FC = ({ className={`mt-btnybase border-solid border-[1px] border-BORDER border-b-0 rounded ${disabled ? '' : 'mt-btnbase'}`} pagination={false} size='small' - columns={columns} dataSource={value} rowKey='id' /> } + columns={columns} dataSource={value} rowKey='_eoKey' /> }
= ({ selectedOptionNameSet={selectedOptionNameSet} disabled={disabled} setFormCanSubmit={setFormCanSubmit} + serviceId={serviceId} />
diff --git a/frontend/packages/core/src/pages/policy/ServicePolicyLayout.tsx b/frontend/packages/core/src/pages/policy/ServicePolicyLayout.tsx new file mode 100644 index 00000000..8ae89112 --- /dev/null +++ b/frontend/packages/core/src/pages/policy/ServicePolicyLayout.tsx @@ -0,0 +1,15 @@ +import { useEffect } from "react"; +import { Outlet, useLocation, useNavigate } from "react-router-dom"; + +export default function ServicePolicyLayout(){ + const location = useLocation() + const pathName = location.pathname + const navigator = useNavigate() + useEffect(()=>{ + const tmpPath = pathName.split('/') + if(tmpPath[tmpPath.length -1 ] === 'servicepolicy'){ + navigator('datamasking/list') + } + },[pathName]) + return () +} \ No newline at end of file diff --git a/frontend/packages/core/src/pages/policy/dataMasking/DataMasking.tsx b/frontend/packages/core/src/pages/policy/dataMasking/DataMasking.tsx index 23dc41b0..2acd899b 100644 --- a/frontend/packages/core/src/pages/policy/dataMasking/DataMasking.tsx +++ b/frontend/packages/core/src/pages/policy/dataMasking/DataMasking.tsx @@ -1,10 +1,10 @@ import { ActionType } from "@ant-design/pro-components"; -import { useMemo, useRef, useState } from "react"; -import { Button, message, Switch } from 'antd' +import { useEffect, useMemo, useRef, useState } from "react"; +import { App, Button, message, Switch } from 'antd' import PageList, { PageProColumns } from "@common/components/aoplatform/PageList"; import { $t } from "@common/locales"; import { useGlobalContext } from "@common/contexts/GlobalStateContext"; -import { BasicResponse, RESPONSE_TIPS, STATUS_CODE } from "@common/const/const.tsx"; +import { BasicResponse, DELETE_TIPS, RESPONSE_TIPS, STATUS_CODE } from "@common/const/const.tsx"; import { useFetch } from "@common/hooks/http"; import WithPermission from "@common/components/aoplatform/WithPermission.tsx"; import TableBtnWithPermission from "@common/components/aoplatform/TableBtnWithPermission"; @@ -14,6 +14,7 @@ import { PolicyPublishInfoType, PolicyPublishModalHandle, RouterParams } from "@ import { DrawerWithFooter } from "@common/components/aoplatform/DrawerWithFooter"; import { DataMaskStrategyItem } from "@common/const/policy/type"; import {PolicyPublishModalContent} from '@common/components/aoplatform/PolicyPublishModalContent' +import { checkAccess } from "@common/utils/permission"; const DataMasking = (props: any) => { @@ -24,12 +25,15 @@ const DataMasking = (props: any) => { rowOperation = [] } = props; const { serviceId, teamId } = useParams() - const { state } = useGlobalContext() + const { state,accessData } = useGlobalContext() const navigator = useNavigate() const [drawerVisible, setDrawerVisible] = useState(false) const [drawerData, setDrawerData] = useState() const [isOkToPublish, setIsOkToPublish] = useState(false) const drawerRef = useRef(null) + const { modal } = App.useApp() + + useEffect(()=>{console.log(props, publishBtn)},[publishBtn]) /** * 列表ref */ @@ -52,7 +56,7 @@ const DataMasking = (props: any) => { const res = DATA_MASSKING_TABLE_COLUMNS.map(x => { // 启动列渲染 if (x.dataIndex === 'isStop') { - x.render = (text: any, record: any) => { changeOpenApiStatus(e, record) }} /> + x.render = (text: any, record: any) => { changeOpenApiStatus(e, record) }} /> } // 处理数列渲染 if (x.dataIndex === 'treatmentNumber') { @@ -77,11 +81,11 @@ const DataMasking = (props: any) => { fixed: 'right', valueType: 'option', render: (_: React.ReactNode, entity: any) => [ - ...(rowOperation.length && rowOperation.find((item: string) => item === 'edit') ? [ { openEditModal(entity) }} btnTitle="编辑" />] : []), - // ...(rowOperation.length && rowOperation.find((item: string) => item === 'logs') ? [ { openLogsModal(entity) }} btnTitle="详情" />] : []), + ...(rowOperation.length && rowOperation.find((item: string) => item === 'edit') ? [ { openEditModal(entity) }} btnTitle="编辑" />] : []), + // ...(rowOperation.length && rowOperation.find((item: string) => item === 'logs') ? [ { openLogsModal(entity) }} btnTitle="详情" />] : []), ...(rowOperation.length && rowOperation.find((item: string) => item === 'delete') ? [ - entity.isDeleted ? { restorePolicy(entity) }} btnTitle="恢复" /> : - { deletePolicy(entity) }} btnTitle="删除" /> + entity.isDelete ? { restorePolicy(entity) }} btnTitle="恢复" /> : + { openModal('delete',entity) }} btnTitle="删除" /> ] : []), ], } @@ -100,10 +104,11 @@ const DataMasking = (props: any) => { * @param entity 行数据 */ const changeOpenApiStatus = (enabled: boolean, entity: any) => { + console.log(enabled) fetchData>( - `strategy/${serviceId === undefined? 'global':'service'}/data-masking/${enabled ? 'disable' : 'enable'}`, + `strategy/${serviceId === undefined? 'global':'service'}/data-masking/${enabled ? 'enable' :'disable' }`, { - method: 'PUT', + method: 'PATCH', eoParams: { service:serviceId, team:teamId, @@ -159,14 +164,14 @@ const DataMasking = (props: any) => { keyword: searchWord, service:serviceId, team:teamId,}, - eoTransformKeys: ['is_stop', 'is_deleted', 'update_time','publish_status','processed_total'] + eoTransformKeys: ['is_stop', 'is_delete', 'update_time','publish_status','processed_total'] } ).then(response => { const { code,data, msg } = response if (code === STATUS_CODE.SUCCESS) { // 保存数据 return { - data:data.strategies, + data:data.list, total:data.total, success: true } @@ -186,7 +191,7 @@ const DataMasking = (props: any) => { * @param type */ const addPolicy = () => { - navigator('/globalpolicy/datamasking/create') + navigator('../create') } /** @@ -213,7 +218,7 @@ const DataMasking = (props: any) => { * 编辑 */ const openEditModal = (entity: any) => { - navigator(`/globalpolicy/datamasking/${entity.id}`) + navigator(`../${entity.id}`) } /** @@ -224,12 +229,47 @@ const DataMasking = (props: any) => { console.log('日志', entity); } + + + const openModal =async (type:'delete',entity?:DataMaskStrategyItem)=>{ + if(entity?.publishStatus === 'online'){ + return deletePolicy(entity!).then((res)=>{if(res === true) manualReloadTable()}) + } + let title:string = '' + let content:string|React.ReactNode = '' + switch (type){ + case 'delete': + title=$t('删除') + content=$t(DELETE_TIPS.default) + break; + } + + modal.confirm({ + title, + content, + onOk:()=>{ + switch (type){ + case 'delete': + return deletePolicy(entity!).then((res)=>{if(res === true) manualReloadTable()}) + } + }, + width:600, + okText:$t('确认'), + okButtonProps:{ + disabled : !checkAccess( `${ serviceId === undefined ? 'system.devops':'team.service'}.policy.edit`, accessData) + }, + cancelText:$t('取消'), + closable:true, + icon:<>, + }) +} + /** * 删除 * @param entity */ const deletePolicy = (entity: DataMaskStrategyItem) => { - fetchData>( + return fetchData>( `strategy/${serviceId === undefined? 'global':'service'}/data-masking`, { method: 'DELETE', @@ -242,11 +282,12 @@ const DataMasking = (props: any) => { const { code, msg } = response if (code === STATUS_CODE.SUCCESS) { message.success(msg || $t(RESPONSE_TIPS.success)) - manualReloadTable() + return Promise.resolve(true) } else { message.error(msg || $t(RESPONSE_TIPS.error)) + return Promise.reject(msg || $t(RESPONSE_TIPS.error)) } - }) + }).catch((errorInfo)=> Promise.reject(errorInfo)) } /** @@ -295,11 +336,11 @@ const DataMasking = (props: any) => { sort:Record, filter:Record) => getPolicyList(params,sort, filter)} addNewBtnTitle={$t("添加策略")} - addNewBtnAccess="system.organization.member.edit" + addNewBtnAccess={`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.edit`} onAddNewBtnClick={() => { addPolicy() }} searchPlaceholder={$t("输入名称、筛选条件查找")} afterNewBtn={ - publishBtn && [ + publishBtn && [ ] } @@ -316,7 +357,7 @@ const DataMasking = (props: any) => { okBtnTitle={$t('发布')} open={drawerVisible} submitDisabled={!isOkToPublish} - submitAccess={`team.service.release.add`} + submitAccess={`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.publish`} onSubmit={onSubmit} > [] = [ }, { title: ('更新者'), - dataIndex: 'operator', + dataIndex: ['updater','name'], width: 140, ellipsis: true }, diff --git a/frontend/packages/core/src/pages/policy/dataMasking/DataMaskingConfig.tsx b/frontend/packages/core/src/pages/policy/dataMasking/DataMaskingConfig.tsx index fdeb9416..e4c7bba7 100644 --- a/frontend/packages/core/src/pages/policy/dataMasking/DataMaskingConfig.tsx +++ b/frontend/packages/core/src/pages/policy/dataMasking/DataMaskingConfig.tsx @@ -11,8 +11,9 @@ import { forwardRef, useEffect, useImperativeHandle, useMemo, useState } from "r import { useParams, useNavigate } from "react-router-dom" import DataMaskRuleTable from "./DataMaskingRuleTable" import FilterTable from "../FilterTable" -import { DataMaskingConfigHandle ,DataMaskingConfigFieldType} from "@common/const/policy/type" +import { DataMaskingConfigHandle ,DataMaskingConfigFieldType, PolicyMatchType} from "@common/const/policy/type" import {PolicyOptions} from '@common/const/policy/consts' +import {v4 as uuidv4} from 'uuid' const DataMaskingConfig = forwardRef((_,ref) => { const { message,modal } = App.useApp() @@ -37,7 +38,8 @@ const DataMaskingConfig = forwardRef((_,ref) => { setTimeout(()=>{ form.setFieldsValue({ ...data.strategy, - type:'data-masking' + type:'data-masking', + filters:data.strategy.filters.map((x)=>{x._eoKey = uuidv4(); return x}) }) },0) }else{ @@ -48,16 +50,22 @@ const DataMaskingConfig = forwardRef((_,ref) => { const onFinish:()=>Promise = () => { return form.validateFields().then((value)=>{ + if(value.filters){ + value.filters = value.filters.map((x:PolicyMatchType)=>({ + ...x, + values:x.name === 'ip' ? x.values?.[0].split('\n'): (x.values.indexOf('ALL')!== -1 ? ['ALL']:x.values)})) + } return fetchData>( `strategy/${serviceId === undefined? 'global':'service'}/data-masking`, { method:policyId === undefined? 'POST' : 'PUT', - eoParams: {service:serviceId,team:teamId, policyId:policyId}, + eoParams: {service:serviceId,team:teamId, strategy:policyId}, eoBody:({...value}) }).then(response=>{ const {code,data,msg} = response if(code === STATUS_CODE.SUCCESS){ message.success(msg || $t(RESPONSE_TIPS.success)) + navigator(serviceId? '':'/globalpolicy/datamasking/list') return Promise.resolve(true) }else{ message.error(msg || $t(RESPONSE_TIPS.error)) @@ -84,14 +92,13 @@ const DataMaskingConfig = forwardRef((_,ref) => { return ( - } spinning={loading} wrapperClassName=' pb-PAGE_INSIDE_B pr-PAGE_INSIDE_X'> - - +
((_,ref) => { - label={$t("优先级")} name={'priority'} @@ -145,19 +151,19 @@ const DataMaskingConfig = forwardRef((_,ref) => { label={$t("数据脱敏规则")} - name="rules" + name={["config","rules"]} rules={[{required: true}]} > - + - diff --git a/frontend/packages/core/src/pages/policy/dataMasking/DataMaskingRuleForm.tsx b/frontend/packages/core/src/pages/policy/dataMasking/DataMaskingRuleForm.tsx index 4ad2707a..baed9c5b 100644 --- a/frontend/packages/core/src/pages/policy/dataMasking/DataMaskingRuleForm.tsx +++ b/frontend/packages/core/src/pages/policy/dataMasking/DataMaskingRuleForm.tsx @@ -95,8 +95,8 @@ const DataMaskRuleForm: React.FC = ({ editData, ruleList, case 'shuffling': break; default: - submitData.mask.begin = formData.mask.begin; - submitData.mask.length = formData.mask.length; + submitData.mask.begin = Number(formData.mask.begin) || 0; + submitData.mask.length = Number(formData.mask.length) || 0; break; } return submitData; diff --git a/frontend/packages/core/src/pages/policy/globalPolicy.tsx b/frontend/packages/core/src/pages/policy/globalPolicy.tsx index 0193dc44..01cd4ce7 100644 --- a/frontend/packages/core/src/pages/policy/globalPolicy.tsx +++ b/frontend/packages/core/src/pages/policy/globalPolicy.tsx @@ -4,10 +4,12 @@ import PolicyTabContainer from "./policyTabContainer.tsx"; import DataMasking from "./dataMasking/DataMasking.tsx"; import { useGlobalContext } from "@common/contexts/GlobalStateContext.tsx"; import { useMemo } from "react"; - +import { useParams } from "react-router-dom"; +import { RouterParams } from "@common/const/type.ts"; const PartitionInsideGlobalPolicy = () => { const {state} = useGlobalContext() + const {serviceId} = useParams() /** * tab列表 */ @@ -20,7 +22,6 @@ const PartitionInsideGlobalPolicy = () => { ],[state.language]) return ( - <> { > - ) } diff --git a/frontend/packages/core/src/pages/policy/servicePolicy.tsx b/frontend/packages/core/src/pages/policy/servicePolicy.tsx index 1fbfacea..acd56dd2 100644 --- a/frontend/packages/core/src/pages/policy/servicePolicy.tsx +++ b/frontend/packages/core/src/pages/policy/servicePolicy.tsx @@ -1,6 +1,6 @@ import { $t } from "@common/locales/index.ts"; import DataMasking from "./dataMasking/DataMasking"; -import PolicyTabContainer from "./globalPolicy.tsx"; +import PolicyTabContainer from "./policyTabContainer.tsx"; const servicePolicy = () => { /** @@ -10,9 +10,11 @@ const servicePolicy = () => { { key: 'dataMasking', label: $t('数据脱敏'), - children:
+ children:
} ] + + console.log('publish',false) return ( <> diff --git a/frontend/packages/core/src/pages/system/SystemInsidePage.tsx b/frontend/packages/core/src/pages/system/SystemInsidePage.tsx index 9dd929d9..89ac2c36 100644 --- a/frontend/packages/core/src/pages/system/SystemInsidePage.tsx +++ b/frontend/packages/core/src/pages/system/SystemInsidePage.tsx @@ -63,7 +63,7 @@ const SystemInsidePage: FC = () => { getItem({$t('API 文档')}, 'api', undefined, undefined, undefined, 'team.service.api_doc.view'), getItem({$t('上游')}, 'upstream', undefined, undefined, undefined, 'team.service.upstream.view'), getItem({$t('使用说明')}, 'document', undefined, undefined, undefined, 'team.service.service_intro.view'), - getItem({$t('服务策略')}, 'servicePolicy', undefined, undefined, undefined, 'team.service.service_intro.view'), + getItem({$t('服务策略')}, 'servicepolicy', undefined, undefined, undefined, 'team.service.policy.view'), getItem({$t('发布')}, 'publish', undefined, undefined, undefined, 'team.service.release.view'), ], 'group'), @@ -111,6 +111,8 @@ const SystemInsidePage: FC = () => { setShowMenu(!routeId && !currentUrl.includes('route/create')) if (apiId !== undefined) { setActiveMenu('api') + } else if(currentUrl.includes('servicepolicy')){ + setActiveMenu('servicepolicy') } else if (serviceId !== currentUrl.split('/')[currentUrl.split('/').length - 1]) { setActiveMenu(currentUrl.split('/')[currentUrl.split('/').length - 1]) } else { diff --git a/frontend/packages/dashboard/src/const/const.tsx b/frontend/packages/dashboard/src/const/const.tsx index ee718d62..c62a6f62 100644 --- a/frontend/packages/dashboard/src/const/const.tsx +++ b/frontend/packages/dashboard/src/const/const.tsx @@ -169,7 +169,7 @@ export const DASHBOARD_BASE_COLUMNS_CONFIG:(PageProColumns&{eoTitle { title:('所属服务'), eoTitle:('所属服务'), - dataIndex: ['project','name'], + dataIndex: ['service','name'], ellipsis:true, width: 80 },