1
This commit is contained in:
parent
8a15130a31
commit
85d7e573ad
@ -1,7 +1,7 @@
|
|||||||
import React, {useEffect, useState} from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import type {Application, RepositoryGroup} from '../types';
|
import type {Application, RepositoryGroup, RepositoryProject} from '../types';
|
||||||
import {DevelopmentLanguageTypeEnum} 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 type {ExternalSystemResponse} from '@/pages/Deploy/External/types';
|
||||||
import {SystemType} from '@/pages/Deploy/External/types';
|
import {SystemType} from '@/pages/Deploy/External/types';
|
||||||
import {getExternalSystems} from '@/pages/Deploy/External/service';
|
import {getExternalSystems} from '@/pages/Deploy/External/service';
|
||||||
@ -58,6 +58,7 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const [gitInstances, setGitInstances] = useState<ExternalSystemResponse[]>([]);
|
const [gitInstances, setGitInstances] = useState<ExternalSystemResponse[]>([]);
|
||||||
const [repositoryGroups, setRepositoryGroups] = useState<RepositoryGroup[]>([]);
|
const [repositoryGroups, setRepositoryGroups] = useState<RepositoryGroup[]>([]);
|
||||||
|
const [repositoryProjects, setRepositoryProjects] = useState<RepositoryProject[]>([]);
|
||||||
const {toast} = useToast();
|
const {toast} = useToast();
|
||||||
const isEdit = !!initialValues?.id;
|
const isEdit = !!initialValues?.id;
|
||||||
const [selectedGitInstance, setSelectedGitInstance] = useState<ExternalSystemResponse>();
|
const [selectedGitInstance, setSelectedGitInstance] = useState<ExternalSystemResponse>();
|
||||||
@ -74,6 +75,7 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
|||||||
sort: 0,
|
sort: 0,
|
||||||
gitInstanceId: undefined,
|
gitInstanceId: undefined,
|
||||||
repositoryGroupId: undefined,
|
repositoryGroupId: undefined,
|
||||||
|
repositoryProjectId: undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -113,6 +115,7 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
|||||||
sort: initialValues.sort,
|
sort: initialValues.sort,
|
||||||
gitInstanceId: initialValues.gitInstanceId,
|
gitInstanceId: initialValues.gitInstanceId,
|
||||||
repositoryGroupId: initialValues.repositoryGroupId,
|
repositoryGroupId: initialValues.repositoryGroupId,
|
||||||
|
repositoryProjectId: initialValues.repositoryProjectId,
|
||||||
});
|
});
|
||||||
const gitInstance = gitInstances.find(instance => instance.id === initialValues.gitInstanceId);
|
const gitInstance = gitInstances.find(instance => instance.id === initialValues.gitInstanceId);
|
||||||
if (gitInstance) {
|
if (gitInstance) {
|
||||||
@ -122,20 +125,21 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
|||||||
}, [initialValues, form, gitInstances]);
|
}, [initialValues, form, gitInstances]);
|
||||||
|
|
||||||
// 当选择Git实例时,获取对应的仓库组列表
|
// 当选择Git实例时,获取对应的仓库组列表
|
||||||
const handleGitInstanceChange = async (gitInstanceId: number) => {
|
const handleGitInstanceChange = (gitInstanceId: number) => {
|
||||||
try {
|
|
||||||
const data = await getRepositoryGroupList(gitInstanceId);
|
|
||||||
setRepositoryGroups(data);
|
|
||||||
// 清空已选择的仓库组
|
|
||||||
form.setValue('repositoryGroupId', undefined);
|
form.setValue('repositoryGroupId', undefined);
|
||||||
} catch (error) {
|
form.setValue('repositoryProjectId', undefined);
|
||||||
console.error('Failed to fetch repository groups:', error);
|
setRepositoryProjects([]);
|
||||||
toast({
|
fetchRepositoryGroups(gitInstanceId);
|
||||||
title: "错误",
|
};
|
||||||
description: "获取仓库组列表失败",
|
|
||||||
variant: "destructive",
|
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) => {
|
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
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="gitInstanceId"
|
name="gitInstanceId"
|
||||||
@ -251,7 +255,6 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
|||||||
<Select
|
<Select
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
field.onChange(Number(value));
|
field.onChange(Number(value));
|
||||||
form.setValue('repositoryGroupId', undefined);
|
|
||||||
handleGitInstanceChange(Number(value));
|
handleGitInstanceChange(Number(value));
|
||||||
}}
|
}}
|
||||||
value={field.value?.toString()}
|
value={field.value?.toString()}
|
||||||
@ -282,6 +285,7 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
|||||||
name="repositoryGroupId"
|
name="repositoryGroupId"
|
||||||
render={({field}) => {
|
render={({field}) => {
|
||||||
const [searchValue, setSearchValue] = React.useState("");
|
const [searchValue, setSearchValue] = React.useState("");
|
||||||
|
const [open, setOpen] = React.useState(false);
|
||||||
const filteredGroups = repositoryGroups.filter(group =>
|
const filteredGroups = repositoryGroups.filter(group =>
|
||||||
group.name.toLowerCase().includes(searchValue.toLowerCase())
|
group.name.toLowerCase().includes(searchValue.toLowerCase())
|
||||||
);
|
);
|
||||||
@ -289,7 +293,7 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
|||||||
return (
|
return (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>代码仓库组</FormLabel>
|
<FormLabel>代码仓库组</FormLabel>
|
||||||
<Popover>
|
<Popover open={open} onOpenChange={setOpen}>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Button
|
<Button
|
||||||
@ -337,12 +341,11 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
|||||||
)}
|
)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
form.setValue("repositoryGroupId", group.id);
|
form.setValue("repositoryGroupId", group.id);
|
||||||
|
form.setValue("repositoryProjectId", undefined);
|
||||||
|
setRepositoryProjects([]);
|
||||||
|
fetchRepositoryProjects(group.id);
|
||||||
setSearchValue("");
|
setSearchValue("");
|
||||||
// 关闭 Popover
|
setOpen(false);
|
||||||
const popoverTrigger = document.querySelector('[role="combobox"]');
|
|
||||||
if (popoverTrigger) {
|
|
||||||
(popoverTrigger as HTMLElement).click();
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{group.name}
|
{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>
|
</div>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import request from '@/utils/request';
|
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 type { Page } from '@/types/base';
|
||||||
import {DevelopmentLanguageType} from "./types";
|
import {DevelopmentLanguageType} from "./types";
|
||||||
|
|
||||||
const BASE_URL = '/api/v1/applications';
|
const BASE_URL = '/api/v1/applications';
|
||||||
const REPOSITORY_GROUP_URL = '/api/v1/repository-group';
|
const REPOSITORY_GROUP_URL = '/api/v1/repository-group';
|
||||||
|
const REPOSITORY_PROJECT_URL = '/api/v1/repository-project';
|
||||||
|
|
||||||
// 创建应用
|
// 创建应用
|
||||||
export const createApplication = (data: CreateApplicationRequest) =>
|
export const createApplication = (data: CreateApplicationRequest) =>
|
||||||
@ -43,3 +44,9 @@ export const getRepositoryGroupList = (externalSystemId: number) =>
|
|||||||
request.get<RepositoryGroup[]>(`${REPOSITORY_GROUP_URL}/list`, {
|
request.get<RepositoryGroup[]>(`${REPOSITORY_GROUP_URL}/list`, {
|
||||||
params: { externalSystemId },
|
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;
|
sort?: number;
|
||||||
enabled?: boolean;
|
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