feat: 重构项目页面架构并实现流水线步骤拖拽排序功能
主要更新: - 重构项目页面结构:将原有项目页面拆分为 list 和 detail 两个子模块 - 新增项目详情页面,支持多标签页展示(流水线、部署记录) - 实现流水线管理功能:支持新建、编辑、复制、删除、启用/禁用 - 实现流水线步骤管理:支持添加、编辑、删除、启用/禁用步骤 - 新增流水线步骤拖拽排序功能:集成 @dnd-kit 实现拖拽重排 - 优化左右两栏布局:左侧流水线列表,右侧步骤详情 - 新增部署记录展示功能:左右两栏布局,支持选中切换 - 提取可复用组件:DeployRecordItem、PipelineStepItem - 添加表单验证和用户交互反馈 - 更新路由配置支持项目详情页面 技术改进: - 安装 @dnd-kit 相关依赖实现拖拽功能 - 优化 TypeScript 类型定义 - 改进组件化设计,提高代码复用性 - 增强用户体验和交互反馈
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
import { Typography, Tag, Switch, Button } from '@arco-design/web-react';
|
||||
import { IconDragArrow, IconEdit, IconDelete } from '@arco-design/web-react/icon';
|
||||
import { useSortable } from '@dnd-kit/sortable';
|
||||
import { CSS } from '@dnd-kit/utilities';
|
||||
|
||||
// 流水线步骤类型定义
|
||||
interface PipelineStep {
|
||||
id: string;
|
||||
name: string;
|
||||
script: string;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
interface PipelineStepItemProps {
|
||||
step: PipelineStep;
|
||||
index: number;
|
||||
pipelineId: string;
|
||||
onToggle: (pipelineId: string, stepId: string, enabled: boolean) => void;
|
||||
onEdit: (pipelineId: string, step: PipelineStep) => void;
|
||||
onDelete: (pipelineId: string, stepId: string) => void;
|
||||
}
|
||||
|
||||
function PipelineStepItem({
|
||||
step,
|
||||
index,
|
||||
pipelineId,
|
||||
onToggle,
|
||||
onEdit,
|
||||
onDelete,
|
||||
}: PipelineStepItemProps) {
|
||||
const {
|
||||
attributes,
|
||||
listeners,
|
||||
setNodeRef,
|
||||
transform,
|
||||
transition,
|
||||
isDragging,
|
||||
} = useSortable({ id: step.id });
|
||||
|
||||
const style = {
|
||||
transform: CSS.Transform.toString(transform),
|
||||
transition,
|
||||
opacity: isDragging ? 0.5 : 1,
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={setNodeRef}
|
||||
style={style}
|
||||
className={`bg-gray-50 rounded-lg p-4 ${isDragging ? 'shadow-lg z-10' : ''}`}
|
||||
>
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
{...attributes}
|
||||
{...listeners}
|
||||
className="cursor-grab active:cursor-grabbing"
|
||||
>
|
||||
<IconDragArrow className="text-gray-400" />
|
||||
</div>
|
||||
<div className="w-8 h-8 rounded-full bg-blue-100 text-blue-600 flex items-center justify-center text-sm font-medium">
|
||||
{index + 1}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<Typography.Title heading={6} className="!m-0">
|
||||
{step.name}
|
||||
</Typography.Title>
|
||||
<Switch
|
||||
size="small"
|
||||
checked={step.enabled}
|
||||
onChange={(enabled) => onToggle(pipelineId, step.id, enabled)}
|
||||
/>
|
||||
{!step.enabled && (
|
||||
<Tag color="gray" size="small">
|
||||
已禁用
|
||||
</Tag>
|
||||
)}
|
||||
</div>
|
||||
<div className="bg-gray-900 text-green-400 p-3 rounded font-mono text-sm">
|
||||
<pre className="whitespace-pre-wrap break-words">{step.script}</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<IconEdit />}
|
||||
className="text-gray-400 hover:text-blue-500 hover:bg-blue-50 rounded-md p-1 transition-all duration-200"
|
||||
onClick={() => onEdit(pipelineId, step)}
|
||||
/>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<IconDelete />}
|
||||
className="text-gray-400 hover:text-red-500 hover:bg-red-50 rounded-md p-1 transition-all duration-200"
|
||||
onClick={() => onDelete(pipelineId, step.id)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PipelineStepItem;
|
||||
Reference in New Issue
Block a user