Instant widget placeholder placement on drag end (#15496)

closes -
https://discord.com/channels/1130383047699738754/1430596561137700957

fixed a bug - where on chart type change in side panel -- wont update
the widgets minimum size

---------

Co-authored-by: Raphaël Bosi <71827178+bosiraphael@users.noreply.github.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
nitin
2025-11-03 22:38:13 +05:30
committed by GitHub
parent 9c695cfed5
commit 902eb2c5d2
21 changed files with 1545 additions and 55 deletions
@@ -15,6 +15,7 @@ import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { pageLayoutDraggedAreaComponentState } from '@/page-layout/states/pageLayoutDraggedAreaComponentState';
import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState';
import { pageLayoutTabSettingsOpenTabIdComponentState } from '@/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
@@ -85,6 +86,12 @@ export const useCommandMenuCloseAnimationCompleteCleanup = () => {
}),
null,
);
set(
pageLayoutDraggedAreaComponentState.atomFamily({
instanceId: record.pageLayoutId,
}),
null,
);
}
}
}
@@ -5,13 +5,13 @@ import { useUpdateCommandMenuPageInfo } from '@/command-menu/hooks/useUpdateComm
import { ChartSettingItem } from '@/command-menu/pages/page-layout/components/chart-settings/ChartSettingItem';
import { ChartTypeSelectionSection } from '@/command-menu/pages/page-layout/components/ChartTypeSelectionSection';
import { GRAPH_TYPE_INFORMATION } from '@/command-menu/pages/page-layout/constants/GraphTypeInformation';
import { GRAPH_TYPE_TO_CONFIG_TYPENAME } from '@/command-menu/pages/page-layout/constants/GraphTypeToConfigTypename';
import { useChartSettingsValues } from '@/command-menu/pages/page-layout/hooks/useChartSettingsValues';
import { useNavigatePageLayoutCommandMenu } from '@/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu';
import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord';
import { useUpdateChartSettingInput } from '@/command-menu/pages/page-layout/hooks/useUpdateChartSettingInput';
import { useUpdateChartSettingToggle } from '@/command-menu/pages/page-layout/hooks/useUpdateChartSettingToggle';
import { useUpdateCurrentWidgetConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig';
import { useUpdateGraphTypeConfig } from '@/command-menu/pages/page-layout/hooks/useUpdateGraphTypeConfig';
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layout/types/ChartConfigurationSettingIds';
import { shouldHideChartSetting } from '@/command-menu/pages/page-layout/utils/shouldHideChartSetting';
@@ -24,14 +24,9 @@ import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectab
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { isDefined, isFieldMetadataDateKind } from 'twenty-shared/utils';
import { SidePanelInformationBanner } from 'twenty-ui/display';
import {
AggregateOperations,
GraphType,
type PageLayoutWidget,
} from '~/generated/graphql';
import { GraphType, type PageLayoutWidget } from '~/generated/graphql';
const StyledSidePanelInformationBanner = styled(SidePanelInformationBanner)`
margin-top: ${({ theme }) => theme.spacing(2)};
@@ -69,6 +64,12 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => {
const { updateChartSettingInput } = useUpdateChartSettingInput(pageLayoutId);
const { updateGraphTypeConfig } = useUpdateGraphTypeConfig({
pageLayoutId,
widget,
configuration,
});
const isGroupByEnabled = getChartSettingsValues(
CHART_CONFIGURATION_SETTING_IDS.GROUP_BY,
);
@@ -76,34 +77,7 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => {
useRecoilComponentState(hasWidgetTooManyGroupsComponentState);
const handleGraphTypeChange = (graphType: GraphType) => {
const configToUpdate: Record<string, any> = {
__typename: GRAPH_TYPE_TO_CONFIG_TYPENAME[graphType],
graphType,
};
if (graphType !== GraphType.AGGREGATE && graphType !== GraphType.GAUGE) {
const currentAggregateFieldMetadataId =
configuration.aggregateFieldMetadataId;
const objectMetadataItem = objectMetadataItems.find(
(item) => item.id === widget.objectMetadataId,
);
if (isDefined(objectMetadataItem)) {
const aggregateField = objectMetadataItem.fields.find(
(field) => field.id === currentAggregateFieldMetadataId,
);
if (
isDefined(aggregateField) &&
isFieldMetadataDateKind(aggregateField.type) &&
(configuration.aggregateOperation === AggregateOperations.MIN ||
configuration.aggregateOperation === AggregateOperations.MAX)
) {
configToUpdate.aggregateOperation = AggregateOperations.COUNT;
}
}
}
const configToUpdate = updateGraphTypeConfig(graphType);
updateCurrentWidgetConfig({
configToUpdate,
@@ -0,0 +1,111 @@
import { GRAPH_TYPE_TO_CONFIG_TYPENAME } from '@/command-menu/pages/page-layout/constants/GraphTypeToConfigTypename';
import { type ChartConfiguration } from '@/command-menu/pages/page-layout/types/ChartConfiguration';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState';
import { getTabListInstanceIdFromPageLayoutId } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutId';
import { updateWidgetMinimumSizeForGraphType } from '@/page-layout/utils/updateWidgetMinimumSizeForGraphType';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
import { useRecoilCallback } from 'recoil';
import { isDefined, isFieldMetadataDateKind } from 'twenty-shared/utils';
import { GraphType, type PageLayoutWidget } from '~/generated/graphql';
export const useUpdateGraphTypeConfig = ({
pageLayoutId,
widget,
configuration,
}: {
pageLayoutId: string;
widget: PageLayoutWidget;
configuration: ChartConfiguration;
}) => {
const { objectMetadataItems } = useObjectMetadataItems();
const tabListInstanceId = getTabListInstanceIdFromPageLayoutId(pageLayoutId);
const activeTabIdState = useRecoilComponentCallbackState(
activeTabIdComponentState,
tabListInstanceId,
);
const currentlyEditingWidgetIdState = useRecoilComponentCallbackState(
pageLayoutEditingWidgetIdComponentState,
pageLayoutId,
);
const pageLayoutCurrentLayoutsState = useRecoilComponentCallbackState(
pageLayoutCurrentLayoutsComponentState,
pageLayoutId,
);
const updateGraphTypeConfig = useRecoilCallback(
({ set, snapshot }) =>
(graphType: GraphType) => {
const configToUpdate: Record<string, any> = {
__typename: GRAPH_TYPE_TO_CONFIG_TYPENAME[graphType],
graphType,
};
if (
graphType !== GraphType.AGGREGATE &&
graphType !== GraphType.GAUGE
) {
const currentAggregateFieldMetadataId =
configuration.aggregateFieldMetadataId;
const objectMetadataItem = objectMetadataItems.find(
(item) => item.id === widget.objectMetadataId,
);
if (isDefined(objectMetadataItem)) {
const aggregateField = objectMetadataItem.fields.find(
(field) => field.id === currentAggregateFieldMetadataId,
);
if (
isDefined(aggregateField) &&
isFieldMetadataDateKind(aggregateField.type) &&
(configuration.aggregateOperation === AggregateOperations.MIN ||
configuration.aggregateOperation === AggregateOperations.MAX)
) {
configToUpdate.aggregateOperation = AggregateOperations.COUNT;
}
}
}
const activeTabId = snapshot.getLoadable(activeTabIdState).getValue();
const currentlyEditingWidgetId = snapshot
.getLoadable(currentlyEditingWidgetIdState)
.getValue();
if (isDefined(activeTabId) && isDefined(currentlyEditingWidgetId)) {
const currentLayouts = snapshot
.getLoadable(pageLayoutCurrentLayoutsState)
.getValue();
const updatedLayouts = updateWidgetMinimumSizeForGraphType(
graphType,
currentlyEditingWidgetId,
activeTabId,
currentLayouts,
);
set(pageLayoutCurrentLayoutsState, updatedLayouts);
}
return configToUpdate;
},
[
activeTabIdState,
configuration,
currentlyEditingWidgetIdState,
objectMetadataItems,
pageLayoutCurrentLayoutsState,
widget.objectMetadataId,
],
);
return { updateGraphTypeConfig };
};