diff --git a/dinky-web/src/components/CallBackButton/CircleBtn.tsx b/dinky-web/src/components/CallBackButton/CircleBtn.tsx index 3435ddca66c..ab383b6a551 100644 --- a/dinky-web/src/components/CallBackButton/CircleBtn.tsx +++ b/dinky-web/src/components/CallBackButton/CircleBtn.tsx @@ -16,9 +16,9 @@ * */ +import { TabsItemType } from '@/pages/DataStudio/model'; import { Button } from 'antd'; import React from 'react'; -import {TabsItemType} from "@/pages/DataStudio/model"; export type CircleButtonProps = { icon: React.ReactNode; @@ -30,7 +30,7 @@ export type CircleButtonProps = { export type CircleDataStudioButtonProps = { icon: React.ReactNode; loading?: boolean; - onClick?: (panes:TabsItemType[],activeKey:string) => void; + onClick?: (panes: TabsItemType[], activeKey: string) => void; title?: string; key?: string; }; diff --git a/dinky-web/src/components/FlinkDag/component/DagDataNode.tsx b/dinky-web/src/components/FlinkDag/component/DagDataNode.tsx index 51ed6a7ffff..3f181ec9dab 100644 --- a/dinky-web/src/components/FlinkDag/component/DagDataNode.tsx +++ b/dinky-web/src/components/FlinkDag/component/DagDataNode.tsx @@ -98,13 +98,20 @@ const DagDataNode = (props: any) => { {' '} {l('devops.baseinfo.busy')}: - {renderRatio((backpressure && backpressure.subtasks)?backpressure.subtasks[0]?.busyRatio:0, false)} + {renderRatio( + backpressure && backpressure.subtasks ? backpressure.subtasks[0]?.busyRatio : 0, + false + )} {l('devops.baseinfo.backpressure')}: - + @@ -113,7 +120,10 @@ const DagDataNode = (props: any) => { {l('devops.baseinfo.idle')}: - {renderRatio((backpressure && backpressure.subtasks)?backpressure.subtasks[0]?.idleRatio:0, true)} + {renderRatio( + backpressure && backpressure.subtasks ? backpressure.subtasks[0]?.idleRatio : 0, + true + )} diff --git a/dinky-web/src/components/FlinkDag/index.tsx b/dinky-web/src/components/FlinkDag/index.tsx index 0e48b2b92dc..19e134834f3 100644 --- a/dinky-web/src/components/FlinkDag/index.tsx +++ b/dinky-web/src/components/FlinkDag/index.tsx @@ -20,74 +20,72 @@ import DagDataNode from '@/components/FlinkDag/component/DagDataNode'; import DagPlanNode from '@/components/FlinkDag/component/DagPlanNode'; import { - edgeConfig, - graphConfig, - layoutConfig, - portConfig, - zoomOptions + edgeConfig, + graphConfig, + layoutConfig, + portConfig, + zoomOptions } from '@/components/FlinkDag/config'; -import {buildDag, regConnect, updateDag} from '@/components/FlinkDag/functions'; -import {Jobs} from '@/types/DevOps/data'; -import {DagreLayout} from '@antv/layout'; -import {Edge, Graph} from '@antv/x6'; -import {Selection} from '@antv/x6-plugin-selection'; -import {register} from '@antv/x6-react-shape'; -import {Drawer, Select, Slider, Table, Tabs, TabsProps, Typography} from 'antd'; -import {useEffect, useRef, useState} from 'react'; +import { buildDag, regConnect, updateDag } from '@/components/FlinkDag/functions'; +import { getData } from '@/services/api'; +import { API_CONSTANTS } from '@/services/endpoints'; +import { Jobs } from '@/types/DevOps/data'; +import { DagreLayout } from '@antv/layout'; +import { Edge, Graph } from '@antv/x6'; +import { Rectangle } from '@antv/x6-geometry'; +import { Selection } from '@antv/x6-plugin-selection'; +import { register } from '@antv/x6-react-shape'; +import { Drawer, Select, Slider, Table, Tabs, TabsProps, Typography } from 'antd'; +import { useEffect, useRef, useState } from 'react'; import './index.css'; -import {getData} from "@/services/api"; -import {API_CONSTANTS} from "@/services/endpoints"; -import {Rectangle} from "@antv/x6-geometry"; -import {Options as GraphOptions} from "@antv/x6/src/graph/options"; -import path from "path"; export type DagProps = { - job: Jobs.Job; - onlyPlan?: boolean; - checkPoints?: any; + job: Jobs.Job; + onlyPlan?: boolean; + checkPoints?: any; }; -const {Paragraph} = Typography; +const { Paragraph } = Typography; const FlinkDag = (props: DagProps) => { - const container = useRef(null); - - const {job, onlyPlan = false, checkPoints = {}} = props; - - const [graph, setGraph] = useState(); - const [currentJob, setCurrentJob] = useState(); - const [currentSelect, setCurrentSelect] = useState(); - const [open, setOpen] = useState(false); - const [zoom, setZoom] = useState(1); - let originPosition = { - zoom: 1 - }; - - const handleClose = () => { - setOpen(false); - setCurrentSelect(undefined); - graph?.zoomToFit(zoomOptions); - graph?.centerContent(); - }; - - const initListen = (graph: Graph) => { - graph.on('node:selected', ({cell}) => { - if (!onlyPlan) { - setOpen(true); - setZoom(oldValue => { - originPosition = {zoom: oldValue} - return 1; - }) - graph.zoomTo(1) - setCurrentSelect(cell); - graph.positionPoint(Rectangle.create(cell.getBBox()).getLeftMiddle(), '10%', '50%'); - } - }); + const container = useRef(null); + + const { job, onlyPlan = false, checkPoints = {} } = props; + + const [graph, setGraph] = useState(); + const [currentJob, setCurrentJob] = useState(); + const [currentSelect, setCurrentSelect] = useState(); + const [open, setOpen] = useState(false); + const [zoom, setZoom] = useState(1); + let originPosition = { + zoom: 1 + }; - graph.on('node:unselected', ({cell}) => { - setZoom(originPosition.zoom) - handleClose(); + const handleClose = () => { + setOpen(false); + setCurrentSelect(undefined); + graph?.zoomToFit(zoomOptions); + graph?.centerContent(); + }; + + const initListen = (graph: Graph) => { + graph.on('node:selected', ({ cell }) => { + if (!onlyPlan) { + setOpen(true); + setZoom((oldValue) => { + originPosition = { zoom: oldValue }; + return 1; }); - }; + graph.zoomTo(1); + setCurrentSelect(cell); + graph.positionPoint(Rectangle.create(cell.getBBox()).getLeftMiddle(), '10%', '50%'); + } + }); + + graph.on('node:unselected', ({ cell }) => { + setZoom(originPosition.zoom); + handleClose(); + }); + }; const initGraph = (flinkData: any) => { register({ @@ -98,156 +96,193 @@ const FlinkDag = (props: DagProps) => { ports: portConfig }); - Edge.config(edgeConfig); - Graph.registerConnector('curveConnector', regConnect, true); - Graph.registerEdge('data-processing-curve', Edge, true); + Edge.config(edgeConfig); + Graph.registerConnector('curveConnector', regConnect, true); + Graph.registerEdge('data-processing-curve', Edge, true); - const graph: Graph = new Graph({ - // @ts-ignore - container: container.current, - ...graphConfig - }); + const graph: Graph = new Graph({ + // @ts-ignore + container: container.current, + ...graphConfig + }); - graph.use( - new Selection({ - enabled: true, - multiple: false, - rubberband: false, - showNodeSelectionBox: true - }) - ); - - // Adaptive layout - const model = new DagreLayout(layoutConfig).layout(flinkData); - graph.fromJSON(model); - - // Automatically zoom to fit - graph.zoomToFit(zoomOptions); - graph.on('scale', ({sx}) => setZoom(sx)); - graph.centerContent(); - graph?.zoomTo(zoom) - updateDag(job?.vertices, graph); - initListen(graph); - return graph; - }; + graph.use( + new Selection({ + enabled: true, + multiple: false, + rubberband: false, + showNodeSelectionBox: true + }) + ); - useEffect(() => { - const flinkData = buildDag(job?.plan); - // Clean up old data - if (graph) { - graph.clearCells(); - } - setGraph(initGraph(flinkData)); - setZoom(1 / flinkData.nodes.length + 0.5) - }, [currentJob]); + // Adaptive layout + const model = new DagreLayout(layoutConfig).layout(flinkData); + graph.fromJSON(model); - useEffect(() => { - updateDag(job?.vertices, graph); - if (currentJob != job?.jid) { - setCurrentJob(job?.jid); - } - }, [job]); + // Automatically zoom to fit + graph.zoomToFit(zoomOptions); + graph.on('scale', ({ sx }) => setZoom(sx)); + graph.centerContent(); + graph?.zoomTo(zoom); + updateDag(job?.vertices, graph); + initListen(graph); + return graph; + }; + + useEffect(() => { + const flinkData = buildDag(job?.plan); + // Clean up old data + if (graph) { + graph.clearCells(); + } + setGraph(initGraph(flinkData)); + setZoom(1 / flinkData.nodes.length + 0.5); + }, [currentJob]); + + useEffect(() => { + updateDag(job?.vertices, graph); + if (currentJob != job?.jid) { + setCurrentJob(job?.jid); + } + }, [job]); + useEffect(() => { + graph?.zoomTo(zoom); + }, [zoom]); + + const renderCheckpoint = (id: string) => { + const [selectPath, setSelectPath] = useState(''); + const key = id + selectPath; + const [itemChildren, setItemChildren] = useState({ [key]: [] as TabsProps['items'] }); + const checkpointArray = ((checkPoints.history ?? []) as any[]) + .filter((x) => x.status === 'COMPLETED') + .map((x) => { + return { checkpointType: x.checkpoint_type, path: x.external_path, id: x.id }; + }); useEffect(() => { - graph?.zoomTo(zoom) - }, [zoom]); - - const renderCheckpoint = (id: string) => { - const [selectPath, setSelectPath] = useState(''); - const key = id + selectPath; - const [itemChildren, setItemChildren] = useState({[key]: [] as TabsProps['items']}); - const checkpointArray = ((checkPoints.history?? []) as any[]).filter(x => x.status === "COMPLETED").map(x => { - return {checkpointType: x.checkpoint_type, path: x.external_path, id: x.id} - }); - useEffect(() => { - if (selectPath && id) { - if (!itemChildren[key]) { - getData(API_CONSTANTS.READ_CHECKPOINT, {path: selectPath, operatorId: id}).then(res => { - const genData = Object.keys(res.datas).map(x => { - const datum = res.datas[x]; - return { - key: x, - label: x, - children: - { - return { - key: y, - label: y, - children: { - return { - title: z, - dataIndex: z, - key: z, - render: (text) => {text}, - } - })}/> - } - }) - } tabBarStyle={{marginBlock: 0}} tabBarGutter={10}/> - } - }) - setItemChildren({...itemChildren, [key]: genData}) - }) - } + if (selectPath && id) { + if (!itemChildren[key]) { + getData(API_CONSTANTS.READ_CHECKPOINT, { path: selectPath, operatorId: id }).then( + (res) => { + const genData = Object.keys(res.datas).map((x) => { + const datum = res.datas[x]; + return { + key: x, + label: x, + children: ( + { + return { + key: y, + label: y, + children: ( +
{ + return { + title: z, + dataIndex: z, + key: z, + render: (text) => ( + + {text} + + ) + }; + })} + /> + ) + }; + })} + tabBarStyle={{ marginBlock: 0 }} + tabBarGutter={10} + /> + ) + }; + }); + setItemChildren({ ...itemChildren, [key]: genData }); } - }, [selectPath, id]) - - return <> - { + return { label: x.id, value: x.path }; + })} + onChange={(path) => { + setSelectPath(path); + }} + /> + + + ); + }; + return ( + +
+ +
+
+ + {onlyPlan ? ( + <> + ) : ( + {currentSelect?.getData().description}

+ }, + { + key: '2', + label: 'CheckPointRead', + children: renderCheckpoint(currentSelect?.id) + } + ]} + tabBarGutter={10} + /> + )} +
+ + ); }; export default FlinkDag; diff --git a/dinky-web/src/pages/DataStudio/HeaderContainer/index.tsx b/dinky-web/src/pages/DataStudio/HeaderContainer/index.tsx index c99788b8366..6b3f2c2a685 100644 --- a/dinky-web/src/pages/DataStudio/HeaderContainer/index.tsx +++ b/dinky-web/src/pages/DataStudio/HeaderContainer/index.tsx @@ -44,13 +44,14 @@ import { SettingConfigKeyEnum } from '@/pages/SettingCenter/GlobalSetting/Settin import { handlePutDataJson } from '@/services/BusinessCrud'; import { BaseConfigProperties } from '@/types/SettingCenter/data'; import { l } from '@/utils/intl'; -import {connect, history} from '@@/exports'; +import { connect, history } from '@@/exports'; import { EnvironmentOutlined, FlagTwoTone, MoreOutlined, PauseCircleTwoTone, - PlayCircleTwoTone, RotateRightOutlined, + PlayCircleTwoTone, + RotateRightOutlined, SafetyCertificateTwoTone, SaveTwoTone, SendOutlined, @@ -260,9 +261,9 @@ const HeaderContainer = (props: any) => { // flink jobdetail跳转 icon: , title: l('pages.datastudio.to.jobDetail'), - click: ()=>history.push(`/devops/job-detail?id=${getCurrentData(panes, activeKey)?.id}`), + click: () => history.push(`/devops/job-detail?id=${getCurrentData(panes, activeKey)?.id}`), isShow: (type?: TabsPageType, subType?: string, data?: any) => - type === TabsPageType.project && data?.jobInstanceId && subType==="flinksql" + type === TabsPageType.project && data?.jobInstanceId && subType === 'flinksql' }, // { // // 异步提交按钮 @@ -329,13 +330,13 @@ const HeaderContainer = (props: any) => { }; const renderHotkey = () => { document.onkeydown = (e) => { - if (getCurrentTab(panes, activeKey)){ + if (getCurrentTab(panes, activeKey)) { routes - .filter((r) => r.hotKey?.(e)) - .forEach((r) => { - r.click(); - e.preventDefault(); - }); + .filter((r) => r.hotKey?.(e)) + .forEach((r) => { + r.click(); + e.preventDefault(); + }); } }; }; diff --git a/dinky-web/src/pages/DataStudio/LeftContainer/Project/JobTree/index.tsx b/dinky-web/src/pages/DataStudio/LeftContainer/Project/JobTree/index.tsx index f2f2a308b16..4d967af0c37 100644 --- a/dinky-web/src/pages/DataStudio/LeftContainer/Project/JobTree/index.tsx +++ b/dinky-web/src/pages/DataStudio/LeftContainer/Project/JobTree/index.tsx @@ -17,13 +17,14 @@ * */ +import { getCurrentTab } from '@/pages/DataStudio/function'; import { buildProjectTree, generateList, getLeafKeyList, getParentKey } from '@/pages/DataStudio/LeftContainer/Project/function'; -import {StateType, TabsItemType} from '@/pages/DataStudio/model'; +import { StateType, TabsItemType } from '@/pages/DataStudio/model'; import { BtnRoute } from '@/pages/DataStudio/route'; import { l } from '@/utils/intl'; import { connect } from '@@/exports'; @@ -31,7 +32,6 @@ import { Key } from '@ant-design/pro-components'; import { Empty, Tree } from 'antd'; import Search from 'antd/es/input/Search'; import React, { useEffect, useState } from 'react'; -import {getCurrentData, getCurrentTab} from "@/pages/DataStudio/function"; const { DirectoryTree } = Tree; @@ -46,8 +46,7 @@ type TreeProps = { }; const JobTree: React.FC = (props) => { - - const { projectData, onNodeClick, style, height, onRightClick} = props; + const { projectData, onNodeClick, style, height, onRightClick } = props; const [searchValue, setSearchValueValue] = useState(''); const [data, setData] = useState(buildProjectTree(projectData, searchValue)); @@ -89,25 +88,24 @@ const JobTree: React.FC = (props) => { setExpandedKeys(getLeafKeyList(projectData)); }; - const btn = BtnRoute['menu.datastudio.project']; - const positionKey = (panes:TabsItemType[],activeKey:string) => { - const treeKey = getCurrentTab(panes,activeKey)?.treeKey; - if (treeKey){ + const positionKey = (panes: TabsItemType[], activeKey: string) => { + const treeKey = getCurrentTab(panes, activeKey)?.treeKey; + if (treeKey) { const expandList: any[] = generateList(data, []); let expandedKeys: any = expandList - .map((item: any) => { - if (item?.key==treeKey) { - return getParentKey(item.key, data); - } - return null; - }) - .filter((item: any, i: number, self: any) => item && self.indexOf(item) === i); + .map((item: any) => { + if (item?.key == treeKey) { + return getParentKey(item.key, data); + } + return null; + }) + .filter((item: any, i: number, self: any) => item && self.indexOf(item) === i); setExpandedKeys(expandedKeys); setAutoExpandParent(true); - setSelectedKeys([treeKey]) + setSelectedKeys([treeKey]); } - } + }; btn[1].onClick = expandAll; @@ -147,5 +145,5 @@ const JobTree: React.FC = (props) => { export default connect(({ Studio }: { Studio: StateType }) => ({ height: Studio.toolContentHeight, - projectData: Studio.project.data, + projectData: Studio.project.data }))(JobTree); diff --git a/dinky-web/src/pages/DataStudio/LeftContainer/Project/index.tsx b/dinky-web/src/pages/DataStudio/LeftContainer/Project/index.tsx index c1d906645fa..9a820b86e41 100644 --- a/dinky-web/src/pages/DataStudio/LeftContainer/Project/index.tsx +++ b/dinky-web/src/pages/DataStudio/LeftContainer/Project/index.tsx @@ -42,7 +42,6 @@ import { Modal, Typography } from 'antd'; import { MenuInfo } from 'rc-menu/es/interface'; import React, { useEffect, useState } from 'react'; import { connect } from 'umi'; -import {BtnRoute} from "@/pages/DataStudio/route"; const { Text } = Typography; diff --git a/dinky-web/src/pages/DataStudio/LeftContainer/index.tsx b/dinky-web/src/pages/DataStudio/LeftContainer/index.tsx index 141af7cbfd3..7db42c332ee 100644 --- a/dinky-web/src/pages/DataStudio/LeftContainer/index.tsx +++ b/dinky-web/src/pages/DataStudio/LeftContainer/index.tsx @@ -17,7 +17,7 @@ * */ -import {CircleBtn, CircleButtonProps, CircleDataStudioButtonProps} from '@/components/CallBackButton/CircleBtn'; +import { CircleBtn, CircleDataStudioButtonProps } from '@/components/CallBackButton/CircleBtn'; import MovableSidebar, { MovableSidebarProps } from '@/components/Sidebar/MovableSidebar'; import useThemeValue from '@/hooks/useThemeValue'; import ProjectTitle from '@/pages/DataStudio/LeftContainer/Project/ProjectTitle'; @@ -31,7 +31,14 @@ export type LeftContainerProps = { size: number; }; const LeftContainer: React.FC = (props: any) => { - const { dispatch, size, toolContentHeight, leftContainer, rightContainer , tabs: { panes, activeKey }} = props; + const { + dispatch, + size, + toolContentHeight, + leftContainer, + rightContainer, + tabs: { panes, activeKey } + } = props; const themeValue = useThemeValue(); const MAX_WIDTH = size.width - 2 * VIEW.leftToolWidth - rightContainer.width - 700; @@ -81,7 +88,12 @@ const LeftContainer: React.FC = (props: any) => { enable: { right: true }, btnGroup: BtnRoute[leftContainer.selectKey] ? BtnRoute[leftContainer.selectKey].map((item: CircleDataStudioButtonProps) => ( - item.onClick?.(panes,activeKey)} key={item.title} /> + item.onClick?.(panes, activeKey)} + key={item.title} + /> )) : [], style: { borderInlineEnd: `1px solid ${themeValue.borderColor}` } diff --git a/dinky-web/src/pages/DataStudio/route.tsx b/dinky-web/src/pages/DataStudio/route.tsx index 3c58231333d..76a2b5dd27d 100644 --- a/dinky-web/src/pages/DataStudio/route.tsx +++ b/dinky-web/src/pages/DataStudio/route.tsx @@ -17,7 +17,7 @@ * */ -import {CircleButtonProps, CircleDataStudioButtonProps} from '@/components/CallBackButton/CircleBtn'; +import { CircleDataStudioButtonProps } from '@/components/CallBackButton/CircleBtn'; import Console from '@/pages/DataStudio/BottomContainer/Console'; import Result from '@/pages/DataStudio/BottomContainer/Result'; import TableData from '@/pages/DataStudio/BottomContainer/TableData'; @@ -37,9 +37,10 @@ import { CalendarOutlined, ConsoleSqlOutlined, DatabaseOutlined, - DesktopOutlined, EnvironmentOutlined, + DesktopOutlined, + EnvironmentOutlined, FolderOutlined, - HistoryOutlined, HolderOutlined, + HistoryOutlined, InfoCircleOutlined, MonitorOutlined, PlayCircleOutlined, @@ -270,7 +271,7 @@ export const BtnRoute: { [c: string]: CircleDataStudioButtonProps[] } = { }, { icon: , - title:l('button.position'), + title: l('button.position'), key: 'button.position', onClick: () => {} } diff --git a/dinky-web/src/pages/DevOps/JobDetail/JobOverview/JobOverview.tsx b/dinky-web/src/pages/DevOps/JobDetail/JobOverview/JobOverview.tsx index 420fb205fd0..8f1370479ce 100644 --- a/dinky-web/src/pages/DevOps/JobDetail/JobOverview/JobOverview.tsx +++ b/dinky-web/src/pages/DevOps/JobDetail/JobOverview/JobOverview.tsx @@ -36,7 +36,11 @@ const JobConfigTab = (props: JobProps) => { height: '40vh' }} > - {job ? : } + {job ? ( + + ) : ( + + )} diff --git a/dinky-web/src/pages/Metrics/Job/index.tsx b/dinky-web/src/pages/Metrics/Job/index.tsx index f8ba26019ea..868fae0f53f 100644 --- a/dinky-web/src/pages/Metrics/Job/index.tsx +++ b/dinky-web/src/pages/Metrics/Job/index.tsx @@ -17,290 +17,290 @@ * */ -import {ChartData, JobMetrics, MetricsLayout, SubTask, Task} from '@/pages/Metrics/Job/data'; +import { ChartData, JobMetrics, MetricsLayout, SubTask, Task } from '@/pages/Metrics/Job/data'; import { - buildMetricsList, - buildRunningJobList, - buildSubTaskList + buildMetricsList, + buildRunningJobList, + buildSubTaskList } from '@/pages/Metrics/Job/function'; -import {getFlinkRunTask, saveFlinkMetrics} from '@/pages/Metrics/Job/service'; -import {getData} from '@/services/api'; -import {API_CONSTANTS} from '@/services/endpoints'; -import {l} from '@/utils/intl'; -import {ProCard, ProFormSelect} from '@ant-design/pro-components'; -import {Button, Input, Row} from 'antd'; -import {useEffect, useState} from 'react'; +import { getFlinkRunTask, saveFlinkMetrics } from '@/pages/Metrics/Job/service'; +import { getData } from '@/services/api'; +import { API_CONSTANTS } from '@/services/endpoints'; +import { l } from '@/utils/intl'; +import { ProCard, ProFormSelect } from '@ant-design/pro-components'; +import { Button, Input, Row } from 'antd'; +import { useEffect, useState } from 'react'; import FlinkChart from '../../../components/FlinkChart'; const getJobMetrics = async (job: JobMetrics) => { - const url = - API_CONSTANTS.FLINK_PROXY + - '/' + - job.url + - '/jobs/' + - job.flinkJobId + - '/vertices/' + - job.subTaskId + - '/metrics' + - '?get=' + - encodeURIComponent(job.metrics); - const json = await getData(url); - json[0].time = new Date(); - return json[0] as ChartData; + const url = + API_CONSTANTS.FLINK_PROXY + + '/' + + job.url + + '/jobs/' + + job.flinkJobId + + '/vertices/' + + job.subTaskId + + '/metrics' + + '?get=' + + encodeURIComponent(job.metrics); + const json = await getData(url); + json[0].time = new Date(); + return json[0] as ChartData; }; const Job = () => { - const [metricsData, setMetricsData] = useState({ - url: '', - jid: '', - flinkName: '', - selectTaskId: 0, - selectSubTask: '', - selectMetrics: [] as string[] - }); + const [metricsData, setMetricsData] = useState({ + url: '', + jid: '', + flinkName: '', + selectTaskId: 0, + selectSubTask: '', + selectMetrics: [] as string[] + }); - const [subTaskList, setSubTaskList] = useState([]); - const [metrics, setMetrics] = useState([]); - const [taskData, setTaskData] = useState([]); - const [jobMetricsList, setJobMetricsList] = useState([]); - const [chartData, setChartData] = useState>({}); - const [layoutName, setLayoutName] = useState(''); - const [timers, setTimers] = useState>({}); + const [subTaskList, setSubTaskList] = useState([]); + const [metrics, setMetrics] = useState([]); + const [taskData, setTaskData] = useState([]); + const [jobMetricsList, setJobMetricsList] = useState([]); + const [chartData, setChartData] = useState>({}); + const [layoutName, setLayoutName] = useState(''); + const [timers, setTimers] = useState>({}); - useEffect(() => { - getFlinkRunTask().then((res) => { - setTaskData(res.data); - }); - }, []); + useEffect(() => { + getFlinkRunTask().then((res) => { + setTaskData(res.data); + }); + }, []); - useEffect(() => { - Object.keys(timers) - .filter((x) => !jobMetricsList.map((x) => x.metrics).includes(x)) - // @ts-ignore - .forEach((x) => clearInterval(timers[x])); - }, [jobMetricsList]); + useEffect(() => { + Object.keys(timers) + .filter((x) => !jobMetricsList.map((x) => x.metrics).includes(x)) + // @ts-ignore + .forEach((x) => clearInterval(timers[x])); + }, [jobMetricsList]); - /** - * query flink job detail - * @param {number} id - * @returns {Promise} - */ - const getFlinkTaskDetail = async (id: number) => { - return await getData(API_CONSTANTS.REFRESH_JOB_DETAIL, {id: id}); - }; + /** + * query flink job detail + * @param {number} id + * @returns {Promise} + */ + const getFlinkTaskDetail = async (id: number) => { + return await getData(API_CONSTANTS.REFRESH_JOB_DETAIL, { id: id }); + }; - /** - * query flink job sub task - * @param {string} url - * @param {string} jid - * @returns {Promise<[]>} - */ - const getFlinkJobSubTask = async (url: string, jid: string) => { - const flinkJobVertices = await getData(API_CONSTANTS.FLINK_PROXY + '/' + url + '/jobs/' + jid); - return flinkJobVertices.vertices as SubTask[]; - }; + /** + * query flink job sub task + * @param {string} url + * @param {string} jid + * @returns {Promise<[]>} + */ + const getFlinkJobSubTask = async (url: string, jid: string) => { + const flinkJobVertices = await getData(API_CONSTANTS.FLINK_PROXY + '/' + url + '/jobs/' + jid); + return flinkJobVertices.vertices as SubTask[]; + }; - /** - * query flink job metrics list - * @param {string} url - * @param {string} jid - * @param subTask - * @returns {Promise} - */ - const getFlinkJobMetrics = async (url: string, jid: string, subTask: string) => { - const flinkJobMetrics = await getData( - API_CONSTANTS.FLINK_PROXY + '/' + url + '/jobs/' + jid + '/vertices/' + subTask + '/metrics' - ); - return (flinkJobMetrics as any[]).map((x) => x.id as string); - }; + /** + * query flink job metrics list + * @param {string} url + * @param {string} jid + * @param subTask + * @returns {Promise} + */ + const getFlinkJobMetrics = async (url: string, jid: string, subTask: string) => { + const flinkJobMetrics = await getData( + API_CONSTANTS.FLINK_PROXY + '/' + url + '/jobs/' + jid + '/vertices/' + subTask + '/metrics' + ); + return (flinkJobMetrics as any[]).map((x) => x.id as string); + }; - /** - * 1 level , change running job - * @returns {Promise} - * @param taskId - */ - const handleRunningJobChange = async (taskId: number) => { - // query data of flink running job - const taskDetail = await getFlinkTaskDetail(taskId); - // 解构出 flink job url , job name , job id - const { - cluster: {hosts: url}, - instance: {name: flinkJobName, jid: flinkJobId} - } = taskDetail.datas; - setMetricsData((prevState) => ({ - ...prevState, - url: url, - flinkName: flinkJobName, - jid: flinkJobId, - selectTaskId: taskId - })); - const subTasks = await getFlinkJobSubTask(url, flinkJobId); - setSubTaskList(subTasks); - }; + /** + * 1 level , change running job + * @returns {Promise} + * @param taskId + */ + const handleRunningJobChange = async (taskId: number) => { + // query data of flink running job + const taskDetail = await getFlinkTaskDetail(taskId); + // 解构出 flink job url , job name , job id + const { + cluster: { hosts: url }, + instance: { name: flinkJobName, jid: flinkJobId } + } = taskDetail.datas; + setMetricsData((prevState) => ({ + ...prevState, + url: url, + flinkName: flinkJobName, + jid: flinkJobId, + selectTaskId: taskId + })); + const subTasks = await getFlinkJobSubTask(url, flinkJobId); + setSubTaskList(subTasks); + }; - /** - * 2 level , change subtask - * @returns {Promise} - * @param subTaskName - */ - const handleSubTaskChange = async (subTaskName: string) => { - setMetricsData((prevState) => ({ - ...prevState, - selectSubTask: subTaskName - })); - const jobMetricsDataList = await getFlinkJobMetrics( - metricsData.url, - metricsData.jid, - subTaskName - ); - setMetrics(jobMetricsDataList.sort()); - }; + /** + * 2 level , change subtask + * @returns {Promise} + * @param subTaskName + */ + const handleSubTaskChange = async (subTaskName: string) => { + setMetricsData((prevState) => ({ + ...prevState, + selectSubTask: subTaskName + })); + const jobMetricsDataList = await getFlinkJobMetrics( + metricsData.url, + metricsData.jid, + subTaskName + ); + setMetrics(jobMetricsDataList.sort()); + }; - /** - * 3 level , change metrics list - * @returns {Promise} - * @param selectList - */ - const handleMetricsChange = async (selectList: string[]) => { - setMetricsData((prevState) => ({ - ...prevState, - selectMetrics: selectList - })); + /** + * 3 level , change metrics list + * @returns {Promise} + * @param selectList + */ + const handleMetricsChange = async (selectList: string[]) => { + setMetricsData((prevState) => ({ + ...prevState, + selectMetrics: selectList + })); - const d: JobMetrics[] = selectList.map((item) => { - return { - taskId: metricsData.selectTaskId, - url: metricsData.url, - flinkJobId: metricsData.jid, - jobName: metricsData.flinkName, - subTaskId: metricsData.selectSubTask, - metrics: item, - layoutName: layoutName, - title: item, - showSize: '25%', - showType: 'Chart' - }; - }); - d.forEach((j) => { - const data: ChartData[] = []; - chartData[j.taskId + j.subTaskId + j.metrics] = data; - setChartData(chartData); - timers[j.metrics] = setInterval(() => { - getJobMetrics(j).then((res) => { - data.push(res); - }); - }, 1000); - setTimers(timers); + const d: JobMetrics[] = selectList.map((item) => { + return { + taskId: metricsData.selectTaskId, + url: metricsData.url, + flinkJobId: metricsData.jid, + jobName: metricsData.flinkName, + subTaskId: metricsData.selectSubTask, + metrics: item, + layoutName: layoutName, + title: item, + showSize: '25%', + showType: 'Chart' + }; + }); + d.forEach((j) => { + const data: ChartData[] = []; + chartData[j.taskId + j.subTaskId + j.metrics] = data; + setChartData(chartData); + timers[j.metrics] = setInterval(() => { + getJobMetrics(j).then((res) => { + data.push(res); }); - setJobMetricsList(d); - }; - /** - * render metrics card list - * @param {JobMetrics[]} metricsList - * @returns {JSX.Element} - */ - const renderMetricsCardList = (metricsList: JobMetrics[]) => { - return ( - <> - - {metricsList.map((j) => { - return ( - { - j.showSize = chartSize; - j.showType = chartType; - }} - data={chartData[j.taskId + j.subTaskId + j.metrics]} - title={j.metrics} - extraType={'size'} - /> - ); - })} - - - ); - }; - + }, 1000); + setTimers(timers); + }); + setJobMetricsList(d); + }; + /** + * render metrics card list + * @param {JobMetrics[]} metricsList + * @returns {JSX.Element} + */ + const renderMetricsCardList = (metricsList: JobMetrics[]) => { return ( - <> - setLayoutName(e.target.value)} - style={{width: '100vh'}} - /> - } - extra={ - - } - > - handleRunningJobChange(value as number)}} - /> - {metricsData.selectTaskId !== 0 && ( - handleSubTaskChange(value as string)}} - /> - )} - {metricsData.selectSubTask !== '' && ( - handleMetricsChange(value as string[])}} - /> - )} - {/* render metrics list */} - {jobMetricsList.length > 0 && renderMetricsCardList(jobMetricsList)} - - + <> + + {metricsList.map((j) => { + return ( + { + j.showSize = chartSize; + j.showType = chartType; + }} + data={chartData[j.taskId + j.subTaskId + j.metrics]} + title={j.metrics} + extraType={'size'} + /> + ); + })} + + ); + }; + + return ( + <> + setLayoutName(e.target.value)} + style={{ width: '100vh' }} + /> + } + extra={ + + } + > + handleRunningJobChange(value as number) }} + /> + {metricsData.selectTaskId !== 0 && ( + handleSubTaskChange(value as string) }} + /> + )} + {metricsData.selectSubTask !== '' && ( + handleMetricsChange(value as string[]) }} + /> + )} + {/* render metrics list */} + {jobMetricsList.length > 0 && renderMetricsCardList(jobMetricsList)} + + + ); }; export default Job;