mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[kbn-grid-layout] Allow rows to be reordered (#213166)
Closes https://github.com/elastic/kibana/issues/190381 ## Summary This PR adds the ability to drag and drop rows by their headers in order to reorder them:  It can be a bit confusing dragging section headers around when other sections are expanded - it is easy to lose track of them, especially when the expanded sections are very large. I experimented with auto-collapsing all sections on drag, but this felt extremely disorienting because you instantly lost all of your context - so, to improve the UI here, I added a "scroll to" effect on drop like so: https://github.com/user-attachments/assets/0b519783-a4f5-4590-9a1c-580df66a2f66 Reminder that, to test this feature, you need to run Kibana with examples via `yarn start --run-examples` and navigate to the grid examples app via `Analytics > Developer examples > Grid Example`. ### 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) ### Identify risks Collapsible sections are not available on Dashboard yet and so there is no user-facing risk to this PR.
This commit is contained in:
parent
24de20fe9b
commit
05db9e9597
26 changed files with 686 additions and 203 deletions
|
@ -23,8 +23,8 @@ import {
|
|||
EuiFlexItem,
|
||||
EuiPageTemplate,
|
||||
EuiSpacer,
|
||||
UseEuiTheme,
|
||||
transparentize,
|
||||
useEuiTheme,
|
||||
} from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import { AppMountParameters } from '@kbn/core-application-browser';
|
||||
|
@ -58,8 +58,6 @@ export const GridExample = ({
|
|||
coreStart: CoreStart;
|
||||
uiActions: UiActionsStart;
|
||||
}) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
|
||||
const savedState = useRef<MockSerializedDashboardState>(getSerializedDashboardState());
|
||||
const [hasUnsavedChanges, setHasUnsavedChanges] = useState<boolean>(false);
|
||||
const [currentLayout, setCurrentLayout] = useState<GridLayoutData>(
|
||||
|
@ -90,8 +88,8 @@ export const GridExample = ({
|
|||
const currentPanel = panels[panelId];
|
||||
const savedPanel = savedState.current.panels[panelId];
|
||||
panelsAreEqual = deepEqual(
|
||||
{ row: 'first', ...currentPanel.gridData },
|
||||
{ row: 'first', ...savedPanel.gridData }
|
||||
{ row: 'first', ...currentPanel?.gridData },
|
||||
{ row: 'first', ...savedPanel?.gridData }
|
||||
);
|
||||
}
|
||||
const hasChanges = !(panelsAreEqual && deepEqual(rows, savedState.current.rows));
|
||||
|
@ -173,41 +171,6 @@ export const GridExample = ({
|
|||
mockDashboardApi.rows$.next(rows);
|
||||
}, [mockDashboardApi.panels$, mockDashboardApi.rows$]);
|
||||
|
||||
const customLayoutCss = useMemo(() => {
|
||||
const gridColor = transparentize(euiTheme.colors.backgroundFilledAccentSecondary, 0.2);
|
||||
return css`
|
||||
.kbnGridRow--targeted {
|
||||
background-position: top calc((var(--kbnGridGutterSize) / 2) * -1px) left
|
||||
calc((var(--kbnGridGutterSize) / 2) * -1px);
|
||||
background-size: calc((var(--kbnGridColumnWidth) + var(--kbnGridGutterSize)) * 1px)
|
||||
calc((var(--kbnGridRowHeight) + var(--kbnGridGutterSize)) * 1px);
|
||||
background-image: linear-gradient(to right, ${gridColor} 1px, transparent 1px),
|
||||
linear-gradient(to bottom, ${gridColor} 1px, transparent 1px);
|
||||
background-color: ${transparentize(euiTheme.colors.backgroundFilledAccentSecondary, 0.1)};
|
||||
}
|
||||
|
||||
.kbnGridPanel--dragPreview {
|
||||
border-radius: ${euiTheme.border.radius};
|
||||
background-color: ${transparentize(euiTheme.colors.backgroundFilledAccentSecondary, 0.2)};
|
||||
transition: opacity 100ms linear;
|
||||
}
|
||||
|
||||
.kbnGridPanel--resizeHandle {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s, border 0.2s;
|
||||
border-radius: 7px 0 7px 0;
|
||||
border-bottom: 2px solid ${euiTheme.colors.accentSecondary};
|
||||
border-right: 2px solid ${euiTheme.colors.accentSecondary};
|
||||
&:hover,
|
||||
&:focus {
|
||||
outline-style: none !important;
|
||||
opacity: 1;
|
||||
background-color: ${transparentize(euiTheme.colors.accentSecondary, 0.05)};
|
||||
}
|
||||
}
|
||||
`;
|
||||
}, [euiTheme]);
|
||||
|
||||
return (
|
||||
<KibanaRenderContextProvider {...coreStart}>
|
||||
<EuiPageTemplate grow={false} offset={0} restrictWidth={false}>
|
||||
|
@ -314,7 +277,7 @@ export const GridExample = ({
|
|||
useCustomDragHandle={true}
|
||||
renderPanelContents={renderPanelContents}
|
||||
onLayoutChange={onLayoutChange}
|
||||
css={customLayoutCss}
|
||||
css={layoutStyles}
|
||||
/>
|
||||
</EuiPageTemplate.Section>
|
||||
</EuiPageTemplate>
|
||||
|
@ -330,3 +293,50 @@ export const renderGridExampleApp = (
|
|||
|
||||
return () => ReactDOM.unmountComponentAtNode(element);
|
||||
};
|
||||
|
||||
const layoutStyles = ({ euiTheme }: UseEuiTheme) => {
|
||||
const gridColor = transparentize(euiTheme.colors.backgroundFilledAccentSecondary, 0.2);
|
||||
return css({
|
||||
// background for grid row that is being targetted
|
||||
'.kbnGridRow--targeted': {
|
||||
backgroundPosition: `top calc((var(--kbnGridGutterSize) / 2) * -1px) left calc((var(--kbnGridGutterSize) / 2) * -1px)`,
|
||||
backgroundSize: `calc((var(--kbnGridColumnWidth) + var(--kbnGridGutterSize)) * 1px) calc((var(--kbnGridRowHeight) + var(--kbnGridGutterSize)) * 1px)`,
|
||||
backgroundImage: `linear-gradient(to right, ${gridColor} 1px, transparent 1px), linear-gradient(to bottom, ${gridColor} 1px, transparent 1px)`,
|
||||
backgroundColor: `${transparentize(euiTheme.colors.backgroundFilledAccentSecondary, 0.1)}`,
|
||||
},
|
||||
// styling for the "locked to grid" preview for what the panel will look like when dropped / resized
|
||||
'.kbnGridPanel--dragPreview': {
|
||||
borderRadius: `${euiTheme.border.radius}`,
|
||||
backgroundColor: `${transparentize(euiTheme.colors.backgroundFilledAccentSecondary, 0.2)}`,
|
||||
transition: `opacity 100ms linear`,
|
||||
},
|
||||
// styling for panel resize handle
|
||||
'.kbnGridPanel--resizeHandle': {
|
||||
opacity: '0',
|
||||
transition: `opacity 0.2s, border 0.2s`,
|
||||
borderRadius: `7px 0 7px 0`,
|
||||
borderBottom: `2px solid ${euiTheme.colors.accentSecondary}`,
|
||||
borderRight: `2px solid ${euiTheme.colors.accentSecondary}`,
|
||||
'&:hover, &:focus': {
|
||||
outlineStyle: `none !important`,
|
||||
opacity: 1,
|
||||
backgroundColor: `${transparentize(euiTheme.colors.accentSecondary, 0.05)}`,
|
||||
},
|
||||
},
|
||||
// styling for what the grid row header looks like when being dragged
|
||||
'.kbnGridRowHeader--active': {
|
||||
backgroundColor: euiTheme.colors.backgroundBasePlain,
|
||||
border: `1px solid ${euiTheme.border.color}`,
|
||||
borderRadius: `${euiTheme.border.radius.medium} ${euiTheme.border.radius.medium}`,
|
||||
paddingLeft: '8px',
|
||||
// hide accordian arrow + panel count text when row is being dragged
|
||||
'& .kbnGridRowTitle--button svg, & .kbnGridLayout--panelCount': {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
// styles for the area where the row will be dropped
|
||||
'.kbnGridPanel--rowDragPreview': {
|
||||
backgroundColor: euiTheme.components.dragDropDraggingBackground,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue