diff --git a/react-ui/src/components/CodeConfigItem/index.less b/react-ui/src/components/CodeConfigItem/index.less index ce6cb059..bc450f47 100644 --- a/react-ui/src/components/CodeConfigItem/index.less +++ b/react-ui/src/components/CodeConfigItem/index.less @@ -1,11 +1,22 @@ .code-config-item { position: relative; - width: calc(25% - 7.5px); + width: calc(33.33% - 7px); padding: 15px; background-color: .addAlpha(@primary-color, 0.04) []; border: 1px solid transparent; border-radius: 4px; - cursor: pointer; + + &__checkbox { + flex: 1; + min-width: 0; + + :global { + .ant-checkbox + span { + flex: 1; + min-width: 0; + } + } + } &__name { margin-right: 8px; @@ -38,6 +49,8 @@ margin-bottom: 10px !important; color: @text-color-secondary; font-size: 13px; + cursor: pointer; + word-break: break-all; } &__branch { @@ -46,11 +59,17 @@ } &:hover { + background-color: .addAlpha(@primary-color, 0.08) []; + } + + &--active { border-color: @primary-color; box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.1); } - &:hover &__name { + &--active &__name { color: @primary-color; } + + } diff --git a/react-ui/src/components/CodeConfigItem/index.tsx b/react-ui/src/components/CodeConfigItem/index.tsx index 942fa203..afe3e6ee 100644 --- a/react-ui/src/components/CodeConfigItem/index.tsx +++ b/react-ui/src/components/CodeConfigItem/index.tsx @@ -1,25 +1,51 @@ import { type CodeConfigData } from '@/pages/CodeConfig/List'; -import { Flex, Typography } from 'antd'; +import { getGitUrl } from '@/utils'; +import { Checkbox, Flex, Typography } from 'antd'; +import { type CheckboxChangeEvent } from 'antd/es/checkbox'; import classNames from 'classnames'; import { useState } from 'react'; import styles from './index.less'; type CodeConfigItemProps = { item: CodeConfigData; - onClick?: (item: CodeConfigData) => void; + checked: boolean; + onChange?: (item: CodeConfigData, checked: boolean) => void; }; -function CodeConfigItem({ item, onClick }: CodeConfigItemProps) { +function CodeConfigItem({ item, checked, onChange }: CodeConfigItemProps) { const [isEllipsis, setIsEllipsis] = useState(false); + + const openProject = (e: React.MouseEvent) => { + e.stopPropagation(); + const { git_url, git_branch } = item; + const url = getGitUrl(git_url, git_branch); + window.open(url, '_blank'); + }; + + const handleChange = (e: CheckboxChangeEvent) => { + onChange?.(item, e.target.checked); + }; + return ( -
onClick?.(item)}> +
- - {item.code_repo_name} - + + {item.code_repo_name} + +
setIsEllipsis(ellipsis), + tooltip: isEllipsis ? item.git_url : false, + onEllipsis: (ellipsis) => setIsEllipsis(ellipsis), // 必须这样,不然不能省略 }} + onClick={openProject} > {item.git_url} diff --git a/react-ui/src/components/CodeSelect/index.tsx b/react-ui/src/components/CodeSelect/index.tsx index 059d857f..12f52c07 100644 --- a/react-ui/src/components/CodeSelect/index.tsx +++ b/react-ui/src/components/CodeSelect/index.tsx @@ -18,7 +18,19 @@ export { type ParameterInputValue, } from '../ParameterInput'; -type CodeSelectProps = ParameterInputProps; +export type CodeSelectProps = ParameterInputProps; + +// 服务的需要的代码配置数据格式 +export type ServerCodeData = { + id: number; + name: string; + code_path: string; + branch: string; + username: string; + password: string; + ssh_private_key: string; + is_public: boolean; +}; /** 代码配置选择表单组件 */ function CodeSelect({ @@ -32,11 +44,34 @@ function CodeSelect({ }: CodeSelectProps) { // 选择代码配置 const selectResource = () => { + const codeData = value as ServerCodeData; + const defaultSelected = + value && typeof value === 'object' + ? { + id: codeData.id, + code_repo_name: codeData.name, + git_url: codeData.code_path, + git_branch: codeData.branch, + git_user_name: codeData.username, + git_password: codeData.password, + ssh_key: codeData.ssh_private_key, + is_public: codeData.is_public, + } + : undefined; const { close } = openAntdModal(CodeSelectorModal, { + defaultSelected: defaultSelected, onOk: (res) => { if (res) { - const { id, code_repo_name, git_url, git_branch, git_user_name, git_password, ssh_key } = - res; + const { + id, + code_repo_name, + git_url, + git_branch, + git_user_name, + git_password, + ssh_key, + is_public, + } = res; const jsonObj = { id, name: code_repo_name, @@ -45,6 +80,7 @@ function CodeSelect({ username: git_user_name, password: git_password, ssh_private_key: ssh_key, + is_public, }; const jsonObjStr = JSON.stringify(jsonObj); onChange?.({ diff --git a/react-ui/src/components/CodeSelectorModal/index.less b/react-ui/src/components/CodeSelectorModal/index.less index 82d73ff8..eaff45d7 100644 --- a/react-ui/src/components/CodeSelectorModal/index.less +++ b/react-ui/src/components/CodeSelectorModal/index.less @@ -17,6 +17,7 @@ margin-bottom: 30px; overflow-x: hidden; overflow-y: auto; + padding-bottom: 10px; } &__empty { diff --git a/react-ui/src/components/CodeSelectorModal/index.tsx b/react-ui/src/components/CodeSelectorModal/index.tsx index 430971e6..f6a9d45b 100644 --- a/react-ui/src/components/CodeSelectorModal/index.tsx +++ b/react-ui/src/components/CodeSelectorModal/index.tsx @@ -7,7 +7,8 @@ import KFIcon from '@/components/KFIcon'; import KFModal from '@/components/KFModal'; import { type CodeConfigData } from '@/pages/CodeConfig/List'; -import { getCodeConfigListReq } from '@/services/codeConfig'; +import { getCodeConfigListReq, getCodeConfigPageNumReq } from '@/services/codeConfig'; +import { CustomPartial } from '@/types'; import { to } from '@/utils/promise'; import type { ModalProps, PaginationProps } from 'antd'; import { Empty, Input, Pagination } from 'antd'; @@ -17,24 +18,68 @@ import './index.less'; export { type CodeConfigData }; +export type SelectCodeData = CustomPartial< + CodeConfigData, + | 'id' + | 'code_repo_name' + | 'git_url' + | 'git_branch' + | 'git_user_name' + | 'git_password' + | 'ssh_key' + | 'is_public' +>; + export interface CodeSelectorModalProps extends Omit { - onOk?: (params: CodeConfigData | undefined) => void; + defaultSelected?: SelectCodeData; + onOk?: (params: SelectCodeData | undefined) => void; } /** 选择代码配置的弹窗,推荐使用函数的方式打开 */ -function CodeSelectorModal({ onOk, ...rest }: CodeSelectorModalProps) { +function CodeSelectorModal({ defaultSelected, onOk, ...rest }: CodeSelectorModalProps) { + const defaultPageSize = 10; const [dataList, setDataList] = useState([]); const [total, setTotal] = useState(0); - const [pagination, setPagination] = useState({ - current: 1, - pageSize: 20, - }); const [searchText, setSearchText] = useState(undefined); const [inputText, setInputText] = useState(undefined); + const [selected, setSelected] = useState(defaultSelected); + const [isScrolled, setIsScrolled] = useState(false); + const [pagination, setPagination] = useState({ + current: defaultSelected?.id ? 0 : 1, // 为 0 时,不请求,等待接口返回选中的代码配置在第几页 + pageSize: defaultPageSize, + }); + + useEffect(() => { + const getCodeConfigPageNum = async (id: number, size: number) => { + const [res] = await to( + getCodeConfigPageNumReq(id, { + size, + }), + ); + if (res) { + setPagination({ + current: typeof res.data === 'number' ? Math.max(0, res.data) + 1 : 1, + pageSize: defaultPageSize, + }); + } else { + setPagination({ + current: 1, + pageSize: defaultPageSize, + }); + } + }; + if (defaultSelected?.id) { + getCodeConfigPageNum(defaultSelected?.id, defaultPageSize); + } + }, [defaultSelected?.id]); useEffect(() => { // 获取数据请求 const getDataList = async () => { + // 为 0 时,不请求,等待接口返回选中的代码配置在第几页 + if (pagination.current === 0) { + return; + } const params = { page: pagination.current! - 1, size: pagination.pageSize, @@ -50,6 +95,16 @@ function CodeSelectorModal({ onOk, ...rest }: CodeSelectorModalProps) { getDataList(); }, [pagination, searchText]); + useEffect(() => { + if (dataList.length > 0 && !isScrolled && defaultSelected?.id) { + const selectedItem = document.getElementById(`code-config-item-${defaultSelected?.id}`); + if (selectedItem) { + selectedItem.scrollIntoView(); + } + setIsScrolled(true); + } + }, [isScrolled, dataList, defaultSelected?.id]); + // 搜索 const handleSearch = (value: string) => { setSearchText(value); @@ -59,8 +114,12 @@ function CodeSelectorModal({ onOk, ...rest }: CodeSelectorModalProps) { })); }; - const handleClick = (item: CodeConfigData) => { - onOk?.(item); + const handleChange = (item: CodeConfigData, checked: boolean) => { + if (checked) { + setSelected(item); + } else { + setSelected(undefined); + } }; // 分页切换 @@ -77,7 +136,7 @@ function CodeSelectorModal({ onOk, ...rest }: CodeSelectorModalProps) { title="选择代码配置" image={require('@/assets/img/modal-code-config.png')} width={920} - footer={null} + onOk={() => onOk?.(selected)} destroyOnClose >
@@ -93,19 +152,21 @@ function CodeSelectorModal({ onOk, ...rest }: CodeSelectorModalProps) { prefix={ } - // prefix={ - // - // } /> {dataList?.length !== 0 ? ( <>
{dataList?.map((item) => ( - + ))}
, ) => { + const jsonValue = form.getFieldValue(formItemName)?.value; + const fieldValue = parseJsonText(jsonValue) as ServerCodeData; + const defaultSelected = fieldValue + ? { + id: fieldValue.id, + code_repo_name: fieldValue.name, + git_url: fieldValue.code_path, + git_branch: fieldValue.branch, + git_user_name: fieldValue.username, + git_password: fieldValue.password, + ssh_key: fieldValue.ssh_private_key, + is_public: fieldValue.is_public, + } + : undefined; const { close } = openAntdModal(CodeSelectorModal, { + defaultSelected, onOk: (res) => { if (res) { - const { id, code_repo_name, git_url, git_branch, git_user_name, git_password, ssh_key } = - res; + const { + id, + code_repo_name, + git_url, + git_branch, + git_user_name, + git_password, + ssh_key, + is_public, + } = res; const value = JSON.stringify({ id, name: code_repo_name, @@ -168,6 +193,7 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete username: git_user_name, password: git_password, ssh_private_key: ssh_key, + is_public, }); form.setFieldValue(formItemName, { ...item, diff --git a/react-ui/src/services/codeConfig/index.js b/react-ui/src/services/codeConfig/index.js index 768b2878..4acb51d4 100644 --- a/react-ui/src/services/codeConfig/index.js +++ b/react-ui/src/services/codeConfig/index.js @@ -37,3 +37,12 @@ export function getCodeConfigDetailReq(id) { method: 'GET', }); } + +// 获取代码配置项在第几页 +export function getCodeConfigPageNumReq(id, params) { + return request(`/api/mmp/codeConfig/getPageNum/${id}`, { + method: 'GET', + params + }); +} + diff --git a/react-ui/src/types.ts b/react-ui/src/types.ts index 36bf3a98..52b39517 100644 --- a/react-ui/src/types.ts +++ b/react-ui/src/types.ts @@ -151,3 +151,6 @@ export type UploadFileRes = { fileSize: number; url: string; }; + +// 定义一个类型,取一个类型的有些字段必须的,其它的是可选 +export type CustomPartial = Pick & Partial>;