github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/ui/src/pages/index.tsx (about) 1 import React, { useEffect, useState } from 'react' 2 import { useNavigate } from 'react-router-dom' 3 import { useLocalStorageState } from 'ahooks' 4 import { useTranslation } from 'react-i18next' 5 import clsx from 'clsx' 6 7 import { ControlOutlined } from '~/uikit/icons' 8 import { 9 Alert, 10 Button, 11 Modal, 12 Skeleton, 13 Form, 14 Input, 15 Popover, 16 Select, 17 } from '~/uikit' 18 19 const standard = 20 '/d/canCEQgnk/dm-monitor-standard?orgId=1&refresh=1m&theme=light&from=now-12h&to=now&kiosk' 21 const professional = 22 '/d/Ja68YqRnz/dm-monitor-professional?orgId=1&refresh=1m&theme=light&from=now-12h&to=now&kiosk' 23 24 const Dashboard = () => { 25 const [t] = useTranslation() 26 const [config, setDashboardConfig] = useLocalStorageState<{ 27 port: string 28 host: string 29 view: string 30 }>('dashboard-config', { 31 defaultValue: { 32 port: '', 33 host: '', 34 view: standard, 35 }, 36 }) 37 const [isModalOpen, setIsModalOpen] = useState(false) 38 const [loading, setLoading] = useState(true) 39 const [form] = Form.useForm() 40 const { host, port, view } = config 41 42 const handleCancel = () => { 43 setIsModalOpen(false) 44 } 45 const handleOk = () => { 46 form.validateFields().then(values => { 47 setDashboardConfig(c => ({ ...c, ...values })) 48 setIsModalOpen(false) 49 }) 50 } 51 52 useEffect(() => { 53 if (!config?.host || !config?.port) { 54 setIsModalOpen(true) 55 } 56 }, [config]) 57 58 return ( 59 <div className="h-full w-full relative"> 60 <Popover 61 arrowPointAtCenter={false} 62 placement="topRight" 63 content={ 64 <div> 65 <div className="mt-4"> 66 <Form 67 form={form} 68 initialValues={config} 69 onFinish={values => 70 setDashboardConfig(c => ({ ...c, ...values })) 71 } 72 > 73 <Form.Item label={t('host')} name="host"> 74 <Input /> 75 </Form.Item> 76 77 <Form.Item label={t('port')} name="port"> 78 <Input /> 79 </Form.Item> 80 81 <Form.Item label={t('dashboard view')} name="view"> 82 <Select> 83 <Select.Option value={standard}> 84 {t('dashboard standard')} 85 </Select.Option> 86 <Select.Option value={professional}> 87 {t('dashboard professional')} 88 </Select.Option> 89 </Select> 90 </Form.Item> 91 92 <Button htmlType="submit">{t('save')}</Button> 93 </Form> 94 </div> 95 </div> 96 } 97 > 98 <div 99 style={{ 100 zIndex: 2, 101 position: 'fixed', 102 bottom: 100, 103 right: 40, 104 height: 50, 105 width: 50, 106 lineHeight: '50px', 107 textAlign: 'center', 108 borderRadius: '50%', 109 backgroundColor: '#fff', 110 cursor: 'pointer', 111 boxShadow: 112 '0 3px 6px -4px #0000001f,0 6px 16px #00000014,0 9px 28px 8px #0000000d', 113 }} 114 > 115 <ControlOutlined style={{ fontSize: '18px' }} /> 116 </div> 117 </Popover> 118 <Modal 119 title={t('edit config')} 120 visible={isModalOpen} 121 onOk={handleOk} 122 onCancel={handleCancel} 123 > 124 <Alert 125 message={t('note')} 126 description={t('note-dashboard-config')} 127 type="info" 128 showIcon 129 /> 130 131 <div className="mt-4"> 132 <Form form={form} initialValues={config}> 133 <Form.Item label={t('host')} name="host" required> 134 <Input /> 135 </Form.Item> 136 137 <Form.Item label={t('port')} name="port" required> 138 <Input /> 139 </Form.Item> 140 </Form> 141 </div> 142 </Modal> 143 {loading && ( 144 <div className="m-4 absolute h-full w-full z-1"> 145 {t('dashboard loading tip')} 146 <Skeleton active /> 147 <Skeleton active /> 148 </div> 149 )} 150 {port && host && ( 151 <iframe 152 key={view} 153 onLoad={() => setLoading(false)} 154 src={`//${host}:${port}${view}`} 155 className={clsx('w-full h-full', loading && 'invisible')} 156 frameBorder="0" 157 /> 158 )} 159 </div> 160 ) 161 } 162 163 const DashboardV2 = () => { 164 const navigate = useNavigate() 165 166 useEffect(() => { 167 navigate('/migration/task') 168 }, []) 169 170 return null 171 } 172 173 export default DashboardV2