Topology constraints, metrics uppercase fix, node title link
This commit is contained in:
parent
398071ade2
commit
97a4537330
@ -2,18 +2,18 @@
|
|||||||
"your-dashboard": "Your dashboard",
|
"your-dashboard": "Your dashboard",
|
||||||
"project-feed": "Project Feed",
|
"project-feed": "Project Feed",
|
||||||
"summary": "Summary",
|
"summary": "Summary",
|
||||||
"metric-s": "Metrics",
|
"metrics": "Metrics",
|
||||||
"networks": "Networks",
|
"networks": "Networks",
|
||||||
"tags-metadata": "Tags and Meta Data",
|
"tags-metadata": "Tags and Meta Data",
|
||||||
"activity-feed": "Activity Feed",
|
"activity-feed": "Activity Feed",
|
||||||
"firewall": "Firewall",
|
"firewall": "Firewall",
|
||||||
|
"service-manifest": "Service manifest",
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"projects": "Projects",
|
"projects": "Projects",
|
||||||
"people": "People",
|
"people": "People",
|
||||||
"services": "Services",
|
"services": "Services",
|
||||||
"instances": "Instances",
|
"instances": "Instances",
|
||||||
"manifest": "Project manifest",
|
"manifest": "Project manifest",
|
||||||
"service-manifest": "Service manifest",
|
|
||||||
"create-new": "Create new project",
|
"create-new": "Create new project",
|
||||||
"rollback": "Rollback",
|
"rollback": "Rollback",
|
||||||
"import-services-title": "Import your services",
|
"import-services-title": "Import your services",
|
||||||
@ -52,7 +52,7 @@
|
|||||||
"description": "Please provide your billing details.",
|
"description": "Please provide your billing details.",
|
||||||
"save-details-label": "Save details"
|
"save-details-label": "Save details"
|
||||||
},
|
},
|
||||||
"metrics": {
|
"metrics-section": {
|
||||||
"add": {
|
"add": {
|
||||||
"add-label": "Add",
|
"add-label": "Add",
|
||||||
"added-label": "Added",
|
"added-label": "Added",
|
||||||
|
@ -21,26 +21,29 @@ const AddMetrics = ({
|
|||||||
|
|
||||||
const addButton = (metric) => (
|
const addButton = (metric) => (
|
||||||
<AddMetricButton metric={metric} onClick={onAddMetric}>
|
<AddMetricButton metric={metric} onClick={onAddMetric}>
|
||||||
<FormattedMessage id={'metrics.add.add-label'} onClick={onAddMetric} />
|
<FormattedMessage
|
||||||
|
id={'metrics-section.add.add-label'}
|
||||||
|
onClick={onAddMetric}
|
||||||
|
/>
|
||||||
</AddMetricButton>
|
</AddMetricButton>
|
||||||
);
|
);
|
||||||
|
|
||||||
const addedButton = (
|
const addedButton = (
|
||||||
<AddMetricButton disabled>
|
<AddMetricButton disabled>
|
||||||
<FormattedMessage id={'metrics.add.added-label'} />
|
<FormattedMessage id={'metrics-section.add.added-label'} />
|
||||||
</AddMetricButton>
|
</AddMetricButton>
|
||||||
);
|
);
|
||||||
|
|
||||||
const metricList = metricTypes.map((metric) => (
|
const metricList = metricTypes.map((metric) => (
|
||||||
<AddMetricTile key={metric.id}>
|
<AddMetricTile key={metric.id}>
|
||||||
<AddMetricTitle>
|
<AddMetricTitle>
|
||||||
<FormattedMessage id={`metrics.${metric.id}.title`} />
|
<FormattedMessage id={`metrics-section.${metric.id}.title`} />
|
||||||
</AddMetricTitle>
|
</AddMetricTitle>
|
||||||
<AddMetricDescription>
|
<AddMetricDescription>
|
||||||
<FormattedMessage id={`metrics.${metric.id}.description`} />
|
<FormattedMessage id={`metrics-section.${metric.id}.description`} />
|
||||||
</AddMetricDescription>
|
</AddMetricDescription>
|
||||||
<AddMetricLink href='http://somelink.com'>
|
<AddMetricLink href='http://somelink.com'>
|
||||||
<FormattedMessage id={'metrics.add.link-label'} />
|
<FormattedMessage id={'metrics-section.add.link-label'} />
|
||||||
</AddMetricLink>
|
</AddMetricLink>
|
||||||
{ added(metric.uuid) ? addedButton : addButton(metric.uuid) }
|
{ added(metric.uuid) ? addedButton : addButton(metric.uuid) }
|
||||||
</AddMetricTile>
|
</AddMetricTile>
|
||||||
|
@ -47,13 +47,13 @@ const MetricCharts = ({
|
|||||||
<MetricHeader>
|
<MetricHeader>
|
||||||
<MetricTitle>
|
<MetricTitle>
|
||||||
{type.name}
|
{type.name}
|
||||||
{/*<FormattedMessage id={`metrics.${type.id}.title`} />*/}
|
{/*<FormattedMessage id={`metrics-section.${type.id}.title`} />*/}
|
||||||
</MetricTitle>
|
</MetricTitle>
|
||||||
<MetricSelect onChange={handleSelectChange} value={String(duration)}>
|
<MetricSelect onChange={handleSelectChange} value={String(duration)}>
|
||||||
{optionList}
|
{optionList}
|
||||||
</MetricSelect>
|
</MetricSelect>
|
||||||
<MetricSettingsButton onClick={handleSettingsClick}>
|
<MetricSettingsButton onClick={handleSettingsClick}>
|
||||||
<FormattedMessage id={'metrics.metric.settings-label'} />
|
<FormattedMessage id={'metrics-section.metric.settings-label'} />
|
||||||
</MetricSettingsButton>
|
</MetricSettingsButton>
|
||||||
<MetricCloseButton onClick={handleRemoveMetric} />
|
<MetricCloseButton onClick={handleRemoveMetric} />
|
||||||
</MetricHeader>
|
</MetricHeader>
|
||||||
|
@ -2,7 +2,8 @@ import React from 'react';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import PropTypes from '@root/prop-types';
|
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 { TopologyGraph } from '@ui/components/topology';
|
||||||
import { LayoutContainer } from '@components/layout';
|
import { LayoutContainer } from '@components/layout';
|
||||||
import ServicesTooltip from '@components/services/tooltip';
|
import ServicesTooltip from '@components/services/tooltip';
|
||||||
@ -22,6 +23,11 @@ const StyledBackground = styled.div`
|
|||||||
|
|
||||||
const StyledContainer = styled(LayoutContainer)`
|
const StyledContainer = styled(LayoutContainer)`
|
||||||
position: relative;
|
position: relative;
|
||||||
|
padding: ${unitcalc(4)} 2rem;
|
||||||
|
|
||||||
|
${breakpoints.large`
|
||||||
|
padding: ${unitcalc(4)} 0;
|
||||||
|
`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Services = (props) => {
|
const Services = (props) => {
|
||||||
@ -30,14 +36,16 @@ const Services = (props) => {
|
|||||||
org = {},
|
org = {},
|
||||||
project = {},
|
project = {},
|
||||||
toggleTooltip,
|
toggleTooltip,
|
||||||
uiTooltip
|
uiTooltip,
|
||||||
|
push
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const onQuickActions = (evt, tooltipData) => {
|
const getService = (uuid) => services.reduce((acc, service) =>
|
||||||
const service = services.reduce((acc, service) =>
|
service.uuid === uuid ? service : acc
|
||||||
service.uuid === tooltipData.service ? service : acc
|
|
||||||
, {});
|
, {});
|
||||||
|
|
||||||
|
const onQuickActions = (evt, tooltipData) => {
|
||||||
|
const service = getService(tooltipData.service);
|
||||||
const ttData = {
|
const ttData = {
|
||||||
...tooltipData,
|
...tooltipData,
|
||||||
data: {
|
data: {
|
||||||
@ -54,11 +62,20 @@ const Services = (props) => {
|
|||||||
service: uiTooltip.service
|
service: uiTooltip.service
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const onNodeTitleClick = (uuid) => {
|
||||||
|
const service = getService(uuid);
|
||||||
|
|
||||||
|
const path = `/${org.id}/projects/${project.id}/services/${service.id}`;
|
||||||
|
|
||||||
|
push(path);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledBackground>
|
<StyledBackground>
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<TopologyGraph
|
<TopologyGraph
|
||||||
onQuickActions={onQuickActions}
|
onQuickActions={onQuickActions}
|
||||||
|
onNodeTitleClick={onNodeTitleClick}
|
||||||
services={services}
|
services={services}
|
||||||
/>
|
/>
|
||||||
<ServicesTooltip {...uiTooltip} onBlur={handleTooltipBlur} />
|
<ServicesTooltip {...uiTooltip} onBlur={handleTooltipBlur} />
|
||||||
@ -71,6 +88,7 @@ Services.propTypes = {
|
|||||||
org: PropTypes.org,
|
org: PropTypes.org,
|
||||||
services: React.PropTypes.arrayOf(PropTypes.service),
|
services: React.PropTypes.arrayOf(PropTypes.service),
|
||||||
project: PropTypes.project,
|
project: PropTypes.project,
|
||||||
|
push: React.PropTypes.func.isRequired,
|
||||||
toggleTooltip: React.PropTypes.func,
|
toggleTooltip: React.PropTypes.func,
|
||||||
uiTooltip: React.PropTypes.object
|
uiTooltip: React.PropTypes.object
|
||||||
};
|
};
|
||||||
@ -78,12 +96,14 @@ Services.propTypes = {
|
|||||||
const mapStateToProps = (state, {
|
const mapStateToProps = (state, {
|
||||||
match = {
|
match = {
|
||||||
params: {}
|
params: {}
|
||||||
}
|
},
|
||||||
|
push
|
||||||
}) => ({
|
}) => ({
|
||||||
org: orgByIdSelector(match.params.org)(state),
|
org: orgByIdSelector(match.params.org)(state),
|
||||||
project: projectByIdSelector(match.params.projectId)(state),
|
project: projectByIdSelector(match.params.projectId)(state),
|
||||||
services: servicesForTopologySelector(match.params.projectId)(state),
|
services: servicesForTopologySelector(match.params.projectId)(state),
|
||||||
uiTooltip: serviceUiTooltipSelector(state)
|
uiTooltip: serviceUiTooltipSelector(state),
|
||||||
|
push: push
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
@ -75,7 +75,7 @@
|
|||||||
"id": "cpu-wait-time",
|
"id": "cpu-wait-time",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 100,
|
"max": 100,
|
||||||
"measurement": "%"
|
"measurement": "bytes"
|
||||||
}, {
|
}, {
|
||||||
"uuid": "dca08514-72e5-46ce-ad91-e68b3b0914d7",
|
"uuid": "dca08514-72e5-46ce-ad91-e68b3b0914d7",
|
||||||
"name": "Zfs used",
|
"name": "Zfs used",
|
||||||
@ -96,14 +96,14 @@
|
|||||||
"id": "load-average",
|
"id": "load-average",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 20,
|
"max": 20,
|
||||||
"measurement": "kb"
|
"measurement": " Mb"
|
||||||
}, {
|
}, {
|
||||||
"uuid": "dca08514-72e5-46ce-ad92-e68b3b0914d4",
|
"uuid": "dca08514-72e5-46ce-ad92-e68b3b0914d4",
|
||||||
"name": "Memory",
|
"name": "Memory",
|
||||||
"id": "mem-agg-usage",
|
"id": "mem-agg-usage",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 100,
|
"max": 100,
|
||||||
"measurement": "%"
|
"measurement": " Mb"
|
||||||
}, {
|
}, {
|
||||||
"uuid": "dca08514-72e5-46ce-ad93-e68b3b0914d4",
|
"uuid": "dca08514-72e5-46ce-ad93-e68b3b0914d4",
|
||||||
"name": "Memory limit",
|
"name": "Memory limit",
|
||||||
|
@ -14,6 +14,7 @@ const GraphNode = ({
|
|||||||
data,
|
data,
|
||||||
index,
|
index,
|
||||||
onDragStart,
|
onDragStart,
|
||||||
|
onNodeTitleClick,
|
||||||
onQuickActions
|
onQuickActions
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
@ -61,6 +62,9 @@ const GraphNode = ({
|
|||||||
onQuickActions(evt, d);
|
onQuickActions(evt, d);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onTitleClick = () =>
|
||||||
|
onNodeTitleClick(data.uuid);
|
||||||
|
|
||||||
const onStart = (evt) => {
|
const onStart = (evt) => {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
onDragStart(evt, data.id);
|
onDragStart(evt, data.id);
|
||||||
@ -107,6 +111,7 @@ const GraphNode = ({
|
|||||||
<GraphNodeTitle
|
<GraphNodeTitle
|
||||||
connected={connected}
|
connected={connected}
|
||||||
data={data}
|
data={data}
|
||||||
|
onNodeTitleClick={onTitleClick}
|
||||||
/>
|
/>
|
||||||
<GraphNodeButton
|
<GraphNodeButton
|
||||||
connected={connected}
|
connected={connected}
|
||||||
@ -123,6 +128,7 @@ GraphNode.propTypes = {
|
|||||||
data: React.PropTypes.object.isRequired,
|
data: React.PropTypes.object.isRequired,
|
||||||
index: React.PropTypes.number.isRequired,
|
index: React.PropTypes.number.isRequired,
|
||||||
onDragStart: React.PropTypes.func,
|
onDragStart: React.PropTypes.func,
|
||||||
|
onNodeTitleClick: React.PropTypes.func,
|
||||||
onQuickActions: React.PropTypes.func
|
onQuickActions: React.PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,7 +6,8 @@ import HeartIcon from './icon-heart.svg';
|
|||||||
|
|
||||||
const GraphNodeTitle = ({
|
const GraphNodeTitle = ({
|
||||||
connected,
|
connected,
|
||||||
data
|
data,
|
||||||
|
onNodeTitleClick
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -15,6 +16,8 @@ const GraphNodeTitle = ({
|
|||||||
x={Constants.paddingLeft}
|
x={Constants.paddingLeft}
|
||||||
y={30}
|
y={30}
|
||||||
connected={connected}
|
connected={connected}
|
||||||
|
onClick={onNodeTitleClick}
|
||||||
|
onKeyDown={onNodeTitleClick}
|
||||||
>
|
>
|
||||||
{data.name}
|
{data.name}
|
||||||
</GraphTitle>
|
</GraphTitle>
|
||||||
@ -32,7 +35,8 @@ const GraphNodeTitle = ({
|
|||||||
|
|
||||||
GraphNodeTitle.propTypes = {
|
GraphNodeTitle.propTypes = {
|
||||||
connected: React.PropTypes.bool,
|
connected: React.PropTypes.bool,
|
||||||
data: React.PropTypes.object.isRequired
|
data: React.PropTypes.object.isRequired,
|
||||||
|
onNodeTitleClick: React.PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Baseline(
|
export default Baseline(
|
||||||
|
@ -5,7 +5,6 @@ import Constants from './constants';
|
|||||||
import GraphNode from './graph-node';
|
import GraphNode from './graph-node';
|
||||||
import GraphLink from './graph-link';
|
import GraphLink from './graph-link';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { triggerMouseEvent } from '../../shared/functions';
|
|
||||||
|
|
||||||
const StyledSvg = styled.svg`
|
const StyledSvg = styled.svg`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -103,26 +102,36 @@ class TopologyGraph extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isWithinSVGBounds(target, x, y) {
|
getSvgSize() {
|
||||||
const svgBounds = document
|
return document.getElementById('topology-svg') ?
|
||||||
.getElementsByClassName('topology-svg')[0]
|
document.getElementById('topology-svg').getBoundingClientRect() :
|
||||||
.getBoundingClientRect();
|
svgSize;
|
||||||
|
}
|
||||||
|
|
||||||
const nodeHeight = target.getBoundingClientRect().height;
|
constrain(x, y, children=false) {
|
||||||
const nodeWidth = target.getBoundingClientRect().width;
|
const svgSize = this.getSvgSize();
|
||||||
|
|
||||||
const constraints = {
|
const nodeRect = children ?
|
||||||
top: svgBounds.top + (nodeHeight / 2),
|
Constants.nodeRectWithChildren :
|
||||||
left: svgBounds.left + (nodeWidth / 2),
|
Constants.nodeRect;
|
||||||
bottom: svgBounds.bottom - (nodeHeight / 2),
|
|
||||||
right: svgBounds.right - (nodeWidth / 2)
|
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() {
|
render() {
|
||||||
@ -147,9 +156,14 @@ class TopologyGraph extends React.Component {
|
|||||||
y: 0
|
y: 0
|
||||||
} : simNode(service.uuid);
|
} : simNode(service.uuid);
|
||||||
|
|
||||||
|
const constrained = {
|
||||||
|
...sNode,
|
||||||
|
...this.constrain(sNode.x, sNode.y, service.children)
|
||||||
|
};
|
||||||
|
|
||||||
return ({
|
return ({
|
||||||
...service,
|
...service,
|
||||||
...sNode
|
...constrained
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -188,10 +202,6 @@ class TopologyGraph extends React.Component {
|
|||||||
? evt.changedTouches[0].pageY
|
? evt.changedTouches[0].pageY
|
||||||
: evt.clientY;
|
: evt.clientY;
|
||||||
|
|
||||||
if ( !this.isWithinSVGBounds(evt.target, x, y) ) {
|
|
||||||
triggerMouseEvent(evt.target, 'mouseup');
|
|
||||||
}
|
|
||||||
|
|
||||||
const offset = {
|
const offset = {
|
||||||
x: x - dragInfo.position.x,
|
x: x - dragInfo.position.x,
|
||||||
y: y - dragInfo.position.y
|
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) => (
|
const renderedNodes = nodesData.map((n, index) => (
|
||||||
<GraphNode
|
<GraphNode
|
||||||
key={index}
|
key={index}
|
||||||
data={n}
|
data={n}
|
||||||
index={index}
|
index={index}
|
||||||
onDragStart={onDragStart}
|
onDragStart={onDragStart}
|
||||||
|
onNodeTitleClick={onTitleClick}
|
||||||
onQuickActions={onQuickActions}
|
onQuickActions={onQuickActions}
|
||||||
connected={n.id !== 'consul'}
|
connected={n.id !== 'consul'}
|
||||||
/>
|
/>
|
||||||
@ -255,7 +269,7 @@ class TopologyGraph extends React.Component {
|
|||||||
onMouseUp={onDragEnd}
|
onMouseUp={onDragEnd}
|
||||||
onTouchEnd={onDragEnd}
|
onTouchEnd={onDragEnd}
|
||||||
onTouchCancel={onDragEnd}
|
onTouchCancel={onDragEnd}
|
||||||
className='topology-svg'
|
id='topology-svg'
|
||||||
>
|
>
|
||||||
<g>
|
<g>
|
||||||
{renderedNodes}
|
{renderedNodes}
|
||||||
@ -270,6 +284,7 @@ class TopologyGraph extends React.Component {
|
|||||||
|
|
||||||
TopologyGraph.propTypes = {
|
TopologyGraph.propTypes = {
|
||||||
onQuickActions: React.PropTypes.func,
|
onQuickActions: React.PropTypes.func,
|
||||||
|
onNodeTitleClick: React.PropTypes.func,
|
||||||
services: React.PropTypes.array
|
services: React.PropTypes.array
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user