diff --git a/frontend/src/components/ui/select.tsx b/frontend/src/components/ui/select.tsx index bcdcff0e..b830cd52 100644 --- a/frontend/src/components/ui/select.tsx +++ b/frontend/src/components/ui/select.tsx @@ -1,6 +1,6 @@ import * as React from "react" import * as SelectPrimitive from "@radix-ui/react-select" -import { Check, ChevronDown, ChevronUp } from "lucide-react" +import { Check, ChevronDown, ChevronUp, X } from "lucide-react" import { cn } from "@/lib/utils" @@ -10,24 +10,64 @@ const SelectGroup = SelectPrimitive.Group const SelectValue = SelectPrimitive.Value +interface SelectTriggerProps extends React.ComponentPropsWithoutRef { + clearable?: boolean; + onClear?: () => void; + hasValue?: boolean; +} + const SelectTrigger = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - span]:line-clamp-1", - className - )} - {...props} - > - {children} - - - - -)) + SelectTriggerProps +>(({ className, children, clearable, onClear, hasValue, ...props }, ref) => { + const clearButtonRef = React.useRef(null); + + const handleClear = (e: React.MouseEvent | React.PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + onClear?.(); + }; + + const handleTriggerPointerDown = (e: React.PointerEvent) => { + // 如果点击的是清空按钮或其子元素,阻止触发器的默认行为 + if (clearButtonRef.current && (e.target === clearButtonRef.current || clearButtonRef.current.contains(e.target as Node))) { + e.preventDefault(); + e.stopPropagation(); + return; + } + props.onPointerDown?.(e); + }; + + return ( + span]:line-clamp-1", + className + )} + {...props} + onPointerDown={handleTriggerPointerDown} + > + {children} +
+ {clearable && hasValue && ( + + + + )} + + + +
+
+ ); +}) SelectTrigger.displayName = SelectPrimitive.Trigger.displayName const SelectScrollUpButton = React.forwardRef< diff --git a/frontend/src/pages/Dashboard/components/ApplicationCard.tsx b/frontend/src/pages/Dashboard/components/ApplicationCard.tsx index b5bf3597..72308358 100644 --- a/frontend/src/pages/Dashboard/components/ApplicationCard.tsx +++ b/frontend/src/pages/Dashboard/components/ApplicationCard.tsx @@ -7,7 +7,6 @@ import { Package, GitBranch, Rocket, - Server, CheckCircle2, XCircle, TrendingUp, @@ -85,39 +84,6 @@ export const ApplicationCard: React.FC = ({ )} - {/* 工作流 */} -
- - {app.workflowDefinitionName ? ( - {app.workflowDefinitionName} - ) : ( - - )} -
- - {/* Jenkins */} - {app.deploySystemName ? ( - - - -
- - {app.deploySystemName} -
-
- {app.deployJob && ( - -

{app.deploySystemName} ({app.deployJob})

-
- )} -
-
- ) : ( -
- - -
- )} {/* 部署统计信息 */} diff --git a/frontend/src/pages/Deploy/Team/List/components/TeamEnvironmentConfigDialog.tsx b/frontend/src/pages/Deploy/Team/List/components/TeamEnvironmentConfigDialog.tsx index e56a8478..882dff96 100644 --- a/frontend/src/pages/Deploy/Team/List/components/TeamEnvironmentConfigDialog.tsx +++ b/frontend/src/pages/Deploy/Team/List/components/TeamEnvironmentConfigDialog.tsx @@ -50,7 +50,6 @@ import { getTeamEnvironmentConfig, createTeamEnvironmentConfig, updateTeamEnvironmentConfig, - getNotificationChannels, } from '../service'; interface User { @@ -64,23 +63,9 @@ const formSchema = z.object({ environmentId: z.number().min(1, '请选择环境'), approvalRequired: z.boolean().default(false), approverUserIds: z.array(z.number()).default([]), - notificationChannelId: z.number().nullish(), - notificationEnabled: z.boolean().default(false), requireCodeReview: z.boolean().default(false), remark: z.string().max(100, '备注最多100个字符').optional(), }).refine( - (data) => { - // 如果启用了通知,则通知渠道必填 - if (data.notificationEnabled && !data.notificationChannelId) { - return false; - } - return true; - }, - { - message: '启用通知时必须选择通知渠道', - path: ['notificationChannelId'], - } -).refine( (data) => { // 如果需要审批,则审批人必填 if (data.approvalRequired && (!data.approverUserIds || data.approverUserIds.length === 0)) { @@ -96,13 +81,7 @@ const formSchema = z.object({ type FormData = z.infer; -interface NotificationChannel { - id: number; - name: string; - type: string; -} - -interface TeamEnvironmentConfigDialogProps { +interface TeamEnvironmentConfigDialogProps{ open: boolean; onOpenChange: (open: boolean) => void; teamId: number; @@ -115,8 +94,6 @@ interface TeamEnvironmentConfigDialogProps { initialData?: { environmentId: number; workflowDefinitionId?: number; - notificationChannelId?: number; - notificationEnabled?: boolean; requireCodeReview?: boolean; remark?: string; }; @@ -138,10 +115,6 @@ export const TeamEnvironmentConfigDialog: React.FC< const [submitting, setSubmitting] = useState(false); const [loading, setLoading] = useState(false); const [configId, setConfigId] = useState(null); - const [notificationChannels, setNotificationChannels] = useState< - NotificationChannel[] - >([]); - const [loadingChannels, setLoadingChannels] = useState(false); const form = useForm({ resolver: zodResolver(formSchema), @@ -149,8 +122,6 @@ export const TeamEnvironmentConfigDialog: React.FC< environmentId: initialData?.environmentId || editEnvironmentId || 0, approvalRequired: false, approverUserIds: [], - notificationChannelId: initialData?.notificationChannelId, - notificationEnabled: initialData?.notificationEnabled || false, requireCodeReview: initialData?.requireCodeReview || false, remark: initialData?.remark || '', }, @@ -159,7 +130,6 @@ export const TeamEnvironmentConfigDialog: React.FC< // 对话框打开时初始化 useEffect(() => { if (open) { - loadNotificationChannels(); if (editEnvironmentId) { // 编辑模式或绑定新环境:设置环境ID并加载配置 @@ -172,8 +142,6 @@ export const TeamEnvironmentConfigDialog: React.FC< environmentId: initialData.environmentId, approvalRequired: false, approverUserIds: [], - notificationChannelId: initialData.notificationChannelId, - notificationEnabled: initialData.notificationEnabled || false, requireCodeReview: initialData.requireCodeReview || false, remark: initialData.remark || '', }); @@ -184,8 +152,6 @@ export const TeamEnvironmentConfigDialog: React.FC< environmentId: 0, approvalRequired: false, approverUserIds: [], - notificationChannelId: undefined, - notificationEnabled: false, requireCodeReview: false, remark: '', }); @@ -206,8 +172,6 @@ export const TeamEnvironmentConfigDialog: React.FC< environmentId: config.environmentId, approvalRequired: config.approvalRequired || false, approverUserIds: config.approverUserIds || [], - notificationChannelId: config.notificationChannelId, - notificationEnabled: config.notificationEnabled || false, requireCodeReview: config.requireCodeReview || false, remark: config.remark || '', }); @@ -220,8 +184,6 @@ export const TeamEnvironmentConfigDialog: React.FC< environmentId: editEnvironmentId, approvalRequired: false, approverUserIds: [], - notificationChannelId: undefined, - notificationEnabled: false, requireCodeReview: false, remark: '', }); @@ -237,22 +199,6 @@ export const TeamEnvironmentConfigDialog: React.FC< } }; - const loadNotificationChannels = async () => { - setLoadingChannels(true); - try { - const channels = await getNotificationChannels(); - setNotificationChannels(channels); - } catch (error) { - toast({ - title: '加载失败', - description: '无法加载通知渠道列表', - variant: 'destructive', - }); - } finally { - setLoadingChannels(false); - } - }; - const handleSubmit = async (data: FormData) => { console.log('表单提交开始', data); setSubmitting(true); @@ -263,9 +209,6 @@ export const TeamEnvironmentConfigDialog: React.FC< approvalRequired: data.approvalRequired, // 如果不需要审批,清空审批人列表 approverUserIds: data.approvalRequired ? data.approverUserIds : [], - // 如果未启用通知,清空通知渠道 - notificationChannelId: data.notificationEnabled ? data.notificationChannelId : undefined, - notificationEnabled: data.notificationEnabled, requireCodeReview: data.requireCodeReview, remark: data.remark, }; @@ -493,77 +436,6 @@ export const TeamEnvironmentConfigDialog: React.FC< /> )} - {/* 启用通知 */} - ( - -
- 启用通知 -
- 部署状态变更时发送通知 -
-
- - { - field.onChange(checked); - // 取消通知时自动清空通知渠道 - if (!checked) { - form.setValue('notificationChannelId', undefined); - } - }} - /> - -
- )} - /> - - {/* 通知渠道选择 - 仅在启用通知时显示 */} - {form.watch('notificationEnabled') && ( - ( - - 通知渠道 * - - - - )} - /> - )} - {/* 需要代码审查 */} (); + number | null + >(null); + + // 通知配置对话框状态 + const [notificationDialogOpen, setNotificationDialogOpen] = useState(false); + const [notificationEnvironmentId, setNotificationEnvironmentId] = useState(null); + const [notificationEnvironmentName, setNotificationEnvironmentName] = useState(''); // 删除确认对话框状态 const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); @@ -123,6 +129,12 @@ export const TeamEnvironmentManageDialog: React.FC< setAppManageDialogOpen(true); }; + const handleOpenNotificationDialog = (config: TeamEnvironmentConfig) => { + setNotificationEnvironmentId(config.environmentId); + setNotificationEnvironmentName(config.environmentName || ''); + setNotificationDialogOpen(true); + }; + const handleOpenDeleteDialog = (config: TeamEnvironmentConfig) => { setDeletingConfig(config); setDeleteDialogOpen(true); @@ -202,13 +214,28 @@ export const TeamEnvironmentManageDialog: React.FC< )} - {config.notificationEnabled ? ( - - {config.notificationChannelName || '已启用'} - + {config.notificationConfig ? ( +
+ {config.notificationConfig.deployNotificationEnabled && ( + + 部署通知 + + )} + {config.notificationConfig.buildNotificationEnabled && ( + + 构建通知 + + )} + {!config.notificationConfig.deployNotificationEnabled && + !config.notificationConfig.buildNotificationEnabled && ( + + 未启用 + + )} +
) : ( - 未启用 + 未配置 )}
@@ -247,6 +274,14 @@ export const TeamEnvironmentManageDialog: React.FC< 配置 +