diff --git a/web/mock/datamanagement/pipeline.js b/web/mock/datamanagement/pipeline.js
new file mode 100644
index 00000000..9b2e587a
--- /dev/null
+++ b/web/mock/datamanagement/pipeline.js
@@ -0,0 +1,101 @@
+var pipelineList = [{
+ name:"fix_locales",
+ desc: "test fix_locales",
+ processors: ` [
+ {
+ "set": {
+ "if": "ctx['locales'].empty",
+ "field": "locales",
+ "value": "en-en"
+ }
+ },
+ {
+ "set": {
+ "field": "reindexBatch",
+ "value": 3
+ }
+ },
+ {
+ "split": {
+ "field": "locales",
+ "separator": ","
+ }
+ }
+ ]`
+ },{
+ name:"fix_locales",
+ desc: "test fix_locales",
+ processors: ` [
+ {
+ "set": {
+ "if": "ctx['locales'].empty",
+ "field": "locales",
+ "value": "en-en"
+ }
+ },
+ {
+ "set": {
+ "field": "reindexBatch",
+ "value": 3
+ }
+ },
+ {
+ "split": {
+ "field": "locales",
+ "separator": ","
+ }
+ }
+ ]`
+ }];
+export default {
+ 'get /data/pipeline': function (req, res) {
+ res.json(pipelineList);
+ },
+ 'POST /data/pipeline/add': (req, res) => {
+ pipelineList.push(req.body);
+ setTimeout(() => {
+ res.send({ message: 'Ok' });
+ },2000);
+ },
+ 'PUT /data/pipeline/update': (req, res) => {
+ var targetIdx = -1;
+ pipelineList.forEach(function(p, i){
+ if(p.name == req.body.name){
+ targetIdx = i;
+ }
+ });
+ console.log(req.body);
+ if(targetIdx > -1) {
+ pipelineList[targetIdx] = req.body
+ setTimeout(() => {
+ res.send({ message: 'Ok' });
+ },2000);
+ return;
+ }
+ res.send({ message: 'Fail' });
+ },
+ //delete /data/pipeline/:name
+ 'POST /data/pipeline': (req, res) => {
+ var keys = req.body.key || [];
+ var hasDeleted = false;
+ for(let i=0; i< keys.length; i++){
+ var targetIdx = -1;
+ pipelineList.forEach(function(p, j){
+ if(keys[i] == p.name){
+ targetIdx = j;
+ }
+ });
+ if(targetIdx > -1) {
+ pipelineList.splice(targetIdx, 1);
+ hasDeleted = true;
+ }
+ }
+ if(hasDeleted) {
+ setTimeout(() => {
+ res.send({ message: 'Ok' });
+ },2000);
+ return;
+ }
+ res.send({ message: 'Fail' });
+ },
+ };
\ No newline at end of file
diff --git a/web/src/pages/DataManagement/IngestPipeline.js b/web/src/pages/DataManagement/IngestPipeline.js
index 0d238ed7..2834a035 100644
--- a/web/src/pages/DataManagement/IngestPipeline.js
+++ b/web/src/pages/DataManagement/IngestPipeline.js
@@ -1,80 +1,386 @@
-import React, { Component,Fragment } from 'react';
+import React, { PureComponent, Fragment } from 'react';
import { connect } from 'dva';
-import { Card,Form,Input, Select,Button } from 'antd';
-const { Option } = Select;
-import { formatMessage, FormattedMessage } from 'umi/locale';
-import DescriptionList from '@/components/DescriptionList';
-import styles from '../profile/AdvancedProfile.less';
-const { Description } = DescriptionList;
+import moment from 'moment';
+import {
+ Row,
+ Col,
+ Card,
+ Form,
+ Input,
+ Select,
+ Icon,
+ Button,
+ Dropdown,
+ Menu,
+ InputNumber,
+ DatePicker,
+ Modal,
+ message,
+ Badge,
+ Divider,
+ Steps,
+ Radio,
+} from 'antd';
+import StandardTable from '@/components/StandardTable';
+import PageHeaderWrapper from '@/components/PageHeaderWrapper';
+
+import styles from '../List/TableList.less';
+
const FormItem = Form.Item;
+const { Step } = Steps;
const { TextArea } = Input;
+const { Option } = Select;
+const getValue = obj =>
+ Object.keys(obj)
+ .map(key => obj[key])
+ .join(',');
+const statusMap = ['default', 'processing', 'success', 'error'];
+const status = ['关闭', '运行中', '已上线', '异常'];
-@connect(({ profile, loading }) => ({
- profile,
- loading: loading.effects['profile/fetchBasic'],
+const CreateForm = Form.create()(props => {
+ const { modalVisible, form, handleAdd, handleModalVisible } = props;
+ const okHandle = () => {
+ form.validateFields((err, fieldsValue) => {
+ if (err) return;
+ form.resetFields();
+ handleAdd(fieldsValue);
+ });
+ };
+ return (
+ handleModalVisible()}
+ >
+
+ {form.getFieldDecorator('name', {
+ rules: [{ required: true, message: '请输入至少五个字符的名称!', min: 5 }],
+ })()}
+
+
+ {form.getFieldDecorator('desc', {
+ rules: [{ required: false }],
+ })()}
+
+
+ {form.getFieldDecorator('processors', {
+ rules: [{ required: true }],
+ })()}
+
+
+ );
+});
+
+const UpdateForm = Form.create()(props => {
+ const { updateModalVisible, handleUpdateModalVisible, handleUpdate,values,form } = props;
+
+ const okHandle = () => {
+ form.validateFields((err, fieldsValue) => {
+ if (err) return;
+ form.resetFields();
+ handleUpdate(fieldsValue);
+ });
+ };
+
+ return (
+ handleUpdateModalVisible()}
+ >
+
+ {form.getFieldDecorator('name', {
+ initialValue: values.name,
+ rules: [{ required: true, message: '请输入至少五个字符的名称!', min: 5 }],
+ })()}
+
+
+ {form.getFieldDecorator('desc', {
+ initialValue: values.desc,
+ rules: [{ required: false }],
+ })()}
+
+
+ {form.getFieldDecorator('processors', {
+ initialValue: values.processors,
+ rules: [{ required: true }],
+ })()}
+
+
+ );
+});
+
+/* eslint react/no-multi-comp:0 */
+@connect(({ pipeline, loading }) => ({
+ pipeline,
+ loading: loading.models.pipeline,
}))
-
@Form.create()
-class IngestPipeline extends Component {
- state = {
- operationkey: 'tab1'
- };
+class IngestPipeline extends PureComponent {
+ state = {
+ modalVisible: false,
+ updateModalVisible: false,
+ expandForm: false,
+ selectedRows: [],
+ formValues: {},
+ updateFormValues: {},
+ };
+
+ columns = [
+ {
+ title: '名称',
+ dataIndex: 'name',
+ },
+ {
+ title: '描述',
+ dataIndex: 'desc',
+ },
+ {
+ title: '处理器',
+ dataIndex: 'processors',
+ ellipsis: true,
+ },
+ {
+ title: '操作',
+ render: (text, record) => (
+
+ this.handleUpdateModalVisible(true, record)}>编辑
+
+ {
+ this.state.selectedRows.push(record);
+ this.handleDeleteClick();
+ }}>删除
+
+ ),
+ },
+ ];
+
componentDidMount() {
const { dispatch } = this.props;
dispatch({
- type: 'profile/fetchBasic',
+ type: 'pipeline/fetch',
});
}
- onOperationTabChange = key => {
- this.setState({ operationkey: key });
- };
- handleSubmit = e => {
- const { dispatch, form } = this.props;
- e.preventDefault();
- form.validateFieldsAndScroll((err, values) => {
- if (!err) {
- dispatch({
- type: 'form/submitRegularForm',
- payload: values,
- });
- }
+
+ handleStandardTableChange = (pagination, filtersArg, sorter) => {
+ const { dispatch } = this.props;
+ const { formValues } = this.state;
+
+ const filters = Object.keys(filtersArg).reduce((obj, key) => {
+ const newObj = { ...obj };
+ newObj[key] = getValue(filtersArg[key]);
+ return newObj;
+ }, {});
+
+ const params = {
+ currentPage: pagination.current,
+ pageSize: pagination.pageSize,
+ ...formValues,
+ ...filters,
+ };
+ if (sorter.field) {
+ params.sorter = `${sorter.field}_${sorter.order}`;
+ }
+
+ dispatch({
+ type: 'pipeline/fetch',
+ payload: params,
});
};
- render() {
- const { operationkey } = this.state;
- const { submitting } = this.props;
+ handleFormReset = () => {
+ const { form, dispatch } = this.props;
+ form.resetFields();
+ this.setState({
+ formValues: {},
+ });
+ dispatch({
+ type: 'pipeline/fetch',
+ payload: {},
+ });
+ };
+
+ handleDeleteClick = e => {
+ const { dispatch } = this.props;
+ const { selectedRows } = this.state;
+
+ if (!selectedRows) return;
+ dispatch({
+ type: 'pipeline/delete',
+ payload: {
+ key: selectedRows.map(row => row.name),
+ },
+ callback: () => {
+ this.setState({
+ selectedRows: [],
+ });
+ },
+ });
+ };
+
+ handleSelectRows = rows => {
+ this.setState({
+ selectedRows: rows,
+ });
+ };
+
+ handleSearch = e => {
+ e.preventDefault();
+
+ const { dispatch, form } = this.props;
+
+ form.validateFields((err, fieldsValue) => {
+ if (err) return;
+
+ const values = {
+ ...fieldsValue,
+ updatedAt: fieldsValue.updatedAt && fieldsValue.updatedAt.valueOf(),
+ };
+
+ this.setState({
+ formValues: values,
+ });
+
+ dispatch({
+ type: 'rule/fetch',
+ payload: values,
+ });
+ });
+ };
+
+ handleModalVisible = flag => {
+ this.setState({
+ modalVisible: !!flag,
+ });
+ };
+
+ handleUpdateModalVisible = (flag, record) => {
+ this.setState({
+ updateModalVisible: !!flag,
+ updateFormValues: record || {},
+ });
+ };
+
+ handleAdd = fields => {
+ const { dispatch } = this.props;
+ dispatch({
+ type: 'pipeline/add',
+ payload: {
+ name: fields.name,
+ desc: fields.desc,
+ processors: fields.processors,
+ },
+ });
+
+ message.success('添加成功');
+ this.handleModalVisible();
+ };
+
+ handleUpdate = fields => {
+ const { dispatch } = this.props;
+ dispatch({
+ type: 'pipeline/update',
+ payload: {
+ name: fields.name,
+ desc: fields.desc,
+ processors: fields.processors,
+ },
+ });
+
+ message.success('修改成功');
+ this.handleUpdateModalVisible();
+ };
+
+ renderSimpleForm() {
const {
- form: { getFieldDecorator, getFieldValue },
+ form: { getFieldDecorator },
} = this.props;
- const formItemLayout = {
- labelCol: {
- xs: { span: 24 },
- sm: { span: 7 },
- },
- wrapperCol: {
- xs: { span: 24 },
- sm: { span: 12 },
- md: { span: 10 },
- },
- };
- const submitFormLayout = {
- wrapperCol: {
- xs: { span: 24, offset: 0 },
- sm: { span: 10, offset: 7 },
- },
- };
return (
-
-
- unimplement, waiting to do
-
-
+
+ );
+ }
+
+ renderForm() {
+ return this.renderSimpleForm();
+ }
+
+ render() {
+ let {pipeline, loading} = this.props;
+ const { selectedRows, modalVisible, updateModalVisible, updateFormValues } = this.state;
+ const parentMethods = {
+ handleAdd: this.handleAdd,
+ handleModalVisible: this.handleModalVisible,
+ };
+ const updateMethods = {
+ handleUpdateModalVisible: this.handleUpdateModalVisible,
+ handleUpdate: this.handleUpdate,
+ };
+ return (
+
+
+
+
{this.renderForm()}
+
+
+ {selectedRows.length > 0 && (
+
+
+
+ )}
+
+
+
+
+
+ {updateFormValues && Object.keys(updateFormValues).length ? (
+
+ ) : null}
+
);
}
}
diff --git a/web/src/pages/DataManagement/models/pipeline.js b/web/src/pages/DataManagement/models/pipeline.js
new file mode 100644
index 00000000..e5716d1b
--- /dev/null
+++ b/web/src/pages/DataManagement/models/pipeline.js
@@ -0,0 +1,95 @@
+import { message } from 'antd';
+import { getPipelines, addPipeline, updatePipeline,deletePipeline } from '@/services/datamanagement';
+
+export default {
+ namespace: 'pipeline',
+
+ state: {
+ datalist: {
+ list:[],
+ pagination:{
+ pageSize: 5,
+ }
+ },
+ },
+ effects: {
+ *fetch({payload}, {call, put}){
+ let idata = yield call(getPipelines);
+ yield put({
+ type:"initdata",
+ payload: idata,
+ });
+ },
+ *add({payload}, {call, put}){
+ const res = yield call(addPipeline, payload);
+ if(res.message == "Ok") {
+ yield put({
+ type: 'addNew',
+ payload: payload,
+ });
+ }
+ },
+ *update({payload}, {call, put}){
+ const res = yield call(updatePipeline, payload);
+ if(res.message == "Ok") {
+ yield put({
+ type: 'updateData',
+ payload: payload,
+ });
+ }
+ },
+ *delete({payload}, {call, put}){
+ const res = yield call(deletePipeline, payload);
+ console.log(res);
+ if(res.message == "Ok") {
+ yield put({
+ type: 'deleteData',
+ payload: payload,
+ });
+ }
+ },
+ },
+ reducers: {
+ initdata(state, {payload: newdata}){
+ return {
+ ...state,
+ datalist: {
+ ...state.datalist,
+ list: newdata,
+ },
+ };
+ },
+ addNew(state, {payload: newdata}){
+ state.datalist.list.push(newdata);
+ return state;
+ },
+ updateData(state, {payload: newdata}){
+ let targetIdx = -1;
+ state.datalist.list.forEach((p,i) => {
+ if(p.name == newdata.name){
+ targetIdx = i;
+ }
+ });
+ targetIdx > -1 && (state.datalist.list[targetIdx] = newdata);
+ return state;
+ },
+ deleteData(state, {payload: newdata}){
+ let pipelineList = state.datalist.list;
+ var keys = newdata.key || [];
+ var hasDeleted = false;
+ for(let i=0; i< keys.length; i++){
+ let targetIdx = -1;
+ pipelineList.forEach(function(p, j){
+ if(keys[i] == p.name){
+ targetIdx = j;
+ }
+ });
+ if(targetIdx > -1) {
+ pipelineList.splice(targetIdx, 1);
+ hasDeleted = true;
+ }
+ }
+ return state;
+ },
+ },
+};
diff --git a/web/src/services/datamanagement.js b/web/src/services/datamanagement.js
index 025627e0..4f2f0762 100644
--- a/web/src/services/datamanagement.js
+++ b/web/src/services/datamanagement.js
@@ -9,4 +9,30 @@ export async function saveLogstashConfig(config){
method: 'POST',
body: config,
});
-}
\ No newline at end of file
+}
+
+// pipeline
+export async function getPipelines(params){
+ return request('/data/pipeline');
+}
+
+export async function addPipeline(params){
+ return request('/data/pipeline/add', {
+ method: 'POST',
+ body: params,
+ });
+}
+
+export async function updatePipeline(params){
+ return request('/data/pipeline/update', {
+ method: 'PUT',
+ body: params,
+ });
+}
+export async function deletePipeline(params){
+ return request('/data/pipeline', {
+ method: 'POST',
+ body: params,
+ });
+}
+//end pipeline
\ No newline at end of file