import { orderBy } from "lodash"; import moment from "moment"; import * as React from "react"; import { connect } from "react-redux"; import { Dispatch } from "redux"; import sanitize from "sanitize-html"; import { AnchorButton, Button, Card, Classes, Code, Divider, Elevation, H2, H4, HTMLTable, NonIdealState, Position, Tab, Tabs, Tooltip } from "@blueprintjs/core"; import { IconNames } from "@blueprintjs/icons"; import { selectAndLoadInstance } from "../redux/actions"; import { IAppState, IGraph, IInstanceDetails } from "../redux/types"; import { ErrorState } from "./ErrorState"; interface ISidebarProps { graph?: IGraph; instanceName: string | null; instanceLoadError: boolean; instanceDetails: IInstanceDetails | null; isLoadingInstanceDetails: boolean; selectAndLoadInstance: (instanceName: string) => void; } interface ISidebarState { isOpen: boolean; } class SidebarImpl extends React.Component { constructor(props: ISidebarProps) { super(props); const isOpen = window.innerWidth >= 900 ? true : false; this.state = { isOpen }; } public render() { const closedClass = this.state.isOpen ? "" : " closed"; const buttonIcon = this.state.isOpen ? IconNames.DOUBLE_CHEVRON_RIGHT : IconNames.DOUBLE_CHEVRON_LEFT; return (
); } private handleToggle = () => { this.setState({ isOpen: !this.state.isOpen }); }; private renderSidebarContents = () => { if (this.props.isLoadingInstanceDetails) { return this.renderLoadingState(); } else if (!this.props.instanceDetails) { return this.renderEmptyState(); } else if (this.props.instanceDetails.status.toLowerCase().indexOf("personalinstance") > -1) { return this.renderPersonalInstanceErrorState(); } else if (this.props.instanceDetails.status !== "success") { return this.renderMissingDataState(); } else if (this.props.instanceLoadError) { return ; } else if ( this.props.graph && this.props.instanceName && this.props.graph.nodes.map(n => n.id).indexOf(this.props.instanceName) < 0 ) { return this.renderQuietInstanceState(); } return (
{this.renderHeading()} {this.props.instanceDetails.description && ( )} {this.shouldRenderStats() && }
); }; private shouldRenderStats = () => { const details = this.props.instanceDetails; return details && (details.version || details.userCount || details.statusCount || details.domainCount); }; private renderHeading = () => { let content: JSX.Element; if (!this.props.instanceName) { content = {"No instance selected"}; } else { content = ( {this.props.instanceName + " "} ); } return (

{content}

); }; private renderDescription = () => { const description = this.props.instanceDetails!.description; if (!description) { return; } return

; }; private renderVersionAndCounts = () => { const version = this.props.instanceDetails!.version; const userCount = this.props.instanceDetails!.userCount; const statusCount = this.props.instanceDetails!.statusCount; const domainCount = this.props.instanceDetails!.domainCount; const lastUpdated = this.props.instanceDetails!.lastUpdated; return (

Version {{version} || "Unknown"} Users {userCount || "Unknown"} Statuses {statusCount || "Unknown"} Known peers {domainCount || "Unknown"} Last updated {moment(lastUpdated + "Z").fromNow() || "Unknown"}
); }; private renderNeighbors = () => { if (!this.props.graph || !this.props.instanceName) { return; } const edges = this.props.graph.edges.filter(e => [e.source, e.target].indexOf(this.props.instanceName!) > -1); const neighbors: any[] = []; edges.forEach(e => { if (e.source === this.props.instanceName) { neighbors.push({ neighbor: e.target, weight: e.size }); } else { neighbors.push({ neighbor: e.source, weight: e.size }); } }); const neighborRows = orderBy(neighbors, ["weight"], ["desc"]).map((neighborDetails: any, idx: number) => ( {neighborDetails.neighbor} {neighborDetails.weight.toFixed(4)} )); return (

The mention ratio is the average of how many times the two instances mention each other per status. A mention ratio of 1 would mean that every single status contained a mention of a user on the other instance.

Instance Mention ratio {neighborRows}
); }; private renderPeers = () => { const peers = this.props.instanceDetails!.peers; if (!peers || peers.length === 0) { return; } const peerRows = peers.map(instance => ( {instance.name} )); return (

All the instances, past and present, that {this.props.instanceName} knows about.

{peerRows}
); }; private renderEmptyState = () => { return ( ); }; private renderLoadingState = () => { return (

Description

Eaque rerum sequi unde omnis voluptatibus non quia fugit. Dignissimos asperiores aut incidunt. Cupiditate sit voluptates quia nulla et saepe id suscipit. Voluptas sed rerum placeat consectetur pariatur necessitatibus tempora. Eaque rerum sequi unde omnis voluptatibus non quia fugit. Dignissimos asperiores aut incidunt. Cupiditate sit voluptates quia nulla et saepe id suscipit. Voluptas sed rerum placeat consectetur pariatur necessitatibus tempora.

Version

Eaque rerum sequi unde omnis voluptatibus non quia fugit.

Stats

Eaque rerum sequi unde omnis voluptatibus non quia fugit. Dignissimos asperiores aut incidunt. Cupiditate sit voluptates quia nulla et saepe id suscipit. Eaque rerum sequi unde omnis voluptatibus non quia fugit. Dignissimos asperiores aut incidunt. Cupiditate sit voluptates quia nulla et saepe id suscipit.

); }; private renderPersonalInstanceErrorState = () => { return ( Message @tao to opt in } /> ); }; private renderMissingDataState = () => { return ( ); }; private renderQuietInstanceState = () => { return ( ); }; private openInstanceLink = () => { window.open("https://" + this.props.instanceName, "_blank"); }; private selectInstance = (e: any) => { this.props.selectAndLoadInstance(e.target.innerText); }; } const mapStateToProps = (state: IAppState) => ({ graph: state.data.graph, instanceDetails: state.currentInstance.currentInstanceDetails, instanceLoadError: state.currentInstance.error, instanceName: state.currentInstance.currentInstanceName, isLoadingInstanceDetails: state.currentInstance.isLoadingInstanceDetails }); const mapDispatchToProps = (dispatch: Dispatch) => ({ selectAndLoadInstance: (instanceName: string) => dispatch(selectAndLoadInstance(instanceName) as any) }); export const Sidebar = connect( mapStateToProps, mapDispatchToProps )(SidebarImpl);