Skip to content

Commit 5e4e0b1

Browse files
committed
* Samples: Added new tag 'Simple'
* Web-view: Improved Dashboard
1 parent f0902f2 commit 5e4e0b1

10 files changed

Lines changed: 194 additions & 27 deletions

File tree

samples/ktor-simple/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ ktor_version=1.3.1
22
kotlin.code.style=official
33
logback_version=1.2.1
44
h2_version=1.4.197
5-
sample.tags=Ktor, Netty, No Auth
5+
sample.tags=Ktor, Netty, No Auth, Simple
66
sample.api=fibonacci
77
sample.started.pattern=.+Uptime\\s(\\d+\\.?\\d*)\\sseconds.*
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
sample.tags=Micronaut, Netty, No Auth
1+
sample.tags=Micronaut, Netty, No Auth, Simple
22
sample.api=fibonacci
33
sample.started.pattern=.+Uptime\\s(\\d+\\.?\\d*)\\sseconds.*
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
sample.tags=Spring Boot, Tomcat, No Auth
1+
sample.tags=Spring Boot, Tomcat, No Auth, Simple
22
sample.api=fibonacci
33
sample.started.pattern=.+Started\\s([\\w\\d]+)\\sin\\s(\\d+\\.?\\d*)\\sseconds\\s\\(JVM\\srunning\\sfor\\s(\\d+\\.?\\d*)\\).*

web-view/package-lock.json

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web-view/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@
1717
"primeflex": "^1.0.0",
1818
"primeicons": "^2.0.0",
1919
"primereact": "^4.0.0",
20+
"prop-types": "latest",
21+
"randomcolor": "^0.5.4",
2022
"react": "^16.13.0",
2123
"react-dom": "^16.13.0",
2224
"react-redux": "^7.2.0",
2325
"react-router-dom": "^5.1.2",
2426
"react-scripts": "3.4.0",
27+
"react-tagcloud": "^2.0.0",
2528
"redux": "^4.0.5",
26-
"redux-thunk": "^2.3.0",
27-
"prop-types": "latest"
29+
"redux-thunk": "^2.3.0"
2830
},
2931
"scripts": {
3032
"start": "react-scripts start",

web-view/src/actions/index.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,25 @@ export const fetchGitHubRelease = (release = 'latest') => async dispatch => {
88
payload: response.data
99
});
1010

11-
fetchMetrics(response.data.assets.find(it => it.name === 'metrics.json').browser_download_url)(dispatch)
11+
const metricsAsset = response.data.assets.find(it => it.name === 'metrics.json');
12+
fetchMetrics(response.data.id, metricsAsset.id, metricsAsset.browser_download_url)(dispatch)
1213
};
1314

