Tracing: Add node graph panel suggestion (#83311)

* Add node graph panel suggestion

* Update logic

* Add comment

* Check for correct fields

* Simplify logic

* Also check for viz type

* Remove extra logic on boolean
This commit is contained in:
Joey 2024-02-27 12:28:17 +00:00 committed by GitHub
parent d94db905c7
commit 92f53d3670
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 112 additions and 36 deletions

View File

@ -22,6 +22,7 @@ export const panelsToCheckFirst = [
'candlestick', 'candlestick',
'flamegraph', 'flamegraph',
'traces', 'traces',
'nodeGraph',
]; ];
export async function getAllSuggestions(data?: PanelData, panel?: PanelModel): Promise<VisualizationSuggestion[]> { export async function getAllSuggestions(data?: PanelData, panel?: PanelModel): Promise<VisualizationSuggestion[]> {

View File

@ -2,41 +2,44 @@ import { PanelPlugin } from '@grafana/data';
import { NodeGraphPanel } from './NodeGraphPanel'; import { NodeGraphPanel } from './NodeGraphPanel';
import { ArcOptionsEditor } from './editor/ArcOptionsEditor'; import { ArcOptionsEditor } from './editor/ArcOptionsEditor';
import { NodeGraphSuggestionsSupplier } from './suggestions';
import { NodeGraphOptions } from './types'; import { NodeGraphOptions } from './types';
export const plugin = new PanelPlugin<NodeGraphOptions>(NodeGraphPanel).setPanelOptions((builder, context) => { export const plugin = new PanelPlugin<NodeGraphOptions>(NodeGraphPanel)
builder.addNestedOptions({ .setPanelOptions((builder, context) => {
category: ['Nodes'], builder.addNestedOptions({
path: 'nodes', category: ['Nodes'],
build: (builder) => { path: 'nodes',
builder.addUnitPicker({ build: (builder) => {
name: 'Main stat unit', builder.addUnitPicker({
path: 'mainStatUnit', name: 'Main stat unit',
}); path: 'mainStatUnit',
builder.addUnitPicker({ });
name: 'Secondary stat unit', builder.addUnitPicker({
path: 'secondaryStatUnit', name: 'Secondary stat unit',
}); path: 'secondaryStatUnit',
builder.addCustomEditor({ });
name: 'Arc sections', builder.addCustomEditor({
path: 'arcs', name: 'Arc sections',
id: 'arcs', path: 'arcs',
editor: ArcOptionsEditor, id: 'arcs',
}); editor: ArcOptionsEditor,
}, });
}); },
builder.addNestedOptions({ });
category: ['Edges'], builder.addNestedOptions({
path: 'edges', category: ['Edges'],
build: (builder) => { path: 'edges',
builder.addUnitPicker({ build: (builder) => {
name: 'Main stat unit', builder.addUnitPicker({
path: 'mainStatUnit', name: 'Main stat unit',
}); path: 'mainStatUnit',
builder.addUnitPicker({ });
name: 'Secondary stat unit', builder.addUnitPicker({
path: 'secondaryStatUnit', name: 'Secondary stat unit',
}); path: 'secondaryStatUnit',
}, });
}); },
}); });
})
.setSuggestionsSupplier(new NodeGraphSuggestionsSupplier());

View File

@ -0,0 +1,71 @@
import { DataFrame, FieldType, VisualizationSuggestionsBuilder, VisualizationSuggestionScore } from '@grafana/data';
import { SuggestionName } from 'app/types/suggestions';
export class NodeGraphSuggestionsSupplier {
getListWithDefaults(builder: VisualizationSuggestionsBuilder) {
return builder.getListAppender<{}, {}>({
name: SuggestionName.NodeGraph,
pluginId: 'nodeGraph',
});
}
hasCorrectFields(frames: DataFrame[]): boolean {
let hasNodesFrame = false;
let hasEdgesFrame = false;
const nodeFields: Array<[string, FieldType]> = [
['id', FieldType.string],
['title', FieldType.string],
['mainstat', FieldType.number],
];
const edgeFields: Array<[string, FieldType]> = [
['id', FieldType.string],
['source', FieldType.string],
['target', FieldType.string],
];
for (const frame of frames) {
if (this.checkFields(nodeFields, frame)) {
hasNodesFrame = true;
}
if (this.checkFields(edgeFields, frame)) {
hasEdgesFrame = true;
}
}
return hasNodesFrame && hasEdgesFrame;
}
checkFields(fields: Array<[string, FieldType]>, frame: DataFrame): boolean {
let hasCorrectFields = true;
for (const field of fields) {
const [name, type] = field;
const frameField = frame.fields.find((f) => f.name === name);
if (!frameField || type !== frameField.type) {
hasCorrectFields = false;
break;
}
}
return hasCorrectFields;
}
getSuggestionsForData(builder: VisualizationSuggestionsBuilder) {
if (!builder.data) {
return;
}
const hasCorrectFields = this.hasCorrectFields(builder.data.series);
const nodeGraphFrames = builder.data.series.filter(
(df) => df.meta && df.meta.preferredVisualisationType === 'nodeGraph'
);
if (hasCorrectFields || nodeGraphFrames.length === 2) {
this.getListWithDefaults(builder).append({
name: SuggestionName.NodeGraph,
score: VisualizationSuggestionScore.Best,
});
}
}
}

View File

@ -29,4 +29,5 @@ export enum SuggestionName {
Logs = 'Logs', Logs = 'Logs',
FlameGraph = 'Flame graph', FlameGraph = 'Flame graph',
Trace = 'Trace', Trace = 'Trace',
NodeGraph = 'Node graph',
} }