github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/ui/dashboard/src/components/dashboards/common/NodeAndEdgePanelInformation.tsx (about) 1 import ErrorMessage from "../../ErrorMessage"; 2 import Icon from "../../Icon"; 3 import LoadingIndicator from "../LoadingIndicator"; 4 import { DashboardRunState } from "../../../types"; 5 import { EdgeStatus, GraphStatuses, NodeStatus } from "../graphs/types"; 6 import { Node } from "reactflow"; 7 8 type NodeAndEdgePanelInformationProps = { 9 nodes: Node[]; 10 status: DashboardRunState; 11 statuses: GraphStatuses; 12 }; 13 14 const nodeOrEdgeTitle = (nodeOrEdge: NodeStatus | EdgeStatus) => 15 nodeOrEdge.title || 16 nodeOrEdge?.category?.title || 17 nodeOrEdge?.category?.name || 18 nodeOrEdge.id; 19 20 const WaitingRow = ({ title }) => ( 21 <div className="flex items-center space-x-1"> 22 <Icon 23 className="w-3.5 h-3.5 text-foreground-light shrink-0" 24 icon="pending" 25 /> 26 <span className="block truncate">{title}</span> 27 </div> 28 ); 29 30 const RunningRow = ({ title }) => ( 31 <div className="flex items-center space-x-1"> 32 <LoadingIndicator className="w-3.5 h-3.5 shrink-0" /> 33 <span className="block truncate">{title}</span> 34 </div> 35 ); 36 37 const ErrorRow = ({ title, error }: { title: string; error?: string }) => ( 38 <> 39 <div className="flex items-center space-x-1"> 40 <Icon 41 className="w-3.5 h-3.5 text-alert shrink-0" 42 icon="materialsymbols-solid:error" 43 /> 44 <span className="block">{title}</span> 45 </div> 46 {error && ( 47 <span className="block"> 48 <ErrorMessage error={error} /> 49 </span> 50 )} 51 </> 52 ); 53 54 const NodeAndEdgePanelInformation = ({ 55 nodes, 56 status, 57 statuses, 58 }: NodeAndEdgePanelInformationProps) => ( 59 <div className="space-y-2 overflow-y-scroll"> 60 <div className="space-y-1"> 61 <div> 62 {statuses.complete.total} complete, {statuses.running.total} running,{" "} 63 {statuses.blocked.total} waiting, {statuses.error.total}{" "} 64 {statuses.error.total === 1 ? "error" : "errors"}. 65 </div> 66 {statuses.initialized.total === 0 && 67 statuses.blocked.total === 0 && 68 statuses.running.total === 0 && 69 statuses.complete.total === 0 && 70 status === "complete" && 71 nodes.length === 0 && ( 72 <span className="block text-foreground-light italic"> 73 No nodes or edges 74 </span> 75 )} 76 {statuses.running.withs.map((withStatus, idx) => ( 77 <RunningRow 78 key={`with:${withStatus.id}-${idx}`} 79 title={`with: ${withStatus.title || withStatus.id}`} 80 /> 81 ))} 82 {statuses.running.nodes.map((node, idx) => ( 83 <RunningRow 84 key={`node:${node.id}-${idx}`} 85 title={`node: ${nodeOrEdgeTitle(node)}`} 86 /> 87 ))} 88 {statuses.running.edges.map((edge, idx) => ( 89 <RunningRow 90 key={`edge:${edge.id}-${idx}`} 91 title={`edge: ${nodeOrEdgeTitle(edge)}`} 92 /> 93 ))} 94 {statuses.blocked.withs.map((withStatus, idx) => ( 95 <WaitingRow 96 key={`with:${withStatus.id}-${idx}`} 97 title={`with: ${withStatus.title || withStatus.id}`} 98 /> 99 ))} 100 {statuses.blocked.nodes.map((node, idx) => ( 101 <WaitingRow 102 key={`node:${node.id}-${idx}`} 103 title={`node: ${nodeOrEdgeTitle(node)}`} 104 /> 105 ))} 106 {statuses.blocked.edges.map((edge, idx) => ( 107 <WaitingRow 108 key={`edge:${edge.id}-${idx}`} 109 title={`edge: ${nodeOrEdgeTitle(edge)}`} 110 /> 111 ))} 112 {statuses.error.withs.map((withStatus, idx) => ( 113 <ErrorRow 114 key={`with:${withStatus.id}-${idx}`} 115 title={`with: ${withStatus.title || withStatus.id}`} 116 error={withStatus.error} 117 /> 118 ))} 119 {statuses.error.nodes.map((node, idx) => ( 120 <ErrorRow 121 key={`node:${node.id}-${idx}`} 122 title={`node: ${nodeOrEdgeTitle(node)}`} 123 error={node.error} 124 /> 125 ))} 126 {statuses.error.edges.map((edge, idx) => ( 127 <ErrorRow 128 key={`edge:${edge.id}-${idx}`} 129 title={`edge: ${nodeOrEdgeTitle(edge)}`} 130 error={edge.error} 131 /> 132 ))} 133 </div> 134 </div> 135 ); 136 137 export default NodeAndEdgePanelInformation;