feat: use side-column variant for all widgets on mobile and side panel (#16822)
Closes [1957](https://github.com/twentyhq/core-team-issues/issues/1957). `getWidgetCardVariant` now returns `side-panel` for mobile and right drawer instead of returning `record-page`. Added stories to WidgetRenderer.stories.tsx because WidgetRenderer is where getWidgetCardVariant is called and the variant is applied. These stories test the actual behavior (mobile/side panel triggering side-column variant) rather than just visual appearance, following the existing pattern of individual behavior-testing stories in this file.
This commit is contained in:
@@ -18,6 +18,8 @@ import { getWidgetCardVariant } from '@/page-layout/widgets/utils/getWidgetCardV
|
||||
import { WidgetCard } from '@/page-layout/widgets/widget-card/components/WidgetCard';
|
||||
import { WidgetCardContent } from '@/page-layout/widgets/widget-card/components/WidgetCardContent';
|
||||
import { WidgetCardHeader } from '@/page-layout/widgets/widget-card/components/WidgetCardHeader';
|
||||
import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useSetRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyState';
|
||||
import { useTheme } from '@emotion/react';
|
||||
@@ -60,6 +62,8 @@ export const WidgetRenderer = ({ widget }: WidgetRendererProps) => {
|
||||
|
||||
const { layoutMode } = usePageLayoutContentContext();
|
||||
const { isInPinnedTab } = useIsInPinnedTab();
|
||||
const { isInRightDrawer } = useLayoutRenderingContext();
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const { currentPageLayout } = useCurrentPageLayoutOrThrow();
|
||||
|
||||
@@ -99,6 +103,8 @@ export const WidgetRenderer = ({ widget }: WidgetRendererProps) => {
|
||||
layoutMode,
|
||||
isInPinnedTab,
|
||||
pageLayoutType: currentPageLayout.type,
|
||||
isMobile,
|
||||
isInRightDrawer,
|
||||
});
|
||||
|
||||
const actions = useWidgetActions({ widget });
|
||||
|
||||
+195
@@ -1195,6 +1195,201 @@ export const WithOneToManyRelationFieldWidget: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const OnMobile: Story = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: 'mobile1',
|
||||
},
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
'Widget on mobile viewport should use side-column variant instead of record-page variant.',
|
||||
},
|
||||
},
|
||||
},
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'widget-mobile',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.GRAPH,
|
||||
title: 'Mobile Widget',
|
||||
objectMetadataId: companyObjectMetadataItem.id,
|
||||
gridPosition: {
|
||||
__typename: 'GridPosition',
|
||||
row: 0,
|
||||
column: 0,
|
||||
rowSpan: 2,
|
||||
columnSpan: 3,
|
||||
},
|
||||
configuration: {
|
||||
__typename: 'AggregateChartConfiguration',
|
||||
graphType: GraphType.AGGREGATE,
|
||||
aggregateOperation: AggregateOperations.COUNT,
|
||||
aggregateFieldMetadataId: idField.id,
|
||||
displayDataLabel: true,
|
||||
},
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
updatedAt: '2024-01-01T00:00:00Z',
|
||||
deletedAt: null,
|
||||
};
|
||||
|
||||
const initializeState = (snapshot: MutableSnapshot) => {
|
||||
snapshot.set(objectMetadataItemsState, generatedMockObjectMetadataItems);
|
||||
snapshot.set(shouldAppBeLoadingState, false);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
PageLayoutType.RECORD_PAGE,
|
||||
);
|
||||
snapshot.set(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID,
|
||||
}),
|
||||
pageLayoutData,
|
||||
);
|
||||
snapshot.set(
|
||||
pageLayoutDraftComponentState.atomFamily({
|
||||
instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID,
|
||||
}),
|
||||
pageLayoutData,
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ width: '100%', padding: '20px' }}>
|
||||
<JestMetadataAndApolloMocksWrapper>
|
||||
<CoreClientProviderWrapper>
|
||||
<PageLayoutTestWrapper initializeState={initializeState}>
|
||||
<LayoutRenderingProvider
|
||||
value={{
|
||||
isInRightDrawer: false,
|
||||
layoutType: PageLayoutType.RECORD_PAGE,
|
||||
targetRecordIdentifier: {
|
||||
id: TEST_RECORD_ID,
|
||||
targetObjectNameSingular:
|
||||
companyObjectMetadataItem.nameSingular,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<PageLayoutContentProvider
|
||||
value={{
|
||||
layoutMode: 'grid',
|
||||
tabId: TAB_ID_OVERVIEW,
|
||||
}}
|
||||
>
|
||||
<WidgetComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: 'widget-mobile',
|
||||
}}
|
||||
>
|
||||
<WidgetRenderer widget={widget} />
|
||||
</WidgetComponentInstanceContext.Provider>
|
||||
</PageLayoutContentProvider>
|
||||
</LayoutRenderingProvider>
|
||||
</PageLayoutTestWrapper>
|
||||
</CoreClientProviderWrapper>
|
||||
</JestMetadataAndApolloMocksWrapper>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const InSidePanel: Story = {
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
'Widget in side panel (right drawer) should use side-column variant instead of record-page variant.',
|
||||
},
|
||||
},
|
||||
},
|
||||
render: () => {
|
||||
const widget: PageLayoutWidget = {
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'widget-side-panel',
|
||||
pageLayoutTabId: TAB_ID_OVERVIEW,
|
||||
type: WidgetType.GRAPH,
|
||||
title: 'Side Panel Widget',
|
||||
objectMetadataId: companyObjectMetadataItem.id,
|
||||
gridPosition: {
|
||||
__typename: 'GridPosition',
|
||||
row: 0,
|
||||
column: 0,
|
||||
rowSpan: 2,
|
||||
columnSpan: 3,
|
||||
},
|
||||
configuration: {
|
||||
__typename: 'AggregateChartConfiguration',
|
||||
graphType: GraphType.AGGREGATE,
|
||||
aggregateOperation: AggregateOperations.COUNT,
|
||||
aggregateFieldMetadataId: idField.id,
|
||||
displayDataLabel: true,
|
||||
},
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
updatedAt: '2024-01-01T00:00:00Z',
|
||||
deletedAt: null,
|
||||
};
|
||||
|
||||
const initializeState = (snapshot: MutableSnapshot) => {
|
||||
snapshot.set(objectMetadataItemsState, generatedMockObjectMetadataItems);
|
||||
snapshot.set(shouldAppBeLoadingState, false);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
PageLayoutType.RECORD_PAGE,
|
||||
);
|
||||
snapshot.set(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID,
|
||||
}),
|
||||
pageLayoutData,
|
||||
);
|
||||
snapshot.set(
|
||||
pageLayoutDraftComponentState.atomFamily({
|
||||
instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID,
|
||||
}),
|
||||
pageLayoutData,
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ width: '400px', padding: '20px' }}>
|
||||
<JestMetadataAndApolloMocksWrapper>
|
||||
<CoreClientProviderWrapper>
|
||||
<PageLayoutTestWrapper initializeState={initializeState}>
|
||||
<LayoutRenderingProvider
|
||||
value={{
|
||||
isInRightDrawer: true,
|
||||
layoutType: PageLayoutType.RECORD_PAGE,
|
||||
targetRecordIdentifier: {
|
||||
id: TEST_RECORD_ID,
|
||||
targetObjectNameSingular:
|
||||
companyObjectMetadataItem.nameSingular,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<PageLayoutContentProvider
|
||||
value={{
|
||||
layoutMode: 'grid',
|
||||
tabId: TAB_ID_OVERVIEW,
|
||||
}}
|
||||
>
|
||||
<WidgetComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: 'widget-side-panel',
|
||||
}}
|
||||
>
|
||||
<WidgetRenderer widget={widget} />
|
||||
</WidgetComponentInstanceContext.Provider>
|
||||
</PageLayoutContentProvider>
|
||||
</LayoutRenderingProvider>
|
||||
</PageLayoutTestWrapper>
|
||||
</CoreClientProviderWrapper>
|
||||
</JestMetadataAndApolloMocksWrapper>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const Catalog: CatalogStory<Story, typeof WidgetRenderer> = {
|
||||
parameters: {
|
||||
catalog: {
|
||||
|
||||
@@ -6,12 +6,16 @@ type GetWidgetCardVariantParams = {
|
||||
layoutMode: PageLayoutTabLayoutMode;
|
||||
isInPinnedTab: boolean;
|
||||
pageLayoutType: PageLayoutType | null;
|
||||
isMobile: boolean;
|
||||
isInRightDrawer: boolean;
|
||||
};
|
||||
|
||||
export const getWidgetCardVariant = ({
|
||||
layoutMode,
|
||||
isInPinnedTab,
|
||||
pageLayoutType,
|
||||
isMobile,
|
||||
isInRightDrawer,
|
||||
}: GetWidgetCardVariantParams): WidgetCardVariant => {
|
||||
if (pageLayoutType === PageLayoutType.DASHBOARD) {
|
||||
return 'dashboard';
|
||||
@@ -21,7 +25,7 @@ export const getWidgetCardVariant = ({
|
||||
return 'canvas';
|
||||
}
|
||||
|
||||
if (isInPinnedTab) {
|
||||
if (isInPinnedTab || isMobile || isInRightDrawer) {
|
||||
return 'side-column';
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user