增加团队管理页面
This commit is contained in:
parent
e087b6abd8
commit
f60bcf704b
@ -38,7 +38,6 @@ import {
|
|||||||
ChevronDown,
|
ChevronDown,
|
||||||
ExternalLink,
|
ExternalLink,
|
||||||
|
|
||||||
Shield,
|
|
||||||
Code2,
|
Code2,
|
||||||
Calendar,
|
Calendar,
|
||||||
User,
|
User,
|
||||||
@ -379,26 +378,14 @@ const GitManager: React.FC = () => {
|
|||||||
// 选中仓库组(支持反选取消)
|
// 选中仓库组(支持反选取消)
|
||||||
const handleSelectGroup = useCallback((group: RepositoryGroupResponse) => {
|
const handleSelectGroup = useCallback((group: RepositoryGroupResponse) => {
|
||||||
// 如果点击的是已选中的组,则取消选择
|
// 如果点击的是已选中的组,则取消选择
|
||||||
setSelectedGroup((prev) => {
|
setSelectedGroup((prev) => prev?.id === group.id ? undefined : group);
|
||||||
const newGroup = prev?.id === group.id ? undefined : group;
|
}, []);
|
||||||
setSelectedProject(undefined);
|
|
||||||
setBranches([]);
|
|
||||||
// 加载项目列表,如果取消选择则不传 repoGroupId(加载所有项目)
|
|
||||||
loadProjects(newGroup?.repoGroupId || newGroup?.id);
|
|
||||||
return newGroup;
|
|
||||||
});
|
|
||||||
}, [loadProjects]);
|
|
||||||
|
|
||||||
// 选中项目(支持反选取消)
|
// 选中项目(支持反选取消)
|
||||||
const handleSelectProject = useCallback((project: RepositoryProjectResponse) => {
|
const handleSelectProject = useCallback((project: RepositoryProjectResponse) => {
|
||||||
// 如果点击的是已选中的项目,则取消选择
|
// 如果点击的是已选中的项目,则取消选择
|
||||||
setSelectedProject((prev) => {
|
setSelectedProject((prev) => prev?.id === project.id ? undefined : project);
|
||||||
const newProject = prev?.id === project.id ? undefined : project;
|
}, []);
|
||||||
// 加载分支列表,如果取消选择则不传 repoProjectId(加载所有分支)
|
|
||||||
loadBranches(newProject?.repoProjectId || newProject?.id);
|
|
||||||
return newProject;
|
|
||||||
});
|
|
||||||
}, [loadBranches]);
|
|
||||||
|
|
||||||
// 格式化时间
|
// 格式化时间
|
||||||
const formatTime = useCallback((time?: string) => {
|
const formatTime = useCallback((time?: string) => {
|
||||||
@ -571,6 +558,7 @@ const GitManager: React.FC = () => {
|
|||||||
loadInstancesEffect();
|
loadInstancesEffect();
|
||||||
}, [selectedInstanceId, toast]);
|
}, [selectedInstanceId, toast]);
|
||||||
|
|
||||||
|
// 监听实例变化
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedInstanceId) {
|
if (selectedInstanceId) {
|
||||||
loadGroupTree();
|
loadGroupTree();
|
||||||
@ -581,6 +569,26 @@ const GitManager: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}, [selectedInstanceId, loadGroupTree]);
|
}, [selectedInstanceId, loadGroupTree]);
|
||||||
|
|
||||||
|
// 监听仓库组加载完成 或 仓库组选择变化,自动加载项目列表
|
||||||
|
useEffect(() => {
|
||||||
|
// 只有当仓库组不在加载中时才加载项目
|
||||||
|
if (selectedInstanceId && !loading.groups) {
|
||||||
|
setSelectedProject(undefined);
|
||||||
|
setBranches([]);
|
||||||
|
// 如果选择了组,传递repoGroupId;否则不传,加载所有项目
|
||||||
|
loadProjects(selectedGroup?.repoGroupId || selectedGroup?.id);
|
||||||
|
}
|
||||||
|
}, [loading.groups, selectedInstanceId, selectedGroup, loadProjects]);
|
||||||
|
|
||||||
|
// 监听项目加载完成 或 项目选择变化,自动加载分支列表
|
||||||
|
useEffect(() => {
|
||||||
|
// 只有当项目不在加载中时才加载分支
|
||||||
|
if (selectedInstanceId && !loading.projects) {
|
||||||
|
// 如果选择了项目,传递repoProjectId;否则不传,加载所有分支
|
||||||
|
loadBranches(selectedProject?.repoProjectId || selectedProject?.id);
|
||||||
|
}
|
||||||
|
}, [loading.projects, selectedInstanceId, selectedProject, loadBranches]);
|
||||||
|
|
||||||
const filteredGroupTree = useMemo(() => filterGroupTree(groupTree), [groupTree, filterGroupTree]);
|
const filteredGroupTree = useMemo(() => filterGroupTree(groupTree), [groupTree, filterGroupTree]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -910,24 +918,11 @@ const GitManager: React.FC = () => {
|
|||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{branch.isProtected && (
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<Badge variant="secondary" className="text-xs flex items-center gap-1 cursor-help">
|
|
||||||
<Shield className="h-3 w-3" />
|
|
||||||
受保护
|
|
||||||
</Badge>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent>
|
|
||||||
<p>受保护的分支,限制直接推送</p>
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{branch.lastCommitMessage && (
|
{branch.commitMessage && (
|
||||||
<p className="text-xs text-muted-foreground mt-1 line-clamp-2">
|
<p className="text-xs text-muted-foreground mt-1 line-clamp-2">
|
||||||
<GitCommit className="h-3 w-3 inline mr-1" />
|
<GitCommit className="h-3 w-3 inline mr-1" />
|
||||||
{branch.lastCommitMessage}
|
{branch.commitMessage}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{(branch.commitAuthor || branch.commitDate) && (
|
{(branch.commitAuthor || branch.commitDate) && (
|
||||||
|
|||||||
@ -71,17 +71,27 @@ export const syncRepositoryProjects = (externalSystemId: number, repoGroupId?: n
|
|||||||
// ==================== 仓库分支 ====================
|
// ==================== 仓库分支 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取仓库分支列表
|
* 获取仓库分支列表(按最后更新时间倒序排序)
|
||||||
*/
|
*/
|
||||||
export const getRepositoryBranches = (params?: RepositoryBranchQuery) =>
|
export const getRepositoryBranches = (params?: RepositoryBranchQuery) =>
|
||||||
request.get<RepositoryBranchResponse[]>(`${BRANCH_URL}/list`, { params });
|
request.get<RepositoryBranchResponse[]>(`${BRANCH_URL}/list`, {
|
||||||
|
params: {
|
||||||
|
...params,
|
||||||
|
sortField: 'lastUpdateTime',
|
||||||
|
sortOrder: 'desc'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据项目ID获取分支列表
|
* 根据项目ID获取分支列表(按最后更新时间倒序排序)
|
||||||
*/
|
*/
|
||||||
export const getBranchesByProjectId = (repoProjectId: number) =>
|
export const getBranchesByProjectId = (repoProjectId: number) =>
|
||||||
request.get<RepositoryBranchResponse[]>(`${BRANCH_URL}/list`, {
|
request.get<RepositoryBranchResponse[]>(`${BRANCH_URL}/list`, {
|
||||||
params: { repoProjectId },
|
params: {
|
||||||
|
repoProjectId,
|
||||||
|
sortField: 'lastUpdateTime',
|
||||||
|
sortOrder: 'desc'
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -74,8 +74,6 @@ export interface RepositoryBranchResponse extends BaseResponse {
|
|||||||
name: string;
|
name: string;
|
||||||
/** 是否为默认分支 */
|
/** 是否为默认分支 */
|
||||||
isDefaultBranch?: boolean;
|
isDefaultBranch?: boolean;
|
||||||
/** 是否受保护 */
|
|
||||||
isProtected?: boolean;
|
|
||||||
/** 是否可推送 */
|
/** 是否可推送 */
|
||||||
canPush?: boolean;
|
canPush?: boolean;
|
||||||
/** 开发者是否可推送 */
|
/** 开发者是否可推送 */
|
||||||
@ -84,15 +82,19 @@ export interface RepositoryBranchResponse extends BaseResponse {
|
|||||||
developersCanMerge?: boolean;
|
developersCanMerge?: boolean;
|
||||||
/** 最后提交ID */
|
/** 最后提交ID */
|
||||||
lastCommitId?: string;
|
lastCommitId?: string;
|
||||||
/** 最后提交信息 */
|
/** 提交信息 */
|
||||||
lastCommitMessage?: string;
|
commitMessage?: string;
|
||||||
/** 提交作者 */
|
/** 提交作者 */
|
||||||
commitAuthor?: string;
|
commitAuthor?: string;
|
||||||
/** 提交日期 */
|
/** 提交日期 */
|
||||||
commitDate?: string;
|
commitDate?: string;
|
||||||
|
/** 最后更新时间 */
|
||||||
|
lastUpdateTime?: string;
|
||||||
/** 网页URL */
|
/** 网页URL */
|
||||||
webUrl?: string;
|
webUrl?: string;
|
||||||
/** 所属项目ID */
|
/** 项目ID */
|
||||||
|
projectId?: number;
|
||||||
|
/** 所属项目ID(外部系统中的项目ID) */
|
||||||
repoProjectId: number;
|
repoProjectId: number;
|
||||||
/** 外部系统ID */
|
/** 外部系统ID */
|
||||||
externalSystemId: number;
|
externalSystemId: number;
|
||||||
|
|||||||
@ -309,23 +309,25 @@ const JenkinsManager: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}, [selectedInstanceId, loadViews]);
|
}, [selectedInstanceId, loadViews]);
|
||||||
|
|
||||||
// 监听视图选择变化
|
// 监听视图加载完成 或 视图选择变化,自动加载任务列表
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedInstanceId) {
|
// 只有当视图不在加载中时才加载任务
|
||||||
|
if (selectedInstanceId && !loading.views) {
|
||||||
setSelectedJob(undefined);
|
setSelectedJob(undefined);
|
||||||
setBuilds([]);
|
setBuilds([]);
|
||||||
// 如果选择了视图,传递viewId;否则不传,加载所有任务
|
// 如果选择了视图,传递viewId;否则不传,加载所有任务
|
||||||
loadJobs(selectedView?.id);
|
loadJobs(selectedView?.id);
|
||||||
}
|
}
|
||||||
}, [selectedView, selectedInstanceId, loadJobs]);
|
}, [loading.views, selectedInstanceId, selectedView, loadJobs]);
|
||||||
|
|
||||||
// 监听任务选择变化
|
// 监听任务加载完成 或 任务选择变化,自动加载构建列表
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedInstanceId) {
|
// 只有当任务不在加载中时才加载构建
|
||||||
|
if (selectedInstanceId && !loading.jobs) {
|
||||||
// 如果选择了任务,传递jobId;否则不传,加载所有构建
|
// 如果选择了任务,传递jobId;否则不传,加载所有构建
|
||||||
loadBuilds(selectedJob?.id);
|
loadBuilds(selectedJob?.id);
|
||||||
}
|
}
|
||||||
}, [selectedJob, selectedInstanceId, loadBuilds]);
|
}, [loading.jobs, selectedInstanceId, selectedJob, loadBuilds]);
|
||||||
|
|
||||||
// 过滤视图(使用防抖搜索值)
|
// 过滤视图(使用防抖搜索值)
|
||||||
const filteredViews = useMemo(() => {
|
const filteredViews = useMemo(() => {
|
||||||
|
|||||||
@ -36,9 +36,15 @@ export const syncJenkinsJobs = (params: { externalSystemId: number; viewId?: num
|
|||||||
|
|
||||||
// ==================== Jenkins 构建 ====================
|
// ==================== Jenkins 构建 ====================
|
||||||
|
|
||||||
// 获取构建列表
|
// 获取构建列表(按开始时间倒序排序)
|
||||||
export const getJenkinsBuilds = (params: { externalSystemId: number; jobId?: number }) =>
|
export const getJenkinsBuilds = (params: { externalSystemId: number; jobId?: number }) =>
|
||||||
request.get<JenkinsBuildDTO[]>(`/api/v1/jenkins-build/list`, { params });
|
request.get<JenkinsBuildDTO[]>(`/api/v1/jenkins-build/list`, {
|
||||||
|
params: {
|
||||||
|
...params,
|
||||||
|
sortField: 'starttime',
|
||||||
|
sortOrder: 'desc'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 同步构建(根据jobId)
|
// 同步构建(根据jobId)
|
||||||
export const syncJenkinsBuilds = (params: { externalSystemId: number; jobId?: number }) =>
|
export const syncJenkinsBuilds = (params: { externalSystemId: number; jobId?: number }) =>
|
||||||
|
|||||||
@ -282,8 +282,8 @@ const MemberManageDialog: React.FC<MemberManageDialogProps> = ({
|
|||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<div className="flex-1 overflow-hidden flex flex-col px-6 pb-6">
|
<div className="flex-1 overflow-hidden flex flex-col px-6 pb-6">
|
||||||
<div className="space-y-4 flex-1 overflow-y-auto">
|
<div className="space-y-4 flex-1 overflow-y-auto">
|
||||||
{/* 操作栏 */}
|
{/* 操作栏 */}
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="relative flex-1">
|
<div className="relative flex-1">
|
||||||
@ -358,8 +358,8 @@ const MemberManageDialog: React.FC<MemberManageDialogProps> = ({
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Plus className="h-4 w-4 mr-2" />
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
添加成员
|
添加成员
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
@ -451,8 +451,8 @@ const MemberManageDialog: React.FC<MemberManageDialogProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
@ -469,8 +469,8 @@ const MemberManageDialog: React.FC<MemberManageDialogProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium">团队角色</label>
|
<label className="text-sm font-medium">团队角色</label>
|
||||||
<Input
|
<Input
|
||||||
placeholder="请输入团队角色,如:开发、测试、产品经理等"
|
placeholder="请输入团队角色,如:开发、测试、产品经理等"
|
||||||
value={editRole}
|
value={editRole}
|
||||||
onChange={(e) => setEditRole(e.target.value)}
|
onChange={(e) => setEditRole(e.target.value)}
|
||||||
/>
|
/>
|
||||||
@ -478,12 +478,12 @@ const MemberManageDialog: React.FC<MemberManageDialogProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex justify-end gap-2">
|
<div className="flex justify-end gap-2">
|
||||||
<Button variant="outline" onClick={() => setEditDialogOpen(false)}>
|
<Button variant="outline" onClick={() => setEditDialogOpen(false)}>
|
||||||
取消
|
取消
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleEditSave}>
|
<Button onClick={handleEditSave}>
|
||||||
保存
|
保存
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user