Commit b7d9b0dc authored by wenmo's avatar wenmo

作业剪切和粘贴

parent cea2b80b
......@@ -217,4 +217,16 @@ public class CatalogueController {
return Result.failed("重命名失败");
}
}
/**
* 重命名节点和作业
*/
@PutMapping("/moveCatalogue")
public Result moveCatalogue(@RequestBody Catalogue catalogue) throws Exception {
if (catalogueService.moveCatalogue(catalogue.getId(), catalogue.getParentId())) {
return Result.succeed(true, "移动成功");
} else {
return Result.failed(false, "移动失败");
}
}
}
......@@ -25,4 +25,6 @@ public interface CatalogueService extends ISuperService<Catalogue> {
boolean toRename(Catalogue catalogue);
boolean removeCatalogueAndTaskById(Integer id);
boolean moveCatalogue(Integer id, Integer parentId);
}
......@@ -15,6 +15,9 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import static com.dlink.assertion.Asserts.isNotNull;
import static com.dlink.assertion.Asserts.isNull;
/**
* CatalogueServiceImpl
*
......@@ -29,9 +32,6 @@ public class CatalogueServiceImpl extends SuperServiceImpl<CatalogueMapper, Cata
@Autowired
private StatementService statementService;
@Autowired
private CatalogueMapper catalogueMapper;
@Override
public List<Catalogue> getAllData() {
return this.list();
......@@ -39,7 +39,7 @@ public class CatalogueServiceImpl extends SuperServiceImpl<CatalogueMapper, Cata
@Override
public Catalogue findByParentIdAndName(Integer parent_id, String name) {
return catalogueMapper.selectOne(Wrappers.<Catalogue>query().eq("parent_id", parent_id).eq("name", name));
return baseMapper.selectOne(Wrappers.<Catalogue>query().eq("parent_id", parent_id).eq("name", name));
}
@Transactional(rollbackFor = Exception.class)
......@@ -83,7 +83,7 @@ public class CatalogueServiceImpl extends SuperServiceImpl<CatalogueMapper, Cata
@Override
public boolean toRename(Catalogue catalogue) {
Catalogue oldCatalogue = this.getById(catalogue.getId());
if (oldCatalogue == null) {
if (isNull(oldCatalogue)) {
return false;
} else {
Task task = new Task();
......@@ -99,10 +99,10 @@ public class CatalogueServiceImpl extends SuperServiceImpl<CatalogueMapper, Cata
@Override
public boolean removeCatalogueAndTaskById(Integer id) {
Catalogue catalogue = this.getById(id);
if (catalogue == null) {
if (isNull(catalogue)) {
return false;
} else {
if (catalogue.getTaskId() != null) {
if (isNotNull(catalogue.getTaskId())) {
taskService.removeById(catalogue.getTaskId());
statementService.removeById(catalogue.getTaskId());
}
......@@ -110,4 +110,15 @@ public class CatalogueServiceImpl extends SuperServiceImpl<CatalogueMapper, Cata
return true;
}
}
@Override
public boolean moveCatalogue(Integer id, Integer parentId) {
Catalogue catalogue = this.getById(id);
if (isNull(catalogue)) {
return false;
} else {
catalogue.setParentId(parentId);
return updateById(catalogue);
}
}
}
import {executeDDL} from "@/pages/FlinkSqlStudio/service";
import FlinkSQL from "./FlinkSQL";
import {SessionType} from "@/pages/FlinkSqlStudio/model";
import {Modal,message} from "antd";
import {Modal, message} from "antd";
import {addOrUpdateData, getData, handleRemove} from "@/components/Common/crud";
/*--- 保存sql ---*/
export function saveTask(current:any,dispatch: any){
export function saveTask(current: any, dispatch: any) {
if (current.task) {
let task = {
...current.task,
......@@ -19,24 +19,26 @@ export function saveTask(current:any,dispatch: any){
}
/*--- 创建会话 ---*/
export function createSession(session: SessionType,dispatch: any) {
const res = addOrUpdateData("api/studio/createSession",session)
export function createSession(session: SessionType, dispatch: any) {
const res = addOrUpdateData("api/studio/createSession", session)
res.then((result) => {
message.success(`创建会话【${session.session}】成功!`);
result.datas&&changeSession(result.datas,dispatch);
result.datas && changeSession(result.datas, dispatch);
listSession(dispatch);
});
}
/*--- 查询会话列表 ---*/
export function listSession(dispatch: any) {
const res = getData("api/studio/listSession");
res.then((result)=>{
res.then((result) => {
dispatch && dispatch({
type: "Studio/saveSession",
payload: result.datas,
});
});
}
/*--- 切换会话 ---*/
export function changeSession(session: SessionType, dispatch: any) {
dispatch && dispatch({
......@@ -44,15 +46,17 @@ export function changeSession(session: SessionType, dispatch: any) {
payload: session,
});
setTimeout(function () {
showTables(session.session,dispatch);
},200);
showTables(session.session, dispatch);
}, 200);
}
/*--- 退出会话 ---*/
export function quitSession( dispatch: any) {
export function quitSession(dispatch: any) {
dispatch && dispatch({
type: "Studio/quitCurrentSession",
});
}
/*--- 注销会话 ---*/
export function clearSession(session: string, dispatch: any) {
Modal.confirm({
......@@ -71,9 +75,10 @@ export function clearSession(session: string, dispatch: any) {
}
});
}
/*--- 刷新 Catalog Table ---*/
export function showTables(session: string, dispatch: any) {
if(session==null||session==''){
if (session == null || session == '') {
return;
}
const res = executeDDL({
......@@ -90,11 +95,12 @@ export function showTables(session: string, dispatch: any) {
dispatch && dispatch({
type: "Studio/refreshCurrentSession",
payload: {
connectors:tableData
connectors: tableData
},
});
});
}
/*--- 移除 Catalog Table ---*/
export function removeTable(tablename: string, session: string, dispatch: any) {
Modal.confirm({
......@@ -114,6 +120,7 @@ export function removeTable(tablename: string, session: string, dispatch: any) {
}
});
}
/*--- 刷新 集群 ---*/
export function showCluster(dispatch: any) {
const res = getData('api/cluster/listEnabledAll');
......@@ -124,6 +131,7 @@ export function showCluster(dispatch: any) {
});
});
}
/*--- 刷新 Session集群 ---*/
export function showSessionCluster(dispatch: any) {
const res = getData('api/cluster/listSessionEnable');
......@@ -134,6 +142,7 @@ export function showSessionCluster(dispatch: any) {
});
});
}
/*--- 刷新 数据源 ---*/
export function showDataBase(dispatch: any) {
const res = getData('api/database/listEnabledAll');
......@@ -144,6 +153,7 @@ export function showDataBase(dispatch: any) {
});
});
}
/*--- 刷新 执行环境 ---*/
export function showEnv(dispatch: any) {
const res = getData('api/task/listFlinkSQLEnv');
......@@ -154,6 +164,7 @@ export function showEnv(dispatch: any) {
});
});
}
/*--- 刷新 自定义Jar ---*/
export function showJars(dispatch: any) {
const res = getData('api/jar/listEnabledAll');
......@@ -164,6 +175,7 @@ export function showJars(dispatch: any) {
});
});
}
/*--- 刷新 报警实例 ---*/
export function showAlertInstance(dispatch: any) {
const res = getData('api/alertInstance/listEnabledAll');
......@@ -174,6 +186,7 @@ export function showAlertInstance(dispatch: any) {
});
});
}
/*--- 刷新 报警组 ---*/
export function showAlertGroup(dispatch: any) {
const res = getData('api/alertGroup/listEnabledAll');
......@@ -184,29 +197,35 @@ export function showAlertGroup(dispatch: any) {
});
});
}
/*--- 刷新 元数据表 ---*/
export function showMetaDataTable(id:number) {
return getData('api/database/getSchemasAndTables',{id:id});
export function showMetaDataTable(id: number) {
return getData('api/database/getSchemasAndTables', {id: id});
}
/*--- 刷新 Flink Jobs ---*/
export function showFlinkJobs(clusterId:number) {
return getData('api/studio/listJobs',{clusterId:clusterId});
export function showFlinkJobs(clusterId: number) {
return getData('api/studio/listJobs', {clusterId: clusterId});
}
/*--- 停止 Flink Jobs ---*/
export function cancelJob(clusterId:number,jobId:string) {
return getData('api/studio/cancel',{clusterId:clusterId,jobId:jobId});
export function cancelJob(clusterId: number, jobId: string) {
return getData('api/studio/cancel', {clusterId: clusterId, jobId: jobId});
}
/*--- 重启 Flink Jobs ---*/
export function restartJob(id: number) {
return getData('api/task/restartTask',{id});
export function restartJob(id: number, isOnLine: boolean) {
return getData('api/task/restartTask', {id, isOnLine});
}
/*--- 停止 SavePoint Jobs ---*/
export function savepointJob(clusterId:number,jobId:string,savePointType:string,name:string,taskId:number) {
return getData('api/studio/savepoint',{clusterId,jobId,savePointType,name,taskId});
export function savepointJob(clusterId: number, jobId: string, savePointType: string, name: string, taskId: number) {
return getData('api/studio/savepoint', {clusterId, jobId, savePointType, name, taskId});
}
/*--- 根据版本号获取所有自动补全的文档 ---*/
export function getFillAllByVersion(version:string,dispatch: any) {
const res = getData('api/document/getFillAllByVersion',{version:version});
export function getFillAllByVersion(version: string, dispatch: any) {
const res = getData('api/document/getFillAllByVersion', {version: version});
res.then((result) => {
result.datas && dispatch && dispatch({
type: "Document/saveAllFillDocuments",
......@@ -214,6 +233,7 @@ export function getFillAllByVersion(version:string,dispatch: any) {
});
});
}
/*--- 刷新 集群 ---*/
export function showClusterConfiguration(dispatch: any) {
const res = getData('api/clusterConfiguration/listEnabledAll');
......@@ -224,27 +244,33 @@ export function showClusterConfiguration(dispatch: any) {
});
});
}
/*--- 发布作业 ---*/
export function releaseTask(id: number) {
return getData('api/task/releaseTask',{id});
return getData('api/task/releaseTask', {id});
}
/*--- 发布作业 ---*/
export function developTask(id: number) {
return getData('api/task/developTask',{id});
return getData('api/task/developTask', {id});
}
/*--- 上线作业 ---*/
export function onLineTask(id: number) {
return getData('api/task/onLineTask',{id});
return getData('api/task/onLineTask', {id});
}
/*--- 下线作业 ---*/
export function offLineTask(id: number, type: string) {
return getData('api/task/offLineTask',{id, type});
return getData('api/task/offLineTask', {id, type});
}
/*--- 注销作业 ---*/
export function cancelTask(id: number) {
return getData('api/task/cancelTask',{id});
return getData('api/task/cancelTask', {id});
}
/*--- 恢复作业 ---*/
export function recoveryTask(id: number) {
return getData('api/task/recoveryTask',{id});
return getData('api/task/recoveryTask', {id});
}
import styles from "./index.less";
import {Menu, Dropdown, Tooltip, Row, Col, notification, Modal, message} from "antd";
import {
PauseCircleTwoTone, CarryOutTwoTone, DeleteTwoTone, PlayCircleTwoTone, CameraTwoTone,SnippetsTwoTone,
FileAddTwoTone, FolderOpenTwoTone, SafetyCertificateTwoTone, SaveTwoTone, FlagTwoTone,CodeTwoTone,
PauseCircleTwoTone, CarryOutTwoTone, DeleteTwoTone, PlayCircleTwoTone, CameraTwoTone, SnippetsTwoTone,
FileAddTwoTone, FolderOpenTwoTone, SafetyCertificateTwoTone, SaveTwoTone, FlagTwoTone, CodeTwoTone,
EnvironmentOutlined, SmileOutlined, RocketTwoTone, QuestionCircleTwoTone, MessageOutlined, ClusterOutlined
, EditTwoTone, RestTwoTone
} from "@ant-design/icons";
......@@ -51,7 +51,7 @@ const menu = (
const StudioMenu = (props: any) => {
const {isFullScreen, tabs, current, currentPath, form,width,height, refs, dispatch, currentSession} = props;
const {isFullScreen, tabs, current, currentPath, form, width, height, refs, dispatch, currentSession} = props;
const [modalVisible, handleModalVisible] = useState<boolean>(false);
const [exportModalVisible, handleExportModalVisible] = useState<boolean>(false);
const [graphModalVisible, handleGraphModalVisible] = useState<boolean>(false);
......@@ -59,15 +59,15 @@ const StudioMenu = (props: any) => {
const [graphData, setGraphData] = useState();
const onKeyDown = useCallback((e) => {
if(e.keyCode === 83 && (e.ctrlKey === true || e.metaKey)){
if (e.keyCode === 83 && (e.ctrlKey === true || e.metaKey)) {
e.preventDefault();
if(current) {
if (current) {
props.saveTask(current);
}
}
if(e.keyCode === 113){
if (e.keyCode === 113) {
e.preventDefault();
if(current) {
if (current) {
// handleEditModalVisible(true);
props.changeFullScreen(true);
}
......@@ -82,7 +82,7 @@ const StudioMenu = (props: any) => {
}, [current]);
const execute = () => {
if(!isSql(current.task.dialect)&&!isOnline(current.task.type)){
if (!isSql(current.task.dialect) && !isOnline(current.task.type)) {
message.warn(`该任务执行模式为【${current.task.type}】,不支持 SQL 查询,请手动保存后使用右侧按钮——作业提交`);
return;
}
......@@ -97,6 +97,7 @@ const StudioMenu = (props: any) => {
let useSession = !!currentSession.session;
let param = {
...current.task,
taskId: current.task.id,
useSession: useSession,
session: currentSession.session,
configJson: JSON.stringify(current.task.config),
......@@ -118,7 +119,7 @@ const StudioMenu = (props: any) => {
result.then(res => {
notification.close(taskKey);
if (res.datas.success) {
res.datas?.jobInstanceId&&props.changeTaskJobInstance(current.task.id,res.datas?.jobInstanceId);
res.datas?.jobInstanceId && props.changeTaskJobInstance(current.task.id, res.datas?.jobInstanceId);
message.success('执行成功');
} else {
message.error('执行失败');
......@@ -163,7 +164,7 @@ const StudioMenu = (props: any) => {
const res = await postDataArray('/api/task/submit', [task.id]);
notification.close(taskKey);
if (res.datas[0].success) {
res.datas[0].jobInstanceId && props.changeTaskJobInstance(current.task.id,res.datas[0].jobInstanceId);
res.datas[0].jobInstanceId && props.changeTaskJobInstance(current.task.id, res.datas[0].jobInstanceId);
message.success('异步提交成功');
} else {
message.success('异步提交失败');
......@@ -177,7 +178,7 @@ const StudioMenu = (props: any) => {
handleModalVisible(true);
};
const onGetStreamGraph=()=>{
const onGetStreamGraph = () => {
let selectsql = null;
if (current.monaco.current) {
let selection = current.monaco.current.editor.getSelection();
......@@ -196,36 +197,38 @@ const StudioMenu = (props: any) => {
};
const res = getJobPlan(param);
handleGraphModalVisible(true);
res.then((result)=>{
if(result.code==0){
res.then((result) => {
if (result.code == 0) {
setGraphData(buildGraphData(result.datas));
}else{
} else {
setGraphData(undefined);
}
})
};
const buildGraphData=(data)=>{
const buildGraphData = (data) => {
let edges = [];
for(let i in data.nodes){
data.nodes[i].id=data.nodes[i].id.toString();
data.nodes[i].value={
title:data.nodes[i].pact,
for (let i in data.nodes) {
data.nodes[i].id = data.nodes[i].id.toString();
data.nodes[i].value = {
title: data.nodes[i].pact,
items: [
{
text: getRangeText(data.nodes[i].description),
},
{
text: '\r\nParallelism: ',
value: '\r\n '+data.nodes[i].parallelism,
value: '\r\n ' + data.nodes[i].parallelism,
},
],
};
if(data.nodes[i].inputs){
for(let j in data.nodes[i].inputs){
edges.push({source: data.nodes[i].inputs[j].id.toString(),
if (data.nodes[i].inputs) {
for (let j in data.nodes[i].inputs) {
edges.push({
source: data.nodes[i].inputs[j].id.toString(),
target: data.nodes[i].id.toString(),
value: data.nodes[i].inputs[j].ship_strategy})
value: data.nodes[i].inputs[j].ship_strategy
})
}
}
}
......@@ -233,17 +236,17 @@ const StudioMenu = (props: any) => {
return data;
};
const getRangeText = (str:string) => {
const getRangeText = (str: string) => {
str = escape2Html(str);
var canvas = getRangeText.canvas || (getRangeText.canvas = document.createElement("canvas"));
var context = canvas.getContext("2d");
context.font = "10px sans-serif";
let result = '';
let count = 1;
for(let i=0,len=str.length;i<len;i++){
for (let i = 0, len = str.length; i < len; i++) {
result += str[i];
let width = context.measureText(result).width;
if(width >= 110*count) {
if (width >= 110 * count) {
result += '\r\n';
count++;
}
......@@ -251,7 +254,7 @@ const StudioMenu = (props: any) => {
return result;
};
const getTextWidth = (text:string, font:string) => {
const getTextWidth = (text: string, font: string) => {
var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
var context = canvas.getContext("2d");
context.font = font;
......@@ -259,13 +262,15 @@ const StudioMenu = (props: any) => {
return metrics.width;
}
const escape2Html = (str:string) => {
let arrEntities={'lt':'<','gt':'>','nbsp':' ','amp':'&','quot':'"'};
return str.replace(/&(lt|gt|nbsp|amp|quot);/ig,function(all,t){return arrEntities[t];});
const escape2Html = (str: string) => {
let arrEntities = {'lt': '<', 'gt': '>', 'nbsp': ' ', 'amp': '&', 'quot': '"'};
return str.replace(/&(lt|gt|nbsp|amp|quot);/ig, function (all, t) {
return arrEntities[t];
});
}
const toFullScreen = () => {
if(current) {
if (current) {
props.changeFullScreen(true);
}
};
......@@ -287,10 +292,10 @@ const StudioMenu = (props: any) => {
onOk: async () => {
const res = releaseTask(current.task.id);
res.then((result) => {
if(result.code == CODE.SUCCESS) {
props.changeTaskStep(current.task.id,JOB_LIFE_CYCLE.RELEASE);
if (result.code == CODE.SUCCESS) {
props.changeTaskStep(current.task.id, JOB_LIFE_CYCLE.RELEASE);
message.success(`发布作业【${current.task.alias}】成功`);
}else {
} else {
message.error(`发布作业【${current.task.alias}】失败,原因:\n${result.msg}`);
}
});
......@@ -307,8 +312,8 @@ const StudioMenu = (props: any) => {
onOk: async () => {
const res = developTask(current.task.id);
res.then((result) => {
result.datas && props.changeTaskStep(current.task.id,JOB_LIFE_CYCLE.DEVELOP);
if(result.code == CODE.SUCCESS) {
result.datas && props.changeTaskStep(current.task.id, JOB_LIFE_CYCLE.DEVELOP);
if (result.code == CODE.SUCCESS) {
message.success(`维护作业【${current.task.alias}】成功`);
}
});
......@@ -325,11 +330,11 @@ const StudioMenu = (props: any) => {
onOk: async () => {
const res = onLineTask(current.task.id);
res.then((result) => {
if(result.code === CODE.SUCCESS) {
props.changeTaskStep(current.task.id,JOB_LIFE_CYCLE.ONLINE);
result.datas?.jobInstanceId && props.changeTaskJobInstance(current.task.id,result.datas?.jobInstanceId);
if (result.code === CODE.SUCCESS) {
props.changeTaskStep(current.task.id, JOB_LIFE_CYCLE.ONLINE);
result.datas?.jobInstanceId && props.changeTaskJobInstance(current.task.id, result.datas?.jobInstanceId);
message.success(`上线作业【${current.task.alias}】成功`);
}else {
} else {
message.error(`上线作业【${current.task.alias}】失败,原因:\n${result.msg}`);
}
});
......@@ -344,15 +349,15 @@ const StudioMenu = (props: any) => {
okText: '确认',
cancelText: '取消',
onOk: async () => {
const res = offLineTask(current.task.id,type);
const res = offLineTask(current.task.id, type);
res.then((result) => {
if(result.code === CODE.SUCCESS) {
if(current.task.step === JOB_LIFE_CYCLE.ONLINE){
props.changeTaskStep(current.task.id,JOB_LIFE_CYCLE.RELEASE);
if (result.code === CODE.SUCCESS) {
if (current.task.step === JOB_LIFE_CYCLE.ONLINE) {
props.changeTaskStep(current.task.id, JOB_LIFE_CYCLE.RELEASE);
}
props.changeTaskJobInstance(current.task.id,0);
props.changeTaskJobInstance(current.task.id, 0);
message.success(`停止作业【${current.task.alias}】成功`);
}else {
} else {
message.error(`停止作业【${current.task.alias}】失败,原因:\n${result.msg}`);
}
});
......@@ -367,13 +372,13 @@ const StudioMenu = (props: any) => {
okText: '确认',
cancelText: '取消',
onOk: async () => {
const res = offLineTask(current.task.id,type);
const res = offLineTask(current.task.id, type);
res.then((result) => {
if(result.code === CODE.SUCCESS) {
props.changeTaskStep(current.task.id,JOB_LIFE_CYCLE.RELEASE);
props.changeTaskJobInstance(current.task.id,0);
if (result.code === CODE.SUCCESS) {
props.changeTaskStep(current.task.id, JOB_LIFE_CYCLE.RELEASE);
props.changeTaskJobInstance(current.task.id, 0);
message.success(`下线作业【${current.task.alias}】成功`);
}else {
} else {
message.error(`下线作业【${current.task.alias}】失败,原因:\n${result.msg}`);
}
});
......@@ -390,10 +395,10 @@ const StudioMenu = (props: any) => {
onOk: async () => {
const res = cancelTask(current.task.id);
res.then((result) => {
if(result.code === CODE.SUCCESS) {
props.changeTaskStep(current.task.id,JOB_LIFE_CYCLE.CANCEL);
if (result.code === CODE.SUCCESS) {
props.changeTaskStep(current.task.id, JOB_LIFE_CYCLE.CANCEL);
message.success(`注销作业【${current.task.alias}】成功`);
}else {
} else {
message.error(`注销作业【${current.task.alias}】失败,原因:\n${result.msg}`);
}
});
......@@ -410,8 +415,8 @@ const StudioMenu = (props: any) => {
onOk: async () => {
const res = recoveryTask(current.task.id);
res.then((result) => {
result.datas && props.changeTaskStep(current.task.id,JOB_LIFE_CYCLE.DEVELOP);
if(result.code == CODE.SUCCESS) {
result.datas && props.changeTaskStep(current.task.id, JOB_LIFE_CYCLE.DEVELOP);
if (result.code == CODE.SUCCESS) {
message.success(`恢复作业【${current.task.alias}】成功`);
}
});
......@@ -420,19 +425,19 @@ const StudioMenu = (props: any) => {
};
const isShowGetStreamGraphBtn = () => {
return (!current.task.dialect||current.task.dialect === DIALECT.FLINKSQL);
return (!current.task.dialect || current.task.dialect === DIALECT.FLINKSQL);
};
const isShowExecuteBtn = () => {
return !isDeletedTask(current.task.step) && isExecuteSql( current.task.dialect ) && !isRunningTask(current.task.jobInstanceId);
return !isDeletedTask(current.task.step) && isExecuteSql(current.task.dialect) && !isRunningTask(current.task.jobInstanceId);
};
const isShowSubmitBtn = () => {
return !isDeletedTask(current.task.step) && isTask( current.task.dialect ) && !isRunningTask(current.task.jobInstanceId);
return !isDeletedTask(current.task.step) && isTask(current.task.dialect) && !isRunningTask(current.task.jobInstanceId);
};
const isShowCancelTaskBtn = () => {
return !isDeletedTask(current.task.step) && isTask( current.task.dialect ) && isRunningTask(current.task.jobInstanceId);
return !isDeletedTask(current.task.step) && isTask(current.task.dialect) && isRunningTask(current.task.jobInstanceId);
};
const runMenu = (
......@@ -516,12 +521,12 @@ const StudioMenu = (props: any) => {
</Breadcrumb>
)}
</Col>
{current?.task?
{current?.task ?
<Col span={8}>
<Tooltip title="全屏开发">
<Button
type="text"
icon={<CodeTwoTone />}
icon={<CodeTwoTone/>}
onClick={toFullScreen}
/>
</Tooltip>
......@@ -543,7 +548,7 @@ const StudioMenu = (props: any) => {
<Tooltip title="导出当前的 Sql 及配置">
<Button
type="text"
icon={<SnippetsTwoTone />}
icon={<SnippetsTwoTone/>}
onClick={exportSql}
/>
</Tooltip>
......@@ -555,7 +560,7 @@ const StudioMenu = (props: any) => {
onClick={onCheckSql}
/>
</Tooltip>
{isShowGetStreamGraphBtn() &&(
{isShowGetStreamGraphBtn() && (
<Tooltip title="获取当前的 FlinkSql 的执行图">
<Button
type="text"
......@@ -563,7 +568,7 @@ const StudioMenu = (props: any) => {
onClick={onGetStreamGraph}
/>
</Tooltip>)}
{isShowExecuteBtn() &&(
{isShowExecuteBtn() && (
<Tooltip title="执行当前的 SQL">
<Button
type="text"
......@@ -572,7 +577,7 @@ const StudioMenu = (props: any) => {
onClick={execute}
/>
</Tooltip>)}
{isShowSubmitBtn() &&(<>
{isShowSubmitBtn() && (<>
<Tooltip title="提交当前的作业到集群,提交前请手动保存">
<Button
type="text"
......@@ -585,8 +590,8 @@ const StudioMenu = (props: any) => {
<Tooltip title="停止">
<Button
type="text"
icon={<PauseCircleTwoTone />}
onClick={()=>handleCancelTask('canceljob')}
icon={<PauseCircleTwoTone/>}
onClick={() => handleCancelTask('canceljob')}
/>
</Tooltip>
}
......@@ -598,46 +603,46 @@ const StudioMenu = (props: any) => {
icon={<CameraTwoTone/>}
onClick={toReleaseTask}
/>
</Tooltip>:undefined
</Tooltip> : undefined
}{current.task.step == JOB_LIFE_CYCLE.RELEASE ?
<><Tooltip title="维护,点击进入编辑状态">
<Button
type="text"
icon={<EditTwoTone />}
icon={<EditTwoTone/>}
onClick={toDevelopTask}
/>
</Tooltip>
<Tooltip title="上线,上线后自动恢复、告警等将生效">
<Button
type="text"
icon={<CarryOutTwoTone />}
icon={<CarryOutTwoTone/>}
onClick={toOnLineTask}
/>
</Tooltip></>:undefined
</Tooltip></> : undefined
}{current.task.step == JOB_LIFE_CYCLE.ONLINE ?
<Tooltip title="下线,将进入最新发布状态">
<Button
type="text"
icon={<PauseCircleTwoTone />}
onClick={()=>toOffLineTask('cancel')}
icon={<PauseCircleTwoTone/>}
onClick={() => toOffLineTask('cancel')}
/>
</Tooltip>:undefined
</Tooltip> : undefined
}{(current.task.step != JOB_LIFE_CYCLE.ONLINE && current.task.step != JOB_LIFE_CYCLE.CANCEL) ?
<Tooltip title="注销,将进入回收站">
<Button
type="text"
icon={<DeleteTwoTone />}
icon={<DeleteTwoTone/>}
onClick={toCancelTask}
/>
</Tooltip>:undefined
</Tooltip> : undefined
}{current.task.step == JOB_LIFE_CYCLE.CANCEL ?
<Tooltip title="恢复,将进入维护模式">
<Button
type="text"
icon={<RestTwoTone />}
icon={<RestTwoTone/>}
onClick={toRecoveryTask}
/>
</Tooltip>:undefined
</Tooltip> : undefined
}
<Tooltip title="查看使用帮助">
<Button
......@@ -646,12 +651,14 @@ const StudioMenu = (props: any) => {
onClick={showHelp}
/>
</Tooltip>
</Col>:undefined}
</Col> : undefined}
</Row>
</Col>
<StudioExplain
modalVisible={modalVisible}
onClose={()=>{handleModalVisible(false)}}
onClose={() => {
handleModalVisible(false)
}}
/>
<Modal
width={1000}
......@@ -661,16 +668,16 @@ const StudioMenu = (props: any) => {
visible={graphModalVisible}
onCancel={() => handleGraphModalVisible(false)}
>
<StudioGraph data={graphData} />
<StudioGraph data={graphData}/>
</Modal>
{current?.task?
{current?.task ?
<ModalForm
title={`${current.task.alias} 的 ${current.task.dialect} 导出`}
visible={exportModalVisible}
width={1000}
modalProps={{
maskClosable:false,
bodyStyle:{
maskClosable: false,
bodyStyle: {
padding: '5px'
}
}}
......@@ -683,12 +690,12 @@ const StudioMenu = (props: any) => {
},
}}
>
<SqlExport id={current.task.id} />
</ModalForm>:undefined}
{current && isFullScreen?<Modal
<SqlExport id={current.task.id}/>
</ModalForm> : undefined}
{current && isFullScreen ? <Modal
width={width}
bodyStyle={{padding: 0}}
style={{top:0,padding:0,margin:0,maxWidth:'100vw'}}
style={{top: 0, padding: 0, margin: 0, maxWidth: '100vw'}}
destroyOnClose
maskClosable={false}
closable={false}
......@@ -698,31 +705,31 @@ const StudioMenu = (props: any) => {
props.changeFullScreen(false);
}}>
<StudioTabs width={width} height={height}/>
</Modal>:undefined}
</Modal> : undefined}
</Row>
);
};
const mapDispatchToProps = (dispatch: Dispatch)=>({
saveTask:(current: any)=>dispatch({
const mapDispatchToProps = (dispatch: Dispatch) => ({
saveTask: (current: any) => dispatch({
type: "Studio/saveTask",
payload: current.task,
}),saveTabs:(tabs: any)=>dispatch({
}), saveTabs: (tabs: any) => dispatch({
type: "Studio/saveTabs",
payload: tabs,
}),changeFullScreen:(isFull: boolean)=>dispatch({
}), changeFullScreen: (isFull: boolean) => dispatch({
type: "Studio/changeFullScreen",
payload: isFull,
}),changeTaskStep:(id: number, step: number)=>dispatch({
}), changeTaskStep: (id: number, step: number) => dispatch({
type: "Studio/changeTaskStep",
payload: {
id,step
id, step
},
}),changeTaskJobInstance:(id: number, jobInstanceId: number)=>dispatch({
}), changeTaskJobInstance: (id: number, jobInstanceId: number) => dispatch({
type: "Studio/changeTaskJobInstance",
payload: {
id,jobInstanceId
id, jobInstanceId
},
}),
});
......@@ -734,4 +741,4 @@ export default connect(({Studio}: { Studio: StateType }) => ({
tabs: Studio.tabs,
refs: Studio.refs,
currentSession: Studio.currentSession,
}),mapDispatchToProps)(StudioMenu);
}), mapDispatchToProps)(StudioMenu);
import React, {useEffect, useState,Key} from "react";
import React, {useEffect, useState, Key} from "react";
import {connect} from "umi";
import {DownOutlined, SwitcherOutlined, FolderAddOutlined} from "@ant-design/icons";
import {Tree, Menu, Empty, Button, message, Modal,Tooltip,Row,Col,Input} from 'antd';
import {Tree, Menu, Empty, Button, message, Modal, Tooltip, Row, Col, Input} from 'antd';
import {getCatalogueTreeData} from "@/pages/FlinkSqlStudio/service";
import {convertToTreeData, getTreeNodeByKey, TreeDataNode} from "@/components/Studio/StudioTree/Function";
import style from "./index.less";
......@@ -11,18 +11,18 @@ import {
} from "@/components/Common/crud";
import UpdateCatalogueForm from './components/UpdateCatalogueForm';
import SimpleTaskForm from "@/components/Studio/StudioTree/components/SimpleTaskForm";
import { Scrollbars } from "react-custom-scrollbars";
import {Scrollbars} from "react-custom-scrollbars";
import {getIcon} from "@/components/Studio/icon";
import {showEnv} from "@/components/Studio/StudioEvent/DDL";
import UploadModal from "@/components/Studio/StudioTree/components/UploadModal";
type StudioTreeProps = {
rightClickMenu:StateType['rightClickMenu'];
dispatch:any;
tabs:StateType['tabs'];
current:StateType['current'];
toolHeight:number;
refs:any;
rightClickMenu: StateType['rightClickMenu'];
dispatch: any;
tabs: StateType['tabs'];
current: StateType['current'];
toolHeight: number;
refs: any;
};
type RightClickMenu = {
......@@ -36,18 +36,18 @@ type RightClickMenu = {
const generateList = (data: any, list: any[]) => {
for (let i = 0; i < data.length; i++) {
const node = data[i];
const { name, id, parentId,level} = node;
list.push({ name, id, key: id, title: name, parentId,level });
const {name, id, parentId, level} = node;
list.push({name, id, key: id, title: name, parentId, level});
if (node.children) {
generateList(node.children, list);
}
}
return list
}
};
// tree树 匹配方法
const getParentKey = (key: number | string, tree: any): any => {
let parentKey
let parentKey;
for (let i = 0; i < tree.length; i++) {
const node = tree[i];
if (node.children) {
......@@ -58,16 +58,18 @@ const getParentKey = (key: number | string, tree: any): any => {
}
}
}
// console.log(key, parentKey, tree,)
return parentKey;
}
};
const {DirectoryTree} = Tree;
const {Search} = Input;
const StudioTree: React.FC<StudioTreeProps> = (props) => {
const {rightClickMenu,dispatch,tabs,refs,toolHeight} = props;
const {rightClickMenu, dispatch, tabs, refs, toolHeight} = props;
const [treeData, setTreeData] = useState<TreeDataNode[]>();
const [expandedKeys, setExpandedKeys] = useState<Key[]>();
const [defaultExpandedKeys, setDefaultExpandedKeys] = useState<any[]>([]);
const [rightClickNodeTreeItem,setRightClickNodeTreeItem] = useState<RightClickMenu>();
const [rightClickNodeTreeItem, setRightClickNodeTreeItem] = useState<RightClickMenu>();
const [updateCatalogueModalVisible, handleUpdateCatalogueModalVisible] = useState<boolean>(false);
const [updateTaskModalVisible, handleUpdateTaskModalVisible] = useState<boolean>(false);
const [isCreate, setIsCreate] = useState<boolean>(true);
......@@ -78,10 +80,9 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
const [isUploadModalVisible, setIsUploadModalVisible] = useState(false);
const [uploadNodeId, setUploadNodeId] = useState(0);
const sref: any = React.createRef<Scrollbars>();
const { DirectoryTree } = Tree;
const {Search} = Input;
const [searchValue, setSearchValue] = useState('')
const [searchValue, setSearchValue] = useState('');
const [autoExpandParent, setAutoExpandParent] = useState(true);
const [cutId, setCutId] = useState<number | undefined>(undefined);
const getTreeData = async () => {
const result = await getCatalogueTreeData();
......@@ -95,23 +96,23 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
expendList.push(item.id);
})
}
})
});
data = convertToTreeData(list, 0);
setTreeData(data);
//默认展开所有
setExpandedKeys(expendList|| []);
setExpandedKeys(expendList || []);
setDefaultExpandedKeys(expendList || []);
};
const onChange = (e: any) => {
let { value } = e.target
let {value} = e.target;
if (!value) {
setExpandedKeys(defaultExpandedKeys);
setSearchValue(value)
setSearchValue(value);
return
}
value = String(value).trim()
const expandList: any[] = generateList(treeData, [])
value = String(value).trim();
const expandList: any[] = generateList(treeData, []);
let expandedKeys: any = expandList.map((item: any) => {
if (item && item.name.indexOf(value) > -1) {
let key = getParentKey(item.key, treeData);
......@@ -125,21 +126,21 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
setAutoExpandParent(true)
}
const openByKey = async (key:any)=>{
const openByKey = async (key: any) => {
const result = await getCatalogueTreeData();
let data = result.datas;
let list = data;
for(let i=0;i<list.length;i++){
list[i].title=list[i].name;
list[i].key=list[i].id;
if(list[i].isLeaf){
for (let i = 0; i < list.length; i++) {
list[i].title = list[i].name;
list[i].key = list[i].id;
if (list[i].isLeaf) {
list[i].icon = getIcon(list[i].type);
}
}
data = convertToTreeData(list, 0);
setTreeData(data);
let node = getTreeNodeByKey(data,key);
onSelect([],{node:node});
let node = getTreeNodeByKey(data, key);
onSelect([], {node: node});
};
useEffect(() => {
......@@ -147,74 +148,80 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
}, []);
const handleMenuClick=(key:string)=>{
if(key=='Open'){
const handleMenuClick = (key: string) => {
if (key == 'Open') {
toOpen(rightClickNode);
}else if(key=='Submit'){
} else if (key == 'Submit') {
toSubmit(rightClickNode);
}else if(key=='CreateCatalogue'){
} else if (key == 'CreateCatalogue') {
createCatalogue(rightClickNode);
}else if(key=='CreateRootCatalogue'){
} else if (key == 'CreateRootCatalogue') {
createRootCatalogue();
} else if(key == 'ShowUploadModal'){
} else if (key == 'ShowUploadModal') {
showUploadModal(rightClickNode);
}else if(key=='CreateTask'){
} else if (key == 'CreateTask') {
createTask(rightClickNode);
}else if(key=='Rename'){
} else if (key == 'Rename') {
toRename(rightClickNode);
}else if(key=='Delete'){
} else if (key == 'Delete') {
toDelete(rightClickNode);
} else if (key == 'Cut') {
toCut(rightClickNode);
} else if (key == 'Paste') {
toPaste(rightClickNode);
}
};
const showUploadModal=(node:TreeDataNode|undefined)=>{
if(node == undefined) return;
const showUploadModal = (node: TreeDataNode | undefined) => {
if (node == undefined) return;
setUploadNodeId(node.id);
setIsUploadModalVisible(true);
}
};
const toOpen=(node:TreeDataNode|undefined)=>{
if(!available){return}
const toOpen = (node: TreeDataNode | undefined) => {
if (!available) {
return
}
setAvailable(false);
setTimeout(()=>{
setTimeout(() => {
setAvailable(true);
},200);
}, 200);
if(node?.isLeaf&&node.taskId) {
for(let item of tabs.panes){
if(item.key==node.taskId){
dispatch&&dispatch({
if (node?.isLeaf && node.taskId) {
for (let item of tabs.panes) {
if (item.key == node.taskId) {
dispatch && dispatch({
type: "Studio/saveToolHeight",
payload: toolHeight-0.0001,
payload: toolHeight - 0.0001,
});
dispatch&&dispatch({
dispatch && dispatch({
type: "Studio/changeActiveKey",
payload: node.taskId,
});
return;
}
}
const result = getInfoById('/api/task',node.taskId);
result.then(result=>{
const result = getInfoById('/api/task', node.taskId);
result.then(result => {
let newTabs = tabs;
let newPane:any = {
let newPane: any = {
title: <>{node!.icon} {node!.name}</>,
key: node!.taskId,
value:(result.datas.statement?result.datas.statement:''),
value: (result.datas.statement ? result.datas.statement : ''),
closable: true,
path: node!.path,
task:{
session:'',
task: {
session: '',
maxRowNum: 100,
jobName:node!.name,
useResult:true,
useChangeLog:false,
useAutoCancel:false,
useSession:false,
useRemote:true,
jobName: node!.name,
useResult: true,
useChangeLog: false,
useAutoCancel: false,
useSession: false,
useRemote: true,
...result.datas,
},
console:{
console: {
result: {},
chart: {},
},
......@@ -222,7 +229,7 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
};
newTabs!.activeKey = node!.taskId;
newTabs!.panes!.push(newPane);
dispatch&&dispatch({
dispatch && dispatch({
type: "Studio/saveTabs",
payload: newTabs,
});
......@@ -230,8 +237,8 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
}
};
const createCatalogue=(node:TreeDataNode|undefined)=>{
if(!node?.isLeaf) {
const createCatalogue = (node: TreeDataNode | undefined) => {
if (!node?.isLeaf) {
handleUpdateCatalogueModalVisible(true);
setIsCreate(true);
setCatalogueFormValues({
......@@ -239,12 +246,12 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
parentId: node?.id,
});
getTreeData();
}else{
} else {
message.error('只能在目录上创建目录');
}
};
const createRootCatalogue=()=>{
const createRootCatalogue = () => {
handleUpdateCatalogueModalVisible(true);
setIsCreate(true);
setCatalogueFormValues({
......@@ -254,25 +261,25 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
getTreeData();
};
const toSubmit=(node:TreeDataNode|undefined)=>{
const toSubmit = (node: TreeDataNode | undefined) => {
Modal.confirm({
title: '提交作业',
content: '确定提交该作业到其配置的集群吗?',
okText: '确认',
cancelText: '取消',
onOk:async () => {
onOk: async () => {
let task = {
id:node?.taskId,
id: node?.taskId,
};
setTimeout(()=>{
setTimeout(() => {
refs?.history?.current?.reload();
},2000);
handleSubmit('/api/task/submit','作业',[task]);
}, 2000);
handleSubmit('/api/task/submit', '作业', [task]);
}
});
};
const toRename=(node:TreeDataNode|undefined)=>{
const toRename = (node: TreeDataNode | undefined) => {
handleUpdateCatalogueModalVisible(true);
setIsCreate(false);
setCatalogueFormValues({
......@@ -282,29 +289,45 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
getTreeData();
};
const createTask=(node:TreeDataNode|undefined)=>{
if(!node?.isLeaf) {
const toCut = (node: TreeDataNode | undefined) => {
setCutId(node?.id);
message.success('剪切成功');
};
const toPaste = async (node: TreeDataNode | undefined) => {
if (cutId == 0) {
return;
}
const datas = await handleAddOrUpdateWithResult('/api/catalogue/moveCatalogue', {id: cutId, parentId: node?.id});
if (datas) {
setCutId(undefined);
getTreeData();
}
};
const createTask = (node: TreeDataNode | undefined) => {
if (!node?.isLeaf) {
handleUpdateTaskModalVisible(true);
setIsCreate(true);
setTaskFormValues({
parentId: node?.id,
});
//getTreeData();
}else{
} else {
message.error('只能在目录上创建作业');
}
};
const toDelete= (node: TreeDataNode|undefined)=>{
let label = (node?.taskId==null)?'目录':'作业';
const toDelete = (node: TreeDataNode | undefined) => {
let label = (node?.taskId == null) ? '目录' : '作业';
Modal.confirm({
title: `删除${label}`,
content: `确定删除该${label}${node?.name}】吗?`,
okText: '确认',
cancelText: '取消',
onOk:async () => {
await handleRemoveById('/api/catalogue',node!.id);
if(node?.taskId) {
onOk: async () => {
await handleRemoveById('/api/catalogue', node!.id);
if (node?.taskId) {
dispatch({
type: "Studio/deleteTabByKey",
payload: node?.taskId,
......@@ -317,33 +340,39 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
const getNodeTreeRightClickMenu = () => {
const {pageX, pageY} = {...rightClickNodeTreeItem};
const tmpStyle:any = {
const tmpStyle: any = {
position: 'absolute',
left: pageX,
top: pageY,
};
let menuItems;
if(rightClickNode&&rightClickNode.isLeaf){
menuItems=(<>
if (rightClickNode && rightClickNode.isLeaf) {
menuItems = (<>
<Menu.Item key='Open'>{'打开'}</Menu.Item>
<Menu.Item key='Submit'>{'异步提交'}</Menu.Item>
<Menu.Item key='Rename'>{'重命名'}</Menu.Item>
<Menu.Item key='Cut'>{'剪切'}</Menu.Item>
{cutId && <Menu.Item key='Paste'>{'粘贴'}</Menu.Item>}
<Menu.Item key='Delete'>{'删除'}</Menu.Item>
</>)
}else if(rightClickNode&&rightClickNode.children&&rightClickNode.children.length>0){
menuItems=(<>
} else if (rightClickNode && rightClickNode.children && rightClickNode.children.length > 0) {
menuItems = (<>
<Menu.Item key='CreateCatalogue'>{'创建目录'}</Menu.Item>
<Menu.Item key='CreateRootCatalogue'>{'创建根目录'}</Menu.Item>
<Menu.Item key='ShowUploadModal'>{'上传zip包创建工程'}</Menu.Item>
<Menu.Item key='CreateTask'>{'创建作业'}</Menu.Item>
<Menu.Item key='Rename'>{'重命名'}</Menu.Item>
<Menu.Item key='Cut'>{'剪切'}</Menu.Item>
{cutId && <Menu.Item key='Paste'>{'粘贴'}</Menu.Item>}
<Menu.Item disabled>{'删除'}</Menu.Item>
</>)
}else{
menuItems=(<>
} else {
menuItems = (<>
<Menu.Item key='CreateCatalogue'>{'创建目录'}</Menu.Item>
<Menu.Item key='CreateTask'>{'创建作业'}</Menu.Item>
<Menu.Item key='Rename'>{'重命名'}</Menu.Item>
<Menu.Item key='Cut'>{'剪切'}</Menu.Item>
{cutId && <Menu.Item key='Paste'>{'粘贴'}</Menu.Item>}
<Menu.Item key='Delete'>{'删除'}</Menu.Item>
</>)
}
......@@ -356,40 +385,40 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
{menuItems}
</Menu>
);
return rightClickMenu? menu: '';
return rightClickMenu ? menu : '';
};
const getEmpty = () =>{
const empty = (<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} ><Button type="primary" onClick={() => {
const getEmpty = () => {
const empty = (<Empty image={Empty.PRESENTED_IMAGE_SIMPLE}><Button type="primary" onClick={() => {
handleUpdateCatalogueModalVisible(true);
setIsCreate(true);
setCatalogueFormValues({
isLeaf:false,
parentId:0,
isLeaf: false,
parentId: 0,
});
}}>创建目录</Button></Empty>);
return (treeData&&treeData.length==0)?empty:'';
return (treeData && treeData.length == 0) ? empty : '';
};
const handleContextMenu = (e:any) => {
const handleContextMenu = (e: any) => {
let position = e.event.currentTarget.getBoundingClientRect();
let scrollTop = document.documentElement.scrollTop;
setRightClickNode(e.node);
setRightClickNodeTreeItem({
pageX: e.event.pageX-40,
pageY: position.y+sref.current.getScrollTop()+scrollTop-145-position.height,
pageX: e.event.pageX - 40,
pageY: position.y + sref.current.getScrollTop() + scrollTop - 145 - position.height,
id: e.node.id,
categoryName: e.node.name
});
dispatch&&dispatch({
dispatch && dispatch({
type: "Studio/showRightClickMenu",
payload: true,
});
};
//选中节点时触发
const onSelect = (selectedKeys:Key[], e:any) => {
if(e.node&&e.node.isLeaf) {
const onSelect = (selectedKeys: Key[], e: any) => {
if (e.node && e.node.isLeaf) {
dispatch({
type: "Studio/saveCurrentPath",
payload: e.node.path,
......@@ -398,18 +427,18 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
}
};
const offExpandAll = ()=>{
const offExpandAll = () => {
setExpandedKeys([]);
};
// 树节点展开/收缩
const onExpand=(expandedKeys:Key[])=>{
const onExpand = (expandedKeys: Key[]) => {
setExpandedKeys(expandedKeys);
setAutoExpandParent(false)
};
const loop = (data:any) =>
data?.map((item:any) => {
const loop = (data: any) =>
data?.map((item: any) => {
const index = item.title.indexOf(searchValue);
const beforeStr = item.title.substr(0, index);
const afterStr = item.title.substr(index + searchValue.length);
......@@ -425,61 +454,72 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
<span>{item.title}</span>
);
if (item.children) {
return {isLeaf:item.isLeaf,name:item.name,id:item.id,taskId:item.taskId,parentId:item.parentId,path:item.path,icon:item.isLeaf?item.icon:'', title, key: item.key, children: loop(item.children) };
return {
isLeaf: item.isLeaf,
name: item.name,
id: item.id,
taskId: item.taskId,
parentId: item.parentId,
path: item.path,
icon: item.isLeaf ? item.icon : '',
title,
key: item.key,
children: loop(item.children)
};
}
return {
isLeaf:item.isLeaf,
name:item.name,
id:item.id,
taskId:item.taskId,
parentId:item.parentId,
path:item.path,
icon:item.isLeaf?item.icon:'',
isLeaf: item.isLeaf,
name: item.name,
id: item.id,
taskId: item.taskId,
parentId: item.parentId,
path: item.path,
icon: item.isLeaf ? item.icon : '',
title,
key: item.key,
};
});
return (
<div className={style.tree_div} >
<div className={style.tree_div}>
<Row>
<Col span={24}>
<Tooltip title="创建根目录">
<Button
type="text"
icon={<FolderAddOutlined />}
icon={<FolderAddOutlined/>}
onClick={createRootCatalogue}
/>
</Tooltip>
<Tooltip title="折叠目录">
<Button
type="text"
icon={<SwitcherOutlined />}
icon={<SwitcherOutlined/>}
onClick={offExpandAll}
/>
</Tooltip>
</Col>
</Row>
<Search style={{marginBottom: 8}} placeholder="Search" onChange={onChange} allowClear={true}/>
<Scrollbars style={{height:(toolHeight-72)}} ref={sref}>
<Scrollbars style={{height: (toolHeight - 72)}} ref={sref}>
<DirectoryTree
multiple
onRightClick={handleContextMenu}
onSelect={onSelect}
switcherIcon={<DownOutlined/>}
treeData={loop(treeData)}
onExpand ={onExpand}
onExpand={onExpand}
autoExpandParent={autoExpandParent}
defaultExpandAll
expandedKeys={expandedKeys}
/>
{getNodeTreeRightClickMenu()}
{getEmpty()}
{updateCatalogueModalVisible? (
{updateCatalogueModalVisible ? (
<UpdateCatalogueForm
onSubmit={async (value) => {
const success = await handleAddOrUpdate(
isCreate?'/api/catalogue':'/api/catalogue/toRename',value);
isCreate ? '/api/catalogue' : '/api/catalogue/toRename', value);
if (success) {
handleUpdateCatalogueModalVisible(false);
setCatalogueFormValues({});
......@@ -495,10 +535,10 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
isCreate={isCreate}
/>
) : null}
{updateTaskModalVisible? (
{updateTaskModalVisible ? (
<SimpleTaskForm
onSubmit={async (value) => {
const datas = await handleAddOrUpdateWithResult('/api/catalogue/createTask',value);
const datas = await handleAddOrUpdateWithResult('/api/catalogue/createTask', value);
if (datas) {
handleUpdateTaskModalVisible(false);
setTaskFormValues({});
......@@ -516,18 +556,20 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
/>
) : null}
</Scrollbars>
<UploadModal visible={isUploadModalVisible} action={`/api/catalogue/upload/${uploadNodeId}`} handleOk={()=>{
<UploadModal visible={isUploadModalVisible} action={`/api/catalogue/upload/${uploadNodeId}`} handleOk={() => {
setIsUploadModalVisible(false);
setExpandedKeys(defaultExpandedKeys);
getTreeData();
}} onCancel={()=>{setIsUploadModalVisible(false)}} buttonTitle="上传zip包并创建工程" />
}} onCancel={() => {
setIsUploadModalVisible(false)
}} buttonTitle="上传zip包并创建工程"/>
</div>
);
};
export default connect(({Studio}: { Studio: StateType }) => ({
currentPath:Studio.currentPath,
currentPath: Studio.currentPath,
tabs: Studio.tabs,
rightClickMenu: Studio.rightClickMenu,
refs: Studio.refs,
......
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