Merge remote-tracking branch 'origin/main' into feature/data-mask

This commit is contained in:
Liujian
2024-11-27 18:30:46 +08:00
24 changed files with 330 additions and 324 deletions
@@ -37,13 +37,13 @@ const InsidePage:FC<InsidePageProps> = ({showBanner=true,pageTitle,tagList,showB
// <div className="h-full flex flex-col flex-1 overflow-hidden bg-[#f7f8fa]">
<div className={`h-full flex flex-col flex-1 overflow-hidden ${className}`}>
{ showBanner && <div className={`border-[0px] mr-PAGE_INSIDE_X ${showBorder ? 'border-b-[1px] border-solid border-BORDER' : ''} ${headerClassName}`}>
<div className="mb-[30px]">
{!pageTitle && !description && !backUrl &&!customBtn ? <></>: <div className="mb-[30px]">
{backUrl &&<div className="text-[18px] leading-[25px] mb-[12px]">
<Button type="text" onClick={goBack}><ArrowLeftOutlined className="max-h-[14px]" />{$t('返回')}</Button>
</div>}
<div className="flex justify-between mb-[20px] items-center ">
<div className="flex items-center gap-TAG_LEFT ">
<p className="text-theme text-[26px] ">{pageTitle}</p>
<div className="text-theme text-[26px] ">{pageTitle}</div>
{tagList && tagList?.length > 0 && tagList?.map((tag)=>{
return ( <Tag key={tag.label as string} bordered={false} >{tag.label}</Tag>)
})}
@@ -53,10 +53,10 @@ const InsidePage:FC<InsidePageProps> = ({showBanner=true,pageTitle,tagList,showB
}}>{btnTitle}</Button></WithPermission>}
{customBtn}
</div>
<p >
<div >
{description}
</p>
</div>
</div>
</div>}
</div>}
<div className={`h-full ${scrollPage ? 'overflow-hidden' : 'overflow-auto'} ${contentClassName || ''}`}>{children}</div>
</div>
@@ -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"] }]
@@ -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
@@ -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 = {
@@ -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: <Login /> ,key:'root',},
{ path: '/', pathMatch: 'full', component: <Root /> ,key:'root',},
{ path: '/login', component: <Login /> ,key:'login'},
{ path: '/', pathMatch:'prefix',component:<ProtectedRoute /> ,key:'basciLayout',children:[
{ path: '*', component: <ErrorBoundary><NotFound/></ErrorBoundary>, 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<Map<string,string[]>>(new Map())
const [pluginAccessDictionary, setPluginAccessDictionary] = useState<{[k:string]:string}>({})
@@ -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<unknown>(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 <Spin indicator={<LoadingOutlined style={{ fontSize: 24 }} spin />} spinning={true} className='w-full h-full flex items-center justify-center'></Spin>;
}
@@ -77,7 +78,9 @@ const generateRoutes = (routerConfig: RouteConfig[]):RouteObject[] => {
{
path: route.path,
element: <ErrorBoundary>{routeElement}</ErrorBoundary> ,
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? <BasicLayout project="core" /> : <Navigate to="/login" />;
// return state.isAuthenticated? <BasicLayout project="core" /> : <Navigate to="/login" />;
return <BasicLayout project="core" />
}
export default RenderRoutes
+49 -9
View File
@@ -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:<ServicePolicyLayout />,
children:[{
path:'datamasking',
component:<Outlet />,
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:<ServicePolicyLayout />,
children:[{
path:'datamasking',
component:<Outlet />,
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'
}]
}
]
},
]
}
+9 -4
View File
@@ -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<FormInstance>(null);
const [loading,setLoading] = useState<boolean>()
// const { encryptByEnAES } = useCrypto();
const [allowGuest, setAllowGuest] = useState<boolean>(false)
const [spinning,setSpinning] = useState<boolean>(false)
const check = useCallback(()=>{
state.isAuthenticated &&setSpinning(true)
fetchData<BasicResponse<{channel:Array<{name:string}>, 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?
<Spin indicator={<LoadingOutlined style={{ fontSize: 24 }} spin />} spinning={spinning} className='w-full h-full flex items-center justify-center'></Spin> :
<div className="h-full w-full flex flex-col items-center overflow-auto min-h-[490px] bg-[#0d1117]">
<div id="glow-background" className="background-container">
<svg className="background-pattern" aria-hidden="true">
+14
View File
@@ -0,0 +1,14 @@
import { useGlobalContext } from "@common/contexts/GlobalStateContext"
import { Navigate, useLocation } from "react-router-dom"
export default function Root() {
const { state } = useGlobalContext()
const location = useLocation()
console.log(state?.isAuthenticated ,location?.pathname)
return (<>
{
state?.isAuthenticated && !location?.pathname
?<Navigate to={location?.pathname ?? state?.mainPage} />:<Navigate to="/login" />
}</>
)
}
@@ -7,7 +7,7 @@ import {debounce} from "lodash-es";
import {DownOutlined, SearchOutlined} from "@ant-design/icons";
import TreeWithMore from "@common/components/aoplatform/TreeWithMore.tsx";
import {useFetch} from "@common/hooks/http.ts";
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 { DepartmentListItem, MemberDropdownModalHandle } from "../../const/member/type.ts";
import WithPermission from "@common/components/aoplatform/WithPermission.tsx";
import { RouterParams } from "@core/components/aoplatform/RenderRoutes.tsx";
@@ -77,7 +77,7 @@ const MemberPage = ()=>{
break;
case 'delete':
title=$t('删除')
content=$t('该数据删除后将无法找回,请确认是否删除?')
content=DELETE_TIPS.default
break;
}
modal.confirm({
@@ -6,9 +6,10 @@ import { validateApiPath, validateIPorCIDR } from '@common/utils/validate';
import { $t } from '@common/locales';
import { FilterFormItemProps, RemoteTitleType, FilterFormHandle, FilterFormProps } from '@common/const/policy/type';
import { BasicResponse, PLACEHOLDER, RESPONSE_TIPS, STATUS_CODE } from '@common/const/const';
import { v4 as uuidv4 } from 'uuid'
const RemoteFormItem: React.FC<FilterFormItemProps> = (props) =>{
const {value, onChange, disabled,option, onShowValueChange} = props
const {value, onChange, disabled,option, onShowValueChange,serviceId} = props
const [remoteList, setRemoteList] = useState<unknown[]>([])
const [remoteTableColumns, setRemoteTableColumns] = useState<TableColumnsType>([])
const [loading, setLoading] = useState<boolean>(false)
@@ -24,23 +25,22 @@ const RemoteFormItem: React.FC<FilterFormItemProps> = (props) =>{
fetchData<BasicResponse<{
key:string,
list:Record<string,unknown>[],
target:string,
titles:Array<RemoteTitleType>,
total:number
value:string
}>>(`strategy/filter-REMOTE/${option?.name}`,{method:'GET', eoParams:{keyword:searchWord}}).then(response=>{
}>>(`strategy/${serviceId === undefined ? '' : 'service/'}filter-remote/${option?.name}`,{method:'GET', eoParams:{keyword:searchWord}}).then(response=>{
const {code,data, msg} = response
if(code === STATUS_CODE.SUCCESS){
setRemoteList(data[data.target as string] as unknown[])
setRemoteList(data.list as unknown[])
setRowKey(data.key as string)
setRemoteTableColumns(data.titles.map((x:RemoteTitleType)=>({
title: x.title,dataIndex:x.field,key:x.field,ellipsis:true
})))
setRemoteCounts(data.total)
if(!searchWord){
setOriginRemoteList(data[data.target as string])
setOriginRemoteList(data.list)
if(value?.length === 1 && value[0] === 'ALL'){
const totalDataArr = data[data.target as string]?.map((x:Record<string,unknown>)=>x[data.key as string])
const totalDataArr = data.list?.map((x:Record<string,unknown>)=>x[data.key as string])
onChange?.(totalDataArr)
onShowValueChange?.(totalDataArr.join(','))
}
@@ -81,7 +81,8 @@ const RemoteFormItem: React.FC<FilterFormItemProps> = (props) =>{
type: 'checkbox',
onChange: (selectedRowKeys: React.Key[]) => {
onChange?.(selectedRowKeys as string[]);
onShowValueChange?.(selectedRowKeys.length === remoteCounts? $t('所有(0)',[title]) : originRemoteList.filter(x=>selectedRowKeys?.indexOf(x[option.target]))?.map(x=>x.title).join(' , '))
console.log(originRemoteList)
onShowValueChange?.(selectedRowKeys.length === remoteCounts? $t('所有(0)',[title]) : originRemoteList.filter(x=>selectedRowKeys?.indexOf(x[option.key]))?.map(x=>x.title).join(' , '))
},
selectedRowKeys: value,
// getCheckboxProps: (record: unknown) => ({
@@ -93,15 +94,18 @@ const RemoteFormItem: React.FC<FilterFormItemProps> = (props) =>{
onClick:()=>{
if(value === undefined){
onChange?.([record[rowKey]])
onShowValueChange?.(record.title)
console.log(record[rowKey],record)
onShowValueChange?.(remoteCounts === 1 ? $t('所有(0)',[option?.title]) : record.name)
}else if(value?.indexOf(record[rowKey])!== -1){
const newSelectedKeys = value?.filter(x=>x!==record[rowKey])
onChange?.(newSelectedKeys!)
onShowValueChange?.(newSelectedKeys.length === remoteCounts? $t('所有(0)',[option?.title]) : originRemoteList.filter(x=>newSelectedKeys.indexOf(x[rowKey]) !== -1)?.map(x=>x.title)?.join(' , '))
console.log(newSelectedKeys,newSelectedKeys.length === remoteCounts? $t('所有(0)',[option?.title]) : originRemoteList.filter(x=>newSelectedKeys.indexOf(x[rowKey]) !== -1)?.map(x=>x.name)?.join(' , '))
onShowValueChange?.(newSelectedKeys.length === remoteCounts? $t('所有(0)',[option?.title]) : originRemoteList.filter(x=>newSelectedKeys.indexOf(x[rowKey]) !== -1)?.map(x=>x.name)?.join(' , '))
}else{
const newSelectedKeys = [...value,record[rowKey]]
onChange?.(newSelectedKeys)
onShowValueChange?.(newSelectedKeys.length === remoteCounts? $t('所有(0)',[option?.title]) : originRemoteList.filter(x=>newSelectedKeys.indexOf(x[rowKey]) !== -1)?.map(x=>x.title)?.join(' , '))
console.log(newSelectedKeys,originRemoteList,rowKey,remoteCounts,newSelectedKeys.length === remoteCounts? $t('所有(0)',[option?.title]) : originRemoteList.filter(x=>newSelectedKeys.indexOf(x[rowKey]) !== -1)?.map(x=>x.name)?.join(' , '))
onShowValueChange?.(newSelectedKeys.length === remoteCounts? $t('所有(0)',[option?.title]) : originRemoteList.filter(x=>newSelectedKeys.indexOf(x[rowKey]) !== -1)?.map(x=>x.name)?.join(' , '))
}
}
})}
@@ -155,7 +159,8 @@ const FilterForm = forwardRef<FilterFormHandle,FilterFormProps>(({
filterOptions,
selectedOptionNameSet,
disabled,
setFormCanSubmit},ref)=> {
setFormCanSubmit,
serviceId},ref)=> {
const [form] = Form.useForm();
const [filterType, setFilterType] = useState<'remote'|'static'|'pattern'>();
const [curOption, setCurOption] = useState<unknown>()
@@ -167,10 +172,12 @@ const FilterForm = forwardRef<FilterFormHandle,FilterFormProps>(({
},
save:()=>form.validateFields().then((res)=>{
const selectedOption = filterOptions.filter(x=>x.name === res.name)[0]
console.log('??',res,selectedOption,filterType,label)
return Promise.resolve({
...res,
label:filterType === 'pattern' ? res.value : label,
title:selectedOption.label
label:filterType === 'pattern' ? res.values : label,
title:selectedOption.label,
_eoKey:uuidv4()
})
}).catch((errorInfo)=>Promise.reject(errorInfo))
})
@@ -181,8 +188,8 @@ const FilterForm = forwardRef<FilterFormHandle,FilterFormProps>(({
setFormCanSubmit(false)
return
}
if(allValues.value instanceof Array){
setFormCanSubmit(allValues.value.length > 0)
if(allValues.values instanceof Array){
setFormCanSubmit(allValues.values.length > 0)
return
}
setFormCanSubmit(true)
@@ -190,7 +197,7 @@ const FilterForm = forwardRef<FilterFormHandle,FilterFormProps>(({
const handleTypeChange = (value:string)=>{
form.setFieldValue('value',filterForm?.name === value ? filterForm.value : undefined)
form.setFieldValue('values',filterForm?.name === value ? filterForm.values : undefined)
const selectedOption = filterOptions?.filter(item=>item.name === value)[0]
setFilterType(selectedOption?.type)
setCurOption(selectedOption)
@@ -205,10 +212,14 @@ const FilterForm = forwardRef<FilterFormHandle,FilterFormProps>(({
useEffect(()=>{
if(filterForm?.name){
form.setFieldsValue(filterForm)
form.setFieldsValue({
...filterForm,
values: filterForm?.type === 'pattern' ?
(filterForm.name === 'ip' ? (filterForm.values as string[])?.join('\n') : (filterForm.values as string[])?.[0] ) :filterForm.values})
const selectedOption = filterOptions.filter(x=>x.name === filterForm?.name)[0]
setFilterType(selectedOption?.type )
setCurOption(selectedOption)
setFormCanSubmit(filterForm?.values && filterForm?.values?.length >0)
}else{
const firstOption = filterOptions.filter(x=>!selectedOptionNameSet.has(x.name))[0]
form.setFieldValue('name',firstOption?.name)
@@ -227,10 +238,10 @@ const FilterForm = forwardRef<FilterFormHandle,FilterFormProps>(({
<Form.Item name="name" label={$t('属性名称')} rules={[{ required: true }]}>
<Select disabled={disabled} onChange={handleTypeChange} options={filterOptionsList} />
</Form.Item>
<Form.Item name="value" label={$t('属性值')} rules={
<Form.Item name="values" label={$t('属性值')} rules={
(filterType === 'pattern' ? ( [{validator:form.getFieldValue('name') === 'ip' ? validateIPorCIDR : validateApiPath}]):[])
}>
{filterType === 'remote' && <RemoteFormItem option={curOption} disabled={disabled} onShowValueChange={setLabel}/>}
{filterType === 'remote' && <RemoteFormItem serviceId={serviceId} option={curOption} disabled={disabled} onShowValueChange={setLabel}/>}
{filterType === 'pattern' && form.getFieldValue('name') !== 'ip' && (
<Input
@@ -1,4 +1,4 @@
import React, { useState, useEffect, useRef, useMemo } from 'react';
import React, { useState, useEffect, useRef, useMemo, useCallback } from 'react';
import { Button, Table, Modal, App, Divider } from 'antd';
import { ColumnsType } from 'antd/es/table';
import { $t } from '@common/locales';
@@ -8,6 +8,8 @@ import TableBtnWithPermission from '@common/components/aoplatform/TableBtnWithPe
import { FilterFormField, FilterTableProps, FilterOptionType, FilterFormHandle } from '@common/const/policy/type.ts';
import FilterForm from './FilterForm';
import { BasicResponse, COLUMNS_TITLE, RESPONSE_TIPS, STATUS_CODE } from '@common/const/const';
import { useParams } from 'react-router-dom';
import { RouterParams } from '@common/const/type';
const FilterTable: React.FC<FilterTableProps> = ({
@@ -25,13 +27,13 @@ const FilterTable: React.FC<FilterTableProps> = ({
const formRef = useRef<FilterFormHandle>(null);
const [formCanSubmit,setFormCanSubmit] = useState(false)
const [selectedOptionNameSet, setSelectedOptionNameSet] = useState<Set<string>>(new Set());
const {serviceId} = useParams<RouterParams>()
const openDrawer = (type: string, data?: FilterFormField) => {
switch (type) {
case 'addFilter':
setFilterForm(undefined)
break;
case 'editFilter':
console.log(data)
setFilterForm(data)
}
setIsModalVisible(true);
@@ -51,24 +53,24 @@ const FilterTable: React.FC<FilterTableProps> = ({
formPromise?.then?.((res)=>{
const newFilterForm = {
name:res.name,
value:res.value instanceof Array ? res.value : [res.value],
values:res.values instanceof Array ? res.values : [res.values],
label:res.label,
title:res.title
}
console.log(res, newFilterForm, value)
onChange?.([newFilterForm, ...(value?.filter(x=>!filterForm?.name|| x.name!==filterForm.name) || [])])
setSelectedOptionNameSet(prev=>{filterForm?.name &&prev.delete(filterForm?.name); prev.add(res.name); return prev})
closeDrawer()
})
};
const handleDeleteFilter = (item: FilterFormField) => {
setSelectedOptionNameSet(prev=>{prev.delete(item?.name); return prev})
const newFilterShowList = value.filter((filter) => filter !== item);
onChange?.(newFilterShowList);
};
const handleDeleteFilter = useCallback((item: FilterFormField) => {
console.log(item, value, isModalVisible);
const newFilterShowList = value?.filter((filter) => filter._eoKey !== item._eoKey) || [];
onChange?.(newFilterShowList);
}, [value, onChange]);
const getFilterOptions = ()=>{
fetchData<BasicResponse<{options:FilterOptionType[]}>>('strategy/filter-options',{method:'GET'}).then(response=>{
fetchData<BasicResponse<{options:FilterOptionType[]}>>(`strategy/${serviceId === undefined ? 'global' : 'service'}/filter-options`,{method:'GET'}).then(response=>{
const {code,data,msg} = response
if(code === STATUS_CODE.SUCCESS){
setFilterOptions(data.options)
@@ -99,12 +101,16 @@ const FilterTable: React.FC<FilterTableProps> = ({
<Divider type="vertical" className="mx-0" key="div2"/>
<TableBtnWithPermission key="delete" btnType="delete" onClick={()=>{handleDeleteFilter(record)}} btnTitle={$t("删除")}/></div>)
}
],[state.language])
],[state.language,handleDeleteFilter])
useEffect(()=>{
getFilterOptions()
},[state.language])
useEffect(()=>{
setSelectedOptionNameSet(new Set(value?.map(x=>x.name) || []))
console.log('valuechange',value)
},[value])
return (
<div>
{
@@ -116,7 +122,7 @@ const FilterTable: React.FC<FilterTableProps> = ({
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' /> }
<div role="alert" className="ant-form-item-explain-error">
</div>
<Modal
@@ -135,6 +141,7 @@ const FilterTable: React.FC<FilterTableProps> = ({
selectedOptionNameSet={selectedOptionNameSet}
disabled={disabled}
setFormCanSubmit={setFormCanSubmit}
serviceId={serviceId}
/>
</Modal>
</div>
@@ -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 (<Outlet></Outlet>)
}
@@ -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<RouterParams>()
const { state } = useGlobalContext()
const { state,accessData } = useGlobalContext()
const navigator = useNavigate()
const [drawerVisible, setDrawerVisible] = useState<boolean>(false)
const [drawerData, setDrawerData] = useState<PolicyPublishInfoType >()
const [isOkToPublish, setIsOkToPublish] = useState<boolean>(false)
const drawerRef = useRef<PolicyPublishModalHandle>(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) => <Switch checked={!record.isStop} onChange={(e) => { changeOpenApiStatus(e, record) }} />
x.render = (text: any, record: any) => <WithPermission access={`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.edit`} ><Switch checked={!record.isStop} onChange={(e) => { changeOpenApiStatus(e, record) }} /></WithPermission>
}
// 处理数列渲染
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') ? [<TableBtnWithPermission access="system.organization.member.edit" key="edit" btnType="edit" onClick={() => { openEditModal(entity) }} btnTitle="编辑" />] : []),
// ...(rowOperation.length && rowOperation.find((item: string) => item === 'logs') ? [<TableBtnWithPermission access="system.organization.member.edit" key="logs" btnType="logs" onClick={() => { openLogsModal(entity) }} btnTitle="详情" />] : []),
...(rowOperation.length && rowOperation.find((item: string) => item === 'edit') ? [<TableBtnWithPermission access={`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.edit`} key="edit" btnType="edit" onClick={() => { openEditModal(entity) }} btnTitle="编辑" />] : []),
// ...(rowOperation.length && rowOperation.find((item: string) => item === 'logs') ? [<TableBtnWithPermission access={`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.view`} key="logs" btnType="logs" onClick={() => { openLogsModal(entity) }} btnTitle="详情" />] : []),
...(rowOperation.length && rowOperation.find((item: string) => item === 'delete') ? [
entity.isDeleted ? <TableBtnWithPermission access="system.organization.member.edit" key="refresh" btnType="refresh" onClick={() => { restorePolicy(entity) }} btnTitle="恢复" /> :
<TableBtnWithPermission access="system.organization.member.edit" key="delete" btnType="delete" onClick={() => { deletePolicy(entity) }} btnTitle="删除" />
entity.isDelete ? <TableBtnWithPermission access={`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.edit`} key="refresh" btnType="refresh" onClick={() => { restorePolicy(entity) }} btnTitle="恢复" /> :
<TableBtnWithPermission access={`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.delete`} key="delete" btnType="delete" onClick={() => { openModal('delete',entity) }} btnTitle="删除" />
] : []),
],
}
@@ -100,10 +104,11 @@ const DataMasking = (props: any) => {
* @param entity 行数据
*/
const changeOpenApiStatus = (enabled: boolean, entity: any) => {
console.log(enabled)
fetchData<BasicResponse<null>>(
`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<BasicResponse<null>>(
return fetchData<BasicResponse<null>>(
`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<string, string>,
filter:Record<string, string>) => 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 && [<WithPermission key="removeFromDepPermission" access="system.organization.member.edit">
publishBtn && [<WithPermission key="removeFromDepPermission" access={`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.publish`} >
<Button className="mr-btnbase" key="removeFromDep" onClick={() => publish()}>{$t('发布')}</Button>
</WithPermission>]
}
@@ -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}
>
<PolicyPublishModalContent
@@ -55,7 +55,7 @@ export const DATA_MASSKING_TABLE_COLUMNS: PageProColumns<any>[] = [
},
{
title: ('更新者'),
dataIndex: 'operator',
dataIndex: ['updater','name'],
width: 140,
ellipsis: true
},
@@ -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<DataMaskingConfigHandle>((_,ref) => {
const { message,modal } = App.useApp()
@@ -37,7 +38,8 @@ const DataMaskingConfig = forwardRef<DataMaskingConfigHandle>((_,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<DataMaskingConfigHandle>((_,ref) => {
const onFinish:()=>Promise<boolean|string> = () => {
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<BasicResponse<{service:{id:string}}>>(
`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<DataMaskingConfigHandle>((_,ref) => {
return (
<InsidePage pageTitle={ $t('编辑策略')|| '-'}
<InsidePage pageTitle={serviceId ? undefined: $t('编辑策略')}
showBorder={false}
scrollPage={false}
className="overflow-y-auto"
>
<Spin indicator={<LoadingOutlined style={{ fontSize: 24 }} spin />} spinning={loading} wrapperClassName=' pb-PAGE_INSIDE_B pr-PAGE_INSIDE_X'>
<WithPermission access={onEdit ? ['team.service.service.edit'] :''}>
<WithPermission access={onEdit ? [`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.edit`] :''}>
<Form
layout='vertical'
labelAlign='left'
@@ -120,7 +127,6 @@ const DataMaskingConfig = forwardRef<DataMaskingConfigHandle>((_,ref) => {
</Select>
</Form.Item>
<Form.Item<DataMaskingConfigFieldType>
label={$t("优先级")}
name={'priority'}
@@ -145,19 +151,19 @@ const DataMaskingConfig = forwardRef<DataMaskingConfigHandle>((_,ref) => {
<Form.Item<DataMaskingConfigFieldType>
label={$t("数据脱敏规则")}
name="rules"
name={["config","rules"]}
rules={[{required: true}]}
>
<DataMaskRuleTable />
</Form.Item>
<Row className="mb-[10px]">
<WithPermission access={onEdit ? ['team.service.service.edit'] :''}>
<WithPermission access={onEdit ? [`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.edit`] :''}>
<Button type="primary" htmlType="submit">
{$t('保存')}
</Button>
</WithPermission>
<Button className="ml-btnrbase" type="default" onClick={() => navigator('/globalpolicy/datamasking/list')}>
<Button className="ml-btnrbase" type="default" onClick={() => navigator('../list')}>
{$t('取消')}
</Button>
</Row>
@@ -95,8 +95,8 @@ const DataMaskRuleForm: React.FC<DataMaskRuleFormProps> = ({ 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;
@@ -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<RouterParams>()
/**
* tab列表
*/
@@ -20,7 +22,6 @@ const PartitionInsideGlobalPolicy = () => {
],[state.language])
return (
<>
<InsidePage
pageTitle={$t('全局策略')}
description={$t("支持对系统全局进行统一的策略配置,从而简化管理并确保一致性。全局策略的优先级比服务策略略低。")}
@@ -29,7 +30,6 @@ const PartitionInsideGlobalPolicy = () => {
>
<PolicyTabContainer tabs={tabItems} />
</InsidePage>
</>
)
}
@@ -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: <div className="pr-[40px] h-full preview-document mb-PAGE_INSIDE_B"><DataMasking rowOperation={['edit', 'logs', 'delete']} /></div>
children: <div className="pr-[40px] h-full preview-document mb-PAGE_INSIDE_B"><DataMasking publishBtn={false} rowOperation={['edit', 'logs', 'delete']} /></div>
}
]
console.log('publish',false)
return (
<>
<PolicyTabContainer tabs={tabItems} />
@@ -63,7 +63,7 @@ const SystemInsidePage: FC = () => {
getItem(<Link to="./api">{$t('API 文档')}</Link>, 'api', undefined, undefined, undefined, 'team.service.api_doc.view'),
getItem(<Link to="./upstream">{$t('上游')}</Link>, 'upstream', undefined, undefined, undefined, 'team.service.upstream.view'),
getItem(<Link to="./document">{$t('使用说明')}</Link>, 'document', undefined, undefined, undefined, 'team.service.service_intro.view'),
getItem(<Link to="./servicePolicy">{$t('服务策略')}</Link>, 'servicePolicy', undefined, undefined, undefined, 'team.service.service_intro.view'),
getItem(<Link to="./servicepolicy">{$t('服务策略')}</Link>, 'servicepolicy', undefined, undefined, undefined, 'team.service.policy.view'),
getItem(<Link to="./publish">{$t('发布')}</Link>, '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 {
@@ -28,7 +28,7 @@ export type MonitorApiPageProps = {
detailEntityName:string
}
export type MonitorApiQueryData = SearchBody & { path?:string, apis?:string[], projects?:string[] }
export type MonitorApiQueryData = SearchBody & { path?:string, apis?:string[], services?:string[] }
export default function MonitorApiPage(props:MonitorApiPageProps){
const {fetchTableData,detailDrawerContent,fullScreen,setFullScreen,setDetailId,timeButton,setTimeButton,detailEntityName,setDetailEntityName} = props
@@ -51,7 +51,7 @@ export default function MonitorApiPage(props:MonitorApiPageProps){
}, []);
const getApiList = (projectIds?:string[])=>{
return fetchData<{apis:EntityItem[]}>('simple/project/apis',{method:'POST',eoBody:({projects:projectIds || queryData?.projects})}).then((resp) => {
return fetchData<{apis:EntityItem[]}>('simple/service/apis',{method:'POST',eoBody:({services:projectIds || queryData?.services})}).then((resp) => {
const {code,data,msg} = resp
if(code === STATUS_CODE.SUCCESS){
setApiOptionList(data.apis?.map((x:EntityItem)=>({label:x.name, value:x.id})))
@@ -65,10 +65,10 @@ export default function MonitorApiPage(props:MonitorApiPageProps){
}
const getProjectList = ()=>{
return fetchData<{projects:EntityItem[]}>('simple/projects',{method:'GET'}).then((resp) => {
return fetchData<{services:EntityItem[]}>('simple/services',{method:'GET'}).then((resp) => {
const {code,data,msg} = resp
if(code === STATUS_CODE.SUCCESS){
setProjectOptionList(data.projects?.map((x:EntityItem)=>({label:x.name, value:x.id})))
setProjectOptionList(data.services?.map((x:EntityItem)=>({label:x.name, value:x.id})))
}else{
message.error(msg || $t(RESPONSE_TIPS.dataError))
return setProjectOptionList([])
@@ -164,13 +164,13 @@ export default function MonitorApiPage(props:MonitorApiPageProps){
<label className=" whitespace-nowrap inline-block">{$t('服务')}</label>
<Select
className="w-[346px]"
value={queryData?.projects}
value={queryData?.services}
options={projectOptionList}
mode="multiple"
allowClear
maxCount={3}
placeholder={$t("选择服务")}
onChange={(value)=>{setQueryData(prevData=>({...prevData || {}, projects:value}));getApiList(value)}}
onChange={(value)=>{setQueryData(prevData=>({...prevData || {}, services:value}));getApiList(value)}}
/>
</div>
<div className="flex flex-nowrap items-center pt-btnybase mr-btnybase">
@@ -56,10 +56,10 @@ export default function MonitorAppPage(props:MonitorAppPageProps){
};
const getAppList = ()=>{
return fetchData<{projects:EntityItem[]}>('simple/apps/mine',{method:'GET'}).then((resp) => {
return fetchData<{apps:EntityItem[]}>('simple/apps/mine',{method:'GET'}).then((resp) => {
const {code,data,msg} = resp
if(code === STATUS_CODE.SUCCESS){
setListOfApps(data.projects?.map((x:EntityItem)=>({label:x.name, value:x.id})))
setListOfApps(data.apps?.map((x:EntityItem)=>({label:x.name, value:x.id})))
}else{
message.error(msg || $t(RESPONSE_TIPS.dataError))
return setListOfApps([])
@@ -151,9 +151,9 @@ export default function MonitorAppPage(props:MonitorAppPageProps){
maxTagCount={1}
// maxTagPlaceholder={(selectedList) => `and ${selectedList.length} more selected`}
placeholder={$t("请选择消费者")}
value={queryData?.projects}
value={queryData?.apps}
options={listOfApps}
onChange={(value)=>{setQueryData(prevData=>({...prevData || {}, projects:value}))}}
onChange={(value)=>{setQueryData(prevData=>({...prevData || {},apps :value}))}}
/>
</div>
<div>
@@ -15,7 +15,7 @@ import { CloseOutlined, ExpandOutlined } from "@ant-design/icons";
import { useFetch } from "@common/hooks/http";
import { $t } from "@common/locales";
export type MonitorSubQueryData = SearchBody & { projects?:string[] ,type?:'subscriber'|'provider'}
export type MonitorSubQueryData = SearchBody & { services?:string[] , apps?:string[],type?:'subscriber'|'provider'}
export type MonitorSubPageProps = {
@@ -60,10 +60,10 @@ export default function MonitorSubPage(props:MonitorSubPageProps){
};
const getProjectList = ()=>{
return fetchData<{projects:EntityItem[]}>('simple/projects',{method:'GET'}).then((resp) => {
return fetchData<{services:EntityItem[]}>('simple/services',{method:'GET'}).then((resp) => {
const {code,data,msg} = resp
if(code === STATUS_CODE.SUCCESS){
setListOfProjects(data.projects?.map((x:EntityItem)=>({label:x.name, value:x.id})))
setListOfProjects(data.services?.map((x:EntityItem)=>({label:x.name, value:x.id})))
}else{
message.error(msg || $t(RESPONSE_TIPS.dataError))
return setListOfProjects([])
@@ -154,9 +154,9 @@ export default function MonitorSubPage(props:MonitorSubPageProps){
mode="multiple"
maxTagCount={1}
placeholder={$t("请选择服务")}
value={queryData?.projects}
value={queryData?.services}
options={listOfProjects}
onChange={(value)=>{setQueryData(prevData=>({...prevData || {}, projects:value}))}}
onChange={(value)=>{setQueryData(prevData=>({...prevData || {}, services:value}))}}
/>
</div>
<div>
@@ -169,7 +169,7 @@ export const DASHBOARD_BASE_COLUMNS_CONFIG:(PageProColumns<MonitorData>&{eoTitle
{
title:('所属服务'),
eoTitle:('所属服务'),
dataIndex: ['project','name'],
dataIndex: ['service','name'],
ellipsis:true,
width: 80
},