diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownButton.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownButton.tsx index 3b5672783..9abc6b784 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownButton.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownButton.tsx @@ -1,9 +1,8 @@ -import { useRecoilValue } from 'recoil'; - -import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { ObjectFilterDropdownScope } from '@/object-record/object-filter-dropdown/scopes/ObjectFilterDropdownScope'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState'; import { MultipleFiltersDropdownButton } from './MultipleFiltersDropdownButton'; import { SingleEntityObjectFilterDropdownButton } from './SingleEntityObjectFilterDropdownButton'; @@ -16,12 +15,9 @@ export const ObjectFilterDropdownButton = ({ filterDropdownId, hotkeyScope, }: ObjectFilterDropdownButtonProps) => { - const { availableFilterDefinitionsState } = useFilterDropdown({ - filterDropdownId: filterDropdownId, - }); - - const availableFilterDefinitions = useRecoilValue( - availableFilterDefinitionsState, + const availableFilterDefinitions = useRecoilComponentValueV2( + availableFilterDefinitionsComponentState, + filterDropdownId, ); const hasOnlyOneEntityFilter = diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect.tsx index caf6db621..59ee04d92 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect.tsx @@ -1,8 +1,6 @@ import styled from '@emotion/styled'; import { useState } from 'react'; -import { useRecoilValue } from 'recoil'; -import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { ObjectFilterDropdownFilterSelectMenuItem } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItem'; @@ -12,6 +10,8 @@ import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem'; import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState'; import { isDefined } from 'twenty-ui'; export const StyledInput = styled.input` @@ -43,10 +43,8 @@ export const StyledInput = styled.input` export const ObjectFilterDropdownFilterSelect = () => { const [searchText, setSearchText] = useState(''); - const { availableFilterDefinitionsState } = useFilterDropdown(); - - const availableFilterDefinitions = useRecoilValue( - availableFilterDefinitionsState, + const availableFilterDefinitions = useRecoilComponentValueV2( + availableFilterDefinitionsComponentState, ); const sortedAvailableFilterDefinitions = [...availableFilterDefinitions] diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx index 7546dc51c..ddaaf2e6a 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx @@ -7,7 +7,7 @@ import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types import { MultipleRecordSelectDropdown } from '@/object-record/select/components/MultipleRecordSelectDropdown'; import { useRecordsForSelect } from '@/object-record/select/hooks/useRecordsForSelect'; import { SelectableRecord } from '@/object-record/select/types/SelectableRecord'; -import { useCombinedViewFilters } from '@/views/hooks/useCombinedViewFilters'; +import { useDeleteCombinedViewFilters } from '@/views/hooks/useDeleteCombinedViewFilters'; import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; import { isDefined } from '~/utils/isDefined'; @@ -17,6 +17,7 @@ export const MAX_RECORDS_TO_DISPLAY = 3; type ObjectFilterDropdownRecordSelectProps = { viewComponentId?: string; }; + export const ObjectFilterDropdownRecordSelect = ({ viewComponentId, }: ObjectFilterDropdownRecordSelectProps) => { @@ -31,7 +32,9 @@ export const ObjectFilterDropdownRecordSelect = ({ emptyFilterButKeepDefinition, } = useFilterDropdown(); - const { removeCombinedViewFilter } = useCombinedViewFilters(viewComponentId); + const { deleteCombinedViewFilter } = + useDeleteCombinedViewFilters(viewComponentId); + const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView(viewComponentId); @@ -78,7 +81,7 @@ export const ObjectFilterDropdownRecordSelect = ({ if (newSelectedRecordIds.length === 0) { emptyFilterButKeepDefinition(); - removeCombinedViewFilter(fieldId); + deleteCombinedViewFilter(fieldId); return; } diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/SingleEntityObjectFilterDropdownButton.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/SingleEntityObjectFilterDropdownButton.tsx index 5f57a990d..ddfb5125b 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/SingleEntityObjectFilterDropdownButton.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/SingleEntityObjectFilterDropdownButton.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { useTheme } from '@emotion/react'; +import React from 'react'; import { useRecoilValue } from 'recoil'; import { IconChevronDown } from 'twenty-ui'; @@ -11,8 +11,9 @@ import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/Styl import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState'; import { getOperandsForFilterType } from '../utils/getOperandsForFilterType'; - import { GenericEntityFilterChip } from './GenericEntityFilterChip'; import { ObjectFilterDropdownRecordSelect } from './ObjectFilterDropdownRecordSelect'; import { ObjectFilterDropdownSearchInput } from './ObjectFilterDropdownSearchInput'; @@ -25,14 +26,13 @@ export const SingleEntityObjectFilterDropdownButton = ({ hotkeyScope: HotkeyScope; }) => { const { - availableFilterDefinitionsState, selectedFilterState, setFilterDefinitionUsedInDropdown, setSelectedOperandInDropdown, } = useFilterDropdown(); - const availableFilterDefinitions = useRecoilValue( - availableFilterDefinitionsState, + const availableFilterDefinitions = useRecoilComponentValueV2( + availableFilterDefinitionsComponentState, ); const selectedFilter = useRecoilValue(selectedFilterState); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/__stories__/MultipleFiltersDropdownButton.stories.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/__stories__/MultipleFiltersDropdownButton.stories.tsx index c09981493..b97deda7b 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/__stories__/MultipleFiltersDropdownButton.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/__stories__/MultipleFiltersDropdownButton.stories.tsx @@ -2,8 +2,10 @@ import { Meta, StoryObj } from '@storybook/react'; import { TaskGroups } from '@/activities/tasks/components/TaskGroups'; import { MultipleFiltersDropdownButton } from '@/object-record/object-filter-dropdown/components/MultipleFiltersDropdownButton'; -import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { ObjectFilterDropdownScope } from '@/object-record/object-filter-dropdown/scopes/ObjectFilterDropdownScope'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; +import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState'; +import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { within } from '@storybook/test'; import { ComponentDecorator } from 'twenty-ui'; import { FieldMetadataType } from '~/generated/graphql'; @@ -17,9 +19,12 @@ const meta: Meta = { component: MultipleFiltersDropdownButton, decorators: [ (Story) => { - const { setAvailableFilterDefinitions } = useFilterDropdown({ - filterDropdownId: 'entity-tasks-filter-scope', - }); + const instanceId = 'entity-tasks-filter-scope'; + const setAvailableFilterDefinitions = useSetRecoilComponentStateV2( + availableFilterDefinitionsComponentState, + instanceId, + ); + setAvailableFilterDefinitions([ { fieldMetadataId: '1', @@ -47,9 +52,11 @@ const meta: Meta = { }, ]); return ( - - - + + + + + ); }, ObjectMetadataItemsDecorator, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/__tests__/useFilterDropdown.test.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/__tests__/useFilterDropdown.test.tsx index 91aed0b40..b69584cb3 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/__tests__/useFilterDropdown.test.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/__tests__/useFilterDropdown.test.tsx @@ -6,6 +6,8 @@ import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/ import { useFilterDropdownStates } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdownStates'; import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; +import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; const filterDropdownId = 'filterDropdownId'; @@ -35,11 +37,13 @@ describe('useFilterDropdown', () => { it('should set availableFilterDefinitions', async () => { const { result } = renderHook(() => { useFilterDropdown({ filterDropdownId }); - const { availableFilterDefinitionsState } = - useFilterDropdownStates(filterDropdownId); const [availableFilterDefinitions, setAvailableFilterDefinitions] = - useRecoilState(availableFilterDefinitionsState); + useRecoilComponentStateV2( + availableFilterDefinitionsComponentState, + filterDropdownId, + ); + return { availableFilterDefinitions, setAvailableFilterDefinitions }; }, renderHookConfig); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useFilterDropdown.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useFilterDropdown.ts index 8325af5e8..b09d33a38 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useFilterDropdown.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useFilterDropdown.ts @@ -18,7 +18,6 @@ export const useFilterDropdown = (props?: UseFilterDropdownProps) => { ); const { - availableFilterDefinitionsState, filterDefinitionUsedInDropdownState, objectFilterDropdownSearchInputState, objectFilterDropdownSelectedRecordIdsState, @@ -73,9 +72,6 @@ export const useFilterDropdown = (props?: UseFilterDropdownProps) => { ], ); - const setAvailableFilterDefinitions = useSetRecoilState( - availableFilterDefinitionsState, - ); const setSelectedFilter = useSetRecoilState(selectedFilterState); const setSelectedOperandInDropdown = useSetRecoilState( selectedOperandInDropdownState, @@ -106,7 +102,6 @@ export const useFilterDropdown = (props?: UseFilterDropdownProps) => { resetFilter, setSelectedFilter, setSelectedOperandInDropdown, - setAvailableFilterDefinitions, setFilterDefinitionUsedInDropdown, setObjectFilterDropdownSearchInput, // setObjectFilterDropdownSelectedEntityId, @@ -116,7 +111,6 @@ export const useFilterDropdown = (props?: UseFilterDropdownProps) => { setIsObjectFilterDropdownUnfolded, setOnFilterSelect, emptyFilterButKeepDefinition, - availableFilterDefinitionsState, filterDefinitionUsedInDropdownState, objectFilterDropdownSearchInputState, // objectFilterDropdownSelectedEntityIdState, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useFilterDropdownStates.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useFilterDropdownStates.ts index 82888840c..8d9e5f1d0 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useFilterDropdownStates.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useFilterDropdownStates.ts @@ -8,14 +8,8 @@ import { onFilterSelectComponentState } from '@/object-record/object-filter-drop import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; -import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState'; export const useFilterDropdownStates = (scopeId: string) => { - const availableFilterDefinitionsState = extractComponentState( - availableFilterDefinitionsComponentState, - scopeId, - ); - const filterDefinitionUsedInDropdownState = extractComponentState( filterDefinitionUsedInDropdownComponentState, scopeId, @@ -63,7 +57,6 @@ export const useFilterDropdownStates = (scopeId: string) => { ); return { - availableFilterDefinitionsState, filterDefinitionUsedInDropdownState, objectFilterDropdownSearchInputState, objectFilterDropdownSelectedRecordIdsState, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/scopes/scope-internal-context/ObjectFilterDropdownScopeInternalContext.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/scopes/scope-internal-context/ObjectFilterDropdownScopeInternalContext.ts index 1c29844bd..be81417c1 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/scopes/scope-internal-context/ObjectFilterDropdownScopeInternalContext.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/scopes/scope-internal-context/ObjectFilterDropdownScopeInternalContext.ts @@ -1,7 +1,7 @@ import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; -type ObjectFilterDropdownScopeInternalContextProps = ComponentStateKey; +type ObjectFilterDropdownScopeInternalContextProps = RecoilComponentStateKey; export const ObjectFilterDropdownScopeInternalContext = createScopeInternalContext(); diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/__tests__/useSortDropdown.test.tsx b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/__tests__/useSortDropdown.test.tsx index 6bf6ddf0d..64de66d89 100644 --- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/__tests__/useSortDropdown.test.tsx +++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/__tests__/useSortDropdown.test.tsx @@ -6,6 +6,8 @@ import { useSortDropdown } from '@/object-record/object-sort-dropdown/hooks/useS import { useSortDropdownStates } from '@/object-record/object-sort-dropdown/hooks/useSortDropdownStates'; import { Sort } from '@/object-record/object-sort-dropdown/types/Sort'; import { SortDefinition } from '@/object-record/object-sort-dropdown/types/SortDefinition'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; +import { availableSortDefinitionsComponentState } from '@/views/states/availableSortDefinitionsComponentState'; const Wrapper = ({ children }: { children: React.ReactNode }) => ( {children} @@ -24,11 +26,13 @@ describe('useSortDropdown', () => { it('should set availableSortDefinitions', async () => { const { result } = renderHook(() => { useSortDropdown({ sortDropdownId }); - const { availableSortDefinitionsState } = - useSortDropdownStates(sortDropdownId); + // TODO: verify this instance id works const [availableSortDefinitions, setAvailableSortDefinitions] = - useRecoilState(availableSortDefinitionsState); + useRecoilComponentStateV2( + availableSortDefinitionsComponentState, + sortDropdownId, + ); return { availableSortDefinitions, diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useObjectSortDropdown.ts b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useObjectSortDropdown.ts index 4a797a259..2cbe44c58 100644 --- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useObjectSortDropdown.ts +++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useObjectSortDropdown.ts @@ -7,6 +7,8 @@ import selectedSortDirectionState from '@/object-record/object-sort-dropdown/sta import { SortDefinition } from '@/object-record/object-sort-dropdown/types/SortDefinition'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { availableSortDefinitionsComponentState } from '@/views/states/availableSortDefinitionsComponentState'; import { OBJECT_SORT_DROPDOWN_ID, VIEW_SORT_DROPDOWN_ID, @@ -41,7 +43,6 @@ export const useObjectSortDropdown = () => { }; const { - availableSortDefinitionsState, onSortSelectState, isSortSelectedState, objectSortDropdownSearchInputState, @@ -52,8 +53,10 @@ export const useObjectSortDropdown = () => { }); const isSortSelected = useRecoilValue(isSortSelectedState); - const availableSortDefinitions = useRecoilValue( - availableSortDefinitionsState, + + const availableSortDefinitions = useRecoilComponentValueV2( + availableSortDefinitionsComponentState, + VIEW_SORT_DROPDOWN_ID, ); const onSortSelect = useRecoilValue(onSortSelectState); diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useSortDropdown.ts b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useSortDropdown.ts index 44373f1fa..3a857e28c 100644 --- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useSortDropdown.ts +++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useSortDropdown.ts @@ -14,8 +14,8 @@ export const useSortDropdown = (props?: UseSortProps) => { ObjectSortDropdownScopeInternalContext, props?.sortDropdownId, ); + const { - availableSortDefinitionsState, isSortSelectedState, onSortSelectState, objectSortDropdownSearchInputState, @@ -35,7 +35,6 @@ export const useSortDropdown = (props?: UseSortProps) => { return { scopeId, - availableSortDefinitionsState, isSortSelectedState, onSortSelectState, objectSortDropdownSearchInputState, diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useSortDropdownStates.ts b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useSortDropdownStates.ts index b36788076..40eb5623e 100644 --- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useSortDropdownStates.ts +++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useSortDropdownStates.ts @@ -2,14 +2,8 @@ import { isSortSelectedComponentState } from '@/object-record/object-sort-dropdo import { objectSortDropdownSearchInputComponentState } from '@/object-record/object-sort-dropdown/states/objectSortDropdownSearchInputComponentState'; import { onSortSelectComponentState } from '@/object-record/object-sort-dropdown/states/onSortSelectScopedState'; import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; -import { availableSortDefinitionsComponentState } from '@/views/states/availableSortDefinitionsComponentState'; export const useSortDropdownStates = (scopeId: string) => { - const availableSortDefinitionsState = extractComponentState( - availableSortDefinitionsComponentState, - scopeId, - ); - const isSortSelectedState = extractComponentState( isSortSelectedComponentState, scopeId, @@ -26,7 +20,6 @@ export const useSortDropdownStates = (scopeId: string) => { ); return { - availableSortDefinitionsState, isSortSelectedState, onSortSelectState, objectSortDropdownSearchInputState, diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/scopes/scope-internal-context/ObjectSortDropdownScopeInternalContext.ts b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/scopes/scope-internal-context/ObjectSortDropdownScopeInternalContext.ts index 8454813f3..35a7798bc 100644 --- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/scopes/scope-internal-context/ObjectSortDropdownScopeInternalContext.ts +++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/scopes/scope-internal-context/ObjectSortDropdownScopeInternalContext.ts @@ -1,9 +1,9 @@ import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; import { Sort } from '../../types/Sort'; -type ObjectSortDropdownScopeInternalContextProps = ComponentStateKey & { +type ObjectSortDropdownScopeInternalContextProps = RecoilComponentStateKey & { onSortSelect?: (sort: Sort) => void; }; diff --git a/packages/twenty-front/src/modules/object-record/record-board/scopes/scope-internal-context/RecordBoardScopeInternalContext.ts b/packages/twenty-front/src/modules/object-record/record-board/scopes/scope-internal-context/RecordBoardScopeInternalContext.ts index 22aeae0ed..44ac1e08e 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/scopes/scope-internal-context/RecordBoardScopeInternalContext.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/scopes/scope-internal-context/RecordBoardScopeInternalContext.ts @@ -2,9 +2,9 @@ import { RecordBoardColumnDefinition } from '@/object-record/record-board/types/ import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition'; import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; -type RecordBoardScopeInternalContextProps = ComponentStateKey & { +type RecordBoardScopeInternalContextProps = RecoilComponentStateKey & { onFieldsChange: (fields: FieldDefinition[]) => void; onColumnsChange: (column: RecordBoardColumnDefinition[]) => void; }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/useInitDraftValueV2.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/useInitDraftValueV2.ts index 5c7f8fb2d..f3847113f 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/hooks/useInitDraftValueV2.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/useInitDraftValueV2.ts @@ -27,7 +27,7 @@ export const useInitDraftValueV2 = () => { const recordFieldInputScopeId = `${getRecordFieldInputId( recordId, fieldDefinition?.metadata?.fieldName, - )}-scope`; + )}`; const getDraftValueSelector = extractComponentSelector< FieldInputDraftValue | undefined diff --git a/packages/twenty-front/src/modules/object-record/record-field/scopes/scope-internal-context/RecordFieldInputScopeInternalContext.ts b/packages/twenty-front/src/modules/object-record/record-field/scopes/scope-internal-context/RecordFieldInputScopeInternalContext.ts index eebf6c22d..94769746b 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/scopes/scope-internal-context/RecordFieldInputScopeInternalContext.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/scopes/scope-internal-context/RecordFieldInputScopeInternalContext.ts @@ -1,7 +1,7 @@ import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; -type RecordFieldInputScopeInternalContextProps = ComponentStateKey; +type RecordFieldInputScopeInternalContextProps = RecoilComponentStateKey; export const RecordFieldInputScopeInternalContext = createScopeInternalContext(); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx index e8cdaa20f..3af323792 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx @@ -24,6 +24,7 @@ import { RecordFieldValueSelectorContextProvider } from '@/object-record/record- import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider'; import { ViewBar } from '@/views/components/ViewBar'; +import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { ViewField } from '@/views/types/ViewField'; import { ViewType } from '@/views/types/ViewType'; import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions'; @@ -107,81 +108,91 @@ export const RecordIndexContainer = () => { return ( - - - - - } - onCurrentViewChange={(view) => { - if (!view) { - return; + + + + + } + onCurrentViewChange={(view) => { + if (!view) { + return; + } - onViewFieldsChange(view.viewFields); - setTableFilters( - mapViewFiltersToFilters(view.viewFilters, filterDefinitions), - ); - setRecordIndexFilters( - mapViewFiltersToFilters(view.viewFilters, filterDefinitions), - ); - setTableSorts( - mapViewSortsToSorts(view.viewSorts, sortDefinitions), - ); - setRecordIndexSorts( - mapViewSortsToSorts(view.viewSorts, sortDefinitions), - ); - setRecordIndexViewType(view.type); - setRecordIndexViewKanbanFieldMetadataIdState( - view.kanbanFieldMetadataId, - ); - setRecordIndexIsCompactModeActive(view.isCompact); - }} - /> - - - + onViewFieldsChange(view.viewFields); + setTableFilters( + mapViewFiltersToFilters( + view.viewFilters, + filterDefinitions, + ), + ); + setRecordIndexFilters( + mapViewFiltersToFilters( + view.viewFilters, + filterDefinitions, + ), + ); + setTableSorts( + mapViewSortsToSorts(view.viewSorts, sortDefinitions), + ); + setRecordIndexSorts( + mapViewSortsToSorts(view.viewSorts, sortDefinitions), + ); + setRecordIndexViewType(view.type); + setRecordIndexViewKanbanFieldMetadataIdState( + view.kanbanFieldMetadataId, + ); + setRecordIndexIsCompactModeActive(view.isCompact); + }} + /> + + + - {recordIndexViewType === ViewType.Table && ( - <> - - - - )} - {recordIndexViewType === ViewType.Kanban && ( - - - - - - )} - + {recordIndexViewType === ViewType.Table && ( + <> + + + + )} + {recordIndexViewType === ViewType.Kanban && ( + + + + + + )} + + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx index efe7e4cb9..1a16e7fee 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx @@ -2,7 +2,7 @@ import { useRecoilState } from 'recoil'; import { isRemoveSortingModalOpenState } from '@/object-record/record-table/states/isRemoveSortingModalOpenState'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; -import { useCombinedViewSorts } from '@/views/hooks/useCombinedViewSorts'; +import { useDeleteCombinedViewSorts } from '@/views/hooks/useDeleteCombinedViewSorts'; import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; export const RecordIndexRemoveSortingModal = ({ @@ -21,11 +21,11 @@ export const RecordIndexRemoveSortingModal = ({ isRemoveSortingModalOpenState, ); - const { removeCombinedViewSort } = useCombinedViewSorts(recordTableId); + const { deleteCombinedViewSort } = useDeleteCombinedViewSorts(recordTableId); const handleRemoveClick = () => { fieldMetadataIds.forEach((id) => { - removeCombinedViewSort(id); + deleteCombinedViewSort(id); }); }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx index 32ae2ffc5..428537f69 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx @@ -8,8 +8,9 @@ import { useHandleToggleColumnFilter } from '@/object-record/record-index/hooks/ import { useHandleToggleColumnSort } from '@/object-record/record-index/hooks/useHandleToggleColumnSort'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; -import { useViewStates } from '@/views/hooks/internal/useViewStates'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useSetRecordCountInCurrentView } from '@/views/hooks/useSetRecordCountInCurrentView'; +import { entityCountInCurrentViewComponentState } from '@/views/states/entityCountInCurrentViewComponentState'; type RecordIndexTableContainerEffectProps = { objectNameSingular: string; @@ -50,9 +51,10 @@ export const RecordIndexTableContainerEffect = ({ const { tableRowIdsState, hasUserSelectedAllRowsState } = useRecordTableStates(recordTableId); - const { entityCountInCurrentViewState } = useViewStates(recordTableId); - const entityCountInCurrentView = useRecoilValue( - entityCountInCurrentViewState, + // TODO: verify this instance id works + const entityCountInCurrentView = useRecoilComponentValueV2( + entityCountInCurrentViewComponentState, + recordTableId, ); const hasUserSelectedAllRows = useRecoilValue(hasUserSelectedAllRowsState); const tableRowIds = useRecoilValue(tableRowIdsState); diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleIndexIdentifierClick.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleIndexIdentifierClick.ts index a72fda64b..2ea5bcdc4 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleIndexIdentifierClick.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleIndexIdentifierClick.ts @@ -1,8 +1,8 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { buildShowPageURL } from '@/object-record/record-show/utils/buildShowPageURL'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState'; import { useNavigate } from 'react-router-dom'; -import { useRecoilValue } from 'recoil'; export const useHandleIndexIdentifierClick = ({ objectMetadataItem, @@ -13,10 +13,9 @@ export const useHandleIndexIdentifierClick = ({ }) => { const navigate = useNavigate(); - const currentViewId = useRecoilValue( - currentViewIdComponentState({ - scopeId: recordIndexId, - }), + const currentViewId = useRecoilComponentValueV2( + currentViewIdComponentState, + recordIndexId, ); const handleIndexIdentifierClick = (recordId: string) => { diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnFilter.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnFilter.ts index 18997fbad..41d4fc49d 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnFilter.ts @@ -7,7 +7,7 @@ import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldM import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; import { getOperandsForFilterType } from '@/object-record/object-filter-dropdown/utils/getOperandsForFilterType'; import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2'; -import { useCombinedViewFilters } from '@/views/hooks/useCombinedViewFilters'; +import { useUpsertCombinedViewFilters } from '@/views/hooks/useUpsertCombinedViewFilters'; import { isDefined } from '~/utils/isDefined'; type UseHandleToggleColumnFilterProps = { @@ -26,7 +26,7 @@ export const useHandleToggleColumnFilter = ({ const { columnDefinitions } = useColumnDefinitionsFromFieldMetadata(objectMetadataItem); - const { upsertCombinedViewFilter } = useCombinedViewFilters(viewBarId); + const { upsertCombinedViewFilter } = useUpsertCombinedViewFilters(viewBarId); const { openDropdown } = useDropdownV2(); const handleToggleColumnFilter = useCallback( diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnSort.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnSort.ts index a5253a49e..b285fe345 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnSort.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnSort.ts @@ -3,7 +3,7 @@ import { useCallback } from 'react'; import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { Sort } from '@/object-record/object-sort-dropdown/types/Sort'; -import { useCombinedViewSorts } from '@/views/hooks/useCombinedViewSorts'; +import { useUpsertCombinedViewSorts } from '@/views/hooks/useUpsertCombinedViewSorts'; import { isDefined } from '~/utils/isDefined'; type UseHandleToggleColumnSortProps = { @@ -22,7 +22,7 @@ export const useHandleToggleColumnSort = ({ const { columnDefinitions } = useColumnDefinitionsFromFieldMetadata(objectMetadataItem); - const { upsertCombinedViewSort } = useCombinedViewSorts(viewBarId); + const { upsertCombinedViewSort } = useUpsertCombinedViewSorts(viewBarId); const handleToggleColumnSort = useCallback( (fieldMetadataId: string) => { diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts index bbe862c0a..31dac4ae7 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts @@ -6,7 +6,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; -import { useCombinedViewFilters } from '@/views/hooks/useCombinedViewFilters'; +import { useUpsertCombinedViewFilters } from '@/views/hooks/useUpsertCombinedViewFilters'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { useRecoilCallback } from 'recoil'; import { isDefined } from '~/utils/isDefined'; @@ -27,7 +27,7 @@ export const useHandleToggleTrashColumnFilter = ({ const { columnDefinitions } = useColumnDefinitionsFromFieldMetadata(objectMetadataItem); - const { upsertCombinedViewFilter } = useCombinedViewFilters(viewBarId); + const { upsertCombinedViewFilter } = useUpsertCombinedViewFilters(viewBarId); const { isSoftDeleteActiveState } = useRecordTableStates(viewBarId); const handleToggleTrashColumnFilter = useCallback(() => { diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useTableData.test.tsx b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useTableData.test.tsx index 3d0ce75a0..bac46e652 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useTableData.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useTableData.test.tsx @@ -1,10 +1,10 @@ -import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; import { act, renderHook, waitFor } from '@testing-library/react'; import { percentage, sleep, useTableData } from '../useTableData'; import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard'; import { recordBoardKanbanFieldMetadataNameComponentState } from '@/object-record/record-board/states/recordBoardKanbanFieldMetadataNameComponentState'; import { useRecordIndexOptionsForBoard } from '@/object-record/record-index/options/hooks/useRecordIndexOptionsForBoard'; +import { SnackBarManagerScopeInternalContext } from '@/ui/feedback/snack-bar-manager/scopes/scope-internal-context/SnackBarManagerScopeInternalContext'; import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; import { ViewType } from '@/views/types/ViewType'; import { MockedProvider, MockedResponse } from '@apollo/client/testing'; @@ -148,15 +148,19 @@ const mocks: MockedResponse[] = [ ]; const Wrapper = ({ children }: { children: ReactNode }) => ( - - - + + + {children} - - - + + + ); const graphqlEmptyResponse = [ @@ -174,15 +178,19 @@ const graphqlEmptyResponse = [ ]; const WrapperWithEmptyResponse = ({ children }: { children: ReactNode }) => ( - - - + + + {children} - - - + + + ); describe('useTableData', () => { @@ -191,13 +199,13 @@ describe('useTableData', () => { describe('data fetching', () => { it('should handle no records', async () => { const callback = jest.fn(); + const { result } = renderHook( () => useTableData({ recordIndexId, objectNameSingular, callback, - delayMs: 0, viewType: ViewType.Kanban, }), @@ -209,7 +217,7 @@ describe('useTableData', () => { }); await waitFor(() => { - expect(callback).toHaveBeenCalledWith([], []); + expect(callback).not.toHaveBeenCalled(); }); }); diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useRecordIndexOptionsForBoard.ts b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useRecordIndexOptionsForBoard.ts index 9e1c2b28b..c3d5e87d9 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useRecordIndexOptionsForBoard.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useRecordIndexOptionsForBoard.ts @@ -1,5 +1,5 @@ -import { useCallback, useMemo } from 'react'; import { OnDragEndResponder } from '@hello-pangea/dnd'; +import { useCallback, useMemo } from 'react'; import { useRecoilState } from 'recoil'; import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata'; @@ -8,8 +8,8 @@ import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoar import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState'; import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; -import { useHandleViews } from '@/views/hooks/useHandleViews'; import { useSaveCurrentViewFields } from '@/views/hooks/useSaveCurrentViewFields'; +import { useUpdateCurrentView } from '@/views/hooks/useUpdateCurrentView'; import { GraphQLView } from '@/views/types/GraphQLView'; import { mapBoardFieldDefinitionsToViewFields } from '@/views/utils/mapBoardFieldDefinitionsToViewFields'; import { mapArrayToObject } from '~/utils/array/mapArrayToObject'; @@ -31,7 +31,7 @@ export const useRecordIndexOptionsForBoard = ({ useRecoilState(recordIndexFieldDefinitionsState); const { saveViewFields } = useSaveCurrentViewFields(viewBarId); - const { updateCurrentView } = useHandleViews(viewBarId); + const { updateCurrentView } = useUpdateCurrentView(viewBarId); const { isCompactModeActiveState } = useRecordBoard(recordBoardId); const [isCompactModeActive, setIsCompactModeActive] = useRecoilState( diff --git a/packages/twenty-front/src/modules/object-record/record-table/action-bar/components/RecordTableActionBar.tsx b/packages/twenty-front/src/modules/object-record/record-table/action-bar/components/RecordTableActionBar.tsx index f41025398..0b2c810bc 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/action-bar/components/RecordTableActionBar.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/action-bar/components/RecordTableActionBar.tsx @@ -2,7 +2,8 @@ import { useRecoilValue } from 'recoil'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { ActionBar } from '@/ui/navigation/action-bar/components/ActionBar'; -import { useViewStates } from '@/views/hooks/internal/useViewStates'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { entityCountInCurrentViewComponentState } from '@/views/states/entityCountInCurrentViewComponentState'; export const RecordTableActionBar = ({ recordTableId, @@ -15,10 +16,12 @@ export const RecordTableActionBar = ({ hasUserSelectedAllRowsState, } = useRecordTableStates(recordTableId); - const { entityCountInCurrentViewState } = useViewStates(recordTableId); - const entityCountInCurrentView = useRecoilValue( - entityCountInCurrentViewState, + // TODO: verify this instance id works + const entityCountInCurrentView = useRecoilComponentValueV2( + entityCountInCurrentViewComponentState, + recordTableId, ); + const hasUserSelectedAllRows = useRecoilValue(hasUserSelectedAllRowsState); const tableRowIds = useRecoilValue(tableRowIdsState); const selectedRowIds = useRecoilValue(selectedRowIdsSelector()); diff --git a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyStateSoftDelete.tsx b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyStateSoftDelete.tsx index 6954b6044..71eb045ab 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyStateSoftDelete.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyStateSoftDelete.tsx @@ -5,7 +5,7 @@ import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/h import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; import { RecordTableEmptyStateDisplay } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; -import { useCombinedViewFilters } from '@/views/hooks/useCombinedViewFilters'; +import { useDeleteCombinedViewFilters } from '@/views/hooks/useDeleteCombinedViewFilters'; import { useContext } from 'react'; import { useRecoilValue } from 'recoil'; @@ -13,7 +13,8 @@ export const RecordTableEmptyStateSoftDelete = () => { const { objectMetadataItem, objectNameSingular, recordTableId } = useContext(RecordTableContext); - const { removeCombinedViewFilter } = useCombinedViewFilters(recordTableId); + const { deleteCombinedViewFilter } = + useDeleteCombinedViewFilters(recordTableId); const { tableFiltersState } = useRecordTableStates(recordTableId); const tableFilters = useRecoilValue(tableFiltersState); @@ -24,7 +25,7 @@ export const RecordTableEmptyStateSoftDelete = () => { }); const handleButtonClick = async () => { - removeCombinedViewFilter( + deleteCombinedViewFilter( tableFilters.find( (filter) => filter.definition.label === 'Deleted at' && diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useSelectedTableCellEditMode.test.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useSelectedTableCellEditMode.test.tsx index 1e7ec2088..23b7e3b00 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useSelectedTableCellEditMode.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useSelectedTableCellEditMode.test.tsx @@ -48,14 +48,14 @@ describe('useSelectedTableCellEditMode', () => { expect(mockCallbackInterface.set).toHaveBeenCalledWith( { - key: 'isTableCellInEditModeComponentFamilyState__{"familyKey":{"column":0,"row":0},"scopeId":"yourScopeId-scope"}', + key: 'isTableCellInEditModeComponentFamilyState__{"familyKey":{"column":0,"row":0},"scopeId":"yourScopeId"}', }, false, ); expect(mockCallbackInterface.set).toHaveBeenCalledWith( { - key: 'isTableCellInEditModeComponentFamilyState__{"familyKey":{"column":5,"row":1},"scopeId":"yourScopeId-scope"}', + key: 'isTableCellInEditModeComponentFamilyState__{"familyKey":{"column":5,"row":1},"scopeId":"yourScopeId"}', }, true, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext.ts b/packages/twenty-front/src/modules/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext.ts index 40e3e30c2..1665e2b96 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext.ts @@ -1,11 +1,11 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; import { ColumnDefinition } from '../../types/ColumnDefinition'; // TODO: separate scope contexts from event contexts -type RecordTableScopeInternalContextProps = ComponentStateKey & { +type RecordTableScopeInternalContextProps = RecoilComponentStateKey & { onColumnsChange: (columns: ColumnDefinition[]) => void; }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2.ts b/packages/twenty-front/src/modules/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2.ts index f8b6716a8..9cd066b84 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2.ts @@ -1,8 +1,8 @@ import { RecordTableScopeInternalContext } from '@/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext'; -import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; +import { createComponentStateV2_alpha } from '@/ui/utilities/state/component-state/utils/createComponentStateV2_alpha'; export const hasRecordTableFetchedAllRecordsComponentStateV2 = - createComponentStateV2({ + createComponentStateV2_alpha({ key: 'hasRecordTableFetchedAllRecordsComponentStateV2', componentContext: RecordTableScopeInternalContext, defaultValue: false, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledLeftComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledLeftComponentState.ts index 6f26d8a60..b51a7f63f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledLeftComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledLeftComponentState.ts @@ -1,8 +1,8 @@ import { RecordTableScopeInternalContext } from '@/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext'; -import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; +import { createComponentStateV2_alpha } from '@/ui/utilities/state/component-state/utils/createComponentStateV2_alpha'; export const isRecordTableScrolledLeftComponentState = - createComponentStateV2({ + createComponentStateV2_alpha({ key: 'isRecordTableScrolledLeftComponentState', componentContext: RecordTableScopeInternalContext, defaultValue: true, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledTopComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledTopComponentState.ts index 564c567a6..5a206e88b 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledTopComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledTopComponentState.ts @@ -1,8 +1,8 @@ import { RecordTableScopeInternalContext } from '@/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext'; -import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; +import { createComponentStateV2_alpha } from '@/ui/utilities/state/component-state/utils/createComponentStateV2_alpha'; export const isRecordTableScrolledTopComponentState = - createComponentStateV2({ + createComponentStateV2_alpha({ key: 'isRecordTableScrolledTopComponentState', componentContext: RecordTableScopeInternalContext, defaultValue: true, diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext.ts b/packages/twenty-front/src/modules/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext.ts index 3dbbfc7ef..eda26d3f1 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext.ts +++ b/packages/twenty-front/src/modules/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext.ts @@ -1,7 +1,7 @@ import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; -type RelationPickerScopeInternalContextProps = ComponentStateKey; +type RelationPickerScopeInternalContextProps = RecoilComponentStateKey; export const RelationPickerScopeInternalContext = createScopeInternalContext(); 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 da43d1ee0..1ce2f5aff 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 @@ -4,6 +4,7 @@ import { RecordIndexOptionsDropdown } from '@/object-record/record-index/options import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers'; import { SignInBackgroundMockContainerEffect } from '@/sign-in-background-mock/components/SignInBackgroundMockContainerEffect'; import { ViewBar } from '@/views/components/ViewBar'; +import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { ViewType } from '@/views/types/ViewType'; const StyledContainer = styled.div` @@ -21,28 +22,30 @@ export const SignInBackgroundMockContainer = () => { return ( - {}} - optionsDropdownButton={ - - } - /> - - {}} - /> + + {}} + optionsDropdownButton={ + + } + /> + + {}} + /> + ); }; diff --git a/packages/twenty-front/src/modules/ui/feedback/dialog-manager/scopes/scope-internal-context/DialogManagerScopeInternalContext.ts b/packages/twenty-front/src/modules/ui/feedback/dialog-manager/scopes/scope-internal-context/DialogManagerScopeInternalContext.ts index fb6183db8..8620b0d28 100644 --- a/packages/twenty-front/src/modules/ui/feedback/dialog-manager/scopes/scope-internal-context/DialogManagerScopeInternalContext.ts +++ b/packages/twenty-front/src/modules/ui/feedback/dialog-manager/scopes/scope-internal-context/DialogManagerScopeInternalContext.ts @@ -1,7 +1,7 @@ import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; -type DialogManagerScopeInternalContextProps = ComponentStateKey; +type DialogManagerScopeInternalContextProps = RecoilComponentStateKey; export const DialogManagerScopeInternalContext = createScopeInternalContext(); diff --git a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/scopes/scope-internal-context/SnackBarManagerScopeInternalContext.ts b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/scopes/scope-internal-context/SnackBarManagerScopeInternalContext.ts index 75b7e1e13..c9686c2d2 100644 --- a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/scopes/scope-internal-context/SnackBarManagerScopeInternalContext.ts +++ b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/scopes/scope-internal-context/SnackBarManagerScopeInternalContext.ts @@ -1,7 +1,7 @@ import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; -type SnackBarManagerScopeInternalContextProps = ComponentStateKey; +type SnackBarManagerScopeInternalContextProps = RecoilComponentStateKey; export const SnackBarManagerScopeInternalContext = createScopeInternalContext(); diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/scopes/scope-internal-context/DropdownScopeInternalContext.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/scopes/scope-internal-context/DropdownScopeInternalContext.ts index 0d117b23f..ed9516be6 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/scopes/scope-internal-context/DropdownScopeInternalContext.ts +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/scopes/scope-internal-context/DropdownScopeInternalContext.ts @@ -1,7 +1,7 @@ import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; -type DropdownScopeInternalContextProps = ComponentStateKey; +type DropdownScopeInternalContextProps = RecoilComponentStateKey; export const DropdownScopeInternalContext = createScopeInternalContext(); diff --git a/packages/twenty-front/src/modules/ui/layout/selectable-list/scopes/scope-internal-context/SelectableListScopeInternalContext.ts b/packages/twenty-front/src/modules/ui/layout/selectable-list/scopes/scope-internal-context/SelectableListScopeInternalContext.ts index c347ce3f0..b28f36103 100644 --- a/packages/twenty-front/src/modules/ui/layout/selectable-list/scopes/scope-internal-context/SelectableListScopeInternalContext.ts +++ b/packages/twenty-front/src/modules/ui/layout/selectable-list/scopes/scope-internal-context/SelectableListScopeInternalContext.ts @@ -1,7 +1,7 @@ import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; -type SelectableListScopeInternalContextProps = ComponentStateKey; +type SelectableListScopeInternalContextProps = RecoilComponentStateKey; export const SelectableListScopeInternalContext = createScopeInternalContext(); diff --git a/packages/twenty-front/src/modules/ui/layout/tab/hooks/useTabList.ts b/packages/twenty-front/src/modules/ui/layout/tab/hooks/useTabList.ts index 9925dec4c..0021c89fb 100644 --- a/packages/twenty-front/src/modules/ui/layout/tab/hooks/useTabList.ts +++ b/packages/twenty-front/src/modules/ui/layout/tab/hooks/useTabList.ts @@ -4,7 +4,7 @@ import { useTabListStates } from '@/ui/layout/tab/hooks/internal/useTabListState export const useTabList = (tabListId?: string) => { const { activeTabIdState } = useTabListStates({ - tabListScopeId: `${tabListId}-scope`, + tabListScopeId: tabListId, }); const setActiveTabId = useSetRecoilState(activeTabIdState); diff --git a/packages/twenty-front/src/modules/ui/layout/tab/scopes/scope-internal-context/TabListScopeInternalContext.ts b/packages/twenty-front/src/modules/ui/layout/tab/scopes/scope-internal-context/TabListScopeInternalContext.ts index 878955256..5212b7bdb 100644 --- a/packages/twenty-front/src/modules/ui/layout/tab/scopes/scope-internal-context/TabListScopeInternalContext.ts +++ b/packages/twenty-front/src/modules/ui/layout/tab/scopes/scope-internal-context/TabListScopeInternalContext.ts @@ -1,7 +1,7 @@ import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; -type TabListScopeInternalContextProps = ComponentStateKey; +type TabListScopeInternalContextProps = RecoilComponentStateKey; export const TabListScopeInternalContext = createScopeInternalContext(); diff --git a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2.ts index 952fbfb0e..cf3b74745 100644 --- a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2.ts +++ b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2.ts @@ -1,9 +1,9 @@ import { RecoilState, useRecoilState } from 'recoil'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; export const useRecoilScopedStateV2 = ( - recoilState: (scopedKey: ComponentStateKey) => RecoilState, + recoilState: (scopedKey: RecoilComponentStateKey) => RecoilState, scopeId: string, ) => { return useRecoilState( diff --git a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext.ts b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext.ts index 78911a1ab..abf1b3390 100644 --- a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext.ts +++ b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext.ts @@ -1,10 +1,11 @@ import { Context, createContext } from 'react'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; -type ScopeInternalContext = Context; +type ScopeInternalContext = + Context; -export const createScopeInternalContext = ( +export const createScopeInternalContext = ( initialValue?: T, ) => { return createContext( diff --git a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/types/RecoilScopedSelector.ts b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/types/RecoilScopedSelector.ts index 8e92014b5..5f680bbda 100644 --- a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/types/RecoilScopedSelector.ts +++ b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/types/RecoilScopedSelector.ts @@ -1,7 +1,7 @@ import { RecoilValueReadOnly } from 'recoil'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; export type RecoilScopedSelector = ( - scopedKey: ComponentStateKey, + scopedKey: RecoilComponentStateKey, ) => RecoilValueReadOnly; diff --git a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/types/RecoilScopedState.ts b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/types/RecoilScopedState.ts index beb36d9e9..44ed24a23 100644 --- a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/types/RecoilScopedState.ts +++ b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/types/RecoilScopedState.ts @@ -1,7 +1,7 @@ import { RecoilState } from 'recoil'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; export type RecoilScopedState = ( - scopedKey: ComponentStateKey, + scopedKey: RecoilComponentStateKey, ) => RecoilState; diff --git a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId.ts b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId.ts index feb67c86d..bc5ce6e96 100644 --- a/packages/twenty-front/src/modules/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId.ts +++ b/packages/twenty-front/src/modules/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId.ts @@ -1,2 +1,2 @@ export const getScopeIdFromComponentId = (componentId: string) => - `${componentId}-scope`; + `${componentId}`; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow.ts new file mode 100644 index 000000000..8a497e3c3 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow.ts @@ -0,0 +1,24 @@ +import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext'; +import { ComponentInstanceStateContext } from '@/ui/utilities/state/component-state/types/ComponentInstanceStateContext'; +import { isNonEmptyString } from '@sniptt/guards'; + +export const useAvailableComponentInstanceIdOrThrow = < + T extends { instanceId: string }, +>( + Context: ComponentInstanceStateContext, + instanceIdFromProps?: string, +): string => { + const instanceStateContext = useComponentInstanceStateContext(Context); + + const instanceIdFromContext = instanceStateContext?.instanceId; + + if (isNonEmptyString(instanceIdFromProps)) { + return instanceIdFromProps; + } else if (isNonEmptyString(instanceIdFromContext)) { + return instanceIdFromContext; + } else { + throw new Error( + 'Instance id is not provided and cannot be found in context.', + ); + } +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext.ts new file mode 100644 index 000000000..17dbbf158 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext.ts @@ -0,0 +1,12 @@ +import { ComponentInstanceStateContext } from '@/ui/utilities/state/component-state/types/ComponentInstanceStateContext'; +import { useContext } from 'react'; + +export const useComponentInstanceStateContext = < + T extends { instanceId: string }, +>( + Context: ComponentInstanceStateContext, +) => { + const context = useContext(Context); + + return context; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilCallbackState.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilCallbackState.ts new file mode 100644 index 000000000..bf1143c06 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilCallbackState.ts @@ -0,0 +1,27 @@ +import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; +import { getScopeIdOrUndefinedFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdOrUndefinedFromComponentId'; +import { RecoilComponentState } from '@/ui/utilities/state/component-state/types/RecoilComponentState'; + +export const useRecoilCallbackState = ( + componentState: RecoilComponentState, + componentId?: string, +) => { + const componentContext = (window as any).componentContextStateMap?.get( + componentState.key, + ); + + if (!componentContext) { + throw new Error( + `Component context for key "${componentState.key}" is not defined`, + ); + } + + const internalScopeId = useAvailableScopeIdOrThrow( + componentContext, + getScopeIdOrUndefinedFromComponentId(componentId), + ); + + return componentState.atomFamily({ + scopeId: internalScopeId, + }); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2.ts new file mode 100644 index 000000000..ff3f6ab06 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2.ts @@ -0,0 +1,128 @@ +/* eslint-disable no-redeclare */ +/* eslint-disable prefer-arrow/prefer-arrow-functions */ +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { ComponentFamilyReadOnlySelectorV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyReadOnlySelectorV2'; +import { ComponentFamilySelectorV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilySelectorV2'; +import { ComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyStateV2'; +import { ComponentReadOnlySelectorV2 } from '@/ui/utilities/state/component-state/types/ComponentReadOnlySelectorV2'; +import { ComponentSelectorV2 } from '@/ui/utilities/state/component-state/types/ComponentSelectorV2'; +import { ComponentStateV2 } from '@/ui/utilities/state/component-state/types/ComponentStateV2'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { RecoilState, RecoilValueReadOnly, SerializableParam } from 'recoil'; + +export function useRecoilComponentCallbackStateV2( + componentState: ComponentStateV2, + instanceIdFromProps?: string, +): RecoilState; +export function useRecoilComponentCallbackStateV2( + componentSelector: ComponentSelectorV2, + instanceIdFromProps?: string, +): RecoilState; +export function useRecoilComponentCallbackStateV2( + componentReadOnlySelector: ComponentReadOnlySelectorV2, + instanceIdFromProps?: string, +): RecoilValueReadOnly; +export function useRecoilComponentCallbackStateV2< + ValueType, + FamilyKey extends SerializableParam, +>( + componentFamilyState: ComponentFamilyStateV2, + instanceIdFromProps?: string, +): (familyKey: FamilyKey) => RecoilState; +export function useRecoilComponentCallbackStateV2< + ValueType, + FamilyKey extends SerializableParam, +>( + componentFamilySelector: ComponentFamilySelectorV2, + instanceIdFromProps?: string, +): (familyKey: FamilyKey) => RecoilState; +export function useRecoilComponentCallbackStateV2< + ValueType, + FamilyKey extends SerializableParam, +>( + componentFamilyReadOnlySelector: ComponentFamilyReadOnlySelectorV2< + ValueType, + FamilyKey + >, + instanceIdFromProps?: string, +): (familyKey: FamilyKey) => RecoilValueReadOnly; +export function useRecoilComponentCallbackStateV2< + ValueType, + FamilyKey extends SerializableParam, +>( + componentFamilyState: ComponentFamilyStateV2, + instanceIdFromProps?: string, +): (familyKey: FamilyKey) => RecoilState; +export function useRecoilComponentCallbackStateV2< + ComponentState extends + | ComponentStateV2 + | ComponentSelectorV2 + | ComponentReadOnlySelectorV2 + | ComponentFamilyStateV2 + | ComponentFamilySelectorV2 + | ComponentFamilyReadOnlySelectorV2, + ValueType, + FamilyKey extends SerializableParam = never, +>( + componentState: ComponentState, + instanceIdFromProps?: string, +): + | RecoilState + | RecoilValueReadOnly + | ((familyKey: FamilyKey) => RecoilState) + | ((familyKey: FamilyKey) => RecoilValueReadOnly) { + const componentStateKey = componentState.key; + + const componentInstanceContext = + globalComponentInstanceContextMap.get(componentStateKey); + + if (!componentInstanceContext) { + throw new Error( + `Instance context for key "${componentStateKey}" is not defined, check the component state declaration.`, + ); + } + + const instanceId = useAvailableComponentInstanceIdOrThrow( + componentInstanceContext, + instanceIdFromProps, + ); + + switch (componentState.type) { + case 'ComponentState': { + return componentState.atomFamily({ + instanceId, + }); + } + case 'ComponentSelector': { + return componentState.selectorFamily({ + instanceId, + }); + } + case 'ComponentReadOnlySelector': { + return componentState.selectorFamily({ + instanceId, + }); + } + case 'ComponentFamilyState': { + return (familyKey: FamilyKey) => + componentState.atomFamily({ + instanceId, + familyKey, + }); + } + case 'ComponentFamilySelector': { + return (familyKey: FamilyKey) => + componentState.selectorFamily({ + instanceId, + familyKey, + }); + } + case 'ComponentFamilyReadOnlySelector': { + return (familyKey: FamilyKey) => + componentState.selectorFamily({ + instanceId, + familyKey, + }); + } + } +} diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2.ts new file mode 100644 index 000000000..4e8edaa4e --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2.ts @@ -0,0 +1,52 @@ +/* eslint-disable react-hooks/rules-of-hooks */ +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { ComponentFamilyReadOnlySelectorV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyReadOnlySelectorV2'; +import { ComponentFamilySelectorV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilySelectorV2'; +import { ComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyStateV2'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { SerializableParam, useRecoilValue } from 'recoil'; + +export const useRecoilComponentFamilyValueV2 = < + StateType, + FamilyKey extends SerializableParam, +>( + componentStateV2: + | ComponentFamilyStateV2 + | ComponentFamilySelectorV2 + | ComponentFamilyReadOnlySelectorV2, + familyKey: FamilyKey, + instanceIdFromProps?: string, +): StateType => { + const instanceContext = globalComponentInstanceContextMap.get( + componentStateV2.key, + ); + + if (!instanceContext) { + throw new Error( + `Instance context for key "${componentStateV2.key}" is not defined`, + ); + } + + const instanceId = useAvailableComponentInstanceIdOrThrow( + instanceContext, + instanceIdFromProps, + ); + + switch (componentStateV2.type) { + case 'ComponentFamilyState': { + return useRecoilValue( + componentStateV2.atomFamily({ familyKey, instanceId }), + ); + } + case 'ComponentFamilySelector': { + return useRecoilValue( + componentStateV2.selectorFamily({ familyKey, instanceId }), + ); + } + case 'ComponentFamilyReadOnlySelector': { + return useRecoilValue( + componentStateV2.selectorFamily({ familyKey, instanceId }), + ); + } + } +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentState.ts new file mode 100644 index 000000000..c0bd5e9d5 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentState.ts @@ -0,0 +1,28 @@ +import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; +import { getScopeIdOrUndefinedFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdOrUndefinedFromComponentId'; +import { RecoilComponentState } from '@/ui/utilities/state/component-state/types/RecoilComponentState'; +import { useRecoilState } from 'recoil'; + +export const useRecoilComponentState = ( + componentState: RecoilComponentState, + componentId?: string, +) => { + const componentContext = (window as any).componentContextStateMap?.get( + componentState.key, + ); + + if (!componentContext) { + throw new Error( + `Component context for key "${componentState.key}" is not defined`, + ); + } + + const internalComponentId = useAvailableScopeIdOrThrow( + componentContext, + getScopeIdOrUndefinedFromComponentId(componentId), + ); + + return useRecoilState( + componentState.atomFamily({ scopeId: internalComponentId }), + ); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2.ts new file mode 100644 index 000000000..a3d16acd4 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2.ts @@ -0,0 +1,26 @@ +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { ComponentStateV2 } from '@/ui/utilities/state/component-state/types/ComponentStateV2'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { useRecoilState } from 'recoil'; + +export const useRecoilComponentStateV2 = ( + componentState: ComponentStateV2, + instanceIdFromProps?: string, +) => { + const componentInstanceContext = globalComponentInstanceContextMap.get( + componentState.key, + ); + + if (!componentInstanceContext) { + throw new Error( + `Instance context for key "${componentState.key}" is not defined`, + ); + } + + const instanceId = useAvailableComponentInstanceIdOrThrow( + componentInstanceContext, + instanceIdFromProps, + ); + + return useRecoilState(componentState.atomFamily({ instanceId })); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentValue.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentValue.ts index d72ee3cae..efaa56de1 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentValue.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentValue.ts @@ -2,10 +2,10 @@ import { useRecoilValue } from 'recoil'; import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; import { getScopeIdOrUndefinedFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdOrUndefinedFromComponentId'; -import { ComponentState } from '@/ui/utilities/state/component-state/types/ComponentState'; +import { RecoilComponentState } from '@/ui/utilities/state/component-state/types/RecoilComponentState'; export const useRecoilComponentValue = ( - componentState: ComponentState, + componentState: RecoilComponentState, componentId?: string, ) => { const componentContext = (window as any).componentContextStateMap?.get( diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2.ts new file mode 100644 index 000000000..a76b91c2e --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2.ts @@ -0,0 +1,26 @@ +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { ComponentStateV2 } from '@/ui/utilities/state/component-state/types/ComponentStateV2'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { useRecoilValue } from 'recoil'; + +export const useRecoilComponentValueV2 = ( + componentStateV2: ComponentStateV2, + instanceIdFromProps?: string, +) => { + const instanceContext = globalComponentInstanceContextMap.get( + componentStateV2.key, + ); + + if (!instanceContext) { + throw new Error( + `Instance context for key "${componentStateV2.key}" is not defined`, + ); + } + + const instanceId = useAvailableComponentInstanceIdOrThrow( + instanceContext, + instanceIdFromProps, + ); + + return useRecoilValue(componentStateV2.atomFamily({ instanceId })); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useScopeIdFromStateContext.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useScopeIdFromStateContext.ts index e500060c9..fa30c4cd5 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useScopeIdFromStateContext.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useScopeIdFromStateContext.ts @@ -1,9 +1,9 @@ import { useScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useScopeInternalContext'; import { ComponentFamilyState } from '@/ui/utilities/state/component-state/types/ComponentFamilyState'; -import { ComponentState } from '@/ui/utilities/state/component-state/types/ComponentState'; +import { RecoilComponentState } from '@/ui/utilities/state/component-state/types/RecoilComponentState'; export const useScopeIdFromStateContext = ( - componentState: ComponentState | ComponentFamilyState, + componentState: RecoilComponentState | ComponentFamilyState, ) => { const componentContext = (window as any).componentContextStateMap?.get( componentState.key, diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2.ts new file mode 100644 index 000000000..1ccf392a5 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2.ts @@ -0,0 +1,52 @@ +/* eslint-disable react-hooks/rules-of-hooks */ + +// We're disabling rules-of-hooks because we're sure that the call order cannot be modified +// because a component state cannot change its type during its lifecycle + +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { ComponentFamilySelectorV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilySelectorV2'; +import { ComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyStateV2'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { SerializableParam, SetterOrUpdater, useSetRecoilState } from 'recoil'; + +export const useSetRecoilComponentFamilyStateV2 = < + StateType, + FamilyKey extends SerializableParam, +>( + componentState: + | ComponentFamilyStateV2 + | ComponentFamilySelectorV2, + familyKey: FamilyKey, + instanceIdFromProps?: string, +): SetterOrUpdater => { + const componentInstanceContext = globalComponentInstanceContextMap.get( + componentState.key, + ); + + if (!componentInstanceContext) { + throw new Error( + `Instance context for key "${componentState.key}" is not defined`, + ); + } + + const instanceId = useAvailableComponentInstanceIdOrThrow( + componentInstanceContext, + instanceIdFromProps, + ); + + switch (componentState.type) { + case 'ComponentFamilyState': { + return useSetRecoilState( + componentState.atomFamily({ familyKey, instanceId }), + ); + } + case 'ComponentFamilySelector': { + return useSetRecoilState( + componentState.selectorFamily({ + familyKey, + instanceId, + }), + ); + } + } +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useSetRecoilComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useSetRecoilComponentState.ts index 938d699b3..9e1ca49a4 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useSetRecoilComponentState.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useSetRecoilComponentState.ts @@ -2,10 +2,10 @@ import { useSetRecoilState } from 'recoil'; import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; import { getScopeIdOrUndefinedFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdOrUndefinedFromComponentId'; -import { ComponentState } from '@/ui/utilities/state/component-state/types/ComponentState'; +import { RecoilComponentState } from '@/ui/utilities/state/component-state/types/RecoilComponentState'; export const useSetRecoilComponentState = ( - componentState: ComponentState, + componentState: RecoilComponentState, componentId?: string, ) => { const componentContext = (window as any).componentContextStateMap?.get( diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2.ts new file mode 100644 index 000000000..29e5f1914 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2.ts @@ -0,0 +1,26 @@ +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { ComponentStateV2 } from '@/ui/utilities/state/component-state/types/ComponentStateV2'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { SetterOrUpdater, useSetRecoilState } from 'recoil'; + +export const useSetRecoilComponentStateV2 = ( + componentState: ComponentStateV2, + instanceIdFromProps?: string, +): SetterOrUpdater => { + const componentInstanceContext = globalComponentInstanceContextMap.get( + componentState.key, + ); + + if (!componentInstanceContext) { + throw new Error( + `Instance context for key "${componentState.key}" is not defined`, + ); + } + + const instanceId = useAvailableComponentInstanceIdOrThrow( + componentInstanceContext, + instanceIdFromProps, + ); + + return useSetRecoilState(componentState.atomFamily({ instanceId })); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentFamilyReadOnlySelectorV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentFamilyReadOnlySelectorV2.ts new file mode 100644 index 000000000..0a01f598b --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentFamilyReadOnlySelectorV2.ts @@ -0,0 +1,14 @@ +import { ComponentFamilyStateKeyV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyStateKeyV2'; +import { ComponentStateTypeV2 } from '@/ui/utilities/state/component-state/types/ComponentStateTypeV2'; +import { RecoilValueReadOnly, SerializableParam } from 'recoil'; + +export type ComponentFamilyReadOnlySelectorV2< + StateType, + FamilyKey extends SerializableParam, +> = { + type: Extract; + key: string; + selectorFamily: ( + componentFamilyStateKey: ComponentFamilyStateKeyV2, + ) => RecoilValueReadOnly; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentFamilySelectorV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentFamilySelectorV2.ts new file mode 100644 index 000000000..9ac6c5879 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentFamilySelectorV2.ts @@ -0,0 +1,14 @@ +import { ComponentFamilyStateKeyV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyStateKeyV2'; +import { ComponentStateTypeV2 } from '@/ui/utilities/state/component-state/types/ComponentStateTypeV2'; +import { RecoilState, SerializableParam } from 'recoil'; + +export type ComponentFamilySelectorV2< + StateType, + FamilyKey extends SerializableParam, +> = { + type: Extract; + key: string; + selectorFamily: ( + componentFamilyStateKey: ComponentFamilyStateKeyV2, + ) => RecoilState; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentFamilyStateKeyV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentFamilyStateKeyV2.ts new file mode 100644 index 000000000..a5e278b46 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentFamilyStateKeyV2.ts @@ -0,0 +1,7 @@ +import { ComponentStateKeyV2 } from '@/ui/utilities/state/component-state/types/ComponentStateKeyV2'; +import { SerializableParam } from 'recoil'; + +export type ComponentFamilyStateKeyV2 = + ComponentStateKeyV2 & { + familyKey: FamilyKey; + }; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentFamilyStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentFamilyStateV2.ts new file mode 100644 index 000000000..0410896ad --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentFamilyStateV2.ts @@ -0,0 +1,14 @@ +import { ComponentFamilyStateKeyV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyStateKeyV2'; +import { ComponentStateTypeV2 } from '@/ui/utilities/state/component-state/types/ComponentStateTypeV2'; +import { RecoilState, SerializableParam } from 'recoil'; + +export type ComponentFamilyStateV2< + StateType, + FamilyKey extends SerializableParam, +> = { + type: Extract; + key: string; + atomFamily: ( + componentFamilyStateKey: ComponentFamilyStateKeyV2, + ) => RecoilState; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentInstanceStateContext.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentInstanceStateContext.ts new file mode 100644 index 000000000..10f558926 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentInstanceStateContext.ts @@ -0,0 +1,4 @@ +import { Context } from 'react'; + +export type ComponentInstanceStateContext = + Context; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentReadOnlySelectorV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentReadOnlySelectorV2.ts new file mode 100644 index 000000000..9e62e0a48 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentReadOnlySelectorV2.ts @@ -0,0 +1,11 @@ +import { ComponentStateKeyV2 } from '@/ui/utilities/state/component-state/types/ComponentStateKeyV2'; +import { ComponentStateTypeV2 } from '@/ui/utilities/state/component-state/types/ComponentStateTypeV2'; +import { RecoilValueReadOnly } from 'recoil'; + +export type ComponentReadOnlySelectorV2 = { + type: Extract; + key: string; + selectorFamily: ( + componentStateKey: ComponentStateKeyV2, + ) => RecoilValueReadOnly; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentSelectorV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentSelectorV2.ts new file mode 100644 index 000000000..f93ef3e22 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentSelectorV2.ts @@ -0,0 +1,11 @@ +import { ComponentStateKeyV2 } from '@/ui/utilities/state/component-state/types/ComponentStateKeyV2'; +import { ComponentStateTypeV2 } from '@/ui/utilities/state/component-state/types/ComponentStateTypeV2'; +import { RecoilState } from 'recoil'; + +export type ComponentSelectorV2 = { + type: Extract; + key: string; + selectorFamily: ( + componentStateKey: ComponentStateKeyV2, + ) => RecoilState; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentState.ts deleted file mode 100644 index 8fc43e8a2..000000000 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentState.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { RecoilState } from 'recoil'; - -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; - -export type ComponentState = { - key: string; - atomFamily: (componentStateKey: ComponentStateKey) => RecoilState; -}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentStateKey.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentStateKey.ts deleted file mode 100644 index fb69c4c12..000000000 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentStateKey.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type ComponentStateKey = { - scopeId: string; -}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentStateKeyV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentStateKeyV2.ts new file mode 100644 index 000000000..524b9dfc8 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentStateKeyV2.ts @@ -0,0 +1,3 @@ +export type ComponentStateKeyV2 = { + instanceId: string; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentStateTypeV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentStateTypeV2.ts new file mode 100644 index 000000000..83a3182a6 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentStateTypeV2.ts @@ -0,0 +1,7 @@ +export type ComponentStateTypeV2 = + | 'ComponentState' + | 'ComponentFamilyState' + | 'ComponentSelector' + | 'ComponentReadOnlySelector' + | 'ComponentFamilySelector' + | 'ComponentFamilyReadOnlySelector'; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentStateV2.ts new file mode 100644 index 000000000..faeab37dd --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/ComponentStateV2.ts @@ -0,0 +1,11 @@ +import { ComponentStateKeyV2 } from '@/ui/utilities/state/component-state/types/ComponentStateKeyV2'; +import { ComponentStateTypeV2 } from '@/ui/utilities/state/component-state/types/ComponentStateTypeV2'; +import { RecoilState } from 'recoil'; + +export type ComponentStateV2 = { + type: Extract; + key: string; + atomFamily: ( + componentStateKey: ComponentStateKeyV2, + ) => RecoilState; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/RecoilComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/RecoilComponentState.ts new file mode 100644 index 000000000..8c007e5bd --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/RecoilComponentState.ts @@ -0,0 +1,9 @@ +import { RecoilState } from 'recoil'; +import { RecoilComponentStateKey } from './RecoilComponentStateKey'; + +export type RecoilComponentState = { + key: string; + atomFamily: ( + componentStateKey: RecoilComponentStateKey, + ) => RecoilState; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/RecoilComponentStateKey.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/RecoilComponentStateKey.ts new file mode 100644 index 000000000..6627f39f9 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/types/RecoilComponentStateKey.ts @@ -0,0 +1,3 @@ +export type RecoilComponentStateKey = { + scopeId: string; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentFamilySelectorV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentFamilySelectorV2.ts new file mode 100644 index 000000000..04c9a2d2a --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentFamilySelectorV2.ts @@ -0,0 +1,58 @@ +import { selectorFamily, SerializableParam } from 'recoil'; + +import { ComponentFamilyReadOnlySelectorV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyReadOnlySelectorV2'; +import { ComponentFamilySelectorV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilySelectorV2'; +import { ComponentFamilyStateKeyV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyStateKeyV2'; +import { ComponentInstanceStateContext } from '@/ui/utilities/state/component-state/types/ComponentInstanceStateContext'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { SelectorGetter } from '@/ui/utilities/state/types/SelectorGetter'; +import { SelectorSetter } from '@/ui/utilities/state/types/SelectorSetter'; +import { isDefined } from 'twenty-ui'; + +export const createComponentFamilySelectorV2 = < + ValueType, + FamilyKey extends SerializableParam, +>({ + key, + get, + set, + componentInstanceContext, +}: { + key: string; + get: SelectorGetter>; + set?: SelectorSetter>; + componentInstanceContext: ComponentInstanceStateContext | null; +}): + | ComponentFamilySelectorV2 + | ComponentFamilyReadOnlySelectorV2 => { + if (isDefined(componentInstanceContext)) { + globalComponentInstanceContextMap.set(key, componentInstanceContext); + } + + if (isDefined(set)) { + return { + type: 'ComponentFamilySelector', + key, + selectorFamily: selectorFamily< + ValueType, + ComponentFamilyStateKeyV2 + >({ + key, + get, + set, + }), + } satisfies ComponentFamilySelectorV2; + } else { + return { + type: 'ComponentFamilyReadOnlySelector', + key, + selectorFamily: selectorFamily< + ValueType, + ComponentFamilyStateKeyV2 + >({ + key, + get, + }), + } satisfies ComponentFamilyReadOnlySelectorV2; + } +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentFamilyStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentFamilyStateV2.ts index b3f7b3b5b..2d1f42e61 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentFamilyStateV2.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentFamilyStateV2.ts @@ -1,13 +1,15 @@ +import { ComponentFamilyStateKeyV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyStateKeyV2'; +import { ComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyStateV2'; +import { ComponentInstanceStateContext } from '@/ui/utilities/state/component-state/types/ComponentInstanceStateContext'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; import { AtomEffect, atomFamily, SerializableParam } from 'recoil'; -import { ScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/types/ScopeInternalContext'; -import { ComponentFamilyStateKey } from '@/ui/utilities/state/component-state/types/ComponentFamilyStateKey'; import { isDefined } from 'twenty-ui'; -type CreateComponentFamilyStateV2Type = { +type CreateComponentFamilyStateArgs = { key: string; defaultValue: ValueType; - componentContext: ScopeInternalContext | null; + componentInstanceContext: ComponentInstanceStateContext | null; effects?: AtomEffect[]; }; @@ -18,22 +20,22 @@ export const createComponentFamilyStateV2 = < key, effects, defaultValue, - componentContext, -}: CreateComponentFamilyStateV2Type) => { - if (isDefined(componentContext)) { - if (!isDefined((window as any).componentContextStateMap)) { - (window as any).componentContextStateMap = new Map(); - } - - (window as any).componentContextStateMap.set(key, componentContext); + componentInstanceContext, +}: CreateComponentFamilyStateArgs): ComponentFamilyStateV2< + ValueType, + FamilyKey +> => { + if (isDefined(componentInstanceContext)) { + globalComponentInstanceContextMap.set(key, componentInstanceContext); } return { + type: 'ComponentFamilyState', key, - atomFamily: atomFamily>({ + atomFamily: atomFamily>({ key, default: defaultValue, effects, }), - }; + } satisfies ComponentFamilyStateV2; }; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentInstanceContext.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentInstanceContext.ts new file mode 100644 index 000000000..68b9d93a6 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentInstanceContext.ts @@ -0,0 +1,13 @@ +import { ComponentInstanceStateContext } from '@/ui/utilities/state/component-state/types/ComponentInstanceStateContext'; +import { ComponentStateKeyV2 } from '@/ui/utilities/state/component-state/types/ComponentStateKeyV2'; +import { createContext } from 'react'; + +export const createComponentInstanceContext = < + T extends ComponentStateKeyV2 = ComponentStateKeyV2, +>( + initialValue?: T, +) => { + return createContext( + initialValue ?? null, + ) as ComponentInstanceStateContext; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentReadOnlySelector.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentReadOnlySelector.ts index 3369abc77..5fa337823 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentReadOnlySelector.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentReadOnlySelector.ts @@ -1,6 +1,6 @@ import { selectorFamily } from 'recoil'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; import { SelectorGetter } from '@/ui/utilities/state/types/SelectorGetter'; export const createComponentReadOnlySelector = ({ @@ -8,9 +8,9 @@ export const createComponentReadOnlySelector = ({ get, }: { key: string; - get: SelectorGetter; + get: SelectorGetter; }) => { - return selectorFamily({ + return selectorFamily({ key, get, }); diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentSelector.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentSelector.ts index c4dfc647b..545845ccd 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentSelector.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentSelector.ts @@ -1,6 +1,6 @@ import { selectorFamily } from 'recoil'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; import { SelectorGetter } from '@/ui/utilities/state/types/SelectorGetter'; import { SelectorSetter } from '@/ui/utilities/state/types/SelectorSetter'; @@ -10,10 +10,10 @@ export const createComponentSelector = ({ set, }: { key: string; - get: SelectorGetter; - set: SelectorSetter; + get: SelectorGetter; + set: SelectorSetter; }) => { - return selectorFamily({ + return selectorFamily({ key, get, set, diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentSelectorV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentSelectorV2.ts new file mode 100644 index 000000000..352bff92f --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentSelectorV2.ts @@ -0,0 +1,47 @@ +import { selectorFamily } from 'recoil'; + +import { ComponentInstanceStateContext } from '@/ui/utilities/state/component-state/types/ComponentInstanceStateContext'; +import { ComponentReadOnlySelectorV2 } from '@/ui/utilities/state/component-state/types/ComponentReadOnlySelectorV2'; +import { ComponentSelectorV2 } from '@/ui/utilities/state/component-state/types/ComponentSelectorV2'; +import { ComponentStateKeyV2 } from '@/ui/utilities/state/component-state/types/ComponentStateKeyV2'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { SelectorGetter } from '@/ui/utilities/state/types/SelectorGetter'; +import { SelectorSetter } from '@/ui/utilities/state/types/SelectorSetter'; +import { isDefined } from 'twenty-ui'; + +export const createComponentSelectorV2 = ({ + key, + get, + set, + instanceContext, +}: { + key: string; + get: SelectorGetter; + set?: SelectorSetter; + instanceContext: ComponentInstanceStateContext | null; +}): ComponentSelectorV2 | ComponentReadOnlySelectorV2 => { + if (isDefined(instanceContext)) { + globalComponentInstanceContextMap.set(key, instanceContext); + } + + if (isDefined(set)) { + return { + type: 'ComponentSelector', + key, + selectorFamily: selectorFamily({ + key, + get, + set, + }), + } satisfies ComponentSelectorV2; + } else { + return { + type: 'ComponentReadOnlySelector', + key, + selectorFamily: selectorFamily({ + key, + get, + }), + } satisfies ComponentReadOnlySelectorV2; + } +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentState.ts index ffbd9dd7e..5f2cd0bad 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentState.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentState.ts @@ -1,6 +1,6 @@ import { AtomEffect, atomFamily } from 'recoil'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; type CreateComponentStateType = { key: string; @@ -13,7 +13,7 @@ export const createComponentState = ({ defaultValue, effects, }: CreateComponentStateType) => { - return atomFamily({ + return atomFamily({ key, default: defaultValue, effects: effects, diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentStateV2.ts index 1fda1db82..dc87cbf0c 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentStateV2.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentStateV2.ts @@ -1,37 +1,35 @@ +import { ComponentInstanceStateContext } from '@/ui/utilities/state/component-state/types/ComponentInstanceStateContext'; +import { ComponentStateKeyV2 } from '@/ui/utilities/state/component-state/types/ComponentStateKeyV2'; +import { ComponentStateV2 } from '@/ui/utilities/state/component-state/types/ComponentStateV2'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; import { AtomEffect, atomFamily } from 'recoil'; -import { ScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/types/ScopeInternalContext'; -import { ComponentState } from '@/ui/utilities/state/component-state/types/ComponentState'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; import { isDefined } from '~/utils/isDefined'; -type CreateComponentStateV2Type = { +type CreateComponentInstanceStateArgs = { key: string; defaultValue: ValueType; - componentContext?: ScopeInternalContext | null; + componentInstanceContext: ComponentInstanceStateContext | null; effects?: AtomEffect[]; }; export const createComponentStateV2 = ({ key, defaultValue, - componentContext, + componentInstanceContext, effects, -}: CreateComponentStateV2Type): ComponentState => { - if (isDefined(componentContext)) { - if (!isDefined((window as any).componentContextStateMap)) { - (window as any).componentContextStateMap = new Map(); - } - - (window as any).componentContextStateMap.set(key, componentContext); +}: CreateComponentInstanceStateArgs): ComponentStateV2 => { + if (isDefined(componentInstanceContext)) { + globalComponentInstanceContextMap.set(key, componentInstanceContext); } return { + type: 'ComponentState', key, - atomFamily: atomFamily({ + atomFamily: atomFamily({ key, default: defaultValue, effects: effects, }), - }; + } satisfies ComponentStateV2; }; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentStateV2_alpha.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentStateV2_alpha.ts new file mode 100644 index 000000000..2533b0542 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentStateV2_alpha.ts @@ -0,0 +1,38 @@ +import { AtomEffect, atomFamily } from 'recoil'; + +import { ScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/types/ScopeInternalContext'; + +import { RecoilComponentState } from '@/ui/utilities/state/component-state/types/RecoilComponentState'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; +import { isDefined } from '~/utils/isDefined'; + +type CreateComponentStateV2Type = { + key: string; + defaultValue: ValueType; + componentContext?: ScopeInternalContext | null; + effects?: AtomEffect[]; +}; + +export const createComponentStateV2_alpha = ({ + key, + defaultValue, + componentContext, + effects, +}: CreateComponentStateV2Type): RecoilComponentState => { + if (isDefined(componentContext)) { + if (!isDefined((window as any).componentContextStateMap)) { + (window as any).componentContextStateMap = new Map(); + } + + (window as any).componentContextStateMap.set(key, componentContext); + } + + return { + key, + atomFamily: atomFamily({ + key, + default: defaultValue, + effects: effects, + }), + }; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createEventContext.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createEventContext.ts new file mode 100644 index 000000000..723e1c3f3 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createEventContext.ts @@ -0,0 +1,9 @@ +import { createContext } from 'react'; + +export const createEventContext = < + Events extends Record void>, +>( + initialValue?: Events, +) => { + return createContext((initialValue ?? {}) as Events); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/extractComponentReadOnlySelector.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/extractComponentReadOnlySelector.ts index 98489a266..da5b494b6 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/extractComponentReadOnlySelector.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/extractComponentReadOnlySelector.ts @@ -1,10 +1,10 @@ import { RecoilValueReadOnly } from 'recoil'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; export const extractComponentReadOnlySelector = ( componentSelector: ( - componentStateKey: ComponentStateKey, + componentStateKey: RecoilComponentStateKey, ) => RecoilValueReadOnly, scopeId: string, ) => { diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/extractComponentSelector.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/extractComponentSelector.ts index 60f6fa75d..40befcf6f 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/extractComponentSelector.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/extractComponentSelector.ts @@ -1,10 +1,10 @@ import { RecoilState } from 'recoil'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; export const extractComponentSelector = ( componentSelector: ( - componentStateKey: ComponentStateKey, + componentStateKey: RecoilComponentStateKey, ) => RecoilState, scopeId: string, ) => { diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/extractComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/extractComponentState.ts index ea797fe77..cac495c0c 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/extractComponentState.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/extractComponentState.ts @@ -1,10 +1,10 @@ import { RecoilState } from 'recoil'; -import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey'; export const extractComponentState = ( componentState: ( - componentStateKey: ComponentStateKey, + componentStateKey: RecoilComponentStateKey, ) => RecoilState, scopeId: string, ) => { diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap.ts new file mode 100644 index 000000000..3dd5ce612 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap.ts @@ -0,0 +1,21 @@ +import { ComponentInstanceStateContext } from '@/ui/utilities/state/component-state/types/ComponentInstanceStateContext'; +import { isDefined } from 'twenty-ui'; + +class ComponentInstanceContextMap { + constructor() { + if (!isDefined((window as any).componentComponentStateContextMap)) { + (window as any).componentComponentStateContextMap = new Map(); + } + } + + public get(key: string): ComponentInstanceStateContext { + return (window as any).componentComponentStateContextMap.get(key); + } + + public set(key: string, context: ComponentInstanceStateContext) { + (window as any).componentComponentStateContextMap.set(key, context); + } +} + +export const globalComponentInstanceContextMap = + new ComponentInstanceContextMap(); diff --git a/packages/twenty-front/src/modules/views/components/EditableFilterDropdownButton.tsx b/packages/twenty-front/src/modules/views/components/EditableFilterDropdownButton.tsx index 23613d5c3..bbaa9af31 100644 --- a/packages/twenty-front/src/modules/views/components/EditableFilterDropdownButton.tsx +++ b/packages/twenty-front/src/modules/views/components/EditableFilterDropdownButton.tsx @@ -1,5 +1,4 @@ import { useCallback, useEffect } from 'react'; -import { useRecoilValue } from 'recoil'; import { MultipleFiltersDropdownContent } from '@/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; @@ -8,8 +7,11 @@ import { FilterOperand } from '@/object-record/object-filter-dropdown/types/Filt import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { EditableFilterChip } from '@/views/components/EditableFilterChip'; -import { useCombinedViewFilters } from '@/views/hooks/useCombinedViewFilters'; + +import { useDeleteCombinedViewFilters } from '@/views/hooks/useDeleteCombinedViewFilters'; +import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState'; import { isDefined } from '~/utils/isDefined'; type EditableFilterDropdownButtonProps = { @@ -24,7 +26,6 @@ export const EditableFilterDropdownButton = ({ hotkeyScope, }: EditableFilterDropdownButtonProps) => { const { - availableFilterDefinitionsState, setFilterDefinitionUsedInDropdown, setSelectedOperandInDropdown, setSelectedFilter, @@ -32,13 +33,15 @@ export const EditableFilterDropdownButton = ({ filterDropdownId: viewFilterDropdownId, }); - const availableFilterDefinitions = useRecoilValue( - availableFilterDefinitionsState, + // TODO: verify this instance id works + const availableFilterDefinitions = useRecoilComponentValueV2( + availableFilterDefinitionsComponentState, + viewFilterDropdownId, ); const { closeDropdown } = useDropdown(viewFilterDropdownId); - const { removeCombinedViewFilter } = useCombinedViewFilters(); + const { deleteCombinedViewFilter } = useDeleteCombinedViewFilters(); useEffect(() => { const filterDefinition = availableFilterDefinitions.find( @@ -63,7 +66,7 @@ export const EditableFilterDropdownButton = ({ const handleRemove = () => { closeDropdown(); - removeCombinedViewFilter(viewFilter.id); + deleteCombinedViewFilter(viewFilter.id); }; const handleDropdownClickOutside = useCallback(() => { @@ -72,9 +75,9 @@ export const EditableFilterDropdownButton = ({ !value && ![FilterOperand.IsEmpty, FilterOperand.IsNotEmpty].includes(operand) ) { - removeCombinedViewFilter(fieldId); + deleteCombinedViewFilter(fieldId); } - }, [viewFilter, removeCombinedViewFilter]); + }, [viewFilter, deleteCombinedViewFilter]); return ( { - const { removeCombinedViewSort, upsertCombinedViewSort } = - useCombinedViewSorts(); + const { deleteCombinedViewSort } = useDeleteCombinedViewSorts(); + + const { upsertCombinedViewSort } = useUpsertCombinedViewSorts(); const handleRemoveClick = () => { - removeCombinedViewSort(viewSort.fieldMetadataId); + deleteCombinedViewSort(viewSort.fieldMetadataId); }; const handleClick = () => { diff --git a/packages/twenty-front/src/modules/views/components/QueryParamsFiltersEffect.tsx b/packages/twenty-front/src/modules/views/components/QueryParamsFiltersEffect.tsx index 25278a77c..10ecdfa83 100644 --- a/packages/twenty-front/src/modules/views/components/QueryParamsFiltersEffect.tsx +++ b/packages/twenty-front/src/modules/views/components/QueryParamsFiltersEffect.tsx @@ -1,18 +1,23 @@ import { useEffect } from 'react'; -import { useSetRecoilState } from 'recoil'; +import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2'; import { useViewFromQueryParams } from '@/views/hooks/internal/useViewFromQueryParams'; -import { useViewStates } from '@/views/hooks/internal/useViewStates'; -import { useResetCurrentView } from '@/views/hooks/useResetCurrentView'; +import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; +import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStates'; +import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState'; +import { isDefined } from 'twenty-ui'; export const QueryParamsFiltersEffect = () => { - const { hasFiltersQueryParams, getFiltersFromQueryParams } = + const { hasFiltersQueryParams, getFiltersFromQueryParams, viewIdQueryParam } = useViewFromQueryParams(); - const { unsavedToUpsertViewFiltersState } = useViewStates(); - const setUnsavedViewFilter = useSetRecoilState( - unsavedToUpsertViewFiltersState, + + const setUnsavedViewFilter = useSetRecoilComponentFamilyStateV2( + unsavedToUpsertViewFiltersComponentFamilyState, + { viewId: viewIdQueryParam }, ); - const { resetCurrentView } = useResetCurrentView(); + + const { resetUnsavedViewStates } = useResetUnsavedViewStates(); + const { currentViewId } = useGetCurrentView(); useEffect(() => { if (!hasFiltersQueryParams) { @@ -26,13 +31,16 @@ export const QueryParamsFiltersEffect = () => { }); return () => { - resetCurrentView(); + if (isDefined(currentViewId)) { + resetUnsavedViewStates(currentViewId); + } }; }, [ getFiltersFromQueryParams, hasFiltersQueryParams, - resetCurrentView, + resetUnsavedViewStates, setUnsavedViewFilter, + currentViewId, ]); return <>; diff --git a/packages/twenty-front/src/modules/views/components/QueryParamsViewIdEffect.tsx b/packages/twenty-front/src/modules/views/components/QueryParamsViewIdEffect.tsx index 74d516a7f..2ee24d43f 100644 --- a/packages/twenty-front/src/modules/views/components/QueryParamsViewIdEffect.tsx +++ b/packages/twenty-front/src/modules/views/components/QueryParamsViewIdEffect.tsx @@ -1,22 +1,26 @@ import { useLastVisitedObjectMetadataItem } from '@/navigation/hooks/useLastVisitedObjectMetadataItem'; import { useLastVisitedView } from '@/navigation/hooks/useLastVisitedView'; import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; import { useViewFromQueryParams } from '@/views/hooks/internal/useViewFromQueryParams'; -import { useViewStates } from '@/views/hooks/internal/useViewStates'; import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; -import { useResetCurrentView } from '@/views/hooks/useResetCurrentView'; +import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState'; import { isUndefined } from '@sniptt/guards'; import { useEffect } from 'react'; -import { useRecoilState } from 'recoil'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { isDefined } from '~/utils/isDefined'; export const QueryParamsViewIdEffect = () => { const { getFiltersFromQueryParams, viewIdQueryParam } = useViewFromQueryParams(); - const { currentViewIdState, componentId: objectNamePlural } = useViewStates(); - const [currentViewId, setCurrentViewId] = useRecoilState(currentViewIdState); + // TODO: fix this implicit hack + const { instanceId: objectNamePlural } = useGetCurrentView(); + + const [currentViewId, setCurrentViewId] = useRecoilComponentStateV2( + currentViewIdComponentState, + ); + const { viewsOnCurrentObject } = useGetCurrentView(); const { findObjectMetadataItemByNamePlural } = useFilteredObjectMetadataItems(); @@ -34,13 +38,14 @@ export const QueryParamsViewIdEffect = () => { lastVisitedObjectMetadataItemId, ); - const { resetCurrentView } = useResetCurrentView(); + // // TODO: scope view bar per view id if possible + // const { resetCurrentView } = useResetCurrentView(); - useEffect(() => { - if (isDefined(currentViewId)) { - resetCurrentView(); - } - }, [resetCurrentView, currentViewId]); + // useEffect(() => { + // if (isDefined(currentViewId)) { + // resetCurrentView(); + // } + // }, [resetCurrentView, currentViewId]); useEffect(() => { const indexView = viewsOnCurrentObject.find((view) => view.key === 'INDEX'); diff --git a/packages/twenty-front/src/modules/views/components/UpdateViewButtonGroup.tsx b/packages/twenty-front/src/modules/views/components/UpdateViewButtonGroup.tsx index b41269b4e..fa4054475 100644 --- a/packages/twenty-front/src/modules/views/components/UpdateViewButtonGroup.tsx +++ b/packages/twenty-front/src/modules/views/components/UpdateViewButtonGroup.tsx @@ -1,6 +1,4 @@ -import { useCallback } from 'react'; import styled from '@emotion/styled'; -import { useRecoilValue, useSetRecoilState } from 'recoil'; import { IconChevronDown, IconPlus } from 'twenty-ui'; import { Button } from '@/ui/input/button/components/Button'; @@ -10,14 +8,18 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { UPDATE_VIEW_BUTTON_DROPDOWN_ID } from '@/views/constants/UpdateViewButtonDropdownId'; import { useViewFromQueryParams } from '@/views/hooks/internal/useViewFromQueryParams'; -import { useViewStates } from '@/views/hooks/internal/useViewStates'; import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; import { useSaveCurrentViewFiltersAndSorts } from '@/views/hooks/useSaveCurrentViewFiltersAndSorts'; +import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState'; +import { canPersistViewComponentFamilySelector } from '@/views/states/selectors/canPersistViewComponentFamilySelector'; import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId'; import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode'; -import { useViewPickerStates } from '@/views/view-picker/hooks/useViewPickerStates'; +import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState'; const StyledContainer = styled.div` border-radius: ${({ theme }) => theme.border.radius.md}; @@ -33,12 +35,16 @@ export type UpdateViewButtonGroupProps = { export const UpdateViewButtonGroup = ({ hotkeyScope, }: UpdateViewButtonGroupProps) => { - const { canPersistViewSelector, currentViewIdState } = useViewStates(); const { saveCurrentViewFilterAndSorts } = useSaveCurrentViewFiltersAndSorts(); const { setViewPickerMode } = useViewPickerMode(); - const { viewPickerReferenceViewIdState } = useViewPickerStates(); - const canPersistView = useRecoilValue(canPersistViewSelector()); + + const currentViewId = useRecoilComponentValueV2(currentViewIdComponentState); + + const canPersistView = useRecoilComponentFamilyValueV2( + canPersistViewComponentFamilySelector, + { viewId: currentViewId }, + ); const { closeDropdown: closeUpdateViewButtonDropdown } = useDropdown( UPDATE_VIEW_BUTTON_DROPDOWN_ID, @@ -48,30 +54,31 @@ export const UpdateViewButtonGroup = ({ ); const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView(); - const currentViewId = useRecoilValue(currentViewIdState); - - const setViewPickerReferenceViewId = useSetRecoilState( - viewPickerReferenceViewIdState, + const setViewPickerReferenceViewId = useSetRecoilComponentStateV2( + viewPickerReferenceViewIdComponentState, ); - const handleViewCreate = useCallback(() => { + const openViewPickerInCreateMode = () => { if (!currentViewId) { return; } + openViewPickerDropdown(); setViewPickerReferenceViewId(currentViewId); - setViewPickerMode('create'); + setViewPickerMode('create-from-current'); closeUpdateViewButtonDropdown(); - }, [ - closeUpdateViewButtonDropdown, - currentViewId, - openViewPickerDropdown, - setViewPickerMode, - setViewPickerReferenceViewId, - ]); + }; - const handleViewUpdate = async () => { + const handleCreateViewClick = () => { + openViewPickerInCreateMode(); + }; + + const handleSaveAsNewViewClick = () => { + openViewPickerInCreateMode(); + }; + + const handleUpdateViewClick = async () => { await saveCurrentViewFilterAndSorts(); }; @@ -87,7 +94,7 @@ export const UpdateViewButtonGroup = ({ {currentViewWithCombinedFiltersAndSorts?.key !== 'INDEX' ? ( -