重构前端逻辑
This commit is contained in:
parent
28cae45e51
commit
66efeb6058
@ -70,6 +70,7 @@
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hook-form": "^7.54.2",
|
||||
"react-infinite-scroll-component": "^6.1.0",
|
||||
"react-lazylog": "^4.5.3",
|
||||
"react-redux": "^9.0.4",
|
||||
"react-router-dom": "^6.21.0",
|
||||
"reactflow": "^11.11.4",
|
||||
|
||||
@ -185,6 +185,9 @@ importers:
|
||||
react-infinite-scroll-component:
|
||||
specifier: ^6.1.0
|
||||
version: 6.1.0(react@18.3.1)
|
||||
react-lazylog:
|
||||
specifier: ^4.5.3
|
||||
version: 4.5.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react-redux:
|
||||
specifier: ^9.0.4
|
||||
version: 9.2.0(@types/react@18.3.18)(react@18.3.1)(redux@5.0.1)
|
||||
@ -890,6 +893,11 @@ packages:
|
||||
'@marijn/find-cluster-break@1.0.2':
|
||||
resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
|
||||
|
||||
'@mattiasbuelens/web-streams-polyfill@0.2.1':
|
||||
resolution: {integrity: sha512-oKuFCQFa3W7Hj7zKn0+4ypI8JFm4ZKIoncwAC6wd5WwFW2sL7O1hpPoJdSWpynQ4DJ4lQ6MvFoVDmCLilonDFg==}
|
||||
engines: {node: '>= 8'}
|
||||
deprecated: moved to web-streams-polyfill@2.0.0
|
||||
|
||||
'@monaco-editor/loader@1.4.0':
|
||||
resolution: {integrity: sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==}
|
||||
peerDependencies:
|
||||
@ -2211,6 +2219,9 @@ packages:
|
||||
'@types/uuid@10.0.0':
|
||||
resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==}
|
||||
|
||||
'@types/whatwg-streams@0.0.7':
|
||||
resolution: {integrity: sha512-6sDiSEP6DWcY2ZolsJ2s39ZmsoGQ7KVwBDI3sESQsEm9P2dHTcqnDIHRZFRNtLCzWp7hCFGqYbw5GyfpQnJ01A==}
|
||||
|
||||
'@typescript-eslint/eslint-plugin@6.21.0':
|
||||
resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==}
|
||||
engines: {node: ^16.0.0 || >=18.0.0}
|
||||
@ -2459,6 +2470,10 @@ packages:
|
||||
classnames@2.5.1:
|
||||
resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
|
||||
|
||||
clsx@1.2.1:
|
||||
resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
clsx@2.1.1:
|
||||
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
||||
engines: {node: '>=6'}
|
||||
@ -2802,6 +2817,9 @@ packages:
|
||||
fastq@1.17.1:
|
||||
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
|
||||
|
||||
fetch-readablestream@0.2.0:
|
||||
resolution: {integrity: sha512-qu4mXWf4wus4idBIN/kVH+XSer8IZ9CwHP+Pd7DL7TuKNC1hP7ykon4kkBjwJF3EMX2WsFp4hH7gU7CyL7ucXw==}
|
||||
|
||||
file-entry-cache@6.0.1:
|
||||
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
|
||||
engines: {node: ^10.12.0 || >=12.0.0}
|
||||
@ -2956,6 +2974,10 @@ packages:
|
||||
immer@10.1.1:
|
||||
resolution: {integrity: sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==}
|
||||
|
||||
immutable@3.8.2:
|
||||
resolution: {integrity: sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
import-fresh@3.3.0:
|
||||
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
|
||||
engines: {node: '>=6'}
|
||||
@ -3176,6 +3198,9 @@ packages:
|
||||
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
mitt@1.2.0:
|
||||
resolution: {integrity: sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw==}
|
||||
|
||||
mobx-react-lite@4.1.1:
|
||||
resolution: {integrity: sha512-iUxiMpsvNraCKXU+yPotsOncNNmyeS2B5DKL+TL6Tar/xm+wwNJAubJmtRSeAoYawdZqwv8Z/+5nPRHeQxTiXg==}
|
||||
peerDependencies:
|
||||
@ -3751,6 +3776,11 @@ packages:
|
||||
react-is@18.3.1:
|
||||
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
|
||||
|
||||
react-lazylog@4.5.3:
|
||||
resolution: {integrity: sha512-lyov32A/4BqihgXgtNXTHCajXSXkYHPlIEmV8RbYjHIMxCFSnmtdg4kDCI3vATz7dURtiFTvrw5yonHnrS+NNg==}
|
||||
peerDependencies:
|
||||
react: '>=16.3.0'
|
||||
|
||||
react-lifecycles-compat@3.0.4:
|
||||
resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==}
|
||||
|
||||
@ -3832,6 +3862,10 @@ packages:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
react-string-replace@0.4.4:
|
||||
resolution: {integrity: sha512-FAMkhxmDpCsGTwTZg7p/2v+/GTmxAp73so3fbSvlAcBBX36ujiGRNEaM/1u+jiYQrArhns+7eE92g2pi5E5FUA==}
|
||||
engines: {node: '>=0.12.0'}
|
||||
|
||||
react-style-singleton@2.2.3:
|
||||
resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==}
|
||||
engines: {node: '>=10'}
|
||||
@ -3853,6 +3887,12 @@ packages:
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
|
||||
react-virtualized@9.22.6:
|
||||
resolution: {integrity: sha512-U5j7KuUQt3AaMatlMJ0UJddqSiX+Km0YJxSqbAzIiGw5EmNz0khMyqP2hzgu4+QUtm+QPIrxzUX4raJxmVJnHg==}
|
||||
peerDependencies:
|
||||
react: ^16.3.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^16.3.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
react-window@1.8.11:
|
||||
resolution: {integrity: sha512-+SRbUVT2scadgFSWx+R1P754xHPEqvcfSfVX10QYg6POOz+WNgkN48pS+BtZNIMGiL1HYrSEiCkwsMS15QogEQ==}
|
||||
engines: {node: '>8.0.0'}
|
||||
@ -4115,6 +4155,9 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
text-encoding-utf-8@1.0.2:
|
||||
resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==}
|
||||
|
||||
text-table@0.2.0:
|
||||
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
||||
|
||||
@ -4275,6 +4318,9 @@ packages:
|
||||
warning@4.0.3:
|
||||
resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==}
|
||||
|
||||
whatwg-fetch@2.0.4:
|
||||
resolution: {integrity: sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==}
|
||||
|
||||
which@2.0.2:
|
||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||
engines: {node: '>= 8'}
|
||||
@ -5125,6 +5171,10 @@ snapshots:
|
||||
|
||||
'@marijn/find-cluster-break@1.0.2': {}
|
||||
|
||||
'@mattiasbuelens/web-streams-polyfill@0.2.1':
|
||||
dependencies:
|
||||
'@types/whatwg-streams': 0.0.7
|
||||
|
||||
'@monaco-editor/loader@1.4.0(monaco-editor@0.52.2)':
|
||||
dependencies:
|
||||
monaco-editor: 0.52.2
|
||||
@ -6564,6 +6614,8 @@ snapshots:
|
||||
|
||||
'@types/uuid@10.0.0': {}
|
||||
|
||||
'@types/whatwg-streams@0.0.7': {}
|
||||
|
||||
'@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.1
|
||||
@ -6921,6 +6973,8 @@ snapshots:
|
||||
|
||||
classnames@2.5.1: {}
|
||||
|
||||
clsx@1.2.1: {}
|
||||
|
||||
clsx@2.1.1: {}
|
||||
|
||||
cmdk@1.1.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
@ -7297,6 +7351,8 @@ snapshots:
|
||||
dependencies:
|
||||
reusify: 1.0.4
|
||||
|
||||
fetch-readablestream@0.2.0: {}
|
||||
|
||||
file-entry-cache@6.0.1:
|
||||
dependencies:
|
||||
flat-cache: 3.2.0
|
||||
@ -7462,6 +7518,8 @@ snapshots:
|
||||
|
||||
immer@10.1.1: {}
|
||||
|
||||
immutable@3.8.2: {}
|
||||
|
||||
import-fresh@3.3.0:
|
||||
dependencies:
|
||||
parent-module: 1.0.1
|
||||
@ -7656,6 +7714,8 @@ snapshots:
|
||||
|
||||
minipass@7.1.2: {}
|
||||
|
||||
mitt@1.2.0: {}
|
||||
|
||||
mobx-react-lite@4.1.1(mobx@6.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
mobx: 6.15.0
|
||||
@ -8311,6 +8371,21 @@ snapshots:
|
||||
|
||||
react-is@18.3.1: {}
|
||||
|
||||
react-lazylog@4.5.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
'@mattiasbuelens/web-streams-polyfill': 0.2.1
|
||||
fetch-readablestream: 0.2.0
|
||||
immutable: 3.8.2
|
||||
mitt: 1.2.0
|
||||
prop-types: 15.8.1
|
||||
react: 18.3.1
|
||||
react-string-replace: 0.4.4
|
||||
react-virtualized: 9.22.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
text-encoding-utf-8: 1.0.2
|
||||
whatwg-fetch: 2.0.4
|
||||
transitivePeerDependencies:
|
||||
- react-dom
|
||||
|
||||
react-lifecycles-compat@3.0.4: {}
|
||||
|
||||
react-number-format@5.4.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
@ -8387,6 +8462,10 @@ snapshots:
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
|
||||
react-string-replace@0.4.4:
|
||||
dependencies:
|
||||
lodash: 4.17.21
|
||||
|
||||
react-style-singleton@2.2.3(@types/react@18.3.18)(react@18.3.1):
|
||||
dependencies:
|
||||
get-nonce: 1.0.1
|
||||
@ -8408,6 +8487,17 @@ snapshots:
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
|
||||
react-virtualized@9.22.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.26.0
|
||||
clsx: 1.2.1
|
||||
dom-helpers: 5.2.1
|
||||
loose-envify: 1.4.0
|
||||
prop-types: 15.8.1
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
react-lifecycles-compat: 3.0.4
|
||||
|
||||
react-window@1.8.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.26.0
|
||||
@ -8729,6 +8819,8 @@ snapshots:
|
||||
source-map-support: 0.5.21
|
||||
optional: true
|
||||
|
||||
text-encoding-utf-8@1.0.2: {}
|
||||
|
||||
text-table@0.2.0: {}
|
||||
|
||||
thenify-all@1.6.0:
|
||||
@ -8852,6 +8944,8 @@ snapshots:
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
|
||||
whatwg-fetch@2.0.4: {}
|
||||
|
||||
which@2.0.2:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState, useMemo } from 'react';
|
||||
import { ReactFlowProvider, ReactFlow, Background, Node, Edge, Handle, Position, BackgroundVariant } from '@xyflow/react';
|
||||
import React, { useEffect, useState, useMemo, useCallback } from 'react';
|
||||
import { ReactFlowProvider, ReactFlow, Background, Node, Edge, Handle, Position, BackgroundVariant, NodeProps } from '@xyflow/react';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
@ -17,7 +17,8 @@ import {
|
||||
Clock,
|
||||
CheckCircle2,
|
||||
XCircle,
|
||||
AlertTriangle
|
||||
AlertTriangle,
|
||||
FileText
|
||||
} from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import '@xyflow/react/dist/style.css';
|
||||
@ -32,6 +33,7 @@ import {
|
||||
formatDuration,
|
||||
calculateRunningDuration
|
||||
} from '../utils/dashboardUtils';
|
||||
import DeployNodeLogDialog from './DeployNodeLogDialog';
|
||||
|
||||
interface DeployFlowGraphModalProps {
|
||||
open: boolean;
|
||||
@ -39,16 +41,34 @@ interface DeployFlowGraphModalProps {
|
||||
onOpenChange: (open: boolean) => void;
|
||||
}
|
||||
|
||||
interface CustomNodeData {
|
||||
nodeName: string;
|
||||
nodeType: string;
|
||||
nodeId: string;
|
||||
status: string;
|
||||
startTime?: string | null;
|
||||
endTime?: string | null;
|
||||
duration?: number | null;
|
||||
errorMessage?: string | null;
|
||||
isUnreachable?: boolean;
|
||||
processInstanceId?: string;
|
||||
onViewLog?: (nodeId: string, nodeName: string) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义流程节点组件
|
||||
*/
|
||||
const CustomFlowNode: React.FC<any> = ({ data }) => {
|
||||
const { nodeName, nodeType, status, startTime, endTime, duration, errorMessage, isUnreachable } = data;
|
||||
const { nodeName, nodeType, status, startTime, endTime, duration, errorMessage, isUnreachable } = data as CustomNodeData;
|
||||
const statusColor = getNodeStatusColor(status);
|
||||
const isNotStarted = status === 'NOT_STARTED';
|
||||
const isRunning = status === 'RUNNING';
|
||||
const hasFailed = status === 'FAILED';
|
||||
|
||||
// 判断是否可以查看日志(具有日志输出能力的节点类型)
|
||||
const loggableNodeTypes = ['JENKINS_BUILD', 'ServiceTask'];
|
||||
const canViewLog = loggableNodeTypes.includes(nodeType) && status !== 'NOT_STARTED';
|
||||
|
||||
// 计算显示的时长
|
||||
const displayDuration = useMemo(() => {
|
||||
if (duration !== null && duration !== undefined) {
|
||||
@ -69,7 +89,8 @@ const CustomFlowNode: React.FC<any> = ({ data }) => {
|
||||
isNotStarted && 'border-2 border-dashed',
|
||||
!isNotStarted && 'border-2 border-solid shadow-sm',
|
||||
isRunning && 'animate-pulse',
|
||||
isUnreachable && 'opacity-40' // 不可达节点半透明
|
||||
isUnreachable && 'opacity-40', // 不可达节点半透明
|
||||
canViewLog && 'cursor-pointer hover:shadow-md hover:scale-[1.02]' // 可查看日志的节点增加交互效果
|
||||
)}
|
||||
style={{
|
||||
borderColor: statusColor,
|
||||
@ -77,7 +98,12 @@ const CustomFlowNode: React.FC<any> = ({ data }) => {
|
||||
}}
|
||||
>
|
||||
{/* 节点名称 */}
|
||||
<div className="font-medium text-sm mb-1">{nodeName}</div>
|
||||
<div className="flex items-center justify-between gap-2 mb-1">
|
||||
<div className="font-medium text-sm">{nodeName}</div>
|
||||
{canViewLog && (
|
||||
<FileText className="h-3.5 w-3.5 text-muted-foreground flex-shrink-0" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 节点状态 */}
|
||||
<div
|
||||
@ -108,6 +134,13 @@ const CustomFlowNode: React.FC<any> = ({ data }) => {
|
||||
<span className="text-xs">有错误</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 查看日志提示 */}
|
||||
{canViewLog && (
|
||||
<div className="mt-2 text-xs text-blue-600 flex items-center gap-1">
|
||||
<span>点击查看日志</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -371,6 +404,34 @@ export const DeployFlowGraphModal: React.FC<DeployFlowGraphModalProps> = ({
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [flowData, setFlowData] = useState<DeployRecordFlowGraph | null>(null);
|
||||
|
||||
// 日志对话框状态
|
||||
const [logDialogOpen, setLogDialogOpen] = useState(false);
|
||||
const [selectedNodeId, setSelectedNodeId] = useState<string>('');
|
||||
const [selectedNodeName, setSelectedNodeName] = useState<string>('');
|
||||
|
||||
// 查看日志处理函数
|
||||
const handleViewLog = (nodeId: string, nodeName: string) => {
|
||||
setSelectedNodeId(nodeId);
|
||||
setSelectedNodeName(nodeName);
|
||||
setLogDialogOpen(true);
|
||||
};
|
||||
|
||||
// ReactFlow 节点点击事件处理
|
||||
const onNodeClick = useCallback((_event: React.MouseEvent, node: Node) => {
|
||||
const nodeData = node.data as unknown as CustomNodeData;
|
||||
|
||||
// 可以查看日志的节点类型
|
||||
const loggableNodeTypes = ['JENKINS_BUILD', 'ServiceTask'];
|
||||
const canViewLog = loggableNodeTypes.includes(nodeData.nodeType) && nodeData.status !== 'NOT_STARTED';
|
||||
|
||||
if (canViewLog) {
|
||||
console.log('Node clicked, opening log dialog:', nodeData.nodeId, nodeData.nodeName);
|
||||
handleViewLog(nodeData.nodeId, nodeData.nodeName);
|
||||
} else {
|
||||
console.log('Node clicked but cannot view log:', nodeData.nodeType, nodeData.status);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 加载流程图数据
|
||||
useEffect(() => {
|
||||
if (open && deployRecordId) {
|
||||
@ -492,6 +553,7 @@ export const DeployFlowGraphModal: React.FC<DeployFlowGraphModalProps> = ({
|
||||
data: {
|
||||
nodeName: node.nodeName,
|
||||
nodeType: node.nodeType,
|
||||
nodeId: node.id,
|
||||
status: instance?.status || 'NOT_STARTED',
|
||||
startTime: instance?.startTime,
|
||||
endTime: instance?.endTime,
|
||||
@ -499,6 +561,7 @@ export const DeployFlowGraphModal: React.FC<DeployFlowGraphModalProps> = ({
|
||||
errorMessage: instance?.errorMessage,
|
||||
// 新增:不可达且未执行的节点标记为置灰
|
||||
isUnreachable: isRunning && isNotStarted && !isReachable,
|
||||
processInstanceId: flowData.processInstanceId,
|
||||
},
|
||||
};
|
||||
});
|
||||
@ -595,6 +658,7 @@ export const DeployFlowGraphModal: React.FC<DeployFlowGraphModalProps> = ({
|
||||
: null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="!max-w-7xl w-[90vw] h-[85vh] flex flex-col p-0 overflow-hidden">
|
||||
<DialogHeader className="px-6 pt-6 pb-4 border-b flex-shrink-0">
|
||||
@ -642,9 +706,13 @@ export const DeployFlowGraphModal: React.FC<DeployFlowGraphModalProps> = ({
|
||||
nodes={flowNodes}
|
||||
edges={flowEdges}
|
||||
nodeTypes={nodeTypes}
|
||||
onNodeClick={onNodeClick}
|
||||
fitView
|
||||
className="bg-muted/10"
|
||||
fitViewOptions={{ padding: 0.2, maxZoom: 1, minZoom: 0.5 }}
|
||||
nodesDraggable={false}
|
||||
nodesConnectable={false}
|
||||
elementsSelectable={true}
|
||||
panOnScroll={true}
|
||||
zoomOnScroll={true}
|
||||
zoomOnPinch={true}
|
||||
@ -671,5 +739,17 @@ export const DeployFlowGraphModal: React.FC<DeployFlowGraphModalProps> = ({
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* 节点日志对话框 */}
|
||||
{flowData && (
|
||||
<DeployNodeLogDialog
|
||||
open={logDialogOpen}
|
||||
onOpenChange={setLogDialogOpen}
|
||||
processInstanceId={flowData.processInstanceId}
|
||||
nodeId={selectedNodeId}
|
||||
nodeName={selectedNodeName}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -39,3 +39,13 @@ export const getMyApprovalTasks = (workflowDefinitionKeys?: string[]) => {
|
||||
*/
|
||||
export const completeApproval = (data: CompleteApprovalRequest) =>
|
||||
request.post(`${DEPLOY_URL}/complete`, data);
|
||||
|
||||
/**
|
||||
* 获取部署节点日志
|
||||
* @param processInstanceId 流程实例ID
|
||||
* @param nodeId 节点ID
|
||||
*/
|
||||
export const getDeployNodeLogs = (processInstanceId: string, nodeId: string) =>
|
||||
request.get<import('./types').DeployNodeLogDTO>(`${DEPLOY_URL}/logs`, {
|
||||
params: { processInstanceId, nodeId }
|
||||
});
|
||||
|
||||
@ -255,3 +255,26 @@ export interface DeployRecordFlowGraph {
|
||||
graph: WorkflowDefinitionGraph;
|
||||
nodeInstances: WorkflowNodeInstance[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志级别
|
||||
*/
|
||||
export type LogLevel = 'INFO' | 'WARN' | 'ERROR';
|
||||
|
||||
/**
|
||||
* 日志条目
|
||||
*/
|
||||
export interface LogEntry {
|
||||
sequenceId: number;
|
||||
timestamp: string;
|
||||
level: LogLevel;
|
||||
message: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 部署节点日志响应
|
||||
*/
|
||||
export interface DeployNodeLogDTO {
|
||||
expired: boolean;
|
||||
logs: LogEntry[];
|
||||
}
|
||||
|
||||
@ -44,6 +44,12 @@ export const ApprovalNodeDefinition: ConfigurableNodeDefinition = {
|
||||
title: "审批配置",
|
||||
description: "配置审批人和审批规则",
|
||||
properties: {
|
||||
continueOnFailure: {
|
||||
type: "boolean",
|
||||
title: "失败后继续",
|
||||
description: "当节点执行失败时,是否继续执行后续节点。true: 节点失败时标记为 FAILURE,但流程继续执行后续节点;false: 节点失败时抛出 BpmnError,终止流程",
|
||||
default: true
|
||||
},
|
||||
approvalMode: {
|
||||
type: "string",
|
||||
title: "审批模式",
|
||||
|
||||
@ -44,6 +44,12 @@ export const JenkinsBuildNodeDefinition: ConfigurableNodeDefinition = {
|
||||
title: "输入",
|
||||
description: "当前节点所需数据配置",
|
||||
properties: {
|
||||
continueOnFailure: {
|
||||
type: "boolean",
|
||||
title: "失败后继续",
|
||||
description: "当节点执行失败时,是否继续执行后续节点。true: 节点失败时标记为 FAILURE,但流程继续执行后续节点;false: 节点失败时抛出 BpmnError,终止流程",
|
||||
default: true
|
||||
},
|
||||
serverId: {
|
||||
type: "number",
|
||||
title: "Jenkins服务器",
|
||||
@ -58,7 +64,7 @@ export const JenkinsBuildNodeDefinition: ConfigurableNodeDefinition = {
|
||||
// 注意:jobName 暂时使用手动输入,因为需要先选择 serverId 才能级联加载 jobs
|
||||
// 未来如果需要级联下拉,需要使用 CascadeDataSourceType.JENKINS_SERVER_VIEWS_JOBS
|
||||
"x-allow-variable": true
|
||||
},
|
||||
}
|
||||
},
|
||||
required: ["serverId", "jobName"]
|
||||
},
|
||||
|
||||
@ -44,6 +44,12 @@ export const NotificationNodeDefinition: ConfigurableNodeDefinition = {
|
||||
title: "输入",
|
||||
description: "当前节点所需数据配置",
|
||||
properties: {
|
||||
continueOnFailure: {
|
||||
type: "boolean",
|
||||
title: "失败后继续",
|
||||
description: "当节点执行失败时,是否继续执行后续节点。true: 节点失败时标记为 FAILURE,但流程继续执行后续节点;false: 节点失败时抛出 BpmnError,终止流程",
|
||||
default: true
|
||||
},
|
||||
// notificationType: {
|
||||
// type: "string",
|
||||
// title: "通知类型",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user