Files
weave-scope/client/app/scripts/utils/topology-utils.js
2017-02-03 16:59:25 +01:00

189 lines
5.2 KiB
JavaScript

import { endsWith } from 'lodash';
import { Set as makeSet, List as makeList } from 'immutable';
//
// top priority first
//
const TOPOLOGY_DISPLAY_PRIORITY = [
'ecs-services',
'ecs-tasks',
'services',
'deployments',
'replica-sets',
'pods',
'containers',
];
export function getDefaultTopology(topologies) {
const flatTopologies = topologies
.flatMap(t => makeList([t]).concat(t.get('sub_topologies', makeList())));
return flatTopologies
.sortBy((t) => {
const index = TOPOLOGY_DISPLAY_PRIORITY.indexOf(t.get('id'));
return index === -1 ? Infinity : index;
})
.getIn([0, 'id']);
}
/**
* Returns a cache ID based on the topologyId and optionsQuery
* @param {String} topologyId
* @param {object} topologyOptions (optional)
* @return {String}
*/
export function buildTopologyCacheId(topologyId, topologyOptions) {
let id = '';
if (topologyId) {
id = topologyId;
if (topologyOptions) {
id += JSON.stringify(topologyOptions);
}
}
return id;
}
/**
* Returns a topology object from the topology tree
* @param {List} subTree
* @param {String} topologyId
* @return {Map} topology if found
*/
export function findTopologyById(subTree, topologyId) {
let foundTopology;
subTree.forEach((topology) => {
if (endsWith(topology.get('url'), topologyId)) {
foundTopology = topology;
}
if (!foundTopology && topology.has('sub_topologies')) {
foundTopology = findTopologyById(topology.get('sub_topologies'), topologyId);
}
});
return foundTopology;
}
export function updateNodeDegrees(nodes, edges) {
return nodes.map((node) => {
const nodeId = node.get('id');
const degree = edges.count(edge => edge.get('source') === nodeId
|| edge.get('target') === nodeId);
return node.set('degree', degree);
});
}
/* set topology.id and parentId for sub-topologies in place */
export function updateTopologyIds(topologies, parentId) {
return topologies.map((topology) => {
const result = Object.assign({}, topology);
result.id = topology.url.split('/').pop();
if (parentId) {
result.parentId = parentId;
}
if (topology.sub_topologies) {
result.sub_topologies = updateTopologyIds(topology.sub_topologies, result.id);
}
return result;
});
}
export function addTopologyFullname(topologies) {
return topologies.map((t) => {
if (!t.sub_topologies) {
return Object.assign({}, t, {fullName: t.name});
}
return Object.assign({}, t, {
fullName: t.name,
sub_topologies: t.sub_topologies.map(st => (
Object.assign({}, st, {fullName: `${t.name} ${st.name}`})
))
});
});
}
// adds ID field to topology (based on last part of URL path) and save urls in
// map for easy lookup
export function setTopologyUrlsById(topologyUrlsById, topologies) {
let urlMap = topologyUrlsById;
if (topologies) {
topologies.forEach((topology) => {
urlMap = urlMap.set(topology.id, topology.url);
if (topology.sub_topologies) {
topology.sub_topologies.forEach((subTopology) => {
urlMap = urlMap.set(subTopology.id, subTopology.url);
});
}
});
}
return urlMap;
}
export function filterHiddenTopologies(topologies) {
return topologies.filter(t => (!t.hide_if_empty || t.stats.node_count > 0 ||
t.stats.filtered_nodes > 0));
}
export function getActiveTopologyOptions(state) {
// options for current topology, sub-topologies share options with parent
const parentId = state.getIn(['currentTopology', 'parentId']);
if (parentId) {
return state.getIn(['topologyOptions', parentId]);
}
return state.getIn(['topologyOptions', state.get('currentTopologyId')]);
}
export function getCurrentTopologyOptions(state) {
return state.getIn(['currentTopology', 'options']);
}
export function isTopologyEmpty(state) {
return state.getIn(['currentTopology', 'stats', 'node_count'], 0) === 0
&& state.get('nodes').size === 0;
}
export function getAdjacentNodes(state, originNodeId) {
let adjacentNodes = makeSet();
const nodeId = originNodeId || state.get('selectedNodeId');
if (nodeId) {
if (state.hasIn(['nodes', nodeId])) {
adjacentNodes = makeSet(state.getIn(['nodes', nodeId, 'adjacency']));
// fill up set with reverse edges
state.get('nodes').forEach((node, id) => {
if (node.get('adjacency') && node.get('adjacency').includes(nodeId)) {
adjacentNodes = adjacentNodes.add(id);
}
});
}
}
return adjacentNodes;
}
export function hasSelectedNode(state) {
const selectedNodeId = state.get('selectedNodeId');
return state.hasIn(['nodes', selectedNodeId]);
}
export function getCurrentTopologyUrl(state) {
return state.getIn(['currentTopology', 'url']);
}
export function isNodeMatchingQuery(node, query) {
return node.get('label').includes(query) || node.get('subLabel').includes(query);
}
export function graphExceedsComplexityThresh(stats) {
// Check to see if complexity is high. Used to trigger table view on page load.
return (stats.get('node_count') + (2 * stats.get('edge_count'))) > 500;
}
export function zoomCacheKey(props) {
return `${props.topologyId}-${JSON.stringify(props.topologyOptions)}`;
}