Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/scenes-app/src/demos/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import { getSceneGraphEventsDemo } from './sceneGraphEvents';
import { getSeriesLimitTest } from './seriesLimit';
import { getScopesDemo } from './scopesDemo';
import { getVariableWithObjectValuesDemo } from './variableWithObjectValuesDemo';
import { getPanelRepeaterByProcessorDemo } from './panelRepeaterByProcessor';

export interface DemoDescriptor {
title: string;
Expand Down Expand Up @@ -83,6 +84,12 @@ export function getDemos(): DemoDescriptor[] {
getPage: getPanelRepeaterTest,
getSourceCodeModule: () => import('!!raw-loader!../demos/panelRepeater'),
},
{
title: 'Repeat layout by series (using data processor)',
description: 'Here we use repeat a panel using a data processor',
getPage: getPanelRepeaterByProcessorDemo,
getSourceCodeModule: () => import('!!raw-loader!../demos/panelRepeaterByProcessor'),
},
{
title: 'Repeat layout by variable',
description: 'Test of repeating layout by variable',
Expand Down
100 changes: 100 additions & 0 deletions packages/scenes-app/src/demos/panelRepeaterByProcessor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import {
EmbeddedScene,
PanelBuilders,
SceneAppPage,
SceneAppPageState,
SceneCSSGridLayout,
SceneDataNode,
SceneQueryRunner,
SceneToolbarInput,
VizPanel,
sceneGraph,
} from '@grafana/scenes';
import { getEmbeddedSceneDefaults } from './utils';
import { DATASOURCE_REF } from '../constants';
import { LoadingState, PanelData, getFrameDisplayName } from '@grafana/data';

export function getPanelRepeaterByProcessorDemo(defaults: SceneAppPageState) {
const queryRunner = new SceneQueryRunner({
dataProcessor: repeater,
queries: [
{
refId: 'A',
datasource: DATASOURCE_REF,
scenarioId: 'random_walk',
seriesCount: 4,
alias: '__server_names',
},
],
});

return new SceneAppPage({
...defaults,
getScene: () => {
return new EmbeddedScene({
...getEmbeddedSceneDefaults(),
body: new SceneCSSGridLayout({
children: [
PanelBuilders.timeseries()
.setTitle('Panel')
.setOption('legend', { showLegend: false })
.setData(queryRunner)
.build(),
],
}),
controls: [
new SceneToolbarInput({
value: '4',
label: 'Series count',
onChange: (newValue) => {
queryRunner.setState({
queries: [
{
...queryRunner.state.queries[0],
seriesCount: newValue,
},
],
});
queryRunner.runQueries();
},
}),
...getEmbeddedSceneDefaults().controls,
],
});
},
});
}

function repeater(queryRunner: SceneQueryRunner, data: PanelData) {
const layout = sceneGraph.getAncestor(queryRunner, SceneCSSGridLayout);
const sourcePanel = queryRunner.parent as VizPanel;
const children: VizPanel[] = [sourcePanel];
let returnData = data;

if (data.state === LoadingState.Loading) {
return returnData;
}

for (let seriesIndex = 0; seriesIndex < data.series.length; seriesIndex++) {
if (seriesIndex === 0) {
sourcePanel.setState({ title: getFrameDisplayName(data.series[seriesIndex], seriesIndex) });
returnData = { ...data, series: [data.series[seriesIndex]] };
continue;
}

const clone = sourcePanel.clone({
title: getFrameDisplayName(data.series[seriesIndex], seriesIndex),
$data: new SceneDataNode({
data: {
...data,
series: [data.series[seriesIndex]],
},
}),
});

children.push(clone);
}

layout.setState({ children });
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ideally this would re-use AutoGridItem repeatedPanels state

return returnData;
}
7 changes: 6 additions & 1 deletion packages/scenes/src/querying/SceneQueryRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export interface QueryRunnerState extends SceneObjectState {
runQueriesMode?: 'auto' | 'manual';
// Filters to be applied to data layer results before combining them with SQR results
dataLayerFilter?: DataLayerFilter;
dataProcessor?: (queryRunner: SceneQueryRunner, data: PanelData) => PanelData;
/**
* Optional prefix for the requestId. When set, request IDs will be formatted as `{requestIdPrefix}{counter}`.
* Useful for identifying requests from specific panels or components.
Expand Down Expand Up @@ -620,14 +621,18 @@ export class SceneQueryRunner extends SceneObjectBase<QueryRunnerState> implemen
this._resultAnnotations = data.annotations;

// Will combine annotations & alert state from data layer providers
const dataWithLayersApplied = this._combineDataLayers(preProcessedData);
let dataWithLayersApplied = this._combineDataLayers(preProcessedData);

let hasFetchedData = this.state._hasFetchedData;

if (!hasFetchedData && preProcessedData.state !== LoadingState.Loading) {
hasFetchedData = true;
}

if (this.state.dataProcessor) {
dataWithLayersApplied = this.state.dataProcessor(this, dataWithLayersApplied);
}

this.setState({ data: dataWithLayersApplied, _hasFetchedData: hasFetchedData });
this._results.next({ origin: this, data: dataWithLayersApplied });
};
Expand Down
Loading