mirror of
https://github.com/didi/KnowStreaming.git
synced 2025-12-24 11:52:08 +08:00
修复前端新增角色失败等问题 (#1107)
1.新增角色不选择系统管理权限点报错问题; 2.Connect配置项里面涉及敏感字段的值用*号代替; 3.Topic详情、ConsumerGroup详情,ConsumerGroup表格支持手动刷; 4.Topic Message预览,Offset为0不显示数值,添加offset排序; --------- Co-authored-by: 孙超 <jacksuny@foxmail.com> Co-authored-by: EricZeng <zengqiao_cn@163.com>
This commit is contained in:
@@ -96,7 +96,7 @@ const RoleDetailAndUpdate = forwardRef((props, ref): JSX.Element => {
|
|||||||
arr.push(permissions[i].id);
|
arr.push(permissions[i].id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
formData.permissionIdList = formData.permissionIdList.flat();
|
formData.permissionIdList = formData.permissionIdList.flat().filter((item) => item !== undefined);
|
||||||
setConfirmLoading(true);
|
setConfirmLoading(true);
|
||||||
request(api.editRole, {
|
request(api.editRole, {
|
||||||
method: type === RoleOperate.Add ? 'POST' : 'PUT',
|
method: type === RoleOperate.Add ? 'POST' : 'PUT',
|
||||||
@@ -250,7 +250,7 @@ const RoleDetailAndUpdate = forwardRef((props, ref): JSX.Element => {
|
|||||||
<CheckboxGroupContainer
|
<CheckboxGroupContainer
|
||||||
key={i}
|
key={i}
|
||||||
formInstance={form}
|
formInstance={form}
|
||||||
fieldName="permissionIdList"
|
fieldName={`permissionIdList`}
|
||||||
options={permission.options}
|
options={permission.options}
|
||||||
initSelectedOptions={initSelectedPermissions[permission.id] || []}
|
initSelectedOptions={initSelectedPermissions[permission.id] || []}
|
||||||
groupIdx={i}
|
groupIdx={i}
|
||||||
|
|||||||
@@ -34,11 +34,11 @@ module.exports = {
|
|||||||
proxy: {
|
proxy: {
|
||||||
'/ks-km/api/v3': {
|
'/ks-km/api/v3': {
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
target: 'https://api-kylin-xg02.intra.xiaojukeji.com/ks-km/',
|
target: 'http://127.0.0.1/',
|
||||||
},
|
},
|
||||||
'/logi-security/api/v1': {
|
'/logi-security/api/v1': {
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
target: 'https://api-kylin-xg02.intra.xiaojukeji.com/ks-km/',
|
target: 'http://127.0.0.1/',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
|
export function useForceRefresh() {
|
||||||
|
const [refreshKey, setRefresh] = useState<number>(0);
|
||||||
|
const forceRefresh: () => void = useCallback(() => {
|
||||||
|
setRefresh((x) => x + 1);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return [refreshKey, forceRefresh];
|
||||||
|
}
|
||||||
@@ -816,6 +816,8 @@ const StepFormFifth = (props: SubFormProps) => {
|
|||||||
<InputNumber />
|
<InputNumber />
|
||||||
) : type.toUpperCase() === 'BOOLEAN' ? (
|
) : type.toUpperCase() === 'BOOLEAN' ? (
|
||||||
<Switch size="small" />
|
<Switch size="small" />
|
||||||
|
) : type.toUpperCase() === 'PASSWORD' ? (
|
||||||
|
<Input.Password />
|
||||||
) : (
|
) : (
|
||||||
<Input />
|
<Input />
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useParams, useHistory } from 'react-router-dom';
|
import { useParams, useHistory } from 'react-router-dom';
|
||||||
import { Drawer, ProTable, Utils } from 'knowdesign';
|
import { Button, Space, Divider, Drawer, ProTable, Utils } from 'knowdesign';
|
||||||
import { IconFont } from '@knowdesign/icons';
|
import { IconFont } from '@knowdesign/icons';
|
||||||
import API from '@src/api/index';
|
import API from '@src/api/index';
|
||||||
import { defaultPagination, hashDataParse } from '@src/constants/common';
|
import { defaultPagination, hashDataParse } from '@src/constants/common';
|
||||||
import { getGtoupTopicColumns } from './config';
|
import { getGtoupTopicColumns } from './config';
|
||||||
import { ExpandedRow } from './ExpandedRow';
|
import { ExpandedRow } from './ExpandedRow';
|
||||||
import ResetOffsetDrawer from './ResetOffsetDrawer';
|
import ResetOffsetDrawer from './ResetOffsetDrawer';
|
||||||
|
import { useForceRefresh } from '@src/components/utils';
|
||||||
const { request } = Utils;
|
const { request } = Utils;
|
||||||
|
|
||||||
export interface MetricLine {
|
export interface MetricLine {
|
||||||
@@ -63,6 +64,7 @@ const GroupDetail = (props: any) => {
|
|||||||
const [openKeys, setOpenKeys] = useState();
|
const [openKeys, setOpenKeys] = useState();
|
||||||
const [resetOffsetVisible, setResetOffsetVisible] = useState(false);
|
const [resetOffsetVisible, setResetOffsetVisible] = useState(false);
|
||||||
const [resetOffsetArg, setResetOffsetArg] = useState({});
|
const [resetOffsetArg, setResetOffsetArg] = useState({});
|
||||||
|
const [refreshKey, forceRefresh] = useForceRefresh();
|
||||||
|
|
||||||
const genData = async ({ pageNo, pageSize, groupName }: any) => {
|
const genData = async ({ pageNo, pageSize, groupName }: any) => {
|
||||||
if (urlParams?.clusterId === undefined) return;
|
if (urlParams?.clusterId === undefined) return;
|
||||||
@@ -160,7 +162,7 @@ const GroupDetail = (props: any) => {
|
|||||||
// // 获取Consumer列表 表格模式
|
// // 获取Consumer列表 表格模式
|
||||||
// getTopicGroupMetric(hashData);
|
// getTopicGroupMetric(hashData);
|
||||||
// });
|
// });
|
||||||
}, [hashDataParse(location.hash).groupName]);
|
}, [hashDataParse(location.hash).groupName, refreshKey]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<Drawer
|
||||||
@@ -182,6 +184,14 @@ const GroupDetail = (props: any) => {
|
|||||||
// <Divider type="vertical" />
|
// <Divider type="vertical" />
|
||||||
// </Space>
|
// </Space>
|
||||||
// }
|
// }
|
||||||
|
extra={
|
||||||
|
<Space>
|
||||||
|
<span style={{ display: 'inline-block', fontSize: '15px' }} onClick={forceRefresh as () => void}>
|
||||||
|
<i className="iconfont icon-shuaxin1" style={{ cursor: 'pointer' }} />
|
||||||
|
</span>
|
||||||
|
<Divider type="vertical" />
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<ProTable
|
<ProTable
|
||||||
showQueryForm={false}
|
showQueryForm={false}
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ const AddDrawer = forwardRef((_, ref) => {
|
|||||||
|
|
||||||
if (configType === 'custom') {
|
if (configType === 'custom') {
|
||||||
// 1. 自定义权限
|
// 1. 自定义权限
|
||||||
|
// TODO: 需要和后端联调
|
||||||
const { resourceType, resourcePatternType, aclPermissionType, aclOperation, aclClientHost } = formData;
|
const { resourceType, resourcePatternType, aclPermissionType, aclOperation, aclClientHost } = formData;
|
||||||
submitData.push({
|
submitData.push({
|
||||||
clusterId,
|
clusterId,
|
||||||
@@ -281,6 +282,42 @@ const AddDrawer = forwardRef((_, ref) => {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item dependencies={['configType']} style={{ marginBottom: 0 }}>
|
<Form.Item dependencies={['configType']} style={{ marginBottom: 0 }}>
|
||||||
{({ getFieldValue }) => {
|
{({ getFieldValue }) => {
|
||||||
|
const SelectFormItems = (props: { type: string }) => {
|
||||||
|
const { type } = props;
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
name={`${type}Name`}
|
||||||
|
dependencies={[`${type}PatternType`]}
|
||||||
|
validateTrigger="onBlur"
|
||||||
|
rules={[
|
||||||
|
({ getFieldValue }) => ({
|
||||||
|
validator: (rule: any, value: string) => {
|
||||||
|
if (!value) {
|
||||||
|
return Promise.reject(`${type}Name 不能为空`);
|
||||||
|
}
|
||||||
|
if (type === 'topic' && getFieldValue(`${type}PatternType`) === ACL_PATTERN_TYPE['Literal']) {
|
||||||
|
return Utils.request(api.getTopicMetadata(clusterId as any, value)).then((res: any) => {
|
||||||
|
return res?.exist ? Promise.resolve() : Promise.reject('该 Topic 不存在');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<AutoComplete
|
||||||
|
filterOption={(value, option) => {
|
||||||
|
if (option?.value.includes(value)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}}
|
||||||
|
options={type === 'topic' ? topicMetaData : groupMetaData}
|
||||||
|
placeholder={`请输入 ${type}Name`}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
};
|
||||||
const PatternTypeFormItems = (props: { type: string }) => {
|
const PatternTypeFormItems = (props: { type: string }) => {
|
||||||
const { type } = props;
|
const { type } = props;
|
||||||
const UpperCaseType = type[0].toUpperCase() + type.slice(1);
|
const UpperCaseType = type[0].toUpperCase() + type.slice(1);
|
||||||
@@ -388,6 +425,27 @@ const AddDrawer = forwardRef((_, ref) => {
|
|||||||
}))}
|
}))}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item dependencies={['resourceType']}>
|
||||||
|
{({ getFieldValue }) => {
|
||||||
|
const type = getFieldValue('resourceType');
|
||||||
|
if (type === ACL_RESOURCE_TYPE['Cluster'] || type === ACL_RESOURCE_TYPE['TransactionalId']) {
|
||||||
|
//TODO需要和后端获取集群和事务接口联调
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
name={`${type === 4 ? 'cluster' : 'transactionalId'}`}
|
||||||
|
rules={[{ required: true, message: `${type === 4 ? 'Cluster名称' : 'TransactionalId'} 不能为空` }]}
|
||||||
|
>
|
||||||
|
<Input placeholder={`请输入${type === 4 ? 'Cluster名称' : 'TransactionalId'}`}></Input>
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
} else if (type === ACL_RESOURCE_TYPE['Topic']) {
|
||||||
|
return <PatternTypeFormItems type="topic" />;
|
||||||
|
} else if (type === ACL_RESOURCE_TYPE['Group']) {
|
||||||
|
return <PatternTypeFormItems type="group" />;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
<Form.Item dependencies={['resourceType']} style={{ marginBottom: 0 }}>
|
<Form.Item dependencies={['resourceType']} style={{ marginBottom: 0 }}>
|
||||||
{({ getFieldValue }) => {
|
{({ getFieldValue }) => {
|
||||||
form.resetFields(['aclOperation']);
|
form.resetFields(['aclOperation']);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { useParams } from 'react-router-dom';
|
|||||||
import TagsWithHide from '@src/components/TagsWithHide';
|
import TagsWithHide from '@src/components/TagsWithHide';
|
||||||
import SwitchTab from '@src/components/SwitchTab';
|
import SwitchTab from '@src/components/SwitchTab';
|
||||||
import RenderEmpty from '@src/components/RenderEmpty';
|
import RenderEmpty from '@src/components/RenderEmpty';
|
||||||
|
import { useForceRefresh } from '@src/components/utils';
|
||||||
|
|
||||||
interface PropsType {
|
interface PropsType {
|
||||||
hashData: any;
|
hashData: any;
|
||||||
@@ -401,11 +402,18 @@ export default (props: PropsType) => {
|
|||||||
const { hashData } = props;
|
const { hashData } = props;
|
||||||
const [showMode, setShowMode] = useState<string>('card');
|
const [showMode, setShowMode] = useState<string>('card');
|
||||||
|
|
||||||
|
const [refreshKey, forceRefresh] = useForceRefresh();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="brokers-tab-container">
|
<div className="brokers-tab-container" key={`${refreshKey}`}>
|
||||||
<div className="overview">
|
<div className="overview">
|
||||||
<div className="left">
|
<div className="left">
|
||||||
|
<span
|
||||||
|
style={{ display: 'inline-block', padding: '0 10px', marginRight: '10px', borderRight: '1px solid #ccc', fontSize: '15px' }}
|
||||||
|
onClick={forceRefresh as () => void}
|
||||||
|
>
|
||||||
|
<i className="iconfont icon-shuaxin1" style={{ cursor: 'pointer' }} />
|
||||||
|
</span>
|
||||||
<PartitionSummary clusterId={clusterId} topicName={hashData.topicName} />
|
<PartitionSummary clusterId={clusterId} topicName={hashData.topicName} />
|
||||||
</div>
|
</div>
|
||||||
<div className="cases-box">
|
<div className="cases-box">
|
||||||
|
|||||||
@@ -81,7 +81,8 @@ export const getTopicMessagesColmns = () => {
|
|||||||
title: 'Offset',
|
title: 'Offset',
|
||||||
dataIndex: 'offset',
|
dataIndex: 'offset',
|
||||||
key: 'offset',
|
key: 'offset',
|
||||||
render: (t: number) => (t ? t.toLocaleString() : '-'),
|
sorter: true,
|
||||||
|
render: (t: number) => (+t ? t.toLocaleString() : '-'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Timestamp',
|
title: 'Timestamp',
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
.left {
|
.left {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
.info-box {
|
.info-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
|
|||||||
@@ -15,9 +15,21 @@ import Replicator from './Replicator';
|
|||||||
import './index.less';
|
import './index.less';
|
||||||
import TopicDetailHealthCheck from '@src/components/CardBar/TopicDetailHealthCheck';
|
import TopicDetailHealthCheck from '@src/components/CardBar/TopicDetailHealthCheck';
|
||||||
import { hashDataParse } from '@src/constants/common';
|
import { hashDataParse } from '@src/constants/common';
|
||||||
|
import { useForceRefresh } from '@src/components/utils';
|
||||||
|
|
||||||
const { TabPane } = Tabs;
|
const { TabPane } = Tabs;
|
||||||
|
|
||||||
|
const Reload = (props: any) => {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
style={{ display: 'inline-block', padding: '0 10px', marginRight: '10px', borderRight: '1px solid #ccc', fontSize: '15px' }}
|
||||||
|
onClick={props.forceRefresh as () => void}
|
||||||
|
>
|
||||||
|
<i className="iconfont icon-shuaxin1" style={{ cursor: 'pointer' }} />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const OperationsSlot: any = {
|
const OperationsSlot: any = {
|
||||||
// eslint-disable-next-line react/display-name
|
// eslint-disable-next-line react/display-name
|
||||||
// ['Partitions']: (arg: any) => {
|
// ['Partitions']: (arg: any) => {
|
||||||
@@ -70,17 +82,20 @@ const OperationsSlot: any = {
|
|||||||
// eslint-disable-next-line react/display-name
|
// eslint-disable-next-line react/display-name
|
||||||
['ConsumerGroups']: (arg: any) => {
|
['ConsumerGroups']: (arg: any) => {
|
||||||
return (
|
return (
|
||||||
<SearchInput
|
<>
|
||||||
onSearch={arg.setSearchKeywords}
|
<Reload {...arg} />
|
||||||
attrs={{
|
<SearchInput
|
||||||
value: arg.searchValue,
|
onSearch={arg.setSearchKeywords}
|
||||||
onChange: arg.setSearchValue,
|
attrs={{
|
||||||
placeholder: '请输入Consumer Group',
|
value: arg.searchValue,
|
||||||
size: 'small',
|
onChange: arg.setSearchValue,
|
||||||
style: { width: '210px', marginRight: '2px' },
|
placeholder: '请输入Consumer Group',
|
||||||
maxLength: 128,
|
size: 'small',
|
||||||
}}
|
style: { width: '210px', marginRight: '2px' },
|
||||||
/>
|
maxLength: 128,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -94,6 +109,7 @@ const TopicDetail = (props: any) => {
|
|||||||
const [searchValue, setSearchValue] = useState<string>('');
|
const [searchValue, setSearchValue] = useState<string>('');
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const [hashData, setHashData] = useState<any>({});
|
const [hashData, setHashData] = useState<any>({});
|
||||||
|
const [refreshKey, forceRefresh] = useForceRefresh();
|
||||||
|
|
||||||
const callback = (key: any) => {
|
const callback = (key: any) => {
|
||||||
setSearchValue('');
|
setSearchValue('');
|
||||||
@@ -184,7 +200,7 @@ const TopicDetail = (props: any) => {
|
|||||||
onChange={callback}
|
onChange={callback}
|
||||||
tabBarExtraContent={
|
tabBarExtraContent={
|
||||||
OperationsSlot[positionType] &&
|
OperationsSlot[positionType] &&
|
||||||
OperationsSlot[positionType]({ ...props, setSearchKeywords, setSearchValue, searchValue, positionType })
|
OperationsSlot[positionType]({ ...props, setSearchKeywords, setSearchValue, searchValue, positionType, forceRefresh })
|
||||||
}
|
}
|
||||||
destroyInactiveTabPane
|
destroyInactiveTabPane
|
||||||
>
|
>
|
||||||
@@ -196,7 +212,7 @@ const TopicDetail = (props: any) => {
|
|||||||
</TabPane>
|
</TabPane>
|
||||||
<TabPane tab="ConsumerGroups" key="ConsumerGroups">
|
<TabPane tab="ConsumerGroups" key="ConsumerGroups">
|
||||||
{positionType === 'ConsumerGroups' && (
|
{positionType === 'ConsumerGroups' && (
|
||||||
<Consumers searchKeywords={searchKeywords} positionType={positionType} hashData={hashData} />
|
<Consumers searchKeywords={searchKeywords} positionType={positionType} hashData={hashData} key={`${refreshKey}`} />
|
||||||
)}
|
)}
|
||||||
</TabPane>
|
</TabPane>
|
||||||
<TabPane tab="ACLs" key="ACLs">
|
<TabPane tab="ACLs" key="ACLs">
|
||||||
|
|||||||
Reference in New Issue
Block a user