diff --git a/packages/base/src/hooks/useDbService/index.tsx b/packages/base/src/hooks/useDbService/index.tsx index 6bdade5ab0..318926f10a 100644 --- a/packages/base/src/hooks/useDbService/index.tsx +++ b/packages/base/src/hooks/useDbService/index.tsx @@ -2,10 +2,62 @@ import React, { useCallback, useMemo } from 'react'; import { useBoolean } from 'ahooks'; import { Select } from 'antd'; import { useDbServiceDriver } from '@actiontech/shared/lib/features'; -import { IListDBServiceTipItem } from '@actiontech/shared/lib/api/base/service/common'; +import { + IListDBServiceTipItem, + IListDBServiceV2 +} from '@actiontech/shared/lib/api/base/service/common'; import { DatabaseTypeLogo, ResponseCode } from '@actiontech/dms-kit'; +import { EnvironmentTag } from '@actiontech/shared'; import DBService from '@actiontech/shared/lib/api/base/service/DBService'; import { IListDBServiceTipsParams } from '@actiontech/shared/lib/api/base/service/DBService/index.d'; + +const getDbServiceDisplayLabel = (dbService: IListDBServiceTipItem) => { + return !!dbService.host && !!dbService.port + ? `${dbService.name} (${dbService.host}:${dbService.port})` + : dbService.name; +}; + +const renderDbServiceOptionLabel = (dbService: IListDBServiceTipItem) => { + return ( + + + {getDbServiceDisplayLabel(dbService)} + + ); +}; + +const mergeDbServiceEnvironmentTag = ( + tips: IListDBServiceTipItem[], + dbServices: IListDBServiceV2[] +) => { + if (dbServices.length === 0) { + return tips; + } + + return tips.map((tip) => { + const dbService = dbServices.find( + (item) => item.uid === tip.id || item.name === tip.name + ); + + if (!dbService?.environment_tag) { + return tip; + } + + return { + ...tip, + environment_tag: dbService.environment_tag + }; + }); +}; + const useDbService = () => { const [dbServiceList, setDbServiceList] = React.useState< IListDBServiceTipItem[] @@ -16,9 +68,28 @@ const useDbService = () => { (params: IListDBServiceTipsParams) => { setTrue(); DBService.ListDBServiceTips(params) - .then((res) => { + .then(async (res) => { if (res.data.code === ResponseCode.SUCCESS) { - setDbServiceList(res.data?.data ?? []); + const tips = res.data?.data ?? []; + if (!params.project_uid || tips.length === 0) { + setDbServiceList(tips); + return; + } + + const dbServicesRes = await DBService.ListDBServicesV2({ + project_uid: params.project_uid, + page_index: 1, + page_size: 999 + }); + + setDbServiceList( + mergeDbServiceEnvironmentTag( + tips, + dbServicesRes.data.code === ResponseCode.SUCCESS + ? dbServicesRes.data?.data ?? [] + : [] + ) + ); } else { setDbServiceList([]); } @@ -54,17 +125,14 @@ const useDbService = () => { .map((db) => { const id = db.id ?? ''; const name = db.name ?? ''; - const label = - !!db.host && !!db.port - ? `${db.name} (${db.host}:${db.port})` - : db.name; + const label = getDbServiceDisplayLabel(db); return ( - {label} + {renderDbServiceOptionLabel(db)} ); })} @@ -97,10 +165,8 @@ const useDbService = () => { .filter((db) => db.db_type === type) .map((db) => ({ value: valueType === 'id' ? db?.id : db?.name, - label: - !!db.host && !!db.port - ? `${db.name} (${db.host}:${db.port})` - : db.name + text: getDbServiceDisplayLabel(db), + label: renderDbServiceOptionLabel(db) })) })); }, diff --git a/packages/base/src/page/DataExportManagement/Create/components/CreateTask/ExportSourceForm/ExportSourceFormItem.tsx b/packages/base/src/page/DataExportManagement/Create/components/CreateTask/ExportSourceForm/ExportSourceFormItem.tsx index 97871d4c58..81a41c3652 100644 --- a/packages/base/src/page/DataExportManagement/Create/components/CreateTask/ExportSourceForm/ExportSourceFormItem.tsx +++ b/packages/base/src/page/DataExportManagement/Create/components/CreateTask/ExportSourceForm/ExportSourceFormItem.tsx @@ -169,6 +169,8 @@ const ExportSourceFormItem: React.FC< > { projectID?: string; } @@ -36,7 +49,8 @@ const EnvironmentField: React.FC = ({ if (res.data.code === ResponseCode.SUCCESS) { return res.data.data?.map((item) => ({ value: item.uid || '', - label: item.name || '' + label: item.name || '', + color: item.color || undefined })); } }), @@ -45,10 +59,11 @@ const EnvironmentField: React.FC = ({ ready: !!projectID } ); - const onAdd = (v: string) => { + const onAdd = (v: string, color?: string) => { startOperationLoading(); DmsApi.ProjectService.CreateEnvironmentTag({ environment_name: v, + color: color ?? '', project_uid: projectID ?? '' }) .then((res) => { @@ -105,6 +120,7 @@ const EnvironmentField: React.FC = ({ DmsApi.ProjectService.UpdateEnvironmentTag({ environment_tag_uid: item.value.toString(), environment_name: item.label, + color: item.color ?? '', project_uid: projectID ?? '' }) .then((res) => { @@ -134,6 +150,8 @@ const EnvironmentField: React.FC = ({ onDelete={onDelete} onUpdate={onUpdate} onAdd={onAdd} + colorable + presetColors={ENVIRONMENT_TAG_PRESET_COLORS} loading={operationLoading || loading} errorMessage={ boundServices.length > 0 diff --git a/packages/base/src/page/DataSource/components/List/columns.tsx b/packages/base/src/page/DataSource/components/List/columns.tsx index 764fb0d2de..a3be10105c 100644 --- a/packages/base/src/page/DataSource/components/List/columns.tsx +++ b/packages/base/src/page/DataSource/components/List/columns.tsx @@ -4,8 +4,8 @@ import { t } from '../../../../locale'; import { IListDBServiceV2 } from '@actiontech/shared/lib/api/base/service/common'; import { ActiontechTableColumn } from '@actiontech/dms-kit/es/components/ActiontechTable'; import { IListDBServicesV2Params } from '@actiontech/shared/lib/api/base/service/DBService/index.d'; -import { DatabaseTypeLogo, BasicTag } from '@actiontech/dms-kit'; -import { BasicTypographyEllipsis } from '@actiontech/shared'; +import { DatabaseTypeLogo } from '@actiontech/dms-kit'; +import { BasicTypographyEllipsis, EnvironmentTag } from '@actiontech/shared'; import ScanTypeTagsCell from 'sqle/src/page/SqlManagementConf/List/ScanTypeTagsCell'; import ConnectionResultColumn from './ConnectionResultColumn'; @@ -113,7 +113,9 @@ export const dataSourceColumns = ( if (!environment?.name) { return '-'; } - return {environment?.name}; + return ( + + ); }, filterCustomType: 'select', filterKey: 'filter_by_environment_tag_uid' diff --git a/packages/base/src/page/GlobalDataSource/List/columns.tsx b/packages/base/src/page/GlobalDataSource/List/columns.tsx index 5c2ab03103..17808ad47d 100644 --- a/packages/base/src/page/GlobalDataSource/List/columns.tsx +++ b/packages/base/src/page/GlobalDataSource/List/columns.tsx @@ -7,8 +7,8 @@ import { PageInfoWithoutIndexAndSize } from '@actiontech/dms-kit/es/components/ActiontechTable'; import { IListGlobalDBServicesV2Params } from '@actiontech/shared/lib/api/base/service/DBService/index.d'; -import { DatabaseTypeLogo, BasicTag } from '@actiontech/dms-kit'; -import { BasicTypographyEllipsis } from '@actiontech/shared'; +import { DatabaseTypeLogo } from '@actiontech/dms-kit'; +import { BasicTypographyEllipsis, EnvironmentTag } from '@actiontech/shared'; import ConnectionResultColumn from '../../DataSource/components/List/ConnectionResultColumn'; import { ListDBServiceV2LastConnectionTestStatusEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; @@ -42,7 +42,9 @@ export const GlobalDataSourceColumns = ( if (!environment?.name) { return '-'; } - return {environment?.name}; + return ( + + ); }, filterCustomType: 'select', filterKey: 'filter_by_environment_tag_uid' diff --git a/packages/base/src/page/Nav/SideMenu/ProjectSelector/index.tsx b/packages/base/src/page/Nav/SideMenu/ProjectSelector/index.tsx index 73089fd931..b69f2da270 100644 --- a/packages/base/src/page/Nav/SideMenu/ProjectSelector/index.tsx +++ b/packages/base/src/page/Nav/SideMenu/ProjectSelector/index.tsx @@ -125,7 +125,7 @@ const ProjectSelector: React.FC = ({ }} allowClear={false} dropdownRender={renderDropdown} - onDropdownVisibleChange={(visible) => { + onDropdownVisibleChange={(visible: boolean) => { setOpen(visible); if (!visible) { setSearchValue(''); diff --git a/packages/base/src/page/Project/Drawer/ProjectForm/BusinessField/index.tsx b/packages/base/src/page/Project/Drawer/ProjectForm/BusinessField/index.tsx index 162aaeaa56..5fff297251 100644 --- a/packages/base/src/page/Project/Drawer/ProjectForm/BusinessField/index.tsx +++ b/packages/base/src/page/Project/Drawer/ProjectForm/BusinessField/index.tsx @@ -1,5 +1,8 @@ import { EditableSelect } from '@actiontech/dms-kit'; -import { EditableSelectValue, EditableSelectOption } from '@actiontech/dms-kit'; +import type { + EditableSelectValue, + EditableSelectOption +} from '@actiontech/dms-kit/es/components/EditableSelect/EditableSelect.types'; import { useTranslation } from 'react-i18next'; import { DmsApi } from '@actiontech/shared/lib/api'; import { useRequest } from 'ahooks'; diff --git a/packages/base/src/page/ResourceOverview/components/ResourceDetail/columns.tsx b/packages/base/src/page/ResourceOverview/components/ResourceDetail/columns.tsx index 3211c4bd3e..3c33078491 100644 --- a/packages/base/src/page/ResourceOverview/components/ResourceDetail/columns.tsx +++ b/packages/base/src/page/ResourceOverview/components/ResourceDetail/columns.tsx @@ -6,6 +6,7 @@ import { DatabaseTypeLogo, BasicToolTip } from '@actiontech/dms-kit'; import { TableColumnWithIconStyleWrapper } from '@actiontech/dms-kit'; import { FlagFilled, DatabaseSchemaFilled } from '@actiontech/icons'; import { ResourceOverviewTheme } from '../../../../theme/type'; +import { EnvironmentTag } from '@actiontech/shared'; export const ResourceDetailListColumns = ( getLogoUrlByDbType: (dbType: string) => string, theme: ResourceOverviewTheme @@ -66,7 +67,16 @@ export const ResourceDetailListColumns = ( dataIndex: 'environment_tag', title: t('resourceOverview.resourceList.environment'), render: (environmentTag) => { - return environmentTag?.name ?? '-'; + if (!environmentTag?.name) { + return '-'; + } + + return ( + + ); }, filterCustomType: 'select', filterKey: 'filter_by_environment_tag_uid' diff --git a/packages/base/src/scripts/version.ts b/packages/base/src/scripts/version.ts index 6d5baaff06..75047c4dce 100644 --- a/packages/base/src/scripts/version.ts +++ b/packages/base/src/scripts/version.ts @@ -1 +1 @@ -export const UI_VERSION = 'sync/data-masking 417b194dd'; +export const UI_VERSION = 'main 6fdc83ce'; diff --git a/packages/dms-kit/src/components/CustomSelect/CustomSelect.tsx b/packages/dms-kit/src/components/CustomSelect/CustomSelect.tsx index a3899fe781..c7420991c3 100644 --- a/packages/dms-kit/src/components/CustomSelect/CustomSelect.tsx +++ b/packages/dms-kit/src/components/CustomSelect/CustomSelect.tsx @@ -41,6 +41,8 @@ const CustomSelect: React.FC = ({ typeof option.label === 'string' ? option.label : option.text ?? option.value; + const displayLabel = + typeof option.label === 'string' ? showLabel : option.label; if ( !showLabel.toLowerCase().includes(innerSearchValue?.toLowerCase() ?? '') @@ -52,7 +54,7 @@ const CustomSelect: React.FC = ({ optionLabel: !!props.mode ? ( showLabel ) : ( - + ) }; }; diff --git a/packages/dms-kit/src/components/EditableSelect/EditableSelect.tsx b/packages/dms-kit/src/components/EditableSelect/EditableSelect.tsx index 7d64322155..927eca7dcb 100644 --- a/packages/dms-kit/src/components/EditableSelect/EditableSelect.tsx +++ b/packages/dms-kit/src/components/EditableSelect/EditableSelect.tsx @@ -1,5 +1,7 @@ import { useState, useMemo } from 'react'; -import { Dropdown, Menu, Space, Popconfirm, Spin } from 'antd'; +import type { CSSProperties } from 'react'; +import GlobalStyles from '@mui/material/GlobalStyles'; +import { Dropdown, Menu, Space, Popconfirm, Spin, ColorPicker } from 'antd'; import { BasicButton } from '../BasicButton'; import { BasicInput } from '../BasicInput'; import { useTranslation } from 'react-i18next'; @@ -7,7 +9,10 @@ import { EditableSelectStyleWrapper, EditableSelectTriggerStyleWrapper } from './style'; -import { EditableSelectProps, EditableSelectOption } from './index.type'; +import { + EditableSelectProps, + EditableSelectOption +} from './EditableSelect.types'; import classNames from 'classnames'; import { EmptyBox } from '../EmptyBox'; import { @@ -21,6 +26,16 @@ import type { MenuProps } from 'antd'; import { ReminderInformation } from '../ReminderInformation'; import { BasicEmpty } from '../BasicEmpty'; +const COLOR_PICKER_POPUP_CLASS_NAME = 'editable-select-color-picker-popup'; + +const COLOR_PICKER_POPUP_STYLE: CSSProperties = { + zIndex: 1070 +}; + +const COLOR_PICKER_POPUP_INNER_STYLE: CSSProperties = { + zIndex: 1071 +}; + const EditableSelect: React.FC = ({ value, onChange, @@ -39,7 +54,9 @@ const EditableSelect: React.FC = ({ errorMessage, searchable = true, searchPlaceholder, - contentMaxHeight = 320 + contentMaxHeight = 320, + colorable = false, + presetColors = [] }) => { const { t } = useTranslation(); const [newItemName, setNewItemName] = useState(''); @@ -48,6 +65,8 @@ const EditableSelect: React.FC = ({ null ); const [editName, setEditName] = useState(''); + const [newItemColor, setNewItemColor] = useState(); + const [editColor, setEditColor] = useState(); const [dropdownOpen, setDropdownOpen] = useState(false); const [deletingItem, setDeletingItem] = useState( null @@ -55,29 +74,34 @@ const EditableSelect: React.FC = ({ const [searchValue, setSearchValue] = useState(''); const handleAdd = () => { - onAdd?.(newItemName); + onAdd?.(newItemName, newItemColor); setNewItemName(''); + setNewItemColor(undefined); setIsAdding(false); }; const handleUpdate = () => { onUpdate?.({ value: editingItem?.value ?? '', - label: editName.trim() + label: editName.trim(), + color: editColor }); setEditingItem(null); setEditName(''); + setEditColor(undefined); }; const startEditing = (item: EditableSelectOption) => { setEditingItem(item); setEditName(item.label); + setEditColor(item.color); setDeletingItem(null); }; const cancelEditing = () => { setEditingItem(null); setEditName(''); + setEditColor(undefined); }; const startAdding = () => { @@ -87,9 +111,11 @@ const EditableSelect: React.FC = ({ const resetState = () => { setNewItemName(''); + setNewItemColor(undefined); setIsAdding(false); setEditingItem(null); setEditName(''); + setEditColor(undefined); setDeletingItem(null); setSearchValue(''); }; @@ -112,6 +138,15 @@ const EditableSelect: React.FC = ({ ); }, [searchable, searchValue, options]); + const colorPresets = presetColors.length + ? [ + { + label: '', + colors: presetColors + } + ] + : undefined; + const generateMenuItems = (): MenuProps['items'] => { const optionItems: MenuProps['items'] = filteredOptions.map((option) => ({ key: option.value, @@ -133,6 +168,25 @@ const EditableSelect: React.FC = ({ autoFocus onChange={(e) => setEditName(e.target.value)} /> + +
+ {t('common.color')} + + setEditColor(color.toHexString()) + } + allowClear + onClear={() => setEditColor(undefined)} + /> +
+
{t('common.cancel')} @@ -149,7 +203,15 @@ const EditableSelect: React.FC = ({
) : ( <> - {option.label} + + + + + {option.label} + = ({ onChange={(e) => setNewItemName(e.target.value)} placeholder={t('common.form.placeholder.input')} /> + +
+ {t('common.color')} + + setNewItemColor(color.toHexString()) + } + allowClear + onClear={() => setNewItemColor(undefined)} + /> +
+
= ({ ); const selectedLabel = options.find((o) => o.value === value)?.label; + const selectedColor = options.find((o) => o.value === value)?.color; return ( - dropdownContentRender} - trigger={['click']} - open={dropdownOpen} - onOpenChange={onOpenChange} - disabled={disabled} - > - + + dropdownContentRender} + trigger={['click']} open={dropdownOpen} + onOpenChange={onOpenChange} disabled={disabled} - className={classNames('editable-select-trigger', { - 'editable-select-trigger-disabled': disabled - })} > - {selectedLabel ? ( - {selectedLabel} - ) : ( - - {placeholder ?? t('common.form.placeholder.select')} - - )} - - {dropdownOpen ? ( - + + {selectedLabel ? ( + + + + + {selectedLabel} + ) : ( - + + {placeholder ?? t('common.form.placeholder.select')} + )} - - - + + {dropdownOpen ? ( + + ) : ( + + )} + + + + ); }; diff --git a/packages/dms-kit/src/components/EditableSelect/index.type.ts b/packages/dms-kit/src/components/EditableSelect/EditableSelect.types.ts similarity index 86% rename from packages/dms-kit/src/components/EditableSelect/index.type.ts rename to packages/dms-kit/src/components/EditableSelect/EditableSelect.types.ts index 9c0dd9a989..7895a34362 100644 --- a/packages/dms-kit/src/components/EditableSelect/index.type.ts +++ b/packages/dms-kit/src/components/EditableSelect/EditableSelect.types.ts @@ -5,13 +5,14 @@ export type EditableSelectValue = string | number; export interface EditableSelectOption { value: EditableSelectValue; label: string; + color?: string; } export interface EditableSelectProps { value?: EditableSelectValue; onChange?: (value: EditableSelectValue) => void; loading?: boolean; - onAdd?: (value: string) => void; + onAdd?: (value: string, color?: string) => void; addable?: boolean; onUpdate?: (newData: EditableSelectOption) => void; updatable?: boolean; @@ -26,4 +27,6 @@ export interface EditableSelectProps { searchable?: boolean; searchPlaceholder?: string; contentMaxHeight?: number; + colorable?: boolean; + presetColors?: string[]; } diff --git a/packages/dms-kit/src/components/EditableSelect/__tests__/EditableSelect.test.tsx b/packages/dms-kit/src/components/EditableSelect/__tests__/EditableSelect.test.tsx index 422cd90c38..1c22423ed0 100644 --- a/packages/dms-kit/src/components/EditableSelect/__tests__/EditableSelect.test.tsx +++ b/packages/dms-kit/src/components/EditableSelect/__tests__/EditableSelect.test.tsx @@ -1,7 +1,7 @@ import { fireEvent, act, screen } from '@testing-library/react'; import { superRender } from '../../../testUtil/superRender'; import EditableSelect from '../EditableSelect'; -import { EditableSelectOption } from '../index.type'; +import { EditableSelectOption } from '../EditableSelect.types'; import { getBySelector, getAllBySelector, diff --git a/packages/dms-kit/src/components/EditableSelect/index.ts b/packages/dms-kit/src/components/EditableSelect/index.ts index a8057705d8..546eaf4247 100644 --- a/packages/dms-kit/src/components/EditableSelect/index.ts +++ b/packages/dms-kit/src/components/EditableSelect/index.ts @@ -1,2 +1,2 @@ export { default as EditableSelect } from './EditableSelect'; -export type * from './index.type'; +export type * from './EditableSelect.types'; diff --git a/packages/dms-kit/src/components/EditableSelect/style.ts b/packages/dms-kit/src/components/EditableSelect/style.ts index 5d536cc59e..c71c169cf9 100644 --- a/packages/dms-kit/src/components/EditableSelect/style.ts +++ b/packages/dms-kit/src/components/EditableSelect/style.ts @@ -71,13 +71,36 @@ export const EditableSelectStyleWrapper = styled('div')<{ width: 100%; padding: 0 8px; + .editable-select-color-row { + display: flex; + align-items: center; + justify-content: space-between; + margin-top: 8px; + } + .button-group { display: flex; justify-content: flex-end; - gap: 8px; margin-top: 8px; + + button + button { + margin-left: 8px; + } } } + + .editable-select-option-label { + display: inline-flex; + align-items: center; + } + + .editable-select-color-dot { + width: 6px; + height: 6px; + margin-right: 6px; + border-radius: 50%; + flex-shrink: 0; + } `; export const EditableSelectTriggerStyleWrapper = styled('div')<{ @@ -119,4 +142,17 @@ export const EditableSelectTriggerStyleWrapper = styled('div')<{ .arrow-icon { display: flex; } + + .editable-select-option-label { + display: inline-flex; + align-items: center; + } + + .editable-select-color-dot { + width: 6px; + height: 6px; + margin-right: 6px; + border-radius: 50%; + flex-shrink: 0; + } `; diff --git a/packages/dms-kit/src/index.ts b/packages/dms-kit/src/index.ts index 5a44baf151..efae1cac3b 100644 --- a/packages/dms-kit/src/index.ts +++ b/packages/dms-kit/src/index.ts @@ -49,6 +49,7 @@ export * from './components/CustomSelect'; export * from './components/DatabaseTypeLogo'; export * from './components/EditText'; export * from './components/EditableSelect'; +export type * from './components/EditableSelect/EditableSelect.types'; export * from './components/EmptyBox'; export * from './components/HeaderProgress'; export * from './components/LazyLoadComponent'; diff --git a/packages/dms-kit/src/locale/en-US/common.ts b/packages/dms-kit/src/locale/en-US/common.ts index dbaa131e98..36c1b03c3c 100644 --- a/packages/dms-kit/src/locale/en-US/common.ts +++ b/packages/dms-kit/src/locale/en-US/common.ts @@ -7,6 +7,7 @@ export default { unknownStatus: 'Unknown status...', unknown: 'Unknown', status: 'Status', + color: 'Color', all: 'All', enabled: 'Enabled', diff --git a/packages/dms-kit/src/locale/zh-CN/common.ts b/packages/dms-kit/src/locale/zh-CN/common.ts index ee88718814..df41ecb45c 100644 --- a/packages/dms-kit/src/locale/zh-CN/common.ts +++ b/packages/dms-kit/src/locale/zh-CN/common.ts @@ -7,6 +7,7 @@ export default { unknownStatus: '未知状态...', unknown: '未知', status: '状态', + color: '颜色', all: '全部', enabled: '已启用', diff --git a/packages/shared/lib/api/base/service/Project/index.d.ts b/packages/shared/lib/api/base/service/Project/index.d.ts index 6cfc9bfc63..61318a3ec6 100644 --- a/packages/shared/lib/api/base/service/Project/index.d.ts +++ b/packages/shared/lib/api/base/service/Project/index.d.ts @@ -168,6 +168,8 @@ export interface ICreateEnvironmentTagParams { project_uid: string; environment_name: string; + + color?: string; } export interface ICreateEnvironmentTagReturn extends IGenericResp {} @@ -178,6 +180,8 @@ export interface IUpdateEnvironmentTagParams { environment_tag_uid: string; environment_name: string; + + color?: string; } export interface IUpdateEnvironmentTagReturn extends IGenericResp {} diff --git a/packages/shared/lib/api/base/service/common.d.ts b/packages/shared/lib/api/base/service/common.d.ts index 5d9d120e87..9de62bde99 100644 --- a/packages/shared/lib/api/base/service/common.d.ts +++ b/packages/shared/lib/api/base/service/common.d.ts @@ -796,6 +796,8 @@ export interface IDeleteSensitiveDataDiscoveryTaskReply { } export interface IEnvironmentTag { + color?: string; + name?: string; uid?: string; @@ -1658,6 +1660,8 @@ export interface IListDBServiceSyncTasksReply { export interface IListDBServiceTipItem { db_type?: string; + environment_tag?: IEnvironmentTag; + host?: string; id?: string; diff --git a/packages/shared/lib/api/sqle/service/common.d.ts b/packages/shared/lib/api/sqle/service/common.d.ts index 57804bfc7f..6782ae9008 100644 --- a/packages/shared/lib/api/sqle/service/common.d.ts +++ b/packages/shared/lib/api/sqle/service/common.d.ts @@ -4943,6 +4943,8 @@ export interface IInstanceTipResV2 { enable_backup?: boolean; + environment_tag_color?: string; + environment_tag_name?: string; environment_tag_uid?: string; diff --git a/packages/shared/lib/components/EnvironmentTag/index.tsx b/packages/shared/lib/components/EnvironmentTag/index.tsx new file mode 100644 index 0000000000..b8b9de0146 --- /dev/null +++ b/packages/shared/lib/components/EnvironmentTag/index.tsx @@ -0,0 +1,40 @@ +import { CSSProperties, memo } from 'react'; +import { EnvironmentTagStyleWrapper } from './style'; + +export const DEFAULT_ENVIRONMENT_TAG_COLOR = '#8C8C8C'; + +export type EnvironmentTagProps = { + name?: string; + color?: string; + size?: 'small' | 'default'; + className?: string; + style?: CSSProperties; +}; + +const EnvironmentTag: React.FC = ({ + name, + color, + size = 'default', + className, + style +}) => { + if (!name) { + return null; + } + + const tagColor = color || DEFAULT_ENVIRONMENT_TAG_COLOR; + + return ( + + + {name} + + ); +}; + +export default memo(EnvironmentTag); diff --git a/packages/shared/lib/components/EnvironmentTag/style.ts b/packages/shared/lib/components/EnvironmentTag/style.ts new file mode 100644 index 0000000000..597772a004 --- /dev/null +++ b/packages/shared/lib/components/EnvironmentTag/style.ts @@ -0,0 +1,47 @@ +import { styled } from '@mui/material/styles'; + +const hexToRgba = (hexColor: string, alpha: number) => { + if (!/^#([0-9a-fA-F]{6})$/.test(hexColor)) { + return `rgba(140, 140, 140, ${alpha})`; + } + + const red = parseInt(hexColor.slice(1, 3), 16); + const green = parseInt(hexColor.slice(3, 5), 16); + const blue = parseInt(hexColor.slice(5, 7), 16); + + return `rgba(${red}, ${green}, ${blue}, ${alpha})`; +}; + +export const EnvironmentTagStyleWrapper = styled('span')<{ + color: string; + size: 'small' | 'default'; +}>` + display: inline-flex; + align-items: center; + width: max-content; + max-width: 100%; + height: ${({ size }) => (size === 'small' ? '22px' : '24px')}; + padding: ${({ size }) => (size === 'small' ? '0 6px' : '0 8px')}; + border-radius: 4px; + color: ${({ color }) => color}; + background: ${({ color }) => hexToRgba(color, 0.1)}; + border: 1px solid ${({ color }) => hexToRgba(color, 0.32)}; + font-size: 12px; + line-height: 1; + vertical-align: middle; + + .environment-tag-color-dot { + flex-shrink: 0; + width: 6px; + height: 6px; + margin-right: 6px; + border-radius: 50%; + background: ${({ color }) => color}; + } + + .environment-tag-name { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +`; diff --git a/packages/shared/lib/components/index.ts b/packages/shared/lib/components/index.ts index 3d18e42c24..383c268bee 100644 --- a/packages/shared/lib/components/index.ts +++ b/packages/shared/lib/components/index.ts @@ -14,3 +14,6 @@ export * from './TypedRouter'; export * from './BasicMDEditor'; export * from './BackendForm'; + +export { default as EnvironmentTag } from './EnvironmentTag'; +export type * from './EnvironmentTag'; diff --git a/packages/sqle/src/hooks/useInstance/index.tsx b/packages/sqle/src/hooks/useInstance/index.tsx index 62cae3499b..b3476fef60 100644 --- a/packages/sqle/src/hooks/useInstance/index.tsx +++ b/packages/sqle/src/hooks/useInstance/index.tsx @@ -6,6 +6,7 @@ import { instanceListDefaultKey } from '../../data/common'; import { IGetInstanceTipListV2Params } from '@actiontech/shared/lib/api/sqle/service/instance/index.d'; import { IInstanceTipResV2 } from '@actiontech/shared/lib/api/sqle/service/common'; import { DatabaseTypeLogo } from '@actiontech/dms-kit'; +import { EnvironmentTag } from '@actiontech/shared'; import useDatabaseType from '../useDatabaseType'; import { SqleApi } from '@actiontech/shared/lib/api'; const useInstance = () => { @@ -65,14 +66,25 @@ const useInstance = () => { {filterInstanceList .filter((item) => item.instance_type === type) .map((item) => { + const label = + !!item.host && !!item.port + ? `${item.instance_name} (${item.host}:${item.port})` + : item.instance_name; return ( - {!!item.host && !!item.port - ? `${item.instance_name} (${item.host}:${item.port})` - : item.instance_name} + + + {label} + ); })} @@ -95,7 +107,18 @@ const useInstance = () => { .filter((v) => v.instance_type === type) .map((v) => ({ value: v.instance_name, - label: `${v.instance_name}(${v.host}:${v.port})` + text: `${v.instance_name}(${v.host}:${v.port})`, + label: ( + + + {`${v.instance_name}(${v.host}:${v.port})`} + + ) })) }; }); @@ -114,7 +137,18 @@ const useInstance = () => { .filter((v) => v.instance_type === type) .map((v) => ({ value: v.instance_id, - label: `${v.instance_name}(${v.host}:${v.port})` + text: `${v.instance_name}(${v.host}:${v.port})`, + label: ( + + + {`${v.instance_name}(${v.host}:${v.port})`} + + ) })) }; }); diff --git a/packages/sqle/src/hooks/useServiceEnvironment/index.ts b/packages/sqle/src/hooks/useServiceEnvironment/index.ts index bd8844e5ad..18d87a806a 100644 --- a/packages/sqle/src/hooks/useServiceEnvironment/index.ts +++ b/packages/sqle/src/hooks/useServiceEnvironment/index.ts @@ -1,7 +1,8 @@ import { useRequest } from 'ahooks'; import { DmsApi } from '@actiontech/shared/lib/api'; import { ResponseCode } from '@actiontech/dms-kit'; -import { useMemo } from 'react'; +import { createElement, useMemo } from 'react'; +import { EnvironmentTag } from '@actiontech/shared'; const useServiceEnvironment = () => { const { @@ -32,7 +33,12 @@ const useServiceEnvironment = () => { const environmentOptions = useMemo(() => { return ( data?.map((environment) => ({ - label: environment.name, + label: createElement(EnvironmentTag, { + name: environment.name, + color: environment.color, + size: 'small' + }), + text: environment.name, value: environment.uid })) ?? [] ); diff --git a/packages/sqle/src/page/GlobalDashboard/components/TableFilter/index.tsx b/packages/sqle/src/page/GlobalDashboard/components/TableFilter/index.tsx index b56d05eb5f..85971a7118 100644 --- a/packages/sqle/src/page/GlobalDashboard/components/TableFilter/index.tsx +++ b/packages/sqle/src/page/GlobalDashboard/components/TableFilter/index.tsx @@ -1,4 +1,4 @@ -import { Form, Space } from 'antd'; +import { Form, Space, SelectProps } from 'antd'; import { CustomSelect } from '@actiontech/dms-kit'; import { useTranslation } from 'react-i18next'; import { GlobalDashboardFilterStyleWrapper } from '../../style'; @@ -24,7 +24,9 @@ const GlobalDashboardTableFilter: React.FC = ({ placeholder={t('common.all')} suffixIcon={null} options={projectOptions} - onChange={(value) => { + onChange={( + value: Parameters>[0] + ) => { onProjectChange?.(value as string); }} /> diff --git a/packages/sqle/src/page/Rule/RuleListFilter/CustomSelectField.tsx b/packages/sqle/src/page/Rule/RuleListFilter/CustomSelectField.tsx index 897fe1dedf..79bb5790cf 100644 --- a/packages/sqle/src/page/Rule/RuleListFilter/CustomSelectField.tsx +++ b/packages/sqle/src/page/Rule/RuleListFilter/CustomSelectField.tsx @@ -1,4 +1,5 @@ import { CustomSelect, CustomSelectProps } from '@actiontech/dms-kit'; +import { SelectProps } from 'antd'; const CustomSelectField: React.FC< CustomSelectProps & { onAfterChange: (v: string) => void } @@ -6,9 +7,12 @@ const CustomSelectField: React.FC< return ( { + onChange={( + v: Parameters>[0], + option: Parameters>[1] + ) => { onChange?.(v, option); - onAfterChange(v); + onAfterChange(v as string); }} /> ); diff --git a/packages/sqle/src/page/SqlAudit/Create/SQLInfoForm/DatabaseInfo.tsx b/packages/sqle/src/page/SqlAudit/Create/SQLInfoForm/DatabaseInfo.tsx index c9e7c5038e..e2b3916cfe 100644 --- a/packages/sqle/src/page/SqlAudit/Create/SQLInfoForm/DatabaseInfo.tsx +++ b/packages/sqle/src/page/SqlAudit/Create/SQLInfoForm/DatabaseInfo.tsx @@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next'; import { AuditTypeEnum, DatabaseInfoProps } from './index.type'; import { FormItemLabel, FormItemNoLabel } from '@actiontech/dms-kit'; import { useCallback, useContext, useMemo, useState } from 'react'; -import { Form, Space } from 'antd'; +import { Form, Space, SelectProps } from 'antd'; import { CustomSelect } from '@actiontech/dms-kit'; import useInstanceSchema from '../../../../hooks/useInstanceSchema'; import { IInstanceResV2 } from '@actiontech/shared/lib/api/sqle/service/common'; @@ -152,7 +152,9 @@ const DatabaseInfo = ({ disabled={submitLoading} loading={instanceLoading} options={instanceOptions} - onChange={(value) => handleInstanceNameChange(value)} + onChange={( + value: Parameters>[0] + ) => handleInstanceNameChange(value as string)} /> = ({ ? versionFirstStageInstanceOptions : instanceOptions } - onChange={(name) => { + onChange={( + name: Parameters< + NonNullable + >[0] + ) => { form.setFieldValue( ['databaseInfo', field.name, 'instanceSchema'], undefined @@ -240,8 +244,15 @@ const DatabaseSelectionItem: React.FC = ({ !form.getFieldValue('databaseInfo')?.[index] ?.instanceName } - onChange={(value) => - handleInstanceSchemaChange(fieldKey, value) + onChange={( + value: Parameters< + NonNullable + >[0] + ) => + handleInstanceSchemaChange( + fieldKey, + value as string + ) } prefix={ diff --git a/packages/sqle/src/page/SqlManagementConf/List/column.tsx b/packages/sqle/src/page/SqlManagementConf/List/column.tsx index 21d2bb1cc1..99f6fa7f98 100644 --- a/packages/sqle/src/page/SqlManagementConf/List/column.tsx +++ b/packages/sqle/src/page/SqlManagementConf/List/column.tsx @@ -7,6 +7,7 @@ import { t } from '../../../locale'; import { DatabaseTypeLogo, BasicToolTip, EmptyBox } from '@actiontech/dms-kit'; import { TypedLink } from '@actiontech/shared'; import { IInstanceAuditPlanResV1 } from '@actiontech/shared/lib/api/sqle/service/common'; +import { IEnvironmentTag } from '@actiontech/shared/lib/api/base/service/common'; import { InstanceAuditPlanTableFilterParamType } from './index.type'; import { formatTime, @@ -26,6 +27,7 @@ import { import ScanTypeTagsCell from './ScanTypeTagsCell'; import { InfoCircleOutlined } from '@actiontech/icons/'; import { PlanListTaskTypeButtonStyleWrapper } from './style'; +import { EnvironmentTag } from '@actiontech/shared'; export const ExtraFilterMeta: () => ActiontechTableFilterMeta< IInstanceAuditPlanResV1, InstanceAuditPlanTableFilterParamType @@ -46,11 +48,12 @@ export const ExtraFilterMeta: () => ActiontechTableFilterMeta< }; export const SqlManagementConfColumns: ( projectID: string, - getLogoUrlByDbType: (dbType: string) => string + getLogoUrlByDbType: (dbType: string) => string, + environmentList: IEnvironmentTag[] ) => ActiontechTableColumn< IInstanceAuditPlanResV1, InstanceAuditPlanTableFilterParamType -> = (projectID, getLogoUrlByDbType) => { +> = (projectID, getLogoUrlByDbType, environmentList) => { return [ { dataIndex: 'instance_name', @@ -103,7 +106,20 @@ export const SqlManagementConfColumns: ( dataIndex: 'environment', title: () => t('managementConf.list.table.column.environmentAttribute'), render: (environment) => { - return environment || '-'; + if (!environment) { + return '-'; + } + + const matchedEnvironment = environmentList.find( + (item) => item.name === environment || item.uid === environment + ); + + return ( + + ); }, filterCustomType: 'select', filterKey: 'filter_by_environment_tag' diff --git a/packages/sqle/src/page/SqlManagementConf/List/hooks/useTableFilter.ts b/packages/sqle/src/page/SqlManagementConf/List/hooks/useTableFilter.ts index 32258ddd3c..76d7ed7459 100644 --- a/packages/sqle/src/page/SqlManagementConf/List/hooks/useTableFilter.ts +++ b/packages/sqle/src/page/SqlManagementConf/List/hooks/useTableFilter.ts @@ -12,7 +12,8 @@ const useInstanceAuditPlanFilter = () => { const { updateInstanceList, instanceIDOptions } = useInstance(); - const { environmentOptions, updateEnvironmentList } = useServiceEnvironment(); + const { environmentList, environmentOptions, updateEnvironmentList } = + useServiceEnvironment(); const filterCustomProps = useMemo(() => { return new Map([ @@ -61,7 +62,8 @@ const useInstanceAuditPlanFilter = () => { filterCustomData, setFilterCustomData, updateInstanceList, - updateEnvironmentList + updateEnvironmentList, + environmentList }; }; diff --git a/packages/sqle/src/page/SqlManagementConf/List/index.tsx b/packages/sqle/src/page/SqlManagementConf/List/index.tsx index 9e505ded25..fb6e57ace4 100644 --- a/packages/sqle/src/page/SqlManagementConf/List/index.tsx +++ b/packages/sqle/src/page/SqlManagementConf/List/index.tsx @@ -48,10 +48,6 @@ const List: React.FC = () => { useTableRequestError(); const [messageApi, contextMessageHolder] = message.useMessage(); const { getLogoUrlByDbType } = useDbServiceDriver(); - const columns = useMemo( - () => SqlManagementConfColumns(projectID, getLogoUrlByDbType), - [getLogoUrlByDbType, projectID] - ); const { tableFilterInfo, tableChange, @@ -65,15 +61,21 @@ const List: React.FC = () => { InstanceAuditPlanTableFilterParamType >(); const { parse2TableActionPermissions } = usePermission(); - const { filterButtonMeta, filterContainerMeta, updateAllSelectedFilterItem } = - useTableFilterContainer(columns, updateTableFilterInfo, ExtraFilterMeta()); const { filterCustomData, filterCustomProps, + environmentList, setFilterCustomData, updateInstanceList, updateEnvironmentList } = useTableFilter(); + const columns = useMemo( + () => + SqlManagementConfColumns(projectID, getLogoUrlByDbType, environmentList), + [getLogoUrlByDbType, projectID, environmentList] + ); + const { filterButtonMeta, filterContainerMeta, updateAllSelectedFilterItem } = + useTableFilterContainer(columns, updateTableFilterInfo, ExtraFilterMeta()); const [ taskTypeShowStatus, { setFalse: setTaskTypeHide, setTrue: setTaskTypeShow } diff --git a/packages/sqle/src/page/SqlOptimization/Create/SQLInfoForm/DatabaseInfo.tsx b/packages/sqle/src/page/SqlOptimization/Create/SQLInfoForm/DatabaseInfo.tsx index 557d7ca4ff..54017443d1 100644 --- a/packages/sqle/src/page/SqlOptimization/Create/SQLInfoForm/DatabaseInfo.tsx +++ b/packages/sqle/src/page/SqlOptimization/Create/SQLInfoForm/DatabaseInfo.tsx @@ -1,6 +1,6 @@ import { useTranslation } from 'react-i18next'; import { DatabaseInfoProps } from '../../index.type'; -import { Alert, Form, Space } from 'antd'; +import { Alert, Form, Space, SelectProps } from 'antd'; import { CustomSelect } from '@actiontech/dms-kit'; import useInstanceSchema from '../../../../hooks/useInstanceSchema'; import { useCurrentProject } from '@actiontech/shared/lib/features'; @@ -82,7 +82,9 @@ const DatabaseInfo: React.FC = ({ disabled={submitLoading} loading={instanceLoading} options={instanceOptions} - onChange={(value) => handleInstanceNameChange(value)} + onChange={( + value: Parameters>[0] + ) => handleInstanceNameChange(value as string)} />