Path: blob/main/web/ui/src/features/component/ComponentView.tsx
5286 views
import { FC, Fragment, ReactElement } from 'react';1import { Link } from 'react-router-dom';2import { faCubes, faLink } from '@fortawesome/free-solid-svg-icons';3import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';45import { partitionBody } from '../../utils/partition';67import ComponentBody from './ComponentBody';8import ComponentList from './ComponentList';9import { HealthLabel } from './HealthLabel';10import { ComponentDetail, ComponentInfo, PartitionedBody } from './types';1112import styles from './ComponentView.module.css';1314export interface ComponentViewProps {15component: ComponentDetail;16info: Record<string, ComponentInfo>;17}1819export const ComponentView: FC<ComponentViewProps> = (props) => {20// TODO(rfratto): expand/collapse icon for sections (treat it like Row in grafana dashboard)2122const referencedBy = props.component.referencedBy.filter((id) => props.info[id] !== undefined).map((id) => props.info[id]);23const referencesTo = props.component.referencesTo.filter((id) => props.info[id] !== undefined).map((id) => props.info[id]);2425const argsPartition = partitionBody(props.component.arguments, 'Arguments');26const exportsPartition = props.component.exports && partitionBody(props.component.exports, 'Exports');27const debugPartition = props.component.debugInfo && partitionBody(props.component.debugInfo, 'Debug info');2829function partitionTOC(partition: PartitionedBody): ReactElement {30return (31<li>32<Link to={'#' + partition.key.join('-')} target="_top">33{partition.displayName[partition.displayName.length - 1]}34</Link>35{partition.inner.length > 0 && (36<ul>37{partition.inner.map((next, idx) => {38return <Fragment key={idx.toString()}>{partitionTOC(next)}</Fragment>;39})}40</ul>41)}42</li>43);44}4546return (47<div className={styles.page}>48<nav>49<h1>Sections</h1>50<hr />51<ul>52<li>53<Link to={'#' + props.component.id} target="_top">54{props.component.id}55</Link>56</li>57{argsPartition && partitionTOC(argsPartition)}58{exportsPartition && partitionTOC(exportsPartition)}59{debugPartition && partitionTOC(debugPartition)}60{props.component.referencesTo.length > 0 && (61<li>62<Link to="#dependencies" target="_top">63Dependencies64</Link>65</li>66)}67{props.component.referencedBy.length > 0 && (68<li>69<Link to="#dependants" target="_top">70Dependants71</Link>72</li>73)}74{props.component.moduleInfo && (75<li>76<Link to="#module" target="_top">77Module components78</Link>79</li>80)}81</ul>82</nav>8384<main className={styles.content}>85<h1 id={props.component.id}>86<span className={styles.icon}>87<FontAwesomeIcon icon={faCubes} />88</span>89{props.component.id}90 {/* space to separate the component name and label so double-click selections work */}91<span className={styles.healthLabel}>92<HealthLabel health={props.component.health.state} />93</span>94</h1>9596<div className={styles.docsLink}>97<a href={`https://grafana.com/docs/agent/latest/flow/reference/components/${props.component.name}`}>98Documentation <FontAwesomeIcon icon={faLink} />99</a>100</div>101102{props.component.health.message && (103<blockquote>104<h1>105Latest health message{' '}106{props.component.health.updatedTime && (107<span className={styles.updateTime}>({props.component.health.updatedTime})</span>108)}109</h1>110<p>{props.component.health.message}</p>111</blockquote>112)}113114<ComponentBody partition={argsPartition} />115{exportsPartition && <ComponentBody partition={exportsPartition} />}116{debugPartition && <ComponentBody partition={debugPartition} />}117118{props.component.referencesTo.length > 0 && (119<section id="dependencies">120<h2>Dependencies</h2>121<div className={styles.sectionContent}>122<ComponentList components={referencesTo} parent={props.component.parent} />123</div>124</section>125)}126127{props.component.referencedBy.length > 0 && (128<section id="dependants">129<h2>Dependants</h2>130<div className={styles.sectionContent}>131<ComponentList components={referencedBy} parent={props.component.parent} />132</div>133</section>134)}135136{props.component.moduleInfo && (137<section id="module">138<h2>Module components</h2>139<div className={styles.sectionContent}>140<ComponentList141components={props.component.moduleInfo}142parent={pathJoin([props.component.parent, props.component.id])}143/>144</div>145</section>146)}147</main>148</div>149);150};151152function pathJoin(paths: (string | undefined)[]): string {153return paths.filter((p) => p && p !== '').join('/');154}155156157