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