Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Dashboard] [Collapsable Panels] Add embeddable support #198413

Merged
Merged
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
4fbed10
First attempt at using references for drag handles
Heenawter Oct 30, 2024
152e302
Small type cleanup
Heenawter Oct 30, 2024
bb2cb57
Better handling of `onDrop` event
Heenawter Nov 4, 2024
5ee77d8
Fix combined drag action + small cleanup
Heenawter Nov 4, 2024
4202473
Handle remount case on row change
Heenawter Nov 4, 2024
0dace51
Small cleanup
Heenawter Nov 4, 2024
46f30dc
Clean up event listeners to prevent duplication
Heenawter Nov 4, 2024
15856ed
Fix small style bug
Heenawter Nov 5, 2024
d282c9c
Merge branch 'main' of github.com:elastic/kibana into kbn-grid-layout…
Heenawter Nov 5, 2024
bb8d025
Fix merge conflicts
Heenawter Nov 5, 2024
0b2c9f8
Make events passive
Heenawter Nov 7, 2024
8107c4e
Prevent text from being highlighted on drag
Heenawter Nov 7, 2024
ac5a395
Merge branch 'main' of github.com:elastic/kibana into kbn-grid-layout…
Heenawter Nov 7, 2024
0490df2
Merge branch 'main' of github.com:elastic/kibana into kbn-grid-layout…
Heenawter Nov 27, 2024
22a5244
Fix merge conflicts
Heenawter Nov 27, 2024
e8ca538
Reduce re-rendering
Heenawter Nov 28, 2024
440cc95
Load sample dashboard
Heenawter Nov 28, 2024
7a0f43f
Fix loss of data
Heenawter Nov 28, 2024
99917f6
Add ease at top and bottom
Heenawter Nov 28, 2024
cfabaa6
Make ease smoother
Heenawter Nov 29, 2024
758289a
Small cleanup of ease
Heenawter Nov 29, 2024
8fea110
Do some more code cleanup
Heenawter Nov 29, 2024
441bf76
Merge branch 'main' of github.com:elastic/kibana into kbn-grid-layout…
Heenawter Nov 29, 2024
43d36c5
Fix merge conflicts
Heenawter Nov 29, 2024
f046009
Make maximize panels work
Heenawter Nov 29, 2024
5a942cb
Fix gutter size
Heenawter Nov 29, 2024
8cca8dd
[CI] Auto-commit changed files from 'node scripts/notice'
kibanamachine Nov 29, 2024
2eee1e1
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Nov 29, 2024
b70d189
Fix styling of expanding panels - v2
Heenawter Nov 30, 2024
dae36e2
Merge branch 'kbn-grid-layout_embeddable-support_2024-10-30' of githu…
Heenawter Nov 30, 2024
aa3ee07
Make add panel work
Heenawter Dec 2, 2024
baec31c
Re-use add button
Heenawter Dec 2, 2024
57f4cd7
Clean up drag handles
Heenawter Dec 2, 2024
2d9e40a
Make drag handles respond to access mode changes
Heenawter Dec 2, 2024
4dbe124
True fix for drag handles
Heenawter Dec 2, 2024
875a7c3
Do some cleanup
Heenawter Dec 4, 2024
02c649b
Merge branch 'main' of github.com:elastic/kibana into kbn-grid-layout…
Heenawter Dec 5, 2024
adc5014
Fix merge conflicts
Heenawter Dec 5, 2024
5d90fa1
Move custom drag handle logic to drag handle component
Heenawter Dec 5, 2024
4e021f2
Make set drag handles optional
Heenawter Dec 5, 2024
0e248e1
Do some more cleanup
Heenawter Dec 5, 2024
f55edf3
More more cleanup
Heenawter Dec 6, 2024
fe13a60
[CI] Auto-commit changed files from 'node scripts/notice'
kibanamachine Dec 6, 2024
89699d1
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Dec 6, 2024
4c9e395
Fix types
Heenawter Dec 6, 2024
5393529
Merge branch 'kbn-grid-layout_embeddable-support_2024-10-30' of githu…
Heenawter Dec 6, 2024
fc22f3c
Fix more types + additional cleanup
Heenawter Dec 6, 2024
64b193d
More more more cleanup
Heenawter Dec 6, 2024
5319aa8
Remove missed console log
Heenawter Dec 6, 2024
91f28d3
Fix failing test
Heenawter Dec 6, 2024
585ec5d
Merge branch 'main' into kbn-grid-layout_embeddable-support_2024-10-30
Heenawter Dec 6, 2024
fb587c1
Merge branch 'main' into kbn-grid-layout_embeddable-support_2024-10-30
Heenawter Dec 9, 2024
1d9fe66
Merge branch 'main' into kbn-grid-layout_embeddable-support_2024-10-30
Heenawter Dec 9, 2024
4bc0f55
Merge branch 'main' into kbn-grid-layout_embeddable-support_2024-10-30
Heenawter Dec 9, 2024
bcc4046
Merge branch 'main' into kbn-grid-layout_embeddable-support_2024-10-30
Heenawter Dec 10, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
import React, { ReactElement, useEffect, useState } from 'react';
import { EuiButton, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui';
import { ADD_PANEL_TRIGGER, UiActionsStart } from '@kbn/ui-actions-plugin/public';
import { PageApi } from '../types';

export function AddButton({ pageApi, uiActions }: { pageApi: PageApi; uiActions: UiActionsStart }) {
export function AddButton({ pageApi, uiActions }: { pageApi: unknown; uiActions: UiActionsStart }) {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const [items, setItems] = useState<ReactElement[]>([]);

Expand Down Expand Up @@ -73,7 +72,7 @@ export function AddButton({ pageApi, uiActions }: { pageApi: PageApi; uiActions:
setIsPopoverOpen(!isPopoverOpen);
}}
>
Add
Add panel
</EuiButton>
}
isOpen={isPopoverOpen}
Expand Down
2 changes: 2 additions & 0 deletions examples/embeddable_examples/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@

import { EmbeddableExamplesPlugin } from './plugin';

export { AddButton as AddEmbeddableButton } from './app/presentation_container_example/components/add_button';

export const plugin = () => new EmbeddableExamplesPlugin();
2 changes: 1 addition & 1 deletion examples/grid_example/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"id": "gridExample",
"server": false,
"browser": true,
"requiredPlugins": ["developerExamples"],
"requiredPlugins": ["developerExamples", "embeddable", "uiActions", "embeddableExamples"],
"requiredBundles": []
}
}
140 changes: 59 additions & 81 deletions examples/grid_example/public/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,28 @@ import deepEqual from 'fast-deep-equal';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import ReactDOM from 'react-dom';
import { combineLatest, debounceTime } from 'rxjs';
import { v4 as uuidv4 } from 'uuid';

