github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/ui/src/pages/migration/replication-detail.tsx (about) 1 import React, { useState } from 'react' 2 import { useTranslation } from 'react-i18next' 3 import { isEqual } from 'lodash-es' 4 5 import i18n from '~/i18n' 6 import { 7 Row, 8 Col, 9 Button, 10 Space, 11 Table, 12 Input, 13 Select, 14 Breadcrumb, 15 TableColumnsType, 16 } from '~/uikit' 17 import { 18 Task, 19 TaskMigrateTarget, 20 useDmapiGetTaskListQuery, 21 useDmapiGetTaskMigrateTargetsQuery, 22 } from '~/models/task' 23 import { useDmapiGetSourceQuery } from '~/models/source' 24 25 interface ReplicationDetailSearchOptions { 26 currentTask?: Task 27 currentSourceName: string 28 dbPattern: string 29 tablePattern: string 30 } 31 32 const ReplicationDetail: React.FC = () => { 33 const [t] = useTranslation() 34 35 const [ 36 { currentTask, currentSourceName, dbPattern, tablePattern }, 37 setSearchOptions, 38 ] = useState<ReplicationDetailSearchOptions>({ 39 currentTask: undefined, 40 currentSourceName: '', 41 dbPattern: '', 42 tablePattern: '', 43 }) 44 45 const [payload, setPayload] = useState({ 46 taskName: currentTask?.name ?? '', 47 sourceName: currentSourceName ?? '', 48 schemaPattern: dbPattern, 49 tablePattern: tablePattern, 50 }) 51 52 const { data: taskList, isFetching: isFetchingTaskList } = 53 useDmapiGetTaskListQuery({ 54 withStatus: true, 55 }) 56 const { 57 data: migrateTagetData, 58 refetch, 59 isFetching: isFetchingMigrateTarget, 60 } = useDmapiGetTaskMigrateTargetsQuery(payload, { 61 skip: !payload.taskName || !payload.sourceName, 62 }) 63 const { data: sourceData } = useDmapiGetSourceQuery( 64 { sourceName: currentSourceName ?? '' }, 65 { skip: !currentSourceName } 66 ) 67 const loading = isFetchingTaskList || isFetchingMigrateTarget 68 69 const dataSource = migrateTagetData?.data 70 71 const columns: TableColumnsType<TaskMigrateTarget> = [ 72 { 73 title: t('task name'), 74 key: 'taskname', 75 render() { 76 return currentTask?.name 77 }, 78 }, 79 { 80 title: t('source info'), 81 key: 'sourceinfo', 82 render() { 83 if (sourceData) { 84 return `${sourceData?.host}:${sourceData.port}` 85 } 86 return '-' 87 }, 88 }, 89 { 90 title: t('source schema'), 91 dataIndex: 'source_schema', 92 }, 93 { 94 title: t('source table'), 95 dataIndex: 'source_table', 96 }, 97 { 98 title: t('target info'), 99 render() { 100 return `${currentTask?.target_config.host}:${currentTask?.target_config.port}` 101 }, 102 }, 103 { 104 title: t('target schema'), 105 dataIndex: 'target_schema', 106 }, 107 { 108 title: t('target table'), 109 dataIndex: 'target_table', 110 }, 111 ] 112 113 return ( 114 <div> 115 <div className="px-4 pt-4"> 116 <Breadcrumb> 117 <Breadcrumb.Item>{t('migration')}</Breadcrumb.Item> 118 <Breadcrumb.Item>{t('replication detail')}</Breadcrumb.Item> 119 </Breadcrumb> 120 </div> 121 122 <Row className="p-4" justify="space-between"> 123 <Col span={22}> 124 <Space> 125 <Select 126 placeholder="Select a task" 127 className="w-150px" 128 loading={loading} 129 options={taskList?.data?.map(i => ({ 130 label: i.name, 131 value: i.name, 132 }))} 133 onSelect={(value: string) => { 134 const t = taskList?.data.find(i => i.name === value) 135 if (t) { 136 setSearchOptions(prev => ({ ...prev, currentTask: t })) 137 } 138 }} 139 /> 140 141 <Select 142 placeholder="Select a source" 143 className="w-150px" 144 loading={loading} 145 options={currentTask?.source_config.source_conf?.map(i => ({ 146 label: i.source_name, 147 value: i.source_name, 148 }))} 149 onSelect={(value: string) => { 150 setSearchOptions(prev => ({ 151 ...prev, 152 currentSourceName: value, 153 })) 154 }} 155 /> 156 157 <Input 158 addonBefore="database" 159 placeholder="source database" 160 onChange={e => { 161 setSearchOptions(prev => ({ 162 ...prev, 163 dbPattern: e.target.value, 164 })) 165 }} 166 /> 167 <Input 168 addonBefore="table" 169 placeholder="source table" 170 onChange={e => { 171 setSearchOptions(prev => ({ 172 ...prev, 173 tablePattern: e.target.value, 174 })) 175 }} 176 /> 177 <Button 178 onClick={() => { 179 const next = { 180 taskName: currentTask?.name ?? '', 181 sourceName: currentSourceName ?? '', 182 schemaPattern: dbPattern, 183 tablePattern: tablePattern, 184 } 185 186 if (isEqual(next, payload)) { 187 refetch() 188 } else { 189 setPayload(next) 190 } 191 }} 192 > 193 {t('check')} 194 </Button> 195 </Space> 196 </Col> 197 </Row> 198 199 <Table 200 className="p-4" 201 dataSource={dataSource} 202 columns={columns} 203 loading={loading} 204 rowKey="key" 205 pagination={{ 206 total: taskList?.total, 207 }} 208 /> 209 </div> 210 ) 211 } 212 213 export const meta = { 214 title: () => i18n.t('replication detail'), 215 index: 3, 216 } 217 218 export default ReplicationDetail