Removes the combined table-topo-view

This commit is contained in:
Simon Howe
2016-05-04 14:58:36 +02:00
parent c51e290127
commit fa502ae6ad
12 changed files with 72 additions and 79 deletions

View File

@@ -18,10 +18,12 @@ export function showHelp() {
return {type: ActionTypes.SHOW_HELP};
}
export function hideHelp() {
return {type: ActionTypes.HIDE_HELP};
}
export function toggleHelp() {
return (dispatch, getState) => {
if (getState().get('showingHelp')) {
@@ -32,6 +34,20 @@ export function toggleHelp() {
};
}
export function toggleGridMode(enabled) {
return {type: ActionTypes.SET_GRID_MODE, enabled};
}
export function sortOrderChanged(newOrder) {
return {
type: ActionTypes.SORT_ORDER_CHANGED,
newOrder
};
}
//
// Networks
//
@@ -78,18 +94,12 @@ export function unpinNetwork(networkId) {
};
}
export function sortOrderChanged(newOrder) {
AppDispatcher.dispatch({
type: ActionTypes.SORT_ORDER_CHANGED,
newOrder
});
}
//
// Metrics
//
export function selectMetric(metricId) {
return {
type: ActionTypes.SELECT_METRIC,

View File

@@ -5,7 +5,6 @@ import React from 'react';
import { connect } from 'react-redux';
import { Map as makeMap, fromJS, is as isDeepEqual } from 'immutable';
import timely from 'timely';
import { Set as makeSet } from 'immutable';
import { clickBackground } from '../actions/app-actions';
import { EDGE_ID_SEPARATOR } from '../constants/naming';
@@ -13,8 +12,7 @@ import { DETAILS_PANEL_WIDTH } from '../constants/styles';
import Logo from '../components/logo';
import { doLayout } from './nodes-layout';
import NodesChartElements from './nodes-chart-elements';
import { getActiveTopologyOptions, getAdjacentNodes,
isSameTopology } from '../utils/topology-utils';
import { getActiveTopologyOptions, getAdjacentNodes } from '../utils/topology-utils';
const log = debug('scope:nodes-chart');
@@ -62,7 +60,7 @@ class NodesChart extends React.Component {
// re-apply cached canvas zoom/pan to d3 behavior (or set defaul values)
const defaultZoom = { scale: 1, panTranslateX: 0, panTranslateY: 0, hasZoomed: false };
const nextZoom = this.state.zoomCache[nextProps.topologyId] || defaultZoom;
if (nextZoom && this.zoom) {
if (this.zoom && nextZoom) {
this.zoom.scale(nextZoom.scale);
this.zoom.translate([nextZoom.panTranslateX, nextZoom.panTranslateY]);
}
@@ -80,13 +78,15 @@ class NodesChart extends React.Component {
}
// reset layout dimensions only when forced
state.height = nextProps.height;
state.width = nextProps.width;
// state.height = nextProps.height;
// state.width = nextProps.width;
state.height = nextProps.forceRelayout ? nextProps.height : (state.height || nextProps.height);
state.width = nextProps.forceRelayout ? nextProps.width : (state.width || nextProps.width);
_.assign(state, this.updateGraphState(nextProps, state));
// if (nextProps.forceRelayout || nextProps.nodes !== this.props.nodes) {
// _.assign(state, this.updateGraphState(nextProps, state));
// }
// _.assign(state, this.updateGraphState(nextProps, state));
if (nextProps.forceRelayout || nextProps.nodes !== this.props.nodes) {
_.assign(state, this.updateGraphState(nextProps, state));
}
if (this.props.selectedNodeId !== nextProps.selectedNodeId) {
_.assign(state, this.restoreLayout(state));
@@ -326,7 +326,6 @@ class NodesChart extends React.Component {
const stateEdges = this.initEdges(props.nodes, stateNodes);
const nodeScale = this.getNodeScale(props.nodes, state.width, state.height);
const nextState = { nodeScale };
console.log(props.nodeOrder);
const nodeOrder = props.nodeOrder || makeMap(stateNodes
.toList()
.sortBy(n => n.get('label'))
@@ -343,7 +342,6 @@ class NodesChart extends React.Component {
nodeOrder
};
console.log('nodes-chart', state.height);
const timedLayouter = timely(doLayout);
const graph = timedLayouter(stateNodes, stateEdges, options);
@@ -370,6 +368,7 @@ class NodesChart extends React.Component {
if (!this.props.noZoom && !state.hasZoomed && zoomFactor > 0 && zoomFactor < 1) {
zoomScale = zoomFactor;
console.log(zoomScale);
// saving in d3's behavior cache
if (this.zoom) {
this.zoom.scale(zoomFactor);

View File

@@ -2,21 +2,10 @@
import React from 'react';
import { Set as makeSet, List as makeList, Map as makeMap } from 'immutable';
import NodesChart from './nodes-chart';
import NodeDetailsTable from '../components/node-details/node-details-table';
import { enterNode, leaveNode } from '../actions/app-actions';
function MiniChart(props) {
const {width, height} = props;
return (
<div style={{height, width}} className="nodes-grid-graph">
<NodesChart {...props} />
</div>
);
}
const IGNORED_COLUMNS = ['docker_container_ports'];
@@ -43,17 +32,7 @@ export default class NodesGrid extends React.Component {
}
render() {
const {margins, nodes, height, nodeSize} = this.props;
const rowStyle = { height: nodeSize };
const tableHeight = nodes.size * rowStyle.height;
const graphProps = Object.assign({}, this.props, {
height: tableHeight,
width: 400,
noZoom: true,
nodeSize: nodeSize - 4,
margins: {top: 0, left: 0, right: 0, bottom: 0},
nodes: nodes.map(node => node.remove('label').remove('label_minor'))
});
const { margins, nodes, height } = this.props;
const cmpStyle = {
height,
paddingTop: margins.top,
@@ -77,9 +56,7 @@ export default class NodesGrid extends React.Component {
onMouseOverRow={this.onMouseOverRow}
{...detailsData}
highlightedNodeIds={this.props.highlightedNodeIds}
limit={1000}>
<MiniChart {...graphProps} />
</NodeDetailsTable>
limit={1000} />
</div>
);
}

View File

@@ -51,8 +51,8 @@ function runLayoutEngine(graph, imNodes, imEdges, opts) {
graph.setGraph({
nodesep,
ranksep,
rankdir: 'LR',
align: 'UL'
// rankdir: 'LR',
// align: 'UL'
});
// add nodes to the graph if not already there
@@ -182,16 +182,14 @@ function layoutSingleNodes(layout, opts) {
const rows = Math.ceil(singleNodes.size / columns);
let row = 0;
let col = 0;
let singleX;
let singleY;
nodes = nodes.sortBy(node => node.get('rank')).map(node => {
if (singleNodes.has(node.get('id'))) {
if (col === columns) {
col = 0;
row++;
}
singleX = col * (nodesep + nodeWidth) + offsetX;
singleY = row * (ranksep + nodeHeight) + offsetY;
const singleX = col * (nodesep + nodeWidth) + offsetX;
const singleY = row * (ranksep + nodeHeight) + offsetY;
col++;
return node.merge({
x: singleX,
@@ -201,8 +199,6 @@ function layoutSingleNodes(layout, opts) {
return node;
});
console.log(singleX, singleY);
// adjust layout dimensions if graph is now bigger
result.width = Math.max(layout.width, columns * nodeWidth + (columns - 1) * nodesep);
result.height = Math.max(layout.height, rows * nodeHeight + (rows - 1) * ranksep);
@@ -250,6 +246,7 @@ function shiftLayoutToCenter(layout, opts) {
return result;
}
/**
* Adds `points` array to edge based on location of source and target
* @param {Map} edge new edge
@@ -266,7 +263,7 @@ function setSimpleEdgePoints(edge, nodeCache) {
}
function uniqueRowConstraint(layout, options) {
export function uniqueRowConstraint(layout, options) {
const result = Object.assign({}, layout);
const scale = options.scale || DEFAULT_SCALE;
const nodeHeight = scale(NODE_SIZE_FACTOR);
@@ -285,7 +282,6 @@ function uniqueRowConstraint(layout, options) {
.range([nodeWidth, options.width - nodeWidth])
.clamp(false);
console.log('uniqueRowConstraint', options.height);
result.nodes = layout.nodes.map(node => node.merge({
x: xScale(node.get('x')),
y: nodeOrder.get(node.get('id')) * rowHeight + nodeHeight * 0.5 + margins.top + 2
@@ -395,7 +391,8 @@ export function doLayout(immNodes, immEdges, opts) {
let layout;
++layoutRuns;
if (false && !options.forceRelayout && cachedLayout && nodeCache && edgeCache
// if (false && !options.forceRelayout && cachedLayout && nodeCache && edgeCache
if (!options.forceRelayout && cachedLayout && nodeCache && edgeCache
&& !hasUnseenNodes(immNodes, nodeCache)) {
log('skip layout, trivial adjustment', ++layoutRunsTrivial, layoutRuns);
layout = cloneLayout(cachedLayout, immNodes, immEdges);
@@ -410,7 +407,7 @@ export function doLayout(immNodes, immEdges, opts) {
}
layout = layoutSingleNodes(layout, opts);
layout = shiftLayoutToCenter(layout, opts);
layout = uniqueRowConstraint(layout, opts);
// layout = uniqueRowConstraint(layout, opts);
}
// cache results

View File

@@ -15,6 +15,7 @@ import { focusSearch, pinNextMetric, hitBackspace, hitEnter, hitEsc, unpinMetric
selectMetric, toggleHelp } from '../actions/app-actions';
import Details from './details';
import Nodes from './nodes';
import GridModeSelector from './grid-mode-selector';
import MetricSelector from './metric-selector';
import NetworkSelector from './networks-selector';
import EmbeddedTerminal from './embedded-terminal';
@@ -127,6 +128,7 @@ class App extends React.Component {
<Sidebar>
<Status />
<GridModeSelector />
{showingMetricsSelector && <MetricSelector />}
{showingNetworkSelector && <NetworkSelector />}
<TopologyOptions />

View File

@@ -184,7 +184,7 @@ class DebugToolbar extends React.Component {
addNodes(n, prefix = 'zing') {
const ns = this.props.nodes;
const nodeNames = ns.keySeq().toJS();
const newNodeNames = _.range(ns.size, ns.size + n).map(i => (
const newNodeNames = _.range(nodeNames.length, nodeNames.length + n).map(i => (
// `${randomLetter()}${randomLetter()}-zing`
`${prefix}${i}`
));

View File

@@ -4,7 +4,6 @@ import { Map as makeMap } from 'immutable';
import ShowMore from '../show-more';
import NodeDetailsTableRow from './node-details-table-row';
import { sortOrderChanged } from '../../actions/app-actions';
function isNumberField(field) {
@@ -95,7 +94,6 @@ export default class NodeDetailsTable extends React.Component {
? !this.state.sortedDesc : this.state.sortedDesc;
const sortBy = headerId;
this.setState({sortBy, sortedDesc});
sortOrderChanged({sortBy, sortedDesc});
}
handleLimitClick() {
@@ -185,8 +183,6 @@ export default class NodeDetailsTable extends React.Component {
React.cloneElement(child, { nodeOrder })
));
console.log(this.props.selectedRowId);
return (
<div className="node-details-table-wrapper-wrapper" style={this.props.style}>
<div className="node-details-table-wrapper" onMouseOut={this.props.onMouseOut}>
@@ -198,7 +194,8 @@ export default class NodeDetailsTable extends React.Component {
{nodes && nodes.map(node => (
<NodeDetailsTableRow
key={node.id}
selected={this.props.highlightedNodeIds.has(node.id)}
selected={this.props.highlightedNodeIds &&
this.props.highlightedNodeIds.has(node.id)}
node={node}
nodeIdKey={nodeIdKey}
columns={columns}

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { connect } from 'react-redux';
// import NodesChart from '../charts/nodes-chart';
import NodesChart from '../charts/nodes-chart';
import NodesGrid from '../charts/nodes-grid';
import NodesError from '../charts/nodes-error';
import { DelayedShow } from '../utils/delayed-show';
@@ -11,7 +11,6 @@ import { CANVAS_MARGINS } from '../constants/styles';
const navbarHeight = 160;
const marginTop = 0;
const detailsWidth = 450;
/**
@@ -68,10 +67,9 @@ class Nodes extends React.Component {
}
render() {
const { nodes, selectedNodeId, topologyEmpty, topologiesLoaded, nodesLoaded, topologies,
topology } = this.props;
const { nodes, topologyEmpty, topologiesLoaded, nodesLoaded, topologies,
topology, highlightedNodeIds } = this.props;
const layoutPrecision = getLayoutPrecision(nodes.size);
const hasSelectedNode = selectedNodeId && nodes.has(selectedNodeId);
return (
<div className="nodes-wrapper">
@@ -82,15 +80,18 @@ class Nodes extends React.Component {
show={topologiesLoaded && !nodesLoaded} />
</DelayedShow>
{this.renderEmptyTopologyError(topologiesLoaded && nodesLoaded && topologyEmpty)}
<NodesGrid {...this.state}
nodeSize="24"
width={1300}
height={780}
margins={CANVAS_MARGINS}
detailsWidth={detailsWidth}
layoutPrecision={layoutPrecision}
hasSelectedNode={hasSelectedNode}
/>
{this.props.gridMode ?
<NodesGrid {...this.state}
nodeSize="24"
nodes={nodes}
margins={CANVAS_MARGINS}
layoutPrecision={layoutPrecision}
highlightedNodeIds={highlightedNodeIds}
/> :
<NodesChart {...this.state}
margins={CANVAS_MARGINS}
layoutPrecision={layoutPrecision}
/>}
</div>
);
}
@@ -109,13 +110,14 @@ class Nodes extends React.Component {
function mapStateToProps(state) {
return {
gridMode: state.get('gridMode'),
nodes: state.get('nodes'),
nodesLoaded: state.get('nodesLoaded'),
selectedNodeId: state.get('selectedNodeId'),
topologies: state.get('topologies'),
topologiesLoaded: state.get('topologiesLoaded'),
topologyEmpty: isTopologyEmpty(state),
topology: state.get('currentTopology'),
highlightedNodeIds: state.get('highlightedNodeIds')
};
}

View File

@@ -55,7 +55,8 @@ const ACTION_TYPES = [
'UNPIN_NETWORK',
'SHOW_NETWORKS',
'SET_RECEIVED_NODES_DELTA',
'SORT_ORDER_CHANGED'
'SORT_ORDER_CHANGED',
'SET_GRID_MODE',
];
export default _.zipObject(ACTION_TYPES, ACTION_TYPES);

View File

@@ -28,6 +28,7 @@ export const initialState = makeMap({
currentTopologyId: 'containers',
errorUrl: null,
forceRelayout: false,
gridMode: false,
highlightedEdgeIds: makeSet(),
highlightedNodeIds: makeSet(),
hostname: '...',
@@ -166,6 +167,10 @@ export function rootReducer(state = initialState, action) {
return state.set('exportingGraph', action.exporting);
}
case ActionTypes.SET_GRID_MODE: {
return state.setIn(['gridMode'], action.enabled);
}
case ActionTypes.CLEAR_CONTROL_ERROR: {
return state.removeIn(['controlStatus', action.nodeId, 'error']);
}
@@ -625,6 +630,7 @@ export function rootReducer(state = initialState, action) {
selectedNodeId: action.state.selectedNodeId,
pinnedMetricType: action.state.pinnedMetricType
});
state = state.set('gridMode', action.state.mode === 'grid');
if (action.state.showingNetworks) {
state = state.set('showingNetworks', action.state.showingNetworks);
}

View File

@@ -39,6 +39,7 @@ export function getUrlState(state) {
const urlState = {
controlPipe: cp ? cp.toJS() : null,
mode: state.get('gridMode') ? 'grid' : 'topo',
nodeDetails: nodeDetails.toJS(),
pinnedMetricType: state.get('pinnedMetricType'),
pinnedSearches: state.get('pinnedSearches').toJS(),

View File

@@ -269,10 +269,11 @@ h2 {
cursor: pointer;
padding: 4px 8px;
border-radius: @border-radius;
opacity: 0.8;
opacity: 0.9;
margin-bottom: 3px;
border: 1px solid transparent;
background-color: #f7f7fa;
&-active, &:hover {
color: @text-color;
background-color: @background-darker-secondary-color;