import {
EuiBadge,
EuiButton,
EuiButtonEmpty,
EuiButtonGroup,
EuiCallOut,
EuiFlexGroup,
EuiFlexItem,
EuiPageTemplate,
EuiProvider,
EuiSpacer,
EuiButtonGroup,
EuiButtonIcon,
} from '@elastic/eui';
import { AppMountParameters } from '@kbn/core-application-browser';
import { CoreStart } from '@kbn/core-lifecycle-browser';
import { GridLayout, GridLayoutData, GridAccessMode } from '@kbn/grid-layout';
import { AddEmbeddableButton } from '@kbn/embeddable-examples-plugin/public';
import { ReactEmbeddableRenderer } from '@kbn/embeddable-plugin/public';
import { GridLayout, GridLayoutData } from '@kbn/grid-layout';
import { i18n } from '@kbn/i18n';
import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
import { UiActionsStart } from '@kbn/ui-actions-plugin/public';

import { getPanelId } from './get_panel_id';
import {
clearSerializedDashboardState,
getSerializedDashboardState,
Expand All @@ -45,82 +46,69 @@ const DASHBOARD_MARGIN_SIZE = 8;
const DASHBOARD_GRID_HEIGHT = 20;
const DASHBOARD_GRID_COLUMN_COUNT = 48;

export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => {
export const GridExample = ({
coreStart,
uiActions,
}: {
coreStart: CoreStart;
uiActions: UiActionsStart;
}) => {
const savedState = useRef<MockSerializedDashboardState>(getSerializedDashboardState());
const [hasUnsavedChanges, setHasUnsavedChanges] = useState<boolean>(false);
const [expandedPanelId, setExpandedPanelId] = useState<string | undefined>();
const [accessMode, setAccessMode] = useState<GridAccessMode>('EDIT');
const [currentLayout, setCurrentLayout] = useState<GridLayoutData>(
dashboardInputToGridLayout(savedState.current)
);

const mockDashboardApi = useMockDashboardApi({ savedState: savedState.current });
const [viewMode, expandedPanelId] = useBatchedPublishingSubjects(
mockDashboardApi.viewMode,
mockDashboardApi.expandedPanelId
);

useEffect(() => {
combineLatest([mockDashboardApi.panels$, mockDashboardApi.rows$])
.pipe(debounceTime(0)) // debounce to avoid subscribe being called twice when both panels$ and rows$ publish
.subscribe(([panels, rows]) => {
const hasChanges = !(
deepEqual(panels, savedState.current.panels) && deepEqual(rows, savedState.current.rows)
deepEqual(
Object.values(panels).map(({ gridData }) => ({ row: 0, ...gridData })),
Object.values(savedState.current.panels).map(({ gridData }) => ({
row: 0, // if row is undefined, then default to 0
...gridData,
}))
) && deepEqual(rows, savedState.current.rows)
);
setHasUnsavedChanges(hasChanges);
setCurrentLayout(dashboardInputToGridLayout({ panels, rows }));
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const renderBasicPanel = useCallback(
(id: string) => {
const renderPanelContents = useCallback(
(id: string, setDragHandles?: (refs: Array<HTMLElement | null>) => void) => {
const currentPanels = mockDashboardApi.panels$.getValue();

return (
<>
<div style={{ padding: 8 }}>{id}</div>
<EuiButtonEmpty
onClick={() => {
setExpandedPanelId(undefined);
mockDashboardApi.removePanel(id);
}}
>
{i18n.translate('examples.gridExample.deletePanelButton', {
defaultMessage: 'Delete panel',
})}
</EuiButtonEmpty>
<EuiButtonEmpty
onClick={async () => {
setExpandedPanelId(undefined);
const newPanelId = await getPanelId({
coreStart,
suggestion: id,
});
if (newPanelId) mockDashboardApi.replacePanel(id, newPanelId);
}}
>
{i18n.translate('examples.gridExample.replacePanelButton', {
defaultMessage: 'Replace panel',
})}
</EuiButtonEmpty>
<EuiButtonIcon
iconType={expandedPanelId ? 'minimize' : 'expand'}
onClick={() => setExpandedPanelId((expandedId) => (expandedId ? undefined : id))}
aria-label={
expandedPanelId
? i18n.translate('examples.gridExample.minimizePanel', {
defaultMessage: 'Minimize panel {id}',
values: { id },
})
: i18n.translate('examples.gridExample.maximizePanel', {
defaultMessage: 'Maximize panel {id}',
values: { id },
})
}
/>
</>
<ReactEmbeddableRenderer
key={id}
maybeId={id}
type={currentPanels[id].type}
getParentApi={() => mockDashboardApi}
panelProps={{
showBadges: true,
showBorder: true,
showNotifications: true,
showShadow: false,
setDragHandles,
}}
/>
);
},
[coreStart, mockDashboardApi, setExpandedPanelId, expandedPanelId]
[mockDashboardApi]
);

return (
<EuiProvider>
<KibanaRenderContextProvider {...coreStart}>
<EuiPageTemplate grow={false} offset={0} restrictWidth={false}>
<EuiPageTemplate.Header
iconType={'dashboardApp'}
Expand All @@ -131,7 +119,7 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => {
<EuiPageTemplate.Section
color="subdued"
contentProps={{
css: { display: 'flex', flexFlow: 'column nowrap', flexGrow: 1 },
css: { flexGrow: 1 },
Heenawter marked this conversation as resolved.
Show resolved Hide resolved
}}
>
<EuiCallOut
Expand All @@ -156,20 +144,7 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => {
<EuiSpacer size="m" />
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center">
<EuiFlexItem grow={false}>
<EuiButton
onClick={async () => {
setExpandedPanelId(undefined);
const panelId = await getPanelId({
coreStart,
suggestion: uuidv4(),
});
if (panelId) mockDashboardApi.addNewPanel({ id: panelId });
}}
>
{i18n.translate('examples.gridExample.addPanelButton', {
defaultMessage: 'Add a panel',
})}
</EuiButton>
<AddEmbeddableButton pageApi={mockDashboardApi} uiActions={uiActions} />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="xs" alignItems="center">
Expand All @@ -180,24 +155,24 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => {
})}
options={[
{
id: 'VIEW',
id: 'view',
nickpeihl marked this conversation as resolved.
Show resolved Hide resolved
label: i18n.translate('examples.gridExample.viewOption', {
defaultMessage: 'View',
}),
toolTipContent:
'The layout adjusts when the window is resized. Panel interactivity, such as moving and resizing within the grid, is disabled.',
},
{
id: 'EDIT',
id: 'edit',
label: i18n.translate('examples.gridExample.editOption', {
defaultMessage: 'Edit',
}),
toolTipContent: 'The layout does not adjust when the window is resized.',
},
]}
idSelected={accessMode}
idSelected={viewMode}
onChange={(id) => {
setAccessMode(id as GridAccessMode);
mockDashboardApi.viewMode.next(id);
}}
/>
</EuiFlexItem>
Expand Down Expand Up @@ -245,32 +220,35 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => {
</EuiFlexGroup>
<EuiSpacer size="m" />
<GridLayout
accessMode={accessMode}
accessMode={viewMode === 'view' ? 'VIEW' : 'EDIT'}
expandedPanelId={expandedPanelId}
layout={currentLayout}
gridSettings={{
gutterSize: DASHBOARD_MARGIN_SIZE,
rowHeight: DASHBOARD_GRID_HEIGHT,
columnCount: DASHBOARD_GRID_COLUMN_COUNT,
}}
renderPanelContents={renderBasicPanel}
renderPanelContents={renderPanelContents}
onLayoutChange={(newLayout) => {
const { panels, rows } = gridLayoutToDashboardPanelMap(newLayout);
const { panels, rows } = gridLayoutToDashboardPanelMap(
mockDashboardApi.panels$.getValue(),
newLayout
);
mockDashboardApi.panels$.next(panels);
mockDashboardApi.rows$.next(rows);
}}
/>
</EuiPageTemplate.Section>
</EuiPageTemplate>
</EuiProvider>
</KibanaRenderContextProvider>
);
};

export const renderGridExampleApp = (
element: AppMountParameters['element'],
coreStart: CoreStart
deps: { uiActions: UiActionsStart; coreStart: CoreStart }
) => {
ReactDOM.render(<GridExample coreStart={coreStart} />, element);
ReactDOM.render(<GridExample {...deps} />, element);

return () => ReactDOM.unmountComponentAtNode(element);
};
Loading