diff --git a/src/hooks/useUserInfo.ts b/src/hooks/useUserInfo.ts index d399cbe..d28a06b 100644 --- a/src/hooks/useUserInfo.ts +++ b/src/hooks/useUserInfo.ts @@ -1,4 +1,5 @@ import { useModel } from '@umijs/max'; +import { useMemo } from 'react'; export default function useUserInfo() { const { initialState, setInitialState } = useModel('@@initialState'); @@ -14,5 +15,24 @@ export default function useUserInfo() { setUserInfo(info); }; - return { userInfo, refreshUserInfo, setUserInfo }; + const userPlatform = useMemo(() => { + const company = userInfo?.company; + const originalPlatform = [ + { + label: 'MT5', + value: 5, + isOpen: company?.mt5Open === 1, + }, + { + label: 'MT4', + value: 4, + isOpen: company?.mt4Open === 1, + }, + ]; + + // return originalPlatform.filter((item) => item.isOpen); + return originalPlatform; + }, [userInfo]); + + return { userInfo, refreshUserInfo, setUserInfo, userPlatform }; } diff --git a/src/locales/en_US/pages.ts b/src/locales/en_US/pages.ts index e9ed0aa..18144db 100644 --- a/src/locales/en_US/pages.ts +++ b/src/locales/en_US/pages.ts @@ -2,6 +2,7 @@ export default { 'common.loading': 'Loading...', 'common.content.noRules': 'No rules available', 'common.content.noData': 'No data available', + 'table.platformAccess': 'Platform Quota', 'table.group': 'Group', 'table.operatorRecords': 'Operator Records', 'table.operatorAction': 'Operator Action', @@ -615,6 +616,10 @@ export default { 'Enter verified sender emails (comma separated)', 'pages.email.status.normal': 'Active', 'pages.email.status.disabled': 'Inactive', + 'pages.email.platformAccess': ' Platform Access', + 'pages.email.platformAccessEnable': ' Access', + 'pages.email.platformMax': 'Quota Limit', + 'pages.email.platformAssigned': 'Assigned', 'pages.email.notification': 'Email Notification Config', 'pages.email.notificationEmail': 'Notification Email', 'pages.email.notificationEmail.tips': diff --git a/src/locales/zh_CN/pages.ts b/src/locales/zh_CN/pages.ts index dd90000..28bfc3c 100644 --- a/src/locales/zh_CN/pages.ts +++ b/src/locales/zh_CN/pages.ts @@ -2,6 +2,7 @@ export default { 'common.loading': '加载中...', 'common.content.noRules': '暂无规则', 'common.content.noData': '暂无数据', + 'table.platformAccess': '平台配额', 'table.group': '所属组', 'table.operatorRecords': '操作记录', 'table.operatorAction': '操作动作', @@ -581,6 +582,10 @@ export default { 'pages.email.availableEmails.tips': '在服务商已验证的邮箱,多个用逗号分隔', 'pages.email.status.normal': '正常', 'pages.email.status.disabled': '停用', + 'pages.email.platformAccess': '平台接入权限', + 'pages.email.platformAccessEnable': '接入', + 'pages.email.platformMax': '最大数量上限', + 'pages.email.platformAssigned': '已配', 'pages.email.notification': '邮件通知配置', 'pages.email.notificationEmail': '通知邮箱', 'pages.email.notificationEmail.tips': diff --git a/src/pages/account/index.tsx b/src/pages/account/index.tsx index 71fd260..85360a2 100644 --- a/src/pages/account/index.tsx +++ b/src/pages/account/index.tsx @@ -21,7 +21,7 @@ const maxAlertHideCount = 9999; const Account: React.FC = () => { const { isGlobalCompany } = useAccess(); - const { userInfo } = useUserInfo(); + const { userInfo, userPlatform } = useUserInfo(); const companyInfo = userInfo?.company; const [visible, setVisible] = useState(false); @@ -122,14 +122,7 @@ const Account: React.FC = () => { label: $t('table.all'), value: '', }, - // { - // label: 'MT4', - // value: '4', - // }, - { - label: 'MT5', - value: '5', - }, + ...userPlatform, ], }, }, diff --git a/src/pages/alert/index.tsx b/src/pages/alert/index.tsx index 236fabc..7a03bc1 100644 --- a/src/pages/alert/index.tsx +++ b/src/pages/alert/index.tsx @@ -64,7 +64,7 @@ const Alert: React.FC = () => { const [dataSourceList, setDataSourceList] = useState< API.DataSourceListItem[] >([]); - const { userInfo } = useUserInfo(); + const { userInfo, userPlatform } = useUserInfo(); const userDataSourceList = userInfo?.userDataSourceList; const companyInfo = userInfo?.company; @@ -257,14 +257,7 @@ const Alert: React.FC = () => { label: $t('table.all'), value: '', }, - // { - // label: 'MT4', - // value: 4, - // }, - { - label: 'MT5', - value: 5, - }, + ...userPlatform, ], }, render: (_, { platform }) => { diff --git a/src/pages/company/Popup.tsx b/src/pages/company/Popup.tsx index 24359ab..1363f20 100644 --- a/src/pages/company/Popup.tsx +++ b/src/pages/company/Popup.tsx @@ -2,13 +2,14 @@ import { ModalForm, ProFormDatePicker, ProFormDependency, + ProFormDigit, type ProFormInstance, ProFormSelect, ProFormSwitch, ProFormText, } from '@ant-design/pro-components'; import { useAccess } from '@umijs/max'; -import { Divider, Space, Typography } from 'antd'; +import { Card, Col, Divider, Row, Space, Typography } from 'antd'; import type { Dayjs } from 'dayjs'; import { useRef } from 'react'; import useUserInfo from '@/hooks/useUserInfo'; @@ -138,6 +139,75 @@ export default (props: { {formValues?.id !== void 0 && ( <> + + + ⚙️ {$t('pages.email.platformAccess')} + + + + +value} + /> + } + styles={{ + header: { fontSize: 14, minHeight: 40, paddingInline: 14 }, + body: { paddingInline: 14 }, + }} + > + + {({ mt4Open }) => ( + + )} + + + + + +value} + /> + } + styles={{ + header: { fontSize: 14, minHeight: 40, paddingInline: 14 }, + body: { paddingInline: 14 }, + }} + > + + {({ mt5Open }) => ( + + )} + + + + + {/* */} 📧 {$t('pages.email.notification')} diff --git a/src/pages/company/index.tsx b/src/pages/company/index.tsx index 135262d..cfcee8c 100644 --- a/src/pages/company/index.tsx +++ b/src/pages/company/index.tsx @@ -74,6 +74,46 @@ const Company: React.FC = () => { ); }, }, + { + title: $t('table.platformAccess'), + dataIndex: 'platformAccess', + render: ( + _, + { + mt4Count, + mt4Open, + mt5Count, + mt5Open, + sourceType4Count, + sourceType5Count, + }, + ) => { + return ( + + + MT4:{' '} + {mt4Open === 1 ? ( + + {sourceType4Count ?? '-'} / {mt4Count ?? '-'} + + ) : ( + $t('pages.rules.disable') + )} + + + MT5:{' '} + {mt5Open === 1 ? ( + + {sourceType5Count ?? '-'} / {mt5Count ?? '-'} + + ) : ( + $t('pages.rules.disable') + )} + + + ); + }, + }, { title: $t('table.userCount'), dataIndex: 'userCount', diff --git a/src/pages/data-source/Popup.tsx b/src/pages/data-source/Popup.tsx index d908de8..92f0ca3 100644 --- a/src/pages/data-source/Popup.tsx +++ b/src/pages/data-source/Popup.tsx @@ -6,7 +6,7 @@ import { } from '@ant-design/pro-components'; import { useAccess } from '@umijs/max'; import { Divider, type FormInstance, Typography } from 'antd'; -import { useRef } from 'react'; +import { useMemo, useRef } from 'react'; import useUserInfo from '@/hooks/useUserInfo'; import { preventScientificNotation } from '@/utils'; import { $t } from '@/utils/i18n'; @@ -22,7 +22,7 @@ export default (props: { }) => { const { visible, formValues, onSubmit, onDone, companyList } = props; - const { userInfo } = useUserInfo(); + const { userInfo, userPlatform } = useUserInfo(); const { isGlobalCompany } = useAccess(); const globalCompanyId = isGlobalCompany ? userInfo?.companyId : 0; const formRef = useRef(null); @@ -41,6 +41,12 @@ export default (props: { message: $t('form.placeholder.ipAddress'), }, ]; + + const filteredUserPlatform = useMemo( + () => userPlatform.filter((v) => v?.isOpen), + [userPlatform], + ); + return ( 0 + ? filteredUserPlatform[0].value + : null, } } open={visible} @@ -78,16 +87,7 @@ export default (props: { label={$t('form.dataSource.type')} allowClear={false} rules={[{ required: true, message: $t('form.required') }]} - options={[ - // { - // value: 4, - // label: 'MT4', - // }, - { - value: 5, - label: 'MT5', - }, - ]} + options={filteredUserPlatform} /> {isGlobalCompany && ( diff --git a/src/pages/data-source/index.tsx b/src/pages/data-source/index.tsx index 1704abc..f2a174a 100644 --- a/src/pages/data-source/index.tsx +++ b/src/pages/data-source/index.tsx @@ -18,6 +18,7 @@ import { dataSourceHandle, getCompanyList, getDataSourcePages, + getPlatformList, } from '@/services/api'; import { $t } from '@/utils/i18n'; import Popup from './Popup'; @@ -49,6 +50,7 @@ const DataSource: React.FC = () => { setCompanyList(data || []); }); } + getPlatformList(); }, []); const [cardInfo, setCardInfo] = useState({ // mt4Count: 0, diff --git a/src/pages/rules/components/CopyRule/Multi‌CopyPopup.tsx b/src/pages/rules/components/CopyRule/Multi‌CopyPopup.tsx index 82291b8..801d796 100644 --- a/src/pages/rules/components/CopyRule/Multi‌CopyPopup.tsx +++ b/src/pages/rules/components/CopyRule/Multi‌CopyPopup.tsx @@ -4,7 +4,7 @@ import { useBreakpoint, } from '@ant-design/pro-components'; import { Button, Divider, Flex, Input, Modal, Space, Typography } from 'antd'; -import { createContext, useMemo, useRef, useState } from 'react'; +import { useMemo, useRef, useState } from 'react'; import useRichFormat from '@/hooks/useRichI18n'; import { $t } from '@/utils/i18n'; import '../style.less'; @@ -14,26 +14,9 @@ import { handleEmptyValuesFunc } from '../../utils'; import BatchCloneModal from './comp/BatchCloneModal'; import Step1 from './comp/Step1'; import Step2 from './comp/Step2'; +import { MultiCopyPopupContext } from './context'; const { Text, Title } = Typography; -type MultiCopyPopupContextValue = { - ruleMeta: Record; - dataSourceList: API.DataSourceListItem[]; - currentRuleType: number; - targetDataSourceId: string | number | null; - selectRules: API.RuleListItem[]; - setSelectRules: (rules: API.RuleListItem[]) => void; - currentSchemaMap: Record; -}; -export const MultiCopyPopupContext = createContext({ - ruleMeta: {}, - dataSourceList: [], - currentRuleType: 0, - targetDataSourceId: null, - selectRules: [], - setSelectRules: () => {}, - currentSchemaMap: {}, -}); type MultiCopyPopupProps = { visible: boolean; ruleMeta: Record; @@ -232,22 +215,22 @@ const MultiCopyPopup = ({ onValuesChange={({ sourceDataSourceId }) => { if (sourceDataSourceId) { const curFormRef = formMapRef?.current?.[0]?.current; - const curTargetDataSourceId = - curFormRef?.getFieldValue('targetDataSourceId'); - if (curTargetDataSourceId === sourceDataSourceId) { - let targetDataSourceId: string | number | null = null; - for (const item of dataSourceList) { - if (item.id !== sourceDataSourceId) { - targetDataSourceId = item.id; - break; - } - } - if (targetDataSourceId) { - curFormRef?.setFieldsValue({ - targetDataSourceId, - }); - setTargetDataSourceId(targetDataSourceId); - } + const curTargetId = curFormRef?.getFieldValue('targetDataSourceId'); + const sourceItem = dataSourceList.find( + (item) => item.id === sourceDataSourceId, + ); + const targetItem = dataSourceList.find( + (item) => item.id === curTargetId, + ); + if (targetItem && sourceItem && targetItem.sourceType !== sourceItem.sourceType) { + const fallback = + dataSourceList.find( + (item) => + item.id !== sourceDataSourceId && + item.sourceType === sourceItem.sourceType, + )?.id || sourceDataSourceId; + curFormRef?.setFieldsValue({ targetDataSourceId: fallback }); + setTargetDataSourceId(fallback); } } }} diff --git a/src/pages/rules/components/CopyRule/SingleCopyPopup.tsx b/src/pages/rules/components/CopyRule/SingleCopyPopup.tsx index e096366..6a34012 100644 --- a/src/pages/rules/components/CopyRule/SingleCopyPopup.tsx +++ b/src/pages/rules/components/CopyRule/SingleCopyPopup.tsx @@ -17,7 +17,7 @@ import { Row, Typography, } from 'antd'; -import { useEffect, useRef, useState } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import useRichFormat from '@/hooks/useRichI18n'; import { $t } from '@/utils/i18n'; import { type SchemaType, schemaMap } from '../../ruleFormSchema'; @@ -68,49 +68,83 @@ const SingleCopyPopup = ({ } = schemaMap[currentRuleType as unknown as SchemaType]?.({ richFormat }) || {}; - const rightDataSourceList = dataSourceList.filter( - (item) => item.id !== formValues?.dataSourceId, - ); + const sourceSourceType = useMemo(() => { + return dataSourceList.find((item) => item.id === formValues?.dataSourceId) + ?.sourceType; + }, [dataSourceList, formValues?.dataSourceId]); + + const dataSourceOptions = useMemo(() => { + return dataSourceList.map((item) => ({ + ...item, + disabled: item.sourceType !== sourceSourceType, + label: ( + + {item.sourceName} + + MT{item.sourceType} + + + ), + })); + }, [dataSourceList, sourceSourceType]); const initialValues = transformInitialValue?.(formValues) || formValues; - const rightFirstDataSource = rightDataSourceList[0]; + const rightFirstDataSource = + dataSourceOptions.find( + (item) => item.id !== formValues?.dataSourceId && !item.disabled, + ) || dataSourceOptions[0]; + const isSameSource = rightFirstDataSource?.id === formValues?.dataSourceId; const copyFormValues = { ...initialValues, name: initialValues?.name ? `${initialValues.name} - ${rightFirstDataSource?.sourceName}` : `${Date.now()} - ${rightFirstDataSource?.sourceName}`, - groupFilter: '', id: void 0, dataSourceId: rightFirstDataSource?.id || '', + ...(isSameSource + ? {} + : { + groupFilter: '', + ...(symbolFormShow ? { param2: '' } : {}), + ...(assetFormShow ? { param1: '' } : {}), + }), }; - if (symbolFormShow) { - copyFormValues.param2 = ''; - } - if (assetFormShow) { - copyFormValues.param1 = ''; - } const formContent = ({ - dataSourceList, + dataSourceList: options, formAttr, + onDataSourceChange, }: { - dataSourceList: API.DataSourceListItem[]; + dataSourceList: any[]; formAttr: Record; + onDataSourceChange?: (dataSourceId: string | number) => void; }) => { return ( - + { + if (changedValues.dataSourceId && onDataSourceChange) { + onDataSourceChange(changedValues.dataSourceId); + } + }} + > @@ -194,53 +228,64 @@ const SingleCopyPopup = ({ }, }} > - - -
- 📋 {$t('pages.rules.originalRule')} -
- {formContent({ - dataSourceList, - formAttr: { initialValues, disabled: true }, - })} - + {visible && ( + + +
+ 📋 {$t('pages.rules.originalRule')} +
+ {formContent({ + dataSourceList: dataSourceOptions, + formAttr: { initialValues, disabled: true }, + })} + - - - - - - + + + + + + - -
- -
- + +
+ +
+ - -
- ✏️ {$t('pages.rules.cloneRulePreview')} -
+ +
+ ✏️ {$t('pages.rules.cloneRulePreview')} +
- {formContent({ - dataSourceList: rightDataSourceList, - formAttr: { - initialValues: copyFormValues, - formRef: formRef, - disabled: confirmLoading, - }, - })} - {errMsg && ( - - )} - -
+ {formContent({ + dataSourceList: dataSourceOptions, + formAttr: { + initialValues: copyFormValues, + formRef: formRef, + disabled: confirmLoading, + }, + onDataSourceChange: (dataSourceId) => { + const isSame = dataSourceId === formValues?.dataSourceId; + if (!isSame) { + const fields: Record = { groupFilter: '' }; + if (symbolFormShow) fields.param2 = ''; + if (assetFormShow) fields.param1 = ''; + formRef.current?.setFieldsValue(fields); + } + }, + })} + {errMsg && ( + + )} + +
+ )} ); }; diff --git a/src/pages/rules/components/CopyRule/comp/BatchCloneModal.tsx b/src/pages/rules/components/CopyRule/comp/BatchCloneModal.tsx index da86944..0553332 100644 --- a/src/pages/rules/components/CopyRule/comp/BatchCloneModal.tsx +++ b/src/pages/rules/components/CopyRule/comp/BatchCloneModal.tsx @@ -17,10 +17,13 @@ import { Tag, Tooltip, } from 'antd'; -import { useEffect, useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { processSingleRule } from '@/pages/rules/utils'; import { $t } from '@/utils/i18n'; +type TaskStatus = 'waiting' | 'processing' | 'success' | 'warning' | 'error'; +type Task = { name: string; status: TaskStatus; errorMsg: string }; + type BatchCloneModalProps = { visible: boolean; selectedRows: Partial[]; @@ -33,26 +36,33 @@ const BatchCloneModal = ({ onClose, onFinish, }: BatchCloneModalProps) => { - const [tasks, setTasks] = useState([]); + const [tasks, setTasks] = useState([]); const [isRunning, setIsRunning] = useState(false); const [currentRunning, setCurrentRunning] = useState(0); + const selectedRowsRef = useRef(selectedRows); + selectedRowsRef.current = selectedRows; useEffect(() => { - const initialTasks = selectedRows.map((row) => ({ - name: row.name, - status: 'waiting', // waiting, processing, success, error - errorMsg: '', - })); - setTasks(initialTasks); - }, [visible, selectedRows]); + if (visible) { + setTasks( + selectedRows.map((row) => ({ + name: row.name || '', + status: 'waiting', + errorMsg: '', + })), + ); + setIsRunning(false); + setCurrentRunning(0); + } + }, [visible]); const finishedTasks = useMemo( - () => tasks.filter((t) => ['success', 'warning'].includes(t.status)), + () => tasks.filter((t) => t.status === 'success' || t.status === 'warning'), [tasks], ); const finishedMessage = useMemo(() => { - const hasWarning = finishedTasks.find((t) => t.status === 'warning'); + const hasWarning = finishedTasks.some((t) => t.status === 'warning'); const type: AlertProps['type'] = hasWarning ? 'warning' : finishedTasks.length === tasks.length @@ -69,9 +79,10 @@ const BatchCloneModal = ({ }; }, [finishedTasks, tasks]); - const startBatch = async () => { + const startBatch = useCallback(async () => { + const rows = selectedRowsRef.current; setIsRunning(true); - for (let i = 0; i < selectedRows.length; i++) { + for (let i = 0; i < rows.length; i++) { setCurrentRunning(i + 1); setTasks((prev) => { const next = [...prev]; @@ -79,8 +90,7 @@ const BatchCloneModal = ({ return next; }); try { - await processSingleRule({ payload: selectedRows[i] }); - + await processSingleRule({ payload: rows[i] }); setTasks((prev) => { const next = [...prev]; next[i].status = 'success'; @@ -96,13 +106,13 @@ const BatchCloneModal = ({ } } setIsRunning(false); - }; + }, []); - const handleReset = () => { + const handleReset = useCallback(() => { setTasks([]); setIsRunning(false); setCurrentRunning(0); - }; + }, []); return ( void; }; const RuleCheckCard = ({ dataSourceId }: RuleCheckCardProps) => { - const [ruleList, setRuleList] = useState([]); - const { ruleMeta, currentRuleType, setSelectRules } = useContext( MultiCopyPopupContext, ); + const [ruleList, setRuleList] = useState([]); const { loading } = useRequest( () => @@ -25,7 +23,6 @@ const RuleCheckCard = ({ dataSourceId }: RuleCheckCardProps) => { dataSourceId, }), { - // manual: true, refreshDeps: [dataSourceId, currentRuleType], onSuccess: ({ data = [] }: { data: API.RuleListItem[] }) => { setRuleList(data); @@ -37,15 +34,17 @@ const RuleCheckCard = ({ dataSourceId }: RuleCheckCardProps) => { }, ); + useEffect(() => { + return () => setSelectRules([]); + }, []); + if (!dataSourceId) return
{$t('pages.clones.step1.tips')}
; if (loading) return ; - // const - return ( { const { dataSourceList } = useContext(MultiCopyPopupContext); + const buildOptions = (sourceId?: string | number) => { + const sourceType = dataSourceList.find((item) => item.id === sourceId) + ?.sourceType; + return dataSourceList.map((item) => ({ + ...item, + disabled: item.sourceType !== sourceType, + label: ( + + {item.sourceName} + + MT{item.sourceType} + + + ), + })); + }; + + const sourceOptions = useMemo( + () => dataSourceList.map((item) => ({ + ...item, + label: ( + + {item.sourceName} + + MT{item.sourceType} + + + ), + })), + [dataSourceList], + ); + useEffect(() => { if (dataSourceList?.length) { - // waitTime(1000).then(() => { - const sourceDataSourceId = dataSourceList[0]?.id || ''; - const targetDataSourceId = dataSourceList[1]?.id || ''; + const sourceItem = dataSourceList[0]; + const sourceDataSourceId = sourceItem?.id || ''; + const sameTypeItem = dataSourceList.find( + (item) => item.id !== sourceDataSourceId && item.sourceType === sourceItem?.sourceType, + ); + const targetDataSourceId = sameTypeItem?.id || sourceDataSourceId; const curFormRef = formMapRef?.current?.[0]?.current; if (curFormRef) { curFormRef?.setFieldsValue({ @@ -26,7 +67,6 @@ const Step1 = ({ formMapRef, setTargetDataSourceId }: Step1Props) => { }); setTargetDataSourceId(targetDataSourceId); } - // }); } }, [dataSourceList]); @@ -35,14 +75,15 @@ const Step1 = ({ formMapRef, setTargetDataSourceId }: Step1Props) => { @@ -61,21 +102,20 @@ const Step1 = ({ formMapRef, setTargetDataSourceId }: Step1Props) => { {({ sourceDataSourceId }) => { if (!sourceDataSourceId) return null; - const dataSourceOptions = dataSourceList.filter( - (item) => item.id !== sourceDataSourceId, - ); + const targetOptions = buildOptions(sourceDataSourceId); return ( { setTargetDataSourceId(value || null); diff --git a/src/pages/rules/components/CopyRule/comp/Step2.tsx b/src/pages/rules/components/CopyRule/comp/Step2.tsx index d5bf321..e6890ce 100644 --- a/src/pages/rules/components/CopyRule/comp/Step2.tsx +++ b/src/pages/rules/components/CopyRule/comp/Step2.tsx @@ -16,7 +16,7 @@ import { import { useContext, useEffect, useMemo, useState } from 'react'; import { $t } from '@/utils/i18n'; import { RuleCardBodyInfo } from '../../RuleCardBody'; -import { MultiCopyPopupContext } from '../Multi‌CopyPopup'; +import { MultiCopyPopupContext } from '../context'; const { Text } = Typography; diff --git a/src/pages/rules/components/CopyRule/context.ts b/src/pages/rules/components/CopyRule/context.ts new file mode 100644 index 0000000..01cbc14 --- /dev/null +++ b/src/pages/rules/components/CopyRule/context.ts @@ -0,0 +1,21 @@ +import { createContext } from 'react'; + +type MultiCopyPopupContextValue = { + ruleMeta: Record; + dataSourceList: API.DataSourceListItem[]; + currentRuleType: number; + targetDataSourceId: string | number | null; + selectRules: API.RuleListItem[]; + setSelectRules: (rules: API.RuleListItem[]) => void; + currentSchemaMap: Record; +}; + +export const MultiCopyPopupContext = createContext({ + ruleMeta: {}, + dataSourceList: [], + currentRuleType: 0, + targetDataSourceId: null, + selectRules: [], + setSelectRules: () => {}, + currentSchemaMap: {}, +}); diff --git a/src/pages/rules/index.tsx b/src/pages/rules/index.tsx index df201b0..b8f54a1 100644 --- a/src/pages/rules/index.tsx +++ b/src/pages/rules/index.tsx @@ -297,10 +297,6 @@ const RuleCommon: React.FC = () => {