mirror of
https://github.com/ansible/awx.git
synced 2026-03-10 22:19:28 -02:30
Refactor: move constants and helper functions into their own files.
This commit is contained in:
@@ -1,14 +1,32 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { InstancesAPI } from 'api';
|
|
||||||
import debounce from 'util/debounce';
|
import debounce from 'util/debounce';
|
||||||
// import { t } from '@lingui/macro';
|
// import { t } from '@lingui/macro';
|
||||||
import * as d3 from 'd3';
|
import * as d3 from 'd3';
|
||||||
import Legend from './Legend';
|
import Legend from './Legend';
|
||||||
import Tooltip from './Tooltip';
|
import Tooltip from './Tooltip';
|
||||||
import ContentLoading from './ContentLoading';
|
import ContentLoading from './ContentLoading';
|
||||||
import { truncateString } from '../../util/strings';
|
import {
|
||||||
|
renderStateColor,
|
||||||
|
renderLabelText,
|
||||||
|
renderNodeType,
|
||||||
|
renderNodeIcon,
|
||||||
|
redirectToDetailsPage,
|
||||||
|
// generateRandomNodes,
|
||||||
|
// getRandomInt,
|
||||||
|
} from './utils/helpers';
|
||||||
|
import {
|
||||||
|
MESH_FORCE_LAYOUT,
|
||||||
|
DEFAULT_RADIUS,
|
||||||
|
DEFAULT_NODE_COLOR,
|
||||||
|
DEFAULT_NODE_HIGHLIGHT_COLOR,
|
||||||
|
DEFAULT_NODE_LABEL_TEXT_COLOR,
|
||||||
|
DEFAULT_FONT_SIZE,
|
||||||
|
MARGIN,
|
||||||
|
HEIGHT,
|
||||||
|
FALLBACK_WIDTH,
|
||||||
|
} from './constants';
|
||||||
|
|
||||||
const Loader = styled(ContentLoading)`
|
const Loader = styled(ContentLoading)`
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -16,67 +34,15 @@ const Loader = styled(ContentLoading)`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
background: white;
|
background: white;
|
||||||
`;
|
`;
|
||||||
// function MeshGraph({ data }) {
|
function MeshGraph({ data, showLegend, zoom }) {
|
||||||
function MeshGraph({ showLegend, zoom }) {
|
// function MeshGraph({ showLegend, zoom }) {
|
||||||
const [isNodeSelected, setIsNodeSelected] = useState(false);
|
const [isNodeSelected, setIsNodeSelected] = useState(false);
|
||||||
const [selectedNode, setSelectedNode] = useState(null);
|
const [selectedNode, setSelectedNode] = useState(null);
|
||||||
const [nodeDetail, setNodeDetail] = useState(null);
|
const [nodeDetail, setNodeDetail] = useState(null);
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
function getRandomInt(min, max) {
|
// const data = generateRandomNodes(getRandomInt(4, 50));
|
||||||
min = Math.ceil(min);
|
|
||||||
max = Math.floor(max);
|
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
||||||
}
|
|
||||||
const nodes = [];
|
|
||||||
const links = [];
|
|
||||||
const generateLinks = (n, r) => {
|
|
||||||
for (let i = 0; i < r; i++) {
|
|
||||||
const link = {
|
|
||||||
source: n[getRandomInt(0, n.length - 1)].hostname,
|
|
||||||
target: n[getRandomInt(0, n.length - 1)].hostname,
|
|
||||||
};
|
|
||||||
links.push(link);
|
|
||||||
}
|
|
||||||
return { nodes: n, links };
|
|
||||||
};
|
|
||||||
const generateNodes = (n) => {
|
|
||||||
function getRandomType() {
|
|
||||||
return ['hybrid', 'execution', 'control', 'hop'][getRandomInt(0, 3)];
|
|
||||||
}
|
|
||||||
function getRandomState() {
|
|
||||||
return ['healthy', 'error', 'disabled'][getRandomInt(0, 2)];
|
|
||||||
}
|
|
||||||
for (let i = 0; i < n; i++) {
|
|
||||||
const id = i + 1;
|
|
||||||
const randomType = getRandomType();
|
|
||||||
const randomState = getRandomState();
|
|
||||||
const node = {
|
|
||||||
id,
|
|
||||||
hostname: `node-${id}`,
|
|
||||||
node_type: randomType,
|
|
||||||
node_state: randomState,
|
|
||||||
};
|
|
||||||
nodes.push(node);
|
|
||||||
}
|
|
||||||
return generateLinks(nodes, getRandomInt(1, n - 1));
|
|
||||||
};
|
|
||||||
const data = generateNodes(getRandomInt(250, 250));
|
|
||||||
const draw = () => {
|
const draw = () => {
|
||||||
const margin = 15;
|
|
||||||
const defaultRadius = 16;
|
|
||||||
const defaultCollisionFactor = 80;
|
|
||||||
const defaultForceStrength = -100;
|
|
||||||
const defaultForceBody = 75;
|
|
||||||
const defaultForceX = 0;
|
|
||||||
const defaultForceY = 0;
|
|
||||||
const height = 600;
|
|
||||||
const fallbackWidth = 700;
|
|
||||||
const defaultNodeColor = '#0066CC';
|
|
||||||
const defaultNodeHighlightColor = '#16407C';
|
|
||||||
const defaultNodeLabelColor = 'white';
|
|
||||||
const defaultFontSize = '12px';
|
|
||||||
const labelMaxLen = 15;
|
|
||||||
const getWidth = () => {
|
const getWidth = () => {
|
||||||
let width;
|
let width;
|
||||||
// This is in an a try/catch due to an error from jest.
|
// This is in an a try/catch due to an error from jest.
|
||||||
@@ -84,10 +50,10 @@ function MeshGraph({ showLegend, zoom }) {
|
|||||||
// style function, it says it is null in the test
|
// style function, it says it is null in the test
|
||||||
try {
|
try {
|
||||||
width =
|
width =
|
||||||
parseInt(d3.select(`#chart`).style('width'), 10) - margin ||
|
parseInt(d3.select(`#chart`).style('width'), 10) - MARGIN ||
|
||||||
fallbackWidth;
|
FALLBACK_WIDTH;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
width = fallbackWidth;
|
width = FALLBACK_WIDTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
return width;
|
return width;
|
||||||
@@ -100,13 +66,13 @@ function MeshGraph({ showLegend, zoom }) {
|
|||||||
.select('#chart')
|
.select('#chart')
|
||||||
.append('svg')
|
.append('svg')
|
||||||
.attr('class', 'mesh-svg')
|
.attr('class', 'mesh-svg')
|
||||||
.attr('width', `${width + margin}px`)
|
.attr('width', `${width + MARGIN}px`)
|
||||||
.attr('height', `${height + margin}px`)
|
.attr('height', `${HEIGHT + MARGIN}px`)
|
||||||
.attr('viewBox', [0, 0, width, height]);
|
.attr('viewBox', [0, 0, width, HEIGHT]);
|
||||||
const mesh = svg
|
const mesh = svg
|
||||||
.append('g')
|
.append('g')
|
||||||
.attr('class', 'mesh')
|
.attr('class', 'mesh')
|
||||||
.attr('transform', `translate(${margin}, ${margin})`);
|
.attr('transform', `translate(${MARGIN}, ${MARGIN})`);
|
||||||
|
|
||||||
const graph = data;
|
const graph = data;
|
||||||
|
|
||||||
@@ -114,16 +80,21 @@ function MeshGraph({ showLegend, zoom }) {
|
|||||||
.forceSimulation(graph.nodes)
|
.forceSimulation(graph.nodes)
|
||||||
.force(
|
.force(
|
||||||
'charge',
|
'charge',
|
||||||
d3.forceManyBody(defaultForceBody).strength(defaultForceStrength)
|
d3
|
||||||
|
.forceManyBody(MESH_FORCE_LAYOUT.defaultForceBody)
|
||||||
|
.strength(MESH_FORCE_LAYOUT.defaultForceStrength)
|
||||||
)
|
)
|
||||||
.force(
|
.force(
|
||||||
'link',
|
'link',
|
||||||
d3.forceLink(graph.links).id((d) => d.hostname)
|
d3.forceLink(graph.links).id((d) => d.hostname)
|
||||||
)
|
)
|
||||||
.force('collide', d3.forceCollide(defaultCollisionFactor))
|
.force(
|
||||||
.force('forceX', d3.forceX(defaultForceX))
|
'collide',
|
||||||
.force('forceY', d3.forceY(defaultForceY))
|
d3.forceCollide(MESH_FORCE_LAYOUT.defaultCollisionFactor)
|
||||||
.force('center', d3.forceCenter(width / 2, height / 2));
|
)
|
||||||
|
.force('forceX', d3.forceX(MESH_FORCE_LAYOUT.defaultForceX))
|
||||||
|
.force('forceY', d3.forceY(MESH_FORCE_LAYOUT.defaultForceY))
|
||||||
|
.force('center', d3.forceCenter(width / 2, HEIGHT / 2));
|
||||||
|
|
||||||
const link = mesh
|
const link = mesh
|
||||||
.append('g')
|
.append('g')
|
||||||
@@ -133,7 +104,7 @@ function MeshGraph({ showLegend, zoom }) {
|
|||||||
.data(graph.links)
|
.data(graph.links)
|
||||||
.enter()
|
.enter()
|
||||||
.append('line')
|
.append('line')
|
||||||
.attr('class', (d, i) => `link-${i}`)
|
.attr('class', (_, i) => `link-${i}`)
|
||||||
.attr('data-cy', (d) => `${d.source}-${d.target}`)
|
.attr('data-cy', (d) => `${d.source}-${d.target}`)
|
||||||
.style('fill', 'none')
|
.style('fill', 'none')
|
||||||
.style('stroke', '#ccc')
|
.style('stroke', '#ccc')
|
||||||
@@ -166,11 +137,11 @@ function MeshGraph({ showLegend, zoom }) {
|
|||||||
// node circles
|
// node circles
|
||||||
node
|
node
|
||||||
.append('circle')
|
.append('circle')
|
||||||
.attr('r', defaultRadius)
|
.attr('r', DEFAULT_RADIUS)
|
||||||
.attr('class', (d) => d.node_type)
|
.attr('class', (d) => d.node_type)
|
||||||
.attr('class', (d) => `id-${d.id}`)
|
.attr('class', (d) => `id-${d.id}`)
|
||||||
.attr('fill', defaultNodeColor)
|
.attr('fill', DEFAULT_NODE_COLOR)
|
||||||
.attr('stroke', defaultNodeLabelColor);
|
.attr('stroke', DEFAULT_NODE_LABEL_TEXT_COLOR);
|
||||||
|
|
||||||
// node type labels
|
// node type labels
|
||||||
node
|
node
|
||||||
@@ -178,7 +149,7 @@ function MeshGraph({ showLegend, zoom }) {
|
|||||||
.text((d) => renderNodeType(d.node_type))
|
.text((d) => renderNodeType(d.node_type))
|
||||||
.attr('text-anchor', 'middle')
|
.attr('text-anchor', 'middle')
|
||||||
.attr('alignment-baseline', 'central')
|
.attr('alignment-baseline', 'central')
|
||||||
.attr('fill', defaultNodeLabelColor);
|
.attr('fill', DEFAULT_NODE_LABEL_TEXT_COLOR);
|
||||||
|
|
||||||
// node hostname labels
|
// node hostname labels
|
||||||
const hostNames = node.append('g');
|
const hostNames = node.append('g');
|
||||||
@@ -186,7 +157,7 @@ function MeshGraph({ showLegend, zoom }) {
|
|||||||
.append('text')
|
.append('text')
|
||||||
.text((d) => renderLabelText(d.node_state, d.hostname))
|
.text((d) => renderLabelText(d.node_state, d.hostname))
|
||||||
.attr('class', 'placeholder')
|
.attr('class', 'placeholder')
|
||||||
.attr('fill', defaultNodeLabelColor)
|
.attr('fill', DEFAULT_NODE_LABEL_TEXT_COLOR)
|
||||||
.attr('text-anchor', 'middle')
|
.attr('text-anchor', 'middle')
|
||||||
.attr('y', 40)
|
.attr('y', 40)
|
||||||
.each(function calculateLabelWidth() {
|
.each(function calculateLabelWidth() {
|
||||||
@@ -207,8 +178,8 @@ function MeshGraph({ showLegend, zoom }) {
|
|||||||
hostNames
|
hostNames
|
||||||
.append('text')
|
.append('text')
|
||||||
.text((d) => renderLabelText(d.node_state, d.hostname))
|
.text((d) => renderLabelText(d.node_state, d.hostname))
|
||||||
.attr('font-size', defaultFontSize)
|
.attr('font-size', DEFAULT_FONT_SIZE)
|
||||||
.attr('fill', defaultNodeLabelColor)
|
.attr('fill', DEFAULT_NODE_LABEL_TEXT_COLOR)
|
||||||
.attr('text-anchor', 'middle')
|
.attr('text-anchor', 'middle')
|
||||||
.attr('y', 38);
|
.attr('y', 38);
|
||||||
|
|
||||||
@@ -216,7 +187,6 @@ function MeshGraph({ showLegend, zoom }) {
|
|||||||
simulation.force('link').links(graph.links);
|
simulation.force('link').links(graph.links);
|
||||||
|
|
||||||
function ticked() {
|
function ticked() {
|
||||||
// link.attr('d', linkArc);
|
|
||||||
d3.select('.simulation-loader').style('visibility', 'visible');
|
d3.select('.simulation-loader').style('visibility', 'visible');
|
||||||
|
|
||||||
link
|
link
|
||||||
@@ -226,42 +196,16 @@ function MeshGraph({ showLegend, zoom }) {
|
|||||||
.attr('y2', (d) => d.target.y);
|
.attr('y2', (d) => d.target.y);
|
||||||
|
|
||||||
node.attr('transform', (d) => `translate(${d.x},${d.y})`);
|
node.attr('transform', (d) => `translate(${d.x},${d.y})`);
|
||||||
calculateAlphaDecay(simulation.alpha(), simulation.alphaMin(), 35);
|
calculateAlphaDecay(simulation.alpha(), simulation.alphaMin(), 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
svg.call(zoom);
|
svg.call(zoom);
|
||||||
|
|
||||||
function renderStateColor(nodeState) {
|
|
||||||
const colorKey = {
|
|
||||||
disabled: '#6A6E73',
|
|
||||||
healthy: '#3E8635',
|
|
||||||
error: '#C9190B',
|
|
||||||
};
|
|
||||||
return colorKey[nodeState];
|
|
||||||
}
|
|
||||||
function renderLabelText(nodeState, name) {
|
|
||||||
const stateKey = {
|
|
||||||
disabled: '\u25EF',
|
|
||||||
healthy: '\u2713',
|
|
||||||
error: '\u0021',
|
|
||||||
};
|
|
||||||
return `${stateKey[nodeState]} ${truncateString(name, labelMaxLen)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderNodeType(nodeType) {
|
|
||||||
const typeKey = {
|
|
||||||
hop: 'h',
|
|
||||||
execution: 'Ex',
|
|
||||||
hybrid: 'Hy',
|
|
||||||
control: 'C',
|
|
||||||
};
|
|
||||||
|
|
||||||
return typeKey[nodeType];
|
|
||||||
}
|
|
||||||
|
|
||||||
function highlightSiblings(n) {
|
function highlightSiblings(n) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
svg.select(`circle.id-${n.id}`).attr('fill', defaultNodeHighlightColor);
|
svg
|
||||||
|
.select(`circle.id-${n.id}`)
|
||||||
|
.attr('fill', DEFAULT_NODE_HIGHLIGHT_COLOR);
|
||||||
const immediate = graph.links.filter(
|
const immediate = graph.links.filter(
|
||||||
(l) =>
|
(l) =>
|
||||||
n.hostname === l.source.hostname || n.hostname === l.target.hostname
|
n.hostname === l.source.hostname || n.hostname === l.target.hostname
|
||||||
@@ -277,7 +221,7 @@ function MeshGraph({ showLegend, zoom }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deselectSiblings(n) {
|
function deselectSiblings(n) {
|
||||||
svg.select(`circle.id-${n.id}`).attr('fill', defaultNodeColor);
|
svg.select(`circle.id-${n.id}`).attr('fill', DEFAULT_NODE_COLOR);
|
||||||
const immediate = graph.links.filter(
|
const immediate = graph.links.filter(
|
||||||
(l) =>
|
(l) =>
|
||||||
n.hostname === l.source.hostname || n.hostname === l.target.hostname
|
n.hostname === l.source.hostname || n.hostname === l.target.hostname
|
||||||
@@ -317,35 +261,11 @@ function MeshGraph({ showLegend, zoom }) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
async function redirectToDetailsPage() {
|
|
||||||
// TODO: redirect to top-level instances details page
|
|
||||||
const { id: nodeId } = selectedNode;
|
|
||||||
const {
|
|
||||||
data: { results },
|
|
||||||
} = await InstancesAPI.readInstanceGroup(nodeId);
|
|
||||||
const { id: instanceGroupId } = results[0];
|
|
||||||
const constructedURL = `/instance_groups/${instanceGroupId}/instances/${nodeId}/details`;
|
|
||||||
history.push(constructedURL);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderNodeIcon() {
|
|
||||||
if (selectedNode) {
|
|
||||||
const { node_type: nodeType } = selectedNode;
|
|
||||||
const typeKey = {
|
|
||||||
hop: 'h',
|
|
||||||
execution: 'Ex',
|
|
||||||
hybrid: 'Hy',
|
|
||||||
control: 'C',
|
|
||||||
};
|
|
||||||
|
|
||||||
return typeKey[nodeType];
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function handleResize() {
|
function handleResize() {
|
||||||
d3.select('.simulation-loader').style('visibility', 'visible');
|
d3.select('.simulation-loader').style('visibility', 'visible');
|
||||||
|
setSelectedNode(null);
|
||||||
|
setIsNodeSelected(false);
|
||||||
draw();
|
draw();
|
||||||
}
|
}
|
||||||
window.addEventListener('resize', debounce(handleResize, 500));
|
window.addEventListener('resize', debounce(handleResize, 500));
|
||||||
@@ -358,9 +278,11 @@ function MeshGraph({ showLegend, zoom }) {
|
|||||||
{showLegend && <Legend />}
|
{showLegend && <Legend />}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
isNodeSelected={isNodeSelected}
|
isNodeSelected={isNodeSelected}
|
||||||
renderNodeIcon={renderNodeIcon}
|
renderNodeIcon={renderNodeIcon(selectedNode)}
|
||||||
nodeDetail={nodeDetail}
|
nodeDetail={nodeDetail}
|
||||||
redirectToDetailsPage={redirectToDetailsPage}
|
redirectToDetailsPage={() =>
|
||||||
|
redirectToDetailsPage(selectedNode, history)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<Loader className="simulation-loader" />
|
<Loader className="simulation-loader" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ function Tooltip({
|
|||||||
<TextContent>
|
<TextContent>
|
||||||
<Text
|
<Text
|
||||||
component={TextVariants.small}
|
component={TextVariants.small}
|
||||||
style={{ 'fontWeight': 'bold', color: 'black' }}
|
style={{ fontWeight: 'bold', color: 'black' }}
|
||||||
>
|
>
|
||||||
Details
|
Details
|
||||||
</Text>
|
</Text>
|
||||||
@@ -79,7 +79,7 @@ function Tooltip({
|
|||||||
<DescriptionListGroup>
|
<DescriptionListGroup>
|
||||||
<DescriptionListTerm>
|
<DescriptionListTerm>
|
||||||
<Button variant="primary" isSmall>
|
<Button variant="primary" isSmall>
|
||||||
{renderNodeIcon()}
|
{renderNodeIcon}
|
||||||
</Button>
|
</Button>
|
||||||
</DescriptionListTerm>
|
</DescriptionListTerm>
|
||||||
<DescriptionListDescription>
|
<DescriptionListDescription>
|
||||||
|
|||||||
38
awx/ui/src/screens/TopologyView/constants.js
Normal file
38
awx/ui/src/screens/TopologyView/constants.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/* eslint-disable-next-line import/prefer-default-export */
|
||||||
|
export const MESH_FORCE_LAYOUT = {
|
||||||
|
defaultCollisionFactor: 80,
|
||||||
|
defaultForceStrength: -100,
|
||||||
|
defaultForceBody: 75,
|
||||||
|
defaultForceX: 0,
|
||||||
|
defaultForceY: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DEFAULT_RADIUS = 16;
|
||||||
|
export const DEFAULT_NODE_COLOR = '#0066CC';
|
||||||
|
export const DEFAULT_NODE_HIGHLIGHT_COLOR = '#16407C';
|
||||||
|
export const DEFAULT_NODE_LABEL_TEXT_COLOR = 'white';
|
||||||
|
export const DEFAULT_FONT_SIZE = '12px';
|
||||||
|
export const LABEL_TEXT_MAX_LENGTH = 15;
|
||||||
|
|
||||||
|
export const MARGIN = 15;
|
||||||
|
export const HEIGHT = 600;
|
||||||
|
export const FALLBACK_WIDTH = 700;
|
||||||
|
|
||||||
|
export const NODE_STATE_COLOR_KEY = {
|
||||||
|
disabled: '#6A6E73',
|
||||||
|
healthy: '#3E8635',
|
||||||
|
error: '#C9190B',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NODE_STATE_HTML_ENTITY_KEY = {
|
||||||
|
disabled: '\u25EF',
|
||||||
|
healthy: '\u2713',
|
||||||
|
error: '\u0021',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NODE_TYPE_SYMBOL_KEY = {
|
||||||
|
hop: 'h',
|
||||||
|
execution: 'Ex',
|
||||||
|
hybrid: 'Hy',
|
||||||
|
control: 'C',
|
||||||
|
};
|
||||||
86
awx/ui/src/screens/TopologyView/utils/helpers.js
Normal file
86
awx/ui/src/screens/TopologyView/utils/helpers.js
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import { InstancesAPI } from 'api';
|
||||||
|
import { truncateString } from '../../../util/strings';
|
||||||
|
|
||||||
|
import {
|
||||||
|
NODE_STATE_COLOR_KEY,
|
||||||
|
NODE_STATE_HTML_ENTITY_KEY,
|
||||||
|
NODE_TYPE_SYMBOL_KEY,
|
||||||
|
LABEL_TEXT_MAX_LENGTH,
|
||||||
|
} from '../constants';
|
||||||
|
|
||||||
|
export function renderStateColor(nodeState) {
|
||||||
|
return NODE_STATE_COLOR_KEY[nodeState];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renderLabelText(nodeState, name) {
|
||||||
|
return `${NODE_STATE_HTML_ENTITY_KEY[nodeState]} ${truncateString(
|
||||||
|
name,
|
||||||
|
LABEL_TEXT_MAX_LENGTH
|
||||||
|
)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renderNodeType(nodeType) {
|
||||||
|
return NODE_TYPE_SYMBOL_KEY[nodeType];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renderNodeIcon(selectedNode) {
|
||||||
|
if (selectedNode) {
|
||||||
|
const { node_type: nodeType } = selectedNode;
|
||||||
|
return NODE_TYPE_SYMBOL_KEY[nodeType];
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function redirectToDetailsPage(selectedNode, history) {
|
||||||
|
// TODO: redirect to top-level instances details page
|
||||||
|
const { id: nodeId } = selectedNode;
|
||||||
|
const {
|
||||||
|
data: { results },
|
||||||
|
} = await InstancesAPI.readInstanceGroup(nodeId);
|
||||||
|
const { id: instanceGroupId } = results[0];
|
||||||
|
const constructedURL = `/instance_groups/${instanceGroupId}/instances/${nodeId}/details`;
|
||||||
|
history.push(constructedURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEBUG TOOLS
|
||||||
|
export function getRandomInt(min, max) {
|
||||||
|
min = Math.ceil(min);
|
||||||
|
max = Math.floor(max);
|
||||||
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
const generateRandomLinks = (n, r) => {
|
||||||
|
const links = [];
|
||||||
|
for (let i = 0; i < r; i++) {
|
||||||
|
const link = {
|
||||||
|
source: n[getRandomInt(0, n.length - 1)].hostname,
|
||||||
|
target: n[getRandomInt(0, n.length - 1)].hostname,
|
||||||
|
};
|
||||||
|
links.push(link);
|
||||||
|
}
|
||||||
|
return { nodes: n, links };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const generateRandomNodes = (n) => {
|
||||||
|
const nodes = [];
|
||||||
|
function getRandomType() {
|
||||||
|
return ['hybrid', 'execution', 'control', 'hop'][getRandomInt(0, 3)];
|
||||||
|
}
|
||||||
|
function getRandomState() {
|
||||||
|
return ['healthy', 'error', 'disabled'][getRandomInt(0, 2)];
|
||||||
|
}
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
const id = i + 1;
|
||||||
|
const randomType = getRandomType();
|
||||||
|
const randomState = getRandomState();
|
||||||
|
const node = {
|
||||||
|
id,
|
||||||
|
hostname: `node-${id}`,
|
||||||
|
node_type: randomType,
|
||||||
|
node_state: randomState,
|
||||||
|
};
|
||||||
|
nodes.push(node);
|
||||||
|
}
|
||||||
|
return generateRandomLinks(nodes, getRandomInt(1, n - 1));
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user