1
0
mirror of https://github.com/yldio/copilot.git synced 2024-11-14 07:10:05 +02:00

instance metrics

This commit is contained in:
Sérgio Ramos 2017-01-11 21:11:48 +00:00
parent 520b178281
commit 6f48ec1d23
10 changed files with 239 additions and 91 deletions

View File

@ -0,0 +1,56 @@
const React = require('react');
const Styled = require('styled-components');
const Column = require('@ui/components/column');
const MiniMetric = require('@ui/components/mini-metric');
const PropTypes = require('@root/prop-types');
const Row = require('@ui/components/row');
const {
default: styled
} = Styled;
const {
MiniMetricGraph,
MiniMetricMeta,
MiniMetricTitle,
MiniMetricSubtitle,
MiniMetricView
} = MiniMetric;
const StyledRow = styled(Row)`
margin: 0;
& > div {
padding-left: 0;
padding-right: 0;
}
`;
const MetricsRow = ({
datasets = []
}) => {
const _datasets = datasets.map((metric, i) => (
<Column key={i} xs={4}>
<MiniMetricView borderless>
<MiniMetricMeta>
<MiniMetricTitle>Memory: 54%</MiniMetricTitle>
<MiniMetricSubtitle>(1280/3000 MB)</MiniMetricSubtitle>
</MiniMetricMeta>
<MiniMetricGraph data={metric.data} />
</MiniMetricView>
</Column>
));
return (
<StyledRow>
{_datasets}
</StyledRow>
);
};
MetricsRow.propTypes = {
datasets: React.PropTypes.arrayOf(PropTypes.dataset)
};
module.exports = MetricsRow;

View File

