Files
Andrej Ocenas fdd6620d0a NodeGraph: Exploration mode (#33623)
* 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>
2021-05-12 16:04:21 +02:00

89 lines
2.5 KiB
TypeScript

import React, { useCallback } from 'react';
import { NodeDatum } from './types';
import { Field, FieldColorModeId, getColorForTheme, GrafanaTheme } from '@grafana/data';
import { identity } from 'lodash';
import { Config } from './layout';
import { css } from '@emotion/css';
import { Icon, LegendDisplayMode, useStyles, useTheme, VizLegend, VizLegendItem, VizLegendListItem } from '@grafana/ui';
function getStyles() {
return {
item: css`
label: LegendItem;
flex-grow: 0;
`,
};
}
interface Props {
nodes: NodeDatum[];
onSort: (sort: Config['sort']) => void;
sort?: Config['sort'];
sortable: boolean;
}
export const Legend = function Legend(props: Props) {
const { nodes, onSort, sort, sortable } = props;
const theme = useTheme();
const styles = useStyles(getStyles);
const colorItems = getColorLegendItems(nodes, theme);
const onClick = useCallback(
(item) => {
onSort({
field: item.data!.field,
ascending: item.data!.field === sort?.field ? !sort?.ascending : true,
});
},
[sort, onSort]
);
return (
<VizLegend<ItemData>
displayMode={LegendDisplayMode.List}
placement={'bottom'}
items={colorItems}
itemRenderer={(item) => {
return (
<>
<VizLegendListItem item={item} className={styles.item} onLabelClick={sortable ? onClick : undefined} />
{sortable &&
(sort?.field === item.data!.field ? <Icon name={sort!.ascending ? 'angle-up' : 'angle-down'} /> : '')}
</>
);
}}
/>
);
};
interface ItemData {
field: Field;
}
function getColorLegendItems(nodes: NodeDatum[], theme: GrafanaTheme): Array<VizLegendItem<ItemData>> {
const fields = [nodes[0].mainStat, nodes[0].secondaryStat].filter(identity) as Field[];
const node = nodes.find((n) => n.arcSections.length > 0);
if (node) {
if (node.arcSections[0]!.config?.color?.mode === FieldColorModeId.Fixed) {
// We assume in this case we have a set of fixed colors which map neatly into a basic legend.
// Lets collect and deduplicate as there isn't a requirement for 0 size arc section to be defined
fields.push(...new Set(nodes.map((n) => n.arcSections).flat()));
} else {
// TODO: probably some sort of gradient which we will have to deal with later
return [];
}
}
return fields.map((f) => {
return {
label: f.config.displayName || f.name,
color: getColorForTheme(f.config.color?.fixedColor || '', theme),
yAxis: 0,
data: { field: f },
};
});
}