14-
export const fetchMetrics = url => async dispatch => {
15-
const response = await axios.get(`https://cors-anywhere.herokuapp.com/${url}`);
15+
export const fetchMetrics = (releaseId, assetId, url) => async dispatch => {
16+
let data;
17+
const dataStr = localStorage.getItem(`${releaseId}:${assetId}`);
18+
if (dataStr) {
19+
data = JSON.parse(dataStr);
20+
} else {
21+
const response = await axios.get(`https://cors-anywhere.herokuapp.com/${url}`).catch(reason =>
22+
(axios.get('https://api.allorigins.win/get?url=' + encodeURIComponent(url)))
23+
);
24+
data = response.data.contents ? JSON.parse(response.data.contents) : response.data;
25+
localStorage.setItem(`${releaseId}:${assetId}`, JSON.stringify(data));
26+
}
27+
1628
dispatch({
1729
type: LOAD_METRICS,
18-
payload: response.data
30+
payload: data
1931
});
2032
};

web-view/src/components/chart-card.js

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,28 @@ class ChartCard extends React.Component {
1111
if (this.props.chartType !== nextProps.chartType) {
1212
this.changeType = true;
1313
return true;
14-
} else if (!_.isEqual(this.props.data, nextProps.data)) {
15-
this.chart.refresh();
16-
return true;
1714
}
1815
return !_.isEqual(this.props, nextProps);
1916
}
2017

2118
setChartRef(c) {
22-
if (!!this.changeType && !!c)
19+
if (!!this.changeType && c)
2320
c.reinit();
2421
this.chart = c;
22+
this.changeType = false;
2523
}
2624

2725
render() {
28-
const {first, title, chartType, data} = this.props;
26+
const {first, title, chartType, data, samples} = this.props;
27+
const filter = (data, samples) => {
28+
data = _.clone(data);
29+
data.datasets = data.datasets.filter((it) => _.find(samples, (s) => s.name === it.label));
30+
return data;
31+
};
2932

3033
return (
3134
<Card title={title} style={{marginTop: !first ? '3em' : '0'}}>
32-
<Chart type={chartType || "bar"} data={data} ref={this.setChartRef.bind(this)}/>
35+
<Chart type={chartType || "bar"} data={filter(data, samples)} ref={this.setChartRef.bind(this)}/>
3336
</Card>
3437
);
3538
}
@@ -39,7 +42,8 @@ ChartCard.propTypes = {
3942
first: PropTypes.bool,
4043
title: PropTypes.string,
4144
chartType: PropTypes.oneOf(["bar", "horizontalBar"]),
42-
data: PropTypes.object
45+
data: PropTypes.object,
46+
samples: PropTypes.array
4347
};
4448

4549
export default ChartCard;

web-view/src/components/dashboard.js

Lines changed: 76 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,100 @@ import {Card} from "primereact/card";
55
import {ScrollPanel} from "primereact/scrollpanel";
66
import {SelectButton} from "primereact/selectbutton";
77
import ChartCard from "./chart-card";
8+
import {AutoComplete} from "primereact/autocomplete";
9+
import {ListBox} from "primereact/listbox";
10+
import {Button} from "primereact/button";
11+
import randomColor from 'randomcolor';
12+
import TagsCard from "./tags-card";
813

914
const Dashboard = (props) => {
1015
const [chartType, setChartType] = useState("bar");
16+
const [tags, setTags] = useState(null);
17+
const [samples, setSamples] = useState(props.samples);
18+
const [tagsSuggestions, setTagsSuggestions] = useState(null);
1119
const types = [
1220
{label: 'Vertical Bar', value: 'bar'},
1321
{label: 'Horizontal Bar', value: 'horizontalBar'},
1422
];
23+
24+
const filterTags = (event) => {
25+
setTimeout(() => {
26+
const results = props.tags.filter(tag => (tag.toLowerCase().indexOf(event.query.toLowerCase()) >= 0));
27+
setTagsSuggestions(results)
28+
}, 250);
29+
};
30+
31+
const renderListItem = (item) => {
32+
const classes = !!samples.find((it) => it.name === item.name) ?
33+
"mdi mdi-checkbox-marked-outline mdi-18" : "mdi mdi-checkbox-blank-outline mdi-18";
34+
return (<span><i className={classes} style={{paddingRight: '5px'}}/>{item.name}</span>);
35+
};
36+
37+
const selectTags = (e) => {
38+
const tags = e.value;
39+
setTags(tags);
40+
if (tags.length > 0) {
41+
setSamples(props.samples.filter((it) => _.intersection(it.tags, tags).length > 0));
42+
}
43+
};
44+
1545
return (
1646
<div className="p-grid">
1747
<div className="p-sm-12 p-md-12 p-lg-4 p-xl-3" style={{paddingTop: '5em'}}>
1848
<div className="p-grid p-justify-around">
1949
<Card style={{width: '280px'}}>
20-
<SelectButton value={chartType} options={types} onChange={(e) => setChartType(e.value)}/>
50+
<div className="p-grid p-dir-col">
51+
<div className="p-col">
52+
<SelectButton value={chartType} options={types}
53+
onChange={(e) => setChartType(e.value)}/>
54+
</div>
55+
<div className="p-col">
56+
<AutoComplete value={tags} suggestions={tagsSuggestions} completeMethod={filterTags}
57+
minLength={1} placeholder="Tags" multiple={true} className="tags-search"
58+
onChange={selectTags}/>
59+
</div>
60+
<div className="p-col">
61+
<ListBox value={samples} options={props.samples} className="samples-list"
62+
onChange={(e) => setSamples(e.value)}
63+
filter={true} multiple={true} optionLabel="name"
64+
itemTemplate={renderListItem}
65+
/>
66+
67+
<div className="p-grid app-tools">
68+
<div className="p-col">
69+
<Button label="Select All" className="p-button-raised p-button-secondary"
70+
onClick={() => setSamples(props.samples)}
71+
/>
72+
</div>
73+
<div className="p-col">
74+
<Button label="Clear All" className="p-button-raised p-button-secondary"
75+
onClick={() => setSamples([])}
76+
/>
77+
</div>
78+
</div>
79+
</div>
80+
</div>
2181
</Card>
82+
83+
<TagsCard samples={props.samples}/>
2284
</div>
2385
</div>
2486
<div className="p-sm-12 p-md-12 p-lg-8 p-xl-6">
2587
<ScrollPanel style={{width: '100%', height: 'calc(100vh - 5.1em)', paddingTop: '5em'}}>
26-
<ChartCard title="Memory on start (Mb)" chartType={chartType} data={props.memoryOnStart} first={true}/>
88+
<ChartCard title="Memory on start (Mb)" chartType={chartType} data={props.memoryOnStart}
89+
first={true} samples={samples}/>
2790

28-
<ChartCard title="Working memory (Mb)" chartType={chartType} data={props.memoryOnWork}/>
91+
<ChartCard title="Working memory (Mb)" chartType={chartType} data={props.memoryOnWork}
92+
samples={samples}/>
2993

30-
<ChartCard title="Uptime (ms)" chartType={chartType} data={props.uptime}/>
94+
<ChartCard title="Uptime (ms)" chartType={chartType} data={props.uptime}
95+
samples={samples}/>
3196

32-
<ChartCard title="Warming up (ms)" chartType={chartType} data={props.warmingUp}/>
97+
<ChartCard title="Warming up (ms)" chartType={chartType} data={props.warmingUp}
98+
samples={samples}/>
3399

34-
<ChartCard title="Request time (ms)" chartType={chartType} data={props.requestTime}/>
100+
<ChartCard title="Request time (ms)" chartType={chartType} data={props.requestTime}
101+
samples={samples}/>
35102
</ScrollPanel>
36103
</div>
37104
</div>
@@ -45,14 +112,12 @@ const mapStateToProps = state => {
45112

46113
const colors = _.zipObject(
47114
state.metrics.map(sample => (sample.name)),
48-
state.metrics.map(() => ('#' + (0x1000000 + (Math.random()) * 0xffffff).toString(16).substr(1, 6)))
115+
state.metrics.map(() => (randomColor()))
49116
);
50117

51118
return ({
52-
samples: _.zipObject(
53-
state.metrics.map(sample => (sample.name)),
54-
state.metrics.map(sample => (sample.tags))
55-
),
119+
samples: state.metrics.map(sample => ({name: sample.name, tags: sample.tags})),
120+
tags: _.uniq(_.flatMap(state.metrics.map(sample => (sample.tags)))),
56121
uptime: {
57122
labels: ['Avg', 'Max', 'Min'],
58123
datasets: state.metrics.map(sample => ({
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import {TagCloud} from 'react-tagcloud'
4+
import {Card} from "primereact/card";
5+
import _ from 'lodash'
6+
7+
const TagsCard = props => {
8+
const tags = [];
9+
_.flatMap(props.samples, (it) => it.tags).forEach(it => {
10+
let tag = _.find(tags, {value: it});
11+
if (!tag) {
12+
tag = {value: it, count: 0};
13+
tags.push(tag);
14+
}
15+
tag.count += 1;
16+
});
17+
debugger
18+
return (
19+
<Card style={{width: '280px', marginTop: '10px'}}>
20+
<TagCloud
21+
minSize={12}
22+
maxSize={35}
23+
tags={tags}
24+
/>
25+
</Card>
26+
);
27+
};
28+
29+
TagsCard.propTypes = {
30+
samples: PropTypes.array
31+
};
32+
33+
export default TagsCard;

web-view/src/index.css

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,33 @@
2323
body {
2424
background: lightgray;
2525
}
26+
27+
.tags-search, .samples-list {
28+
width: 100% !important;
29+
}
30+
31+
.tags-search > .p-autocomplete-multiple-container {
32+
width: 100%;
33+
}
34+
35+
36+
.samples-list > .p-listbox-list-wrapper {
37+
max-height: 450px;
38+
}
39+
40+
.samples-list > div {
41+
width: 100%;
42+
}
43+
44+
.samples-list .p-highlight {
45+
background: rgba(0,0,0,0) !important;
46+
color: rgb(51,51,51) !important;;
47+
}
48+
49+
.app-tools {
50+
padding-top: 10px;
51+
}
52+
53+
.app-tools > .p-col > button {
54+
width: 100%;
55+
}

0 commit comments

Comments
 (0)