Files
grafana/public/app/features/dashboard-scene/scene/layout-default/SceneGridRowEditableElement.tsx
Torkel Ödegaard c63a52958d RowsLayout: Rethinking row repeats (#104312)
* Something is working

* Update

* Update

* working

* clear repeated rows

* Update

* Update

* Outline via function

* Update

* Update

* Update

* Progress

* Update

* Udpate sum

* Update

* Update public/app/features/dashboard-scene/scene/types/EditableDashboardElement.ts

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/features/dashboard-scene/edit-pane/DashboardOutline.tsx

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/features/dashboard-scene/edit-pane/DashboardOutline.tsx

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridLayoutManager.tsx

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/features/dashboard-scene/scene/layout-default/DefaultGridLayoutManager.tsx

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Update

* more tests

* Update

* Update

* Removed old behavior

* Update

* Update

* Update

* fix outline for default grid

* Update

---------

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
2025-06-25 10:02:42 +02:00

146 lines
5.5 KiB
TypeScript

import { useMemo } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { Trans, t } from '@grafana/i18n';
import { sceneGraph, SceneGridRow, VizPanel } from '@grafana/scenes';
import { Alert, Input, TextLink } from '@grafana/ui';
import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor';
import { OptionsPaneItemDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor';
import { RepeatRowSelect2 } from 'app/features/dashboard/components/RepeatRowSelect/RepeatRowSelect';
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard/constants';
import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
import { getDashboardSceneFor, getLayoutManagerFor, getQueryRunnerFor } from '../../utils/utils';
import { DashboardScene } from '../DashboardScene';
import { BulkActionElement } from '../types/BulkActionElement';
import { EditableDashboardElement, EditableDashboardElementInfo } from '../types/EditableDashboardElement';
import { DefaultGridLayoutManager } from './DefaultGridLayoutManager';
import { RowRepeaterBehavior } from './RowRepeaterBehavior';
export class SceneGridRowEditableElement implements EditableDashboardElement, BulkActionElement {
public readonly isEditableDashboardElement = true;
public constructor(private _row: SceneGridRow) {}
public getEditableElementInfo(): EditableDashboardElementInfo {
return {
typeName: t('dashboard.edit-pane.elements.row', 'Row'),
instanceName: sceneGraph.interpolate(this._row, this._row.state.title, undefined, 'text'),
icon: 'list-ul',
};
}
public getOutlineChildren() {
return this._row.state.children;
}
public useEditPaneOptions(): OptionsPaneCategoryDescriptor[] {
const row = this._row;
const rowOptions = useMemo(() => {
return new OptionsPaneCategoryDescriptor({
title: t('dashboard.default-layout.row-options.title', 'Row options'),
id: 'row-options',
isOpenDefault: true,
}).addItem(
new OptionsPaneItemDescriptor({
title: t('dashboard.default-layout.row-options.form.title', 'Title'),
render: () => <RowTitleInput row={row} />,
})
);
}, [row]);
const rowRepeatOptions = useMemo(() => {
const dashboard = getDashboardSceneFor(row);
return new OptionsPaneCategoryDescriptor({
title: t('dashboard.default-layout.row-options.repeat.title', 'Repeat options'),
id: 'row-repeat-options',
isOpenDefault: true,
}).addItem(
new OptionsPaneItemDescriptor({
title: t('dashboard.default-layout.row-options.repeat.variable.title', 'Variable'),
render: () => <RowRepeatSelect row={row} dashboard={dashboard} />,
})
);
}, [row]);
return [rowOptions, rowRepeatOptions];
}
public onDelete() {
const layoutManager = getLayoutManagerFor(this._row);
if (layoutManager instanceof DefaultGridLayoutManager) {
layoutManager.removeRow(this._row);
}
}
}
function RowTitleInput({ row }: { row: SceneGridRow }) {
const { title } = row.useState();
return <Input value={title} onChange={(e) => row.setState({ title: e.currentTarget.value })} />;
}
function RowRepeatSelect({ row, dashboard }: { row: SceneGridRow; dashboard: DashboardScene }) {
const { $behaviors, children } = row.useState();
let repeatBehavior = $behaviors?.find((b) => b instanceof RowRepeaterBehavior);
const vizPanels = useMemo(
() => children.reduce<VizPanel[]>((acc, child) => [...acc, ...sceneGraph.findDescendents(child, VizPanel)], []),
[children]
);
const isAnyPanelUsingDashboardDS = vizPanels.some((vizPanel) => {
const runner = getQueryRunnerFor(vizPanel);
return (
runner?.state.datasource?.uid === SHARED_DASHBOARD_QUERY ||
(runner?.state.datasource?.uid === MIXED_DATASOURCE_NAME &&
runner?.state.queries.some((query) => query.datasource?.uid === SHARED_DASHBOARD_QUERY))
);
});
return (
<>
<RepeatRowSelect2
sceneContext={dashboard}
repeat={repeatBehavior?.state.variableName}
onChange={(repeat) => {
if (repeat) {
repeatBehavior?.removeBehavior();
repeatBehavior = new RowRepeaterBehavior({ variableName: repeat });
row.setState({ $behaviors: [...(row.state.$behaviors ?? []), repeatBehavior] });
} else {
repeatBehavior?.removeBehavior();
}
}}
/>
{isAnyPanelUsingDashboardDS ? (
<Alert
data-testid={selectors.pages.Dashboard.Rows.Repeated.ConfigSection.warningMessage}
severity="warning"
title=""
topSpacing={3}
bottomSpacing={0}
>
<p>
<Trans i18nKey="dashboard.default-layout.row-options.form.repeat-for.warning.text">
Panels in this row use the {{ SHARED_DASHBOARD_QUERY }} data source. These panels will reference the panel
in the original row, not the ones in the repeated rows.
</Trans>
</p>
<TextLink
external
href={
'https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/create-dashboard/#configure-repeating-rows'
}
>
<Trans i18nKey="dashboard.default-layout.row-options.form.repeat-for.learn-more">Learn more</Trans>
</TextLink>
</Alert>
) : undefined}
</>
);
}