1
This commit is contained in:
parent
8a15130a31
commit
85d7e573ad
@ -1,7 +1,7 @@
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import type {Application, RepositoryGroup} from '../types';
|
||||
import type {Application, RepositoryGroup, RepositoryProject} from '../types';
|
||||
import {DevelopmentLanguageTypeEnum} from '../types';
|
||||
import {createApplication, updateApplication, getRepositoryGroupList} from '../service';
|
||||
import {createApplication, updateApplication, getRepositoryGroupList, getRepositoryProjects} from '../service';
|
||||
import type {ExternalSystemResponse} from '@/pages/Deploy/External/types';
|
||||
import {SystemType} from '@/pages/Deploy/External/types';
|
||||
import {getExternalSystems} from '@/pages/Deploy/External/service';
|
||||
@ -58,6 +58,7 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
||||
}) => {
|
||||
const [gitInstances, setGitInstances] = useState<ExternalSystemResponse[]>([]);
|
||||
const [repositoryGroups, setRepositoryGroups] = useState<RepositoryGroup[]>([]);
|
||||
const [repositoryProjects, setRepositoryProjects] = useState<RepositoryProject[]>([]);
|
||||
const {toast} = useToast();
|
||||
const isEdit = !!initialValues?.id;
|
||||
const [selectedGitInstance, setSelectedGitInstance] = useState<ExternalSystemResponse>();
|
||||
@ -74,6 +75,7 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
||||
sort: 0,
|
||||
gitInstanceId: undefined,
|
||||
repositoryGroupId: undefined,
|
||||
repositoryProjectId: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
@ -113,6 +115,7 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
||||
sort: initialValues.sort,
|
||||
gitInstanceId: initialValues.gitInstanceId,
|
||||
repositoryGroupId: initialValues.repositoryGroupId,
|
||||
repositoryProjectId: initialValues.repositoryProjectId,
|
||||
});
|
||||
const gitInstance = gitInstances.find(instance => instance.id === initialValues.gitInstanceId);
|
||||
if (gitInstance) {
|
||||
@ -122,20 +125,21 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
||||
}, [initialValues, form, gitInstances]);
|
||||
|
||||
// 当选择Git实例时,获取对应的仓库组列表
|
||||
const handleGitInstanceChange = async (gitInstanceId: number) => {
|
||||
try {
|
||||
const data = await getRepositoryGroupList(gitInstanceId);
|
||||
setRepositoryGroups(data);
|
||||
// 清空已选择的仓库组
|
||||
const handleGitInstanceChange = (gitInstanceId: number) => {
|
||||
form.setValue('repositoryGroupId', undefined);
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch repository groups:', error);
|
||||
toast({
|
||||
title: "错误",
|
||||
description: "获取仓库组列表失败",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
form.setValue('repositoryProjectId', undefined);
|
||||
setRepositoryProjects([]);
|
||||
fetchRepositoryGroups(gitInstanceId);
|
||||
};
|
||||
|
||||
const fetchRepositoryGroups = async (externalSystemId: number) => {
|
||||
const response = await getRepositoryGroupList(externalSystemId);
|
||||
setRepositoryGroups(response || []);
|
||||
};
|
||||
|
||||
const fetchRepositoryProjects = async (groupId: number) => {
|
||||
const response = await getRepositoryProjects(groupId);
|
||||
setRepositoryProjects(response || []);
|
||||
};
|
||||
|
||||
const handleSubmit = async (values: ApplicationFormValues) => {
|
||||
@ -241,7 +245,7 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="gitInstanceId"
|
||||
@ -251,7 +255,6 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
||||
<Select
|
||||
onValueChange={(value) => {
|
||||
field.onChange(Number(value));
|
||||
form.setValue('repositoryGroupId', undefined);
|
||||
handleGitInstanceChange(Number(value));
|
||||
}}
|
||||
value={field.value?.toString()}
|
||||
@ -282,6 +285,7 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
||||
name="repositoryGroupId"
|
||||
render={({field}) => {
|
||||
const [searchValue, setSearchValue] = React.useState("");
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const filteredGroups = repositoryGroups.filter(group =>
|
||||
group.name.toLowerCase().includes(searchValue.toLowerCase())
|
||||
);
|
||||
@ -289,7 +293,7 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
||||
return (
|
||||
<FormItem>
|
||||
<FormLabel>代码仓库组</FormLabel>
|
||||
<Popover>
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
@ -337,12 +341,11 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
||||
)}
|
||||
onClick={() => {
|
||||
form.setValue("repositoryGroupId", group.id);
|
||||
form.setValue("repositoryProjectId", undefined);
|
||||
setRepositoryProjects([]);
|
||||
fetchRepositoryProjects(group.id);
|
||||
setSearchValue("");
|
||||
// 关闭 Popover
|
||||
const popoverTrigger = document.querySelector('[role="combobox"]');
|
||||
if (popoverTrigger) {
|
||||
(popoverTrigger as HTMLElement).click();
|
||||
}
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
{group.name}
|
||||
@ -360,6 +363,87 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="repositoryProjectId"
|
||||
render={({field}) => {
|
||||
const [searchValue, setSearchValue] = React.useState("");
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const filteredProjects = repositoryProjects.filter(project =>
|
||||
project.name.toLowerCase().includes(searchValue.toLowerCase())
|
||||
);
|
||||
|
||||
return (
|
||||
<FormItem>
|
||||
<FormLabel>项目</FormLabel>
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
disabled={!form.watch('repositoryGroupId')}
|
||||
className={cn(
|
||||
"w-full justify-between",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
{field.value
|
||||
? repositoryProjects.find(
|
||||
(project) => project.projectId === field.value
|
||||
)?.name
|
||||
: !form.watch('repositoryGroupId')
|
||||
? "请先选择代码仓库组"
|
||||
: "请选择项目"}
|
||||
<ChevronDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[--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 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
value={searchValue}
|
||||
onChange={(e) => setSearchValue(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<ScrollArea className="h-[200px]">
|
||||
{filteredProjects.length === 0 ? (
|
||||
<div className="p-4 text-center text-sm text-muted-foreground">
|
||||
未找到项目
|
||||
</div>
|
||||
) : (
|
||||
filteredProjects.map((project) => (
|
||||
<div
|
||||
key={project.projectId}
|
||||
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.projectId === field.value && "bg-accent text-accent-foreground"
|
||||
)}
|
||||
onClick={() => {
|
||||
form.setValue("repositoryProjectId", project.projectId);
|
||||
setSearchValue("");
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
{project.name}
|
||||
{project.projectId === field.value && (
|
||||
<Check className="ml-auto h-4 w-4" />
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</ScrollArea>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<FormField
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import request from '@/utils/request';
|
||||
import type { CreateApplicationRequest, UpdateApplicationRequest, Application, ApplicationQuery, RepositoryGroup } from './types';
|
||||
import type { CreateApplicationRequest, UpdateApplicationRequest, Application, ApplicationQuery, RepositoryGroup, RepositoryProject } from './types';
|
||||
import type { Page } from '@/types/base';
|
||||
import {DevelopmentLanguageType} from "./types";
|
||||
|
||||
const BASE_URL = '/api/v1/applications';
|
||||
const REPOSITORY_GROUP_URL = '/api/v1/repository-group';
|
||||
const REPOSITORY_PROJECT_URL = '/api/v1/repository-project';
|
||||
|
||||
// 创建应用
|
||||
export const createApplication = (data: CreateApplicationRequest) =>
|
||||
@ -43,3 +44,9 @@ export const getRepositoryGroupList = (externalSystemId: number) =>
|
||||
request.get<RepositoryGroup[]>(`${REPOSITORY_GROUP_URL}/list`, {
|
||||
params: { externalSystemId },
|
||||
});
|
||||
|
||||
// 获取项目列表
|
||||
export const getRepositoryProjects = (groupId: number) =>
|
||||
request.get<RepositoryProject[]>(`${REPOSITORY_PROJECT_URL}/list`, {
|
||||
params: { groupId },
|
||||
});
|
||||
|
||||
@ -64,3 +64,18 @@ export interface RepositoryGroup {
|
||||
sort?: number;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export interface RepositoryProject {
|
||||
name: string;
|
||||
path: string;
|
||||
description: string;
|
||||
visibility: string;
|
||||
groupId: number;
|
||||
isDefaultBranch: string;
|
||||
webUrl: string;
|
||||
sshUrl: string;
|
||||
httpUrl: string;
|
||||
lastActivityAt: string;
|
||||
externalSystemId: number;
|
||||
projectId: number;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user