@ -1,23 +1,16 @@
const forceArray = require('force-array'); const forceArray = require('force-array');
const React = require('react'); const React = require('react');
const ReactRouter = require('react-router'); const ReactRouter = require('react-router');
const Styled = require('styled-components');
const Anchor = require('@ui/components/anchor'); const Anchor = require('@ui/components/anchor');
const Column = require('@ui/components/column');
const List = require('@ui/components/list'); const List = require('@ui/components/list');
const MiniMetric = require('@ui/components/mini-metric'); const MetricsRow = require('@components/metrics-row');
const PropTypes = require('@root/prop-types'); const PropTypes = require('@root/prop-types');
const Row = require('@ui/components/row');
const { const {
Link Link
} = ReactRouter; } = ReactRouter;
const {
default: styled
} = Styled;
const { const {
ListItem, ListItem,
ListItemView, ListItemView,
@ -31,23 +24,6 @@ const {
ListItemHeader ListItemHeader
} = List; } = List;
const {
MiniMetricGraph,
MiniMetricMeta,
MiniMetricTitle,
MiniMetricSubtitle,
MiniMetricView
} = MiniMetric;
const MetricsRow = styled(Row)`
margin: 0;
& > div {
padding-left: 0;
padding-right: 0;
}
`;
const ServiceItem = ({ const ServiceItem = ({
org = '', org = '',
project = '', project = '',
@ -99,18 +75,6 @@ const ServiceItem = ({
</ListItemHeader> </ListItemHeader>
); );
const metrics = service.metrics.map((metric, i) => (
<Column key={i} xs={4}>
<MiniMetricView borderless>
<MiniMetricMeta>
<MiniMetricTitle>Memory: 54%</MiniMetricTitle>
<MiniMetricSubtitle>(1280/3000 MB)</MiniMetricSubtitle>
</MiniMetricMeta>
<MiniMetricGraph data={metric.data} />
</MiniMetricView>
</Column>
));
const view = childs.length ? ( const view = childs.length ? (
<ListItemGroupView> <ListItemGroupView>
{childs} {childs}
@ -123,9 +87,7 @@ const ServiceItem = ({
{description} {description}
</ListItemMeta> </ListItemMeta>
<ListItemOutlet> <ListItemOutlet>
<MetricsRow> <MetricsRow metrics={service.metrics} />
{metrics}
</MetricsRow>
</ListItemOutlet> </ListItemOutlet>
</ListItemView> </ListItemView>
); );

View File

@ -1,11 +1,17 @@
const React = require('react'); const React = require('react');
const ReactRedux = require('react-redux'); const ReactRedux = require('react-redux');
const actions = require('@state/actions');
const EmptyInstances = require('@components/empty/instances'); const EmptyInstances = require('@components/empty/instances');
const PropTypes = require('@root/prop-types'); const PropTypes = require('@root/prop-types');
const List = require('@ui/components/list'); const List = require('@ui/components/list');
const DatasetsRow = require('@components/metrics-row');
const selectors = require('@state/selectors'); const selectors = require('@state/selectors');
const {
toggleInstanceCollapsed
} = actions;
const { const {
connect connect
} = ReactRedux; } = ReactRedux;
@ -19,22 +25,29 @@ const {
ListItemView, ListItemView,
ListItemMeta, ListItemMeta,
ListItemTitle, ListItemTitle,
ListItemOptions ListItemOptions,
ListItemOutlet
} = List; } = List;
const Instances = ({ const Instances = ({
instances = [] instances = [],
toggleCollapsed = () => null
}) => { }) => {
const onClick = (uuid) => () => toggleCollapsed(uuid);
const empty = instances.length ? null : ( const empty = instances.length ? null : (
<EmptyInstances /> <EmptyInstances />
); );
const instanceList = instances.map((service) => ( const instanceList = instances.map((instance) => (
<ListItem collapsed key={service.uuid}> <ListItem collapsed={!instance.collapsed} key={instance.uuid} >
<ListItemView> <ListItemView>
<ListItemMeta> <ListItemMeta onClick={onClick(instance.uuid)}>
<ListItemTitle>{service.name}</ListItemTitle> <ListItemTitle>{instance.name}</ListItemTitle>
</ListItemMeta> </ListItemMeta>
<ListItemOutlet>
<DatasetsRow metrics={instance.metrics} />
</ListItemOutlet>
</ListItemView> </ListItemView>
<ListItemOptions> <ListItemOptions>
@ -51,7 +64,8 @@ const Instances = ({
}; };
Instances.propTypes = { Instances.propTypes = {
instances: React.PropTypes.arrayOf(PropTypes.instance) instances: React.PropTypes.arrayOf(PropTypes.instance),
toggleCollapsed: React.PropTypes.func
}; };
const mapStateToProps = (state, { const mapStateToProps = (state, {
@ -60,6 +74,11 @@ const mapStateToProps = (state, {
instances: instancesByServiceIdSelector(params.serviceId)(state) instances: instancesByServiceIdSelector(params.serviceId)(state)
}); });
const mapDispatchToProps = (dispatch) => ({
toggleCollapsed: (uuid) => dispatch(toggleInstanceCollapsed(uuid))
});
module.exports = connect( module.exports = connect(
mapStateToProps mapStateToProps,
mapDispatchToProps
)(Instances); )(Instances);

View File

@ -378,72 +378,130 @@
}] }]
}, },
"instances": { "instances": {
"ui": {
"collapsed": []
},
"data": [{ "data": [{
"uuid": "309ecd9f-ac03-474b-aff7-4bd2e743296c", "uuid": "309ecd9f-ac03-474b-aff7-4bd2e743296c",
"name": "wordpress_01", "name": "wordpress_01",
"datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb", "datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb",
"service": "be227788-74f1-4e5b-a85f-b5c71cbae8d8", "service": "be227788-74f1-4e5b-a85f-b5c71cbae8d8",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401" "project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"metrics": [
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec"
]
}, { }, {
"uuid": "0db6db53-de6f-4378-839e-5d5b452fbaf2", "uuid": "0db6db53-de6f-4378-839e-5d5b452fbaf2",
"name": "nfs_01", "name": "nfs_01",
"datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb", "datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb",
"service": "6a0eee76-c019-413b-9d5f-44712b55b993", "service": "6a0eee76-c019-413b-9d5f-44712b55b993",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401" "project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"metrics": [
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec"
]
}, { }, {
"uuid": "250c8a6c-7d02-49a9-8abd-e1c22773041d", "uuid": "250c8a6c-7d02-49a9-8abd-e1c22773041d",
"name": "consul", "name": "consul",
"datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb", "datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb",
"service": "97c68055-db88-45c9-ad49-f26da4264777", "service": "97c68055-db88-45c9-ad49-f26da4264777",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401" "project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"metrics": [
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec"
]
}, { }, {
"uuid": "2c921f3a-8bc3-4f57-9cd7-789ebae72061", "uuid": "2c921f3a-8bc3-4f57-9cd7-789ebae72061",
"name": "memcache_01", "name": "memcache_01",
"datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb", "datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb",
"service": "6d31aff4-de1e-4042-a983-fbd23d5c530c", "service": "6d31aff4-de1e-4042-a983-fbd23d5c530c",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401" "project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"metrics": [
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec"
]
}, { }, {
"uuid": "68d3046e-8e34-4f5d-a0e5-db3795a250fd", "uuid": "68d3046e-8e34-4f5d-a0e5-db3795a250fd",
"name": "memcache_02", "name": "memcache_02",
"datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb", "datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb",
"service": "6d31aff4-de1e-4042-a983-fbd23d5c530c", "service": "6d31aff4-de1e-4042-a983-fbd23d5c530c",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401" "project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"metrics": [
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec"
]
}, { }, {
"uuid": "2ea99763-3b44-4179-8393-d66d94961051", "uuid": "2ea99763-3b44-4179-8393-d66d94961051",
"name": "memcache_03", "name": "memcache_03",
"datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb", "datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb",
"service": "6d31aff4-de1e-4042-a983-fbd23d5c530c", "service": "6d31aff4-de1e-4042-a983-fbd23d5c530c",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401" "project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"metrics": [
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec"
]
}, { }, {
"uuid": "25f6bc62-63b8-4959-908e-1f6d7ff6341d", "uuid": "25f6bc62-63b8-4959-908e-1f6d7ff6341d",
"name": "memcache_04", "name": "memcache_04",
"datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb", "datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb",
"service": "6d31aff4-de1e-4042-a983-fbd23d5c530c", "service": "6d31aff4-de1e-4042-a983-fbd23d5c530c",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401" "project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"metrics": [
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec"
]
}, { }, {
"uuid": "8be01042-0281-4a77-a357-25979e87bf3d", "uuid": "8be01042-0281-4a77-a357-25979e87bf3d",
"name": "memcache_05", "name": "memcache_05",
"datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb", "datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb",
"service": "6d31aff4-de1e-4042-a983-fbd23d5c530c", "service": "6d31aff4-de1e-4042-a983-fbd23d5c530c",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401" "project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"metrics": [
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec"
]
}, { }, {
"uuid": "3d652e9d-73e8-4a6f-8171-84fa83740662", "uuid": "3d652e9d-73e8-4a6f-8171-84fa83740662",
"name": "nginx", "name": "nginx",
"datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb", "datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb",
"service": "081a792c-47e0-4439-924b-2efa9788ae9e", "service": "081a792c-47e0-4439-924b-2efa9788ae9e",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401" "project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"metrics": [
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec"
]
}, { }, {
"uuid": "c3ec7633-a02b-4615-86a0-9e6faeaae94b", "uuid": "c3ec7633-a02b-4615-86a0-9e6faeaae94b",
"name": "percona-primary", "name": "percona-primary",
"datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb", "datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb",
"service": "4ee4103e-1a52-4099-a48e-01588f597c70", "service": "4ee4103e-1a52-4099-a48e-01588f597c70",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401" "project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"metrics": [
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec"
]
}, { }, {
"uuid": "c2b5fec2-31e2-41a7-b7fc-cd0bb1822e76", "uuid": "c2b5fec2-31e2-41a7-b7fc-cd0bb1822e76",
"name": "percona-secundary", "name": "percona-secundary",
"datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb", "datacenter": "f018da03-41c8-4619-a36a-ab8b706160cb",
"service": "4ee4103e-1a52-4099-a48e-01588f597c70", "service": "4ee4103e-1a52-4099-a48e-01588f597c70",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401" "project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"metrics": [
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec",
"3e6ee79a-7453-4fc6-b9da-7ae1e41138ec"
]
}] }]
} }
} }

View File

@ -39,6 +39,20 @@ const Metric = React.PropTypes.shape({
...BaseObject ...BaseObject
}); });
const Dataset = React.PropTypes.shape({
uuid: React.PropTypes.string,
type: React.PropTypes.string,
data: React.PropTypes.arrayOf(
React.PropTypes.shape({
firstQuartile: React.PropTypes.string,
thirdQuartile: React.PropTypes.string,
median: React.PropTypes.string,
max: React.PropTypes.string,
min: React.PropTypes.string
})
)
});
const Sections = React.PropTypes.arrayOf( const Sections = React.PropTypes.arrayOf(
React.PropTypes.string React.PropTypes.string
); );
@ -58,5 +72,6 @@ module.exports = {
instance: Instance, instance: Instance,
metric: Metric, metric: Metric,
// consinder renaming this to 'Types' as it could be used for any // consinder renaming this to 'Types' as it could be used for any
metricTypes: MetricTypes metricTypes: MetricTypes,
dataset: Dataset
}; };

View File

@ -11,5 +11,6 @@ module.exports = {
...require('@state/thunks'), ...require('@state/thunks'),
updateRouter: createAction(`${APP}/APP/UPDATE_ROUTER`), updateRouter: createAction(`${APP}/APP/UPDATE_ROUTER`),
toggleHeaderTooltip: createAction(`${APP}/APP/TOGGLE_HEADER_TOOLTIP`), toggleHeaderTooltip: createAction(`${APP}/APP/TOGGLE_HEADER_TOOLTIP`),
toggleServiceCollapsed: createAction(`${APP}/APP/TOGGLE_SERVICE_COLLAPSED`) toggleServiceCollapsed: createAction(`${APP}/APP/TOGGLE_SERVICE_COLLAPSED`),
toggleInstanceCollapsed: createAction(`${APP}/APP/TOGGLE_INSTANCE_COLLAPSED`)
}; };

View File

@ -0,0 +1,25 @@
const toggleCollapsed = (state, action) => {
const {
ui
} = state;
const {
collapsed = []
} = ui;
const _collapsed = collapsed.indexOf(action.payload) >= 0
? collapsed.filter((uuid) => uuid !== action.payload)
: [...collapsed, action.payload];
return {
...state,
ui: {
...ui,
collapsed: _collapsed
}
};
};
module.exports = {
toggleCollapsed
};

View File

@ -1,9 +1,20 @@
const ReduxActions = require('redux-actions'); const ReduxActions = require('redux-actions');
const actions = require('@state/actions');
const common = require('@state/reducers/common');
const { const {
handleActions handleActions
} = ReduxActions; } = ReduxActions;
const {
toggleInstanceCollapsed
} = actions;
const {
toggleCollapsed
} = common;
module.exports = handleActions({ module.exports = handleActions({
'x': (state) => state // somehow handleActions needs at least one reducer [toggleInstanceCollapsed.toString()]: toggleCollapsed
}, {}); }, {});

View File

@ -1,6 +1,7 @@
const ReduxActions = require('redux-actions'); const ReduxActions = require('redux-actions');
const actions = require('@state/actions'); const actions = require('@state/actions');
const common = require('@state/reducers/common');
const { const {
handleActions handleActions
@ -10,14 +11,10 @@ const {
toggleServiceCollapsed toggleServiceCollapsed
} = actions; } = actions;
const {
toggleCollapsed
} = common;
module.exports = handleActions({ module.exports = handleActions({
[toggleServiceCollapsed.toString()]: (state, action) => ({ [toggleServiceCollapsed.toString()]: toggleCollapsed
...state,
ui: {
...state.ui,
collapsed: state.ui.collapsed.indexOf(action.payload) >= 0
? state.ui.collapsed.filter((uuid) => uuid !== action.payload)
: [...state.ui.collapsed, action.payload]
}
})
}, {}); }, {});

View File

@ -16,6 +16,7 @@ const orgs = (state) => get(state, 'orgs.data', []);
const projects = (state) => get(state, 'projects.data', []); const projects = (state) => get(state, 'projects.data', []);
const services = (state) => get(state, 'services.data', []); const services = (state) => get(state, 'services.data', []);
const collapsedServices = (state) => get(state, 'services.ui.collapsed', []); const collapsedServices = (state) => get(state, 'services.ui.collapsed', []);
const collapsedInstances = (state) => get(state, 'instances.ui.collapsed', []);
const instances = (state) => get(state, 'instances.data', []); const instances = (state) => get(state, 'instances.data', []);
const metricDatasets = (state) => get(state, 'metrics.data.datasets', []); const metricDatasets = (state) => get(state, 'metrics.data.datasets', []);
@ -46,6 +47,13 @@ const orgSections = (orgId) => createSelector(
) )
); );
const isCollapsed = (collapsed, uuid) => collapsed.indexOf(uuid) >= 0;
const datasets = (metrics, uuids) => uuids.map((uuid) => find(metrics, [
'uuid',
uuid
]));
const servicesByProjectId = (projectId) => createSelector( const servicesByProjectId = (projectId) => createSelector(
[services, projectById(projectId), collapsedServices, metricDatasets], [services, projectById(projectId), collapsedServices, metricDatasets],
(services, project, collapsed, metrics) => (services, project, collapsed, metrics) =>
@ -55,31 +63,27 @@ const servicesByProjectId = (projectId) => createSelector(
services: services.filter((s) => s.parent === service.uuid) services: services.filter((s) => s.parent === service.uuid)
})) }))
.filter((s) => !s.parent) .filter((s) => !s.parent)
.map((service) => { .map((service) => ({
const isCollapsed = (uuid) => collapsed.indexOf(uuid) >= 0; ...service,
metrics: datasets(metrics, service.metrics),
const datasets = (uuids) => uuids.map((uuid) => find(metrics, [ collapsed: isCollapsed(collapsed, service.uuid),
'uuid', services: service.services.map((service) => ({
uuid
]));
return {
...service, ...service,
metrics: datasets(service.metrics), metrics: datasets(metrics, service.metrics),
collapsed: isCollapsed(service.uuid), collapsed: isCollapsed(collapsed, service.uuid)
services: service.services.map((service) => ({ }))
...service, }))
metrics: datasets(service.metrics),
collapsed: isCollapsed(service.uuid)
}))
};
})
); );
const instancesByServiceId = (serviceId) => createSelector( const instancesByServiceId = (serviceId) => createSelector(
[instances, serviceById(serviceId)], [instances, serviceById(serviceId), collapsedInstances, metricDatasets],
(instances, service) => (instances, service, collapsed, metrics) =>
instances.filter((i) => i.service === service.uuid) instances.filter((i) => i.service === service.uuid)
.map((instance) => ({
...instance,
metrics: datasets(metrics, instance.metrics),
collapsed: isCollapsed(collapsed, instance.uuid)
}))
); );