diff --git a/packages/twenty-front/jest.config.ts b/packages/twenty-front/jest.config.ts index 95a088439b..c4e8c7ac94 100644 --- a/packages/twenty-front/jest.config.ts +++ b/packages/twenty-front/jest.config.ts @@ -58,9 +58,9 @@ const jestConfig: JestConfigWithTsJest = { extensionsToTreatAsEsm: ['.ts', '.tsx'], coverageThreshold: { global: { - statements: 55, - lines: 54, - functions: 44, + statements: 54, + lines: 53, + functions: 43, }, }, collectCoverageFrom: ['/src/**/*.ts'], diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContainer.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContainer.tsx index 429239aae0..b9ecb32537 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContainer.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContainer.tsx @@ -8,9 +8,7 @@ import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; -import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; -import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; +import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { AnimatePresence } from 'framer-motion'; @@ -50,35 +48,23 @@ export const CommandMenuContainer = ({ useCommandMenuHotKeys(); return ( - - + - - - - - {isCommandMenuOpened && ( - - {children} - - )} - - - - - - + {isCommandMenuOpened && ( + {children} + )} + + + + ); }; diff --git a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx index 95d615234a..d9239fbb78 100644 --- a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx @@ -25,9 +25,7 @@ import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpe import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages'; import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; -import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; -import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; -import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; +import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { HttpResponse, graphql } from 'msw'; import { IconDotsVertical } from 'twenty-ui/display'; import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator'; @@ -38,33 +36,25 @@ const openTimeout = 50; const ContextStoreDecorator: Decorator = (Story) => { return ( - - - - - - - - - - - - - + + + + + ); }; diff --git a/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuMergeRecordPage.tsx b/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuMergeRecordPage.tsx index 1edad710e6..3c9ebef8fc 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuMergeRecordPage.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuMergeRecordPage.tsx @@ -3,10 +3,8 @@ import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/c import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'; import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; -import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; +import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { MergeRecordsContainer } from '@/object-record/record-merge/components/MergeRecordsContainer'; -import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext'; import styled from '@emotion/styled'; @@ -35,31 +33,23 @@ export const CommandMenuMergeRecordPage = () => { } return ( - - - - - - - - - - - - - + + + + + + ); }; diff --git a/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuRecordPage.tsx b/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuRecordPage.tsx index 16b6d9a707..fdf4cb5002 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuRecordPage.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuRecordPage.tsx @@ -5,12 +5,10 @@ import { viewableRecordNameSingularComponentState } from '@/command-menu/pages/r import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext'; import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { INFORMATION_BANNER_HEIGHT } from '@/information-banner/constants/InformationBannerHeight'; -import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; -import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; +import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { RecordShowContainer } from '@/object-record/record-show/components/RecordShowContainer'; import { RecordShowEffect } from '@/object-record/record-show/components/RecordShowEffect'; import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage'; -import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext'; @@ -71,48 +69,40 @@ export const CommandMenuRecordPage = () => { } return ( - - - - - - - - - - - - - - - - + + + + + + + ); }; diff --git a/packages/twenty-front/src/modules/object-record/components/RecordComponentInstanceContextsWrapper.tsx b/packages/twenty-front/src/modules/object-record/components/RecordComponentInstanceContextsWrapper.tsx new file mode 100644 index 0000000000..8843190a0b --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/components/RecordComponentInstanceContextsWrapper.tsx @@ -0,0 +1,34 @@ +import { RecordFieldsComponentInstanceContext } from '@/object-record/record-field/states/context/RecordFieldsComponentInstanceContext'; +import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; +import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; +import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; +import { type PropsWithChildren } from 'react'; + +export type RecordComponentInstanceContextsWrapperProps = PropsWithChildren<{ + componentInstanceId: string; +}>; + +export const RecordComponentInstanceContextsWrapper = ({ + componentInstanceId, + children, +}: RecordComponentInstanceContextsWrapperProps) => { + return ( + + + + + {children} + + + + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/__stories__/ObjectOptionsDropdownContent.stories.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/__stories__/ObjectOptionsDropdownContent.stories.tsx index 6a9e06255a..7e8a013c54 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/__stories__/ObjectOptionsDropdownContent.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/__stories__/ObjectOptionsDropdownContent.stories.tsx @@ -1,14 +1,12 @@ import { type Meta, type StoryObj } from '@storybook/react'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { ObjectOptionsDropdownContent } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownContent'; import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId'; import { ObjectOptionsDropdownContext } from '@/object-record/object-options-dropdown/states/contexts/ObjectOptionsDropdownContext'; import { type ObjectOptionsContentId } from '@/object-record/object-options-dropdown/types/ObjectOptionsContentId'; -import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; -import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; -import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; @@ -42,30 +40,20 @@ const meta: Meta = { }, [setObjectMetadataItems]); return ( - - - - + + - - - - - - - - - + + + + + ); }, ContextStoreDecorator, diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useObjectOptionsForTable.ts b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useObjectOptionsForTable.ts index ba3f919cca..a24a8e2540 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useObjectOptionsForTable.ts +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useObjectOptionsForTable.ts @@ -1,6 +1,7 @@ import { type OnDragEndResponder } from '@hello-pangea/dnd'; import { useCallback } from 'react'; +import { useReorderRecordFields } from '@/object-record/record-field/hooks/useReorderRecordFields'; import { useTableColumns } from '@/object-record/record-table/hooks/useTableColumns'; import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector'; import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector'; @@ -24,6 +25,8 @@ export const useObjectOptionsForTable = ( { recordTableId, objectMetadataId }, ); + const { reorderRecordFields } = useReorderRecordFields(); + const handleReorderColumns: OnDragEndResponder = useCallback( async (result) => { if ( @@ -39,9 +42,14 @@ export const useObjectOptionsForTable = ( toIndex: result.destination.index - 1, }); + reorderRecordFields({ + fromIndex: result.source.index - 1, + toIndex: result.destination.index - 1, + }); + handleColumnReorder(reorderedFields); }, - [visibleTableColumns, handleColumnReorder], + [visibleTableColumns, handleColumnReorder, reorderRecordFields], ); return { diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/useMoveRecordField.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/useMoveRecordField.ts new file mode 100644 index 0000000000..c72742c4d0 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/useMoveRecordField.ts @@ -0,0 +1,70 @@ +import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; +import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilCallback } from 'recoil'; + +export const useMoveRecordField = () => { + const currentRecordFieldsCallbackState = useRecoilComponentCallbackState( + currentRecordFieldsComponentState, + ); + + const moveRecordField = useRecoilCallback( + ({ set, snapshot }) => + ({ + direction, + fieldMetadataItemIdToMove, + }: { + direction: 'before' | 'after'; + fieldMetadataItemIdToMove: string; + }) => { + const currentRecordFields = snapshot + .getLoadable(currentRecordFieldsCallbackState) + .getValue(); + + const indexOfRecordFieldToMove = currentRecordFields.findIndex( + (recordField) => + recordField.fieldMetadataItemId === fieldMetadataItemIdToMove, + ); + + if (indexOfRecordFieldToMove === -1) { + return; + } + + const newRecordFields = [...currentRecordFields]; + + const targetArrayIndex = + direction === 'before' + ? indexOfRecordFieldToMove - 1 + : indexOfRecordFieldToMove + 1; + + const targetArraySize = newRecordFields.length - 1; + + if ( + indexOfRecordFieldToMove >= 0 && + targetArrayIndex >= 0 && + indexOfRecordFieldToMove <= targetArraySize && + targetArrayIndex <= targetArraySize + ) { + const currentRecordField = newRecordFields[indexOfRecordFieldToMove]; + const targetRecordField = newRecordFields[targetArrayIndex]; + + const targetRecordFieldNewPosition = currentRecordField.position; + const currentRecordFieldNewPosition = targetRecordField.position; + + newRecordFields[indexOfRecordFieldToMove] = { + ...newRecordFields[indexOfRecordFieldToMove], + position: currentRecordFieldNewPosition, + }; + + newRecordFields[targetRecordFieldNewPosition] = { + ...newRecordFields[targetRecordFieldNewPosition], + position: targetRecordFieldNewPosition, + }; + + set(currentRecordFieldsCallbackState, newRecordFields); + } + }, + [currentRecordFieldsCallbackState], + ); + + return { moveRecordField }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/useReorderRecordFields.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/useReorderRecordFields.ts new file mode 100644 index 0000000000..c71ca91edc --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/useReorderRecordFields.ts @@ -0,0 +1,39 @@ +import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; +import { type RecordField } from '@/object-record/record-field/types/RecordField'; +import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilCallback } from 'recoil'; +import { moveArrayItem } from '~/utils/array/moveArrayItem'; + +export const useReorderRecordFields = () => { + const currentRecordFieldsCallbackState = useRecoilComponentCallbackState( + currentRecordFieldsComponentState, + ); + + const reorderRecordFields = useRecoilCallback( + ({ set, snapshot }) => + ({ fromIndex, toIndex }: { fromIndex: number; toIndex: number }) => { + const currentRecordFields = snapshot + .getLoadable(currentRecordFieldsCallbackState) + .getValue(); + + const reorderedRecordFields = moveArrayItem(currentRecordFields, { + fromIndex, + toIndex, + }); + + const reorderedRecordFieldsWithNewPosition = + reorderedRecordFields.map((recordField, index) => ({ + ...recordField, + position: index, + })); + + set( + currentRecordFieldsCallbackState, + reorderedRecordFieldsWithNewPosition, + ); + }, + [currentRecordFieldsCallbackState], + ); + + return { reorderRecordFields }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/useUpdateRecordField.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/useUpdateRecordField.ts new file mode 100644 index 0000000000..a252426c8d --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/useUpdateRecordField.ts @@ -0,0 +1,58 @@ +import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; +import { type RecordField } from '@/object-record/record-field/types/RecordField'; +import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilCallback } from 'recoil'; + +export const useUpdateRecordField = () => { + const currentRecordFieldsCallbackState = useRecoilComponentCallbackState( + currentRecordFieldsComponentState, + ); + + const updateRecordField = useRecoilCallback( + ({ set, snapshot }) => + ( + fieldMetadataItemId: string, + partialRecordField: Partial< + Pick + >, + ) => { + const currentRecordFields = getSnapshotValue( + snapshot, + currentRecordFieldsCallbackState, + ); + + const foundRecordFieldInCurrentRecordFields = currentRecordFields.some( + (existingRecordField) => + existingRecordField.fieldMetadataItemId === fieldMetadataItemId, + ); + + if (!foundRecordFieldInCurrentRecordFields) { + throw new Error( + `Cannot find record field to update with field metadata item id : ${fieldMetadataItemId}`, + ); + } else { + set(currentRecordFieldsCallbackState, (currentRecordFields) => { + const newCurrentRecordFields = [...currentRecordFields]; + + const indexOfRecordFieldToUpdate = newCurrentRecordFields.findIndex( + (existingRecordField) => + existingRecordField.fieldMetadataItemId === fieldMetadataItemId, + ); + + newCurrentRecordFields[indexOfRecordFieldToUpdate] = { + ...newCurrentRecordFields[indexOfRecordFieldToUpdate], + ...partialRecordField, + }; + + return newCurrentRecordFields; + }); + } + }, + [currentRecordFieldsCallbackState], + ); + + return { + updateRecordField, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/useUpsertRecordField.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/useUpsertRecordField.ts new file mode 100644 index 0000000000..71fe1b2e07 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/useUpsertRecordField.ts @@ -0,0 +1,53 @@ +import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; +import { type RecordField } from '@/object-record/record-field/types/RecordField'; +import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilCallback } from 'recoil'; + +export const useUpsertRecordField = () => { + const currentRecordFieldsCallbackState = useRecoilComponentCallbackState( + currentRecordFieldsComponentState, + ); + + const upsertRecordField = useRecoilCallback( + ({ set, snapshot }) => + (recordFieldToUpsert: RecordField) => { + const currentRecordFields = getSnapshotValue( + snapshot, + currentRecordFieldsCallbackState, + ); + + const foundRecordFieldInCurrentRecordFields = currentRecordFields.some( + (existingRecordField) => + existingRecordField.id === recordFieldToUpsert.id, + ); + + if (!foundRecordFieldInCurrentRecordFields) { + set(currentRecordFieldsCallbackState, [ + ...currentRecordFields, + recordFieldToUpsert, + ]); + } else { + set(currentRecordFieldsCallbackState, (currentRecordFields) => { + const newCurrentRecordFields = [...currentRecordFields]; + + const indexOfRecordFieldToUpdate = newCurrentRecordFields.findIndex( + (existingRecordField) => + existingRecordField.id === recordFieldToUpsert.id, + ); + + newCurrentRecordFields[indexOfRecordFieldToUpdate] = { + ...recordFieldToUpsert, + }; + + return newCurrentRecordFields; + }); + } + }, + [currentRecordFieldsCallbackState], + ); + + return { + upsertRecordField, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/states/context/RecordFieldsComponentInstanceContext.ts b/packages/twenty-front/src/modules/object-record/record-field/states/context/RecordFieldsComponentInstanceContext.ts new file mode 100644 index 0000000000..4260a24689 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/states/context/RecordFieldsComponentInstanceContext.ts @@ -0,0 +1,4 @@ +import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext'; + +export const RecordFieldsComponentInstanceContext = + createComponentInstanceContext(); diff --git a/packages/twenty-front/src/modules/object-record/record-field/states/currentRecordFieldsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-field/states/currentRecordFieldsComponentState.ts new file mode 100644 index 0000000000..8c4d539863 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/states/currentRecordFieldsComponentState.ts @@ -0,0 +1,11 @@ +import { RecordFieldsComponentInstanceContext } from '@/object-record/record-field/states/context/RecordFieldsComponentInstanceContext'; +import { type RecordField } from '@/object-record/record-field/types/RecordField'; +import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; + +export const currentRecordFieldsComponentState = createComponentState< + RecordField[] +>({ + key: 'currentRecordFieldsComponentState', + defaultValue: [], + componentInstanceContext: RecordFieldsComponentInstanceContext, +}); diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/RecordField.ts b/packages/twenty-front/src/modules/object-record/record-field/types/RecordField.ts new file mode 100644 index 0000000000..55abe5c69e --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/types/RecordField.ts @@ -0,0 +1,10 @@ +import { type AggregateOperations } from '~/generated/graphql'; + +export type RecordField = { + id: string; + fieldMetadataItemId: string; + position: number; + isVisible: boolean; + size: number; + aggregateOperation?: AggregateOperations | null; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx index 8f11426e4a..daf0a761b0 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx @@ -3,17 +3,15 @@ import { RecordIndexContextProvider } from '@/object-record/record-index/context import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId'; import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObjectPermissionsForObject'; +import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions'; import { lastShowPageRecordIdState } from '@/object-record/record-field/ui/states/lastShowPageRecordId'; -import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; -import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; import { RecordIndexContainer } from '@/object-record/record-index/components/RecordIndexContainer'; import { RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect } from '@/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect'; import { RecordIndexLoadBaseOnContextStoreEffect } from '@/object-record/record-index/components/RecordIndexLoadBaseOnContextStoreEffect'; import { RecordIndexPageHeader } from '@/object-record/record-index/components/RecordIndexPageHeader'; import { useHandleIndexIdentifierClick } from '@/object-record/record-index/hooks/useHandleIndexIdentifierClick'; import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore'; -import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; import { PageBody } from '@/ui/layout/page/components/PageBody'; import { RECORD_INDEX_DRAG_SELECT_BOUNDARY_CLASS } from '@/ui/utilities/drag-select/constants/RecordIndecDragSelectBoundaryClass'; import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle'; @@ -74,34 +72,26 @@ export const RecordIndexContainerGater = () => { - - - - + + + - - - - - - - - - - - - + + + + + + diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useHandleColumnsChange.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useHandleColumnsChange.ts index 165fd1e13f..fc4b006eb9 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useHandleColumnsChange.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/useHandleColumnsChange.ts @@ -5,6 +5,7 @@ import { type ColumnDefinition } from '@/object-record/record-table/types/Column // TODO: see how we can better abstract this and set the correct interaction between view and table // but for now it allows to have a cleaner API globally. +// TODO: should be solved with new RecordField abstraction export const useHandleColumnsChange = () => { const { saveColumnsToView } = useSaveColumnsToView(); const { setTableColumns } = useSetTableColumns(); diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useTableColumns.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useTableColumns.ts index 9b52807324..4d10fd617e 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useTableColumns.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/useTableColumns.ts @@ -4,11 +4,15 @@ import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldM import { useUnfocusRecordTableCell } from '@/object-record/record-table/record-table-cell/hooks/useUnfocusRecordTableCell'; import { useMoveViewColumns } from '@/views/hooks/useMoveViewColumns'; +import { useMoveRecordField } from '@/object-record/record-field/hooks/useMoveRecordField'; +import { useUpdateRecordField } from '@/object-record/record-field/hooks/useUpdateRecordField'; +import { useUpsertRecordField } from '@/object-record/record-field/hooks/useUpsertRecordField'; import { useHandleColumnsChange } from '@/object-record/record-table/hooks/useHandleColumnsChange'; import { availableTableColumnsComponentState } from '@/object-record/record-table/states/availableTableColumnsComponentState'; import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector'; import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { v4 } from 'uuid'; import { type ColumnDefinition } from '../types/ColumnDefinition'; type useRecordTableProps = { @@ -40,6 +44,9 @@ export const useTableColumns = ({ const { handleColumnsChange } = useHandleColumnsChange(); + const { updateRecordField } = useUpdateRecordField(); + const { upsertRecordField } = useUpsertRecordField(); + const handleColumnVisibilityChange = useCallback( async ( viewField: Omit, 'size' | 'position'>, @@ -68,6 +75,14 @@ export const useTableColumns = ({ { ...newColumn, isVisible: true, position: lastPosition + 1 }, ]; + upsertRecordField({ + id: v4(), + fieldMetadataItemId: viewField.fieldMetadataId, + size: 100, + isVisible: true, + position: lastPosition + 1, + }); + await handleColumnsChange({ columns: nextColumns, objectMetadataId, @@ -80,6 +95,10 @@ export const useTableColumns = ({ : previousColumn, ); + updateRecordField(viewField.fieldMetadataId, { + isVisible: !viewField.isVisible, + }); + await handleColumnsChange({ columns: nextColumns, objectMetadataId, @@ -88,15 +107,19 @@ export const useTableColumns = ({ } }, [ + upsertRecordField, tableColumns, availableTableColumns, handleColumnsChange, visibleTableColumns, objectMetadataId, recordTableId, + updateRecordField, ], ); + const { moveRecordField } = useMoveRecordField(); + const handleMoveTableColumn = useCallback( async ( direction: 'left' | 'right', @@ -115,6 +138,11 @@ export const useTableColumns = ({ visibleTableColumns, ); + moveRecordField({ + direction: direction === 'left' ? 'before' : 'after', + fieldMetadataItemIdToMove: column.fieldMetadataId, + }); + await handleColumnsChange({ columns, objectMetadataId, @@ -128,6 +156,7 @@ export const useTableColumns = ({ handleColumnsChange, objectMetadataId, recordTableId, + moveRecordField, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx index 3577cca20c..846d83de6a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx @@ -2,6 +2,7 @@ import styled from '@emotion/styled'; import { useCallback, useMemo, useState } from 'react'; import { useRecoilCallback } from 'recoil'; +import { useUpdateRecordField } from '@/object-record/record-field/hooks/useUpdateRecordField'; import { isObjectReadOnly } from '@/object-record/record-field/ui/hooks/read-only/utils/isObjectReadOnly'; import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; @@ -135,13 +136,17 @@ export const RecordTableHeaderCell = ({ const [initialPointerPositionX, setInitialPointerPositionX] = useState< number | null >(null); - const [resizedFieldKey, setResizedFieldKey] = useState(null); + const [resizedFieldMetadataItemId, setResizedFieldMetadataItemId] = useState< + string | null + >(null); const { handleColumnsChange } = useTableColumns({ objectMetadataId: objectMetadataItem.id, recordTableId, }); + const { updateRecordField } = useUpdateRecordField(); + const handleResizeHandlerStart = useCallback( ({ x }) => { setInitialPointerPositionX(x); @@ -162,7 +167,7 @@ export const RecordTableHeaderCell = ({ const handleResizeHandlerEnd = useRecoilCallback( ({ snapshot, set }) => async () => { - if (!resizedFieldKey) return; + if (!resizedFieldMetadataItemId) return; const resizeFieldOffset = getSnapshotValue( snapshot, @@ -171,22 +176,27 @@ export const RecordTableHeaderCell = ({ const nextWidth = Math.round( Math.max( - tableColumnsByKey[resizedFieldKey].size + resizeFieldOffset, + tableColumnsByKey[resizedFieldMetadataItemId].size + + resizeFieldOffset, COLUMN_MIN_WIDTH, ), ); set(resizeFieldOffsetState, 0); setInitialPointerPositionX(null); - setResizedFieldKey(null); + setResizedFieldMetadataItemId(null); - if (nextWidth !== tableColumnsByKey[resizedFieldKey].size) { + if (nextWidth !== tableColumnsByKey[resizedFieldMetadataItemId].size) { const nextColumns = tableColumns.map((column) => - column.fieldMetadataId === resizedFieldKey + column.fieldMetadataId === resizedFieldMetadataItemId ? { ...column, size: nextWidth } : column, ); + updateRecordField(resizedFieldMetadataItemId, { + size: nextWidth, + }); + await handleColumnsChange({ columns: nextColumns, objectMetadataId: objectMetadataItem.id, @@ -195,19 +205,20 @@ export const RecordTableHeaderCell = ({ } }, [ - resizedFieldKey, + resizedFieldMetadataItemId, resizeFieldOffsetState, tableColumnsByKey, - setResizedFieldKey, + setResizedFieldMetadataItemId, tableColumns, handleColumnsChange, objectMetadataItem, recordTableId, + updateRecordField, ], ); useTrackPointer({ - shouldTrackPointer: resizedFieldKey !== null, + shouldTrackPointer: resizedFieldMetadataItemId !== null, onMouseDown: handleResizeHandlerStart, onMouseMove: handleResizeHandlerMove, onMouseUp: handleResizeHandlerEnd, @@ -251,10 +262,12 @@ export const RecordTableHeaderCell = ({ return ( { - setResizedFieldKey(column.fieldMetadataId); + setResizedFieldMetadataItemId(column.fieldMetadataId); }} /> )} diff --git a/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx b/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx index fa6e7a07c4..3114e5dd07 100644 --- a/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx +++ b/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx @@ -5,10 +5,8 @@ import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainCo import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; -import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; +import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; -import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers'; import { SignInBackgroundMockContainerEffect } from '@/sign-in-background-mock/components/SignInBackgroundMockContainerEffect'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; @@ -57,48 +55,40 @@ export const SignInBackgroundMockContainer = () => { - - - + - - - - {isDefined(objectMetadataItem) && ( - <> - } - /> + {isDefined(objectMetadataItem) && ( + <> + } + /> - {}} - /> - - )} - - - - - + {}} + /> + + )} + + + diff --git a/packages/twenty-front/src/modules/views/components/ViewBar.tsx b/packages/twenty-front/src/modules/views/components/ViewBar.tsx index b64744d706..f6ba1af7f8 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBar.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBar.tsx @@ -14,6 +14,7 @@ import { VIEW_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/cons import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext'; import { ViewBarAnyFieldFilterEffect } from '@/views/components/ViewBarAnyFieldFilterEffect'; import { ViewBarFilterDropdown } from '@/views/components/ViewBarFilterDropdown'; +import { ViewBarRecordFieldEffect } from '@/views/components/ViewBarRecordFieldEffect'; import { ViewBarRecordFilterEffect } from '@/views/components/ViewBarRecordFilterEffect'; import { ViewBarRecordFilterGroupEffect } from '@/views/components/ViewBarRecordFilterGroupEffect'; import { ViewBarRecordSortEffect } from '@/views/components/ViewBarRecordSortEffect'; @@ -45,6 +46,7 @@ export const ViewBar = ({ > + diff --git a/packages/twenty-front/src/modules/views/components/ViewBarRecordFieldEffect.tsx b/packages/twenty-front/src/modules/views/components/ViewBarRecordFieldEffect.tsx new file mode 100644 index 0000000000..f3ec4bf963 --- /dev/null +++ b/packages/twenty-front/src/modules/views/components/ViewBarRecordFieldEffect.tsx @@ -0,0 +1,65 @@ +import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; +import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; +import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; +import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector'; +import { useRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyState'; +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { hasInitializedCurrentRecordFieldsComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordFieldsComponentFamilyState'; +import { mapViewFieldToRecordField } from '@/views/utils/mapViewFieldToRecordField'; +import { useEffect } from 'react'; +import { useRecoilValue } from 'recoil'; +import { isDefined } from 'twenty-shared/utils'; + +export const ViewBarRecordFieldEffect = () => { + const currentViewId = useRecoilComponentValue( + contextStoreCurrentViewIdComponentState, + ); + + const { objectMetadataItem } = useRecordIndexContextOrThrow(); + + const currentView = useRecoilValue( + prefetchViewFromViewIdFamilySelector({ + viewId: currentViewId ?? '', + }), + ); + + const [ + hasInitializedCurrentRecordFields, + setHasInitializedCurrentRecordFields, + ] = useRecoilComponentFamilyState( + hasInitializedCurrentRecordFieldsComponentFamilyState, + { + viewId: currentViewId ?? undefined, + }, + ); + + const setCurrentRecordFields = useSetRecoilComponentState( + currentRecordFieldsComponentState, + ); + + useEffect(() => { + if (!hasInitializedCurrentRecordFields && isDefined(currentView)) { + if (currentView.objectMetadataId !== objectMetadataItem.id) { + return; + } + + const recordFields = currentView.viewFields + .map(mapViewFieldToRecordField) + .filter(isDefined); + + setCurrentRecordFields(recordFields); + + setHasInitializedCurrentRecordFields(true); + } + }, [ + currentViewId, + setCurrentRecordFields, + hasInitializedCurrentRecordFields, + setHasInitializedCurrentRecordFields, + currentView, + objectMetadataItem, + ]); + + return null; +}; diff --git a/packages/twenty-front/src/modules/views/components/__stories__/ViewBarFilterDropdown.stories.tsx b/packages/twenty-front/src/modules/views/components/__stories__/ViewBarFilterDropdown.stories.tsx index 3951c4c3df..385c025a5a 100644 --- a/packages/twenty-front/src/modules/views/components/__stories__/ViewBarFilterDropdown.stories.tsx +++ b/packages/twenty-front/src/modules/views/components/__stories__/ViewBarFilterDropdown.stories.tsx @@ -6,10 +6,7 @@ import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlur import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; -import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; -import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; -import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState'; import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState'; @@ -20,6 +17,7 @@ import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; import { ViewType } from '@/views/types/ViewType'; import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; +import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations'; import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId'; import { type View } from '@/views/types/View'; @@ -106,33 +104,23 @@ const meta: Meta = { recordIndexId: instanceId, }} > - - - - - - - - - - - - - + + + + + + ); }, diff --git a/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordFieldsComponentFamilyState.ts b/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordFieldsComponentFamilyState.ts new file mode 100644 index 0000000000..34cb071eae --- /dev/null +++ b/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordFieldsComponentFamilyState.ts @@ -0,0 +1,9 @@ +import { RecordFieldsComponentInstanceContext } from '@/object-record/record-field/states/context/RecordFieldsComponentInstanceContext'; +import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; + +export const hasInitializedCurrentRecordFieldsComponentFamilyState = + createComponentFamilyState({ + key: 'hasInitializedCurrentRecordFieldsComponentFamilyState', + defaultValue: false, + componentInstanceContext: RecordFieldsComponentInstanceContext, + }); diff --git a/packages/twenty-front/src/modules/views/utils/areRecordFieldsEqual.ts b/packages/twenty-front/src/modules/views/utils/areRecordFieldsEqual.ts new file mode 100644 index 0000000000..f16e608a25 --- /dev/null +++ b/packages/twenty-front/src/modules/views/utils/areRecordFieldsEqual.ts @@ -0,0 +1,22 @@ +import { type RecordField } from '@/object-record/record-field/types/RecordField'; +import { compareStrictlyExceptForNullAndUndefined } from '~/utils/compareStrictlyExceptForNullAndUndefined'; + +export const areRecordFieldsEqual = ( + recordFieldA: RecordField, + recordFieldB: RecordField, +) => { + const propertiesToCompare: (keyof RecordField)[] = [ + 'fieldMetadataItemId', + 'isVisible', + 'position', + 'size', + 'aggregateOperation', + ]; + + return propertiesToCompare.every((property) => + compareStrictlyExceptForNullAndUndefined( + recordFieldA[property], + recordFieldB[property], + ), + ); +}; diff --git a/packages/twenty-front/src/modules/views/utils/mapViewFieldToRecordField.ts b/packages/twenty-front/src/modules/views/utils/mapViewFieldToRecordField.ts new file mode 100644 index 0000000000..ba0ebcbdb0 --- /dev/null +++ b/packages/twenty-front/src/modules/views/utils/mapViewFieldToRecordField.ts @@ -0,0 +1,15 @@ +import { type RecordField } from '@/object-record/record-field/types/RecordField'; +import { type ViewField } from '@/views/types/ViewField'; + +export const mapViewFieldToRecordField = (viewField: ViewField) => { + const recordField: RecordField = { + id: viewField.id, + fieldMetadataItemId: viewField.fieldMetadataId, + isVisible: viewField.isVisible, + position: viewField.position, + size: viewField.size, + aggregateOperation: viewField.aggregateOperation, + }; + + return recordField; +}; diff --git a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx index d7ac9c91f0..44f98df29a 100644 --- a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx +++ b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx @@ -5,12 +5,10 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/context import { TimelineActivityContext } from '@/activities/timeline-activities/contexts/TimelineActivityContext'; import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; -import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; +import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { RecordShowContainer } from '@/object-record/record-show/components/RecordShowContainer'; import { RecordShowEffect } from '@/object-record/record-show/components/RecordShowEffect'; import { computeRecordShowComponentInstanceId } from '@/object-record/record-show/utils/computeRecordShowComponentInstanceId'; -import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; import { PageHeaderToggleCommandMenuButton } from '@/ui/layout/page-header/components/PageHeaderToggleCommandMenuButton'; import { PageBody } from '@/ui/layout/page/components/PageBody'; import { PageContainer } from '@/ui/layout/page/components/PageContainer'; @@ -33,55 +31,47 @@ export const RecordShowPage = () => { computeRecordShowComponentInstanceId(objectRecordId); return ( - - - - - + + - - + + + + + - - - - - - - - - - - - - - - - + loading={false} + /> + + + + + + ); }; diff --git a/packages/twenty-front/src/testing/decorators/PageDecorator.tsx b/packages/twenty-front/src/testing/decorators/PageDecorator.tsx index ce7bf8d7aa..e57e462b1a 100644 --- a/packages/twenty-front/src/testing/decorators/PageDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/PageDecorator.tsx @@ -24,9 +24,7 @@ import { MainContextStoreProvider } from '@/context-store/components/MainContext import { RecoilDebugObserverEffect } from '@/debug/components/RecoilDebugObserver'; import { ObjectMetadataItemsLoadEffect } from '@/object-metadata/components/ObjectMetadataItemsLoadEffect'; import { ObjectMetadataItemsProvider } from '@/object-metadata/components/ObjectMetadataItemsProvider'; -import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; -import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; -import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; +import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { PrefetchDataProvider } from '@/prefetch/components/PrefetchDataProvider'; import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext'; import { WorkspaceProviderEffect } from '@/workspace/components/WorkspaceProviderEffect'; @@ -97,26 +95,11 @@ const Providers = () => { - - - - - - - + + diff --git a/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx b/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx index 0396c45dff..ce794ac3ce 100644 --- a/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx @@ -5,12 +5,10 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/context import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions'; -import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; -import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates'; -import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; import { RecordTableBodyContextProvider } from '@/object-record/record-table/contexts/RecordTableBodyContext'; import { RecordTableContextProvider, @@ -145,32 +143,24 @@ export const RecordTableDecorator: Decorator = (Story, context) => { - - - - - - - - - - - - + + + + + ); diff --git a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper.tsx b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper.tsx index 9821d06895..5b68c52cca 100644 --- a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper.tsx +++ b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper.tsx @@ -1,9 +1,7 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; -import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; +import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; -import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; import { type MockedResponse } from '@apollo/client/testing'; import { type ReactNode } from 'react'; import { type MutableSnapshot } from 'recoil'; @@ -51,58 +49,48 @@ export const getJestMetadataAndApolloMocksAndActionMenuWrapper = ({ return ({ children }: { children: ReactNode }) => ( - - - - 'indexIdentifierUrl', + onIndexRecordsLoaded: () => {}, + objectNamePlural: mockObjectMetadataItem.namePlural, + objectNameSingular: mockObjectMetadataItem.nameSingular, + objectMetadataItem: mockObjectMetadataItem, + recordIndexId: 'recordIndexId', + }} > - - 'indexIdentifierUrl', - onIndexRecordsLoaded: () => {}, - objectNamePlural: mockObjectMetadataItem.namePlural, - objectNameSingular: mockObjectMetadataItem.nameSingular, - objectMetadataItem: mockObjectMetadataItem, - recordIndexId: 'recordIndexId', - }} - > - - {children} - - - - - - - + {children} + + + + + ); }; diff --git a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksWrapper.tsx b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksWrapper.tsx index 87faba2ec7..aacb1852b1 100644 --- a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksWrapper.tsx +++ b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksWrapper.tsx @@ -1,12 +1,10 @@ import { MockedProvider, type MockedResponse } from '@apollo/client/testing'; import { type ReactNode } from 'react'; -import { type MutableSnapshot, RecoilRoot } from 'recoil'; +import { RecoilRoot, type MutableSnapshot } from 'recoil'; import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; -import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; -import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; +import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { type InMemoryCache } from '@apollo/client'; @@ -30,31 +28,21 @@ export const getJestMetadataAndApolloMocksWrapper = ({ value={{ instanceId: 'snack-bar-manager' }} > - - - - + - - - - {children} - - - - - - - + {children} + + + +