fe4512f80c
- Fix duplication of tabs in dashboards that didn't open the duplicated tab in the side panel: replaced the logic that used Math.round with an algorithm that switches the positions of the elements. We will keep relying on integers, but it will work well in all cases. - Make dnd work with record page layouts, where there is a pinned tab - Make tab movements work with pinned tab, too - Allow user to set a tab as the pinned tab - Make backend changes to be able to save tabs with `layoutMode` https://github.com/user-attachments/assets/ce1130fa-71df-49ba-ba2f-6f971e15dd49 --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
174 lines
5.6 KiB
TypeScript
174 lines
5.6 KiB
TypeScript
import { useDateTimeFormat } from '@/localization/hooks/useDateTimeFormat';
|
|
import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext';
|
|
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
|
|
import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
|
|
import { pageLayoutDraggedAreaComponentState } from '@/page-layout/states/pageLayoutDraggedAreaComponentState';
|
|
import { type GraphWidgetFieldSelection } from '@/page-layout/types/GraphWidgetFieldSelection';
|
|
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
|
|
import { addWidgetToTab } from '@/page-layout/utils/addWidgetToTab';
|
|
import { createDefaultGraphWidget } from '@/page-layout/utils/createDefaultGraphWidget';
|
|
import { getDefaultWidgetPosition } from '@/page-layout/utils/getDefaultWidgetPosition';
|
|
import { getUpdatedTabLayouts } from '@/page-layout/utils/getUpdatedTabLayouts';
|
|
import { getWidgetSize } from '@/page-layout/utils/getWidgetSize';
|
|
import { getWidgetTitle } from '@/page-layout/utils/getWidgetTitle';
|
|
import { isWidgetConfigurationOfType } from '@/side-panel/pages/page-layout/utils/isWidgetConfigurationOfType';
|
|
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
|
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
|
|
import { useStore } from 'jotai';
|
|
import { useCallback } from 'react';
|
|
import { isDefined } from 'twenty-shared/utils';
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
import {
|
|
BarChartLayout,
|
|
WidgetConfigurationType,
|
|
WidgetType,
|
|
} from '~/generated-metadata/graphql';
|
|
|
|
export const useCreatePageLayoutGraphWidget = ({
|
|
pageLayoutId: pageLayoutIdFromProps,
|
|
tabListInstanceId,
|
|
}: {
|
|
pageLayoutId: string;
|
|
tabListInstanceId: string;
|
|
}) => {
|
|
const pageLayoutId = useAvailableComponentInstanceIdOrThrow(
|
|
PageLayoutComponentInstanceContext,
|
|
pageLayoutIdFromProps,
|
|
);
|
|
|
|
const store = useStore();
|
|
const { timeZone, calendarStartDay } = useDateTimeFormat();
|
|
|
|
const pageLayoutDraftState = useAtomComponentStateCallbackState(
|
|
pageLayoutDraftComponentState,
|
|
pageLayoutId,
|
|
);
|
|
|
|
const pageLayoutCurrentLayoutsState = useAtomComponentStateCallbackState(
|
|
pageLayoutCurrentLayoutsComponentState,
|
|
pageLayoutId,
|
|
);
|
|
|
|
const pageLayoutDraggedAreaState = useAtomComponentStateCallbackState(
|
|
pageLayoutDraggedAreaComponentState,
|
|
pageLayoutId,
|
|
);
|
|
|
|
const createPageLayoutGraphWidget = useCallback(
|
|
({
|
|
fieldSelection,
|
|
}: {
|
|
fieldSelection?: GraphWidgetFieldSelection;
|
|
}): PageLayoutWidget => {
|
|
const activeTabId = store.get(
|
|
activeTabIdComponentState.atomFamily({
|
|
instanceId: tabListInstanceId,
|
|
}),
|
|
);
|
|
|
|
if (!isDefined(activeTabId)) {
|
|
throw new Error('A tab must be selected to create a new graph widget');
|
|
}
|
|
|
|
const pageLayoutDraft = store.get(pageLayoutDraftState);
|
|
|
|
const allTabLayouts = store.get(pageLayoutCurrentLayoutsState);
|
|
|
|
const pageLayoutDraggedArea = store.get(pageLayoutDraggedAreaState);
|
|
|
|
const allWidgets = pageLayoutDraft.tabs.flatMap((tab) => tab.widgets);
|
|
const existingWidgetCount = allWidgets.filter((widget) => {
|
|
if (widget.type !== WidgetType.GRAPH) {
|
|
return false;
|
|
}
|
|
|
|
if (
|
|
!isWidgetConfigurationOfType(
|
|
widget.configuration,
|
|
'BarChartConfiguration',
|
|
)
|
|
) {
|
|
return false;
|
|
}
|
|
return widget.configuration.layout === BarChartLayout.VERTICAL;
|
|
}).length;
|
|
|
|
const title = getWidgetTitle(
|
|
{
|
|
configurationType: WidgetConfigurationType.BAR_CHART,
|
|
layout: BarChartLayout.VERTICAL,
|
|
},
|
|
existingWidgetCount,
|
|
);
|
|
const widgetId = uuidv4();
|
|
|
|
const defaultSize = getWidgetSize(
|
|
WidgetConfigurationType.BAR_CHART,
|
|
'default',
|
|
);
|
|
const minimumSize = getWidgetSize(
|
|
WidgetConfigurationType.BAR_CHART,
|
|
'minimum',
|
|
);
|
|
const position = getDefaultWidgetPosition(
|
|
pageLayoutDraggedArea,
|
|
defaultSize,
|
|
minimumSize,
|
|
);
|
|
|
|
const newWidget = createDefaultGraphWidget({
|
|
id: widgetId,
|
|
pageLayoutTabId: activeTabId,
|
|
title,
|
|
gridPosition: {
|
|
row: position.y,
|
|
column: position.x,
|
|
rowSpan: position.h,
|
|
columnSpan: position.w,
|
|
},
|
|
fieldSelection,
|
|
timezone: timeZone,
|
|
firstDayOfTheWeek: calendarStartDay,
|
|
});
|
|
|
|
const newLayout = {
|
|
i: widgetId,
|
|
x: position.x,
|
|
y: position.y,
|
|
w: position.w,
|
|
h: position.h,
|
|
minW: minimumSize.w,
|
|
minH: minimumSize.h,
|
|
};
|
|
|
|
const updatedLayouts = getUpdatedTabLayouts(
|
|
allTabLayouts,
|
|
activeTabId,
|
|
newLayout,
|
|
);
|
|
store.set(pageLayoutCurrentLayoutsState, updatedLayouts);
|
|
|
|
store.set(pageLayoutDraftState, (prev) => ({
|
|
...prev,
|
|
tabs: addWidgetToTab(prev.tabs, activeTabId, newWidget),
|
|
}));
|
|
|
|
store.set(pageLayoutDraggedAreaState, null);
|
|
|
|
return newWidget;
|
|
},
|
|
[
|
|
tabListInstanceId,
|
|
pageLayoutCurrentLayoutsState,
|
|
pageLayoutDraftState,
|
|
pageLayoutDraggedAreaState,
|
|
timeZone,
|
|
calendarStartDay,
|
|
store,
|
|
],
|
|
);
|
|
|
|
return { createPageLayoutGraphWidget };
|
|
};
|