[DASHBOARDS] Add the ability to click to create a widget (#16673)
## Video QA https://github.com/user-attachments/assets/813a2040-6ee9-418c-b7da-1126c9720446
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
PAGE_LAYOUT_CONFIG,
|
||||
type PageLayoutBreakpoint,
|
||||
} from '@/page-layout/constants/PageLayoutBreakpoints';
|
||||
import { PAGE_LAYOUT_GRID_ITEM_Z_INDEX } from '@/page-layout/constants/PageLayoutGridItemZIndex';
|
||||
import { PAGE_LAYOUT_GRID_MARGIN } from '@/page-layout/constants/PageLayoutGridMargin';
|
||||
import { PAGE_LAYOUT_GRID_ROW_HEIGHT } from '@/page-layout/constants/PageLayoutGridRowHeight';
|
||||
import { usePageLayoutHandleLayoutChange } from '@/page-layout/hooks/usePageLayoutHandleLayoutChange';
|
||||
@@ -54,6 +55,10 @@ const StyledGridContainer = styled.div`
|
||||
user-select: auto;
|
||||
}
|
||||
|
||||
.react-grid-item {
|
||||
z-index: ${PAGE_LAYOUT_GRID_ITEM_Z_INDEX};
|
||||
}
|
||||
|
||||
.react-grid-item:hover .widget-card-resize-handle {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { type PageLayoutBreakpoint } from '@/page-layout/constants/PageLayoutBreakpoints';
|
||||
import { PAGE_LAYOUT_GRID_OVERLAY_Z_INDEX } from '@/page-layout/constants/PageLayoutGridOverlayZIndex';
|
||||
import { useCreateWidgetFromClick } from '@/page-layout/hooks/useCreateWidgetFromClick';
|
||||
import { pageLayoutCurrentBreakpointComponentState } from '@/page-layout/states/pageLayoutCurrentBreakpointComponentState';
|
||||
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
|
||||
import { pageLayoutSelectedCellsComponentState } from '@/page-layout/states/pageLayoutSelectedCellsComponentState';
|
||||
@@ -26,7 +28,7 @@ const StyledGridOverlay = styled.div<{
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
pointer-events: ${({ isDragSelecting }) =>
|
||||
isDragSelecting ? 'auto' : 'none'};
|
||||
z-index: 0;
|
||||
z-index: ${PAGE_LAYOUT_GRID_OVERLAY_Z_INDEX};
|
||||
`;
|
||||
|
||||
const StyledGridCell = styled.div<{ isSelected?: boolean }>`
|
||||
@@ -36,6 +38,7 @@ const StyledGridCell = styled.div<{ isSelected?: boolean }>`
|
||||
${({ theme, isSelected }) =>
|
||||
isSelected ? theme.color.blue7 : theme.border.color.light};
|
||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
@@ -59,6 +62,8 @@ export const PageLayoutGridOverlay = () => {
|
||||
|
||||
const activeTabId = useRecoilComponentValue(activeTabIdComponentState);
|
||||
|
||||
const { createWidgetFromClick } = useCreateWidgetFromClick();
|
||||
|
||||
const numberOfRows = useMemo(() => {
|
||||
const currentTabLayouts = pageLayoutCurrentLayouts[activeTabId ?? ''] || {
|
||||
desktop: [],
|
||||
@@ -92,6 +97,7 @@ export const PageLayoutGridOverlay = () => {
|
||||
key={i}
|
||||
data-selectable-id={cellId}
|
||||
isSelected={pageLayoutSelectedCells.has(cellId)}
|
||||
onClick={() => createWidgetFromClick(cellId)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export const PAGE_LAYOUT_GRID_ITEM_Z_INDEX = 2;
|
||||
@@ -0,0 +1 @@
|
||||
export const PAGE_LAYOUT_GRID_OVERLAY_Z_INDEX = 1;
|
||||
@@ -8,6 +8,6 @@ export const WIDGET_SIZES: Partial<Record<WidgetType, WidgetSizeConfig>> = {
|
||||
},
|
||||
[WidgetType.STANDALONE_RICH_TEXT]: {
|
||||
default: { w: 4, h: 4 },
|
||||
minimum: { w: 1, h: 1 },
|
||||
minimum: { w: 2, h: 2 },
|
||||
},
|
||||
};
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
import { useNavigatePageLayoutCommandMenu } from '@/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import { type ReactNode } from 'react';
|
||||
import { pageLayoutDraggedAreaComponentState } from '../../states/pageLayoutDraggedAreaComponentState';
|
||||
import { pageLayoutEditingWidgetIdComponentState } from '../../states/pageLayoutEditingWidgetIdComponentState';
|
||||
import { useCreateWidgetFromClick } from '../useCreateWidgetFromClick';
|
||||
import {
|
||||
PAGE_LAYOUT_TEST_INSTANCE_ID,
|
||||
PageLayoutTestWrapper,
|
||||
} from './PageLayoutTestWrapper';
|
||||
|
||||
jest.mock(
|
||||
'@/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu',
|
||||
);
|
||||
|
||||
describe('useCreateWidgetFromClick', () => {
|
||||
const mockNavigatePageLayoutCommandMenu = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
(useNavigatePageLayoutCommandMenu as jest.Mock).mockReturnValue({
|
||||
navigatePageLayoutCommandMenu: mockNavigatePageLayoutCommandMenu,
|
||||
});
|
||||
});
|
||||
|
||||
it('should set dragged area and navigate to widget selection when called with a cellId', () => {
|
||||
const { result } = renderHook(
|
||||
() => ({
|
||||
createWidget: useCreateWidgetFromClick(),
|
||||
draggedArea: useRecoilComponentValue(
|
||||
pageLayoutDraggedAreaComponentState,
|
||||
PAGE_LAYOUT_TEST_INSTANCE_ID,
|
||||
),
|
||||
editingWidgetId: useRecoilComponentValue(
|
||||
pageLayoutEditingWidgetIdComponentState,
|
||||
PAGE_LAYOUT_TEST_INSTANCE_ID,
|
||||
),
|
||||
}),
|
||||
{
|
||||
wrapper: ({ children }: { children: ReactNode }) => (
|
||||
<PageLayoutTestWrapper>{children}</PageLayoutTestWrapper>
|
||||
),
|
||||
},
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.createWidget.createWidgetFromClick('cell-2-3');
|
||||
});
|
||||
|
||||
expect(result.current.draggedArea).toEqual({ x: 2, y: 3, w: 1, h: 1 });
|
||||
expect(result.current.editingWidgetId).toBeNull();
|
||||
expect(mockNavigatePageLayoutCommandMenu).toHaveBeenCalledWith({
|
||||
commandMenuPage: CommandMenuPages.PageLayoutWidgetTypeSelect,
|
||||
resetNavigationStack: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
+1
@@ -102,6 +102,7 @@ describe('useEndPageLayoutDragSelection', () => {
|
||||
|
||||
expect(mockNavigatePageLayoutCommandMenu).toHaveBeenCalledWith({
|
||||
commandMenuPage: CommandMenuPages.PageLayoutWidgetTypeSelect,
|
||||
resetNavigationStack: true,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { useNavigatePageLayoutCommandMenu } from '@/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { pageLayoutDraggedAreaComponentState } from '@/page-layout/states/pageLayoutDraggedAreaComponentState';
|
||||
import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState';
|
||||
import { parseCellIdToCoordinates } from '@/page-layout/utils/parseCellIdToCoordinates';
|
||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useCreateWidgetFromClick = () => {
|
||||
const pageLayoutDraggedAreaState = useRecoilComponentCallbackState(
|
||||
pageLayoutDraggedAreaComponentState,
|
||||
);
|
||||
|
||||
const pageLayoutEditingWidgetIdState = useRecoilComponentCallbackState(
|
||||
pageLayoutEditingWidgetIdComponentState,
|
||||
);
|
||||
|
||||
const { navigatePageLayoutCommandMenu } = useNavigatePageLayoutCommandMenu();
|
||||
|
||||
const createWidgetFromClick = useRecoilCallback(
|
||||
({ set }) =>
|
||||
(cellId: string) => {
|
||||
const { col, row } = parseCellIdToCoordinates(cellId);
|
||||
const bounds = { x: col, y: row, w: 1, h: 1 };
|
||||
|
||||
set(pageLayoutDraggedAreaState, bounds);
|
||||
set(pageLayoutEditingWidgetIdState, null);
|
||||
|
||||
navigatePageLayoutCommandMenu({
|
||||
commandMenuPage: CommandMenuPages.PageLayoutWidgetTypeSelect,
|
||||
resetNavigationStack: true,
|
||||
});
|
||||
},
|
||||
[
|
||||
navigatePageLayoutCommandMenu,
|
||||
pageLayoutDraggedAreaState,
|
||||
pageLayoutEditingWidgetIdState,
|
||||
],
|
||||
);
|
||||
|
||||
return { createWidgetFromClick };
|
||||
};
|
||||
@@ -52,6 +52,7 @@ export const useEndPageLayoutDragSelection = (
|
||||
|
||||
navigatePageLayoutCommandMenu({
|
||||
commandMenuPage: CommandMenuPages.PageLayoutWidgetTypeSelect,
|
||||
resetNavigationStack: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -38,6 +38,7 @@ export const DashboardWidgetPlaceholder = () => {
|
||||
}
|
||||
navigatePageLayoutCommandMenu({
|
||||
commandMenuPage: CommandMenuPages.PageLayoutWidgetTypeSelect,
|
||||
resetNavigationStack: true,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user