diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts index a9d2833c45..87c8e19d59 100644 --- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts +++ b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts @@ -477,7 +477,10 @@ const project = { complement_range: 'Complement Range', parameters_variables: 'Parameters variables', global_parameters: 'Global parameters', - local_parameters: 'Local parameters' + local_parameters: 'Local parameters', + type: 'Type', + retry_count: 'Retry Count', + submit_time: 'Submit Time' }, task: { task_name: 'Task Name', diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts index 5ae3aecbf0..fbb0e90da8 100644 --- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts +++ b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts @@ -475,7 +475,10 @@ const project = { complement_range: '补数范围', parameters_variables: '参数变量', global_parameters: '全局参数', - local_parameters: '局部参数' + local_parameters: '局部参数', + type: '类型', + retry_count: '重试次数', + submit_time: '提交时间' }, task: { task_name: '任务名称', diff --git a/dolphinscheduler-ui-next/src/service/modules/process-instances/index.ts b/dolphinscheduler-ui-next/src/service/modules/process-instances/index.ts index 92ec13e35c..67b6323aad 100644 --- a/dolphinscheduler-ui-next/src/service/modules/process-instances/index.ts +++ b/dolphinscheduler-ui-next/src/service/modules/process-instances/index.ts @@ -111,7 +111,7 @@ export function deleteProcessInstanceById(id: number, code: number): any { }) } -export function queryTaskListByProcessId(id: IdReq, code: CodeReq): any { +export function queryTaskListByProcessId(id: number, code: number): any { return axios({ url: `/projects/${code}/process-instances/${id}/tasks`, method: 'get' diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-hooks.ts b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-hooks.ts index 55b6e42ffc..114dbe7229 100644 --- a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-hooks.ts +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-hooks.ts @@ -27,6 +27,7 @@ import { useGraphBackfill } from './use-graph-backfill' import { useDagDragAndDrop } from './use-dag-drag-drop' import { useTaskEdit } from './use-task-edit' import { useNodeMenu } from './use-node-menu' +import { useNodeStatus } from './use-node-status' export { useCanvasInit, @@ -40,5 +41,6 @@ export { useCellUpdate, useDagDragAndDrop, useTaskEdit, - useNodeMenu + useNodeMenu, + useNodeStatus } diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-node-status.tsx b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-node-status.tsx new file mode 100644 index 0000000000..12726270de --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-node-status.tsx @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NTooltip, NSpin, NIcon } from 'naive-ui' +import { defineComponent, PropType, h } from 'vue' +import styles from './status.module.scss' + +const props = { + t: { + type: Object as PropType, + require: true + }, + taskInstance: { + type: Object as PropType, + require: true + }, + stateProps: { + type: Object as PropType, + require: true + } +} + +export default defineComponent({ + name: 'dag-node-status', + props, + setup(props) { + const iconElement = h( + NIcon, + { + size: '20px' + }, + { + default: () => + h(props.stateProps.icon, { + color: props.stateProps.color + }) + } + ) + return { + iconElement + } + }, + render() { + return ( + + {{ + trigger: () => { + if (this.stateProps.isSpin) { + return h( + NSpin, + { + small: 'small' + }, + { + icon: () => this.iconElement + } + ) + } else { + return this.iconElement + } + }, + default: () => ( +
    +
  • + {this.$props.t('project.workflow.name')}:{' '} + {this.taskInstance.name} +
  • +
  • + {this.$props.t('project.workflow.status')}:{' '} + {this.stateProps.desc} +
  • +
  • + {this.$props.t('project.workflow.type')}:{' '} + {this.taskInstance.taskType} +
  • +
  • + {this.$props.t('project.workflow.host')}:{' '} + {this.taskInstance.host || '-'} +
  • +
  • + {this.$props.t('project.workflow.retry_count')}:{' '} + {this.taskInstance.retryTimes} +
  • +
  • + {this.$props.t('project.workflow.submit_time')}:{' '} + {this.taskInstance.submitTime} +
  • +
  • + {this.$props.t('project.workflow.start_time')}:{' '} + {this.taskInstance.startTime} +
  • +
  • + {this.$props.t('project.workflow.end_time')}:{' '} + {this.taskInstance.endTime ? this.taskInstance.endTime : '-'} +
  • +
+ ) + }} +
+ ) + } +}) diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/index.tsx b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/index.tsx index 75c1fc71fd..8e1dc38f7e 100644 --- a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/index.tsx +++ b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/index.tsx @@ -16,7 +16,15 @@ */ import type { Graph } from '@antv/x6' -import { defineComponent, ref, provide, PropType, toRef } from 'vue' +import { + defineComponent, + ref, + provide, + PropType, + toRef, + onMounted, + watch +} from 'vue' import DagToolbar from './dag-toolbar' import DagCanvas from './dag-canvas' import DagSidebar from './dag-sidebar' @@ -28,7 +36,8 @@ import { useDagDragAndDrop, useTaskEdit, useBusinessMapper, - useNodeMenu + useNodeMenu, + useNodeStatus } from './dag-hooks' import { useThemeStore } from '@/store/theme/theme' import VersionModal from '../../definition/components/version-modal' @@ -108,6 +117,8 @@ export default defineComponent({ graph }) + const { refreshTaskStatus } = useNodeStatus({ graph }) + const { onDragStart, onDrop } = useDagDragAndDrop({ graph, readonly: toRef(props, 'readonly'), @@ -155,6 +166,15 @@ export default defineComponent({ saveModelToggle(false) } + onMounted(() => { + refreshTaskStatus() + }) + + watch( + () => props.definition, + () => refreshTaskStatus() + ) + return () => (
+} + +/** + * Node status and tooltip + */ +export function useNodeStatus(options: Options) { + const { graph } = options + const route = useRoute() + + const { t } = useI18n() + + const setNodeStatus = (code: string, state: string, taskInstance: any) => { + const stateProps = tasksState(t)[state] + const node = graph.value?.getCellById(code) + if (node) { + // Destroy the previous dom + node.removeMarkup() + node.setMarkup(NODE.markup.concat(NODE_STATUS_MARKUP)) + const nodeView = graph.value?.findViewByCell(node) + const el = nodeView?.find('div')[0] + const a = h(NodeStatus, { + t, + taskInstance, + stateProps + }) + + render(a, el as HTMLElement) + } + } + + /** + * Task status + */ + const refreshTaskStatus = () => { + const projectCode = Number(route.params.projectCode) + const instanceId = Number(route.params.id) + + queryTaskListByProcessId(instanceId, projectCode).then((res: any) => { + window.$message.success(t('project.workflow.success')) + const { taskList } = res + if (taskList) { + taskList.forEach((taskInstance: any) => { + setNodeStatus(taskInstance.taskCode, taskInstance.state, taskInstance) + }) + } + }) + } + + return { + refreshTaskStatus + } +}