You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@skywalking.apache.org by ha...@apache.org on 2018/01/29 07:25:51 UTC

[incubator-skywalking-ui] 02/02: Refactor page

This is an automated email from the ASF dual-hosted git repository.

hanahmily pushed a commit to branch feature/5.0.0
in repository https://gitbox.apache.org/repos/asf/incubator-skywalking-ui.git

commit e78dc70c7eb17d070ac3854562dc76f0090f916f
Author: hanahmily <ha...@gmail.com>
AuthorDate: Mon Jan 29 15:22:52 2018 +0800

    Refactor page
---
 src/main/frontend/.roadhogrc.mock.js               |   3 +-
 src/main/frontend/mock/application.js              |  10 +-
 .../frontend/src/components/Page/Panel/index.js    |  20 +++-
 src/main/frontend/src/models/application.js        |  56 ++---------
 src/main/frontend/src/models/global.js             |   8 +-
 .../frontend/src/routes/Application/Application.js | 110 +++++++++++----------
 src/main/frontend/src/utils/utils.js               |  99 +++++++++++++++++++
 7 files changed, 198 insertions(+), 108 deletions(-)

diff --git a/src/main/frontend/.roadhogrc.mock.js b/src/main/frontend/.roadhogrc.mock.js
index cf8d767..ac3c99b 100644
--- a/src/main/frontend/.roadhogrc.mock.js
+++ b/src/main/frontend/.roadhogrc.mock.js
@@ -5,7 +5,7 @@ import { getNotices } from './mock/notices';
 import { delay } from 'roadhog-api-doc';
 import { getDashboard } from './mock/dashboard';
 import { getTopology } from './mock/topology';
-import { getApplication } from './mock/application';
+import { getAllApplication, getApplication } from './mock/application';
 import { getServer } from './mock/server';
 import { getService } from './mock/service';
 import { getAlarm } from './mock/alarm';
