mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-14 20:41:15 +08:00
feat: integrate global policy API and implement data log page
This commit is contained in:
@@ -146,8 +146,20 @@ export const PublishApprovalModalContent = forwardRef<PublishApprovalModalHandle
|
||||
...x,
|
||||
title: typeof x.title === 'string' ? $t(x.title) : x.title,
|
||||
...(x.dataIndex === 'status' ? {
|
||||
render:(_,entity)=>(
|
||||
entity.status === 0 ? $t('正常') : $t('无效'))
|
||||
render:(_,entity)=> {
|
||||
switch(entity.change){
|
||||
case 'none':
|
||||
return '-'
|
||||
case 'new':
|
||||
return $t('新建')
|
||||
case 'update':
|
||||
return $t('更新')
|
||||
case 'delete':
|
||||
return $t('删除')
|
||||
default:
|
||||
return '-'
|
||||
}
|
||||
}
|
||||
}:{})
|
||||
}
|
||||
}),[state.language])
|
||||
|
||||
@@ -181,6 +181,10 @@ export const TranslateWord = ()=>{
|
||||
{$t('请输入IP地址或CIDR范围,每条以换行分割')}
|
||||
{$t('待更新')}
|
||||
{$t('待删除')}
|
||||
{$t('内容')}
|
||||
{$t('调用地址')}
|
||||
{$t('消费者 IP')}
|
||||
{$t('鉴权名称')}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -749,5 +749,19 @@
|
||||
"K67f4e9bb": "The domain name for obtaining API market documentation information when integrating with external platforms",
|
||||
"K1da86266": "Invalid",
|
||||
"K3a34d49b": "Pending Update",
|
||||
"Kd2850420": "Pending Deletion"
|
||||
"Kd2850420": "Pending Deletion",
|
||||
"K9ada4366": "Operation successful, the page will refresh shortly",
|
||||
"K9b332ab1": "Request prefix",
|
||||
"K3d78d483": "HTTP headers",
|
||||
"K17dc3a62": "Data logs",
|
||||
"Ke429194e": "Processing logs",
|
||||
"K84ffb1dd": "Enter the invocation address, consumer IP, and consumer condition to search",
|
||||
"Kb147fabc": "Create",
|
||||
"K40ca4f2": "Update",
|
||||
"K3e7aa0ad": "Content",
|
||||
"K2f5fdf5e": "Call Address",
|
||||
"K1bc5e0a3": "Consumer IP",
|
||||
"K6f39ea21": "Authentication Name",
|
||||
"K8c34c02f": "Before Masking",
|
||||
"K8e3d388d": "After Masking"
|
||||
}
|
||||
|
||||
@@ -771,6 +771,19 @@
|
||||
"K67f4e9bb": "外部プラットフォームと統合する際に、API市場のドキュメント情報を取得するためのドメイン名",
|
||||
"K1da86266": "無効",
|
||||
"K3a34d49b": "更新待ち",
|
||||
"Kd2850420": "削除待ち"
|
||||
|
||||
"Kd2850420": "削除待ち",
|
||||
"K9ada4366": "操作成功、ページを更新します",
|
||||
"K9b332ab1": "リクエストプレフィックス",
|
||||
"K3d78d483": "HTTPヘッダー",
|
||||
"K17dc3a62": "データログ",
|
||||
"Ke429194e": "ログの処理",
|
||||
"K84ffb1dd": "呼び出しアドレス、コンシューマーIP、条件を入力して検索",
|
||||
"Kb147fabc": "新規作成",
|
||||
"K40ca4f2": "更新",
|
||||
"K3e7aa0ad": "内容",
|
||||
"K2f5fdf5e": "呼び出しアドレス",
|
||||
"K1bc5e0a3": "コンシューマー IP",
|
||||
"K6f39ea21": "認証名",
|
||||
"K8c34c02f": "マスキング前",
|
||||
"K8e3d388d": "マスキング後"
|
||||
}
|
||||
|
||||
@@ -702,5 +702,19 @@
|
||||
"K31faa2a1": "优先级",
|
||||
"Kbdec9fa": "筛选条件",
|
||||
"Kbcbb7391": "处理数",
|
||||
"Kad207008": "编辑"
|
||||
"Kad207008": "编辑",
|
||||
"K9ada4366": "操作成功,即将刷新页面",
|
||||
"K9b332ab1": "请求前缀",
|
||||
"K3d78d483": "HTTP 头部",
|
||||
"K17dc3a62": "数据日志",
|
||||
"Ke429194e": "处理日志",
|
||||
"K84ffb1dd": "输入调用地址、消费者IP和消费者条件查找",
|
||||
"Kb147fabc": "新建",
|
||||
"K40ca4f2": "更新",
|
||||
"K3e7aa0ad": "内容",
|
||||
"K2f5fdf5e": "调用地址",
|
||||
"K1bc5e0a3": "消费者 IP",
|
||||
"K6f39ea21": "鉴权名称",
|
||||
"K8c34c02f": "脱敏前",
|
||||
"K8e3d388d": "脱敏后"
|
||||
}
|
||||
@@ -771,5 +771,19 @@
|
||||
"K67f4e9bb": "與外部平台集成時,用於獲取 API 市場文檔信息的域名",
|
||||
"K1da86266": "無效",
|
||||
"K3a34d49b": "待更新",
|
||||
"Kd2850420": "待刪除"
|
||||
"Kd2850420": "待刪除",
|
||||
"K9ada4366": "操作成功,即將刷新頁面",
|
||||
"K9b332ab1": "請求前綴",
|
||||
"K3d78d483": "HTTP 標頭",
|
||||
"K17dc3a62": "數據日誌",
|
||||
"Ke429194e": "處理日誌",
|
||||
"K84ffb1dd": "輸入調用地址、消費者 IP 和消費者條件進行查找",
|
||||
"Kb147fabc": "新建",
|
||||
"K40ca4f2": "更新",
|
||||
"K3e7aa0ad": "內容",
|
||||
"K2f5fdf5e": "調用地址",
|
||||
"K1bc5e0a3": "消費者 IP",
|
||||
"K6f39ea21": "鑑權名稱",
|
||||
"K8c34c02f": "脫敏前",
|
||||
"K8e3d388d": "脫敏後"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
import { PageProColumns } from "@common/components/aoplatform/PageList";
|
||||
import { COLUMNS_TITLE } from "@common/const/const";
|
||||
import { EntityItem } from "@common/const/type";
|
||||
|
||||
export type PartitionConfigFieldType = {
|
||||
@@ -113,22 +115,43 @@ export type PartitionDashboardConfigFieldType = {
|
||||
addr: string
|
||||
}
|
||||
}
|
||||
export type PartitionDataLogHeaderListFieldType = {
|
||||
key: string
|
||||
value: string
|
||||
|
||||
}
|
||||
export type PartitionDataLogConfigFieldType = {
|
||||
create_time: string
|
||||
id: string
|
||||
update_time: string
|
||||
updater: {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
creator: {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
config: {
|
||||
headers: {
|
||||
[k: string]: string
|
||||
headers: PartitionDataLogHeaderListFieldType[]
|
||||
url: string
|
||||
}
|
||||
|
||||
export const PARTITION_DATA_LOG_CONFIG_TABLE_COLUMNS: PageProColumns<PartitionDataLogConfigFieldType & { _id: string }>[] = [
|
||||
{
|
||||
title: ('标签'),
|
||||
dataIndex: 'key',
|
||||
formItemProps: {
|
||||
className: 'p-0 bg-transparent border-none',
|
||||
rootClassName: 'test',
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
whitespace: true
|
||||
},
|
||||
],
|
||||
},
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: ('内容'),
|
||||
dataIndex: 'value',
|
||||
formItemProps: {
|
||||
className: 'p-0 bg-transparent border-none'
|
||||
}
|
||||
url: string
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: COLUMNS_TITLE.operate,
|
||||
valueType: 'option',
|
||||
btnNums: 2,
|
||||
render: () => null
|
||||
},
|
||||
];
|
||||
@@ -3,7 +3,7 @@ import { useEffect } from "react";
|
||||
import { PartitionDashboardConfigFieldType } from "../../const/partitions/types";
|
||||
import { DASHBOARD_SETTING_DRIVER_OPTION_LIST } from "../../const/partitions/const";
|
||||
import WithPermission from "@common/components/aoplatform/WithPermission";
|
||||
import { BasicResponse, PLACEHOLDER, STATUS_CODE, VALIDATE_MESSAGE } from "@common/const/const";
|
||||
import { BasicResponse, PLACEHOLDER, STATUS_CODE } from "@common/const/const";
|
||||
import { useFetch } from "@common/hooks/http";
|
||||
import { $t } from "@common/locales";
|
||||
|
||||
@@ -29,10 +29,10 @@ export type DashboardSettingEditProps = {
|
||||
fetchData<BasicResponse<{info: PartitionDashboardConfigFieldType}>>('monitor/config',{method: 'POST',body:JSON.stringify(value),eoParams:{}}).then(response=>{
|
||||
const {code,msg} = response
|
||||
if(code === STATUS_CODE.SUCCESS){
|
||||
message.success(msg || '操作成功,即将刷新页面')
|
||||
message.success(msg || $t('操作成功,即将刷新页面'))
|
||||
refreshData?.()
|
||||
}else{
|
||||
message.error(msg || '操作失败')
|
||||
message.error(msg || $t('操作失败'))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,18 +1,90 @@
|
||||
import { PartitionDataLogConfigFieldType } from "@core/const/partitions/types"
|
||||
import EditableTable from "@common/components/aoplatform/EditableTable"
|
||||
import WithPermission from "@common/components/aoplatform/WithPermission"
|
||||
import { BasicResponse, PLACEHOLDER, STATUS_CODE } from "@common/const/const"
|
||||
import { useFetch } from "@common/hooks/http"
|
||||
import { $t } from "@common/locales"
|
||||
import { PARTITION_DATA_LOG_CONFIG_TABLE_COLUMNS, PartitionDataLogConfigFieldType, PartitionDataLogHeaderListFieldType } from "@core/const/partitions/types"
|
||||
import { Button, Form, Input, message } from "antd"
|
||||
import { useEffect } from "react"
|
||||
|
||||
export type DashboardPageShowStatus = 'view'|'edit'
|
||||
export type DashboardPageShowStatus = 'view' | 'edit'
|
||||
export type DashboardSettingEditProps = {
|
||||
changeStatus:(status:DashboardPageShowStatus)=>void
|
||||
refreshData:()=>void
|
||||
data?:PartitionDataLogConfigFieldType
|
||||
changeStatus: (status: DashboardPageShowStatus) => void
|
||||
refreshData: () => void
|
||||
data?: PartitionDataLogConfigFieldType
|
||||
}
|
||||
const DataLogSettingEdit = (props:DashboardSettingEditProps) => {
|
||||
const {changeStatus,refreshData,data} = props
|
||||
return (
|
||||
<div>
|
||||
222
|
||||
</div>
|
||||
);
|
||||
const DataLogSettingEdit = (props: DashboardSettingEditProps) => {
|
||||
const { changeStatus, refreshData, data } = props
|
||||
const [form] = Form.useForm();
|
||||
const { fetchData } = useFetch()
|
||||
|
||||
const onFinish = () => {
|
||||
form.validateFields().then((value) => {
|
||||
const formData = {
|
||||
config: {
|
||||
url: value.url,
|
||||
headers: value.headers.filter((item: PartitionDataLogHeaderListFieldType) => item.key).map((item: PartitionDataLogHeaderListFieldType) => ({key:item.key, value:item.value || ''}))
|
||||
}
|
||||
}
|
||||
fetchData<BasicResponse<{ info: PartitionDataLogConfigFieldType }>>('log/loki', { method: 'POST', body: JSON.stringify(formData), eoParams: {} }).then(response => {
|
||||
const { code, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
message.success(msg || $t('操作成功,即将刷新页面'))
|
||||
refreshData?.()
|
||||
} else {
|
||||
message.error(msg || $t('操作失败'))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => { form.setFieldsValue(data) }, [data])
|
||||
|
||||
useEffect(() => {
|
||||
return (form.setFieldsValue({}))
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<div className="overflow-auto h-full">
|
||||
<WithPermission access={''} >
|
||||
<Form
|
||||
form={form}
|
||||
className="mx-auto flex flex-col justify-between h-full"
|
||||
layout="vertical"
|
||||
onFinish={onFinish}
|
||||
autoComplete="off"
|
||||
>
|
||||
<Form.Item<PartitionDataLogConfigFieldType>
|
||||
label={$t("请求前缀")}
|
||||
name="url"
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<Input className="w-INPUT_NORMAL" placeholder={$t(PLACEHOLDER.input)} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item<PartitionDataLogConfigFieldType>
|
||||
label={$t("HTTP 头部")}
|
||||
name="headers"
|
||||
>
|
||||
<EditableTable<PartitionDataLogConfigFieldType & { _id: string }>
|
||||
configFields={PARTITION_DATA_LOG_CONFIG_TABLE_COLUMNS}
|
||||
/>
|
||||
</Form.Item>
|
||||
<div className="flex gap-btnbase">
|
||||
<WithPermission access='system.devops.data_source.edit'>
|
||||
<Button type="primary" htmlType="submit">
|
||||
{$t('保存')}
|
||||
</Button>
|
||||
</WithPermission>
|
||||
<Button type="default" onClick={() => changeStatus('view')}>
|
||||
{$t('取消')}
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
</WithPermission>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default DataLogSettingEdit;
|
||||
@@ -8,7 +8,7 @@ import { LoadingOutlined } from "@ant-design/icons";
|
||||
import InsidePage from "@common/components/aoplatform/InsidePage.tsx";
|
||||
import { $t } from "@common/locales/index.ts";
|
||||
import DashboardSettingEdit, { DashboardPageShowStatus } from "./DashboardSettingEdit.tsx";
|
||||
import { PartitionDashboardConfigFieldType, PartitionDataLogConfigFieldType } from "@core/const/partitions/types.ts";
|
||||
import { PARTITION_DATA_LOG_CONFIG_TABLE_COLUMNS, PartitionDashboardConfigFieldType, PartitionDataLogConfigFieldType } from "@core/const/partitions/types.ts";
|
||||
import PageList from "@common/components/aoplatform/PageList.tsx";
|
||||
import DataLogSettingEdit from "./DataLogSettingEdit.tsx";
|
||||
|
||||
@@ -43,10 +43,11 @@ const PartitionInsideDashboardSetting: FC = () => {
|
||||
setDataLogLoading(true)
|
||||
return fetchData<BasicResponse<{ nodes: PartitionDataLogConfigFieldType[] }>>('log/loki', { method: 'GET', eoTransformKeys: [] }).then(response => {
|
||||
const { code, data, msg } = response
|
||||
console.log('data====', data);
|
||||
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
data?.info && setDataLogData(data.info)
|
||||
data?.info && setDataLogData({
|
||||
url: data.info?.config?.url || '',
|
||||
headers: data.info?.config?.headers || []
|
||||
})
|
||||
setShowDataLogStatus('view')
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
@@ -66,10 +67,17 @@ const PartitionInsideDashboardSetting: FC = () => {
|
||||
getDataLogSettingInfo()
|
||||
}, []);
|
||||
|
||||
const setDashboardSettingBtn = (type: string) => {
|
||||
const setDashboardSettingBtn = () => {
|
||||
return (<>
|
||||
{showGraphStatus === 'view' && <WithPermission access="system.devops.data_source.edit" key="changeClusterConfig">
|
||||
<Button type="primary" onClick={() => type === 'graph' ? setShowGraphStatus('edit') : setShowDataLogStatus('edit')}>{$t('修改配置')}</Button>
|
||||
<Button type="primary" onClick={() => setShowGraphStatus('edit')}>{$t('修改配置')}</Button>
|
||||
</WithPermission>}</>
|
||||
)
|
||||
}
|
||||
const setDataLogSettingBtn = () => {
|
||||
return (<>
|
||||
{showDataLogStatus === 'view' && <WithPermission access="system.devops.data_source.edit" key="changeClusterConfig">
|
||||
<Button type="primary" onClick={() => setShowDataLogStatus('edit')}>{$t('修改配置')}</Button>
|
||||
</WithPermission>}</>
|
||||
)
|
||||
}
|
||||
@@ -94,7 +102,7 @@ const PartitionInsideDashboardSetting: FC = () => {
|
||||
{!loading && !data?.driver && <Tag color='#f50'>{$t('未配置')}
|
||||
</Tag>}</div>}
|
||||
|
||||
extra={setDashboardSettingBtn('graph')}>
|
||||
extra={setDashboardSettingBtn()}>
|
||||
{showGraphStatus === 'view' && data && data.driver && DashboardConfigPreview(data)}
|
||||
{showGraphStatus !== 'view' && <DashboardSettingEdit data={data} changeStatus={setShowGraphStatus} refreshData={getDashboardSettingInfo} />}
|
||||
</Card>
|
||||
@@ -111,7 +119,7 @@ const PartitionInsideDashboardSetting: FC = () => {
|
||||
{!dataLogLoading && !dataLogData && <Tag color='#f50'>{$t('未配置')}
|
||||
</Tag>}</div>}
|
||||
|
||||
extra={setDashboardSettingBtn('log')}>
|
||||
extra={setDataLogSettingBtn()}>
|
||||
{showDataLogStatus === 'view' && dataLogData && DataLogConfigPreview(dataLogData)}
|
||||
{showDataLogStatus !== 'view' && <DataLogSettingEdit data={dataLogData} changeStatus={setShowDataLogStatus} refreshData={getDataLogSettingInfo} />}
|
||||
</Card>
|
||||
@@ -131,39 +139,29 @@ export function DashboardConfigPreview(x: PartitionDashboardConfigFieldType) {
|
||||
</div>
|
||||
}
|
||||
export function DataLogConfigPreview(x: PartitionDataLogConfigFieldType) {
|
||||
const columns = [
|
||||
{
|
||||
title: '标签',
|
||||
dataIndex: 'tag',
|
||||
},
|
||||
{
|
||||
title: '内容',
|
||||
dataIndex: 'content'
|
||||
const columns = PARTITION_DATA_LOG_CONFIG_TABLE_COLUMNS.map(x => {
|
||||
return {
|
||||
...x,
|
||||
title: (<span title={$t(x.title as string)}>{$t(x.title as string)}</span>)
|
||||
}
|
||||
]
|
||||
})
|
||||
const getTableList = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve({
|
||||
data: x?.config?.headers ? Object.keys(x?.config?.headers).map((key) => {
|
||||
return {
|
||||
tag: key,
|
||||
content: x?.config?.headers[key]
|
||||
}
|
||||
}) : [],
|
||||
data: x?.headers || [],
|
||||
success: true
|
||||
})
|
||||
})
|
||||
}
|
||||
console.log(getTableList());
|
||||
|
||||
return <div className="flex flex-col gap-[4px] ">
|
||||
<Row className=""><Col className="font-bold text-right pr-[4px]">{$t('请求前缀')}:</Col><Col>{x?.config?.url}</Col></Row>
|
||||
<Row className=""><Col className="font-bold text-right pr-[4px]">{$t('请求前缀')}:</Col><Col>{x?.url}</Col></Row>
|
||||
<Row className=""><Col className="font-bold text-right pr-[4px]">{$t('HTTP 头部')}:</Col><Col className="w-full">
|
||||
<div className="w-full h-full p-[20px]">
|
||||
<PageList
|
||||
id="global_role"
|
||||
tableClass="role_table mb-btnrbase"
|
||||
primaryKey="'tag'"
|
||||
primaryKey="'key'"
|
||||
columns={[...columns]}
|
||||
request={() => getTableList()}
|
||||
showPagination={false}
|
||||
|
||||
@@ -233,7 +233,6 @@ const DataMasking = (props: any) => {
|
||||
* @param entity
|
||||
*/
|
||||
const openLogsModal = (entity: any) => {
|
||||
console.log('日志', entity);
|
||||
setStrategy(entity.id)
|
||||
setModalVisible(true)
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ export const DATA_MASKING_TABLE_LOG_COLUMNS: PageProColumns<any>[] = [
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: ('消费者IP'),
|
||||
title: ('消费者 IP'),
|
||||
dataIndex: 'remote_ip',
|
||||
ellipsis: true,
|
||||
width: 100
|
||||
@@ -103,7 +103,7 @@ export const DATA_MASKING_TABLE_LOG_COLUMNS: PageProColumns<any>[] = [
|
||||
{
|
||||
title: ('时间'),
|
||||
dataIndex: 'record_time',
|
||||
width: 150,
|
||||
width: 110,
|
||||
ellipsis: true
|
||||
},
|
||||
]
|
||||
|
||||
@@ -62,7 +62,7 @@ const DataMaskingCompare = () => {
|
||||
<div className="flex h-full overflow-hidden">
|
||||
<div className="w-1/2 p-2 h-full">
|
||||
<div className="h-[30px] bg-gray-200 mb-2 flex items-center justify-center">
|
||||
脱敏前
|
||||
{$t('脱敏前')}
|
||||
</div>
|
||||
<div style={{ height: 'calc(100vh - 50px)' }}>
|
||||
<Codebox
|
||||
@@ -77,7 +77,7 @@ const DataMaskingCompare = () => {
|
||||
</div>
|
||||
<div className="w-1/2 p-2 h-full">
|
||||
<div className="h-[30px] bg-green-100 mb-2 flex items-center justify-center">
|
||||
脱敏后
|
||||
{$t('脱敏后')}
|
||||
</div>
|
||||
<div style={{ height: 'calc(100vh - 50px)' }}>
|
||||
<Codebox
|
||||
|
||||
@@ -57,7 +57,7 @@ const DataMaskingLogModal = (props: any) => {
|
||||
*/
|
||||
const operation: PageProColumns<any>[] = [
|
||||
{
|
||||
title: '操作',
|
||||
title: '',
|
||||
key: 'option',
|
||||
btnNums: 1,
|
||||
fixed: 'right',
|
||||
@@ -89,7 +89,7 @@ const DataMaskingLogModal = (props: any) => {
|
||||
}
|
||||
return {
|
||||
...x,
|
||||
title: typeof x.title === 'string' ? $t(x.title as string) : x.title
|
||||
title: (<span title={$t(x.title as string)}>{$t(x.title as string)}</span>)
|
||||
}
|
||||
})
|
||||
return res
|
||||
|
||||
Reference in New Issue
Block a user