mirror of
https://github.com/grafana/grafana.git
synced 2025-08-03 00:59:31 +08:00

* Add exploration option to node layout * Add hidden node count * Add grid layout option * Fix panning bounds calculation * Add legend with sorting * Allow sorting on any stats or arc value * Fix merge * Make sorting better * Reset focused node on layout change * Refactor limit hook a bit * Disable selected layout button * Don't show markers if only 1 node is hidden * Move legend to the bottom * Fix text backgrounds * Add show in graph layout action in grid layout * Center view on the focused node, fix perf issue when expanding big graph * Limit the node counting * Comment and linting fixes * Bit of code cleanup and comments * Add state for computing layout * Prevent computing map with partial data * Add rollup plugin for worker * Add rollup plugin for worker * Enhance data from worker * Fix perf issues with reduce and object creation * Improve comment * Fix tests * Css fixes * Remove worker plugin * Add comments * Fix test * Add test for exploration * Add test switching to grid layout * Apply suggestions from code review Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com> * Remove unused plugin * Fix function name * Remove unused rollup plugin * Review fixes * Fix context menu shown on layout change * Make buttons bigger * Moved NodeGraph to core grafana Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com>
117 lines
3.0 KiB
TypeScript
117 lines
3.0 KiB
TypeScript
import React from 'react';
|
|
import { VizLegendBaseProps, VizLegendItem } from './types';
|
|
import { InlineList } from '../List/InlineList';
|
|
import { List } from '../List/List';
|
|
import { css, cx } from '@emotion/css';
|
|
import { useStyles } from '../../themes';
|
|
import { GrafanaTheme } from '@grafana/data';
|
|
import { VizLegendListItem } from './VizLegendListItem';
|
|
|
|
export interface Props<T> extends VizLegendBaseProps<T> {}
|
|
|
|
/**
|
|
* @internal
|
|
*/
|
|
export const VizLegendList = <T extends unknown>({
|
|
items,
|
|
itemRenderer,
|
|
onLabelMouseEnter,
|
|
onLabelMouseOut,
|
|
onLabelClick,
|
|
placement,
|
|
className,
|
|
}: Props<T>) => {
|
|
const styles = useStyles(getStyles);
|
|
|
|
if (!itemRenderer) {
|
|
/* eslint-disable-next-line react/display-name */
|
|
itemRenderer = (item) => (
|
|
<VizLegendListItem
|
|
item={item}
|
|
onLabelClick={onLabelClick}
|
|
onLabelMouseEnter={onLabelMouseEnter}
|
|
onLabelMouseOut={onLabelMouseOut}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const getItemKey = (item: VizLegendItem<T>) => `${item.getItemKey ? item.getItemKey() : item.label}`;
|
|
|
|
switch (placement) {
|
|
case 'right': {
|
|
const renderItem = (item: VizLegendItem<T>, index: number) => {
|
|
return <span className={styles.itemRight}>{itemRenderer!(item, index)}</span>;
|
|
};
|
|
|
|
return (
|
|
<div className={cx(styles.rightWrapper, className)}>
|
|
<List items={items} renderItem={renderItem} getItemKey={getItemKey} />
|
|
</div>
|
|
);
|
|
}
|
|
case 'bottom':
|
|
default: {
|
|
const renderItem = (item: VizLegendItem<T>, index: number) => {
|
|
return <span className={styles.itemBottom}>{itemRenderer!(item, index)}</span>;
|
|
};
|
|
|
|
return (
|
|
<div className={cx(styles.bottomWrapper, className)}>
|
|
<div className={styles.section}>
|
|
<InlineList
|
|
items={items.filter((item) => item.yAxis === 1)}
|
|
renderItem={renderItem}
|
|
getItemKey={getItemKey}
|
|
/>
|
|
</div>
|
|
<div className={cx(styles.section, styles.sectionRight)}>
|
|
<InlineList
|
|
items={items.filter((item) => item.yAxis !== 1)}
|
|
renderItem={renderItem}
|
|
getItemKey={getItemKey}
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
};
|
|
|
|
VizLegendList.displayName = 'VizLegendList';
|
|
|
|
const getStyles = (theme: GrafanaTheme) => {
|
|
const itemStyles = css`
|
|
padding-right: 10px;
|
|
display: flex;
|
|
font-size: ${theme.typography.size.sm};
|
|
white-space: nowrap;
|
|
`;
|
|
|
|
return {
|
|
itemBottom: itemStyles,
|
|
itemRight: cx(
|
|
itemStyles,
|
|
css`
|
|
margin-bottom: ${theme.spacing.xs};
|
|
`
|
|
),
|
|
rightWrapper: css`
|
|
padding-left: ${theme.spacing.sm};
|
|
`,
|
|
bottomWrapper: css`
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: space-between;
|
|
width: 100%;
|
|
padding-left: ${theme.spacing.md};
|
|
`,
|
|
section: css`
|
|
display: flex;
|
|
`,
|
|
sectionRight: css`
|
|
justify-content: flex-end;
|
|
flex-grow: 1;
|
|
`,
|
|
};
|
|
};
|