Unverified Commit 90a82dd0 authored by aiwenmo's avatar aiwenmo Committed by GitHub

[Feature-1027][admin,web] Add data development task information log details button (#1029)

Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>
parent 53b55dbe
......@@ -204,7 +204,7 @@
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<finalName>${project.artifactId}-${project.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
......
......@@ -25,7 +25,7 @@
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/dlink-admin/target/dlink-admin/lib</directory>
<directory>${project.parent.basedir}/dlink-admin/target/dlink-admin-${project.version}/lib</directory>
<outputDirectory>lib</outputDirectory>
<includes>
<include>*.jar</include>
......
......@@ -19,12 +19,11 @@
import MonacoEditor from "react-monaco-editor";
import * as _monaco from "monaco-editor";
export type CodeShowFormProps = {
height?: string;
width?: string;
language: string;
language?: string;
theme?: string;
options?: any;
code: string;
......@@ -40,8 +39,8 @@ const CodeShow = (props: CodeShowFormProps) => {
options = {
selectOnLineNumbers: true,
renderSideBySide: false,
autoIndent:'None',
readOnly:true ,
autoIndent: 'None',
readOnly: true,
},
code,
} = props;
......
......@@ -26,18 +26,15 @@ import ProList from '@ant-design/pro-list';
import {handleRemove, queryData} from "@/components/Common/crud";
import ProDescriptions from '@ant-design/pro-descriptions';
import React, {useState} from "react";
import {ModalForm,} from '@ant-design/pro-form';
import styles from "./index.less";
import {Scrollbars} from 'react-custom-scrollbars';
import StudioPreview from "../StudioPreview";
import {getJobData} from "@/pages/DataStudio/service";
import {HistoryItem} from "@/components/Studio/StudioConsole/StudioHistory/data";
import CodeShow from "@/components/Common/CodeShow";
const { Title, Paragraph, Text, Link } = Typography;
const {Title, Paragraph, Text, Link} = Typography;
type HistoryConfig={
type HistoryConfig = {
useSession: boolean;
session: string;
useRemote: boolean;
......@@ -62,41 +59,44 @@ type HistoryConfig={
const url = '/api/history';
const StudioHistory = (props: any) => {
const {current,refs,dispatch} = props;
const {current, refs, dispatch} = props;
const [modalVisit, setModalVisit] = useState(false);
const [row, setRow] = useState<HistoryItem>();
const [config,setConfig] = useState<HistoryConfig>();
const [type,setType] = useState<number>();
const [result,setResult] = useState<{}>();
const [config, setConfig] = useState<HistoryConfig>();
const [type, setType] = useState<number>();
const [result, setResult] = useState<{}>();
const showDetail=(row:HistoryItem,type:number)=>{
const showDetail = (row: HistoryItem, type: number) => {
setRow(row);
setModalVisit(true);
setType(type);
setConfig(JSON.parse(row.configJson));
if(type===3){
if (type === 3) {
// showJobData(row.jobId,dispatch)
const res = getJobData(row.jobId);
res.then((resd)=>{
res.then((resd) => {
setResult(resd.datas);
});
}
};
const removeHistory=(row:HistoryItem)=>{
const removeHistory = (row: HistoryItem) => {
Modal.confirm({
title: '删除执行记录',
content: '确定删除该执行记录吗?',
okText: '确认',
cancelText: '取消',
onOk:async () => {
await handleRemove(url,[row]);
// refs.current?.reloadAndRest?.();
onOk: async () => {
await handleRemove(url, [row]);
refs.history?.current?.reload();
}
});
};
const handleCancel = () => {
setModalVisit(false);
};
return (
<>
<ProList<HistoryItem>
......@@ -111,7 +111,7 @@ const StudioHistory = (props: any) => {
}}
rowKey="id"
headerTitle="执行历史"
request={(params, sorter, filter) => queryData(url,{...params, sorter:{id:'descend'}, filter})}
request={(params, sorter, filter) => queryData(url, {...params, sorter: {id: 'descend'}, filter})}
pagination={{
pageSize: 5,
}}
......@@ -124,7 +124,7 @@ const StudioHistory = (props: any) => {
return (
<Space size={0}>
<Tag color="blue" key={row.jobId}>
<FireOutlined /> {row.jobId}
<FireOutlined/> {row.jobId}
</Tag>
</Space>
);
......@@ -132,7 +132,7 @@ const StudioHistory = (props: any) => {
},
description: {
search: false,
render:(_, row)=>{
render: (_, row) => {
return (<Paragraph>
<blockquote>
<Link href={`http://${row.jobManagerAddress}`} target="_blank">
......@@ -148,37 +148,37 @@ const StudioHistory = (props: any) => {
render: (_, row) => {
return (
<Space size={0}>
{row.jobName?(
{row.jobName ? (
<Tag color="gray" key={row.jobName}>
{row.jobName}
</Tag>
):''}
{row.session?(
) : ''}
{row.session ? (
<Tag color="orange" key={row.session}>
<MessageOutlined /> {row.session}
<MessageOutlined/> {row.session}
</Tag>
):''}
{row.clusterAlias?(
) : ''}
{row.clusterAlias ? (
<Tag color="green" key={row.clusterAlias}>
<ClusterOutlined /> {row.clusterAlias}
<ClusterOutlined/> {row.clusterAlias}
</Tag>
):(<Tag color="green" key={row.clusterAlias}>
<ClusterOutlined /> 本地环境
) : (<Tag color="green" key={row.clusterAlias}>
<ClusterOutlined/> 本地环境
</Tag>)}
{row.type?(
{row.type ? (
<Tag color="blue" key={row.type}>
<RocketOutlined /> {row.type}
<RocketOutlined/> {row.type}
</Tag>
):''}
{(row.status==2) ?
(<><Badge status="success"/><Text type="success">SUCCESS</Text></>):
(row.status==1) ?
) : ''}
{(row.status == 2) ?
(<><Badge status="success"/><Text type="success">SUCCESS</Text></>) :
(row.status == 1) ?
<><Badge status="success"/><Text type="secondary">RUNNING</Text></> :
(row.status==3) ?
(row.status == 3) ?
<><Badge status="error"/><Text type="danger">FAILED</Text></> :
(row.status==4) ?
(row.status == 4) ?
<><Badge status="error"/><Text type="warning">CANCEL</Text></> :
(row.status==0) ?
(row.status == 0) ?
<><Badge status="error"/><Text type="warning">INITIALIZE</Text></> :
<><Badge status="success"/><Text type="danger">UNKNOWEN</Text></>}
</Space>
......@@ -188,19 +188,29 @@ const StudioHistory = (props: any) => {
},
actions: {
render: (text, row) => [
<a key="config" onClick={()=>{showDetail(row,1)}}>
<a key="config" onClick={() => {
showDetail(row, 1)
}}>
执行配置
</a>,
<a key="statement" onClick={()=>{showDetail(row,2)}}>
<a key="statement" onClick={() => {
showDetail(row, 2)
}}>
FlinkSql语句
</a>,
<a key="result" onClick={()=>{showDetail(row,3)}}>
<a key="result" onClick={() => {
showDetail(row, 3)
}}>
预览数据
</a>,
<a key="error" onClick={()=>{showDetail(row,4)}}>
<a key="error" onClick={() => {
showDetail(row, 4)
}}>
异常信息
</a>,
<a key="delete" onClick={()=>{removeHistory(row)}}>
<a key="delete" onClick={() => {
removeHistory(row)
}}>
删除
</a>,
],
......@@ -259,40 +269,35 @@ const StudioHistory = (props: any) => {
}}
options={{
search: false,
setting:false
setting: false
}}
/>
<ModalForm
<Modal
width={'80%'}
visible={modalVisit}
onFinish={async () => {
}}
onVisibleChange={setModalVisit}
submitter={{
submitButtonProps: {
style: {
display: 'none',
},
},
}}
destroyOnClose
centered
footer={false}
onCancel={handleCancel}
>
{type==1 && (
{type == 1 && (
<ProDescriptions
column={2}
title='执行配置'
>
<ProDescriptions.Item span={2} label="JobId" >
<ProDescriptions.Item span={2} label="JobId">
<Tag color="blue" key={row.jobId}>
<FireOutlined /> {row.jobId}
<FireOutlined/> {row.jobId}
</Tag>
</ProDescriptions.Item>
<ProDescriptions.Item label="共享会话" >
{config.useSession?'启用':'禁用'}
<ProDescriptions.Item label="共享会话">
{config.useSession ? '启用' : '禁用'}
</ProDescriptions.Item>
<ProDescriptions.Item label="会话 Key">
{config.session}
</ProDescriptions.Item>
<ProDescriptions.Item label="执行方式" >
{config.useRemote?'远程':'本地'}
<ProDescriptions.Item label="执行方式">
{config.useRemote ? '远程' : '本地'}
</ProDescriptions.Item>
<ProDescriptions.Item label="任务类型">
{config.type}
......@@ -303,17 +308,17 @@ const StudioHistory = (props: any) => {
<ProDescriptions.Item label="集群配置ID">
{config.clusterConfigurationId}
</ProDescriptions.Item>
<ProDescriptions.Item label="预览结果" >
{config.useResult?'启用':'禁用'}
<ProDescriptions.Item label="预览结果">
{config.useResult ? '启用' : '禁用'}
</ProDescriptions.Item>
<ProDescriptions.Item label="打印流" >
{config.useChangeLog?'启用':'禁用'}
<ProDescriptions.Item label="打印流">
{config.useChangeLog ? '启用' : '禁用'}
</ProDescriptions.Item>
<ProDescriptions.Item label="最大行数">
{config.maxRowNum}
</ProDescriptions.Item>
<ProDescriptions.Item label="自动停止" >
{config.useAutoCancel?'启用':'禁用'}
<ProDescriptions.Item label="自动停止">
{config.useAutoCancel ? '启用' : '禁用'}
</ProDescriptions.Item>
<ProDescriptions.Item span={2} label="JobManagerAddress">
{row.jobManagerAddress}
......@@ -325,10 +330,10 @@ const StudioHistory = (props: any) => {
{config.jobName}
</ProDescriptions.Item>
<ProDescriptions.Item label="片段机制">
{config.useSqlFragment?'启用':'禁用'}
{config.useSqlFragment ? '启用' : '禁用'}
</ProDescriptions.Item>
<ProDescriptions.Item label="语句集">
{config.useStatementSet?'启用':'禁用'}
{config.useStatementSet ? '启用' : '禁用'}
</ProDescriptions.Item>
<ProDescriptions.Item label="并行度">
{config.parallelism}
......@@ -344,59 +349,57 @@ const StudioHistory = (props: any) => {
</ProDescriptions.Item>
</ProDescriptions>
)}
{type==2 && (
{type == 2 && (
<ProDescriptions
column={1}
title='FlinkSql 语句'
>
<ProDescriptions.Item label="JobId" >
<ProDescriptions.Item label="JobId">
<Tag color="blue" key={row.jobId}>
<FireOutlined /> {row.jobId}
<FireOutlined/> {row.jobId}
</Tag>
</ProDescriptions.Item>
<ProDescriptions.Item>
<CodeShow width={"100%"} height={"500px"} language={"sql"} code={row.statement} theme={"vs-dark"}/>
<CodeShow height={"80vh"} language={"sql"} code={row.statement} theme={"vs-dark"}/>
</ProDescriptions.Item>
</ProDescriptions>
)}
{type==3 && (
{type == 3 && (
<ProDescriptions
column={2}
title='数据预览'
>
<ProDescriptions.Item span={2} label="JobId" >
<ProDescriptions.Item span={2} label="JobId">
<Tag color="blue" key={row.jobId}>
<FireOutlined /> {row.jobId}
<FireOutlined/> {row.jobId}
</Tag>
</ProDescriptions.Item>
<ProDescriptions.Item span={2} >
<ProDescriptions.Item span={2}>
<StudioPreview result={result} style={{width: '100%'}}/>
</ProDescriptions.Item>
</ProDescriptions>
)}
{type==4 && (
{type == 4 && (
<ProDescriptions
column={1}
title='异常信息'
>
<ProDescriptions.Item label="JobId" >
<ProDescriptions.Item label="JobId">
<Tag color="blue" key={row.jobId}>
<FireOutlined /> {row.jobId}
<FireOutlined/> {row.jobId}
</Tag>
</ProDescriptions.Item>
<ProDescriptions.Item>
<Scrollbars style={{height: '400px',width:'100%'}}>
<pre className={styles.code}>{row.error}</pre>
</Scrollbars>
<CodeShow height={"80vh"} language={"java"} code={row.error} theme={"vs-dark"}/>
</ProDescriptions.Item>
</ProDescriptions>
)}
</ModalForm>
</Modal>
</>
);
};
export default connect(({Studio}: {Studio: StateType}) => ({
export default connect(({Studio}: { Studio: StateType }) => ({
current: Studio.current,
refs: Studio.refs,
}))(StudioHistory);
......@@ -18,23 +18,39 @@
*/
import {Typography, Divider, Badge, Empty,Tag} from "antd";
import {Badge, Button, Divider, Empty, Modal, Tag, Typography} from "antd";
import {StateType} from "@/pages/DataStudio/model";
import {connect} from "umi";
import {FireOutlined, ScheduleOutlined} from '@ant-design/icons';
import StudioSqlConfig from "@/components/Studio/StudioRightTool/StudioSqlConfig";
import {DIALECT, isSql} from "@/components/Studio/conf";
import {FireOutlined, ZoomInOutlined} from '@ant-design/icons';
import {isSql} from "@/components/Studio/conf";
import {useState} from "react";
import CodeShow from "@/components/Common/CodeShow";
const { Title, Paragraph, Text, Link } = Typography;
const {Title, Paragraph, Text, Link} = Typography;
const StudioMsg = (props:any) => {
const StudioMsg = (props: any) => {
const {current} = props;
const [sqlModalVisit, setSqlModalVisit] = useState(false);
const [errorModalVisit, setErrorModalVisit] = useState(false);
const handleOpenSqlModal = () => {
setSqlModalVisit(true);
};
const handleOpenErrorModal = () => {
setErrorModalVisit(true);
};
const handleCancel = () => {
setSqlModalVisit(false);
setErrorModalVisit(false);
};
const renderCommonSqlContent = () => {
return (<>
<Paragraph>
<blockquote> <Divider type="vertical"/>{current.console.result.startTime}
<blockquote><Divider type="vertical"/>{current.console.result.startTime}
<Divider type="vertical"/>{current.console.result.endTime}
<Divider type="vertical"/>
{!(current.console.result.success) ? <><Badge status="error"/><Text type="danger">Error</Text></> :
......@@ -55,17 +71,34 @@ const StudioMsg = (props:any) => {
</Link> <Divider type="vertical"/>{current.console.result.startTime}
<Divider type="vertical"/>{current.console.result.endTime}
<Divider type="vertical"/>
{!(current.console.result.status==='SUCCESS') ? <><Badge status="error"/><Text type="danger">Error</Text></> :
{!(current.console.result.status === 'SUCCESS') ? <><Badge status="error"/><Text
type="danger">Error</Text></> :
<><Badge status="success"/><Text type="success">Success</Text></>}
<Divider type="vertical"/>
{current.console.result.jobConfig?.jobName&&<Text code>{current.console.result.jobConfig?.jobName}</Text>}
{current.console.result.jobId&&
{current.console.result.jobConfig?.jobName && <Text code>{current.console.result.jobConfig?.jobName}</Text>}
{current.console.result.jobId &&
(<>
<Divider type="vertical"/>
<Tag color="blue" key={current.console.result.jobId}>
<FireOutlined /> {current.console.result.jobId}
<FireOutlined/> {current.console.result.jobId}
</Tag>
</>)}
<Button
type="text"
icon={<ZoomInOutlined/>}
onClick={handleOpenSqlModal}
>
SQL
</Button>
{current.console.result.error ?
<Button
type="text"
icon={<ZoomInOutlined/>}
onClick={handleOpenErrorModal}
>
Error
</Button> : undefined
}
</blockquote>
{current.console.result.statement && (<pre style={{height: '100px'}}>{current.console.result.statement}</pre>)}
{current.console.result.error && (<pre style={{height: '100px'}}>{current.console.result.error}</pre>)}
......@@ -75,14 +108,38 @@ const StudioMsg = (props:any) => {
return (
<Typography>
{current?.task&&current.console.result.startTime?(isSql(current.task.dialect) ? renderCommonSqlContent():
renderFlinkSqlContent() ):<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
}
</Typography>
<>
<Typography>
{current?.task && current.console.result.startTime ? (isSql(current.task.dialect) ? renderCommonSqlContent() :
renderFlinkSqlContent()) : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE}/>
}
</Typography>
<Modal
width={'100%'}
visible={sqlModalVisit}
destroyOnClose
centered
footer={false}
onCancel={handleCancel}
>
{current.console.result.statement &&
(<CodeShow height={"80vh"} language={"sql"} code={current.console.result.statement} theme={"vs-dark"}/>)}
</Modal>
<Modal
width={'100%'}
visible={errorModalVisit}
destroyOnClose
centered
footer={false}
onCancel={handleCancel}
>
{current.console.result.error &&
(<CodeShow height={"80vh"} language={"java"} code={current.console.result.error} theme={"vs-dark"}/>)}
</Modal>
</>
);
};
export default connect(({ Studio }: { Studio: StateType }) => ({
export default connect(({Studio}: { Studio: StateType }) => ({
current: Studio.current,
}))(StudioMsg);
......@@ -1630,6 +1630,24 @@ export default (): React.ReactNode => {
<li>
<Link>优化部署文档</Link>
</li>
<li>
<Link>修复 yarn-application 任务分隔符错误</Link>
</li>
<li>
<Link>升级 Flink 1.15 版本为 1.15.2</Link>
</li>
<li>
<Link>优化 SqlServer 字段类型查询</Link>
</li>
<li>
<Link>修复重命名作业后保存作业失败</Link>
</li>
<li>
<Link>修复提交历史的第二次弹框时无内容</Link>
</li>
<li>
<Link>新增数据开发任务信息日志详情按钮</Link>
</li>
</ul>
</Paragraph>
</Timeline.Item>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment