增加GIT代码检测节点
This commit is contained in:
parent
d65e82b0e8
commit
e03671c5de
@ -395,6 +395,46 @@ const TeamApplicationDialog: React.FC<TeamApplicationDialogProps> = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 源Git级联验证
|
||||||
|
if (formData.codeSourceSystemId) {
|
||||||
|
if (!formData.codeSourceProjectId) {
|
||||||
|
toast({
|
||||||
|
variant: 'destructive',
|
||||||
|
title: '请选择源仓库项目',
|
||||||
|
description: '已选择源Git系统,必须选择对应的仓库项目',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!formData.branch) {
|
||||||
|
toast({
|
||||||
|
variant: 'destructive',
|
||||||
|
title: '请选择源分支',
|
||||||
|
description: '已选择源Git系统,必须选择对应的分支',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 目标Git级联验证
|
||||||
|
if (formData.targetGitSystemId) {
|
||||||
|
if (!formData.targetGitProjectId) {
|
||||||
|
toast({
|
||||||
|
variant: 'destructive',
|
||||||
|
title: '请选择目标仓库项目',
|
||||||
|
description: '已选择目标Git系统,必须选择对应的仓库项目',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!formData.targetBranch) {
|
||||||
|
toast({
|
||||||
|
variant: 'destructive',
|
||||||
|
title: '请选择目标分支',
|
||||||
|
description: '已选择目标Git系统,必须选择对应的分支',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
try {
|
try {
|
||||||
await onSave({
|
await onSave({
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import { Separator } from '@/components/ui/separator';
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { PaginatedTable, type ColumnDef, type SearchFieldDef, type PaginatedTableRef } from '@/components/ui/paginated-table';
|
import { PaginatedTable, type ColumnDef, type SearchFieldDef, type PaginatedTableRef } from '@/components/ui/paginated-table';
|
||||||
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
@ -153,22 +154,47 @@ const TeamList: React.FC = () => {
|
|||||||
{
|
{
|
||||||
key: 'developmentMode',
|
key: 'developmentMode',
|
||||||
title: '开发模式',
|
title: '开发模式',
|
||||||
width: '160px',
|
width: '120px',
|
||||||
render: (_, record) => {
|
render: (_, record) => {
|
||||||
const modeOption = DEVELOPMENT_MODE_OPTIONS.find(opt => opt.value === record.developmentMode);
|
const modeOption = DEVELOPMENT_MODE_OPTIONS.find(opt => opt.value === record.developmentMode);
|
||||||
|
|
||||||
|
// 根据不同模式设置颜色
|
||||||
|
const getBadgeVariant = (mode: string) => {
|
||||||
|
switch (mode) {
|
||||||
|
case 'STANDARD': return 'outline' as const;
|
||||||
|
case 'SYNC_MODE': return 'default' as const; // 蓝色
|
||||||
|
case 'ARTIFACT_DELIVERY': return 'secondary' as const; // 灰色
|
||||||
|
default: return 'outline' as const;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-1">
|
<TooltipProvider>
|
||||||
<Badge variant="outline" className="inline-flex">
|
<Tooltip>
|
||||||
{modeOption?.label || record.developmentMode}
|
<TooltipTrigger asChild>
|
||||||
</Badge>
|
<Badge
|
||||||
{record.enableGitSyncCheck && (
|
variant={getBadgeVariant(record.developmentMode)}
|
||||||
<div className="text-xs text-muted-foreground">
|
className="cursor-help inline-flex items-center gap-1"
|
||||||
<Badge variant="secondary" className="text-xs">
|
>
|
||||||
Git同步检测
|
{modeOption?.label || record.developmentMode}
|
||||||
|
{record.enableGitSyncCheck && (
|
||||||
|
<span className="text-xs">🔄</span>
|
||||||
|
)}
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</TooltipTrigger>
|
||||||
)}
|
<TooltipContent side="right" className="max-w-xs">
|
||||||
</div>
|
<div className="space-y-1 text-xs">
|
||||||
|
<div className="font-semibold">{modeOption?.label}</div>
|
||||||
|
<div className="text-muted-foreground">{modeOption?.description}</div>
|
||||||
|
{record.enableGitSyncCheck && (
|
||||||
|
<div className="text-blue-600 border-t pt-1 mt-1">
|
||||||
|
✓ 已启用Git同步检测
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
167
frontend/src/pages/Workflow/Design/nodes/GitSyncCheckNode.tsx
Normal file
167
frontend/src/pages/Workflow/Design/nodes/GitSyncCheckNode.tsx
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
import {ConfigurableNodeDefinition, NodeType, NodeCategory, defineNodeOutputs} from './types';
|
||||||
|
import {DataSourceType} from '@/domain/dataSource';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Git同步检测节点定义(纯配置)
|
||||||
|
* 检测源分支与目标分支的同步状态
|
||||||
|
*/
|
||||||
|
export const GitSyncCheckNodeDefinition: ConfigurableNodeDefinition = {
|
||||||
|
nodeCode: "GIT_SYNC_CHECK",
|
||||||
|
nodeName: "Git同步检测",
|
||||||
|
nodeType: NodeType.GIT_SYNC_CHECK,
|
||||||
|
category: NodeCategory.TASK,
|
||||||
|
description: "检测源分支与目标分支的同步状态",
|
||||||
|
|
||||||
|
// 渲染配置
|
||||||
|
renderConfig: {
|
||||||
|
shape: 'rounded-rect',
|
||||||
|
size: {width: 140, height: 48},
|
||||||
|
icon: {
|
||||||
|
type: 'emoji',
|
||||||
|
content: '🔄', // 同步图标
|
||||||
|
size: 32
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
primary: '#3b82f6', // 蓝色主题,与Git同步的视觉一致
|
||||||
|
secondary: '#2563eb',
|
||||||
|
selectedBorder: '#3b82f6',
|
||||||
|
hoverBorder: '#60a5fa',
|
||||||
|
gradient: ['#ffffff', '#dbeafe']
|
||||||
|
},
|
||||||
|
handles: {
|
||||||
|
input: true,
|
||||||
|
output: true
|
||||||
|
},
|
||||||
|
features: {
|
||||||
|
showBadge: true,
|
||||||
|
showHoverMenu: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 输入配置Schema
|
||||||
|
inputMappingSchema: {
|
||||||
|
type: "object",
|
||||||
|
title: "输入",
|
||||||
|
description: "Git同步检测配置",
|
||||||
|
properties: {
|
||||||
|
continueOnFailure: {
|
||||||
|
type: "boolean",
|
||||||
|
title: "失败后继续",
|
||||||
|
description: "true: 发现差异时标记为FAILURE,但继续执行;false: 发现差异时抛出BpmnError,终止流程",
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
sourceGitSystemId: {
|
||||||
|
type: "number",
|
||||||
|
title: "源Git系统",
|
||||||
|
description: "内网Git系统(数据源或变量)",
|
||||||
|
"x-dataSource": DataSourceType.GIT_REPOSITORIES,
|
||||||
|
"x-allow-variable": true
|
||||||
|
},
|
||||||
|
sourceGitProjectId: {
|
||||||
|
type: "number",
|
||||||
|
title: "源Git项目",
|
||||||
|
description: "源仓库项目ID(输入变量,如 ${teamApplication.codeSourceProjectId})",
|
||||||
|
"x-allow-variable": true,
|
||||||
|
"x-placeholder": "${teamApplication.codeSourceProjectId}"
|
||||||
|
},
|
||||||
|
sourceBranch: {
|
||||||
|
type: "string",
|
||||||
|
title: "源分支",
|
||||||
|
description: "源分支名称(输入变量,如 ${teamApplication.branch})",
|
||||||
|
"x-allow-variable": true,
|
||||||
|
"x-placeholder": "${teamApplication.branch}"
|
||||||
|
},
|
||||||
|
targetGitSystemId: {
|
||||||
|
type: "number",
|
||||||
|
title: "目标Git系统",
|
||||||
|
description: "客户Git系统(数据源或变量)",
|
||||||
|
"x-dataSource": DataSourceType.GIT_REPOSITORIES,
|
||||||
|
"x-allow-variable": true
|
||||||
|
},
|
||||||
|
targetGitProjectId: {
|
||||||
|
type: "number",
|
||||||
|
title: "目标Git项目",
|
||||||
|
description: "目标仓库项目ID(输入变量,如 ${teamApplication.targetGitProjectId})",
|
||||||
|
"x-allow-variable": true,
|
||||||
|
"x-placeholder": "${teamApplication.targetGitProjectId}"
|
||||||
|
},
|
||||||
|
targetBranch: {
|
||||||
|
type: "string",
|
||||||
|
title: "目标分支",
|
||||||
|
description: "目标分支名称(输入变量,如 ${teamApplication.targetBranch})",
|
||||||
|
"x-allow-variable": true,
|
||||||
|
"x-placeholder": "${teamApplication.targetBranch}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
required: ["sourceGitSystemId", "sourceGitProjectId", "sourceBranch", "targetGitSystemId", "targetGitProjectId", "targetBranch"]
|
||||||
|
},
|
||||||
|
|
||||||
|
// 输出定义
|
||||||
|
outputs: defineNodeOutputs(
|
||||||
|
{
|
||||||
|
name: "hasDifference",
|
||||||
|
title: "是否存在差异",
|
||||||
|
type: "boolean",
|
||||||
|
description: "源分支和目标分支是否存在代码差异",
|
||||||
|
example: true,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "commitsAhead",
|
||||||
|
title: "源分支领先提交数",
|
||||||
|
type: "number",
|
||||||
|
description: "源分支比目标分支多出的提交数量",
|
||||||
|
example: 5,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "commitsBehind",
|
||||||
|
title: "目标分支领先提交数",
|
||||||
|
type: "number",
|
||||||
|
description: "目标分支比源分支多出的提交数量",
|
||||||
|
example: 0,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "differenceCommits",
|
||||||
|
title: "差异提交列表",
|
||||||
|
type: "array",
|
||||||
|
description: "差异提交详情列表(最多显示20条)",
|
||||||
|
example: [
|
||||||
|
{
|
||||||
|
"commitId": "a3f5e8d",
|
||||||
|
"message": "feat: 添加新功能",
|
||||||
|
"author": "张三",
|
||||||
|
"commitTime": "2025-12-04 10:30:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "sourceLatestCommit",
|
||||||
|
title: "源分支最新提交SHA",
|
||||||
|
type: "string",
|
||||||
|
description: "源分支最新提交的完整SHA值",
|
||||||
|
example: "a3f5e8d2c4b1a5e9f2d3e7b8c9d1a2f3e4b5c6d7",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "targetLatestCommit",
|
||||||
|
title: "目标分支最新提交SHA",
|
||||||
|
type: "string",
|
||||||
|
description: "目标分支最新提交的完整SHA值",
|
||||||
|
example: "b2e4c7f8d1a3e5b9c2d6f9a8e7d1c4b5a3f6e8d2",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "checkDetail",
|
||||||
|
title: "检查结果详情",
|
||||||
|
type: "string",
|
||||||
|
description: "检查结果的详细说明(用于通知模板)",
|
||||||
|
example: "源分支 'develop' 领先目标分支 'master' 5个提交,需要同步代码",
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// ✅ 不再需要单独的渲染组件,使用 BaseNode 即可
|
||||||
@ -8,6 +8,7 @@ import BaseNode from './components/BaseNode';
|
|||||||
import { StartEventNodeDefinition } from './StartEventNode';
|
import { StartEventNodeDefinition } from './StartEventNode';
|
||||||
import { EndEventNodeDefinition } from './EndEventNode';
|
import { EndEventNodeDefinition } from './EndEventNode';
|
||||||
import { JenkinsBuildNodeDefinition } from './JenkinsBuildNode';
|
import { JenkinsBuildNodeDefinition } from './JenkinsBuildNode';
|
||||||
|
import { GitSyncCheckNodeDefinition } from './GitSyncCheckNode';
|
||||||
import { NotificationNodeDefinition } from './NotificationNode';
|
import { NotificationNodeDefinition } from './NotificationNode';
|
||||||
import { ApprovalNodeDefinition } from './ApprovalNode';
|
import { ApprovalNodeDefinition } from './ApprovalNode';
|
||||||
import { HttpRequestNodeDefinition } from './HttpRequestNode';
|
import { HttpRequestNodeDefinition } from './HttpRequestNode';
|
||||||
@ -21,6 +22,7 @@ export const NODE_DEFINITIONS: WorkflowNodeDefinition[] = [
|
|||||||
StartEventNodeDefinition,
|
StartEventNodeDefinition,
|
||||||
EndEventNodeDefinition,
|
EndEventNodeDefinition,
|
||||||
JenkinsBuildNodeDefinition,
|
JenkinsBuildNodeDefinition,
|
||||||
|
GitSyncCheckNodeDefinition,
|
||||||
NotificationNodeDefinition,
|
NotificationNodeDefinition,
|
||||||
ApprovalNodeDefinition,
|
ApprovalNodeDefinition,
|
||||||
HttpRequestNodeDefinition,
|
HttpRequestNodeDefinition,
|
||||||
@ -35,6 +37,7 @@ export const nodeTypes = {
|
|||||||
START_EVENT: BaseNode,
|
START_EVENT: BaseNode,
|
||||||
END_EVENT: BaseNode,
|
END_EVENT: BaseNode,
|
||||||
JENKINS_BUILD: BaseNode,
|
JENKINS_BUILD: BaseNode,
|
||||||
|
GIT_SYNC_CHECK: BaseNode,
|
||||||
NOTIFICATION: BaseNode,
|
NOTIFICATION: BaseNode,
|
||||||
APPROVAL: BaseNode,
|
APPROVAL: BaseNode,
|
||||||
HTTP_REQUEST: BaseNode,
|
HTTP_REQUEST: BaseNode,
|
||||||
@ -52,6 +55,7 @@ export {
|
|||||||
StartEventNodeDefinition,
|
StartEventNodeDefinition,
|
||||||
EndEventNodeDefinition,
|
EndEventNodeDefinition,
|
||||||
JenkinsBuildNodeDefinition,
|
JenkinsBuildNodeDefinition,
|
||||||
|
GitSyncCheckNodeDefinition,
|
||||||
NotificationNodeDefinition,
|
NotificationNodeDefinition,
|
||||||
ApprovalNodeDefinition,
|
ApprovalNodeDefinition,
|
||||||
HttpRequestNodeDefinition,
|
HttpRequestNodeDefinition,
|
||||||
|
|||||||
@ -18,6 +18,7 @@ export enum NodeType {
|
|||||||
NOTIFICATION = 'NOTIFICATION',
|
NOTIFICATION = 'NOTIFICATION',
|
||||||
APPROVAL = 'APPROVAL',
|
APPROVAL = 'APPROVAL',
|
||||||
HTTP_REQUEST = 'HTTP_REQUEST',
|
HTTP_REQUEST = 'HTTP_REQUEST',
|
||||||
|
GIT_SYNC_CHECK = 'GIT_SYNC_CHECK',
|
||||||
GATEWAY_NODE = 'GATEWAY_NODE',
|
GATEWAY_NODE = 'GATEWAY_NODE',
|
||||||
SUB_PROCESS = 'SUB_PROCESS',
|
SUB_PROCESS = 'SUB_PROCESS',
|
||||||
CALL_ACTIVITY = 'CALL_ACTIVITY'
|
CALL_ACTIVITY = 'CALL_ACTIVITY'
|
||||||
@ -35,6 +36,7 @@ export const NODE_CATEGORY_MAP: Record<NodeType, NodeCategory> = {
|
|||||||
[NodeType.NOTIFICATION]: NodeCategory.TASK,
|
[NodeType.NOTIFICATION]: NodeCategory.TASK,
|
||||||
[NodeType.APPROVAL]: NodeCategory.TASK,
|
[NodeType.APPROVAL]: NodeCategory.TASK,
|
||||||
[NodeType.HTTP_REQUEST]: NodeCategory.TASK,
|
[NodeType.HTTP_REQUEST]: NodeCategory.TASK,
|
||||||
|
[NodeType.GIT_SYNC_CHECK]: NodeCategory.TASK,
|
||||||
[NodeType.GATEWAY_NODE]: NodeCategory.GATEWAY,
|
[NodeType.GATEWAY_NODE]: NodeCategory.GATEWAY,
|
||||||
[NodeType.SUB_PROCESS]: NodeCategory.CONTAINER,
|
[NodeType.SUB_PROCESS]: NodeCategory.CONTAINER,
|
||||||
[NodeType.CALL_ACTIVITY]: NodeCategory.CONTAINER,
|
[NodeType.CALL_ACTIVITY]: NodeCategory.CONTAINER,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user