增加图标展示,区分清楚项目类型

This commit is contained in:
dengqichen 2025-12-04 15:26:56 +08:00
parent 456a4bede2
commit d65e82b0e8
10 changed files with 735 additions and 242 deletions

View File

@ -171,6 +171,37 @@ const SelectItem = React.forwardRef<
)) ))
SelectItem.displayName = SelectPrimitive.Item.displayName SelectItem.displayName = SelectPrimitive.Item.displayName
// 支持副标题的选项组件
interface SelectItemWithDescriptionProps extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item> {
label: string;
description?: string;
}
const SelectItemWithDescription = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
SelectItemWithDescriptionProps
>(({ className, label, description, ...props }, ref) => (
<SelectPrimitive.Item
ref={ref}
className={cn(
"relative flex w-full cursor-default select-none flex-col items-start rounded-sm py-2 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...props}
>
<span className="absolute right-2 top-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Check className="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText className="font-medium">{label}</SelectPrimitive.ItemText>
{description && (
<span className="text-xs text-muted-foreground mt-0.5">{description}</span>
)}
</SelectPrimitive.Item>
))
SelectItemWithDescription.displayName = "SelectItemWithDescription"
const SelectSeparator = React.forwardRef< const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>, React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator> React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
@ -225,6 +256,7 @@ export {
SelectContent, SelectContent,
SelectLabel, SelectLabel,
SelectItem, SelectItem,
SelectItemWithDescription,
SelectSeparator, SelectSeparator,
SelectScrollUpButton, SelectScrollUpButton,
SelectScrollDownButton, SelectScrollDownButton,

View File

@ -0,0 +1,57 @@
import {
CodeOutlined,
JavaOutlined,
NodeIndexOutlined,
PythonOutlined,
} from '@ant-design/icons';
import { DevelopmentLanguageTypeEnum } from '@/pages/Deploy/Application/List/types';
interface LanguageIconConfig {
icon: React.ReactNode;
color: string;
label: string;
}
/**
* /deploy/applications
*/
export const LANGUAGE_ICONS: Record<DevelopmentLanguageTypeEnum, LanguageIconConfig> = {
JAVA: {
icon: <JavaOutlined />,
color: '#E76F00',
label: 'Java'
},
NODE_JS: {
icon: <NodeIndexOutlined />,
color: '#339933',
label: 'NodeJS'
},
PYTHON: {
icon: <PythonOutlined />,
color: '#3776AB',
label: 'Python'
},
GO: {
icon: <CodeOutlined />,
color: '#00ADD8',
label: 'Go'
}
};
/**
*
*/
export const getLanguageIcon = (language?: DevelopmentLanguageTypeEnum): LanguageIconConfig => {
if (!language) {
return {
icon: <CodeOutlined />,
color: '#666666',
label: '未知'
};
}
return LANGUAGE_ICONS[language] || {
icon: <CodeOutlined />,
color: '#666666',
label: language
};
};

View File

@ -0,0 +1,254 @@
import React, { useState } from 'react';
import { Label } from '@/components/ui/label';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { ScrollArea } from '@/components/ui/scroll-area';
import { Search, Check, ChevronDown } from 'lucide-react';
import { cn } from '@/lib/utils';
import type { RepositoryBranchResponse } from '@/pages/Resource/Git/List/types';
interface GitConfigSelectorProps {
label: string; // "源" 或 "目标"
// Git系统
gitSystems: any[];
selectedSystemId: number | null;
onSystemChange: (systemId: number) => void;
// 仓库项目
repoProjects: any[];
loadingRepoProjects: boolean;
selectedProjectId: number | null;
onProjectChange: (projectId: number) => void;
// 分支
branches: RepositoryBranchResponse[];
loadingBranches: boolean;
selectedBranch: string;
onBranchChange: (branch: string) => void;
}
export const GitConfigSelector: React.FC<GitConfigSelectorProps> = ({
label,
gitSystems,
selectedSystemId,
onSystemChange,
repoProjects,
loadingRepoProjects,
selectedProjectId,
onProjectChange,
branches,
loadingBranches,
selectedBranch,
onBranchChange,
}) => {
const [projectSearchValue, setProjectSearchValue] = useState('');
const [projectPopoverOpen, setProjectPopoverOpen] = useState(false);
const [branchSearchValue, setBranchSearchValue] = useState('');
const [branchPopoverOpen, setBranchPopoverOpen] = useState(false);
// 过滤分支
const filteredBranches = branches.filter(branch =>
branch.name.toLowerCase().includes(branchSearchValue.toLowerCase())
);
return (
<div className="space-y-2">
<Label className="text-sm font-semibold">{label}Git配置</Label>
<div className="grid grid-cols-3 gap-4">
{/* 代码系统 */}
<div className="space-y-2">
<Label className="text-xs text-muted-foreground">{label}</Label>
<Select
value={selectedSystemId?.toString() || ''}
onValueChange={(value) => onSystemChange(Number(value))}
>
<SelectTrigger>
<SelectValue placeholder="选择系统" />
</SelectTrigger>
<SelectContent>
{gitSystems.length === 0 ? (
<div className="p-4 text-center text-sm text-muted-foreground">
Git系统
</div>
) : (
gitSystems.map((system) => (
<SelectItem key={system.id} value={system.id.toString()}>
{system.name}
</SelectItem>
))
)}
</SelectContent>
</Select>
</div>
{/* 仓库项目 */}
<div className="space-y-2">
<Label className="text-xs text-muted-foreground">{label}</Label>
{selectedSystemId ? (
<Popover open={projectPopoverOpen} onOpenChange={setProjectPopoverOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
disabled={loadingRepoProjects || repoProjects.length === 0}
className={cn(
'w-full justify-between',
!selectedProjectId && 'text-muted-foreground'
)}
>
{selectedProjectId
? (() => {
const selectedProject = repoProjects.find(
(p) => p.repoProjectId === selectedProjectId
);
return selectedProject
? (selectedProject.repoGroupName
? `${selectedProject.repoGroupName} / ${selectedProject.name}`
: selectedProject.name)
: '选择项目';
})()
: loadingRepoProjects
? '加载中...'
: repoProjects.length === 0
? '暂无项目'
: '选择项目'}
<ChevronDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[var(--radix-popover-trigger-width)] p-0">
<div className="flex items-center border-b px-3">
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
<input
placeholder="搜索项目..."
className="flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground"
value={projectSearchValue}
onChange={(e) => setProjectSearchValue(e.target.value)}
/>
</div>
<ScrollArea className="h-[200px]">
<div className="p-1">
{repoProjects
.filter(
(project) =>
project.name.toLowerCase().includes(projectSearchValue.toLowerCase()) ||
project.repoGroupName?.toLowerCase().includes(projectSearchValue.toLowerCase())
)
.map((project) => (
<div
key={project.repoProjectId}
className={cn(
'relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground',
project.repoProjectId === selectedProjectId && 'bg-accent text-accent-foreground'
)}
onClick={() => {
onProjectChange(project.repoProjectId);
setProjectSearchValue('');
setProjectPopoverOpen(false);
}}
>
<div className="flex-1 truncate">
{project.repoGroupName && (
<span className="text-muted-foreground">{project.repoGroupName} / </span>
)}
{project.name}
</div>
{project.repoProjectId === selectedProjectId && <Check className="ml-2 h-4 w-4" />}
</div>
))}
</div>
</ScrollArea>
</PopoverContent>
</Popover>
) : (
<Input placeholder="请先选择系统" disabled />
)}
</div>
{/* 分支 */}
<div className="space-y-2">
<Label className="text-xs text-muted-foreground">{label}</Label>
{selectedProjectId ? (
<Popover open={branchPopoverOpen} onOpenChange={setBranchPopoverOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
disabled={loadingBranches || branches.length === 0}
className={cn('w-full justify-between', !selectedBranch && 'text-muted-foreground')}
>
{selectedBranch
? (() => {
const selectedBranchObj = branches.find((b) => b.name === selectedBranch);
return (
<span className="flex items-center gap-2 truncate">
{selectedBranchObj?.name}
{selectedBranchObj?.isDefaultBranch && (
<span className="text-xs text-muted-foreground">()</span>
)}
</span>
);
})()
: loadingBranches
? '加载中...'
: branches.length === 0
? '无分支'
: '选择分支'}
<ChevronDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-full p-0">
<div className="flex items-center border-b px-3">
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
<input
placeholder="搜索分支..."
className="flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground"
value={branchSearchValue}
onChange={(e) => setBranchSearchValue(e.target.value)}
/>
</div>
<ScrollArea className="h-[200px]">
<div className="p-1">
{filteredBranches.length === 0 ? (
<div className="p-4 text-center text-sm text-muted-foreground"></div>
) : (
filteredBranches.map((branch) => (
<div
key={branch.id}
className={cn(
'relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent',
branch.name === selectedBranch && 'bg-accent'
)}
onClick={() => {
onBranchChange(branch.name);
setBranchSearchValue('');
setBranchPopoverOpen(false);
}}
>
<span className="flex-1 truncate">
{branch.name}
{branch.isDefaultBranch && (
<span className="ml-2 text-xs text-muted-foreground">()</span>
)}
</span>
{branch.name === selectedBranch && <Check className="ml-2 h-4 w-4" />}
</div>
))
)}
</div>
</ScrollArea>
</PopoverContent>
</Popover>
) : (
<Input placeholder="请先选择项目" disabled />
)}
</div>
</div>
</div>
);
};

View File

@ -32,6 +32,7 @@ import type { RepositoryBranchResponse } from '@/pages/Resource/Git/List/types';
import type { WorkflowDefinition } from '@/pages/Workflow/Definition/List/types'; import type { WorkflowDefinition } from '@/pages/Workflow/Definition/List/types';
import { getExternalSystemList } from '@/pages/Resource/External/List/service'; import { getExternalSystemList } from '@/pages/Resource/External/List/service';
import { getRepositoryProjectsList, getRepositoryBranchesList } from '@/pages/Resource/Git/List/service'; import { getRepositoryProjectsList, getRepositoryBranchesList } from '@/pages/Resource/Git/List/service';
import { GitConfigSelector } from './GitConfigSelector';
interface TeamApplicationDialogProps { interface TeamApplicationDialogProps {
open: boolean; open: boolean;
@ -39,6 +40,7 @@ interface TeamApplicationDialogProps {
teamId: number; teamId: number;
environmentId: number; environmentId: number;
environmentName: string; environmentName: string;
enableGitSyncCheck: boolean; // 🆕 团队是否启用Git同步检测
application?: TeamApplication; // 编辑时传入 application?: TeamApplication; // 编辑时传入
applications: Application[]; // 可选择的应用列表 applications: Application[]; // 可选择的应用列表
jenkinsSystems: any[]; jenkinsSystems: any[];
@ -55,6 +57,9 @@ interface TeamApplicationDialogProps {
workflowDefinitionId: number | null; workflowDefinitionId: number | null;
codeSourceSystemId: number | null; codeSourceSystemId: number | null;
codeSourceProjectId: number | null; codeSourceProjectId: number | null;
targetGitSystemId: number | null; // 🆕 目标Git系统ID
targetGitProjectId: number | null; // 🆕 目标Git项目ID
targetBranch: string; // 🆕 目标分支
}) => Promise<void>; }) => Promise<void>;
onLoadBranches: (appId: number, app: Application) => Promise<RepositoryBranchResponse[]>; onLoadBranches: (appId: number, app: Application) => Promise<RepositoryBranchResponse[]>;
onLoadJenkinsJobs: (systemId: number) => Promise<any[]>; onLoadJenkinsJobs: (systemId: number) => Promise<any[]>;
@ -66,6 +71,7 @@ const TeamApplicationDialog: React.FC<TeamApplicationDialogProps> = ({
teamId, teamId,
environmentId, environmentId,
environmentName, environmentName,
enableGitSyncCheck,
application, application,
applications, applications,
jenkinsSystems, jenkinsSystems,
@ -86,8 +92,11 @@ const TeamApplicationDialog: React.FC<TeamApplicationDialogProps> = ({
deploySystemId: null as number | null, deploySystemId: null as number | null,
deployJob: '', deployJob: '',
workflowDefinitionId: null as number | null, workflowDefinitionId: null as number | null,
codeSourceSystemId: null as number | null, codeSourceSystemId: null as number | null, // 源代码系统ID
codeSourceProjectId: null as number | null, codeSourceProjectId: null as number | null, // 源仓库项目ID
targetGitSystemId: null as number | null, // 🆕 目标Git系统ID
targetGitProjectId: null as number | null, // 🆕 目标Git项目ID
targetBranch: '', // 🆕 目标分支
}); });
// 加载状态 // 加载状态
@ -99,14 +108,15 @@ const TeamApplicationDialog: React.FC<TeamApplicationDialogProps> = ({
const [gitSystems, setGitSystems] = useState<any[]>([]); const [gitSystems, setGitSystems] = useState<any[]>([]);
const [repoProjects, setRepoProjects] = useState<any[]>([]); const [repoProjects, setRepoProjects] = useState<any[]>([]);
const [loadingRepoProjects, setLoadingRepoProjects] = useState(false); const [loadingRepoProjects, setLoadingRepoProjects] = useState(false);
// 🆕 目标Git相关状态
const [targetRepoProjects, setTargetRepoProjects] = useState<any[]>([]);
const [loadingTargetRepoProjects, setLoadingTargetRepoProjects] = useState(false);
const [targetBranches, setTargetBranches] = useState<RepositoryBranchResponse[]>([]);
const [loadingTargetBranches, setLoadingTargetBranches] = useState(false);
// 搜索和弹窗状态 // 搜索和弹窗状态
const [appSearchValue, setAppSearchValue] = useState(''); const [appSearchValue, setAppSearchValue] = useState('');
const [appPopoverOpen, setAppPopoverOpen] = useState(false); const [appPopoverOpen, setAppPopoverOpen] = useState(false);
const [branchSearchValue, setBranchSearchValue] = useState('');
const [branchPopoverOpen, setBranchPopoverOpen] = useState(false);
const [projectSearchValue, setProjectSearchValue] = useState('');
const [projectPopoverOpen, setProjectPopoverOpen] = useState(false);
const [jobSearchValue, setJobSearchValue] = useState(''); const [jobSearchValue, setJobSearchValue] = useState('');
const [jobPopoverOpen, setJobPopoverOpen] = useState(false); const [jobPopoverOpen, setJobPopoverOpen] = useState(false);
@ -124,14 +134,17 @@ const TeamApplicationDialog: React.FC<TeamApplicationDialogProps> = ({
workflowDefinitionId: application.workflowDefinitionId || null, workflowDefinitionId: application.workflowDefinitionId || null,
codeSourceSystemId: application.codeSourceSystemId || null, codeSourceSystemId: application.codeSourceSystemId || null,
codeSourceProjectId: application.codeSourceProjectId || null, codeSourceProjectId: application.codeSourceProjectId || null,
targetGitSystemId: application.targetGitSystemId || null,
targetGitProjectId: application.targetGitProjectId || null,
targetBranch: application.targetBranch || '',
}); });
// 加载仓库项目 // 加载仓库项目
if (application.codeSourceSystemId) { if (application.codeSourceSystemId) {
loadRepoProjects(application.codeSourceSystemId); loadRepoProjects(application.codeSourceSystemId);
} }
// 加载分支(优先使用代码源信息,向后兼容旧数据) // 加载分支(优先使用代码源信息,向后兼容旧数据)
if (application.codeSourceSystemId && application.codeSourceProjectId) { if (application.codeSourceSystemId && application.codeSourceProjectId) {
// 使用代码源信息加载分支 // 使用代码源信息加载分支
loadBranchesFromCodeSource(application.codeSourceSystemId, application.codeSourceProjectId); loadBranchesFromCodeSource(application.codeSourceSystemId, application.codeSourceProjectId);
@ -143,6 +156,16 @@ const TeamApplicationDialog: React.FC<TeamApplicationDialogProps> = ({
} }
} }
// 🆕 加载目标仓库项目(如果有)
if (application.targetGitSystemId) {
loadTargetRepoProjects(application.targetGitSystemId);
}
// 🆕 加载目标分支(如果有)
if (application.targetGitSystemId && application.targetGitProjectId) {
loadTargetBranches(application.targetGitSystemId, application.targetGitProjectId);
}
// 加载Jenkins Jobs // 加载Jenkins Jobs
if (application.deploySystemId) { if (application.deploySystemId) {
loadJenkinsJobs(application.deploySystemId); loadJenkinsJobs(application.deploySystemId);
@ -158,6 +181,9 @@ const TeamApplicationDialog: React.FC<TeamApplicationDialogProps> = ({
workflowDefinitionId: null, workflowDefinitionId: null,
codeSourceSystemId: null, codeSourceSystemId: null,
codeSourceProjectId: null, codeSourceProjectId: null,
targetGitSystemId: null,
targetGitProjectId: null,
targetBranch: '',
}); });
setBranches([]); setBranches([]);
setJenkinsJobs([]); setJenkinsJobs([]);
@ -204,20 +230,34 @@ const TeamApplicationDialog: React.FC<TeamApplicationDialogProps> = ({
} }
}; };
// 加载仓库项目列表 // 加载仓库项目列表
const loadRepoProjects = async (externalSystemId: number) => { const loadRepoProjects = async (externalSystemId: number) => {
setLoadingRepoProjects(true); setLoadingRepoProjects(true);
try { try {
const projects = await getRepositoryProjectsList({ externalSystemId }); const projects = await getRepositoryProjectsList({ externalSystemId });
setRepoProjects(projects || []); setRepoProjects(projects || []);
} catch (error) { } catch (error) {
console.error('加载仓库项目失败:', error); console.error('加载仓库项目失败:', error);
setRepoProjects([]); setRepoProjects([]);
} finally { } finally {
setLoadingRepoProjects(false); setLoadingRepoProjects(false);
} }
}; };
// 🆕 加载目标仓库项目列表
const loadTargetRepoProjects = async (externalSystemId: number) => {
setLoadingTargetRepoProjects(true);
try {
const projects = await getRepositoryProjectsList({ externalSystemId });
setTargetRepoProjects(projects || []);
} catch (error) {
console.error('加载目标仓库项目失败:', error);
setTargetRepoProjects([]);
} finally {
setLoadingTargetRepoProjects(false);
}
};
// 初始化加载Git系统列表 // 初始化加载Git系统列表
useEffect(() => { useEffect(() => {
if (open) { if (open) {
@ -236,6 +276,9 @@ const TeamApplicationDialog: React.FC<TeamApplicationDialogProps> = ({
workflowDefinitionId: null, workflowDefinitionId: null,
codeSourceSystemId: null, codeSourceSystemId: null,
codeSourceProjectId: null, codeSourceProjectId: null,
targetGitSystemId: null,
targetGitProjectId: null,
targetBranch: '',
}); });
// 清空分支列表(分支现在基于代码源,不基于应用) // 清空分支列表(分支现在基于代码源,不基于应用)
setBranches([]); setBranches([]);
@ -263,21 +306,35 @@ const TeamApplicationDialog: React.FC<TeamApplicationDialogProps> = ({
loadJenkinsJobs(systemId); loadJenkinsJobs(systemId);
}; };
// 加载基于代码的分支列表 // 加载基于代码的分支列表
const loadBranchesFromCodeSource = async (externalSystemId: number, repoProjectId: number) => { const loadBranchesFromCodeSource = async (externalSystemId: number, repoProjectId: number) => {
setLoadingBranches(true); setLoadingBranches(true);
try { try {
const branchList = await getRepositoryBranchesList({ externalSystemId, repoProjectId }); const branchList = await getRepositoryBranchesList({ externalSystemId, repoProjectId });
setBranches(branchList || []); setBranches(branchList || []);
} catch (error) { } catch (error) {
console.error('加载分支失败:', error); console.error('加载分支失败:', error);
setBranches([]); setBranches([]);
} finally { } finally {
setLoadingBranches(false); setLoadingBranches(false);
} }
}; };
// 处理代码源系统选择 // 🆕 加载目标分支列表
const loadTargetBranches = async (externalSystemId: number, repoProjectId: number) => {
setLoadingTargetBranches(true);
try {
const branchList = await getRepositoryBranchesList({ externalSystemId, repoProjectId });
setTargetBranches(branchList || []);
} catch (error) {
console.error('加载目标分支失败:', error);
setTargetBranches([]);
} finally {
setLoadingTargetBranches(false);
}
};
// 处理源代码系统选择
const handleCodeSourceSystemChange = (systemId: number) => { const handleCodeSourceSystemChange = (systemId: number) => {
setFormData({ setFormData({
...formData, ...formData,
@ -289,7 +346,7 @@ const TeamApplicationDialog: React.FC<TeamApplicationDialogProps> = ({
loadRepoProjects(systemId); loadRepoProjects(systemId);
}; };
// 处理仓库项目选择 // 处理仓库项目选择
const handleCodeSourceProjectChange = (projectId: number) => { const handleCodeSourceProjectChange = (projectId: number) => {
setFormData({ setFormData({
...formData, ...formData,
@ -302,6 +359,31 @@ const TeamApplicationDialog: React.FC<TeamApplicationDialogProps> = ({
} }
}; };
// 🆕 处理目标Git系统选择
const handleTargetGitSystemChange = (systemId: number) => {
setFormData({
...formData,
targetGitSystemId: systemId,
targetGitProjectId: null,
targetBranch: '', // 清空分支
});
setTargetBranches([]); // 清空分支列表
loadTargetRepoProjects(systemId);
};
// 🆕 处理目标仓库项目选择
const handleTargetGitProjectChange = (projectId: number) => {
setFormData({
...formData,
targetGitProjectId: projectId,
targetBranch: '', // 清空分支
});
// 加载该项目的分支
if (formData.targetGitSystemId) {
loadTargetBranches(formData.targetGitSystemId, projectId);
}
};
// 保存 // 保存
const handleSave = async () => { const handleSave = async () => {
// 表单验证 // 表单验证
@ -325,6 +407,9 @@ const TeamApplicationDialog: React.FC<TeamApplicationDialogProps> = ({
workflowDefinitionId: formData.workflowDefinitionId, workflowDefinitionId: formData.workflowDefinitionId,
codeSourceSystemId: formData.codeSourceSystemId, codeSourceSystemId: formData.codeSourceSystemId,
codeSourceProjectId: formData.codeSourceProjectId, codeSourceProjectId: formData.codeSourceProjectId,
targetGitSystemId: formData.targetGitSystemId,
targetGitProjectId: formData.targetGitProjectId,
targetBranch: formData.targetBranch,
}); });
toast({ toast({
@ -338,11 +423,6 @@ const TeamApplicationDialog: React.FC<TeamApplicationDialogProps> = ({
} }
}; };
// 分支过滤
const filteredBranches = branches.filter(branch =>
branch.name.toLowerCase().includes(branchSearchValue.toLowerCase())
);
// Job 过滤 // Job 过滤
const filteredJobs = jenkinsJobs.filter(job => const filteredJobs = jenkinsJobs.filter(job =>
job.jobName.toLowerCase().includes(jobSearchValue.toLowerCase()) job.jobName.toLowerCase().includes(jobSearchValue.toLowerCase())
@ -599,215 +679,39 @@ const TeamApplicationDialog: React.FC<TeamApplicationDialogProps> = ({
</div> </div>
)} )}
{/* 代码源选择 */} {/* 源Git配置 */}
<div className="space-y-2"> <GitConfigSelector
<Label></Label> label="源"
<Select gitSystems={gitSystems}
value={formData.codeSourceSystemId?.toString() || ''} selectedSystemId={formData.codeSourceSystemId}
onValueChange={(value) => handleCodeSourceSystemChange(Number(value))} onSystemChange={handleCodeSourceSystemChange}
> repoProjects={repoProjects}
<SelectTrigger> loadingRepoProjects={loadingRepoProjects}
<SelectValue placeholder="选择代码源" /> selectedProjectId={formData.codeSourceProjectId}
</SelectTrigger> onProjectChange={handleCodeSourceProjectChange}
<SelectContent> branches={branches}
{gitSystems.length === 0 ? ( loadingBranches={loadingBranches}
<div className="p-4 text-center text-sm text-muted-foreground"> selectedBranch={formData.branch}
Git系统 onBranchChange={(branch) => setFormData({ ...formData, branch })}
</div> />
) : (
gitSystems.map((system) => (
<SelectItem key={system.id} value={system.id.toString()}>
{system.name}
</SelectItem>
))
)}
</SelectContent>
</Select>
</div>
{/* 仓库项目选择 */} {/* 🆕 目标Git配置仅当启用Git同步检测时显示 */}
<div className="space-y-2"> {enableGitSyncCheck && (
<Label></Label> <GitConfigSelector
{formData.codeSourceSystemId ? ( label="目标"
<Popover gitSystems={gitSystems}
open={projectPopoverOpen} selectedSystemId={formData.targetGitSystemId}
onOpenChange={setProjectPopoverOpen} onSystemChange={handleTargetGitSystemChange}
> repoProjects={targetRepoProjects}
<PopoverTrigger asChild> loadingRepoProjects={loadingTargetRepoProjects}
<Button selectedProjectId={formData.targetGitProjectId}
variant="outline" onProjectChange={handleTargetGitProjectChange}
role="combobox" branches={targetBranches}
disabled={loadingRepoProjects || repoProjects.length === 0} loadingBranches={loadingTargetBranches}
className={cn( selectedBranch={formData.targetBranch}
'w-full justify-between', onBranchChange={(branch) => setFormData({ ...formData, targetBranch: branch })}
!formData.codeSourceProjectId && 'text-muted-foreground' />
)} )}
>
{formData.codeSourceProjectId
? (() => {
const selectedProject = repoProjects.find(
(p) => p.repoProjectId === formData.codeSourceProjectId
);
return selectedProject
? (selectedProject.repoGroupName
? `${selectedProject.repoGroupName} / ${selectedProject.name}`
: selectedProject.name)
: '选择仓库项目';
})()
: loadingRepoProjects
? '加载中...'
: repoProjects.length === 0
? '暂无项目'
: '选择仓库项目'}
<ChevronDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[var(--radix-popover-trigger-width)] p-0">
<div className="flex items-center border-b px-3">
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
<input
placeholder="搜索项目..."
className="flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground"
value={projectSearchValue}
onChange={(e) => setProjectSearchValue(e.target.value)}
/>
</div>
<ScrollArea className="h-[200px]">
<div className="p-1">
{repoProjects
.filter((project) =>
project.name.toLowerCase().includes(projectSearchValue.toLowerCase()) ||
(project.repoGroupName?.toLowerCase().includes(projectSearchValue.toLowerCase()))
)
.map((project) => (
<div
key={project.repoProjectId}
className={cn(
'relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground',
project.repoProjectId === formData.codeSourceProjectId &&
'bg-accent text-accent-foreground'
)}
onClick={() => {
handleCodeSourceProjectChange(project.repoProjectId);
setProjectSearchValue('');
setProjectPopoverOpen(false);
}}
>
<div className="flex-1 truncate">
{project.repoGroupName && (
<span className="text-muted-foreground">{project.repoGroupName} / </span>
)}
{project.name}
</div>
{project.repoProjectId === formData.codeSourceProjectId && (
<Check className="ml-2 h-4 w-4" />
)}
</div>
))}
</div>
</ScrollArea>
</PopoverContent>
</Popover>
) : (
<Input placeholder="请先选择代码源" disabled />
)}
</div>
{/* 分支选择 */}
<div className="space-y-2">
<Label></Label>
{formData.codeSourceProjectId ? (
<Popover
open={branchPopoverOpen}
onOpenChange={setBranchPopoverOpen}
>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
disabled={loadingBranches || branches.length === 0}
className={cn(
'w-full justify-between',
!formData.branch && 'text-muted-foreground'
)}
>
{formData.branch
? (() => {
const selectedBranch = branches.find(
(b) => b.name === formData.branch
);
return (
<span className="flex items-center gap-2 truncate">
{selectedBranch?.name}
{selectedBranch?.isDefaultBranch && (
<span className="text-xs text-muted-foreground">
()
</span>
)}
</span>
);
})()
: loadingBranches
? '加载中...'
: branches.length === 0
? '无分支'
: '选择分支'}
<ChevronDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-full p-0">
<div className="flex items-center border-b px-3">
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
<input
placeholder="搜索分支..."
className="flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground"
value={branchSearchValue}
onChange={(e) => setBranchSearchValue(e.target.value)}
/>
</div>
<ScrollArea className="h-[200px]">
<div className="p-1">
{filteredBranches.length === 0 ? (
<div className="p-4 text-center text-sm text-muted-foreground">
</div>
) : (
filteredBranches.map((branch) => (
<div
key={branch.id}
className={cn(
'relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent',
branch.name === formData.branch &&
'bg-accent'
)}
onClick={() => {
setFormData({ ...formData, branch: branch.name });
setBranchSearchValue('');
setBranchPopoverOpen(false);
}}
>
<span className="flex-1 truncate">
{branch.name}
{branch.isDefaultBranch && (
<span className="ml-2 text-xs text-muted-foreground">
()
</span>
)}
</span>
{branch.name === formData.branch && (
<Check className="ml-2 h-4 w-4" />
)}
</div>
))
)}
</div>
</ScrollArea>
</PopoverContent>
</Popover>
) : (
<Input placeholder="请先选择仓库项目" disabled />
)}
</div>
{/* 工作流定义 */} {/* 工作流定义 */}
<div className="space-y-2"> <div className="space-y-2">

View File

@ -10,8 +10,9 @@ import {
import { ConfirmDialog } from '@/components/ui/confirm-dialog'; import { ConfirmDialog } from '@/components/ui/confirm-dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { useToast } from '@/components/ui/use-toast'; import { useToast } from '@/components/ui/use-toast';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { PaginatedTable, type ColumnDef, type PaginatedTableRef } from '@/components/ui/paginated-table'; import { PaginatedTable, type ColumnDef, type PaginatedTableRef } from '@/components/ui/paginated-table';
import { Plus, Edit, Trash2 } from 'lucide-react'; import { Plus, Edit, Trash2, GitBranch } from 'lucide-react';
import type { Environment } from '@/pages/Deploy/Environment/List/types'; import type { Environment } from '@/pages/Deploy/Environment/List/types';
import type { TeamApplication, Application } from '../types'; import type { TeamApplication, Application } from '../types';
import type { WorkflowDefinition } from '@/pages/Workflow/Definition/List/types'; import type { WorkflowDefinition } from '@/pages/Workflow/Definition/List/types';
@ -32,6 +33,7 @@ interface TeamApplicationManageDialogProps {
open: boolean; open: boolean;
onOpenChange: (open: boolean) => void; onOpenChange: (open: boolean) => void;
teamId: number; teamId: number;
enableGitSyncCheck: boolean; // 🆕 团队是否启用Git同步检测
environmentId?: number; // 可选:如果指定,则只管理该环境的应用 environmentId?: number; // 可选:如果指定,则只管理该环境的应用
environments: Environment[]; environments: Environment[];
onSuccess?: () => void; onSuccess?: () => void;
@ -39,7 +41,7 @@ interface TeamApplicationManageDialogProps {
export const TeamApplicationManageDialog: React.FC< export const TeamApplicationManageDialog: React.FC<
TeamApplicationManageDialogProps TeamApplicationManageDialogProps
> = ({ open, onOpenChange, teamId, environmentId, environments, onSuccess }) => { > = ({ open, onOpenChange, teamId, enableGitSyncCheck, environmentId, environments, onSuccess }) => {
const { toast } = useToast(); const { toast } = useToast();
const tableRef = useRef<PaginatedTableRef<TeamApplication>>(null); const tableRef = useRef<PaginatedTableRef<TeamApplication>>(null);
const [teamApplications, setTeamApplications] = useState<TeamApplication[]>([]); const [teamApplications, setTeamApplications] = useState<TeamApplication[]>([]);
@ -127,6 +129,9 @@ export const TeamApplicationManageDialog: React.FC<
workflowDefinitionId: number | null; workflowDefinitionId: number | null;
codeSourceSystemId: number | null; codeSourceSystemId: number | null;
codeSourceProjectId: number | null; codeSourceProjectId: number | null;
targetGitSystemId: number | null; // 🆕 目标Git系统ID
targetGitProjectId: number | null; // 🆕 目标Git项目ID
targetBranch: string; // 🆕 目标分支
}) => { }) => {
if (!editingEnvironment) return; if (!editingEnvironment) return;
@ -142,6 +147,10 @@ export const TeamApplicationManageDialog: React.FC<
workflowDefinitionId: data.workflowDefinitionId || undefined, workflowDefinitionId: data.workflowDefinitionId || undefined,
codeSourceSystemId: data.codeSourceSystemId || undefined, codeSourceSystemId: data.codeSourceSystemId || undefined,
codeSourceProjectId: data.codeSourceProjectId || undefined, codeSourceProjectId: data.codeSourceProjectId || undefined,
// 🆕 目标Git相关字段
targetGitSystemId: data.targetGitSystemId || undefined,
targetGitProjectId: data.targetGitProjectId || undefined,
targetBranch: data.targetBranch || undefined,
}; };
if (appDialogMode === 'edit' && data.id) { if (appDialogMode === 'edit' && data.id) {
@ -207,6 +216,84 @@ export const TeamApplicationManageDialog: React.FC<
width: '100px', width: '100px',
render: (_, app) => getEnvironmentName(app.environmentId), render: (_, app) => getEnvironmentName(app.environmentId),
}, },
{
key: 'gitConfig',
title: 'Git配置',
width: '350px',
render: (_, app) => {
const hasTargetGit = app.targetGitSystemId && app.targetGitProjectId;
if (!hasTargetGit) {
// 未配置目标:单行显示
return (
<div className="flex items-center gap-2 text-sm">
<span className="font-medium truncate">
{app.codeSourceSystemName || '-'} / {app.codeSourceProjectName || '-'}
</span>
{app.branch && (
<span className="text-xs text-muted-foreground">({app.branch})</span>
)}
</div>
);
}
// 配置了目标:对称双行显示
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<div className="space-y-0.5 cursor-help">
{/* 源Git */}
<div className="text-sm">
<span className="text-muted-foreground"></span>
<span className="font-medium">
{app.codeSourceSystemName || '-'} / {app.codeSourceProjectName || '-'}
</span>
{app.branch && (
<span className="text-muted-foreground">({app.branch})</span>
)}
</div>
{/* 同步标识 - 居中 */}
<div className="flex justify-center text-xs text-blue-500">
<span> </span>
</div>
{/* 目标Git */}
<div className="text-sm">
<span className="text-muted-foreground"></span>
<span className="font-medium text-blue-600">
{app.targetGitSystemName || '-'} / {app.targetGitProjectName || '-'}
</span>
{app.targetBranch && (
<span className="text-blue-500">({app.targetBranch})</span>
)}
</div>
</div>
</TooltipTrigger>
<TooltipContent side="top" className="max-w-xs">
<div className="space-y-2 text-xs">
<div>
<div className="font-semibold mb-1">Git</div>
<div className="text-muted-foreground">
<div>: {app.codeSourceSystemName}</div>
<div>: {app.codeSourceProjectName}</div>
<div>: {app.branch || '-'}</div>
</div>
</div>
<div className="border-t pt-2">
<div className="font-semibold mb-1">Git</div>
<div className="text-muted-foreground">
<div>: {app.targetGitSystemName}</div>
<div>: {app.targetGitProjectName}</div>
<div>: {app.targetBranch || '-'}</div>
</div>
</div>
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
},
},
{ {
key: 'buildType', key: 'buildType',
title: '构建类型', title: '构建类型',
@ -214,13 +301,6 @@ export const TeamApplicationManageDialog: React.FC<
render: (_, app) => render: (_, app) =>
app.buildType === 'JENKINS' ? 'Jenkins构建' : app.buildType === 'NATIVE' ? '脚本部署' : '-', app.buildType === 'JENKINS' ? 'Jenkins构建' : app.buildType === 'NATIVE' ? '脚本部署' : '-',
}, },
{
key: 'branch',
title: '分支',
dataIndex: 'branch',
width: '100px',
render: (value) => value || '-',
},
{ {
key: 'deploySystemName', key: 'deploySystemName',
title: 'Jenkins系统', title: 'Jenkins系统',
@ -315,6 +395,7 @@ export const TeamApplicationManageDialog: React.FC<
open={appDialogOpen} open={appDialogOpen}
onOpenChange={setAppDialogOpen} onOpenChange={setAppDialogOpen}
mode={appDialogMode} mode={appDialogMode}
enableGitSyncCheck={enableGitSyncCheck}
teamId={teamId} teamId={teamId}
environmentId={editingEnvironment.id} environmentId={editingEnvironment.id}
environmentName={editingEnvironment.envName} environmentName={editingEnvironment.envName}

View File

@ -44,6 +44,7 @@ interface TeamEnvironmentManageDialogProps {
onOpenChange: (open: boolean) => void; onOpenChange: (open: boolean) => void;
teamId: number; teamId: number;
teamName: string; teamName: string;
enableGitSyncCheck: boolean; // 🆕 团队是否启用Git同步检测
environments: Environment[]; environments: Environment[];
users: User[]; users: User[];
onSuccess?: () => void; onSuccess?: () => void;
@ -56,6 +57,7 @@ export const TeamEnvironmentManageDialog: React.FC<
onOpenChange, onOpenChange,
teamId, teamId,
teamName, teamName,
enableGitSyncCheck,
environments, environments,
users, users,
onSuccess, onSuccess,
@ -301,6 +303,7 @@ export const TeamEnvironmentManageDialog: React.FC<
open={appManageDialogOpen} open={appManageDialogOpen}
onOpenChange={setAppManageDialogOpen} onOpenChange={setAppManageDialogOpen}
teamId={teamId} teamId={teamId}
enableGitSyncCheck={enableGitSyncCheck}
environmentId={selectedEnvironmentId} environmentId={selectedEnvironmentId}
environments={environments} environments={environments}
onSuccess={handleConfigSuccess} onSuccess={handleConfigSuccess}

View File

@ -1,5 +1,6 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import type { TeamResponse } from '../types'; import type { TeamResponse } from '../types';
import { DevelopmentModeEnum, DEVELOPMENT_MODE_OPTIONS } from '../types';
import { createTeam, updateTeam } from '../service'; import { createTeam, updateTeam } from '../service';
import { getUserList } from '@/pages/System/User/List/service'; import { getUserList } from '@/pages/System/User/List/service';
import type { UserResponse } from '@/pages/System/User/List/types'; import type { UserResponse } from '@/pages/System/User/List/types';
@ -25,6 +26,7 @@ import {
Select, Select,
SelectContent, SelectContent,
SelectItem, SelectItem,
SelectItemWithDescription,
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
@ -62,9 +64,21 @@ const TeamModal: React.FC<TeamModalProps> = ({
ownerName: "", ownerName: "",
enabled: true, enabled: true,
sort: 0, sort: 0,
developmentMode: DevelopmentModeEnum.STANDARD,
enableGitSyncCheck: false,
}, },
}); });
// 监听开发模式变化自动调整Git同步检测选项
const developmentMode = form.watch('developmentMode');
useEffect(() => {
const modeOption = DEVELOPMENT_MODE_OPTIONS.find(opt => opt.value === developmentMode);
if (modeOption && !modeOption.enablesGitSyncCheck) {
// 如果当前模式不支持Git同步检测自动禁用
form.setValue('enableGitSyncCheck', false);
}
}, [developmentMode, form]);
// 加载用户列表 // 加载用户列表
const loadUsers = async () => { const loadUsers = async () => {
try { try {
@ -89,6 +103,8 @@ const TeamModal: React.FC<TeamModalProps> = ({
ownerName: initialValues.ownerName || "", ownerName: initialValues.ownerName || "",
enabled: initialValues.enabled, enabled: initialValues.enabled,
sort: initialValues.sort, sort: initialValues.sort,
developmentMode: initialValues.developmentMode || DevelopmentModeEnum.STANDARD,
enableGitSyncCheck: initialValues.enableGitSyncCheck || false,
}); });
} else { } else {
form.reset({ form.reset({
@ -99,6 +115,8 @@ const TeamModal: React.FC<TeamModalProps> = ({
ownerName: "", ownerName: "",
enabled: true, enabled: true,
sort: 0, sort: 0,
developmentMode: DevelopmentModeEnum.STANDARD,
enableGitSyncCheck: false,
}); });
} }
} }
@ -236,6 +254,61 @@ const TeamModal: React.FC<TeamModalProps> = ({
)} )}
/> />
<FormField
control={form.control}
name="developmentMode"
render={({ field }) => (
<FormItem>
<FormLabel></FormLabel>
<Select
onValueChange={field.onChange}
value={field.value}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="请选择开发模式" />
</SelectTrigger>
</FormControl>
<SelectContent>
{DEVELOPMENT_MODE_OPTIONS.map((option) => (
<SelectItemWithDescription
key={option.value}
value={option.value}
label={option.label}
description={option.description}
/>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
{developmentMode === 'SYNC_MODE' && (
<FormField
control={form.control}
name="enableGitSyncCheck"
render={({ field }) => (
<FormItem>
<FormLabel>Git同步检测</FormLabel>
<FormControl>
<div className="flex items-center gap-2 h-10">
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
<span className="text-sm text-muted-foreground">
{field.value ? '启用' : '禁用'}
</span>
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
)}
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
<FormField <FormField
control={form.control} control={form.control}

View File

@ -2,6 +2,7 @@ import React, { useState, useEffect, useMemo, useRef } from 'react';
import { PageContainer } from '@/components/ui/page-container'; import { PageContainer } from '@/components/ui/page-container';
import { getTeams } from './service'; import { getTeams } from './service';
import type { TeamResponse, TeamQuery } from './types'; import type { TeamResponse, TeamQuery } from './types';
import { DEVELOPMENT_MODE_OPTIONS } from './types';
import TeamModal from './components/TeamModal'; import TeamModal from './components/TeamModal';
import DeleteDialog from './components/DeleteDialog'; import DeleteDialog from './components/DeleteDialog';
import MemberManageDialog from './components/MemberManageDialog'; import MemberManageDialog from './components/MemberManageDialog';
@ -149,6 +150,28 @@ const TeamList: React.FC = () => {
width: '140px', width: '140px',
render: (_, record) => record.ownerName || '-', render: (_, record) => record.ownerName || '-',
}, },
{
key: 'developmentMode',
title: '开发模式',
width: '160px',
render: (_, record) => {
const modeOption = DEVELOPMENT_MODE_OPTIONS.find(opt => opt.value === record.developmentMode);
return (
<div className="space-y-1">
<Badge variant="outline" className="inline-flex">
{modeOption?.label || record.developmentMode}
</Badge>
{record.enableGitSyncCheck && (
<div className="text-xs text-muted-foreground">
<Badge variant="secondary" className="text-xs">
Git同步检测
</Badge>
</div>
)}
</div>
);
},
},
{ {
key: 'memberCount', key: 'memberCount',
title: '成员数量', title: '成员数量',
@ -332,6 +355,7 @@ const TeamList: React.FC = () => {
onOpenChange={setEnvManageDialogOpen} onOpenChange={setEnvManageDialogOpen}
teamId={currentTeam.id} teamId={currentTeam.id}
teamName={currentTeam.teamName} teamName={currentTeam.teamName}
enableGitSyncCheck={currentTeam.enableGitSyncCheck}
environments={environments} environments={environments}
users={users} users={users}
onSuccess={handleSuccess} onSuccess={handleSuccess}

View File

@ -1,4 +1,5 @@
import { z } from 'zod'; import { z } from 'zod';
import { DevelopmentModeEnum } from './types';
/** /**
* *
@ -20,6 +21,8 @@ export const teamFormSchema = z.object({
ownerName: z.string().optional(), ownerName: z.string().optional(),
enabled: z.boolean().default(true), enabled: z.boolean().default(true),
sort: z.number().min(0).default(0), sort: z.number().min(0).default(0),
developmentMode: z.nativeEnum(DevelopmentModeEnum).default(DevelopmentModeEnum.STANDARD),
enableGitSyncCheck: z.boolean().default(false),
}); });
export type SearchFormValues = z.infer<typeof searchFormSchema>; export type SearchFormValues = z.infer<typeof searchFormSchema>;

View File

@ -5,6 +5,56 @@ import type { Application } from '@/pages/Deploy/Application/List/types';
// 导出环境和应用类型供使用 // 导出环境和应用类型供使用
export type { Environment, Application }; export type { Environment, Application };
/**
*
*/
export enum DevelopmentModeEnum {
/** 标准模式 - 单仓库直接开发部署 */
STANDARD = 'STANDARD',
/** 同步模式 - 源码内外网同步 */
SYNC_MODE = 'SYNC_MODE',
/** 制品交付模式 - 仅交付编译制品,无源码 */
ARTIFACT_DELIVERY = 'ARTIFACT_DELIVERY'
}
/**
*
*/
export interface DevelopmentModeOption {
value: DevelopmentModeEnum;
label: string;
description: string;
requiresExternalRepo: boolean;
enablesGitSyncCheck: boolean;
}
/**
*
*/
export const DEVELOPMENT_MODE_OPTIONS: DevelopmentModeOption[] = [
{
value: DevelopmentModeEnum.STANDARD,
label: '标准模式',
description: '单仓库直接开发部署',
requiresExternalRepo: false,
enablesGitSyncCheck: false
},
{
value: DevelopmentModeEnum.SYNC_MODE,
label: '同步模式',
description: '源码内外网同步',
requiresExternalRepo: true,
enablesGitSyncCheck: true
},
{
value: DevelopmentModeEnum.ARTIFACT_DELIVERY,
label: '制品交付模式',
description: '仅交付编译制品,无源码',
requiresExternalRepo: true,
enablesGitSyncCheck: false
}
];
/** /**
* *
*/ */
@ -25,6 +75,8 @@ export interface TeamResponse extends BaseResponse {
ownerName?: string; ownerName?: string;
enabled: boolean; enabled: boolean;
sort: number; sort: number;
developmentMode: DevelopmentModeEnum; // 开发模式
enableGitSyncCheck: boolean; // 是否启用Git同步检测
memberCount?: number; memberCount?: number;
environmentCount?: number; environmentCount?: number;
applicationCount?: number; applicationCount?: number;
@ -41,6 +93,8 @@ export interface TeamRequest {
ownerName?: string; ownerName?: string;
enabled?: boolean; enabled?: boolean;
sort?: number; sort?: number;
developmentMode?: DevelopmentModeEnum; // 开发模式
enableGitSyncCheck?: boolean; // 是否启用Git同步检测
} }
// ==================== 团队环境配置相关 ==================== // ==================== 团队环境配置相关 ====================
@ -130,16 +184,21 @@ export interface TeamApplication extends BaseResponse {
deploySystemId?: number; deploySystemId?: number;
deployJob?: string; deployJob?: string;
workflowDefinitionId?: number; workflowDefinitionId?: number;
codeSourceSystemId?: number; // 代码源系统ID codeSourceSystemId?: number; // 源代码系统ID
codeSourceProjectId?: number; // 代码源项目ID codeSourceProjectId?: number; // 源仓库项目ID
targetGitSystemId?: number; // 目标Git系统ID仅SYNC_MODE
targetGitProjectId?: number; // 目标Git项目ID
targetBranch?: string; // 目标分支名称
teamName?: string; teamName?: string;
applicationName?: string; applicationName?: string;
applicationCode?: string; applicationCode?: string;
environmentName?: string; environmentName?: string;
deploySystemName?: string; deploySystemName?: string;
workflowDefinitionName?: string; workflowDefinitionName?: string;
codeSourceSystemName?: string; // 代码源系统名称 codeSourceSystemName?: string; // 源代码系统名称
codeSourceProjectName?: string; // 代码源项目名称 codeSourceProjectName?: string; // 源仓库项目名称
targetGitSystemName?: string; // 目标Git系统名称
targetGitProjectName?: string; // 目标Git项目名称
} }
/** /**
@ -154,7 +213,10 @@ export interface TeamApplicationRequest {
deploySystemId?: number; deploySystemId?: number;
deployJob?: string; deployJob?: string;
workflowDefinitionId?: number; workflowDefinitionId?: number;
codeSourceSystemId?: number; // 代码源系统ID codeSourceSystemId?: number; // 源代码系统ID
codeSourceProjectId?: number; // 代码源项目ID codeSourceProjectId?: number; // 源仓库项目ID
targetGitSystemId?: number; // 目标Git系统ID仅SYNC_MODE
targetGitProjectId?: number; // 目标Git项目ID
targetBranch?: string; // 目标分支名称
} }