Topology constraints, metrics uppercase fix, node title link

This commit is contained in:
Alex Windett 2017-03-23 15:31:25 +00:00 committed by Sérgio Ramos
parent 398071ade2
commit 97a4537330
8 changed files with 95 additions and 47 deletions

View File

@ -2,18 +2,18 @@
"your-dashboard": "Your dashboard",
"project-feed": "Project Feed",
"summary": "Summary",
"metric-s": "Metrics",
"metrics": "Metrics",
"networks": "Networks",
"tags-metadata": "Tags and Meta Data",
"activity-feed": "Activity Feed",
"firewall": "Firewall",
"service-manifest": "Service manifest",
"settings": "Settings",
"projects": "Projects",
"people": "People",
"services": "Services",
"instances": "Instances",
"manifest": "Project manifest",
"service-manifest": "Service manifest",
"create-new": "Create new project",
"rollback": "Rollback",
"import-services-title": "Import your services",
@ -52,7 +52,7 @@
"description": "Please provide your billing details.",
"save-details-label": "Save details"
},
"metrics": {
"metrics-section": {
"add": {
"add-label": "Add",
"added-label": "Added",

View File

@ -21,26 +21,29 @@ const AddMetrics = ({
const addButton = (metric) => (
<AddMetricButton metric={metric} onClick={onAddMetric}>
<FormattedMessage id={'metrics.add.add-label'} onClick={onAddMetric} />
<FormattedMessage
id={'metrics-section.add.add-label'}
onClick={onAddMetric}
/>
</AddMetricButton>
);
const addedButton = (
<AddMetricButton disabled>
<FormattedMessage id={'metrics.add.added-label'} />
<FormattedMessage id={'metrics-section.add.added-label'} />
</AddMetricButton>
);
const metricList = metricTypes.map((metric) => (
<AddMetricTile key={metric.id}>
<AddMetricTitle>
<FormattedMessage id={`metrics.${metric.id}.title`} />
<FormattedMessage id={`metrics-section.${metric.id}.title`} />
</AddMetricTitle>
<AddMetricDescription>
<FormattedMessage id={`metrics.${metric.id}.description`} />
<FormattedMessage id={`metrics-section.${metric.id}.description`} />
</AddMetricDescription>
<AddMetricLink href='http://somelink.com'>
<FormattedMessage id={'metrics.add.link-label'} />
<FormattedMessage id={'metrics-section.add.link-label'} />
</AddMetricLink>
{ added(metric.uuid) ? addedButton : addButton(metric.uuid) }
</AddMetricTile>

View File

@ -47,13 +47,13 @@ const MetricCharts = ({
<MetricHeader>
<MetricTitle>
{type.name}
{/*<FormattedMessage id={`metrics.${type.id}.title`} />*/}
{/*<FormattedMessage id={`metrics-section.${type.id}.title`} />*/}
</MetricTitle>
<MetricSelect onChange={handleSelectChange} value={String(duration)}>
{optionList}
</MetricSelect>
<MetricSettingsButton onClick={handleSettingsClick}>
<FormattedMessage id={'metrics.metric.settings-label'} />
<FormattedMessage id={'metrics-section.metric.settings-label'} />
</MetricSettingsButton>
<MetricCloseButton onClick={handleRemoveMetric} />
</MetricHeader>

View File

@ -2,7 +2,8 @@ import React from 'react';
import { connect } from 'react-redux';
import styled from 'styled-components';
import PropTypes from '@root/prop-types';
import { colors } from '@ui/shared/constants';
import { colors, breakpoints } from '@ui/shared/constants';
import { unitcalc } from '@ui/shared/functions';
import { TopologyGraph } from '@ui/components/topology';
import { LayoutContainer } from '@components/layout';
import ServicesTooltip from '@components/services/tooltip';
@ -22,6 +23,11 @@ const StyledBackground = styled.div`
const StyledContainer = styled(LayoutContainer)`
position: relative;
padding: ${unitcalc(4)} 2rem;
${breakpoints.large`
padding: ${unitcalc(4)} 0;
`}
`;
const Services = (props) => {
@ -30,14 +36,16 @@ const Services = (props) => {
org = {},
project = {},
toggleTooltip,
uiTooltip
uiTooltip,
push
} = props;
const onQuickActions = (evt, tooltipData) => {
const service = services.reduce((acc, service) =>
service.uuid === tooltipData.service ? service : acc
, {});
const getService = (uuid) => services.reduce((acc, service) =>
service.uuid === uuid ? service : acc
, {});
const onQuickActions = (evt, tooltipData) => {
const service = getService(tooltipData.service);
const ttData = {
...tooltipData,
data: {
@ -54,11 +62,20 @@ const Services = (props) => {
service: uiTooltip.service
});
const onNodeTitleClick = (uuid) => {
const service = getService(uuid);
const path = `/${org.id}/projects/${project.id}/services/${service.id}`;
push(path);
};
return (
<StyledBackground>
<StyledContainer>
<TopologyGraph
onQuickActions={onQuickActions}
onNodeTitleClick={onNodeTitleClick}
services={services}
/>
<ServicesTooltip {...uiTooltip} onBlur={handleTooltipBlur} />
@ -71,6 +88,7 @@ Services.propTypes = {
org: PropTypes.org,
services: React.PropTypes.arrayOf(PropTypes.service),
project: PropTypes.project,
push: React.PropTypes.func.isRequired,
toggleTooltip: React.PropTypes.func,
uiTooltip: React.PropTypes.object
};
@ -78,12 +96,14 @@ Services.propTypes = {
const mapStateToProps = (state, {
match = {
params: {}
}
},
push
}) => ({
org: orgByIdSelector(match.params.org)(state),
project: projectByIdSelector(match.params.projectId)(state),
services: servicesForTopologySelector(match.params.projectId)(state),
uiTooltip: serviceUiTooltipSelector(state)
uiTooltip: serviceUiTooltipSelector(state),
push: push
});
const mapDispatchToProps = (dispatch) => ({

View File

@ -75,7 +75,7 @@
"id": "cpu-wait-time",
"min": 0,
"max": 100,
"measurement": "%"
"measurement": "bytes"
}, {
"uuid": "dca08514-72e5-46ce-ad91-e68b3b0914d7",
"name": "Zfs used",
@ -96,14 +96,14 @@
"id": "load-average",
"min": 0,
"max": 20,
"measurement": "kb"
"measurement": " Mb"
}, {
"uuid": "dca08514-72e5-46ce-ad92-e68b3b0914d4",
"name": "Memory",
"id": "mem-agg-usage",
"min": 0,
"max": 100,
"measurement": "%"
"measurement": " Mb"
}, {
"uuid": "dca08514-72e5-46ce-ad93-e68b3b0914d4",
"name": "Memory limit",

View File

@ -14,6 +14,7 @@ const GraphNode = ({
data,
index,
onDragStart,
onNodeTitleClick,
onQuickActions
}) => {
@ -61,6 +62,9 @@ const GraphNode = ({
onQuickActions(evt, d);
};
const onTitleClick = () =>
onNodeTitleClick(data.uuid);
const onStart = (evt) => {
evt.preventDefault();
onDragStart(evt, data.id);
@ -107,6 +111,7 @@ const GraphNode = ({
<GraphNodeTitle
connected={connected}
data={data}
onNodeTitleClick={onTitleClick}
/>
<GraphNodeButton
connected={connected}
@ -123,6 +128,7 @@ GraphNode.propTypes = {
data: React.PropTypes.object.isRequired,
index: React.PropTypes.number.isRequired,
onDragStart: React.PropTypes.func,
onNodeTitleClick: React.PropTypes.func,
onQuickActions: React.PropTypes.func
};

View File

@ -6,7 +6,8 @@ import HeartIcon from './icon-heart.svg';
const GraphNodeTitle = ({
connected,
data
data,
onNodeTitleClick
}) => {
return (
@ -15,6 +16,8 @@ const GraphNodeTitle = ({
x={Constants.paddingLeft}
y={30}
connected={connected}
onClick={onNodeTitleClick}
onKeyDown={onNodeTitleClick}
>
{data.name}
</GraphTitle>
@ -32,7 +35,8 @@ const GraphNodeTitle = ({
GraphNodeTitle.propTypes = {
connected: React.PropTypes.bool,
data: React.PropTypes.object.isRequired
data: React.PropTypes.object.isRequired,
onNodeTitleClick: React.PropTypes.func
};
export default Baseline(

View File

@ -5,7 +5,6 @@ import Constants from './constants';
import GraphNode from './graph-node';
import GraphLink from './graph-link';
import React from 'react';
import { triggerMouseEvent } from '../../shared/functions';
const StyledSvg = styled.svg`
width: 100%;
@ -103,26 +102,36 @@ class TopologyGraph extends React.Component {
}
}
isWithinSVGBounds(target, x, y) {
const svgBounds = document
.getElementsByClassName('topology-svg')[0]
.getBoundingClientRect();
getSvgSize() {
return document.getElementById('topology-svg') ?
document.getElementById('topology-svg').getBoundingClientRect() :
svgSize;
}
const nodeHeight = target.getBoundingClientRect().height;
const nodeWidth = target.getBoundingClientRect().width;
constrain(x, y, children=false) {
const svgSize = this.getSvgSize();
const constraints = {
top: svgBounds.top + (nodeHeight / 2),
left: svgBounds.left + (nodeWidth / 2),
bottom: svgBounds.bottom - (nodeHeight / 2),
right: svgBounds.right - (nodeWidth / 2)
const nodeRect = children ?
Constants.nodeRectWithChildren :
Constants.nodeRect;
if(x < nodeRect.right + 2) {
x = nodeRect.right + 2;
}
else if(x > svgSize.width + nodeRect.left - 2) {
x = svgSize.width + nodeRect.left - 2;
}
if(y < -nodeRect.top + 2) {
y = -nodeRect.top + 2;
}
else if(y > svgSize.height - nodeRect.bottom - 2) {
y = svgSize.height - nodeRect.bottom - 2;
}
return {
x,
y
};
if ( x > constraints.right || x < constraints.left ) return false;
if ( y < constraints.top || y > constraints.bottom ) return false;
return true;
}
render() {
@ -147,9 +156,14 @@ class TopologyGraph extends React.Component {
y: 0
} : simNode(service.uuid);
const constrained = {
...sNode,
...this.constrain(sNode.x, sNode.y, service.children)
};
return ({
...service,
...sNode
...constrained
});
});
@ -188,10 +202,6 @@ class TopologyGraph extends React.Component {
? evt.changedTouches[0].pageY
: evt.clientY;
if ( !this.isWithinSVGBounds(evt.target, x, y) ) {
triggerMouseEvent(evt.target, 'mouseup');
}
const offset = {
x: x - dragInfo.position.x,
y: y - dragInfo.position.y
@ -229,12 +239,16 @@ class TopologyGraph extends React.Component {
};
};
const onTitleClick = (serviceUUID) =>
this.props.onNodeTitleClick(serviceUUID);
const renderedNodes = nodesData.map((n, index) => (
<GraphNode
key={index}
data={n}
index={index}
onDragStart={onDragStart}
onNodeTitleClick={onTitleClick}
onQuickActions={onQuickActions}
connected={n.id !== 'consul'}
/>
@ -255,7 +269,7 @@ class TopologyGraph extends React.Component {
onMouseUp={onDragEnd}
onTouchEnd={onDragEnd}
onTouchCancel={onDragEnd}
className='topology-svg'
id='topology-svg'
>
<g>
{renderedNodes}
@ -270,6 +284,7 @@ class TopologyGraph extends React.Component {
TopologyGraph.propTypes = {
onQuickActions: React.PropTypes.func,
onNodeTitleClick: React.PropTypes.func,
services: React.PropTypes.array
};