Merge branch 'master' into seperating-normalize-css
This commit is contained in:
commit
27fccb364d
@ -50,6 +50,18 @@ server.register(plugins, (err) => {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
server.route({
|
||||
method: 'GET',
|
||||
path: '/static/images/{param*}',
|
||||
handler: {
|
||||
directory: {
|
||||
path: './images/',
|
||||
redirectToSlash: true,
|
||||
index: false
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: 'GET',
|
||||
path: '/static/{param*}',
|
||||
|
100
frontend/src/components/breadcrumb/index.js
Normal file
100
frontend/src/components/breadcrumb/index.js
Normal file
@ -0,0 +1,100 @@
|
||||
const Container = require('@ui/components/container');
|
||||
const PropTypes = require('@root/prop-types');
|
||||
const React = require('react');
|
||||
const ReactRouter = require('react-router');
|
||||
const Styled = require('styled-components');
|
||||
const flatten = require('lodash.flatten');
|
||||
const fns = require('@ui/shared/functions');
|
||||
|
||||
const {
|
||||
remcalc
|
||||
} = fns;
|
||||
|
||||
const {
|
||||
default: styled
|
||||
} = Styled;
|
||||
|
||||
// Main Contonent Wrapper Styles
|
||||
const StyledDiv = styled.div`
|
||||
background-color: #FAFAFA;
|
||||
height: ${remcalc(91)};
|
||||
border-bottom: solid ${remcalc(1)} #d8d8d8;
|
||||
`;
|
||||
|
||||
const BreadcrumbA = styled.a`
|
||||
text-decoration: none !important;
|
||||
`;
|
||||
|
||||
const BreadcrumbSpan = styled.span`
|
||||
color: #646464;
|
||||
`;
|
||||
|
||||
const H1 = styled.h1`
|
||||
margin: 0 0 0 0;
|
||||
padding-top: ${remcalc(31)};
|
||||
padding-bottom: ${remcalc(31)};
|
||||
`;
|
||||
|
||||
const {
|
||||
Link
|
||||
} = ReactRouter;
|
||||
|
||||
function getNameLink(name) {
|
||||
return flatten(name.map((part, i) => {
|
||||
if (!part.name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const link = (
|
||||
<Link key={part.pathname} to={part.pathname}>
|
||||
{
|
||||
({
|
||||
href,
|
||||
onClick,
|
||||
}) =>
|
||||
<BreadcrumbA href={href} onClick={onClick}>
|
||||
{part.name}
|
||||
</BreadcrumbA>
|
||||
}
|
||||
</Link>
|
||||
);
|
||||
|
||||
const key = `${part.pathname}${i}`;
|
||||
const slash = (
|
||||
<BreadcrumbSpan key={key}> / </BreadcrumbSpan>
|
||||
);
|
||||
|
||||
return (i === 0) ? link : [
|
||||
slash,
|
||||
link
|
||||
];
|
||||
}));
|
||||
}
|
||||
|
||||
const Breadcrumb = ({
|
||||
children,
|
||||
links = [],
|
||||
name = []
|
||||
}) => {
|
||||
return (
|
||||
<Container>
|
||||
<StyledDiv>
|
||||
<H1
|
||||
style={{
|
||||
fontSize: remcalc(24)
|
||||
}}
|
||||
>
|
||||
{getNameLink(name)}
|
||||
</H1>
|
||||
</StyledDiv>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
Breadcrumb.propTypes = {
|
||||
children: React.PropTypes.node,
|
||||
links: React.PropTypes.arrayOf(PropTypes.link),
|
||||
name: React.PropTypes.arrayOf(PropTypes.link)
|
||||
};
|
||||
|
||||
module.exports = Breadcrumb;
|
@ -66,6 +66,8 @@ const StyledTooltipWrapper = styled.div`
|
||||
`;
|
||||
|
||||
const StyledName = styled.span`
|
||||
color: #646464;
|
||||
font-size: ${remcalc(16)}
|
||||
position: relative;
|
||||
top: ${remcalc(-12)};
|
||||
`;
|
||||
|
@ -42,6 +42,7 @@ const StyledNav = styled.div`
|
||||
|
||||
// TODO: refactor colours into constants in UI
|
||||
const NavigationLinkContainer = styled.div`
|
||||
position: relative;
|
||||
padding: ${remcalc(11)} ${remcalc(12)} ${remcalc(12)};
|
||||
color: #646464;
|
||||
border: solid ${remcalc(1)} #d8d8d8;
|
||||
@ -77,6 +78,17 @@ const NavLi = styled.li`
|
||||
}
|
||||
`;
|
||||
|
||||
const Shadow = styled.div`
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
height: ${remcalc(5)};
|
||||
width: 100%;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background-image:
|
||||
linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.06));
|
||||
`;
|
||||
|
||||
const OrgNavigation = ({
|
||||
orgs = []
|
||||
}) => {
|
||||
@ -98,6 +110,7 @@ const OrgNavigation = ({
|
||||
}) =>
|
||||
<a href={href} onClick={onClick}>
|
||||
<NavigationLinkContainer className={isActive ? 'active' : ''}>
|
||||
{ !isActive && <Shadow />}
|
||||
<OrgImage>
|
||||
<OrgAvatar
|
||||
height={remcalc(26)}
|
||||
|
31
frontend/src/components/people-item/index.js
Normal file
31
frontend/src/components/people-item/index.js
Normal file
@ -0,0 +1,31 @@
|
||||
const React = require('react');
|
||||
|
||||
const PropTypes = require('@root/prop-types');
|
||||
// const List = require('@ui/components/list');
|
||||
|
||||
// const {
|
||||
// ListItem,
|
||||
// ListItemView,
|
||||
// ListItemMeta,
|
||||
// ListItemTitle,
|
||||
// ListItemOptions
|
||||
// } = List;
|
||||
|
||||
const PersonItem = ({
|
||||
person = {},
|
||||
}) => {
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>{person.uuid}</td>
|
||||
<td>{person.uuid}</td>
|
||||
<td>{person.uuid}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
||||
PersonItem.propTypes = {
|
||||
person: PropTypes.person,
|
||||
};
|
||||
|
||||
module.exports = PersonItem;
|
39
frontend/src/components/people-list/index.js
Normal file
39
frontend/src/components/people-list/index.js
Normal file
@ -0,0 +1,39 @@
|
||||
const React = require('react');
|
||||
|
||||
const PersonItem = require('@components/people-item');
|
||||
const PropTypes = require('@root/prop-types');
|
||||
|
||||
const PeopleList = ({
|
||||
people = []
|
||||
}) => {
|
||||
|
||||
const peopleList = people.map((person) => (
|
||||
<PersonItem
|
||||
key={person.uuid}
|
||||
person={person}
|
||||
/>
|
||||
));
|
||||
|
||||
return (
|
||||
<div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Status</th>
|
||||
<th>Role</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{peopleList}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
PeopleList.propTypes = {
|
||||
people: React.PropTypes.arrayOf(PropTypes.person),
|
||||
};
|
||||
|
||||
module.exports = PeopleList;
|
@ -1,30 +1,11 @@
|
||||
const flatten = require('lodash.flatten');
|
||||
const React = require('react');
|
||||
const ReactIntl = require('react-intl');
|
||||
const Styled = require('styled-components');
|
||||
const ReactRouter = require('react-router');
|
||||
|
||||
const H1 = require('@ui/components/base-elements').H1;
|
||||
const Li = require('@ui/components/horizontal-list/li');
|
||||
const PropTypes = require('@root/prop-types');
|
||||
const Ul = require('@ui/components/horizontal-list/ul');
|
||||
const fns = require('@ui/shared/functions');
|
||||
|
||||
const {
|
||||
default: styled
|
||||
} = Styled;
|
||||
|
||||
const BreadcrumbA = styled.a`
|
||||
text-decoration: none !important;
|
||||
`;
|
||||
|
||||
const BreadcrumbSpan = styled.span`
|
||||
color: #646464;
|
||||
`;
|
||||
|
||||
const {
|
||||
remcalc
|
||||
} = fns;
|
||||
const Breadcrumb = require('@components/breadcrumb');
|
||||
|
||||
const {
|
||||
FormattedMessage
|
||||
@ -34,11 +15,12 @@ const {
|
||||
Link
|
||||
} = ReactRouter;
|
||||
|
||||
const Section = ({
|
||||
children,
|
||||
links = [],
|
||||
name = []
|
||||
}) => {
|
||||
const Section = (props) => {
|
||||
const {
|
||||
children,
|
||||
links = [],
|
||||
} = props;
|
||||
|
||||
const navLinks = links.map((link) => (
|
||||
<Li key={link.name}>
|
||||
<Link activeClassName='active' to={link.pathname}>
|
||||
@ -47,44 +29,9 @@ const Section = ({
|
||||
</Li>
|
||||
));
|
||||
|
||||
const nameLinks = flatten(name.map((part, i) => {
|
||||
if (!part.name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const link = (
|
||||
<Link key={part.pathname} to={part.pathname}>
|
||||
{
|
||||
({
|
||||
href,
|
||||
onClick,
|
||||
}) =>
|
||||
<BreadcrumbA href={href} onClick={onClick}>
|
||||
{part.name}
|
||||
</BreadcrumbA>
|
||||
}
|
||||
</Link>
|
||||
);
|
||||
|
||||
const slash = (
|
||||
<BreadcrumbSpan key={`${part.pathname}${i}`}> / </BreadcrumbSpan>
|
||||
);
|
||||
|
||||
return (i === 0) ? link : [
|
||||
slash,
|
||||
link
|
||||
];
|
||||
}));
|
||||
|
||||
return (
|
||||
<div>
|
||||
<H1
|
||||
style={{
|
||||
fontSize: remcalc(24)
|
||||
}}
|
||||
>
|
||||
{nameLinks}
|
||||
</H1>
|
||||
<Breadcrumb {...props} />
|
||||
<Ul>
|
||||
{navLinks}
|
||||
</Ul>
|
||||
@ -95,8 +42,7 @@ const Section = ({
|
||||
|
||||
Section.propTypes = {
|
||||
children: React.PropTypes.node,
|
||||
links: React.PropTypes.arrayOf(PropTypes.link),
|
||||
name: React.PropTypes.arrayOf(PropTypes.link)
|
||||
links: React.PropTypes.arrayOf(PropTypes.link)
|
||||
};
|
||||
|
||||
module.exports = Section;
|
||||
|
@ -3,6 +3,13 @@ const React = require('react');
|
||||
const ReactRedux = require('react-redux');
|
||||
// const ReactRouter = require('react-router');
|
||||
|
||||
const Row = require('@ui/components/row');
|
||||
const Column= require('@ui/components/column');
|
||||
const Button= require('@ui/components/button');
|
||||
const PropTypes = require('@root/prop-types');
|
||||
const PeopleList = require('@components/people-list');
|
||||
const selectors = require('@state/selectors');
|
||||
|
||||
const Section = require('./section');
|
||||
|
||||
// const {
|
||||
@ -13,23 +20,53 @@ const {
|
||||
connect
|
||||
} = ReactRedux;
|
||||
|
||||
// const {
|
||||
// Link,
|
||||
// Match,
|
||||
// Miss,
|
||||
// Redirect
|
||||
// } = ReactRouter;
|
||||
const {
|
||||
peopleByOrgIdSelector
|
||||
} = selectors;
|
||||
|
||||
const buttonStyle = {
|
||||
float: 'right'
|
||||
};
|
||||
|
||||
const People = (props) => {
|
||||
|
||||
const {
|
||||
people = []
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Section {...props}>
|
||||
<p>people</p>
|
||||
<Row>
|
||||
<Column smOffset={9} xs={2}>
|
||||
<Button style={buttonStyle}>Invite</Button>
|
||||
</Column>
|
||||
</Row>
|
||||
|
||||
<Row>
|
||||
<Column>
|
||||
<PeopleList
|
||||
people={people}
|
||||
/>
|
||||
</Column>
|
||||
</Row>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
People.propTypes = {};
|
||||
People.propTypes = {
|
||||
people: React.PropTypes.arrayOf(PropTypes.person)
|
||||
// toggleCollapsed: React.PropTypes.func
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({});
|
||||
const mapStateToProps = (state, {
|
||||
params = {}
|
||||
}) => ({
|
||||
people: peopleByOrgIdSelector(params.org)(state)
|
||||
});
|
||||
|
||||
module.exports = connect(mapStateToProps)(People);
|
||||
const mapDispatchToProps = (dispatch) => ({});
|
||||
|
||||
module.exports = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(People);
|
||||
|
@ -211,18 +211,23 @@
|
||||
"owner": "b94033c1-3665-4c36-afab-d9c3d0b51c01",
|
||||
"id": "nicola",
|
||||
"name": "Your dashboard",
|
||||
"image": "https://pbs.twimg.com/profile_images/641289584580493312/VBfsPlff_400x400.jpg"
|
||||
"image": "https://pbs.twimg.com/profile_images/641289584580493312/VBfsPlff_400x400.jpg",
|
||||
"members": {}
|
||||
}, {
|
||||
"owner": "b94033c1-3665-4c36-afab-d9c3d0b51c01",
|
||||
"uuid": "e12ad7db-91b2-4154-83dd-40dcfc700dcc",
|
||||
"id": "biz-tech",
|
||||
"name": "BizTech"
|
||||
"name": "BizTech",
|
||||
"members": [{
|
||||
"uuid": "fd853d8f-e1dd-49b5-b7b3-ae9adfea1e2f"
|
||||
}]
|
||||
}, {
|
||||
"owner": "b94033c1-3665-4c36-afab-d9c3d0b51c01",
|
||||
"uuid": "551f316d-e414-480f-9787-b4c408db3edd",
|
||||
"id": "make-us-proud",
|
||||
"name": "Make Us Proud",
|
||||
"image": "/static/images/make-us-proud.svg"
|
||||
"image": "/static/images/make-us-proud.svg",
|
||||
"members": {}
|
||||
}]
|
||||
},
|
||||
"projects": {
|
||||
|
@ -61,6 +61,10 @@ const Sections = React.PropTypes.arrayOf(
|
||||
React.PropTypes.string
|
||||
);
|
||||
|
||||
const Person = React.PropTypes.shape({
|
||||
...BaseObject
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
account: Account,
|
||||
link: Link,
|
||||
@ -71,5 +75,6 @@ module.exports = {
|
||||
instance: Instance,
|
||||
metric: Metric,
|
||||
metricType: MetricType,
|
||||
dataset: Dataset
|
||||
dataset: Dataset,
|
||||
person: Person
|
||||
};
|
||||
|
@ -18,6 +18,7 @@ const services = (state) => get(state, 'services.data', []);
|
||||
const collapsedServices = (state) => get(state, 'services.ui.collapsed', []);
|
||||
const collapsedInstances = (state) => get(state, 'instances.ui.collapsed', []);
|
||||
const instances = (state) => get(state, 'instances.data', []);
|
||||
const members = (state) => get(state, 'members.data', []);
|
||||
const metricTypes = (state) => get(state, 'metrics.data.types', []);
|
||||
const metricDatasets = (state) => get(state, 'metrics.data.datasets', []);
|
||||
|
||||
@ -110,6 +111,12 @@ const instancesByProjectId = (projectId) => createSelector(
|
||||
}))
|
||||
);
|
||||
|
||||
const peopleByOrgId = (orgId) => createSelector(
|
||||
// [members, orgById(orgId)], (members, org) => org.members
|
||||
|
||||
[members, orgById(orgId)], (members, org) => org.members
|
||||
);
|
||||
|
||||
module.exports = {
|
||||
accountSelector: account,
|
||||
accountUISelector: accountUi,
|
||||
@ -126,5 +133,6 @@ module.exports = {
|
||||
instancesByServiceIdSelector: instancesByServiceId,
|
||||
metricsByServiceIdSelector: metricsByServiceId,
|
||||
instancesByProjectIdSelector: instancesByProjectId,
|
||||
metricTypeByUuidSelector: metricTypeByUuid
|
||||
metricTypeByUuidSelector: metricTypeByUuid,
|
||||
peopleByOrgIdSelector: peopleByOrgId
|
||||
};
|
||||
|
3044
frontend/yarn.lock
3044
frontend/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -42,7 +42,7 @@ install-production: compile clean
|
||||
.PHONY: compile
|
||||
compile: install
|
||||
mkdir -p dist
|
||||
cp -R src/ dist/.
|
||||
cp -R src/. dist/.
|
||||
$(bindir)/babel src --out-dir dist --source-maps inline
|
||||
|
||||
.PHONY: build
|
||||
|
@ -27,6 +27,7 @@
|
||||
"lodash.isfunction": "^3.0.8",
|
||||
"lodash.isstring": "^4.0.1",
|
||||
"lodash.isundefined": "^3.0.1",
|
||||
"moment": "^2.17.1",
|
||||
"param-case": "^2.1.0",
|
||||
"random-natural": "^1.0.3",
|
||||
"react": "^15.4.2",
|
||||
|
@ -69,14 +69,6 @@ const style = css`
|
||||
padding: ${remcalc('14 16')};
|
||||
position: relative;
|
||||
|
||||
font-family: -apple-system,
|
||||
BlinkMacSystemFont,
|
||||
"Segoe UI",
|
||||
Roboto,
|
||||
"Helvetica Neue",
|
||||
Arial,
|
||||
sans-serif;
|
||||
|
||||
font-size: ${remcalc(16)};
|
||||
font-weight: 400;
|
||||
text-align: center;
|
||||
@ -130,6 +122,7 @@ const style = css`
|
||||
`;
|
||||
|
||||
const StyledButton = styled.button`
|
||||
min-width: ${remcalc(120)};
|
||||
${style}
|
||||
`;
|
||||
|
||||
|
@ -1,13 +1,8 @@
|
||||
const constants = require('../../shared/constants');
|
||||
const fns = require('../../shared/functions');
|
||||
const Item = require('./item');
|
||||
const React = require('react');
|
||||
const Styled = require('styled-components');
|
||||
|
||||
const {
|
||||
colors
|
||||
} = constants;
|
||||
|
||||
const {
|
||||
remcalc
|
||||
} = fns;
|
||||
@ -19,8 +14,9 @@ const {
|
||||
const StyledItem = styled(Item)`
|
||||
position: absolute;
|
||||
|
||||
background-color: ${colors.brandPrimary};
|
||||
border: solid ${remcalc(1)} ${colors.borderPrimary};
|
||||
background-color: #3B4AAF;
|
||||
|
||||
border: solid ${remcalc(1)} #2D3884;
|
||||
box-shadow: none;
|
||||
|
||||
width: calc(100% + ${remcalc(2)});
|
||||
|
@ -1,33 +0,0 @@
|
||||
const React = require('react');
|
||||
const Styled = require('styled-components');
|
||||
const fns = require('../../shared/functions');
|
||||
|
||||
const {
|
||||
remcalc
|
||||
} = fns;
|
||||
|
||||
const {
|
||||
default: styled
|
||||
} = Styled;
|
||||
|
||||
const StyledBody = styled.div`
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: ${remcalc(264)};
|
||||
`;
|
||||
|
||||
const Body = ({
|
||||
children
|
||||
}) => {
|
||||
return (
|
||||
<StyledBody name='metric-body'>
|
||||
{children}
|
||||
</StyledBody>
|
||||
);
|
||||
};
|
||||
|
||||
Body.propTypes = {
|
||||
children: React.PropTypes.node
|
||||
};
|
||||
|
||||
module.exports = Body;
|
174
ui/src/components/metric/graph.js
Normal file
174
ui/src/components/metric/graph.js
Normal file
@ -0,0 +1,174 @@
|
||||
const React = require('react');
|
||||
const Styled = require('styled-components');
|
||||
const moment = require('moment');
|
||||
const Chart = require('chart.js');
|
||||
const whisker = require('chartjs-chart-box-plot');
|
||||
|
||||
whisker(Chart);
|
||||
|
||||
const {
|
||||
default: styled
|
||||
} = Styled;
|
||||
|
||||
const Container = styled.div`
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const Canvas = styled.canvas`
|
||||
|
||||
`;
|
||||
|
||||
class Graph extends React.Component {
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
yMax = 100,
|
||||
yMin = 0,
|
||||
yMeasurement = '%'
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
data,
|
||||
xMax,
|
||||
xMin,
|
||||
xUnitStepSize
|
||||
} = this.processData(this.props);
|
||||
|
||||
this._chart = new Chart(this._refs.component, {
|
||||
type: 'whisker',
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
data: {
|
||||
datasets: [{
|
||||
data: data
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
layout: {
|
||||
padding: 10
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
display: true,
|
||||
type: 'time',
|
||||
time: {
|
||||
unit: 'minute',
|
||||
unitStepSize: xUnitStepSize,
|
||||
max: xMax,
|
||||
min: xMin,
|
||||
/*displayFormats: {
|
||||
hour: 'MMM D, hA'
|
||||
}*/
|
||||
},
|
||||
}],
|
||||
yAxes: [{
|
||||
display: true,
|
||||
ticks: {
|
||||
min: yMin,
|
||||
max: yMax,
|
||||
callback: (value, index, values) => {
|
||||
return `${value.toFixed(2)}${yMeasurement}`;
|
||||
}
|
||||
}
|
||||
}]
|
||||
},
|
||||
legend: {
|
||||
display: false
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
|
||||
const {
|
||||
data,
|
||||
xMax,
|
||||
xMin,
|
||||
xUnitStepSize
|
||||
} = this.processData(nextProps);
|
||||
|
||||
this._chart.data.datasets = [{
|
||||
data
|
||||
}];
|
||||
this._chart.options.scales.xAxes[0].time.max = xMax;
|
||||
this._chart.options.scales.xAxes[0].time.min = xMin;
|
||||
this._chart.options.scales.xAxes[0].time.unitStepSize = xUnitStepSize;
|
||||
this._chart.update(0);
|
||||
}
|
||||
|
||||
processData(props) {
|
||||
const {
|
||||
data = [],
|
||||
duration = 360
|
||||
} = this.props;
|
||||
// I'm going to assume that data will be structured in 10min intervals...
|
||||
// And that newest data will be at the end...
|
||||
// Let's rock and roll!
|
||||
// All this shizzle below needs to be recalculated on new props, yay!
|
||||
const now = moment();
|
||||
// first time on scale x
|
||||
const before = moment().subtract(duration, 'minutes');
|
||||
// remove leading data before first time on scale x
|
||||
const totalData = data.slice(data.length - 1 - duration/10);
|
||||
// adjust time of first data, if there's less data than would fill the chart
|
||||
const start = moment(before)
|
||||
.add(duration - (totalData.length-1)*10, 'minutes');
|
||||
// add times to data
|
||||
const dataWithTime = totalData.map((d, i) => {
|
||||
const add = i*10;
|
||||
return Object.assign(
|
||||
{},
|
||||
d,
|
||||
{
|
||||
x: moment(start).add(add, 'minutes').toDate()
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// set min and max
|
||||
const xMax = now.toDate();
|
||||
const xMin = before.toDate();
|
||||
// calculate stepsize
|
||||
const xUnitStepSize = duration/6;
|
||||
|
||||
return {
|
||||
data: dataWithTime,
|
||||
xMax,
|
||||
xMin,
|
||||
xUnitStepSize
|
||||
};
|
||||
}
|
||||
|
||||
ref(name) {
|
||||
this._refs = this._refs || {};
|
||||
|
||||
return (el) => {
|
||||
this._refs[name] = el;
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Container name='metric-body'>
|
||||
<Canvas
|
||||
height={262}
|
||||
innerRef={this.ref('component')}
|
||||
width={940}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Graph.propTypes = {
|
||||
data: React.PropTypes.array,
|
||||
duration: React.PropTypes.number,
|
||||
yMax: React.PropTypes.number,
|
||||
yMeasurement: React.PropTypes.string,
|
||||
yMin: React.PropTypes.number
|
||||
};
|
||||
|
||||
module.exports = Graph;
|
18
ui/src/components/metric/icon-settings.svg
Normal file
18
ui/src/components/metric/icon-settings.svg
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 41.2 (35397) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>icon: settings </title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="project:-adding-metrics-1.4" transform="translate(-979.000000, -413.000000)" fill="#FFFFFF">
|
||||
<g id="metric:-cpu" transform="translate(208.000000, 391.000000)">
|
||||
<g id="metric-head" transform="translate(5.000000, 0.000000)">
|
||||
<g id="button:-settinga" transform="translate(742.000000, 0.000000)">
|
||||
<path d="M33,34 C31.3425,34 30,32.6575 30,31 C30,29.3425 31.3425,28 33,28 C34.6575,28 36,29.3425 36,31 C36,32.6575 34.6575,34 33,34 L33,34 Z M42,32.5 L42,29.5 L40.3485,29.5 C40.155,28.543 39.774,27.655 39.252,26.869 L40.425,25.696 L38.304,23.575 L37.131,24.748 C36.345,24.226 35.457,23.845 34.5,23.6515 L34.5,22 L31.5,22 L31.5,23.6515 C30.543,23.845 29.655,24.226 28.869,24.748 L27.696,23.575 L25.575,25.696 L26.748,26.869 C26.226,27.655 25.845,28.543 25.6515,29.5 L24,29.5 L24,32.5 L25.6515,32.5 C25.845,33.457 26.226,34.345 26.748,35.131 L25.575,36.304 L27.696,38.425 L28.869,37.252 C29.655,37.774 30.543,38.155 31.5,38.3485 L31.5,40 L34.5,40 L34.5,38.3485 C35.457,38.155 36.345,37.774 37.131,37.252 L38.304,38.425 L40.425,36.304 L39.252,35.131 C39.774,34.345 40.155,33.457 40.3485,32.5 L42,32.5 Z" id="icon:-settings-"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
MetricBody: require('./body'),
|
||||
MetricGraph: require('./graph'),
|
||||
MetricCloseButton: require('./close-button'),
|
||||
MetricHeader: require('./header'),
|
||||
MetricSelect: require('./select'),
|
||||
|
307
ui/src/components/metric/metric-data.js
Normal file
307
ui/src/components/metric/metric-data.js
Normal file
@ -0,0 +1,307 @@
|
||||
module.exports = [{
|
||||
firstQuartile: 15,
|
||||
thirdQuartile: 15,
|
||||
median: 15,
|
||||
max: 15,
|
||||
min: 15,
|
||||
}, {
|
||||
firstQuartile: 26,
|
||||
thirdQuartile: 26,
|
||||
median: 26,
|
||||
max: 26,
|
||||
min: 26,
|
||||
}, {
|
||||
firstQuartile: 17,
|
||||
thirdQuartile: 17,
|
||||
median: 17,
|
||||
max: 17,
|
||||
min: 17,
|
||||
}, {
|
||||
firstQuartile: 15,
|
||||
thirdQuartile: 25,
|
||||
median: 19,
|
||||
max: 19,
|
||||
min: 20,
|
||||
}, {
|
||||
firstQuartile: 19,
|
||||
thirdQuartile: 25,
|
||||
median: 21,
|
||||
max: 20,
|
||||
min: 25,
|
||||
}, {
|
||||
firstQuartile: 24,
|
||||
thirdQuartile: 30,
|
||||
median: 25,
|
||||
max: 26,
|
||||
min: 27,
|
||||
}, {
|
||||
firstQuartile: 28,
|
||||
thirdQuartile: 34,
|
||||
median: 30,
|
||||
max: 30,
|
||||
min: 30,
|
||||
}, {
|
||||
firstQuartile: 30,
|
||||
thirdQuartile: 45,
|
||||
median: 35,
|
||||
max: 40,
|
||||
min: 40,
|
||||
}, {
|
||||
firstQuartile: 20,
|
||||
thirdQuartile: 55,
|
||||
median: 45,
|
||||
max: 44,
|
||||
min: 44,
|
||||
}, {
|
||||
firstQuartile: 55,
|
||||
thirdQuartile: 55,
|
||||
median: 55,
|
||||
max: 55,
|
||||
min: 55,
|
||||
}, {
|
||||
firstQuartile: 57,
|
||||
thirdQuartile: 56,
|
||||
median: 57,
|
||||
max: 58,
|
||||
min: 57,
|
||||
}, {
|
||||
firstQuartile: 57,
|
||||
thirdQuartile: 56,
|
||||
median: 56,
|
||||
max: 56,
|
||||
min: 56,
|
||||
}, {
|
||||
firstQuartile: 60,
|
||||
thirdQuartile: 56,
|
||||
median: 60,
|
||||
max: 60,
|
||||
min: 60,
|
||||
}, {
|
||||
firstQuartile: 57,
|
||||
thirdQuartile: 57,
|
||||
median: 57,
|
||||
max: 57,
|
||||
min: 57,
|
||||
}, {
|
||||
firstQuartile: 57,
|
||||
thirdQuartile: 55,
|
||||
median: 55,
|
||||
max: 55,
|
||||
min: 55,
|
||||
}, {
|
||||
firstQuartile: 20,
|
||||
thirdQuartile: 45,
|
||||
median: 45,
|
||||
max: 45,
|
||||
min: 45,
|
||||
}, {
|
||||
firstQuartile: 15,
|
||||
thirdQuartile: 40,
|
||||
median: 30,
|
||||
max: 49,
|
||||
min: 30,
|
||||
}, {
|
||||
firstQuartile: 15,
|
||||
thirdQuartile: 15,
|
||||
median: 15,
|
||||
max: 15,
|
||||
min: 15,
|
||||
}, {
|
||||
firstQuartile: 26,
|
||||
thirdQuartile: 26,
|
||||
median: 26,
|
||||
max: 26,
|
||||
min: 26,
|
||||
}, {
|
||||
firstQuartile: 17,
|
||||
thirdQuartile: 17,
|
||||
median: 17,
|
||||
max: 17,
|
||||
min: 17,
|
||||
}, {
|
||||
firstQuartile: 15,
|
||||
thirdQuartile: 25,
|
||||
median: 19,
|
||||
max: 19,
|
||||
min: 20,
|
||||
}, {
|
||||
firstQuartile: 19,
|
||||
thirdQuartile: 25,
|
||||
median: 21,
|
||||
max: 20,
|
||||
min: 25,
|
||||
}, {
|
||||
firstQuartile: 24,
|
||||
thirdQuartile: 30,
|
||||
median: 25,
|
||||
max: 26,
|
||||
min: 10,
|
||||
}, {
|
||||
firstQuartile: 28,
|
||||
thirdQuartile: 34,
|
||||
median: 30,
|
||||
max: 30,
|
||||
min: 30,
|
||||
}, {
|
||||
firstQuartile: 30,
|
||||
thirdQuartile: 45,
|
||||
median: 35,
|
||||
max: 40,
|
||||
min: 40,
|
||||
}, {
|
||||
firstQuartile: 20,
|
||||
thirdQuartile: 55,
|
||||
median: 45,
|
||||
max: 44,
|
||||
min: 44,
|
||||
}, {
|
||||
firstQuartile: 55,
|
||||
thirdQuartile: 55,
|
||||
median: 55,
|
||||
max: 55,
|
||||
min: 55,
|
||||
}, {
|
||||
firstQuartile: 57,
|
||||
thirdQuartile: 56,
|
||||
median: 57,
|
||||
max: 58,
|
||||
min: 57,
|
||||
}, {
|
||||
firstQuartile: 57,
|
||||
thirdQuartile: 56,
|
||||
median: 56,
|
||||
max: 56,
|
||||
min: 56,
|
||||
}, {
|
||||
firstQuartile: 60,
|
||||
thirdQuartile: 56,
|
||||
median: 60,
|
||||
max: 60,
|
||||
min: 60,
|
||||
}, {
|
||||
firstQuartile: 57,
|
||||
thirdQuartile: 57,
|
||||
median: 57,
|
||||
max: 57,
|
||||
min: 57,
|
||||
}, {
|
||||
firstQuartile: 57,
|
||||
thirdQuartile: 55,
|
||||
median: 55,
|
||||
max: 55,
|
||||
min: 55,
|
||||
}, {
|
||||
firstQuartile: 20,
|
||||
thirdQuartile: 45,
|
||||
median: 45,
|
||||
max: 45,
|
||||
min: 45,
|
||||
}, {
|
||||
firstQuartile: 15,
|
||||
thirdQuartile: 40,
|
||||
median: 30,
|
||||
max: 49,
|
||||
min: 30,
|
||||
}, {
|
||||
firstQuartile: 15,
|
||||
thirdQuartile: 15,
|
||||
median: 15,
|
||||
max: 15,
|
||||
min: 15,
|
||||
}, {
|
||||
firstQuartile: 26,
|
||||
thirdQuartile: 26,
|
||||
median: 26,
|
||||
max: 26,
|
||||
min: 26,
|
||||
}, {
|
||||
firstQuartile: 17,
|
||||
thirdQuartile: 17,
|
||||
median: 17,
|
||||
max: 17,
|
||||
min: 17,
|
||||
}, {
|
||||
firstQuartile: 15,
|
||||
thirdQuartile: 25,
|
||||
median: 19,
|
||||
max: 19,
|
||||
min: 20,
|
||||
}, {
|
||||
firstQuartile: 19,
|
||||
thirdQuartile: 25,
|
||||
median: 21,
|
||||
max: 20,
|
||||
min: 25,
|
||||
}, {
|
||||
firstQuartile: 24,
|
||||
thirdQuartile: 30,
|
||||
median: 25,
|
||||
max: 26,
|
||||
min: 27,
|
||||
}, {
|
||||
firstQuartile: 28,
|
||||
thirdQuartile: 34,
|
||||
median: 30,
|
||||
max: 30,
|
||||
min: 30,
|
||||
}, {
|
||||
firstQuartile: 30,
|
||||
thirdQuartile: 45,
|
||||
median: 35,
|
||||
max: 40,
|
||||
min: 40,
|
||||
}, {
|
||||
firstQuartile: 20,
|
||||
thirdQuartile: 55,
|
||||
median: 45,
|
||||
max: 44,
|
||||
min: 44,
|
||||
}, {
|
||||
firstQuartile: 55,
|
||||
thirdQuartile: 55,
|
||||
median: 55,
|
||||
max: 55,
|
||||
min: 55,
|
||||
}, {
|
||||
firstQuartile: 57,
|
||||
thirdQuartile: 56,
|
||||
median: 57,
|
||||
max: 58,
|
||||
min: 57,
|
||||
}, {
|
||||
firstQuartile: 57,
|
||||
thirdQuartile: 56,
|
||||
median: 56,
|
||||
max: 56,
|
||||
min: 56,
|
||||
}, {
|
||||
firstQuartile: 60,
|
||||
thirdQuartile: 56,
|
||||
median: 60,
|
||||
max: 60,
|
||||
min: 60,
|
||||
}, {
|
||||
firstQuartile: 57,
|
||||
thirdQuartile: 57,
|
||||
median: 57,
|
||||
max: 57,
|
||||
min: 57,
|
||||
}, {
|
||||
firstQuartile: 57,
|
||||
thirdQuartile: 55,
|
||||
median: 55,
|
||||
max: 55,
|
||||
min: 55,
|
||||
}, {
|
||||
firstQuartile: 20,
|
||||
thirdQuartile: 45,
|
||||
median: 45,
|
||||
max: 45,
|
||||
min: 45,
|
||||
}, {
|
||||
firstQuartile: 15,
|
||||
thirdQuartile: 40,
|
||||
median: 30,
|
||||
max: 49,
|
||||
min: 30,
|
||||
}];
|
@ -59,8 +59,10 @@ const Select = ({
|
||||
form,
|
||||
id = rndId(),
|
||||
name,
|
||||
onChange,
|
||||
required,
|
||||
selected
|
||||
selected,
|
||||
value
|
||||
}) => {
|
||||
return (
|
||||
<SelectWrapper>
|
||||
@ -70,8 +72,10 @@ const Select = ({
|
||||
form={form}
|
||||
id={id}
|
||||
name={name}
|
||||
onChange={onChange}
|
||||
required={required}
|
||||
selected={selected}
|
||||
value={value}
|
||||
>
|
||||
{children}
|
||||
</StyledSelect>
|
||||
@ -86,8 +90,10 @@ Select.propTypes = {
|
||||
form: React.PropTypes.string,
|
||||
id: React.PropTypes.string,
|
||||
name: React.PropTypes.string,
|
||||
onChange: React.PropTypes.func,
|
||||
required: React.PropTypes.bool,
|
||||
selected: React.PropTypes.bool
|
||||
selected: React.PropTypes.bool,
|
||||
value: React.PropTypes.string
|
||||
};
|
||||
|
||||
module.exports = Select;
|
||||
|
@ -3,7 +3,8 @@ const Styled = require('styled-components');
|
||||
const fns = require('../../shared/functions');
|
||||
const constants = require('../../shared/constants');
|
||||
const Button = require('../button');
|
||||
const SettingsIcon = require('!babel!svg-react!./close.svg?name=SettingsIcon');
|
||||
const SettingsIcon =
|
||||
require('!babel!svg-react!./icon-settings.svg?name=SettingsIcon');
|
||||
|
||||
const {
|
||||
default: styled
|
||||
|
@ -6,7 +6,7 @@ const {
|
||||
} = require('@kadira/storybook');
|
||||
|
||||
const {
|
||||
MetricBody,
|
||||
MetricGraph,
|
||||
MetricCloseButton,
|
||||
MetricHeader,
|
||||
MetricSelect,
|
||||
@ -15,7 +15,42 @@ const {
|
||||
MetricView
|
||||
} = require('./');
|
||||
|
||||
const MetricData = require('./metric-data');
|
||||
|
||||
const onButtonClick = () => {};
|
||||
const onMetricSelect = () => {};
|
||||
|
||||
const hour = 60; // in minutes - for moment
|
||||
const sixHours = 6*hour;
|
||||
const twelveHours = 12*hour;
|
||||
const oneDay = 24*hour;
|
||||
const twoDays = 48*hour;
|
||||
|
||||
const withinRange = (
|
||||
value,
|
||||
newMin,
|
||||
newMax,
|
||||
precision = 2,
|
||||
oldMin = 0,
|
||||
oldMax = 100
|
||||
) => {
|
||||
const normalisedValue = value-oldMin;
|
||||
const newRange = newMax-newMin;
|
||||
const oldRange = oldMax-oldMin;
|
||||
const newValue = newMin + normalisedValue*newRange/oldRange;
|
||||
return newValue.toFixed(2);
|
||||
};
|
||||
|
||||
const percentageMetricData = MetricData;
|
||||
const kbMetricData = MetricData.map(m => {
|
||||
return {
|
||||
firstQuartile: withinRange(m.firstQuartile, 1.55, 2.0),
|
||||
thirdQuartile: withinRange(m.thirdQuartile, 1.55, 2.0),
|
||||
median: withinRange(m.median, 1.55, 2.0),
|
||||
max: withinRange(m.max, 1.55, 2.0),
|
||||
min: withinRange(m.min, 1.55, 2.0),
|
||||
};
|
||||
});
|
||||
|
||||
storiesOf('Metric', module)
|
||||
.add('Metric', () => (
|
||||
@ -23,16 +58,46 @@ storiesOf('Metric', module)
|
||||
<MetricView>
|
||||
<MetricHeader>
|
||||
<MetricTitle>Aggregated CPU usage</MetricTitle>
|
||||
<MetricSelect>
|
||||
<option selected>6 hours</option>
|
||||
<option>12 hours</option>
|
||||
<option>24 hours</option>
|
||||
<option>Two days</option>
|
||||
<MetricSelect onChange={onMetricSelect} value={sixHours}>
|
||||
<option value={sixHours}>6 hours</option>
|
||||
<option value={twelveHours}>12 hours</option>
|
||||
<option value={oneDay}>24 hours</option>
|
||||
<option value={twoDays}>Two days</option>
|
||||
</MetricSelect>
|
||||
<MetricSettingsButton>Settings</MetricSettingsButton>
|
||||
<MetricSettingsButton onClick={onButtonClick}>
|
||||
Settings
|
||||
</MetricSettingsButton>
|
||||
<MetricCloseButton onClick={onButtonClick} />
|
||||
</MetricHeader>
|
||||
<MetricBody />
|
||||
<MetricGraph
|
||||
data={percentageMetricData}
|
||||
duration={sixHours}
|
||||
yMax={100}
|
||||
yMeasurement='%'
|
||||
yMin={0}
|
||||
/>
|
||||
</MetricView>
|
||||
<MetricView>
|
||||
<MetricHeader>
|
||||
<MetricTitle>Aggregated CPU usage</MetricTitle>
|
||||
<MetricSelect onChange={onMetricSelect} value={twoDays}>
|
||||
<option value={sixHours}>6 hours</option>
|
||||
<option value={twelveHours}>12 hours</option>
|
||||
<option value={oneDay}>24 hours</option>
|
||||
<option value={twoDays}>Two days</option>
|
||||
</MetricSelect>
|
||||
<MetricSettingsButton onClick={onButtonClick}>
|
||||
Settings
|
||||
</MetricSettingsButton>
|
||||
<MetricCloseButton onClick={onButtonClick} />
|
||||
</MetricHeader>
|
||||
<MetricGraph
|
||||
data={kbMetricData}
|
||||
duration={oneDay}
|
||||
yMax={2.0}
|
||||
yMeasurement='kb'
|
||||
yMin={1.55}
|
||||
/>
|
||||
</MetricView>
|
||||
</Base>
|
||||
));
|
||||
|
@ -1,4 +1,5 @@
|
||||
const constants = require('../../shared/constants');
|
||||
const fns = require('../../shared/functions');
|
||||
const React = require('react');
|
||||
const Styled = require('styled-components');
|
||||
|
||||
@ -7,6 +8,10 @@ const {
|
||||
colors
|
||||
} = constants;
|
||||
|
||||
const {
|
||||
remcalc
|
||||
} = fns;
|
||||
|
||||
const {
|
||||
default: styled
|
||||
} = Styled;
|
||||
@ -15,6 +20,7 @@ const Container = styled.div`
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
max-width: ${remcalc(940)};
|
||||
box-shadow: ${boxes.bottomShaddow};
|
||||
border: 1px solid ${colors.borderSecondary};
|
||||
`;
|
||||
|
55
ui/src/components/mini-metric/story.js
Normal file
55
ui/src/components/mini-metric/story.js
Normal file
@ -0,0 +1,55 @@
|
||||
const React = require('react');
|
||||
const Base = require('../base');
|
||||
const Row = require('../row');
|
||||
const Column = require('../column');
|
||||
|
||||
const {
|
||||
storiesOf,
|
||||
// action,
|
||||
// linkTo
|
||||
} = require('@kadira/storybook');
|
||||
|
||||
const {
|
||||
MiniMetricGraph,
|
||||
MiniMetricMeta,
|
||||
MiniMetricTitle,
|
||||
MiniMetricSubtitle,
|
||||
MiniMetricView
|
||||
} = require('./');
|
||||
|
||||
const MiniMetricData = require('../list/mini-metric-data');
|
||||
|
||||
storiesOf('Metric (Mini)', module)
|
||||
.add('Mini Metric', () => (
|
||||
<Base>
|
||||
<Row around>
|
||||
<Column xs={3}>
|
||||
<MiniMetricView>
|
||||
<MiniMetricMeta>
|
||||
<MiniMetricTitle>Memory: 54%</MiniMetricTitle>
|
||||
<MiniMetricSubtitle>(1280/3000 MB)</MiniMetricSubtitle>
|
||||
</MiniMetricMeta>
|
||||
<MiniMetricGraph data={MiniMetricData} />
|
||||
</MiniMetricView>
|
||||
</Column>
|
||||
<Column xs={3}>
|
||||
<MiniMetricView>
|
||||
<MiniMetricMeta>
|
||||
<MiniMetricTitle>Memory: 54%</MiniMetricTitle>
|
||||
<MiniMetricSubtitle>(1280/3000 MB)</MiniMetricSubtitle>
|
||||
</MiniMetricMeta>
|
||||
<MiniMetricGraph data={MiniMetricData} />
|
||||
</MiniMetricView>
|
||||
</Column>
|
||||
<Column xs={3}>
|
||||
<MiniMetricView>
|
||||
<MiniMetricMeta>
|
||||
<MiniMetricTitle>Memory: 54%</MiniMetricTitle>
|
||||
<MiniMetricSubtitle>(1280/3000 MB)</MiniMetricSubtitle>
|
||||
</MiniMetricMeta>
|
||||
<MiniMetricGraph data={MiniMetricData} />
|
||||
</MiniMetricView>
|
||||
</Column>
|
||||
</Row>
|
||||
</Base>
|
||||
));
|
@ -49,4 +49,4 @@ View.propTypes = {
|
||||
children: React.PropTypes.node
|
||||
};
|
||||
|
||||
module.exports = View;
|
||||
module.exports = View;
|
||||
|
@ -4378,7 +4378,7 @@ mobx@^2.3.4:
|
||||
version "2.7.0"
|
||||
resolved "https://registry.yarnpkg.com/mobx/-/mobx-2.7.0.tgz#cf3d82d18c0ca7f458d8f2a240817b3dc7e54a01"
|
||||
|
||||
moment@^2.10.6:
|
||||
moment@^2.10.6, moment@^2.17.1:
|
||||
version "2.17.1"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user