mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
DashboardScenes: Row repeater panels cannot be dragged outside and adding new panels to a cloned row updates all rows (#91062)
* Disallow dragging panels in repeated rows + dropping panels into cloned rows will update all repeated rows * test
This commit is contained in:
@@ -67,6 +67,42 @@ describe('RowRepeaterBehavior', () => {
|
||||
expect(gridItem.state.body?.state.key).toBe('canvas-1-clone-B1');
|
||||
});
|
||||
|
||||
it('Should update all rows when a panel is added to a clone', async () => {
|
||||
const originalRow = grid.state.children[1] as SceneGridRow;
|
||||
const clone1 = grid.state.children[2] as SceneGridRow;
|
||||
const clone2 = grid.state.children[3] as SceneGridRow;
|
||||
|
||||
expect(originalRow.state.children.length).toBe(1);
|
||||
expect(clone1.state.children.length).toBe(1);
|
||||
expect(clone2.state.children.length).toBe(1);
|
||||
|
||||
clone1.setState({
|
||||
children: [
|
||||
...clone1.state.children,
|
||||
new SceneGridItem({
|
||||
x: 0,
|
||||
y: 16,
|
||||
width: 24,
|
||||
height: 5,
|
||||
key: 'griditem-4',
|
||||
body: new SceneCanvasText({
|
||||
text: 'new panel',
|
||||
}),
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
grid.forceRender();
|
||||
|
||||
// repeater has run so there are new clone row objects
|
||||
const newClone1 = grid.state.children[2] as SceneGridRow;
|
||||
const newClone2 = grid.state.children[3] as SceneGridRow;
|
||||
|
||||
expect(originalRow.state.children.length).toBe(2);
|
||||
expect(newClone1.state.children.length).toBe(2);
|
||||
expect(newClone2.state.children.length).toBe(2);
|
||||
});
|
||||
|
||||
it('Should push row at the bottom down', () => {
|
||||
// Should push row at the bottom down
|
||||
const rowAtTheBottom = grid.state.children[6] as SceneGridRow;
|
||||
|
||||
@@ -46,6 +46,48 @@ export class RowRepeaterBehavior extends SceneObjectBase<RowRepeaterBehaviorStat
|
||||
|
||||
private _activationHandler() {
|
||||
this.performRepeat();
|
||||
|
||||
const layout = this._getLayout();
|
||||
const originalRow = this._getRow();
|
||||
const filterKey = originalRow.state.key + '-clone-';
|
||||
|
||||
const sub = layout.subscribeToState(() => {
|
||||
const repeatedRows = layout.state.children.filter(
|
||||
(child) => child instanceof SceneGridRow && child.state.key?.includes(filterKey)
|
||||
);
|
||||
|
||||
// go through cloned rows, search for panels that are not clones
|
||||
for (const row of repeatedRows) {
|
||||
if (!(row instanceof SceneGridRow)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if no differences in row children compared to original, then no new panel added to clone
|
||||
if (row.state.children.length === originalRow.state.children.length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//if there are differences, find the new panel, move it to the original and perform re peat
|
||||
const gridItem = row.state.children.find((gridItem) => !gridItem.state.key?.includes('clone'));
|
||||
if (gridItem) {
|
||||
const newGridItem = gridItem.clone();
|
||||
row.setState({ children: row.state.children.filter((item) => item !== gridItem) });
|
||||
|
||||
// if we are moving a panel from the origin row to a clone row, we just return
|
||||
// this means we are modifying the origin row, retriggering the repeat and losing that panel
|
||||
if (originalRow.state.children.find((item) => item.state.key === newGridItem.state.key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
originalRow.setState({ children: [...originalRow.state.children, newGridItem] });
|
||||
this.performRepeat(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
sub.unsubscribe();
|
||||
};
|
||||
}
|
||||
|
||||
private _getRow(): SceneGridRow {
|
||||
@@ -66,7 +108,7 @@ export class RowRepeaterBehavior extends SceneObjectBase<RowRepeaterBehaviorStat
|
||||
return layout;
|
||||
}
|
||||
|
||||
public performRepeat() {
|
||||
public performRepeat(force = false) {
|
||||
this.isWaitingForVariables = this._variableDependency.hasDependencyInLoadingState();
|
||||
|
||||
if (this.isWaitingForVariables) {
|
||||
@@ -95,7 +137,7 @@ export class RowRepeaterBehavior extends SceneObjectBase<RowRepeaterBehaviorStat
|
||||
const { values, texts } = getMultiVariableValues(variable);
|
||||
|
||||
// Do nothing if values are the same
|
||||
if (isEqual(this._prevRepeatValues, values)) {
|
||||
if (isEqual(this._prevRepeatValues, values) && !force) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -134,7 +176,12 @@ export class RowRepeaterBehavior extends SceneObjectBase<RowRepeaterBehaviorStat
|
||||
if (index > 0) {
|
||||
ensureUniqueKeys(itemClone, localValue);
|
||||
|
||||
//disallow clones to be dragged around or out of the row
|
||||
if (itemClone instanceof DashboardGridItem) {
|
||||
itemClone.setState({
|
||||
isDraggable: false,
|
||||
});
|
||||
|
||||
itemClone.state.body.setState({
|
||||
menu: new VizPanelMenu({
|
||||
$behaviors: [repeatPanelMenuBehavior],
|
||||
|
||||
Reference in New Issue
Block a user