kibana/examples/grid_example/public/utils.ts
Hannah Mudge b32f0fe1e8
[kbn-grid-layout] Store rows in object instead of array (#212965)
Closes https://github.com/elastic/kibana/issues/211930

## Summary

This PR makes it so that `kbn-grid-layout` stores its rows as an object
/ dictionary (`{ [key: string]: GridRowData }`) rather than an array
(`Array<GridRowData>`). This is a prerequisite for
https://github.com/elastic/kibana/issues/190381 , since it allows us to
re-order rows without re-rendering their contents. It also means that
deleting a row will no longer cause the rows below it to re-render,
since re-rendering is now dependant on the row's **ID** rather than the
row's order.

**Before**


https://github.com/user-attachments/assets/83651b24-a32c-4953-8ad5-c0eced163eb5


**After**


https://github.com/user-attachments/assets/9cef6dbc-3d62-46aa-bc40-ab24fc4e5556


### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
2025-03-04 13:34:39 -07:00

68 lines
2.1 KiB
TypeScript

/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { GridLayoutData } from '@kbn/grid-layout';
import { MockedDashboardPanelMap, MockedDashboardRowMap } from './types';
export const gridLayoutToDashboardPanelMap = (
panelState: MockedDashboardPanelMap,
layout: GridLayoutData
): { panels: MockedDashboardPanelMap; rows: MockedDashboardRowMap } => {
const panels: MockedDashboardPanelMap = {};
const rows: MockedDashboardRowMap = {};
Object.entries(layout).forEach(([rowId, row]) => {
const { panels: rowPanels, isCollapsed, ...rest } = row; // drop panels
rows[rowId] = { ...rest, collapsed: isCollapsed };
Object.values(rowPanels).forEach((panelGridData) => {
panels[panelGridData.id] = {
...panelState[panelGridData.id],
gridData: {
i: panelGridData.id,
y: panelGridData.row,
x: panelGridData.column,
w: panelGridData.width,
h: panelGridData.height,
row: rowId,
},
};
});
});
return { panels, rows };
};
export const dashboardInputToGridLayout = ({
panels,
rows,
}: {
panels: MockedDashboardPanelMap;
rows: MockedDashboardRowMap;
}): GridLayoutData => {
const layout: GridLayoutData = {};
Object.values(rows).forEach((row) => {
const { collapsed, ...rest } = row;
layout[row.id] = {
...rest,
panels: {},
isCollapsed: collapsed,
};
});
Object.keys(panels).forEach((panelId) => {
const gridData = panels[panelId].gridData;
layout[gridData.row ?? 'first'].panels[panelId] = {
id: panelId,
row: gridData.y,
column: gridData.x,
width: gridData.w,
height: gridData.h,
};
});
return layout;
};