github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ui/ccl/src/views/clusterviz/containers/map/nodeView.tsx (about) 1 // Copyright 2017 The Cockroach Authors. 2 // 3 // Licensed as a CockroachDB Enterprise file under the Cockroach Community 4 // License (the "License"); you may not use this file except in compliance with 5 // the License. You may obtain a copy of the License at 6 // 7 // https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt 8 9 import React from "react"; 10 import moment from "moment"; 11 import { Link } from "react-router-dom"; 12 13 import { INodeStatus } from "src/util/proto"; 14 import { nodeCapacityStats, livenessNomenclature } from "src/redux/nodes"; 15 import { trustIcon } from "src/util/trust"; 16 import liveIcon from "!!raw-loader!assets/livenessIcons/live.svg"; 17 import suspectIcon from "!!raw-loader!assets/livenessIcons/suspect.svg"; 18 import deadIcon from "!!raw-loader!assets/livenessIcons/dead.svg"; 19 import nodeIcon from "!!raw-loader!assets/nodeIcon.svg"; 20 import { Labels } from "src/views/clusterviz/components/nodeOrLocality/labels"; 21 import { CapacityArc } from "src/views/clusterviz/components/nodeOrLocality/capacityArc"; 22 import { Sparklines } from "src/views/clusterviz/components/nodeOrLocality/sparklines"; 23 import { LongToMoment } from "src/util/convert"; 24 import { cockroach } from "src/js/protos"; 25 26 import NodeLivenessStatus = cockroach.kv.kvserver.storagepb.NodeLivenessStatus; 27 type ILiveness = cockroach.kv.kvserver.storagepb.ILiveness; 28 29 interface NodeViewProps { 30 node: INodeStatus; 31 livenessStatus: NodeLivenessStatus; 32 liveness: ILiveness; 33 } 34 35 const SCALE_FACTOR = 0.8; 36 const TRANSLATE_X = -90 * SCALE_FACTOR; 37 const TRANSLATE_Y = -100 * SCALE_FACTOR; 38 39 export class NodeView extends React.Component<NodeViewProps> { 40 getLivenessIcon(livenessStatus: NodeLivenessStatus) { 41 switch (livenessStatus) { 42 case NodeLivenessStatus.LIVE: 43 return liveIcon; 44 case NodeLivenessStatus.DEAD: 45 return deadIcon; 46 default: 47 return suspectIcon; 48 } 49 } 50 51 getUptimeText() { 52 const { node, livenessStatus, liveness } = this.props; 53 54 switch (livenessStatus) { 55 case NodeLivenessStatus.DEAD: { 56 if (!liveness) { 57 return "dead"; 58 } 59 60 const deadTime = liveness.expiration.wall_time; 61 const deadMoment = LongToMoment(deadTime); 62 return `dead for ${moment.duration(deadMoment.diff(moment())).humanize()}`; 63 } 64 case NodeLivenessStatus.LIVE: { 65 const startTime = LongToMoment(node.started_at); 66 return `up for ${moment.duration(startTime.diff(moment())).humanize()}`; 67 } 68 default: 69 return livenessNomenclature(livenessStatus); 70 } 71 } 72 73 render() { 74 const { node, livenessStatus } = this.props; 75 const { used, usable } = nodeCapacityStats(node); 76 77 return ( 78 <Link 79 to={`/node/${node.desc.node_id}`} 80 style={{ cursor: "pointer" }} 81 > 82 <g transform={`translate(${TRANSLATE_X},${TRANSLATE_Y})scale(${SCALE_FACTOR})`}> 83 <rect width={180} height={210} opacity={0} /> 84 <Labels 85 label={`Node ${node.desc.node_id}`} 86 subLabel={this.getUptimeText()} 87 tooltip={node.desc.address.address_field} 88 /> 89 <g dangerouslySetInnerHTML={trustIcon(nodeIcon)} transform="translate(14 14)" /> 90 <g 91 dangerouslySetInnerHTML={trustIcon(this.getLivenessIcon(livenessStatus))} 92 transform="translate(9, 9)" 93 /> 94 <CapacityArc 95 usableCapacity={usable} 96 usedCapacity={used} 97 /> 98 <Sparklines nodes={[`${node.desc.node_id}`]} /> 99 </g> 100 </Link> 101 ); 102 } 103 }