Skip to content

Commit

Permalink
Add onLayoutChange + unsaved changes logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Heenawter committed Oct 30, 2024
1 parent 282bb4d commit 96b3e6a
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 23 deletions.
30 changes: 22 additions & 8 deletions examples/grid_example/public/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import React, { useState } from 'react';
import React, { useMemo, useState } from 'react';
import ReactDOM from 'react-dom';
import { v4 as uuidv4 } from 'uuid';

import {
EuiBadge,
EuiButton,
EuiButtonEmpty,
EuiFlexGroup,
Expand All @@ -22,7 +23,7 @@ import {
} from '@elastic/eui';
import { AppMountParameters } from '@kbn/core-application-browser';
import { CoreStart } from '@kbn/core-lifecycle-browser';
import { GridLayout, type GridLayoutApi } from '@kbn/grid-layout';
import { GridLayout, GridLayoutData, isLayoutEqual, type GridLayoutApi } from '@kbn/grid-layout';
import {
DASHBOARD_GRID_COLUMN_COUNT,
DASHBOARD_GRID_HEIGHT,
Expand All @@ -38,13 +39,19 @@ import {
export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => {
const [layoutKey, setLayoutKey] = useState<string>(uuidv4());
const [gridLayoutApi, setGridLayoutApi] = useState<GridLayoutApi | null>();
const [savedLayout, setSavedLayout] = useState<GridLayoutData>(getSerializedGridLayout());
const [currentLayout, setCurrentLayout] = useState<GridLayoutData>(savedLayout);

const hasUnsavedChanges = useMemo(() => {
return !isLayoutEqual(savedLayout, currentLayout);
}, [savedLayout, currentLayout]);

return (
<EuiProvider>
<EuiPageTemplate grow={false} offset={0} restrictWidth={false}>
<EuiPageTemplate.Header iconType={'dashboardApp'} pageTitle="Grid Layout Example" />
<EuiPageTemplate.Section color="subdued">
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center">
<EuiFlexItem grow={false}>
<EuiButton
onClick={async () => {
Expand All @@ -59,11 +66,17 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => {
</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="xs">
<EuiFlexGroup gutterSize="xs" alignItems="center">
{hasUnsavedChanges && (
<EuiFlexItem grow={false}>
<EuiBadge color="warning">Unsaved changes</EuiBadge>
</EuiFlexItem>
)}
<EuiFlexItem grow={false}>
<EuiButtonEmpty
onClick={() => {
clearSerializedGridLayout();
setCurrentLayout(savedLayout);
setLayoutKey(uuidv4()); // force remount of grid
}}
>
Expand All @@ -74,7 +87,9 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => {
<EuiButton
onClick={() => {
if (gridLayoutApi) {
setSerializedGridLayout(gridLayoutApi.serializeState());
const layoutToSave = gridLayoutApi.serializeState();
setSerializedGridLayout(layoutToSave);
setSavedLayout(layoutToSave);
}
}}
>
Expand All @@ -87,7 +102,7 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => {
<EuiSpacer size="m" />
<GridLayout
onLayoutChange={(newLayout) => {
console.log('NEW LAYOUT', newLayout);
setCurrentLayout(newLayout);
}}
key={layoutKey}
ref={setGridLayoutApi}
Expand Down Expand Up @@ -117,14 +132,13 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => {
);
}}
getCreationOptions={() => {
const initialLayout = getSerializedGridLayout();
return {
gridSettings: {
gutterSize: DASHBOARD_MARGIN_SIZE,
rowHeight: DASHBOARD_GRID_HEIGHT,
columnCount: DASHBOARD_GRID_COLUMN_COUNT,
},
initialLayout,
initialLayout: savedLayout,
};
}}
/>
Expand Down
10 changes: 4 additions & 6 deletions packages/kbn-grid-layout/grid/grid_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,7 @@ export const GridLayout = forwardRef<GridLayoutApi, GridLayoutProps>(

useEffect(() => {
const onLayoutChangeSubscription = gridLayoutStateManager.layoutUpdateEvent$
.pipe(
withLatestFrom(gridLayoutStateManager.gridLayout$),
map(([_, layout]) => layout),
pairwise()
)
.pipe(pairwise())
.subscribe(([layoutBefore, layoutAfter]) => {
if (!isLayoutEqual(layoutBefore, layoutAfter)) {
onLayoutChange(layoutAfter);
Expand Down Expand Up @@ -87,7 +83,9 @@ export const GridLayout = forwardRef<GridLayoutApi, GridLayoutProps>(
setInteractionEvent={(nextInteractionEvent) => {
if (!nextInteractionEvent) {
gridLayoutStateManager.activePanel$.next(undefined);
gridLayoutStateManager.layoutUpdateEvent$.next('drop');
gridLayoutStateManager.layoutUpdateEvent$.next(
gridLayoutStateManager.gridLayout$.getValue()
);
}
gridLayoutStateManager.interactionEvent$.next(nextInteractionEvent);
}}
Expand Down
5 changes: 3 additions & 2 deletions packages/kbn-grid-layout/grid/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,14 @@ export interface ActivePanel {
}

export interface GridLayoutStateManager {
gridDimensions$: BehaviorSubject<ObservedSize>;
gridLayout$: BehaviorSubject<GridLayoutData>;

gridDimensions$: BehaviorSubject<ObservedSize>;
runtimeSettings$: BehaviorSubject<RuntimeGridSettings>;
activePanel$: BehaviorSubject<ActivePanel | undefined>;
interactionEvent$: BehaviorSubject<PanelInteractionEvent | undefined>;

layoutUpdateEvent$: BehaviorSubject<'drop' | 'delete' | 'add' | undefined>;
layoutUpdateEvent$: BehaviorSubject<GridLayoutData>;

rowRefs: React.MutableRefObject<Array<HTMLDivElement | null>>;
panelRefs: React.MutableRefObject<Array<{ [id: string]: HTMLDivElement | null }>>;
Expand Down
10 changes: 6 additions & 4 deletions packages/kbn-grid-layout/grid/use_grid_layout_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const useGridLayoutApi = ({
placementStrategy
);
gridLayoutStateManager.gridLayout$.next([nextRow, ...rest]);
gridLayoutStateManager.layoutUpdateEvent$.next('add');
gridLayoutStateManager.layoutUpdateEvent$.next([nextRow, ...rest]);
},

removePanel: (panelId) => {
Expand All @@ -62,18 +62,19 @@ export const useGridLayoutApi = ({
panels: updatedPanels,
});
gridLayoutStateManager.gridLayout$.next(newLayout);
gridLayoutStateManager.layoutUpdateEvent$.next('delete');
gridLayoutStateManager.layoutUpdateEvent$.next(newLayout);
}
},

replacePanel: (oldPanelId, newPanelId) => {
const currentLayout = gridLayoutStateManager.gridLayout$.getValue();
debugger;

// find the row where the panel exists and update its ID to trigger a re-render
let rowIndex = 0;
let updatedPanels;
for (rowIndex; rowIndex < currentLayout.length; rowIndex++) {
const row = currentLayout[rowIndex];
const row = { ...currentLayout[rowIndex] };
if (Object.keys(row.panels).includes(oldPanelId)) {
updatedPanels = { ...row.panels };
const oldPanel = updatedPanels[oldPanelId];
Expand All @@ -82,13 +83,14 @@ export const useGridLayoutApi = ({
break;
}
}
console.log('UPDATE', currentLayout);

// if the panels were updated (i.e. the panel was successfully found and replaced), update the layout
if (updatedPanels) {
const newLayout = [...currentLayout];
newLayout[rowIndex].panels = updatedPanels;
gridLayoutStateManager.gridLayout$.next(newLayout);
gridLayoutStateManager.layoutUpdateEvent$.next('add');
gridLayoutStateManager.layoutUpdateEvent$.next(newLayout);
}
},

Expand Down
4 changes: 1 addition & 3 deletions packages/kbn-grid-layout/grid/use_grid_layout_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ export const useGridLayoutState = ({
const gridLayout$ = new BehaviorSubject<GridLayoutData>(initialLayout);
const gridDimensions$ = new BehaviorSubject<ObservedSize>({ width: 0, height: 0 });
const interactionEvent$ = new BehaviorSubject<PanelInteractionEvent | undefined>(undefined);
const layoutUpdateEvent$ = new BehaviorSubject<'drop' | 'delete' | 'add' | undefined>(
undefined
);
const layoutUpdateEvent$ = new BehaviorSubject<GridLayoutData>(initialLayout);
const activePanel$ = new BehaviorSubject<ActivePanel | undefined>(undefined);
const runtimeSettings$ = new BehaviorSubject<RuntimeGridSettings>({
...gridSettings,
Expand Down
2 changes: 2 additions & 0 deletions packages/kbn-grid-layout/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ export type {
GridRowData,
GridSettings,
} from './grid/types';

export { isLayoutEqual } from './grid/utils/equality_checks';

0 comments on commit 96b3e6a

Please sign in to comment.