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/05/24 03:59:24 UTC
[incubator-skywalking-ui] branch 5.0.0/beta2 updated: Add
application selection to service page
This is an automated email from the ASF dual-hosted git repository.
hanahmily pushed a commit to branch 5.0.0/beta2
in repository https://gitbox.apache.org/repos/asf/incubator-skywalking-ui.git
The following commit(s) were added to refs/heads/5.0.0/beta2 by this push:
new 0e2e237 Add application selection to service page
0e2e237 is described below
commit 0e2e237e25b70cf9c23177bdb3b123ed7111b80a
Author: hanahmily <ha...@gmail.com>
AuthorDate: Thu May 24 11:52:50 2018 +0800
Add application selection to service page
---
.roadhogrc.mock.js | 1 +
mock/service.js | 2 +-
src/components/Page/Search/index.js | 9 +-
src/models/service.js | 27 ++++-
src/routes/Service/Service.js | 231 +++++++++++++++++++++++-------------
src/utils/models.js | 111 ++++++++---------
6 files changed, 245 insertions(+), 136 deletions(-)
diff --git a/.roadhogrc.mock.js b/.roadhogrc.mock.js
index 36ec6a0..436a0e2 100644
--- a/.roadhogrc.mock.js
+++ b/.roadhogrc.mock.js
@@ -19,6 +19,7 @@ const proxy = {
'POST /api/server': getServer,
'POST /api/service/search': searchService,
'POST /api/service': getService,
+ 'POST /api/service/options': getAllApplication,
'POST /api/alarm': getAlarm,
'POST /api/notice': getNoticeAlarm,
'POST /api/trace/options': getAllApplicationForTrace,
diff --git a/mock/service.js b/mock/service.js
index 9c23a21..dcb37f4 100644
--- a/mock/service.js
+++ b/mock/service.js
@@ -44,7 +44,7 @@ export default {
{
'traces|20': [{
key: '@id',
- operationName: '@url(200)',
+ operationName: '200://wgmb.ev/jcknolzq',
duration: () => {
duration -= 100;
return duration;
diff --git a/src/components/Page/Search/index.js b/src/components/Page/Search/index.js
index 9f0026a..a7060a8 100644
--- a/src/components/Page/Search/index.js
+++ b/src/components/Page/Search/index.js
@@ -35,7 +35,14 @@ export default class Search extends PureComponent {
fetching: false,
}
componentDidMount() {
- this.originFetchServer('', !this.props.value.key);
+ if (this.props.variables && Object.keys(this.props.variables).length > 0) {
+ this.originFetchServer('', true);
+ }
+ }
+ componentDidUpdate(prevProps) {
+ if (prevProps.variables !== this.props.variables) {
+ this.originFetchServer('', true);
+ }
}
fetchServer = (value, isSelectOne) => {
if (value === undefined) {
diff --git a/src/models/service.js b/src/models/service.js
index e25065b..0d47fbe 100644
--- a/src/models/service.js
+++ b/src/models/service.js
@@ -16,9 +16,18 @@
*/
-import { generateModal } from '../utils/models';
+import { generateModal, saveOptionsInState } from '../utils/models';
import { query } from '../services/graphql';
+const optionsQuery = `
+ query ApplicationOption($duration: Duration!) {
+ applicationId: getAllApplication(duration: $duration) {
+ key: id
+ label: name
+ }
+ }
+`;
+
const dataQuery = `
query Service($serviceId: ID!, $duration: Duration!, $traceCondition: TraceQueryCondition!) {
getServiceResponseTimeTrend(serviceId: $serviceId, duration: $duration) {
@@ -124,6 +133,7 @@ export default generateModal({
},
},
dataQuery,
+ optionsQuery,
effects: {
*fetchSpans({ payload }, { call, put }) {
const response = yield call(query, 'spans', { query: spanQuery, variables: payload.variables });
@@ -147,6 +157,21 @@ export default generateModal({
},
};
},
+ saveAppInfo(preState, { payload: allOptions }) {
+ const rawState = saveOptionsInState(null, preState, { payload: allOptions });
+ const { data } = rawState;
+ if (data.appInfo) {
+ return rawState;
+ }
+ const { variables: { values } } = rawState;
+ return {
+ ...rawState,
+ data: {
+ ...data,
+ appInfo: { applicationId: values.applicationId },
+ },
+ };
+ },
hideTimeline(state) {
const { data } = state;
return {
diff --git a/src/routes/Service/Service.js b/src/routes/Service/Service.js
index dff6946..82ac1c5 100644
--- a/src/routes/Service/Service.js
+++ b/src/routes/Service/Service.js
@@ -18,7 +18,7 @@
import React, { PureComponent } from 'react';
import { connect } from 'dva';
-import { Row, Col, Form, Button, Icon } from 'antd';
+import { Row, Col, Form, Button, Icon, Select } from 'antd';
import {
ChartCard, MiniArea, MiniBar, Sankey,
} from '../../components/Charts';
@@ -29,16 +29,21 @@ import TraceList from '../../components/Trace/TraceList';
import TraceTimeline from '../Trace/TraceTimeline';
const { Item: FormItem } = Form;
+const { Option } = Select;
@connect(state => ({
service: state.service,
duration: state.global.duration,
globalVariables: state.global.globalVariables,
+ loading: state.loading.models.service,
}))
@Form.create({
mapPropsToFields(props) {
const { variables: { values, labels } } = props.service;
return {
+ applicationId: Form.createFormField({
+ value: { key: values.applicationId ? values.applicationId : '', label: labels.applicationId ? labels.applicationId : '' },
+ }),
serviceId: Form.createFormField({
value: { key: values.serviceId ? values.serviceId : '', label: labels.serviceId ? labels.serviceId : '' },
}),
@@ -46,6 +51,35 @@ const { Item: FormItem } = Form;
},
})
export default class Service extends PureComponent {
+ componentDidMount() {
+ this.props.dispatch({
+ type: 'service/initOptions',
+ payload: { variables: this.props.globalVariables, reducer: 'saveAppInfo' },
+ });
+ }
+ componentWillUpdate(nextProps) {
+ if (nextProps.globalVariables.duration === this.props.globalVariables.duration) {
+ return;
+ }
+ this.props.dispatch({
+ type: 'service/initOptions',
+ payload: { variables: nextProps.globalVariables, reducer: 'saveAppInfo' },
+ });
+ }
+ handleAppSelect = (selected) => {
+ this.props.dispatch({
+ type: 'service/save',
+ payload: {
+ variables: {
+ values: { applicationId: selected.key, serviceId: null },
+ labels: { applicationId: selected.label, serviceId: null },
+ },
+ data: {
+ appInfo: { applicationId: selected.key },
+ },
+ },
+ });
+ }
handleSelect = (selected) => {
this.props.dispatch({
type: 'service/save',
@@ -61,13 +95,21 @@ export default class Service extends PureComponent {
});
}
handleChange = (variables) => {
+ const { variables: { values } } = this.props.service;
+ if (!values.applicationId) {
+ return;
+ }
+ const { key: serviceId, label: serviceName } = variables;
+ if (!serviceId) {
+ return;
+ }
this.props.dispatch({
type: 'service/fetchData',
payload: { variables: {
- ...variables,
+ serviceId,
traceCondition: {
- applicationId: 1,
- operationName: '',
+ applicationId: values.applicationId,
+ operationName: serviceName,
queryDuration: variables.duration,
paging: {
pageNum: 1,
@@ -91,6 +133,75 @@ export default class Service extends PureComponent {
});
}
edgeWith = edge => edge.cpm * edge.avgResponseTime;
+ renderPanel = () => {
+ const { service, duration } = this.props;
+ const { variables: { values }, data } = service;
+ const { getServiceResponseTimeTrend, getServiceThroughputTrend,
+ getServiceSLATrend, getServiceTopology, getTrace } = data;
+ if (!values.serviceId) {
+ return null;
+ }
+ return (
+ <Panel
+ variables={data.serviceInfo}
+ globalVariables={this.props.globalVariables}
+ onChange={this.handleChange}
+ >
+ <Row gutter={8}>
+ <Col xs={24} sm={24} md={24} lg={8} xl={8} style={{ marginTop: 8 }}>
+ <ChartCard
+ title="Avg Throughput"
+ total={`${avgTimeSeries(getServiceThroughputTrend.trendList)} cpm`}
+ contentHeight={46}
+ >
+ <MiniArea
+ color="#975FE4"
+ data={axis(duration, getServiceThroughputTrend.trendList)}
+ />
+ </ChartCard>
+ </Col>
+ <Col xs={24} sm={24} md={24} lg={8} xl={8} style={{ marginTop: 8 }}>
+ <ChartCard
+ title="Avg Response Time"
+ total={`${avgTimeSeries(getServiceResponseTimeTrend.trendList)} ms`}
+ contentHeight={46}
+ >
+ <MiniArea
+ data={axis(duration, getServiceResponseTimeTrend.trendList)}
+ />
+ </ChartCard>
+ </Col>
+ <Col xs={24} sm={24} md={24} lg={8} xl={8} style={{ marginTop: 8 }}>
+ <ChartCard
+ title="Avg SLA"
+ total={`${(avgTimeSeries(getServiceSLATrend.trendList) / 100).toFixed(2)} %`}
+ >
+ <MiniBar
+ animate={false}
+ height={46}
+ data={axis(duration, getServiceSLATrend.trendList,
+ ({ x, y }) => ({ x, y: y / 100 }))}
+ />
+ </ChartCard>
+ </Col>
+ </Row>
+ <Row gutter={8}>
+ <Col xs={24} sm={24} md={24} lg={24} xl={24} style={{ marginTop: 8 }}>
+ <ChartCard
+ title="Top 20 Slow Traces"
+ >
+ <TraceList
+ data={getTrace.traces}
+ onClickTraceTag={this.handleShowTrace}
+ loading={this.props.loading}
+ />
+ </ChartCard>
+ </Col>
+ </Row>
+ {this.renderSankey(getServiceTopology)}
+ </Panel>
+ );
+ }
renderSankey = (data) => {
if (data.nodes.length < 2) {
return <span style={{ display: 'none' }} />;
@@ -126,12 +237,10 @@ export default class Service extends PureComponent {
</Row>);
}
render() {
- const { form, service, duration } = this.props;
+ const { form, service } = this.props;
const { getFieldDecorator } = form;
- const { variables: { values }, data } = service;
- const { getServiceResponseTimeTrend, getServiceThroughputTrend,
- getServiceSLATrend, getServiceTopology, getTrace,
- showTimeline, queryTrace, currentTraceId } = data;
+ const { variables: { options }, data } = service;
+ const { showTimeline, queryTrace, currentTraceId } = data;
return (
<div>
{showTimeline ? (
@@ -147,80 +256,42 @@ export default class Service extends PureComponent {
<Col span={showTimeline ? 0 : 24}>
<Form layout="inline">
<FormItem>
- {getFieldDecorator('serviceId')(
- <Search
- placeholder="Search a service"
- onSelect={this.handleSelect.bind(this)}
- url="/service/search"
- query={`
- query SearchService($keyword: String!) {
- searchService(keyword: $keyword, topN: 10) {
- key: id
- label: name
- }
- }
- `}
- />
+ {getFieldDecorator('applicationId')(
+ <Select
+ showSearch
+ optionFilterProp="children"
+ style={{ width: 200 }}
+ placeholder="Select a application"
+ labelInValue
+ onSelect={this.handleAppSelect.bind(this)}
+ >
+ {options.applicationId && options.applicationId.map(app =>
+ <Option key={app.key} value={app.key}>{app.label}</Option>)}
+ </Select>
)}
</FormItem>
- </Form>
- <Panel
- variables={values}
- globalVariables={this.props.globalVariables}
- onChange={this.handleChange}
- >
- <Row gutter={8}>
- <Col xs={24} sm={24} md={24} lg={8} xl={8} style={{ marginTop: 8 }}>
- <ChartCard
- title="Avg Throughput"
- total={`${avgTimeSeries(getServiceThroughputTrend.trendList)} cpm`}
- contentHeight={46}
- >
- <MiniArea
- color="#975FE4"
- data={axis(duration, getServiceThroughputTrend.trendList)}
- />
- </ChartCard>
- </Col>
- <Col xs={24} sm={24} md={24} lg={8} xl={8} style={{ marginTop: 8 }}>
- <ChartCard
- title="Avg Response Time"
- total={`${avgTimeSeries(getServiceResponseTimeTrend.trendList)} ms`}
- contentHeight={46}
- >
- <MiniArea
- data={axis(duration, getServiceResponseTimeTrend.trendList)}
- />
- </ChartCard>
- </Col>
- <Col xs={24} sm={24} md={24} lg={8} xl={8} style={{ marginTop: 8 }}>
- <ChartCard
- title="Avg SLA"
- total={`${(avgTimeSeries(getServiceSLATrend.trendList) / 100).toFixed(2)} %`}
- >
- <MiniBar
- animate={false}
- height={46}
- data={axis(duration, getServiceSLATrend.trendList,
- ({ x, y }) => ({ x, y: y / 100 }))}
- />
- </ChartCard>
- </Col>
- </Row>
- <Row gutter={8}>
- <Col xs={24} sm={24} md={24} lg={24} xl={24} style={{ marginTop: 8 }}>
- <ChartCard
- title="Top 20 Slow Traces"
- >
- <TraceList
- data={getTrace.traces}
- onClickTraceTag={this.handleShowTrace}
+ {data.appInfo ? (
+ <FormItem>
+ {getFieldDecorator('serviceId')(
+ <Search
+ placeholder="Search a service"
+ onSelect={this.handleSelect.bind(this)}
+ url="/service/search"
+ variables={data.appInfo}
+ query={`
+ query SearchService($applicationId: ID!, $keyword: String!) {
+ searchService(applicationId: $applicationId, keyword: $keyword, topN: 10) {
+ key: id
+ label: name
+ }
+ }
+ `}
/>
- </ChartCard>
- </Col>
- </Row>
- {this.renderSankey(getServiceTopology)}
- </Panel>
+ )}
+ </FormItem>
+ ) : null}
+ </Form>
+ {this.renderPanel()}
</Col>
<Col span={showTimeline ? 24 : 0}>
{showTimeline ? (
diff --git a/src/utils/models.js b/src/utils/models.js
index 25a064a..3c22d22 100644
--- a/src/utils/models.js
+++ b/src/utils/models.js
@@ -18,6 +18,61 @@
import { query as queryService } from '../services/graphql';
+export function saveOptionsInState(defaultOption, preState, { payload: allOptions }) {
+ if (!allOptions) {
+ return preState;
+ }
+ const { variables } = preState;
+ const { values, labels, options } = variables;
+ const amendOptions = {};
+ const defaultValues = {};
+ const defaultLabels = {};
+ Object.keys(allOptions).forEach((_) => {
+ const thisOptions = allOptions[_];
+ let newOptions = [...thisOptions];
+ if (defaultOption && defaultOption[_]) {
+ newOptions = [defaultOption[_], ...newOptions];
+ }
+ if (!values[_]) {
+ if (defaultOption && defaultOption[_]) {
+ defaultValues[_] = defaultOption[_].key;
+ defaultLabels[_] = defaultOption[_].label;
+ } else if (thisOptions.length > 0) {
+ defaultValues[_] = thisOptions[0].key;
+ defaultLabels[_] = thisOptions[0].label;
+ }
+ }
+ const key = values[_];
+ if (!thisOptions.find(o => o.key === key)) {
+ newOptions = [...newOptions, { key, label: labels[_] }];
+ }
+ amendOptions[_] = newOptions;
+ });
+ variables.options = {
+ ...options,
+ ...allOptions,
+ ...amendOptions,
+ };
+ let newVariables = variables;
+ if (Object.keys(defaultValues).length > 0) {
+ newVariables = {
+ ...variables,
+ values: {
+ ...values,
+ ...defaultValues,
+ },
+ labels: {
+ ...labels,
+ ...defaultLabels,
+ },
+ };
+ }
+ return {
+ ...preState,
+ variables: newVariables,
+ };
+}
+
export function generateModal({ namespace, dataQuery, optionsQuery, defaultOption, state = {},
varState = {}, effects = {}, reducers = {}, subscriptions = {} }) {
return {
@@ -68,59 +123,9 @@ export function generateModal({ namespace, dataQuery, optionsQuery, defaultOptio
...effects,
},
reducers: {
- saveOptions(preState, { payload: allOptions }) {
- if (!allOptions) {
- return preState;
- }
- const { variables } = preState;
- const { values, labels, options } = variables;
- const amendOptions = {};
- const defaultValues = {};
- const defaultLabels = {};
- Object.keys(allOptions).forEach((_) => {
- const thisOptions = allOptions[_];
- let newOptions = [...thisOptions];
- if (defaultOption && defaultOption[_]) {
- newOptions = [defaultOption[_], ...newOptions];
- }
- if (!values[_]) {
- if (defaultOption && defaultOption[_]) {
- defaultValues[_] = defaultOption[_].key;
- defaultLabels[_] = defaultOption[_].label;
- } else if (thisOptions.length > 0) {
- defaultValues[_] = thisOptions[0].key;
- defaultLabels[_] = thisOptions[0].label;
- }
- }
- const key = values[_];
- if (!thisOptions.find(o => o.key === key)) {
- newOptions = [...newOptions, { key, label: labels[_] }];
- }
- amendOptions[_] = newOptions;
- });
- variables.options = {
- ...options,
- ...allOptions,
- ...amendOptions,
- };
- let newVariables = variables;
- if (Object.keys(defaultValues).length > 0) {
- newVariables = {
- ...variables,
- values: {
- ...values,
- ...defaultValues,
- },
- labels: {
- ...labels,
- ...defaultLabels,
- },
- };
- }
- return {
- ...preState,
- variables: newVariables,
- };
+ saveOptions(preState, action) {
+ const raw = saveOptionsInState(defaultOption, preState, action);
+ return raw;
},
save(preState, { payload: { variables: { values = {}, options = {}, labels = {} },
data = {} } }) {
--
To stop receiving notification emails like this one, please contact
hanahmily@apache.org.