@@ -19,6 +19,7 @@ const proxy = {
   // 支持值为 Object 和 Array
   'POST /api/dashboard': getDashboard,
   'POST /api/topology': getTopology,
+  'POST /api/application/all': getAllApplication,
   'POST /api/application': getApplication,
   'POST /api/server': getServer,
   'POST /api/service': getService,
diff --git a/src/main/frontend/mock/application.js b/src/main/frontend/mock/application.js
index 253d923..ac8369e 100644
--- a/src/main/frontend/mock/application.js
+++ b/src/main/frontend/mock/application.js
@@ -1,11 +1,19 @@
 import mockjs from 'mockjs';
 
 export default {
+  getAllApplication(req, res) {
+    res.json(mockjs.mock(
+      {
+        data: {
+          'applicationId|20-50': [{ 'key|+1': 3, label: function() { return `app-${this.key}`; } }],
+        },
+      }
+    ));
+  },
   getApplication(req, res) {
     res.json(mockjs.mock(
       {
         data: {
-          'getAllApplication|20-50': [{ 'key|+1': 3, name: function() { return `app-${this.key}`; } }],
           'getSlowService|10': [{ 'key|+1': 1, name: '@name', 'avgResponseTime|200-1000': 1 }],
           'getServerThroughput|10': [{ 'key|+1': 1, name: '@name', 'tps|100-10000': 1 }],
           getApplicationTopology: () => {
diff --git a/src/main/frontend/src/components/Page/Panel/index.js b/src/main/frontend/src/components/Page/Panel/index.js
index a3c630f..ba88752 100644
--- a/src/main/frontend/src/components/Page/Panel/index.js
+++ b/src/main/frontend/src/components/Page/Panel/index.js
@@ -2,17 +2,27 @@ import React, { Component } from 'react';
 
 export default class Panel extends Component {
   componentDidMount() {
-    const { duration, onDurationChange } = this.props;
-    onDurationChange(duration);
+    const { globalVariables, variables, onChange } = this.props;
+    if (!this.isRender(this.props)) {
+      return;
+    }
+    onChange({ ...globalVariables, ...variables });
   }
   shouldComponentUpdate(nextProps) {
-    const { duration, onDurationChange } = this.props;
-    if (duration !== nextProps.duration) {
-      onDurationChange(duration);
+    const { globalVariables, variables, onChange } = nextProps;
+    if (!this.isRender(nextProps)) {
+      return false;
+    }
+    if (globalVariables !== this.props.globalVariables || variables !== this.props.variables) {
+      onChange({ ...globalVariables, ...variables });
       return false;
     }
     return true;
   }
+  isRender = props => [props.variables, props.globalVariables]
+    .reduce((acc, curr) =>
+      (acc && (curr === undefined
+        || (curr !== undefined && Object.keys(curr).length > 0))), true);
   render() {
     const { children } = this.props;
     return children && (<div> {children} </div>);
diff --git a/src/main/frontend/src/models/application.js b/src/main/frontend/src/models/application.js
index 9faee98..85488d9 100644
--- a/src/main/frontend/src/models/application.js
+++ b/src/main/frontend/src/models/application.js
@@ -1,16 +1,15 @@
-import { generateBaseModal } from '../utils/utils';
-import { query as queryService } from '../services/graphql';
+import { generateModal } from '../utils/utils';
 
-const allAppQuery = `
-  query AllApplication($duration: Duration!) {
-    getAllApplication(duration: $duration) {
+const optionsQuery = `
+  query ApplicationOption($duration: Duration!) {
+    applicationId: getAllApplication(duration: $duration) {
       key: id
-      name
+      label: name
     }
   }
 `;
 
-const appQuery = `
+const dataQuery = `
   query Application($applicationId: ID!, $duration: Duration!) {
     getSlowService(applicationId: $applicationId, duration: $duration) {
       key: id
@@ -50,46 +49,8 @@ const appQuery = `
   }
 `;
 
-export default generateBaseModal({
+export default generateModal({
   namespace: 'application',
-  effects: {
-    *loadAllApp({ payload }, { call, put }) {
-      const { data: { getAllApplication: allApplication } } = yield call(queryService, 'application', { variables: payload, query: allAppQuery });
-      const applicationId = allApplication && allApplication.length > 0 && allApplication[0].key;
-      if (!applicationId) {
-        return;
-      }
-      yield put({
-        type: 'saveApplication',
-        payload: { allApplication, applicationId },
-      });
-      const response = yield put({
-        type: 'fetch',
-        payload: { variables: { ...payload, applicationId }, query: appQuery },
-      });
-      yield put({
-        type: 'save',
-        payload: response,
-      });
-    },
-  },
-  reducers: {
-    saveApplication(preState, action) {
-      const { applicationId } = preState;
-      const { allApplication, applicationId: newApplicationId } = action.payload;
-      if (allApplication.find(_ => _.key === applicationId)) {
-        return {
-          ...preState,
-          allApplication,
-        };
-      }
-      return {
-        ...preState,
-        allApplication,
-        applicationId: newApplicationId,
-      };
-    },
-  },
   state: {
     allApplication: [],
     getSlowService: [],
@@ -99,5 +60,6 @@ export default generateBaseModal({
       calls: [],
     },
   },
-  query: appQuery,
+  optionsQuery,
+  dataQuery,
 });
diff --git a/src/main/frontend/src/models/global.js b/src/main/frontend/src/models/global.js
index 311ff7c..831e1a1 100644
--- a/src/main/frontend/src/models/global.js
+++ b/src/main/frontend/src/models/global.js
@@ -64,11 +64,13 @@ export default {
       };
     },
     changeSelectedTime(state, { payload }) {
+      const duration = generateDuration(payload);
       return {
         ...state,
         selectedTime: payload,
-        duration: generateDuration(payload),
+        duration,
         isShowSelectTime: false,
+        globalVariables: { duration: duration.input },
       };
     },
     toggleSelectTime(state) {
@@ -79,9 +81,11 @@ export default {
     },
     reload(state) {
       const { selectedTime } = state;
+      const duration = generateDuration(selectedTime);
       return {
         ...state,
-        duration: generateDuration(selectedTime),
+        duration,
+        globalVariables: { duration: duration.input },
       };
     },
   },
diff --git a/src/main/frontend/src/routes/Application/Application.js b/src/main/frontend/src/routes/Application/Application.js
index 1b047af..ceff4e7 100644
--- a/src/main/frontend/src/routes/Application/Application.js
+++ b/src/main/frontend/src/routes/Application/Application.js
@@ -7,72 +7,74 @@ import { Panel } from '../../components/Page';
 const { Option } = Select;
 const { Item: FormItem } = Form;
 
+const tableColumns = [{
+  title: 'Name',
+  dataIndex: 'name',
+  key: 'name',
+}, {
+  title: 'Duration',
+  dataIndex: 'avgResponseTime',
+  key: 'avgResponseTime',
+}];
+
+const applicationThroughputColumns = [{
+  title: 'Name',
+  dataIndex: 'name',
+  key: 'name',
+}, {
+  title: 'Tps',
+  dataIndex: 'tps',
+  key: 'tps',
+}];
+
+const middleColResponsiveProps = {
+  xs: 24,
+  sm: 24,
+  md: 12,
+  lg: 12,
+  xl: 12,
+  style: { marginBottom: 24, marginTop: 24 },
+};
+
 @connect(state => ({
   application: state.application,
-  duration: state.global.duration,
+  globalVariables: state.global.globalVariables,
 }))
 @Form.create({
   mapPropsToFields(props) {
+    const { variables: { values, labels } } = props.application;
     return {
       applicationId: Form.createFormField({
-        value: props.application.applicationId,
+        value: { key: values.applicationId, label: labels.applicationId },
       }),
     };
   },
 })
 export default class Application extends PureComponent {
-  handleDurationChange = (duration) => {
+  componentDidMount() {
     this.props.dispatch({
-      type: 'application/loadAllApp',
-      payload: { duration },
+      type: 'application/initOptions',
+      payload: { variables: this.props.globalVariables },
     });
   }
-  handleChange = (applicationId) => {
+  handleSelect = (selected) => {
     this.props.dispatch({
-      type: 'application/fetchItem',
+      type: 'application/saveVariables',
       payload: {
-        variables:
-        {
-          applicationId,
-          duration: this.props.duration,
-        },
-        data:
-        {
-          applicationId,
-        },
+        values: { applicationId: selected.key },
+        labels: { applicationId: selected.label },
       },
     });
   }
+  handleChange = (variables) => {
+    this.props.dispatch({
+      type: 'application/fetchData',
+      payload: { variables },
+    });
+  }
   render() {
     const { getFieldDecorator } = this.props.form;
-    const tableColumns = [{
-      title: 'Name',
-      dataIndex: 'name',
-      key: 'name',
-    }, {
-      title: 'Duration',
-      dataIndex: 'avgResponseTime',
-      key: 'avgResponseTime',
-    }];
-
-    const applicationThroughputColumns = [{
-      title: 'Name',
-      dataIndex: 'name',
-      key: 'name',
-    }, {
-      title: 'Tps',
-      dataIndex: 'tps',
-      key: 'tps',
-    }];
-
-    const middleColResponsiveProps = {
-      xs: 24,
-      sm: 24,
-      md: 12,
-      lg: 12,
-      xl: 12,
-      style: { marginBottom: 24, marginTop: 24 },
-    };
+    const { variables: { values, options }, data } = this.props.application;
     return (
       <div>
         <Form layout="inline">
@@ -82,22 +84,26 @@ export default class Application extends PureComponent {
                 showSearch
                 style={{ width: 200 }}
                 placeholder="Select a application"
-                optionFilterProp="children"
-                onSelect={this.handleChange.bind(this)}
+                labelInValue
+                onSelect={this.handleSelect.bind(this)}
               >
-                {this.props.application.allApplication.map((app) => {
-                    return (<Option value={app.key}>{app.name}</Option>);
+                {options.applicationId && options.applicationId.map((app) => {
+                    return (<Option value={app.key}>{app.label}</Option>);
                   })}
               </Select>
             )}
           </FormItem>
         </Form>
-        <Panel duration={this.props.duration} onDurationChange={this.handleDurationChange}>
+        <Panel
+          variables={values}
+          globalVariables={this.props.globalVariables}
+          onChange={this.handleChange}
+        >
           <Card
             bordered={false}
             bodyStyle={{ padding: 0, marginTop: 24 }}
           >
-            <AppTopology elements={this.props.application.getApplicationTopology} layout={{ name: 'concentric', minNodeSpacing: 200 }} />
+            <AppTopology elements={data.getApplicationTopology} layout={{ name: 'concentric', minNodeSpacing: 200 }} />
           </Card>
           <Row gutter={24}>
             <Col {...middleColResponsiveProps}>
@@ -109,7 +115,7 @@ export default class Application extends PureComponent {
                 <Table
                   size="small"
                   columns={tableColumns}
-                  dataSource={this.props.application.getSlowService}
+                  dataSource={data.getSlowService}
                   pagination={{
                     style: { marginBottom: 0 },
                     pageSize: 10,
@@ -126,7 +132,7 @@ export default class Application extends PureComponent {
                 <Table
                   size="small"
                   columns={applicationThroughputColumns}
-                  dataSource={this.props.application.getServerThroughput}
+                  dataSource={data.getServerThroughput}
                   pagination={{
                     style: { marginBottom: 0 },
                     pageSize: 10,
diff --git a/src/main/frontend/src/utils/utils.js b/src/main/frontend/src/utils/utils.js
index ee0bac3..43a024a 100644
--- a/src/main/frontend/src/utils/utils.js
+++ b/src/main/frontend/src/utils/utils.js
@@ -161,3 +161,102 @@ export function generateBaseModal({ namespace, query, state, effects = {}, reduc
     },
   };
 }
+
+export function generateModal({ namespace, dataQuery, optionsQuery, state = {} }) {
+  return {
+    namespace,
+    state: {
+      variables: {
+        values: {},
+        labels: {},
+        options: {},
+      },
+      data: state,
+    },
+    effects: {
+      *initOptions({ payload }, { call, put }) {
+        const { variables } = payload;
+        const response = yield call(queryService, `${namespace}/all`, { variables, query: optionsQuery });
+        yield put({
+          type: 'saveOptions',
+          payload: response.data,
+        });
+      },
+      *fetchData({ payload }, { call, put }) {
+        const { variables } = payload;
+        const response = yield call(queryService, namespace, { variables, query: dataQuery });
+        yield put({
+          type: 'saveData',
+          payload: response.data,
+        });
+      },
+    },
+    reducers: {
+      saveOptions(preState, { payload: allOptions }) {
+        const { variables } = preState;
+        const { values, labels, options } = variables;
+        const amendOptions = {};
+        const defaultValues = {};
+        const defaultLabels = {};
+        Object.keys(allOptions).forEach((_) => {
+          const thisOptions = allOptions[_];
+          if (!values[_] && thisOptions.length > 0) {
+            defaultValues[_] = thisOptions[0].key;
+            defaultLabels[_] = thisOptions[0].label;
+          }
+          const key = values[_];
+          if (!thisOptions.find(o => o.key === key)) {
+            amendOptions[_] = [...thisOptions, { key, label: labels[_] }];
+          }
+        });
+        return {
+          ...preState,
+          variables: {
+            ...variables,
+            options: {
+              ...options,
+              ...allOptions,
+              ...amendOptions,
+            },
+            values: {
+              ...values,
+              ...defaultValues,
+            },
+            labels: {
+              ...labels,
+              ...defaultLabels,
+            },
+          },
+        };
+      },
+      saveData(preState, { payload }) {
+        const { data } = preState;
+        return {
+          ...preState,
+          data: {
+            ...data,
+            ...payload,
+          },
+        };
+      },
+      saveVariables(preState, { payload: { values: variableValues, labels = {} } }) {
+        const { variables: preVariables } = preState;
+        const { values: preValues, lables: preLabels } = preVariables;
+        return {
+          ...preState,
+          variables: {
+            ...preVariables,
+            values: {
+              ...preValues,
+              ...variableValues,
+            },
+            labels: {
+              ...preLabels,
+              ...labels,
+            },
+          },
+        };
+      },
+    },
+  };
+}

-- 
To stop receiving notification emails like this one, please contact
hanahmily@apache.org.