diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx
index a246ff432..cb9548f8b 100644
--- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx
+++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx
@@ -176,7 +176,7 @@ export const CalendarEventRow = ({
: participant.displayName
}
placeholderColorSeed={
- participant.workspaceMemberId ?? participant.personId
+ participant.workspaceMemberId || participant.personId
}
type="rounded"
/>
diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadPreview.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadPreview.tsx
index e381b1bac..bb7f8c140 100644
--- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadPreview.tsx
+++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadPreview.tsx
@@ -1,5 +1,5 @@
-import { useRef } from 'react';
import styled from '@emotion/styled';
+import { useRef } from 'react';
import { useRecoilCallback } from 'recoil';
import { Avatar, GRAY_SCALE } from 'twenty-ui';
@@ -155,12 +155,20 @@ export const EmailThreadPreview = ({
{thread?.lastTwoParticipants?.[0] && (
)}
diff --git a/packages/twenty-front/src/modules/activities/emails/right-drawer/components/RightDrawerEmailThread.tsx b/packages/twenty-front/src/modules/activities/emails/right-drawer/components/RightDrawerEmailThread.tsx
index bd4003ce3..87c986c06 100644
--- a/packages/twenty-front/src/modules/activities/emails/right-drawer/components/RightDrawerEmailThread.tsx
+++ b/packages/twenty-front/src/modules/activities/emails/right-drawer/components/RightDrawerEmailThread.tsx
@@ -13,33 +13,38 @@ import { Button } from '@/ui/input/button/components/Button';
import { RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID } from '@/ui/layout/right-drawer/constants/RightDrawerClickOutsideListener';
import { messageThreadState } from '@/ui/layout/right-drawer/states/messageThreadState';
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
+import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { IconArrowBackUp } from 'twenty-ui';
+const StyledWrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+`;
+
const StyledContainer = styled.div`
box-sizing: border-box;
display: flex;
flex-direction: column;
+ flex: 1;
height: 85%;
- justify-content: flex-start;
overflow-y: auto;
- position: relative;
`;
-const StyledButtonContainer = styled.div`
+const StyledButtonContainer = styled.div<{ isMobile: boolean }>`
background: ${({ theme }) => theme.background.secondary};
- bottom: 0;
+ border-top: 1px solid ${({ theme }) => theme.border.color.light};
display: flex;
- height: 110px;
- left: 0;
- padding-left: ${({ theme }) => theme.spacing(7)};
- padding-top: ${({ theme }) => theme.spacing(5)};
- position: fixed;
- right: 0;
+ justify-content: flex-end;
+ height: ${({ isMobile }) => (isMobile ? '100px' : '50px')};
+ padding: ${({ theme }) => theme.spacing(2)};
+ width: 100%;
+ box-sizing: border-box;
`;
export const RightDrawerEmailThread = () => {
const setMessageThread = useSetRecoilState(messageThreadState);
-
+ const isMobile = useIsMobile();
const {
thread,
messages,
@@ -118,47 +123,49 @@ export const RightDrawerEmailThread = () => {
return null;
}
return (
-
- {threadLoading ? (
-
- ) : (
- <>
-
- {firstMessages.map((message) => (
-
+
+ {threadLoading ? (
+
+ ) : (
+ <>
+
- ))}
-
-
-
- >
- )}
- {canReply && !messageChannelLoading ? (
-
+ {firstMessages.map((message) => (
+
+ ))}
+
+
+
+ >
+ )}
+
+ {canReply && !messageChannelLoading && (
+
+ />
- ) : null}
-
+ )}
+
);
};
diff --git a/packages/twenty-front/src/modules/activities/hooks/useActivities.ts b/packages/twenty-front/src/modules/activities/hooks/useActivities.ts
index d63109339..b5311a800 100644
--- a/packages/twenty-front/src/modules/activities/hooks/useActivities.ts
+++ b/packages/twenty-front/src/modules/activities/hooks/useActivities.ts
@@ -51,13 +51,12 @@ export const useActivities = ({
),
];
+ const skipBecauseNoActivityTargetFound = activityIds.length === 0;
+
const filter: RecordGqlOperationFilter = {
- id:
- targetableObjects.length > 0
- ? {
- in: activityIds,
- }
- : undefined,
+ id: {
+ in: activityIds,
+ },
...activitiesFilters,
};
@@ -69,7 +68,7 @@ export const useActivities = ({
const { records: activities, loading: loadingActivities } =
useFindManyRecords({
- skip: skip || loadingActivityTargets,
+ skip: skip || loadingActivityTargets || skipBecauseNoActivityTargetFound,
objectNameSingular:
FIND_ACTIVITIES_OPERATION_SIGNATURE.objectNameSingular,
recordGqlFields: FIND_ACTIVITIES_OPERATION_SIGNATURE.fields,
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 7302c7195..330ff18ab 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 { FieldDefinition } from '@/object-record/record-field/types/FieldDefinit
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
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: RecordGroupDefinition[]) => 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/meta-types/input/components/FullNameFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/FullNameFieldInput.tsx
index e7f40c461..c8d7a5f52 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/FullNameFieldInput.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/FullNameFieldInput.tsx
@@ -3,8 +3,7 @@ import { FieldDoubleText } from '@/object-record/record-field/types/FieldDoubleT
import { DoubleTextInput } from '@/ui/field/input/components/DoubleTextInput';
import { FieldInputOverlay } from '@/ui/field/input/components/FieldInputOverlay';
-import { usePersistField } from '../../../hooks/usePersistField';
-
+import { isDoubleTextFieldEmpty } from '@/object-record/record-field/meta-types/input/utils/isDoubleTextFieldEmpty';
import { FieldInputEvent } from './DateTimeFieldInput';
const FIRST_NAME_PLACEHOLDER_WITH_SPECIAL_CHARACTER_TO_AVOID_PASSWORD_MANAGERS =
@@ -28,46 +27,55 @@ export const FullNameFieldInput = ({
onTab,
onShiftTab,
}: FullNameFieldInputProps) => {
- const { hotkeyScope, draftValue, setDraftValue } = useFullNameField();
-
- const persistField = usePersistField();
+ const { hotkeyScope, draftValue, setDraftValue, persistFullNameField } =
+ useFullNameField();
const convertToFullName = (newDoubleText: FieldDoubleText) => {
return {
- firstName: newDoubleText.firstValue,
- lastName: newDoubleText.secondValue,
+ firstName: newDoubleText.firstValue.trim(),
+ lastName: newDoubleText.secondValue.trim(),
};
};
+ const getRequiredDraftValueFromDoubleText = (
+ newDoubleText: FieldDoubleText,
+ ) => {
+ return isDoubleTextFieldEmpty(newDoubleText)
+ ? undefined
+ : convertToFullName(newDoubleText);
+ };
+
const handleEnter = (newDoubleText: FieldDoubleText) => {
- onEnter?.(() => persistField(convertToFullName(newDoubleText)));
+ onEnter?.(() => persistFullNameField(convertToFullName(newDoubleText)));
};
const handleEscape = (newDoubleText: FieldDoubleText) => {
- onEscape?.(() => persistField(convertToFullName(newDoubleText)));
+ onEscape?.(() => persistFullNameField(convertToFullName(newDoubleText)));
};
const handleClickOutside = (
event: MouseEvent | TouchEvent,
newDoubleText: FieldDoubleText,
) => {
- onClickOutside?.(() => persistField(convertToFullName(newDoubleText)));
+ onClickOutside?.(() =>
+ persistFullNameField(convertToFullName(newDoubleText)),
+ );
};
const handleTab = (newDoubleText: FieldDoubleText) => {
- onTab?.(() => persistField(convertToFullName(newDoubleText)));
+ onTab?.(() => persistFullNameField(convertToFullName(newDoubleText)));
};
const handleShiftTab = (newDoubleText: FieldDoubleText) => {
- onShiftTab?.(() => persistField(convertToFullName(newDoubleText)));
+ onShiftTab?.(() => persistFullNameField(convertToFullName(newDoubleText)));
};
const handleChange = (newDoubleText: FieldDoubleText) => {
- setDraftValue(convertToFullName(newDoubleText));
+ setDraftValue(getRequiredDraftValueFromDoubleText(newDoubleText));
};
const handlePaste = (newDoubleText: FieldDoubleText) => {
- setDraftValue(convertToFullName(newDoubleText));
+ setDraftValue(getRequiredDraftValueFromDoubleText(newDoubleText));
};
return (
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiSelectFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiSelectFieldInput.tsx
index e95eeb5e2..7ebe1951e 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiSelectFieldInput.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiSelectFieldInput.tsx
@@ -16,6 +16,7 @@ import { MenuItemMultiSelectTag } from '@/ui/navigation/menu-item/components/Men
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { isDefined } from '~/utils/isDefined';
+import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
const StyledRelationPickerContainer = styled.div`
left: -1px;
@@ -109,7 +110,11 @@ export const MultiSelectFieldInput = ({
setSearchFilter(event.currentTarget.value)}
+ onChange={(event) =>
+ setSearchFilter(
+ turnIntoEmptyStringIfWhitespacesOnly(event.currentTarget.value),
+ )
+ }
autoFocus
/>
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/NumberFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/NumberFieldInput.tsx
index 336aefc99..d5fead466 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/NumberFieldInput.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/NumberFieldInput.tsx
@@ -60,7 +60,7 @@ export const NumberFieldInput = ({
{
- onEnter?.(() => persistField(newText));
+ onEnter?.(() => persistField(newText.trim()));
};
const handleEscape = (newText: string) => {
- onEscape?.(() => persistField(newText));
+ onEscape?.(() => persistField(newText.trim()));
};
const handleClickOutside = (
event: MouseEvent | TouchEvent,
newText: string,
) => {
- onClickOutside?.(() => persistField(newText));
+ onClickOutside?.(() => persistField(newText.trim()));
};
const handleTab = (newText: string) => {
- onTab?.(() => persistField(newText));
+ onTab?.(() => persistField(newText.trim()));
};
const handleShiftTab = (newText: string) => {
- onShiftTab?.(() => persistField(newText));
+ onShiftTab?.(() => persistField(newText.trim()));
};
const handleChange = (newText: string) => {
- setDraftValue(newText);
+ setDraftValue(turnIntoUndefinedIfWhitespacesOnly(newText));
};
return (
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/utils/isDoubleTextFieldEmpty.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/utils/isDoubleTextFieldEmpty.ts
new file mode 100644
index 000000000..1ffdc0e78
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/utils/isDoubleTextFieldEmpty.ts
@@ -0,0 +1,9 @@
+import { FieldDoubleText } from '@/object-record/record-field/types/FieldDoubleText';
+
+export const isDoubleTextFieldEmpty = (doubleText: FieldDoubleText) => {
+ const { firstValue, secondValue } = doubleText;
+
+ const totalLength = firstValue.trim().length + secondValue.trim().length;
+
+ return totalLength > 0 ? false : true;
+};
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-field/types/FieldInputDraftValue.ts b/packages/twenty-front/src/modules/object-record/record-field/types/FieldInputDraftValue.ts
index 2e50c1b68..9ab99492f 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/types/FieldInputDraftValue.ts
+++ b/packages/twenty-front/src/modules/object-record/record-field/types/FieldInputDraftValue.ts
@@ -25,7 +25,7 @@ import {
} from '@/object-record/record-field/types/FieldMetadata';
export type FieldTextDraftValue = string;
-export type FieldNumberDraftValue = string;
+export type FieldNumberDraftValue = number;
export type FieldDateTimeDraftValue = string;
export type FieldPhoneDraftValue = string;
export type FieldPhonesDraftValue = {
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 b32c30ef1..a81f88d11 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';
@@ -143,81 +144,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/components/SingleEntitySelectMenuItems.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/components/SingleEntitySelectMenuItems.tsx
index 6404d5e11..a7f029e12 100644
--- a/packages/twenty-front/src/modules/object-record/relation-picker/components/SingleEntitySelectMenuItems.tsx
+++ b/packages/twenty-front/src/modules/object-record/relation-picker/components/SingleEntitySelectMenuItems.tsx
@@ -1,5 +1,5 @@
import { isNonEmptyString } from '@sniptt/guards';
-import { useRef } from 'react';
+import { Fragment, useRef } from 'react';
import { useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum';
import { IconComponent, IconPlus } from 'twenty-ui';
@@ -158,16 +158,15 @@ export const SingleEntitySelectMenuItems = ({
switch (entity.id) {
case 'add-new': {
return (
- <>
+
{entitiesToSelect.length > 0 && }
- >
+
);
}
case 'select-none': {
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/settings/accounts/components/SettingsAccountsMessageChannelsContainer.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageChannelsContainer.tsx
index 3bbe93deb..d2d15d02f 100644
--- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageChannelsContainer.tsx
+++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsMessageChannelsContainer.tsx
@@ -44,6 +44,7 @@ export const SettingsAccountsMessageChannelsContainer = () => {
in: accounts.map((account) => account.id),
},
},
+ skip: !accounts.length,
});
const tabs = [
diff --git a/packages/twenty-front/src/modules/settings/workspace/components/NameField.tsx b/packages/twenty-front/src/modules/settings/workspace/components/NameField.tsx
index 3a921e92f..31b5f31b3 100644
--- a/packages/twenty-front/src/modules/settings/workspace/components/NameField.tsx
+++ b/packages/twenty-front/src/modules/settings/workspace/components/NameField.tsx
@@ -1,10 +1,11 @@
-import { useCallback, useEffect, useState } from 'react';
import styled from '@emotion/styled';
+import { useCallback, useEffect, useState } from 'react';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useDebouncedCallback } from 'use-debounce';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { TextInput } from '@/ui/input/components/TextInput';
+import isEmpty from 'lodash.isempty';
import { useUpdateWorkspaceMutation } from '~/generated/graphql';
import { isDefined } from '~/utils/isDefined';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
@@ -40,6 +41,7 @@ export const NameField = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
const debouncedUpdate = useCallback(
useDebouncedCallback(async (name: string) => {
+ if (isEmpty(name)) return;
// update local recoil state when workspace name is updated
setCurrentWorkspace((currentValue) => {
if (currentValue === null) {
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/components/SnackBar.tsx b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBar.tsx
index 5104ecdbb..b1f663065 100644
--- a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBar.tsx
+++ b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBar.tsx
@@ -1,7 +1,7 @@
-import { ComponentPropsWithoutRef, ReactNode, useMemo } from 'react';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { isUndefined } from '@sniptt/guards';
+import { ComponentPropsWithoutRef, ReactNode, useMemo } from 'react';
import {
IconAlertTriangle,
IconInfoCircle,
@@ -46,7 +46,6 @@ const StyledContainer = styled.div`
box-shadow: ${({ theme }) => theme.boxShadow.strong};
box-sizing: border-box;
cursor: pointer;
- height: 61px;
padding: ${({ theme }) => theme.spacing(2)};
position: relative;
width: 296px;
@@ -90,7 +89,6 @@ const StyledDescription = styled.div`
padding-left: ${({ theme }) => theme.spacing(6)};
overflow: hidden;
text-overflow: ellipsis;
- white-space: nowrap;
width: 200px;
`;
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/field/display/components/PhonesDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/PhonesDisplay.tsx
index 04423ff32..17e9d27f4 100644
--- a/packages/twenty-front/src/modules/ui/field/display/components/PhonesDisplay.tsx
+++ b/packages/twenty-front/src/modules/ui/field/display/components/PhonesDisplay.tsx
@@ -8,6 +8,7 @@ import { RoundedLink } from '@/ui/navigation/link/components/RoundedLink';
import { parsePhoneNumber } from 'libphonenumber-js';
import { isDefined } from '~/utils/isDefined';
+import { logError } from '~/utils/logError';
type PhonesDisplayProps = {
value?: FieldPhonesValue;
@@ -39,7 +40,7 @@ export const PhonesDisplay = ({ value, isFocused }: PhonesDisplayProps) => {
countryCode: value.primaryPhoneCountryCode,
}
: null,
- ...(value?.additionalPhones ?? []),
+ ...parseAdditionalPhones(value?.additionalPhones),
]
.filter(isDefined)
.map(({ number, countryCode }) => {
@@ -85,3 +86,23 @@ export const PhonesDisplay = ({ value, isFocused }: PhonesDisplayProps) => {
);
};
+
+const parseAdditionalPhones = (additionalPhones?: any) => {
+ if (!additionalPhones) {
+ return [];
+ }
+
+ if (typeof additionalPhones === 'object') {
+ return additionalPhones;
+ }
+
+ if (typeof additionalPhones === 'string') {
+ try {
+ return JSON.parse(additionalPhones);
+ } catch (error) {
+ logError(`Error parsing additional phones' : ` + error);
+ }
+ }
+
+ return [];
+};
diff --git a/packages/twenty-front/src/modules/ui/field/input/components/DoubleTextInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/DoubleTextInput.tsx
index 027371815..c003bde59 100644
--- a/packages/twenty-front/src/modules/ui/field/input/components/DoubleTextInput.tsx
+++ b/packages/twenty-front/src/modules/ui/field/input/components/DoubleTextInput.tsx
@@ -13,6 +13,8 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { isDefined } from '~/utils/isDefined';
+import { splitFullName } from '~/utils/format/spiltFullName';
+import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
import { StyledTextInput } from './TextInput';
const StyledContainer = styled.div`
@@ -167,9 +169,12 @@ export const DoubleTextInput = ({
const name = event.clipboardData.getData('Text');
- const splittedName = name.split(' ');
+ const splittedName = splitFullName(name);
- onPaste?.({ firstValue: splittedName[0], secondValue: splittedName[1] });
+ onPaste?.({
+ firstValue: splittedName[0],
+ secondValue: splittedName[1],
+ });
};
const handleClickToPreventParentClickEvents = (
@@ -189,7 +194,10 @@ export const DoubleTextInput = ({
placeholder={firstValuePlaceholder}
value={firstInternalValue}
onChange={(event: ChangeEvent) => {
- handleChange(event.target.value, secondInternalValue);
+ handleChange(
+ turnIntoEmptyStringIfWhitespacesOnly(event.target.value),
+ secondInternalValue,
+ );
}}
onPaste={(event: ClipboardEvent) =>
handleOnPaste(event)
@@ -203,7 +211,10 @@ export const DoubleTextInput = ({
placeholder={secondValuePlaceholder}
value={secondInternalValue}
onChange={(event: ChangeEvent) => {
- handleChange(firstInternalValue, event.target.value);
+ handleChange(
+ firstInternalValue,
+ turnIntoEmptyStringIfWhitespacesOnly(event.target.value),
+ );
}}
onClick={handleClickToPreventParentClickEvents}
/>
diff --git a/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx
index b9a08ef1f..c2da43576 100644
--- a/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx
+++ b/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx
@@ -1,11 +1,12 @@
+import styled from '@emotion/styled';
import { ChangeEvent, useEffect, useRef, useState } from 'react';
import TextareaAutosize from 'react-textarea-autosize';
-import styled from '@emotion/styled';
import { TEXT_INPUT_STYLE } from 'twenty-ui';
import { LightCopyIconButton } from '@/object-record/record-field/components/LightCopyIconButton';
import { useRegisterInputEvents } from '@/object-record/record-field/meta-types/input/hooks/useRegisterInputEvents';
import { isDefined } from '~/utils/isDefined';
+import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
export type TextAreaInputProps = {
disabled?: boolean;
@@ -67,10 +68,12 @@ export const TextAreaInput = ({
copyButton = true,
}: TextAreaInputProps) => {
const [internalText, setInternalText] = useState(value);
-
const handleChange = (event: ChangeEvent) => {
- setInternalText(event.target.value);
- onChange?.(event.target.value);
+ const targetValue = turnIntoEmptyStringIfWhitespacesOnly(
+ event.target.value,
+ );
+ setInternalText(targetValue);
+ onChange?.(targetValue);
};
const wrapperRef = useRef(null);
diff --git a/packages/twenty-front/src/modules/ui/field/input/components/TextInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/TextInput.tsx
index 1490e1f7d..b932cbdc5 100644
--- a/packages/twenty-front/src/modules/ui/field/input/components/TextInput.tsx
+++ b/packages/twenty-front/src/modules/ui/field/input/components/TextInput.tsx
@@ -1,5 +1,5 @@
-import { ChangeEvent, useEffect, useRef, useState } from 'react';
import styled from '@emotion/styled';
+import { ChangeEvent, useEffect, useRef, useState } from 'react';
import { TEXT_INPUT_STYLE } from 'twenty-ui';
import { LightCopyIconButton } from '@/object-record/record-field/components/LightCopyIconButton';
@@ -44,12 +44,11 @@ export const TextInput = ({
const copyRef = useRef(null);
const handleChange = (event: ChangeEvent) => {
- setInternalText(event.target.value);
- onChange?.(event.target.value);
+ setInternalText(event.target.value.trim());
+ onChange?.(event.target.value.trim());
};
-
useEffect(() => {
- setInternalText(value);
+ setInternalText(value.trim());
}, [value]);
useRegisterInputEvents({
diff --git a/packages/twenty-front/src/modules/ui/input/components/TextArea.tsx b/packages/twenty-front/src/modules/ui/input/components/TextArea.tsx
index aee5943e6..9b50504c7 100644
--- a/packages/twenty-front/src/modules/ui/input/components/TextArea.tsx
+++ b/packages/twenty-front/src/modules/ui/input/components/TextArea.tsx
@@ -1,9 +1,10 @@
+import styled from '@emotion/styled';
import { FocusEventHandler } from 'react';
import TextareaAutosize from 'react-textarea-autosize';
-import styled from '@emotion/styled';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
+import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
import { InputHotkeyScope } from '../types/InputHotkeyScope';
const MAX_ROWS = 5;
@@ -75,7 +76,9 @@ export const TextArea = ({
maxRows={MAX_ROWS}
minRows={computedMinRows}
value={value}
- onChange={(event) => onChange?.(event.target.value)}
+ onChange={(event) =>
+ onChange?.(turnIntoEmptyStringIfWhitespacesOnly(event.target.value))
+ }
onFocus={handleFocus}
onBlur={handleBlur}
disabled={disabled}
diff --git a/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx b/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx
index f7a5ddf8b..cf4b06f6a 100644
--- a/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx
+++ b/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx
@@ -11,6 +11,7 @@ import {
} from 'react';
import { IconComponent, IconEye, IconEyeOff } from 'twenty-ui';
import { useCombinedRefs } from '~/hooks/useCombinedRefs';
+import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
const StyledContainer = styled.div<
Pick
@@ -180,7 +181,7 @@ const TextInputV2Component = (
)}
) => {
- onChange?.(event.target.value);
+ onChange?.(
+ turnIntoEmptyStringIfWhitespacesOnly(event.target.value),
+ );
}}
onKeyDown={onKeyDown}
{...{
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/page/PageHeader.tsx b/packages/twenty-front/src/modules/ui/layout/page/PageHeader.tsx
index f352d7343..ed9586bf9 100644
--- a/packages/twenty-front/src/modules/ui/layout/page/PageHeader.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/page/PageHeader.tsx
@@ -30,7 +30,6 @@ const StyledTopBarContainer = styled.div<{ width?: number }>`
padding: ${({ theme }) => theme.spacing(2)};
padding-left: 0;
padding-right: ${({ theme }) => theme.spacing(3)};
- z-index: 20;
width: ${({ width }) => width + 'px' || '100%'};
@media (max-width: ${MOBILE_VIEWPORT}px) {
diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawer.tsx b/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawer.tsx
index 529b0d1f7..d28366027 100644
--- a/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawer.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawer.tsx
@@ -32,7 +32,7 @@ const StyledContainer = styled(motion.div)`
background: ${({ theme }) => theme.background.primary};
border-left: 1px solid ${({ theme }) => theme.border.color.medium};
box-shadow: ${({ theme }) => theme.boxShadow.strong};
- height: 100%;
+ height: 100dvh;
overflow-x: hidden;
position: fixed;
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' ? (
-
+
@@ -115,7 +122,7 @@ export const UpdateViewButtonGroup = ({
) : (