From 6c78c5abfabffc3841c4db4d853685b856eabfd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=B4=E6=99=96?= <2689991790@qq.com> Date: Mon, 18 Mar 2024 19:23:56 +0800 Subject: [PATCH 1/3] feat:Edit resource pool --- ui/src/components/ClassSelect/index.tsx | 104 ----------- ui/src/components/SelectWithTooltip/index.tsx | 66 +++++++ .../customModal/ModifyUnitDetailModal.tsx | 172 ++++++++++++++---- ui/src/pages/Cluster/New/Observer.tsx | 72 ++++++-- .../pages/Tenant/Detail/Overview/Replicas.tsx | 93 ++++++---- ui/src/pages/Tenant/Detail/Overview/index.tsx | 17 +- ui/src/pages/Tenant/New/ResourcePools.tsx | 4 +- ui/src/pages/Tenant/helper.ts | 8 +- ui/src/services/index.ts | 6 +- ui/src/services/typings.d.ts | 19 +- 10 files changed, 364 insertions(+), 197 deletions(-) delete mode 100644 ui/src/components/ClassSelect/index.tsx create mode 100644 ui/src/components/SelectWithTooltip/index.tsx diff --git a/ui/src/components/ClassSelect/index.tsx b/ui/src/components/ClassSelect/index.tsx deleted file mode 100644 index 47b51c1bb..000000000 --- a/ui/src/components/ClassSelect/index.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import { intl } from '@/utils/intl'; -import { Select, Tooltip } from 'antd'; - -interface ClassSelectProps { - selectList: { - value: string; - label: string; - toolTipData: any; - }[]; - form: any; - name: string | number | (string | number)[]; -} - -export default function ClassSelect({ - selectList, - form, - name, -}: ClassSelectProps) { - const filterOption = ( - input: string, - option: { label: string; value: string }, - ) =>{ - return (option?.value ?? '').toLowerCase().includes(input.toLowerCase()); - } - - const formatData = (list: any) => { - list.forEach((item: any) => { - item.label = ( - - {item.toolTipData.map((data: any) => { - let key = Object.keys(data)[0]; - if (typeof data[key] === 'string') { - return ( - - - {key}: - {data[key]} - - - ); - } else { - let value = JSON.stringify(data[key]) || String(data[key]); - return ( - - - {key}: - {value} - - - ); - } - })} - - } - > - {item.value} - - ); - }); - return list; - }; - - const selectChange = (val: string) => { - form.setFieldValue(name, val); - form.validateFields([name]); - }; - - return ( - - ); -} diff --git a/ui/src/components/SelectWithTooltip/index.tsx b/ui/src/components/SelectWithTooltip/index.tsx new file mode 100644 index 000000000..4590ffb11 --- /dev/null +++ b/ui/src/components/SelectWithTooltip/index.tsx @@ -0,0 +1,66 @@ +import { intl } from '@/utils/intl'; +import { Select, Tooltip } from 'antd'; + +interface SelectWithTooltipProps { + selectList: API.TooltipData[]; + form: any; + name: string | number | (string | number)[]; + TooltipItemContent: (item: API.TooltipData) => JSX.Element; +} + +export default function SelectWithTooltip({ + selectList, + form, + name, + TooltipItemContent +}: SelectWithTooltipProps) { + const filterOption = ( + input: string, + option: { label: string; value: string }, + ) =>{ + return (option?.value ?? '').toLowerCase().includes(input.toLowerCase()); + } + + const formatData = (selectList: API.TooltipData[]) => { + selectList.forEach((item: API.TooltipData) => { + item.label = ( + } + > + {item.value} + + ); + }); + return selectList; + }; + + const selectChange = (val: string) => { + form.setFieldValue(name, val); + form.validateFields([name]); + }; + + return ( + + ); +} diff --git a/ui/src/components/customModal/ModifyUnitDetailModal.tsx b/ui/src/components/customModal/ModifyUnitDetailModal.tsx index 8955c2329..5c14eccb2 100644 --- a/ui/src/components/customModal/ModifyUnitDetailModal.tsx +++ b/ui/src/components/customModal/ModifyUnitDetailModal.tsx @@ -1,37 +1,55 @@ +import InputNumber from '@/components/InputNumber'; import { SUFFIX_UNIT } from '@/constants'; import { getNSName } from '@/pages/Cluster/Detail/Overview/helper'; +import { TooltipItemContent } from '@/pages/Cluster/New/Observer'; import type { MaxResourceType } from '@/pages/Tenant/New/ResourcePools'; import ZoneItem from '@/pages/Tenant/ZoneItem'; -import { findMinParameter,getNewClusterList } from '@/pages/Tenant/helper'; +import { findMinParameter,modifyZoneCheckedStatus } from '@/pages/Tenant/helper'; import { patchTenantConfiguration } from '@/services/tenant'; import { formatUnitDetailData } from '@/utils/helper'; import { intl } from '@/utils/intl'; import { useEffect,useState } from 'react'; -import InputNumber from '@/components/InputNumber'; +import SelectWithTooltip from '../SelectWithTooltip'; -import { Col, Form, Row, message } from 'antd'; +import { Col,Form,Row,message } from 'antd'; import type { CommonModalType } from '.'; import CustomModal from '.'; export type UnitDetailType = { unitConfig: { unitConfig: { - cpuCount: number|string; + cpuCount: number | string; iopsWeight: number; logDiskSize: number | string; maxIops: number; memorySize: number | string; minIops: number; }; - pools:any; + pools: any; }; }; +const formatReplicaList = ( + replicaList: API.ReplicaDetailType[], +): API.TooltipData[] => { + return replicaList.map((replica) => ({ + label: replica.zone, + value: replica.zone, + toolTipData: Object.keys(replica) + .filter((key) => key !== 'zone') + .map((key) => ({ [key]: replica[key] })), + })); +}; + type UnitConfigType = { clusterList?: API.SimpleClusterList; clusterResourceName?: string; essentialParameter?: API.EssentialParametersType; setClusterList: React.Dispatch>; + editZone?: string; + replicaList?: API.ReplicaDetailType[]; + newResourcePool?: boolean; + setEditZone?: React.Dispatch> }; export default function ModifyUnitDetailModal({ @@ -42,18 +60,33 @@ export default function ModifyUnitDetailModal({ setClusterList, essentialParameter = {}, clusterResourceName = '', + editZone, + replicaList, + newResourcePool = false, + setEditZone }: CommonModalType & UnitConfigType) { const [form] = Form.useForm(); const [minMemory, setMinMemory] = useState(2); const [maxResource, setMaxResource] = useState({}); - const [selectZones, setSelectZones] = useState([]); + const [selectZones, setSelectZones] = useState( + editZone ? [editZone] : [], + ); + const selectZone = Form.useWatch('selectZone', form); const handleSubmit = async () => { try { await form.validateFields(); form.submit(); } catch (err) {} }; - const handleCancel = () => setVisible(false); + const handleCancel = () => { + if (setEditZone) { + setEditZone(''); + setSelectZones([]); + } + form.resetFields(); + setVisible(false); + }; + const onFinish = async (values: any) => { const [ns, name] = getNSName(); const res = await patchTenantConfiguration({ @@ -62,28 +95,62 @@ export default function ModifyUnitDetailModal({ ...formatUnitDetailData(values), }); if (res.successful) { - message.success(res.message); + message.success(res.message || '修改成功'); successCallback(); form.resetFields(); setVisible(false); } }; const checkBoxOnChange = (checked: boolean, name: string) => { + if (!checked) { form.setFieldValue(['pools', name, 'priority'], undefined); setSelectZones(selectZones.filter((zone) => zone !== name)); } else { setSelectZones([...selectZones, name]); } + setClusterList( - getNewClusterList(clusterList, name, checked, { name: clusterResourceName }), + modifyZoneCheckedStatus(clusterList, name, checked, { + name: clusterResourceName, + }), ); }; - const targetZoneList = clusterList - .filter((cluster) => cluster.name === clusterResourceName)[0] - ?.topology.map((zone) => ({ zone: zone.zone, checked: zone.checked })); - + const getInitialValues = (editZone: string) => { + let result = {}; + const zone = replicaList?.find((replica) => replica.zone === editZone); + result.unitConfig = { + unitConfig: { + cpuCount: zone?.minCPU, + iopsWeight: zone?.iopsWeight, + logDiskSize: zone?.logDiskSize.split('Gi')[0], + maxIops: zone?.maxIops, + memorySize: zone?.memorySize.split('Gi')[0], + minIops: zone?.minIops, + }, + pools: {}, + }; + result.unitConfig.pools[editZone] = { + priority: zone?.priority, + }; + + return result; + }; + let targetCluster = clusterList.find( + (cluster) => cluster.name === clusterResourceName, + ); + let targetZoneList = + targetCluster?.topology.map((zone) => ({ + zone: zone.zone, + checked: zone.checked, + })) || []; + + if (editZone) { + targetZoneList = targetZoneList.filter((zone) => zone.zone === editZone); + } + + const selectOptions = formatReplicaList(replicaList || []); useEffect(() => { if (essentialParameter) { setMinMemory(essentialParameter.minPoolMemory / (1 << 30)); @@ -98,15 +165,30 @@ export default function ModifyUnitDetailModal({ } setMaxResource(findMinParameter(selectZones, essentialParameter)); } - }, [selectZones]); + }, [selectZones, essentialParameter]); + + useEffect(() => { + if (selectZone && replicaList) { + form.setFieldsValue(getInitialValues(selectZone)); + } + }, [selectZone]); + + useEffect(() => { + if (editZone && clusterResourceName) { + setClusterList( + modifyZoneCheckedStatus(clusterList, editZone, true, { + name: clusterResourceName, + }), + ); + form.setFieldsValue(getInitialValues(editZone)); + setSelectZones([editZone]); + } + }, [editZone]); return ( - {targetZoneList && essentialParameter && ( + {newResourcePool && selectOptions.length ? ( - - {intl.formatMessage({ - id: 'Dashboard.Tenant.New.ResourcePools.ZonePriority', - defaultMessage: 'Zone优先级', - })} - - {targetZoneList.map((item, index) => ( - + - ))} + + ) : ( + <> + {targetZoneList && essentialParameter && ( + + + {intl.formatMessage({ + id: 'Dashboard.Tenant.New.ResourcePools.ZonePriority', + defaultMessage: 'Zone优先级', + })} + + {targetZoneList.map((item, index) => ( + + ))} + + )} + > )} + { + return ( + + {item.toolTipData.map((data: any) => { + let key = Object.keys(data)[0]; + if (typeof data[key] === 'string') { + return ( + + + {key}: + {data[key]} + + + ); + } else { + let value = JSON.stringify(data[key]) || String(data[key]); + return ( + + + {key}: + {value} + + + ); + } + })} + + ); +}; + + export default function Observer({ storageClasses, form }: any) { const CustomItem = (prop: any) => { const { label } = prop; @@ -71,6 +113,7 @@ export default function Observer({ storageClasses, form }: any) { }); }; + return ( {storageClasses && ( - )} @@ -221,10 +265,11 @@ export default function Observer({ storageClasses, form }: any) { name={['observer', 'storage', 'log', 'storageClass']} > {storageClasses && ( - )} @@ -253,10 +298,11 @@ export default function Observer({ storageClasses, form }: any) { name={['observer', 'storage', 'redoLog', 'storageClass']} > {storageClasses && ( - )} diff --git a/ui/src/pages/Tenant/Detail/Overview/Replicas.tsx b/ui/src/pages/Tenant/Detail/Overview/Replicas.tsx index 888fd043c..bba95bb1b 100644 --- a/ui/src/pages/Tenant/Detail/Overview/Replicas.tsx +++ b/ui/src/pages/Tenant/Detail/Overview/Replicas.tsx @@ -3,42 +3,54 @@ import showDeleteConfirm from '@/components/customModal/DeleteModal'; import { getNSName } from '@/pages/Cluster/Detail/Overview/helper'; import { deleteObtenantPool } from '@/services/tenant'; import { intl } from '@/utils/intl'; -import { Button, Col, Descriptions, message } from 'antd'; +import { Button,Col,Descriptions,message } from 'antd'; +import type { OperateType } from '.'; import styles from './index.less'; +interface ReplicasProps { + replicaList: API.ReplicaDetailType[]; + refreshTenant: () => void; + openOperateModal: (type: API.ModalType) => void; + setEditZone: React.Dispatch>; + editZone: string; + operateType: React.MutableRefObject; +} + +const LABEL_TEXT_MAP = { + priority: intl.formatMessage({ + id: 'Dashboard.Detail.Overview.Replicas.Priority', + defaultMessage: '优先级', + }), + type: intl.formatMessage({ + id: 'Dashboard.Detail.Overview.Replicas.ReplicaType', + defaultMessage: '副本类型', + }), + maxCPU: intl.formatMessage({ + id: 'Dashboard.Detail.Overview.Replicas.MaximumAvailableCpu', + defaultMessage: '最大可用 CPU', + }), + memorySize: intl.formatMessage({ + id: 'Dashboard.Detail.Overview.Replicas.MemorySize', + defaultMessage: '内存大小', + }), + minCPU: intl.formatMessage({ + id: 'Dashboard.Detail.Overview.Replicas.MinimumAvailableCpu', + defaultMessage: '最小可用 CPU', + }), + logDiskSize: intl.formatMessage({ + id: 'Dashboard.Detail.Overview.Replicas.ClogDiskSize', + defaultMessage: 'Clog 盘大小', + }), +}; + export default function Replicas({ replicaList, refreshTenant, -}: { - replicaList: API.ReplicaDetailType[]; - refreshTenant: () => void; -}) { - const LABEL_TEXT_MAP = { - priority: intl.formatMessage({ - id: 'Dashboard.Detail.Overview.Replicas.Priority', - defaultMessage: '优先级', - }), - type: intl.formatMessage({ - id: 'Dashboard.Detail.Overview.Replicas.ReplicaType', - defaultMessage: '副本类型', - }), - maxCPU: intl.formatMessage({ - id: 'Dashboard.Detail.Overview.Replicas.MaximumAvailableCpu', - defaultMessage: '最大可用 CPU', - }), - memorySize: intl.formatMessage({ - id: 'Dashboard.Detail.Overview.Replicas.MemorySize', - defaultMessage: '内存大小', - }), - minCPU: intl.formatMessage({ - id: 'Dashboard.Detail.Overview.Replicas.MinimumAvailableCpu', - defaultMessage: '最小可用 CPU', - }), - logDiskSize: intl.formatMessage({ - id: 'Dashboard.Detail.Overview.Replicas.ClogDiskSize', - defaultMessage: 'Clog 盘大小', - }), - }; + openOperateModal, + setEditZone, + operateType, + editZone +}: ReplicasProps) { const sortKeys = (keys: string[]) => { const minCpuIdx = keys.findIndex((key) => key === 'minCPU'); const memorySizeIdx = keys.findIndex((key) => key === 'memorySize'); @@ -63,6 +75,17 @@ export default function Replicas({ } }; + const editResourcePool = (zone: string) => { + operateType.current = 'edit'; + setEditZone(zone); + openOperateModal('modifyUnitSpecification'); + }; + + const addResourcePool = ()=>{ + operateType.current = 'create'; + openOperateModal('modifyUnitSpecification'); + } + return ( } + extra={新增资源池} collapsible={true} defaultExpand={true} > @@ -93,7 +117,10 @@ export default function Replicas({ )} - + editResourcePool(replica.zone)} + type="link" + > {intl.formatMessage({ id: 'Dashboard.Detail.Overview.Replicas.Edit', defaultMessage: '编辑', @@ -113,7 +140,7 @@ export default function Replicas({ ), }); }} - disabled={replicaList.length === 2} + disabled={replicaList.length === 2 || replicaList.length === 1} type="link" danger > diff --git a/ui/src/pages/Tenant/Detail/Overview/index.tsx b/ui/src/pages/Tenant/Detail/Overview/index.tsx index 4a38c163c..53a6d1bd9 100644 --- a/ui/src/pages/Tenant/Detail/Overview/index.tsx +++ b/ui/src/pages/Tenant/Detail/Overview/index.tsx @@ -33,6 +33,8 @@ type OperateItemConfigType = { danger?: boolean; }; +export type OperateType = 'edit'|'create'; + export type ClusterNSName = { ns?: string; name?: string }; export default function TenantOverview() { @@ -40,10 +42,12 @@ export default function TenantOverview() { useState(false); //Current operation and maintenance modal type const modalType = useRef('changeUnitCount'); + const operateTypeRef = useRef(); const timerRef = useRef(); const [defaultUnitCount, setDefaultUnitCount] = useState(1); const [[ns, name]] = useState(getNSName()); const [clusterList, setClusterList] = useState([]); + const [editZone, setEditZone] = useState(''); useRequest(getSimpleClusterList, { onSuccess: ({ successful, data }) => { if (successful) { @@ -61,7 +65,10 @@ export default function TenantOverview() { manual: true, }); - const openOperateModal = (type: API.ModalType) => { + const openOperateModal = (type: API.ModalType, operateType?: OperateType) => { + if (operateType) { + operateTypeRef.current = operateType; + } modalType.current = type; setOperateModalVisible(true); }; @@ -300,6 +307,10 @@ export default function TenantOverview() { )} {tenantDetail && ( @@ -325,6 +336,10 @@ export default function TenantOverview() { essentialParameter, clusterResourceName: tenantDetail?.info.clusterResourceName, setClusterList, + setEditZone, + replicaList: tenantDetail?.replicas, + editZone, + newResourcePool: operateTypeRef.current === 'create', }} /> diff --git a/ui/src/pages/Tenant/New/ResourcePools.tsx b/ui/src/pages/Tenant/New/ResourcePools.tsx index 7afe1267e..11cc6df9b 100644 --- a/ui/src/pages/Tenant/New/ResourcePools.tsx +++ b/ui/src/pages/Tenant/New/ResourcePools.tsx @@ -5,7 +5,7 @@ import { Card,Col,Form,Row,Tooltip } from 'antd'; import { FormInstance } from 'antd/lib/form'; import { useEffect,useState } from 'react'; import ZoneItem from '../ZoneItem'; -import { findMinParameter,getNewClusterList } from '../helper'; +import { findMinParameter,modifyZoneCheckedStatus } from '../helper'; import styles from './index.less'; interface ResourcePoolsProps { @@ -40,7 +40,7 @@ export default function ResourcePools({ setSelectZones([...selectZones, name]); } setClusterList( - getNewClusterList(clusterList, name, checked, { id: selectClusterId }), + modifyZoneCheckedStatus(clusterList, name, checked, { id: selectClusterId }), ); }; const targetZoneList = clusterList diff --git a/ui/src/pages/Tenant/helper.ts b/ui/src/pages/Tenant/helper.ts index ed98dbce9..457ad9d0e 100644 --- a/ui/src/pages/Tenant/helper.ts +++ b/ui/src/pages/Tenant/helper.ts @@ -167,7 +167,7 @@ function findMinValue( key: 'availableCPU' | 'availableLogDisk' | 'availableMemory', resources: API.ServerResource[], ) { - return resources.sort((pre, cur) => pre[key] - cur[key])[0][key]; + return resources.sort((pre, cur) => cur[key] - pre[key])[0][key]; } export function findMinParameter( @@ -185,7 +185,11 @@ export function findMinParameter( }; } -export const getNewClusterList = ( +/** + * + * @Describe Modify the checked status of a zone in a cluster from the cluster list + */ +export const modifyZoneCheckedStatus = ( clusterList: API.SimpleClusterList, zone: string, checked: boolean, diff --git a/ui/src/services/index.ts b/ui/src/services/index.ts index d4fe1299e..718c6b3ae 100644 --- a/ui/src/services/index.ts +++ b/ui/src/services/index.ts @@ -3,7 +3,7 @@ import { formatClusterData } from '@/pages/Cluster/Detail/Overview/helper'; import { formatStatisticData } from '@/utils/helper'; import { intl } from '@/utils/intl'; //@ts-nocheck import { request } from '@umijs/max'; -import _ from 'lodash'; +import _,{ cloneDeep } from 'lodash'; import moment from 'moment'; const obClusterPrefix = '/api/v1/obclusters'; @@ -341,7 +341,7 @@ export async function createNameSpace(namespace: string) { }; } -export async function getStorageClasses() { +export async function getStorageClasses(): Promise { const r = await request(`${clusterPrefix}/storageClasses`, { method: 'GET', }); @@ -361,7 +361,7 @@ export async function getStorageClasses() { } return { ...r, - data:res + data: res, }; } return r; diff --git a/ui/src/services/typings.d.ts b/ui/src/services/typings.d.ts index 36b4033d2..dcea64742 100644 --- a/ui/src/services/typings.d.ts +++ b/ui/src/services/typings.d.ts @@ -107,17 +107,29 @@ declare namespace API { topology: Topology[]; } & ClusterInfo; + type TooltipData = { + label:string | Element; + value:string; + toolTipData:any[] + } + interface ClusterListResponse extends CommonResponse { data: ClusterItem[]; } - type SimpleClusterList = { + interface StorageClassesResponse extends CommonResponse { + data: TooltipData[]; + } + + type SimpleCluster = { name: string; clusterName: string; clusterId: number; namespace: string; topology: Topology[]; - }[]; + } + + type SimpleClusterList = SimpleCluster[]; interface SimpleClusterListResponse extends CommonResponse { data: SimpleClusterList; @@ -178,7 +190,8 @@ declare namespace API { logDiskSize: string; maxIops: number; memorySize: string; - cpuCount: number; + maxCPU: string; + minCPU: string; minIops: number; priority: number; type: string; From 589479603932d0c79e1e10f0f52dfbf104131fc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=B4=E6=99=96?= <2689991790@qq.com> Date: Tue, 19 Mar 2024 20:49:30 +0800 Subject: [PATCH 2/3] feat:Create resource pool --- ui/src/components/SelectWithTooltip/index.tsx | 2 +- .../components/customModal/AddZoneModal.tsx | 19 +- .../customModal/ModifyUnitDetailModal.tsx | 198 ++++++++++++++---- ui/src/constants/rules.ts | 50 +++++ ui/src/i18n/strings/en-US.json | 19 +- ui/src/i18n/strings/zh-CN.json | 19 +- ui/src/pages/Cluster/New/BasicInfo.tsx | 2 +- ui/src/pages/Cluster/New/Topo.tsx | 22 +- ui/src/pages/Cluster/New/helper.ts | 28 +-- .../Detail/Backup/BackupConfiguration.tsx | 46 ++-- .../pages/Tenant/Detail/Overview/Replicas.tsx | 30 ++- ui/src/pages/Tenant/Detail/Overview/index.tsx | 39 +++- ui/src/pages/Tenant/ZoneItem/index.tsx | 3 + ui/src/pages/Tenant/helper.ts | 33 +++ ui/src/services/typings.d.ts | 5 + ui/src/utils/helper.ts | 45 ++-- 16 files changed, 391 insertions(+), 169 deletions(-) create mode 100644 ui/src/constants/rules.ts diff --git a/ui/src/components/SelectWithTooltip/index.tsx b/ui/src/components/SelectWithTooltip/index.tsx index 4590ffb11..c84d9ccd5 100644 --- a/ui/src/components/SelectWithTooltip/index.tsx +++ b/ui/src/components/SelectWithTooltip/index.tsx @@ -33,7 +33,7 @@ export default function SelectWithTooltip({ boxShadow: '0 3px 6px -4px rgba(0,0,0,.12), 0 6px 16px 0 rgba(0,0,0,.08), 0 9px 28px 8px rgba(0,0,0,.05)', }} - placement="bottomLeft" + placement="right" title={} > {item.value} diff --git a/ui/src/components/customModal/AddZoneModal.tsx b/ui/src/components/customModal/AddZoneModal.tsx index 017d670de..8854ccff9 100644 --- a/ui/src/components/customModal/AddZoneModal.tsx +++ b/ui/src/components/customModal/AddZoneModal.tsx @@ -1,7 +1,7 @@ import { intl } from '@/utils/intl'; import { Form, Input, InputNumber, message } from 'antd'; -import { TZ_NAME_REG } from '@/constants'; +import { RULER_ZONE } from '@/constants/rules'; import { getNSName } from '@/pages/Cluster/Detail/Overview/helper'; import { addObzone } from '@/services'; import type { CommonModalType } from '.'; @@ -64,22 +64,7 @@ export default function AddZoneModal({ defaultMessage: 'zone名称', })} name="zone" - rules={[ - { - required: true, - message: intl.formatMessage({ - id: 'OBDashboard.components.customModal.AddZoneModal.EnterAZoneName', - defaultMessage: '请输入zone名称!', - }), - }, - { - pattern: TZ_NAME_REG, - message: intl.formatMessage({ - id: 'Dashboard.components.customModal.AddZoneModal.TheFirstCharacterMustBe', - defaultMessage: '首字符必须是字母或者下划线,不能包含 -', - }), - }, - ]} + rules={RULER_ZONE} > > + setEditZone?: React.Dispatch>; + zonesOptions?: API.OptionsType; }; export default function ModifyUnitDetailModal({ @@ -63,15 +68,20 @@ export default function ModifyUnitDetailModal({ editZone, replicaList, newResourcePool = false, - setEditZone + setEditZone, + zonesOptions, }: CommonModalType & UnitConfigType) { - const [form] = Form.useForm(); + const [form] = Form.useForm(); const [minMemory, setMinMemory] = useState(2); const [maxResource, setMaxResource] = useState({}); const [selectZones, setSelectZones] = useState( editZone ? [editZone] : [], ); const selectZone = Form.useWatch('selectZone', form); + const obtenantPoolReq = newResourcePool + ? createObtenantPool + : patchObtenantPool; + const handleSubmit = async () => { try { await form.validateFields(); @@ -89,20 +99,30 @@ export default function ModifyUnitDetailModal({ const onFinish = async (values: any) => { const [ns, name] = getNSName(); - const res = await patchTenantConfiguration({ + const { zoneName, ...reqData } = formatPatchPoolData( + values, + newResourcePool ? 'create' : 'edit', + ); + const res = await obtenantPoolReq({ ns, name, - ...formatUnitDetailData(values), + zoneName, + ...reqData, }); if (res.successful) { - message.success(res.message || '修改成功'); + message.success( + res.message || + intl.formatMessage({ + id: 'Dashboard.components.customModal.ModifyUnitDetailModal.ModifiedSuccessfully', + defaultMessage: '修改成功', + }), + ); successCallback(); form.resetFields(); setVisible(false); } }; const checkBoxOnChange = (checked: boolean, name: string) => { - if (!checked) { form.setFieldValue(['pools', name, 'priority'], undefined); setSelectZones(selectZones.filter((zone) => zone !== name)); @@ -121,20 +141,20 @@ export default function ModifyUnitDetailModal({ let result = {}; const zone = replicaList?.find((replica) => replica.zone === editZone); result.unitConfig = { - unitConfig: { - cpuCount: zone?.minCPU, - iopsWeight: zone?.iopsWeight, - logDiskSize: zone?.logDiskSize.split('Gi')[0], - maxIops: zone?.maxIops, - memorySize: zone?.memorySize.split('Gi')[0], - minIops: zone?.minIops, - }, - pools: {}, - }; - result.unitConfig.pools[editZone] = { - priority: zone?.priority, + cpuCount: zone?.minCPU, + iopsWeight: zone?.iopsWeight, + logDiskSize: zone?.logDiskSize.split('Gi')[0], + maxIops: zone?.maxIops, + memorySize: zone?.memorySize.split('Gi')[0], + minIops: zone?.minIops, }; - + if (newResourcePool) { + result.priority = zone?.priority; + } else { + result[zone?.zone] = { + priority: zone?.priority, + }; + } return result; }; let targetCluster = clusterList.find( @@ -188,7 +208,17 @@ export default function ModifyUnitDetailModal({ return ( {newResourcePool && selectOptions.length ? ( - + + + {/* */} + + + + + + + + + + ({ + validator(_: any, value: string) { + if (checkName(value)) { + return Promise.resolve(); + } + return Promise.reject( + new Error( + intl.formatMessage({ + id: 'Dashboard.src.constants.rules.TheResourceNameMayBe', + defaultMessage: '资源名可能拼接到域名中,需要符合域名格式', + }), + ), + ); + }, +}); + +const RULER_ZONE = [ + { + required: true, + message: intl.formatMessage({ + id: 'Dashboard.src.constants.rules.EnterAZoneName', + defaultMessage: '请输入zone名称', + }), + }, + { + pattern: TZ_NAME_REG, + message: intl.formatMessage({ + id: 'Dashboard.src.constants.rules.TheFirstCharacterMustBe', + defaultMessage: '首字符必须是字母或者下划线,不能包含 -', + }), + }, + resourceNameRule, +]; + +export { RULER_ZONE, checkName, resourceNameRule }; diff --git a/ui/src/i18n/strings/en-US.json b/ui/src/i18n/strings/en-US.json index ff22b94a6..363bf0e65 100644 --- a/ui/src/i18n/strings/en-US.json +++ b/ui/src/i18n/strings/en-US.json @@ -635,5 +635,22 @@ "Dashboard.Detail.Overview.Replicas.Edit": "Edit", "Dashboard.Detail.Overview.Replicas.AreYouSureYouWant": "Are you sure you want to delete the tenant's resource pool on {replicaZone}?", "Dashboard.Detail.Overview.Replicas.Delete": "Delete", - "Dashboard.components.TopoComponent.DeletedSuccessfully": "Deleted successfully" + "Dashboard.components.TopoComponent.DeletedSuccessfully": "Deleted successfully", + "Dashboard.Detail.Backup.BackupConfiguration.DeleteBackup": "Delete Backup", + "Dashboard.Detail.Backup.BackupConfiguration.AreYouSureYouWant": "Are you sure you want to delete the backup policy?", + "Dashboard.Detail.Overview.Replicas.AddAResourcePool": "Add a resource pool", + "Dashboard.components.customModal.ModifyUnitDetailModal.ModifiedSuccessfully": "Modified successfully", + "Dashboard.components.customModal.ModifyUnitDetailModal.AddAResourcePool": "Add a resource pool", + "Dashboard.components.customModal.ModifyUnitDetailModal.EditResourcePool": "Edit resource pool", + "Dashboard.components.customModal.ModifyUnitDetailModal.ZoneName": "Zone name", + "Dashboard.components.customModal.ModifyUnitDetailModal.Weight": "Weight", + "Dashboard.components.customModal.ModifyUnitDetailModal.PleaseEnterTheWeightOf": "Please enter the weight of the selected zone", + "Dashboard.components.customModal.ModifyUnitDetailModal.CopyExistingZoneSpecifications": "Copy existing zone specifications", + "Dashboard.components.customModal.ModifyUnitDetailModal.EnterLogdisksize": "Enter logDiskSize", + "Dashboard.components.customModal.ModifyUnitDetailModal.EnterMiniops": "Enter minIops", + "Dashboard.components.customModal.ModifyUnitDetailModal.EnterMaxiops": "Enter maxIops", + "Dashboard.components.customModal.ModifyUnitDetailModal.EnterIopsWeight": "Enter iops weight", + "Dashboard.src.constants.rules.TheResourceNameMayBe": "The resource name may be spliced into the domain name and must conform to the domain name format.", + "Dashboard.src.constants.rules.EnterAZoneName": "Enter a zone name", + "Dashboard.src.constants.rules.TheFirstCharacterMustBe": "The first character must be a letter or an underscore and cannot contain-" } diff --git a/ui/src/i18n/strings/zh-CN.json b/ui/src/i18n/strings/zh-CN.json index 219819b16..6132dbde5 100644 --- a/ui/src/i18n/strings/zh-CN.json +++ b/ui/src/i18n/strings/zh-CN.json @@ -635,5 +635,22 @@ "Dashboard.Detail.Overview.Replicas.Edit": "编辑", "Dashboard.Detail.Overview.Replicas.AreYouSureYouWant": "确定要删除该租户在{replicaZone}上的资源池吗?", "Dashboard.Detail.Overview.Replicas.Delete": "删除", - "Dashboard.components.TopoComponent.DeletedSuccessfully": "删除成功" + "Dashboard.components.TopoComponent.DeletedSuccessfully": "删除成功", + "Dashboard.Detail.Backup.BackupConfiguration.DeleteBackup": "删除备份", + "Dashboard.Detail.Backup.BackupConfiguration.AreYouSureYouWant": "确定要删除该备份策略吗?", + "Dashboard.Detail.Overview.Replicas.AddAResourcePool": "新增资源池", + "Dashboard.components.customModal.ModifyUnitDetailModal.ModifiedSuccessfully": "修改成功", + "Dashboard.components.customModal.ModifyUnitDetailModal.AddAResourcePool": "新增资源池", + "Dashboard.components.customModal.ModifyUnitDetailModal.EditResourcePool": "编辑资源池", + "Dashboard.components.customModal.ModifyUnitDetailModal.ZoneName": "Zone名称", + "Dashboard.components.customModal.ModifyUnitDetailModal.Weight": "权重", + "Dashboard.components.customModal.ModifyUnitDetailModal.PleaseEnterTheWeightOf": "请输入所选 zone 的权重", + "Dashboard.components.customModal.ModifyUnitDetailModal.CopyExistingZoneSpecifications": "复制已有zone规格", + "Dashboard.components.customModal.ModifyUnitDetailModal.EnterLogdisksize": "请输入 logDiskSize", + "Dashboard.components.customModal.ModifyUnitDetailModal.EnterMiniops": "请输入 minIops", + "Dashboard.components.customModal.ModifyUnitDetailModal.EnterMaxiops": "请输入 maxIops", + "Dashboard.components.customModal.ModifyUnitDetailModal.EnterIopsWeight": "请输入 iops权重", + "Dashboard.src.constants.rules.TheResourceNameMayBe": "资源名可能拼接到域名中,需要符合域名格式", + "Dashboard.src.constants.rules.EnterAZoneName": "请输入zone名称", + "Dashboard.src.constants.rules.TheFirstCharacterMustBe": "首字符必须是字母或者下划线,不能包含 -" } diff --git a/ui/src/pages/Cluster/New/BasicInfo.tsx b/ui/src/pages/Cluster/New/BasicInfo.tsx index 2e20f6ad3..58800ef58 100644 --- a/ui/src/pages/Cluster/New/BasicInfo.tsx +++ b/ui/src/pages/Cluster/New/BasicInfo.tsx @@ -8,7 +8,7 @@ import PasswordInput from '@/components/PasswordInput'; import AddNSModal from '@/components/customModal/AddNSModal'; import { getNameSpaces } from '@/services'; import { useState } from 'react'; -import { resourceNameRule } from './helper'; +import { resourceNameRule } from '@/constants/rules'; import styles from './index.less'; interface BasicInfoProps { diff --git a/ui/src/pages/Cluster/New/Topo.tsx b/ui/src/pages/Cluster/New/Topo.tsx index a8e40304a..18ae15480 100644 --- a/ui/src/pages/Cluster/New/Topo.tsx +++ b/ui/src/pages/Cluster/New/Topo.tsx @@ -13,8 +13,7 @@ import { } from 'antd'; import NodeSelector from '@/components/NodeSelector'; -import { TZ_NAME_REG } from '@/constants'; -import { resourceNameRule } from './helper'; +import { RULER_ZONE } from '@/constants/rules'; export default function Topo({ form }: { form: FormInstance }) { const getNowNodeSelector = (zoneIdx: number) => { @@ -51,24 +50,7 @@ export default function Topo({ form }: { form: FormInstance }) { } validateFirst name={[name, 'zone']} - rules={[ - { - required: true, - message: intl.formatMessage({ - id: 'OBDashboard.Cluster.New.Topo.EnterAZoneName', - defaultMessage: '请输入zone名称', - }), - }, - { - pattern: TZ_NAME_REG, - message: intl.formatMessage({ - id: 'Dashboard.Cluster.New.Topo.TheFirstCharacterMustBe', - defaultMessage: - '首字符必须是字母或者下划线,不能包含 -', - }), - }, - resourceNameRule, - ]} + rules={RULER_ZONE} > ({ - validator(_: any, value: string) { - if (checkName(value)) { - return Promise.resolve(); - } - return Promise.reject( - new Error( - intl.formatMessage({ - id: 'OBDashboard.Cluster.New.helper.TheResourceNameMayBe', - defaultMessage: '资源名可能拼接到域名中,需要符合域名格式', - }), - ), - ); - }, -}); -export { checkName, generateRandomPassword, passwordRules, resourceNameRule }; +export { generateRandomPassword, passwordRules}; diff --git a/ui/src/pages/Tenant/Detail/Backup/BackupConfiguration.tsx b/ui/src/pages/Tenant/Detail/Backup/BackupConfiguration.tsx index b934c1e82..76d455c8e 100644 --- a/ui/src/pages/Tenant/Detail/Backup/BackupConfiguration.tsx +++ b/ui/src/pages/Tenant/Detail/Backup/BackupConfiguration.tsx @@ -2,31 +2,31 @@ import { BACKUP_RESULT_STATUS } from '@/constants'; import { usePublicKey } from '@/hook/usePublicKey'; import { getNSName } from '@/pages/Cluster/Detail/Overview/helper'; import { -deletePolicyOfTenant, -updateBackupPolicyOfTenant, + deletePolicyOfTenant, + updateBackupPolicyOfTenant, } from '@/services/tenant'; import { intl } from '@/utils/intl'; import { useRequest } from 'ahooks'; import { -Button, -Card, -Col, -Descriptions, -Form, -InputNumber, -Popconfirm, -Row, -Select, -Space, -message + Button, + Card, + Col, + Descriptions, + Form, + InputNumber, + Popconfirm, + Row, + Select, + Space, + message, } from 'antd'; import dayjs from 'dayjs'; -import { useRef,useState } from 'react'; +import { useRef, useState } from 'react'; import { -checkIsSame, -checkScheduleDatesHaveFull, -formatBackupForm, -formatBackupPolicyData, + checkIsSame, + checkScheduleDatesHaveFull, + formatBackupForm, + formatBackupPolicyData, } from '../../helper'; import BakMethodsList from '../NewBackup/BakMethodsList'; import SchduleSelectFormItem from '../NewBackup/SchduleSelectFormItem'; @@ -248,8 +248,14 @@ export default function BackupConfiguration({ deleteBackupPolicyReq({ ns, name })} - title="删除备份" - description="确定要删除该备份策略吗?" + title={intl.formatMessage({ + id: 'Dashboard.Detail.Backup.BackupConfiguration.DeleteBackup', + defaultMessage: '删除备份', + })} + description={intl.formatMessage({ + id: 'Dashboard.Detail.Backup.BackupConfiguration.AreYouSureYouWant', + defaultMessage: '确定要删除该备份策略吗?', + })} > {intl.formatMessage({ diff --git a/ui/src/pages/Tenant/Detail/Overview/Replicas.tsx b/ui/src/pages/Tenant/Detail/Overview/Replicas.tsx index bba95bb1b..bfa828d51 100644 --- a/ui/src/pages/Tenant/Detail/Overview/Replicas.tsx +++ b/ui/src/pages/Tenant/Detail/Overview/Replicas.tsx @@ -3,7 +3,7 @@ import showDeleteConfirm from '@/components/customModal/DeleteModal'; import { getNSName } from '@/pages/Cluster/Detail/Overview/helper'; import { deleteObtenantPool } from '@/services/tenant'; import { intl } from '@/utils/intl'; -import { Button,Col,Descriptions,message } from 'antd'; +import { Button, Col, Descriptions, message } from 'antd'; import type { OperateType } from '.'; import styles from './index.less'; @@ -12,7 +12,7 @@ interface ReplicasProps { refreshTenant: () => void; openOperateModal: (type: API.ModalType) => void; setEditZone: React.Dispatch>; - editZone: string; + cluster: API.SimpleCluster; operateType: React.MutableRefObject; } @@ -49,7 +49,7 @@ export default function Replicas({ openOperateModal, setEditZone, operateType, - editZone + cluster, }: ReplicasProps) { const sortKeys = (keys: string[]) => { const minCpuIdx = keys.findIndex((key) => key === 'minCPU'); @@ -80,15 +80,16 @@ export default function Replicas({ setEditZone(zone); openOperateModal('modifyUnitSpecification'); }; - - const addResourcePool = ()=>{ + + const addResourcePool = () => { operateType.current = 'create'; openOperateModal('modifyUnitSpecification'); - } + }; return ( {intl.formatMessage({ @@ -97,7 +98,18 @@ export default function Replicas({ })} } - extra={新增资源池} + extra={ + + {intl.formatMessage({ + id: 'Dashboard.Detail.Overview.Replicas.AddAResourcePool', + defaultMessage: '新增资源池', + })} + + } collapsible={true} defaultExpand={true} > @@ -140,7 +152,9 @@ export default function Replicas({ ), }); }} - disabled={replicaList.length === 2 || replicaList.length === 1} + disabled={ + replicaList.length === 2 || replicaList.length === 1 + } type="link" danger > diff --git a/ui/src/pages/Tenant/Detail/Overview/index.tsx b/ui/src/pages/Tenant/Detail/Overview/index.tsx index 53a6d1bd9..be78f6553 100644 --- a/ui/src/pages/Tenant/Detail/Overview/index.tsx +++ b/ui/src/pages/Tenant/Detail/Overview/index.tsx @@ -19,7 +19,9 @@ import { PageContainer } from '@ant-design/pro-components'; import { history } from '@umijs/max'; import { useRequest } from 'ahooks'; import { Button,Row,Tooltip,message } from 'antd'; +import { cloneDeep } from 'lodash'; import { useEffect,useRef,useState } from 'react'; +import { getClusterFromTenant,getZonesOptions } from '../../helper'; import Backups from './Backups'; import BasicInfo from './BasicInfo'; import Replicas from './Replicas'; @@ -94,6 +96,8 @@ export default function TenantOverview() { manual: true, onSuccess: ({ data, successful }) => { if (successful) { + console.log('data',data); + if (data.info.unitNumber) { setDefaultUnitCount(data.info.unitNumber); } @@ -252,22 +256,25 @@ export default function TenantOverview() { ], }; }; + + /** + * @describe Filter the zones that exist in the tenant resource pool in the cluster + */ const formatClustersTopology = ( clusters: API.SimpleClusterList, tenantDetail: API.TenantBasicInfo | undefined, ) => { - if (!tenantDetail) return clusters; + const newClusters = cloneDeep(clusters); + if (!tenantDetail) return newClusters; const { clusterResourceName } = tenantDetail.info; const { replicas } = tenantDetail; - const cluster = clusters.find( - (cluster) => cluster.name === clusterResourceName, - ); + const cluster = getClusterFromTenant(newClusters,clusterResourceName) if (cluster && cluster.topology) { cluster.topology = cluster.topology.filter((zone) => replicas?.find((item) => item.zone === zone.zone), ); } - return clusters; + return newClusters; }; useEffect(() => { @@ -282,8 +289,9 @@ export default function TenantOverview() { useEffect(() => { if (tenantDetail && clusterList) { - const cluster = clusterList.find( - (cluster) => cluster.name === tenantDetail.info.clusterResourceName, + const cluster = getClusterFromTenant( + clusterList, + tenantDetail.info.clusterResourceName, ); if (cluster) { const { name, namespace } = cluster; @@ -308,6 +316,10 @@ export default function TenantOverview() { refreshTenant={reGetTenantDetail} replicaList={tenantDetail.replicas} openOperateModal={openOperateModal} + cluster={getClusterFromTenant( + clusterList, + tenantDetail.info.clusterResourceName, + )} setEditZone={setEditZone} editZone={editZone} operateType={operateTypeRef} @@ -332,7 +344,8 @@ export default function TenantOverview() { successCallback={operateSuccess} defaultValue={defaultUnitCount} defaultValueForUnitDetail={{ - clusterList: formatClustersTopology(clusterList, tenantDetail), + // clusterList: formatClustersTopology(clusterList, tenantDetail), + clusterList: clusterList, essentialParameter, clusterResourceName: tenantDetail?.info.clusterResourceName, setClusterList, @@ -340,6 +353,16 @@ export default function TenantOverview() { replicaList: tenantDetail?.replicas, editZone, newResourcePool: operateTypeRef.current === 'create', + zonesOptions: + operateTypeRef.current === 'create' + ? getZonesOptions( + getClusterFromTenant( + clusterList, + tenantDetail?.info.clusterResourceName, + ), + tenantDetail?.replicas, + ) + : undefined, }} /> diff --git a/ui/src/pages/Tenant/ZoneItem/index.tsx b/ui/src/pages/Tenant/ZoneItem/index.tsx index 84c786c5e..d632da632 100644 --- a/ui/src/pages/Tenant/ZoneItem/index.tsx +++ b/ui/src/pages/Tenant/ZoneItem/index.tsx @@ -9,6 +9,7 @@ interface ZoneItemProps { checkBoxOnChange: (checked: boolean, name: string) => void; key: number; formName?:string[]|string; + isEdit?:boolean; } export default function ZoneItem({ @@ -17,6 +18,7 @@ export default function ZoneItem({ checked, obZoneResource, checkBoxOnChange, + isEdit, formName = ['pools', name, 'priority'] }: ZoneItemProps) { return ( @@ -32,6 +34,7 @@ export default function ZoneItem({ {name} checkBoxOnChange(e.target.checked, name)} /> diff --git a/ui/src/pages/Tenant/helper.ts b/ui/src/pages/Tenant/helper.ts index 457ad9d0e..a61fed915 100644 --- a/ui/src/pages/Tenant/helper.ts +++ b/ui/src/pages/Tenant/helper.ts @@ -223,4 +223,37 @@ export const checkScheduleDatesHaveFull = (scheduleDates): boolean => { } } return false; +}; + +export const getClusterFromTenant = ( + clusterList: API.SimpleClusterList, + clusterResourceName: string, +): API.SimpleCluster | undefined => { + return clusterList.find((cluster) => cluster.name === clusterResourceName); +}; + +const formatReplicToOption = ( + replicaList: API.ReplicaDetailType[] | API.Topology[], +): API.OptionsType => { + return replicaList.map((replica) => ({ + label: replica.zone, + value: replica.zone, + })); +}; + +export const getZonesOptions = ( + cluster: API.SimpleCluster | undefined, + replicaList: API.ReplicaDetailType[] | undefined, +): API.OptionsType => { + if (!replicaList) return []; + if (!cluster) return formatReplicToOption(replicaList); + const { topology } = cluster; + const newReplicas = topology.filter((zone) => { + if (replicaList.find((replica) => replica.zone === zone.zone)) { + return false; + } else { + return true; + } + }); + return formatReplicToOption(newReplicas); }; \ No newline at end of file diff --git a/ui/src/services/typings.d.ts b/ui/src/services/typings.d.ts index dcea64742..b2fb79741 100644 --- a/ui/src/services/typings.d.ts +++ b/ui/src/services/typings.d.ts @@ -113,6 +113,11 @@ declare namespace API { toolTipData:any[] } + type OptionsType = { + label:string; + value:string; + }[] + interface ClusterListResponse extends CommonResponse { data: ClusterItem[]; } diff --git a/ui/src/utils/helper.ts b/ui/src/utils/helper.ts index 32460488d..1532fee30 100644 --- a/ui/src/utils/helper.ts +++ b/ui/src/utils/helper.ts @@ -1,6 +1,5 @@ -import type { UnitDetailType } from '@/components/customModal/ModifyUnitDetailModal'; +import type { PoolDetailType } from '@/components/customModal/ModifyUnitDetailModal'; import { intl } from '@/utils/intl'; -import { clone } from 'lodash'; type StatisticStatus = 'running' | 'deleting' | 'operating' | 'failed'; type StatisticDataType = { status: StatisticStatus; count: number }[]; @@ -41,23 +40,27 @@ export const formatStatisticData = ( return r; }; -export const formatUnitDetailData = (originUnitData: UnitDetailType) => { - const _originUnitData: UnitDetailType = clone(originUnitData); - _originUnitData.unitConfig.unitConfig.logDiskSize = _originUnitData.unitConfig.unitConfig.logDiskSize + 'Gi'; - _originUnitData.unitConfig.unitConfig.memorySize = _originUnitData.unitConfig.unitConfig.memorySize + 'Gi'; - _originUnitData.unitConfig.unitConfig.cpuCount = String( - _originUnitData.unitConfig.unitConfig.cpuCount, - ); - return { - unitConfig: { - unitConfig: _originUnitData.unitConfig.unitConfig, - pools: Object.keys(_originUnitData.unitConfig.pools) - .map((zone) => ({ - zone, - priority: _originUnitData.unitConfig.pools?.[zone]?.priority, - type: 'Full', - })) - .filter((item) => item.priority || item.priority === 0), - }, +export const formatPatchPoolData = (originUnitData: PoolDetailType,type:'edit'|'create') => { + let newOriginUnitData: PoolDetailType = { + unitConfig: {}, }; -}; \ No newline at end of file + newOriginUnitData.unitConfig = { + ...originUnitData.unitConfig, + logDiskSize: originUnitData.unitConfig.logDiskSize + 'Gi', + memorySize: originUnitData.unitConfig.memorySize + 'Gi', + cpuCount: String(originUnitData.unitConfig.cpuCount), + }; + if(type === 'create'){ + newOriginUnitData.zoneName = originUnitData.zoneName; + newOriginUnitData.priority = originUnitData.priority; + } + if(type === 'edit'){ + Object.keys(originUnitData).forEach((key) => { + if (originUnitData[key]?.priority) { + newOriginUnitData.zoneName = key; + newOriginUnitData.priority = originUnitData[key].priority; + } + }); + } + return newOriginUnitData; +}; From ab6232fa672af1dc1132e33ed852e0a9c1885aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=B4=E6=99=96?= <2689991790@qq.com> Date: Wed, 20 Mar 2024 10:25:21 +0800 Subject: [PATCH 3/3] fix:text --- ui/src/i18n/strings/en-US.json | 3 ++- ui/src/i18n/strings/zh-CN.json | 3 ++- ui/src/pages/Tenant/Detail/NewBackup/BakMethodsList.tsx | 6 +++--- ui/src/pages/Tenant/Detail/Overview/index.tsx | 2 -- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ui/src/i18n/strings/en-US.json b/ui/src/i18n/strings/en-US.json index 363bf0e65..a4689cc87 100644 --- a/ui/src/i18n/strings/en-US.json +++ b/ui/src/i18n/strings/en-US.json @@ -652,5 +652,6 @@ "Dashboard.components.customModal.ModifyUnitDetailModal.EnterIopsWeight": "Enter iops weight", "Dashboard.src.constants.rules.TheResourceNameMayBe": "The resource name may be spliced into the domain name and must conform to the domain name format.", "Dashboard.src.constants.rules.EnterAZoneName": "Enter a zone name", - "Dashboard.src.constants.rules.TheFirstCharacterMustBe": "The first character must be a letter or an underscore and cannot contain-" + "Dashboard.src.constants.rules.TheFirstCharacterMustBe": "The first character must be a letter or an underscore and cannot contain-", + "Dashboard.Detail.NewBackup.BakMethodsList.ConfigureAtLeastOneFull": "Configure at least one full backup" } diff --git a/ui/src/i18n/strings/zh-CN.json b/ui/src/i18n/strings/zh-CN.json index 6132dbde5..73e337f40 100644 --- a/ui/src/i18n/strings/zh-CN.json +++ b/ui/src/i18n/strings/zh-CN.json @@ -652,5 +652,6 @@ "Dashboard.components.customModal.ModifyUnitDetailModal.EnterIopsWeight": "请输入 iops权重", "Dashboard.src.constants.rules.TheResourceNameMayBe": "资源名可能拼接到域名中,需要符合域名格式", "Dashboard.src.constants.rules.EnterAZoneName": "请输入zone名称", - "Dashboard.src.constants.rules.TheFirstCharacterMustBe": "首字符必须是字母或者下划线,不能包含 -" + "Dashboard.src.constants.rules.TheFirstCharacterMustBe": "首字符必须是字母或者下划线,不能包含 -", + "Dashboard.Detail.NewBackup.BakMethodsList.ConfigureAtLeastOneFull": "至少配置 1 个全量备份" } diff --git a/ui/src/pages/Tenant/Detail/NewBackup/BakMethodsList.tsx b/ui/src/pages/Tenant/Detail/NewBackup/BakMethodsList.tsx index 0daa85fc1..567a7fd91 100644 --- a/ui/src/pages/Tenant/Detail/NewBackup/BakMethodsList.tsx +++ b/ui/src/pages/Tenant/Detail/NewBackup/BakMethodsList.tsx @@ -20,7 +20,7 @@ export default function BakMethodsList({ const dataSource = scheduleValue || form?.getFieldValue('scheduleDates'); return ( - + {intl.formatMessage({ id: 'Dashboard.Detail.NewBackup.BakMethodsList.BackupData', @@ -29,7 +29,7 @@ export default function BakMethodsList({ {intl.formatMessage({ - id: 'Dashboard.Detail.NewBackup.BakMethodsList.WeRecommendThatYouConfigure', + id: 'Dashboard.Detail.NewBackup.BakMethodsList.ConfigureAtLeastOneFull', defaultMessage: '至少配置 1 个全量备份', })} @@ -41,7 +41,7 @@ export default function BakMethodsList({ label={ dataSource?.mode === 'Monthly' ? day : WEEK_TEXT_MAP.get(day) } - style={{marginBottom:0}} + style={{ marginBottom: 0 }} key={index} > diff --git a/ui/src/pages/Tenant/Detail/Overview/index.tsx b/ui/src/pages/Tenant/Detail/Overview/index.tsx index be78f6553..3639d3b13 100644 --- a/ui/src/pages/Tenant/Detail/Overview/index.tsx +++ b/ui/src/pages/Tenant/Detail/Overview/index.tsx @@ -96,8 +96,6 @@ export default function TenantOverview() { manual: true, onSuccess: ({ data, successful }) => { if (successful) { - console.log('data',data); - if (data.info.unitNumber) { setDefaultUnitCount(data.info.unitNumber); }
{key}:
{data[key]}
{value}
{intl.formatMessage({ - id: 'Dashboard.Detail.NewBackup.BakMethodsList.WeRecommendThatYouConfigure', + id: 'Dashboard.Detail.NewBackup.BakMethodsList.ConfigureAtLeastOneFull', defaultMessage: '至少配置 1 个全量备份', })}