Commit 5db8eb72 authored by wenmo's avatar wenmo

集群和数据源的studio交互

parent 242166a0
package com.dlink.controller;
import com.dlink.api.FlinkAPI;
import com.dlink.assertion.Asserts;
import com.dlink.cluster.FlinkClusterInfo;
import com.dlink.common.result.ProTableResult;
import com.dlink.common.result.Result;
......@@ -35,7 +36,7 @@ public class ClusterController {
public Result saveOrUpdate(@RequestBody Cluster cluster) throws Exception {
cluster.setAutoRegisters(false);
clusterService.registersCluster(cluster);
return Result.succeed("新增成功");
return Result.succeed(Asserts.isNotNull(cluster.getId())?"修改成功":"新增成功");
}
/**
......
import {
message, Button, Table, Empty, Divider,
Tooltip, Drawer
Tooltip, Drawer, Modal
} from "antd";
import ProDescriptions from '@ant-design/pro-descriptions';
import {StateType} from "@/pages/FlinkSqlStudio/model";
......@@ -13,15 +13,18 @@ import {
} from '@ant-design/icons';
import React from "react";
import {showCluster} from "../../StudioEvent/DDL";
import {handleAddOrUpdate} from "@/components/Common/crud";
import {handleAddOrUpdate, handleRemove} from "@/components/Common/crud";
import ClusterForm from "@/pages/Cluster/components/ClusterForm";
import {Scrollbars} from 'react-custom-scrollbars';
const url = '/api/cluster';
const StudioCluster = (props: any) => {
const {cluster, toolHeight, dispatch} = props;
const [createModalVisible, handleCreateModalVisible] = useState<boolean>(false);
const [row, setRow] = useState<{}>();
const [updateModalVisible, handleUpdateModalVisible] = useState<boolean>(false);
const [row, setRow] = useState<{}>({});
const getColumns = () => {
return [{
......@@ -37,20 +40,18 @@ const StudioCluster = (props: any) => {
const getAllColumns = () => {
return [{
title: "集群名",
dataIndex: "alias",
key: "alias",
title: "ID",
dataIndex: "id",
key: "id",
}, {
title: '名称',
title: '唯一标识',
dataIndex: 'name',
}, {
title: "集群名",
dataIndex: "alias",
},
{
title: '集群ID',
dataIndex: 'id',
},
{
title: '类型',
sorter: true,
dataIndex: 'type',
filters: [
{
......@@ -69,6 +70,14 @@ const StudioCluster = (props: any) => {
text: 'Yarn Application',
value: 'yarn-application',
},
{
text: 'Kubernetes Session',
value: 'kubernetes-session',
},
{
text: 'Kubernetes Application',
value: 'kubernetes-application',
},
],
filterMultiple: false,
valueEnum: {
......@@ -76,21 +85,20 @@ const StudioCluster = (props: any) => {
'standalone': {text: 'Standalone'},
'yarn-per-job': {text: 'Yarn Per-Job'},
'yarn-application': {text: 'Yarn Application'},
'kubernetes-session': {text: 'Kubernetes Session'},
'kubernetes-application': {text: 'Kubernetes Application'},
},
},
{
title: 'JobManager HA 地址',
sorter: true,
dataIndex: 'hosts',
valueType: 'textarea',
},
{
title: '当前 JobManager 地址',
sorter: true,
dataIndex: 'jobManagerHost',
}, {
title: '版本',
sorter: true,
dataIndex: 'version',
},
{
......@@ -114,7 +122,6 @@ const StudioCluster = (props: any) => {
},
{
title: '注释',
sorter: true,
valueType: 'textarea',
dataIndex: 'note',
},
......@@ -156,6 +163,13 @@ const StudioCluster = (props: any) => {
false: {text: '手动', status: 'Error'},
},
},
{
title: '集群配置ID',
dataIndex: 'clusterConfigurationId',
},{
title: '作业ID',
dataIndex: 'taskId',
},
{
title: '创建时间',
dataIndex: 'createTime',
......@@ -171,19 +185,11 @@ const StudioCluster = (props: any) => {
dataIndex: 'option',
valueType: 'option',
render: (_, record) => [
<a
onClick={() => {
message.success('敬请期待');
}}
>
详情
</a>, <Divider type="vertical"/>, <a
onClick={() => {
message.success('敬请期待');
}}
>
管理
</a>
<Button type="dashed" onClick={() => onModifyCluster(record)}>
配置
</Button>, <Button danger onClick={() => onDeleteCluster(record)}>
删除
</Button>
],
},];
};
......@@ -196,6 +202,25 @@ const StudioCluster = (props: any) => {
handleCreateModalVisible(true);
};
const onModifyCluster = (record) => {
setRow(record);
handleUpdateModalVisible(true);
};
const onDeleteCluster = (record) => {
Modal.confirm({
title: '删除集群',
content: `确定删除该集群【${record.alias}】吗?`,
okText: '确认',
cancelText: '取消',
onOk: async () => {
await handleRemove(url, [record]);
setRow({});
onRefreshCluster();
}
});
};
return (
<>
<Tooltip title="新建 Flink 集群">
......@@ -228,12 +253,28 @@ const StudioCluster = (props: any) => {
handleCreateModalVisible(false);
}}
modalVisible={createModalVisible}
values={{}}
/>
{row && Object.keys(row).length ? (<ClusterForm
onSubmit={async (value) => {
const success = await handleAddOrUpdate("api/cluster", value);
if (success) {
handleUpdateModalVisible(false);
setRow({});
onRefreshCluster();
}
}}
onCancel={() => {
handleUpdateModalVisible(false);
}}
modalVisible={updateModalVisible}
values={row}
/>):undefined}
<Drawer
width={600}
visible={!!row}
visible={!!row?.id}
onClose={() => {
setRow(undefined);
setRow({});
}}
closable={false}
>
......
import {
message, Button,Table, Empty, Divider,
Tooltip
message, Button, Table, Empty, Divider,
Tooltip, Drawer, Modal
} from "antd";
import {StateType} from "@/pages/FlinkSqlStudio/model";
import {connect} from "umi";
......@@ -14,40 +14,159 @@ import React from "react";
import {showDataBase} from "../../StudioEvent/DDL";
import DBForm from "@/pages/DataBase/components/DBForm";
import { Scrollbars } from 'react-custom-scrollbars';
import ProDescriptions from "@ant-design/pro-descriptions";
import {handleRemove} from "@/components/Common/crud";
const StudioDataBase = (props: any) => {
const {database,toolHeight, dispatch} = props;
const [chooseDBModalVisible, handleDBFormModalVisible] = useState<boolean>(false);
const [values, setValues] = useState<any>({});
const [row, setRow] = useState<{}>();
const getColumns = () => {
let columns: any = [{
return [{
title: "数据源名",
dataIndex: "alias",
key: "alias",
sorter: true,
render: (dom, entity) => {
return <a onClick={() => setRow(entity)}>{dom}</a>;
},
}];
};
const getAllColumns = () => {
return [{
title: "ID",
dataIndex: "id",
key: "id",
},{
title: "数据源名",
dataIndex: "alias",
}, {
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => [
<a
onClick={() => {
message.success('敬请期待');
}}
>
详情
</a>, <Divider type="vertical"/>, <a
onClick={() => {
message.success('敬请期待');
}}
>
管理
</a>
],
},];
return columns;
title: '唯一标识',
dataIndex: 'name',
},
{
title: '分组类型',
dataIndex: 'groupName',
filters: [
{
text: '来源',
value: '来源',
},
{
text: '数仓',
value: '数仓',
},
{
text: '应用',
value: '应用',
},
{
text: '备份',
value: '备份',
},{
text: '其他',
value: '其他',
},
],
filterMultiple: false,
valueEnum: {
'yarn-session': {text: 'Yarn Session'},
'standalone': {text: 'Standalone'},
'yarn-per-job': {text: 'Yarn Per-Job'},
'yarn-application': {text: 'Yarn Application'},
},
},
{
title: 'URL',
dataIndex: 'url',
valueType: 'textarea',
},
{
title: '用户名',
dataIndex: 'username',
}, {
title: '版本',
sorter: true,
dataIndex: 'dbVersion',
},
{
title: '状态',
dataIndex: 'status',
filters: [
{
text: '正常',
value: 1,
},
{
text: '异常',
value: 0,
},
],
filterMultiple: false,
valueEnum: {
1: {text: '正常', status: 'Success'},
0: {text: '异常', status: 'Error'},
},
},
{
title: '注释',
sorter: true,
valueType: 'textarea',
dataIndex: 'note',
},
{
title: '是否启用',
dataIndex: 'enabled',
filters: [
{
text: '已启用',
value: 1,
},
{
text: '已禁用',
value: 0,
},
],
filterMultiple: false,
valueEnum: {
true: {text: '已启用', status: 'Success'},
false: {text: '已禁用', status: 'Error'},
},
},
{
title: '最近的健康时间',
dataIndex: 'healthTime',
valueType: 'dateTime',
},{
title: '最近的心跳检测时间',
dataIndex: 'heartbeatTime',
valueType: 'dateTime',
},{
title: '创建时间',
dataIndex: 'createTime',
valueType: 'dateTime',
},
{
title: '最近更新时间',
dataIndex: 'updateTime',
valueType: 'dateTime',
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => [
<Button type="dashed" onClick={() => onModifyDataBase(record)}>
配置
</Button>, <Button danger onClick={() => onDeleteDataBase(record)}>
删除
</Button>
],
},];
};
const onRefreshDataBase = () => {
......@@ -59,6 +178,25 @@ const StudioDataBase = (props: any) => {
handleDBFormModalVisible(true);
};
const onModifyDataBase = (record) => {
setValues(record);
handleDBFormModalVisible(true);
};
const onDeleteDataBase = (record) => {
Modal.confirm({
title: '删除数据源',
content: `确定删除该数据源【${record.alias}】吗?`,
okText: '确认',
cancelText: '取消',
onOk: async () => {
await handleRemove('api/database', [record]);
setRow({});
onRefreshDataBase();
}
});
};
return (
<>
<Tooltip title="新建数据源">
......@@ -86,10 +224,33 @@ const StudioDataBase = (props: any) => {
}}
modalVisible={chooseDBModalVisible}
onSubmit={() => {
showDataBase(dispatch);
setRow({});
onRefreshDataBase();
}}
values={values}
/>
<Drawer
width={600}
visible={!!row?.id}
onClose={() => {
setRow(undefined);
}}
closable={false}
>
{row?.name && (
<ProDescriptions
column={2}
title={row?.name}
request={async () => ({
data: row || {},
})}
params={{
id: row?.name,
}}
columns={getAllColumns()}
/>
)}
</Drawer>
</Scrollbars>
</>
);
......
......@@ -238,11 +238,11 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
}
};
const toDelete= (node:TreeDataNode|undefined)=>{
const toDelete= (node: TreeDataNode|undefined)=>{
let label = (node?.taskId==null)?'目录':'作业';
Modal.confirm({
title: `删除${label}`,
content: `确定删除该${label}吗?`,
content: `确定删除该${label}${node?.name}吗?`,
okText: '确认',
cancelText: '取消',
onOk:async () => {
......
import React, {useEffect, useState} from 'react';
import {Form, Button, Input, Modal, Select} from 'antd';
import {Form, Button, Input, Modal, Select, Switch} from 'antd';
import {ClusterTableListItem} from "@/pages/Cluster/data";
......@@ -7,6 +7,7 @@ export type ClusterFormProps = {
onCancel: (flag?: boolean) => void;
onSubmit: (values: Partial<ClusterTableListItem>) => void;
modalVisible: boolean;
values: Partial<ClusterTableListItem>;
};
const Option = Select.Option;
......@@ -18,6 +19,15 @@ const formLayout = {
const ClusterForm: React.FC<ClusterFormProps> = (props) => {
const [form] = Form.useForm();
const [formVals, setFormVals] = useState<Partial<ClusterTableListItem>>({
id: props.values.id,
name: props.values.name,
alias: props.values.alias,
type: props.values.type,
hosts: props.values.hosts,
note: props.values.note,
enabled: props.values.enabled,
});
const {
onSubmit: handleSubmit,
......@@ -27,10 +37,12 @@ const ClusterForm: React.FC<ClusterFormProps> = (props) => {
const submitForm = async () => {
const fieldsValue = await form.validateFields();
fieldsValue.id= formVals.id;
setFormVals(fieldsValue);
handleSubmit(fieldsValue);
};
const renderContent = () => {
const renderContent = (formValsPara: Partial<ClusterTableListItem>) => {
return (
<>
<Form.Item
......@@ -73,6 +85,12 @@ const ClusterForm: React.FC<ClusterFormProps> = (props) => {
<Input.TextArea placeholder="请输入文本注释" allowClear
autoSize={{minRows: 3, maxRows: 10}}/>
</Form.Item>
<Form.Item
name="enabled"
label="是否启用">
<Switch checkedChildren="启用" unCheckedChildren="禁用"
defaultChecked={formValsPara.enabled}/>
</Form.Item>
</>
);
};
......@@ -93,7 +111,7 @@ const ClusterForm: React.FC<ClusterFormProps> = (props) => {
width={640}
bodyStyle={{padding: '32px 40px 48px'}}
destroyOnClose
title="创建集群"
title={formVals.id?"修改集群":"创建集群"}
visible={modalVisible}
footer={renderFooter()}
onCancel={() => handleModalVisible()}
......@@ -101,8 +119,9 @@ const ClusterForm: React.FC<ClusterFormProps> = (props) => {
<Form
{...formLayout}
form={form}
initialValues={formVals}
>
{renderContent()}
{renderContent(formVals)}
</Form>
</Modal>
);
......
......@@ -520,6 +520,9 @@ export default (): React.ReactNode => {
<li>
<Link>新增 FlinkSQL 及 SQL 导出</Link>
</li>
<li>
<Link>新增 集群与数据源的 Studio 管理交互</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