mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-02 09:40:34 +00:00
Force-relayout button
* new button in footer * when clicked, forces a relayout that could help with degraded graphs * sets a store flag that will be unset on next nodes delta update * fixes #863
This commit is contained in:
@@ -57,6 +57,12 @@ export function clickCloseTerminal(pipeId, closePipe) {
|
||||
updateRoute();
|
||||
}
|
||||
|
||||
export function clickForceRelayout() {
|
||||
AppDispatcher.dispatch({
|
||||
type: ActionTypes.CLICK_FORCE_RELAYOUT
|
||||
});
|
||||
}
|
||||
|
||||
export function clickNode(nodeId, label, origin) {
|
||||
AppDispatcher.dispatch({
|
||||
type: ActionTypes.CLICK_NODE,
|
||||
|
||||
@@ -74,7 +74,7 @@ export default class NodesChart extends React.Component {
|
||||
});
|
||||
}
|
||||
// FIXME add PureRenderMixin, Immutables, and move the following functions to render()
|
||||
if (nextProps.nodes !== this.props.nodes) {
|
||||
if (nextProps.forceRelayout || nextProps.nodes !== this.props.nodes) {
|
||||
_.assign(state, this.updateGraphState(nextProps, state));
|
||||
}
|
||||
if (this.props.selectedNodeId !== nextProps.selectedNodeId) {
|
||||
@@ -411,6 +411,7 @@ export default class NodesChart extends React.Component {
|
||||
height: props.height,
|
||||
scale: nodeScale,
|
||||
margins: MARGINS,
|
||||
forceRelayout: props.forceRelayout,
|
||||
topologyId: this.props.topologyId
|
||||
};
|
||||
|
||||
|
||||
@@ -361,7 +361,7 @@ export function doLayout(immNodes, immEdges, opts) {
|
||||
let layout;
|
||||
|
||||
++layoutRuns;
|
||||
if (cachedLayout && nodeCache && edgeCache && !hasUnseenNodes(immNodes, nodeCache)) {
|
||||
if (!options.forceRelayout && cachedLayout && nodeCache && edgeCache && !hasUnseenNodes(immNodes, nodeCache)) {
|
||||
log('skip layout, trivial adjustment', ++layoutRunsTrivial, layoutRuns);
|
||||
layout = cloneLayout(cachedLayout, immNodes, immEdges);
|
||||
// copy old properties, works also if nodes get re-added
|
||||
|
||||
@@ -7,7 +7,7 @@ import Status from './status.js';
|
||||
import Topologies from './topologies.js';
|
||||
import TopologyOptions from './topology-options.js';
|
||||
import { getApiDetails, getTopologies, basePathSlash } from '../utils/web-api-utils';
|
||||
import { hitEsc } from '../actions/app-actions';
|
||||
import { clickForceRelayout, hitEsc } from '../actions/app-actions';
|
||||
import Details from './details';
|
||||
import Nodes from './nodes';
|
||||
import EmbeddedTerminal from './embedded-terminal';
|
||||
@@ -25,6 +25,7 @@ function getStateFromStores() {
|
||||
currentTopologyId: AppStore.getCurrentTopologyId(),
|
||||
currentTopologyOptions: AppStore.getCurrentTopologyOptions(),
|
||||
errorUrl: AppStore.getErrorUrl(),
|
||||
forceRelayout: AppStore.isForceRelayout(),
|
||||
highlightedEdgeIds: AppStore.getHighlightedEdgeIds(),
|
||||
highlightedNodeIds: AppStore.getHighlightedNodeIds(),
|
||||
hostname: AppStore.getHostname(),
|
||||
@@ -79,6 +80,8 @@ export default class App extends React.Component {
|
||||
// link url to switch contrast with current UI state
|
||||
const otherContrastModeUrl = contrastMode ? basePathSlash(window.location.pathname) : 'contrast.html';
|
||||
const otherContrastModeTitle = contrastMode ? 'Switch to normal contrast' : 'Switch to high contrast';
|
||||
const forceRelayoutClassName = 'footer-label footer-label-icon';
|
||||
const forceRelayoutTitle = 'Force re-layout (might reduce edge crossings, but may shift nodes around)';
|
||||
|
||||
return (
|
||||
<div className="app">
|
||||
@@ -100,6 +103,7 @@ export default class App extends React.Component {
|
||||
<Nodes nodes={this.state.nodes} highlightedNodeIds={this.state.highlightedNodeIds}
|
||||
highlightedEdgeIds={this.state.highlightedEdgeIds} detailsWidth={detailsWidth}
|
||||
selectedNodeId={this.state.selectedNodeId} topMargin={topMargin}
|
||||
forceRelayout={this.state.forceRelayout}
|
||||
topologyId={this.state.currentTopologyId} />
|
||||
|
||||
<Sidebar>
|
||||
@@ -117,6 +121,9 @@ export default class App extends React.Component {
|
||||
<span className="footer-label">on</span>
|
||||
{this.state.hostname}
|
||||
|
||||
<a className={forceRelayoutClassName} onClick={clickForceRelayout} title={forceRelayoutTitle}>
|
||||
<span className="fa fa-refresh" />
|
||||
</a>
|
||||
<a className="footer-label footer-label-icon" href={otherContrastModeUrl} title={otherContrastModeTitle}>
|
||||
<span className="fa fa-adjust" />
|
||||
</a>
|
||||
|
||||
@@ -33,6 +33,7 @@ export default class Nodes extends React.Component {
|
||||
nodes={this.props.nodes}
|
||||
width={this.state.width}
|
||||
height={this.state.height}
|
||||
forceRelayout={this.props.forceRelayout}
|
||||
topologyId={this.props.topologyId}
|
||||
detailsWidth={this.props.detailsWidth}
|
||||
topMargin={this.props.topMargin}
|
||||
|
||||
@@ -6,6 +6,7 @@ const ACTION_TYPES = [
|
||||
'CLICK_BACKGROUND',
|
||||
'CLICK_CLOSE_DETAILS',
|
||||
'CLICK_CLOSE_TERMINAL',
|
||||
'CLICK_FORCE_RELAYOUT',
|
||||
'CLICK_NODE',
|
||||
'CLICK_RELATIVE',
|
||||
'CLICK_SHOW_TOPOLOGY_FOR_NODE',
|
||||
|
||||
@@ -56,6 +56,7 @@ let controlStatus = makeMap();
|
||||
let currentTopology = null;
|
||||
let currentTopologyId = 'containers';
|
||||
let errorUrl = null;
|
||||
let forceRelayout = false;
|
||||
let hostname = '...';
|
||||
let version = '...';
|
||||
let mouseOverEdgeId = null;
|
||||
@@ -266,6 +267,10 @@ export class AppStore extends Store {
|
||||
return version;
|
||||
}
|
||||
|
||||
isForceRelayout() {
|
||||
return forceRelayout;
|
||||
}
|
||||
|
||||
isRouteSet() {
|
||||
return routeSet;
|
||||
}
|
||||
@@ -320,6 +325,15 @@ export class AppStore extends Store {
|
||||
this.__emitChange();
|
||||
break;
|
||||
|
||||
case ActionTypes.CLICK_FORCE_RELAYOUT:
|
||||
forceRelayout = true;
|
||||
// fire only once, reset after emitChange
|
||||
setTimeout(() => {
|
||||
forceRelayout = false;
|
||||
}, 0);
|
||||
this.__emitChange();
|
||||
break;
|
||||
|
||||
case ActionTypes.CLICK_NODE:
|
||||
const prevSelectedNodeId = selectedNodeId;
|
||||
const prevDetailsStackSize = nodeDetails.size;
|
||||
@@ -482,6 +496,8 @@ export class AppStore extends Store {
|
||||
case ActionTypes.RECEIVE_NODES_DELTA:
|
||||
const emptyMessage = !payload.delta.add && !payload.delta.remove
|
||||
&& !payload.delta.update;
|
||||
// this action is called frequently, good to check if something changed
|
||||
const emitChange = !emptyMessage || errorUrl !== null;
|
||||
|
||||
if (!emptyMessage) {
|
||||
log('RECEIVE_NODES_DELTA',
|
||||
@@ -516,7 +532,9 @@ export class AppStore extends Store {
|
||||
nodes = nodes.set(node.id, Immutable.fromJS(makeNode(node)));
|
||||
});
|
||||
|
||||
this.__emitChange();
|
||||
if (emitChange) {
|
||||
this.__emitChange();
|
||||
}
|
||||
break;
|
||||
|
||||
case ActionTypes.RECEIVE_NOT_FOUND:
|
||||
|
||||
Reference in New Issue
Block a user