github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ui/src/views/reports/containers/localities/index.tsx (about) 1 // Copyright 2018 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 import _ from "lodash"; 12 import React from "react"; 13 import { Helmet } from "react-helmet"; 14 import { connect } from "react-redux"; 15 import { withRouter } from "react-router-dom"; 16 17 import { refreshLocations, refreshNodes } from "src/redux/apiReducers"; 18 import { LocalityTier, LocalityTree, selectLocalityTree } from "src/redux/localities"; 19 import { LocationTree, selectLocationsRequestStatus, selectLocationTree } from "src/redux/locations"; 20 import { selectNodeRequestStatus } from "src/redux/nodes"; 21 import { AdminUIState } from "src/redux/state"; 22 import { getNodeLocalityTiers } from "src/util/localities"; 23 import { findMostSpecificLocation, hasLocation } from "src/util/locations"; 24 import Loading from "src/views/shared/components/loading"; 25 import "./localities.styl"; 26 import { CachedDataReducerState } from "src/redux/cachedDataReducer"; 27 28 function formatCoord(coordinate: number) { 29 return coordinate.toFixed(4); 30 } 31 32 function renderLocation(locations: LocationTree, tiers: LocalityTier[]) { 33 const location = findMostSpecificLocation(locations, tiers); 34 35 if (_.isNil(location)) { 36 return ""; 37 } 38 39 return `${formatCoord(location.latitude)}, ${formatCoord(location.longitude)}`; 40 } 41 42 function renderLocalityTree(locations: LocationTree, tree: LocalityTree) { 43 let rows: React.ReactNode[] = []; 44 const leftIndentStyle = { 45 paddingLeft: `${20 * tree.tiers.length}px`, 46 }; 47 48 tree.nodes.forEach((node) => { 49 const tiers = getNodeLocalityTiers(node); 50 51 rows.push( 52 <tr> 53 <td></td> 54 <td>n{ node.desc.node_id } @ { node.desc.address.address_field }</td> 55 <td className="parent-location">{ renderLocation(locations, tiers) }</td> 56 </tr>, 57 ); 58 }); 59 60 Object.keys(tree.localities).forEach((key) => { 61 Object.keys(tree.localities[key]).forEach((value) => { 62 const child = tree.localities[key][value]; 63 64 rows.push( 65 <tr> 66 <td><span style={leftIndentStyle}>{ key }={ value }</span></td> 67 <td></td> 68 <td className={hasLocation(locations, { key, value }) ? "own-location" : "parent-location"}> 69 { renderLocation(locations, child.tiers) } 70 </td> 71 </tr>, 72 ); 73 74 rows = rows.concat(renderLocalityTree(locations, child)); 75 }); 76 }); 77 78 return rows; 79 } 80 81 interface LocalitiesProps { 82 localityTree: LocalityTree; 83 localityStatus: CachedDataReducerState<any>; 84 locationTree: LocationTree; 85 locationStatus: CachedDataReducerState<any>; 86 refreshLocations: typeof refreshLocations; 87 refreshNodes: typeof refreshNodes; 88 } 89 90 export class Localities extends React.Component<LocalitiesProps, {}> { 91 componentDidMount() { 92 this.props.refreshLocations(); 93 this.props.refreshNodes(); 94 } 95 96 componentDidUpdate() { 97 this.props.refreshLocations(); 98 this.props.refreshNodes(); 99 } 100 101 render() { 102 return ( 103 <div> 104 <Helmet title="Localities | Debug" /> 105 <section className="section"><h1 className="base-heading">Localities</h1></section> 106 <Loading 107 loading={ !this.props.localityStatus.data || !this.props.locationStatus.data } 108 error={ [this.props.localityStatus.lastError, this.props.locationStatus.lastError] } 109 render={() => ( 110 <section className="section"> 111 <table className="locality-table"> 112 <thead> 113 <tr> 114 <th>Localities</th> 115 <th>Nodes</th> 116 <th>Location</th> 117 </tr> 118 </thead> 119 <tbody> 120 { renderLocalityTree(this.props.locationTree, this.props.localityTree) } 121 </tbody> 122 </table> 123 </section> 124 )} 125 /> 126 </div> 127 ); 128 } 129 } 130 131 const mapStateToProps = (state: AdminUIState) => ({ // RootState contains declaration for whole state 132 localityTree: selectLocalityTree(state), 133 localityStatus: selectNodeRequestStatus(state), 134 locationTree: selectLocationTree(state), 135 locationStatus: selectLocationsRequestStatus(state), 136 }); 137 138 const mapDispatchToProps = { 139 refreshLocations, 140 refreshNodes, 141 }; 142 143 export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Localities));