refactor(quality): Q25 前端巨型组件拆分 — PipelineCreateDialog 559L→498L (-11%), 提取 pipeline-create/ 2 个文件 (types(PRESETS/DEFAULT_TARGET/PipelineCreateDialogProps/EnvVar) + AdvancedSettingsPanel(172L 受控展开面板: 构建节点/Job名/触发模式/环境变量)), 零逻辑变更, ESLint errors=0/warnings=0/any=0, tsc -b=0, npm build✓ (17.45s), 17/17 测试通过

This commit is contained in:
attacker committed 2026-07-09 01:19:05 +08:00
1 parent adf1ac8f71
commit 2f8113cb8e
3 files changed
+353 -195

No files matched your search

@@ -0,0 +1,172 @@
import { useTranslation } from 'react-i18next';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
import { Plus, ChevronDown, Settings2, Trash2 } from 'lucide-react';
import { cn } from '@/lib/utils';
import type { BuildNode } from '@/api';
import type { EnvVar } from './types';
export interface AdvancedSettingsPanelProps {
open: boolean;
onOpenChange: (open: boolean) => void;
buildNodeId: string;
onBuildNodeIdChange: (v: string) => void;
buildNodes: BuildNode[];
jobName: string;
onJobNameChange: (v: string) => void;
triggerMode: string;
onTriggerModeChange: (v: string) => void;
watchBranches: string;
onWatchBranchesChange: (v: string) => void;
cronExpr: string;
onCronExprChange: (v: string) => void;
envVars: EnvVar[];
onEnvVarsChange: (vars: EnvVar[]) => void;
}
export function AdvancedSettingsPanel({
open,
onOpenChange,
buildNodeId,
onBuildNodeIdChange,
buildNodes,
jobName,
onJobNameChange,
triggerMode,
onTriggerModeChange,
watchBranches,
onWatchBranchesChange,
cronExpr,
onCronExprChange,
envVars,
onEnvVarsChange,
}: AdvancedSettingsPanelProps) {
const { t } = useTranslation();
return (
<Collapsible open={open} onOpenChange={onOpenChange}>
<CollapsibleTrigger asChild>
<button
type="button"
className="flex items-center gap-1.5 text-xs text-[var(--dg-text-muted)] hover:text-[var(--dg-text-primary)]"
>
<Settings2 className="h-3.5 w-3.5" />
{t('deploy.advancedSettings')}
<ChevronDown className={cn('h-3.5 w-3.5 transition-transform', open && 'rotate-180')} />
</button>
</CollapsibleTrigger>
<CollapsibleContent className="mt-3 space-y-3 pt-3 border-t border-[var(--dg-border)]">
<div className="space-y-1.5">
<Label className="text-xs">{t('deploy.buildNode')}</Label>
<Select
value={buildNodeId || '__auto'}
onValueChange={(v) => onBuildNodeIdChange(v === '__auto' ? '' : v)}
>
<SelectTrigger className="h-8 text-xs dg-input">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="__auto">{t('deploy.autoSchedule')}</SelectItem>
{buildNodes.map((n) => (
<SelectItem key={n.id} value={String(n.id)}>
{n.name} ({n.running_count || 0}/{n.max_executors})
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-1.5">
<Label className="text-xs">
Job 名称 <span className="text-[var(--dg-text-muted)]">(Webhook)</span>
</Label>
<Input
value={jobName}
onChange={(e) => onJobNameChange(e.target.value)}
className="h-8 text-xs font-mono dg-input"
/>
</div>
<div className="space-y-1.5">
<Label className="text-xs">{t('deploy.triggerMethod')}</Label>
<Select value={triggerMode} onValueChange={onTriggerModeChange}>
<SelectTrigger className="h-8 text-xs dg-input">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="manual">{t('deploy.triggerManual')}</SelectItem>
<SelectItem value="git_push">{t('deploy.codePush')}</SelectItem>
<SelectItem value="cron">{t('deploy.triggerCron')}</SelectItem>
<SelectItem value="webhook">Webhook</SelectItem>
</SelectContent>
</Select>
</div>
{triggerMode === 'git_push' && (
<Input
value={watchBranches}
onChange={(e) => onWatchBranchesChange(e.target.value)}
placeholder="监听分支,如 main, release/*"
className="h-8 text-xs font-mono dg-input"
/>
)}
{triggerMode === 'cron' && (
<Input
value={cronExpr}
onChange={(e) => onCronExprChange(e.target.value)}
placeholder="0 2 * * *"
className="h-8 text-xs font-mono dg-input"
/>
)}
<div className="space-y-1.5">
<div className="flex items-center justify-between">
<Label className="text-xs">{t('deploy.envVars')}</Label>
<Button
type="button"
variant="ghost"
size="sm"
className="h-6 text-[10px]"
onClick={() => onEnvVarsChange([...envVars, { key: '', value: '' }])}
>
<Plus className="h-3 w-3 mr-0.5" />
{t('deploy.addVar')}
</Button>
</div>
{envVars.map((v, i) => (
<div key={i} className="flex gap-1.5">
<Input
value={v.key}
onChange={(e) => {
const nv = [...envVars];
nv[i] = { ...nv[i], key: e.target.value };
onEnvVarsChange(nv);
}}
placeholder="KEY"
className="h-7 text-xs font-mono dg-input flex-1"
/>
<Input
value={v.value}
onChange={(e) => {
const nv = [...envVars];
nv[i] = { ...nv[i], value: e.target.value };
onEnvVarsChange(nv);
}}
placeholder="value"
className="h-7 text-xs font-mono dg-input flex-[2]"
/>
<Button
type="button"
variant="ghost"
size="icon"
className="h-7 w-7 shrink-0"
onClick={() => onEnvVarsChange(envVars.filter((_, idx) => idx !== i))}
>
<Trash2 className="h-3.5 w-3.5 text-[var(--dg-red)]" />
</Button>
</div>
))}
</div>
</CollapsibleContent>
</Collapsible>
);
}