## Recoil to Jotai Migration — PR 13: Workflow, Page Layout, AI,
Activities, Settings, SSE & Remaining Modules

### Summary

This is the 13th PR in the [14-PR migration
series](packages/twenty-front/src/modules/ui/utilities/state/jotai/MIGRATION_PLAN.md)
to replace Recoil with Jotai as the state management library in
`twenty-front`. This PR migrates the remaining consumer code across all
modules — updating ~1,076 files with ~10k insertions/deletions.

### What changed

**New Jotai infrastructure (13 new files):**
- `createComponentSelectorV2` and `createComponentFamilySelectorV2` —
instance-scoped derived atoms, replacing Recoil's component selectors
- 6 new hooks: `useRecoilComponentSelectorValueV2`,
`useRecoilComponentFamilySelectorValueV2`,
`useRecoilComponentSelectorCallbackStateV2`,
`useRecoilComponentFamilySelectorCallbackStateV2`,
`useRecoilComponentStateCallbackStateV2`,
`useRecoilComponentFamilyStateCallbackStateV2`
- New types: `ComponentSelectorV2`, `ComponentFamilySelectorV2`,
`SelectorCallbacksV2`
- Extended `buildGetHelper` to support the new selector patterns

**State definition migrations:**
- `createState()` → `createStateV2()` (Jotai `atom()`)
- `createFamilyState()` → `createFamilyStateV2()` (Jotai `atom()` with
family cache)
- Recoil `selector`/`selectorFamily` → Jotai derived `atom()` via V2
utilities

**Hook migrations (~2,400 removed, ~1,545 added V2 equivalents):**
- `useRecoilValue` → `useRecoilValueV2`
- `useRecoilState` → `useRecoilStateV2`
- `useSetRecoilState` → `useSetRecoilStateV2`
- `useRecoilCallback` → `useCallback` + `jotaiStore.get/set`
- `useRecoilComponentValue` → `useRecoilComponentValueV2`
- `useSetRecoilComponentState` → `useSetRecoilComponentStateV2`
- `useRecoilComponentFamilyValue` → `useRecoilComponentFamilyValueV2` /
`useFamilySelectorValueV2`
- ~397 direct `import from 'recoil'` removed

**Deleted files (9 files):**
- `dateLocaleState.ts` — consolidated
- `currentAIChatThreadTitleStateV2.ts` — renamed to replace the original
- `isCommandMenuOpenedState.ts` — removed
- `filesFieldUploadState.ts` — replaced by V2
- `recordStoreFamilySelector.ts`, `recordStoreFieldValueSelector.ts`,
`recordStoreRecordsSelector.ts` — replaced by V2 equivalents
- `settingsAllRolesSelector.ts` — replaced by `useSettingsAllRoles` hook
- `settingsRoleIdsStateV2.ts` — consolidated

**Modules migrated:**
- Workflow (diagram, steps, variables, filters)
- Page Layout (widgets, fields, graph, tabs)
- AI (chat, agents, browsing context)
- Activities (rich text editor, targets, timeline)
- Action Menu (single/multiple record actions)
- Command Menu (navigation, history, pages, workflow)
- Context Store
- Record Board, Record Table, Record Calendar, Record Index
- Record Field, Record Filter, Record Sort, Record Group
- Record Drag, Record Picker, Record Store
- Views (view bar, view picker, filters, sorts)
- Settings (roles, permissions, SSO, security, data model, developers,
domains)
- SSE (event streams, subscriptions)
- Spreadsheet Import
- Auth, Favorites, Front Components, Information Banner
This commit is contained in:
Charles Bochet
2026-02-24 17:37:01 +01:00
committed by GitHub
parent c6ec764b23
commit 0f2af6a6cb
1326 changed files with 19248 additions and 19389 deletions
@@ -1,6 +1,6 @@
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2';
import { useEffect } from 'react';
import { useSetRecoilState } from 'recoil';
import { useSetAtom } from 'jotai';
type SettingsDataModelSetFieldValueEffectProps = {
recordId: string;
@@ -13,8 +13,8 @@ export const SettingsDataModelSetFieldValueEffect = ({
gqlFieldName,
value,
}: SettingsDataModelSetFieldValueEffectProps) => {
const setFieldValue = useSetRecoilState(
recordStoreFamilySelector({
const setFieldValue = useSetAtom(
recordStoreFamilySelectorV2.selectorFamily({
recordId,
fieldName: gqlFieldName,
}),
@@ -1,7 +1,7 @@
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { usePreviewRecord } from '@/settings/data-model/fields/preview/hooks/usePreviewRecord';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { useEffect } from 'react';
import { useSetRecoilState } from 'recoil';
type SettingsDataModelSetLabelIdentifierRecordEffectProps = {
objectNameSingular: string;
@@ -16,7 +16,7 @@ export const SettingsDataModelSetLabelIdentifierRecordEffect = ({
objectNameSingular: objectNameSingular,
});
const setRecord = useSetRecoilState(recordStoreFamilyState(recordId));
const setRecord = useSetFamilyRecoilStateV2(recordStoreFamilyState, recordId);
useEffect(() => {
setRecord(recordPreviewForLabelIdentifier);
@@ -13,8 +13,8 @@ import { TableRow } from '@/ui/layout/table/components/TableRow';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { useMemo } from 'react';
import { useRecoilState } from 'recoil';
import { FieldMetadataType, SettingsPath } from 'twenty-shared/types';
import { getSettingsPath, isDefined } from 'twenty-shared/utils';
import {
@@ -139,10 +139,9 @@ export const SettingsObjectFieldItemTableRow = ({
const { deleteOneFieldMetadataItem } = useDeleteOneFieldMetadataItem();
const [, setActiveSettingsObjectFields] = useRecoilState(
settingsObjectFieldsFamilyState({
objectMetadataItemId: objectMetadataItem.id,
}),
const setActiveSettingsObjectFields = useSetFamilyRecoilStateV2(
settingsObjectFieldsFamilyState,
{ objectMetadataItemId: objectMetadataItem.id },
);
const handleToggleField = () => {
@@ -11,7 +11,6 @@ import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMe
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import { zodResolver } from '@hookform/resolvers/zod';
import { FormProvider, useForm } from 'react-hook-form';
import { useSetRecoilState } from 'recoil';
import { SettingsPath } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
@@ -28,7 +27,7 @@ export const SettingsUpdateDataModelObjectAboutForm = ({
objectMetadataItem,
});
const navigate = useNavigateSettings();
const setUpdatedObjectNamePlural = useSetRecoilState(
const setUpdatedObjectNamePlural = useSetRecoilStateV2(
updatedObjectNamePluralState,
);
const setNavigationMemorizedUrl = useSetRecoilStateV2(
@@ -1,11 +1,11 @@
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState';
import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2';
export type SortedFieldByTableFamilyStateKey = {
objectMetadataItemId: string;
};
export const settingsObjectFieldsFamilyState = createFamilyState<
export const settingsObjectFieldsFamilyState = createFamilyStateV2<
FieldMetadataItem[] | null,
SortedFieldByTableFamilyStateKey
>({
@@ -1,11 +1,11 @@
import { type IndexMetadataItem } from '@/object-metadata/types/IndexMetadataItem';
import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState';
import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2';
export type SortedIndexByTableFamilyStateKey = {
objectMetadataItemId: string;
};
export const settingsObjectIndexesFamilyState = createFamilyState<
export const settingsObjectIndexesFamilyState = createFamilyStateV2<
IndexMetadataItem[] | null,
SortedIndexByTableFamilyStateKey
>({
@@ -1,6 +1,9 @@
import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState';
import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2';
export const apiKeyTokenFamilyState = createFamilyState<string | null, string>({
export const apiKeyTokenFamilyState = createFamilyStateV2<
string | null,
string
>({
key: 'apiKeyTokenState',
defaultValue: null,
});
@@ -19,7 +19,7 @@ import {
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { CheckPublicDomainValidRecordsEffect } from '@/settings/domains/components/CheckPublicDomainValidRecordsEffect';
import { selectedPublicDomainState } from '@/settings/domains/states/selectedPublicDomainState';
import { useRecoilState } from 'recoil';
import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
import { useState } from 'react';
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
import { getDomainValidationSchema } from '@/settings/domains/utils/get-domain-validation-schema';
@@ -48,7 +48,7 @@ const StyledRecordsWrapper = styled.div`
`;
export const SettingPublicDomain = () => {
const [selectedPublicDomain, setSelectedPublicDomain] = useRecoilState(
const [selectedPublicDomain, setSelectedPublicDomain] = useRecoilStateV2(
selectedPublicDomainState,
);
const { t } = useLingui();
@@ -4,7 +4,6 @@ import { TextInput } from '@/ui/input/components/TextInput';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { Controller, useFormContext } from 'react-hook-form';
import { useRecoilValue } from 'recoil';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { H2Title, IconReload, IconTrash } from 'twenty-ui/display';
import { Button, ButtonGroup } from 'twenty-ui/input';
@@ -38,7 +37,7 @@ const StyledRecordsWrapper = styled.div`
`;
export const SettingsCustomDomain = () => {
const { customDomainRecords, isLoading } = useRecoilValue(
const { customDomainRecords, isLoading } = useRecoilValueV2(
customDomainRecordsState,
);
@@ -2,8 +2,8 @@ import { SettingsCard } from '@/settings/components/SettingsCard';
import { SettingsListCard } from '@/settings/components/SettingsListCard';
import { SettingPublicDomainRowDropdownMenu } from '@/settings/domains/components/SettingPublicDomainRowDropdownMenu';
import { selectedPublicDomainState } from '@/settings/domains/states/selectedPublicDomainState';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import { useLingui } from '@lingui/react/macro';
import { useSetRecoilState } from 'recoil';
import { SettingsPath } from 'twenty-shared/types';
import { IconAt, IconMailCog, Status } from 'twenty-ui/display';
import {
@@ -17,7 +17,9 @@ export const SettingsPublicDomainsListCard = () => {
const { t } = useLingui();
const setSelectedPublicDomain = useSetRecoilState(selectedPublicDomainState);
const setSelectedPublicDomain = useSetRecoilStateV2(
selectedPublicDomainState,
);
const { data, loading } = useFindManyPublicDomainsQuery();
@@ -1,5 +1,5 @@
import { useCheckCustomDomainValidRecordsMutation } from '~/generated-metadata/graphql';
import { useRecoilState } from 'recoil';
import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
import { isDefined } from 'twenty-shared/utils';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { customDomainRecordsState } from '@/settings/domains/states/customDomainRecordsState';
@@ -12,7 +12,7 @@ export const useCheckCustomDomainValidRecords = () => {
const { enqueueErrorSnackBar } = useSnackBar();
const currentWorkspace = useRecoilValueV2(currentWorkspaceState);
const [{ isLoading }, setCustomDomainRecords] = useRecoilState(
const [{ isLoading }, setCustomDomainRecords] = useRecoilStateV2(
customDomainRecordsState,
);
@@ -1,7 +1,7 @@
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
import { type DomainValidRecords } from '~/generated-metadata/graphql';
import { createState } from '@/ui/utilities/state/utils/createState';
export const customDomainRecordsState = createState<{
export const customDomainRecordsState = createStateV2<{
customDomainRecords: DomainValidRecords | null;
isLoading: boolean;
}>({
@@ -1,7 +1,9 @@
import { type PublicDomain } from '~/generated-metadata/graphql';
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const selectedPublicDomainState = createState<PublicDomain | undefined>({
export const selectedPublicDomainState = createStateV2<
PublicDomain | undefined
>({
key: 'selectedPublicDomainState',
defaultValue: undefined,
});
@@ -1,11 +1,9 @@
import { LogicFunctionExecutionResult } from '@/logic-functions/components/LogicFunctionExecutionResult';
import {
type LogicFunctionTestData,
logicFunctionTestDataFamilyState,
} from '@/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { logicFunctionTestDataFamilyState } from '@/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { useRecoilState } from 'recoil';
import { H2Title, IconPlayerPlay } from 'twenty-ui/display';
import { Button, CodeEditor, CoreEditorHeader } from 'twenty-ui/input';
import { Section } from 'twenty-ui/layout';
@@ -33,10 +31,14 @@ export const SettingsLogicFunctionTestTab = ({
isTesting?: boolean;
}) => {
const { t } = useLingui();
const [logicFunctionTestData, setLogicFunctionTestData] =
useRecoilState<LogicFunctionTestData>(
logicFunctionTestDataFamilyState(logicFunctionId),
);
const logicFunctionTestData = useFamilyRecoilValueV2(
logicFunctionTestDataFamilyState,
logicFunctionId,
);
const setLogicFunctionTestData = useSetFamilyRecoilStateV2(
logicFunctionTestDataFamilyState,
logicFunctionId,
);
const onChange = (newInput: string) => {
setLogicFunctionTestData((prev) => ({
@@ -1,10 +1,10 @@
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
import { type FindManyLogicFunctionsQuery } from '~/generated-metadata/graphql';
export type LogicFunction =
FindManyLogicFunctionsQuery['findManyLogicFunctions'][number];
export const logicFunctionsState = createState<LogicFunction[]>({
export const logicFunctionsState = createStateV2<LogicFunction[]>({
key: 'logicFunctionsState',
defaultValue: [],
});
@@ -1,10 +1,9 @@
import { settingsAllRolesSelector } from '@/settings/roles/states/settingsAllRolesSelector';
import { useSettingsAllRoles } from '@/settings/roles/hooks/useSettingsAllRoles';
import { settingsRolesIsLoadingStateV2 } from '@/settings/roles/states/settingsRolesIsLoadingStateV2';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { useRecoilValue } from 'recoil';
export const useWorkspaceMemberRoles = (workspaceMemberId: string) => {
const settingsAllRoles = useRecoilValue(settingsAllRolesSelector);
const settingsAllRoles = useSettingsAllRoles();
const settingsRolesIsLoading = useRecoilValueV2(
settingsRolesIsLoadingStateV2,
);
@@ -1,5 +1,6 @@
import { playgroundApiKeyState } from '@/settings/playground/states/playgroundApiKeyState';
import { PlaygroundSchemas } from '@/settings/playground/types/PlaygroundSchemas';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import styled from '@emotion/styled';
import { explorerPlugin } from '@graphiql/plugin-explorer';
import '@graphiql/plugin-explorer/dist/style.css';
@@ -7,7 +8,6 @@ import { createGraphiQLFetcher } from '@graphiql/toolkit';
import { GraphiQL } from 'graphiql';
import 'graphiql/graphiql.css';
import { useContext } from 'react';
import { useRecoilValue } from 'recoil';
import { ThemeContext } from 'twenty-ui/theme';
import { REACT_APP_SERVER_BASE_URL } from '~/config';
@@ -35,7 +35,7 @@ export const GraphQLPlayground = ({
onError,
schema,
}: GraphQLPlaygroundProps) => {
const playgroundApiKey = useRecoilValue(playgroundApiKeyState);
const playgroundApiKey = useRecoilValueV2(playgroundApiKeyState);
const baseUrl = REACT_APP_SERVER_BASE_URL + '/' + schemaToPath[schema];
const { theme } = useContext(ThemeContext);
@@ -4,11 +4,11 @@ import { PlaygroundSchemas } from '@/settings/playground/types/PlaygroundSchemas
import { PlaygroundTypes } from '@/settings/playground/types/PlaygroundTypes';
import { Select } from '@/ui/input/components/Select';
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
import styled from '@emotion/styled';
import { zodResolver } from '@hookform/resolvers/zod';
import { useLingui } from '@lingui/react/macro';
import { Controller, useForm } from 'react-hook-form';
import { useRecoilState } from 'recoil';
import { SettingsPath } from 'twenty-shared/types';
import { CustomError } from 'twenty-shared/utils';
import { IconApi, IconBrandGraphql } from 'twenty-ui/display';
@@ -37,7 +37,7 @@ const StyledForm = styled.form`
export const PlaygroundSetupForm = () => {
const { t } = useLingui();
const navigateSettings = useNavigateSettings();
const [playgroundApiKey, setPlaygroundApiKey] = useRecoilState(
const [playgroundApiKey, setPlaygroundApiKey] = useRecoilStateV2(
playgroundApiKeyState,
);
@@ -1,10 +1,10 @@
import { playgroundApiKeyState } from '@/settings/playground/states/playgroundApiKeyState';
import { type PlaygroundSchemas } from '@/settings/playground/types/PlaygroundSchemas';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { lazy, Suspense } from 'react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { useRecoilValue } from 'recoil';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
import { REACT_APP_SERVER_BASE_URL } from '~/config';
@@ -51,7 +51,7 @@ type RestPlaygroundProps = {
export const RestPlayground = ({ onError, schema }: RestPlaygroundProps) => {
const theme = useTheme();
const playgroundApiKey = useRecoilValue(playgroundApiKeyState);
const playgroundApiKey = useRecoilValueV2(playgroundApiKeyState);
if (!playgroundApiKey) {
onError();
@@ -1,8 +1,8 @@
import { GraphQLPlayground } from '@/settings/playground/components/GraphQLPlayground';
import { playgroundApiKeyState } from '@/settings/playground/states/playgroundApiKeyState';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import { type Meta, type StoryObj } from '@storybook/react-vite';
import { useEffect } from 'react';
import { useSetRecoilState } from 'recoil';
import { action } from 'storybook/actions';
import {
ComponentDecorator,
@@ -11,7 +11,7 @@ import {
import { graphqlMocks } from '~/testing/graphqlMocks';
const PlaygroundApiKeySetterEffect = () => {
const setPlaygroundApiKey = useSetRecoilState(playgroundApiKeyState);
const setPlaygroundApiKey = useSetRecoilStateV2(playgroundApiKeyState);
useEffect(() => {
setPlaygroundApiKey('test-api-key-123');
@@ -1,15 +1,15 @@
import { RestPlayground } from '@/settings/playground/components/RestPlayground';
import { playgroundApiKeyState } from '@/settings/playground/states/playgroundApiKeyState';
import { PlaygroundSchemas } from '@/settings/playground/types/PlaygroundSchemas';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import { type Meta, type StoryObj } from '@storybook/react-vite';
import { HttpResponse, http } from 'msw';
import { useEffect } from 'react';
import { useSetRecoilState } from 'recoil';
import { action } from 'storybook/actions';
import { ComponentDecorator } from 'twenty-ui/testing';
const PlaygroundApiKeySetterEffect = () => {
const setPlaygroundApiKey = useSetRecoilState(playgroundApiKeyState);
const setPlaygroundApiKey = useSetRecoilStateV2(playgroundApiKeyState);
useEffect(() => {
setPlaygroundApiKey('test-api-key-123');
@@ -1,5 +1,5 @@
import { createState } from '@/ui/utilities/state/utils/createState';
export const openAPIReferenceState = createState<any>({
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const openAPIReferenceState = createStateV2<any>({
key: 'OpenAPIReference',
defaultValue: null,
});
@@ -1,8 +1,7 @@
import { atom } from 'recoil';
import { localStorageEffect } from '~/utils/recoil/localStorageEffect';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const playgroundApiKeyState = atom<string | null>({
export const playgroundApiKeyState = createStateV2<string | null>({
key: 'playgroundApiKeyState',
default: null,
effects: [localStorageEffect()],
defaultValue: null,
useLocalStorage: true,
});
@@ -6,18 +6,17 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain
import { SettingsRoleDefaultRole } from '@/settings/roles/components/SettingsRolesDefaultRole';
import { SettingsRolesList } from '@/settings/roles/components/SettingsRolesList';
import { settingsAllRolesSelector } from '@/settings/roles/states/settingsAllRolesSelector';
import { useSettingsAllRoles } from '@/settings/roles/hooks/useSettingsAllRoles';
import { settingsRolesIsLoadingStateV2 } from '@/settings/roles/states/settingsRolesIsLoadingStateV2';
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { Trans, useLingui } from '@lingui/react/macro';
import { useRecoilValue } from 'recoil';
import { H3Title } from 'twenty-ui/display';
export const SettingsRolesContainer = () => {
const { t } = useLingui();
const settingsAllRoles = useRecoilValue(settingsAllRolesSelector);
const settingsAllRoles = useSettingsAllRoles();
const settingsRolesIsLoading = useRecoilValueV2(
settingsRolesIsLoadingStateV2,
);
@@ -7,11 +7,10 @@ import { t } from '@lingui/core/macro';
import { SettingsRolesTableHeader } from '@/settings/roles/components/SettingsRolesTableHeader';
import { SettingsRolesTableRow } from '@/settings/roles/components/SettingsRolesTableRow';
import { settingsAllRolesSelector } from '@/settings/roles/states/settingsAllRolesSelector';
import { useSettingsAllRoles } from '@/settings/roles/hooks/useSettingsAllRoles';
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { useState } from 'react';
import { useRecoilValue } from 'recoil';
import { SettingsPath } from 'twenty-shared/types';
import {
H2Title,
@@ -61,7 +60,7 @@ export const SettingsRolesList = () => {
const [showAgentRoles, setShowAgentRoles] = useState(false);
const [showApiKeyRoles, setShowApiKeyRoles] = useState(false);
const settingsAllRoles = useRecoilValue(settingsAllRolesSelector);
const settingsAllRoles = useSettingsAllRoles();
const sortedSettingsAllRoles = [...settingsAllRoles].sort((a, b) =>
sortByAscString(a.label, b.label),
@@ -1,14 +1,11 @@
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState';
import { settingsRoleIdsState } from '@/settings/roles/states/settingsRoleIdsState';
import { settingsRoleIdsStateV2 } from '@/settings/roles/states/settingsRoleIdsStateV2';
import { settingsRolesIsLoadingStateV2 } from '@/settings/roles/states/settingsRolesIsLoadingStateV2';
import { type RoleWithPartialMembers } from '@/settings/roles/types/RoleWithPartialMembers';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { useEffect } from 'react';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import { useStore } from 'jotai';
import { useRecoilCallback } from 'recoil';
import { useCallback, useEffect } from 'react';
import { isDefined } from 'twenty-shared/utils';
import { useGetRolesQuery } from '~/generated-metadata/graphql';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
@@ -24,34 +21,30 @@ export const SettingsRolesQueryEffect = () => {
const store = useStore();
const populateRoles = useRecoilCallback(
({ set, snapshot }) =>
(roles: RoleWithPartialMembers[]) => {
const roleIds = roles.map((role) => role.id);
set(settingsRoleIdsState, roleIds);
store.set(settingsRoleIdsStateV2.atom, roleIds);
roles.forEach((role) => {
const persistedRole = getSnapshotValue(
snapshot,
settingsPersistedRoleFamilyState(role.id),
);
const populateRoles = useCallback(
(roles: RoleWithPartialMembers[]) => {
const roleIds = roles.map((role) => role.id);
store.set(settingsRoleIdsState.atom, roleIds);
roles.forEach((role) => {
const persistedRole = store.get(
settingsPersistedRoleFamilyState.atomFamily(role.id),
);
const currentDraftRole = getSnapshotValue(
snapshot,
settingsDraftRoleFamilyState(role.id),
);
const currentDraftRole = store.get(
settingsDraftRoleFamilyState.atomFamily(role.id),
);
if (isDeeplyEqual(role, persistedRole)) {
return;
}
if (isDeeplyEqual(role, persistedRole)) {
return;
}
set(settingsPersistedRoleFamilyState(role.id), role);
store.set(settingsPersistedRoleFamilyState.atomFamily(role.id), role);
if (!isDeeplyEqual(currentDraftRole, role)) {
set(settingsDraftRoleFamilyState(role.id), role);
}
});
},
if (!isDeeplyEqual(currentDraftRole, role)) {
store.set(settingsDraftRoleFamilyState.atomFamily(role.id), role);
}
});
},
[store],
);
@@ -0,0 +1,18 @@
import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState';
import { settingsRoleIdsState } from '@/settings/roles/states/settingsRoleIdsState';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { useStore } from 'jotai';
import { isDefined } from 'twenty-shared/utils';
export const useSettingsAllRoles = () => {
const roleIds = useRecoilValueV2(settingsRoleIdsState);
const store = useStore();
const roles = roleIds
.map((roleId) =>
store.get(settingsPersistedRoleFamilyState.atomFamily(roleId)),
)
.filter(isDefined);
return roles;
};
@@ -1,13 +1,19 @@
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useRecoilState } from 'recoil';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import {
useAssignRoleToAgentMutation,
type Agent,
} from '~/generated-metadata/graphql';
export const useUpdateAgentRole = (roleId: string) => {
const [settingsDraftRole, setSettingsDraftRole] = useRecoilState(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const setSettingsDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
roleId,
);
const [assignRoleToAgentMutation] = useAssignRoleToAgentMutation();
@@ -1,13 +1,19 @@
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useRecoilState } from 'recoil';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import {
useAssignRoleToApiKeyMutation,
type ApiKeyForRole,
} from '~/generated-metadata/graphql';
export const useUpdateApiKeyRole = (roleId: string) => {
const [settingsDraftRole, setSettingsDraftRole] = useRecoilState(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const setSettingsDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
roleId,
);
const [assignRoleToApiKeyMutation] = useAssignRoleToApiKeyMutation();
@@ -1,8 +1,9 @@
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState';
import { useRecoilState, useSetRecoilState } from 'recoil';
import { useUpdateWorkspaceMemberRoleMutation } from '~/generated-metadata/graphql';
import { type PartialWorkspaceMember } from '@/settings/roles/types/RoleWithPartialMembers';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { useUpdateWorkspaceMemberRoleMutation } from '~/generated-metadata/graphql';
type AddWorkspaceMemberToRoleAndUpdateStateParams = {
workspaceMemberId: string;
@@ -18,11 +19,17 @@ type AddWorkspaceMembersToRoleParams = {
};
export const useUpdateWorkspaceMemberRole = (roleId: string) => {
const setSettingsPersistedRole = useSetRecoilState(
settingsPersistedRoleFamilyState(roleId),
const setSettingsPersistedRole = useSetFamilyRecoilStateV2(
settingsPersistedRoleFamilyState,
roleId,
);
const [settingsDraftRole, setSettingsDraftRole] = useRecoilState(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const setSettingsDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
roleId,
);
const [updateWorkspaceMemberRoleMutation] =
@@ -6,14 +6,14 @@ import { useUpdateWorkspaceMemberRole } from '@/settings/roles/hooks/useUpdateWo
import { RoleAssignmentSection } from '@/settings/roles/role-assignment/components/RoleAssignmentSection';
import { SettingsRoleAssignmentConfirmationModal } from '@/settings/roles/role-assignment/components/SettingsRoleAssignmentConfirmationModal';
import { type SettingsRoleAssignmentConfirmationModalSelectedRoleTarget } from '@/settings/roles/role-assignment/types/SettingsRoleAssignmentConfirmationModalSelectedRoleTarget';
import { settingsAllRolesSelector } from '@/settings/roles/states/settingsAllRolesSelector';
import { useSettingsAllRoles } from '@/settings/roles/hooks/useSettingsAllRoles';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
import { isModalOpenedComponentState } from '@/ui/layout/modal/states/isModalOpenedComponentState';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useState } from 'react';
import { useRecoilValue } from 'recoil';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { SettingsPath } from 'twenty-shared/types';
import {
@@ -40,8 +40,9 @@ export const SettingsRoleAssignment = ({
}: SettingsRoleAssignmentProps) => {
const isAiEnabled = useIsFeatureEnabled(FeatureFlagKey.IS_AI_ENABLED);
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const navigateSettings = useNavigateSettings();
@@ -69,7 +70,7 @@ export const SettingsRoleAssignment = ({
currentWorkspaceMembersState,
);
const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState);
const settingsAllRoles = useRecoilValue(settingsAllRolesSelector);
const settingsAllRoles = useSettingsAllRoles();
const roleMaps = buildRoleMaps(settingsAllRoles);
@@ -4,13 +4,13 @@ import {
} from '@/settings/roles/role-assignment/components/SettingsRoleAssignmentTableRow';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { useMemo, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { H2Title, IconSearch } from 'twenty-ui/display';
import { type Agent, type ApiKeyForRole } from '~/generated-metadata/graphql';
@@ -52,8 +52,9 @@ export const SettingsRoleAssignmentTable = <T extends RoleTargetType>({
roleTargetType,
roleId,
}: SettingsRoleAssignmentTableProps<T>) => {
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const [searchFilter, setSearchFilter] = useState('');
@@ -6,7 +6,6 @@ import { useTheme } from '@emotion/react';
import { t } from '@lingui/core/macro';
import styled from '@emotion/styled';
import { useContext } from 'react';
import { useRecoilValue } from 'recoil';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import {
Avatar,
@@ -15,7 +14,7 @@ import {
useIcons,
} from 'twenty-ui/display';
import { type Agent, type ApiKeyForRole } from '~/generated-metadata/graphql';
import { dateLocaleState } from '~/localization/states/dateLocaleState';
import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2';
import { formatDateString } from '~/utils/string/formatDateString';
import { type PartialWorkspaceMember } from '@/settings/roles/types/RoleWithPartialMembers';
@@ -61,7 +60,7 @@ export const SettingsRoleAssignmentTableRow = ({
);
const { getIcon } = useIcons();
const { dateFormat, timeZone } = useContext(UserContext);
const dateLocale = useRecoilValue(dateLocaleState);
const dateLocale = useRecoilValueV2(dateLocaleStateV2);
const renderIcon = () => {
switch (roleTarget.type) {
@@ -1,7 +1,7 @@
import { SettingsRoleAssignment } from '@/settings/roles/role-assignment/components/SettingsRoleAssignment';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { type Meta, type StoryObj } from '@storybook/react-vite';
import { useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
import { getRolesMock } from '~/testing/mock-data/roles';
@@ -9,8 +9,9 @@ import { getRolesMock } from '~/testing/mock-data/roles';
const SettingsRoleAssignmentWrapper = (
args: React.ComponentProps<typeof SettingsRoleAssignment>,
) => {
const setDraftRole = useSetRecoilState(
settingsDraftRoleFamilyState(args.roleId),
const setDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
args.roleId,
);
const role = getRolesMock().find((role) => role.id === args.roleId);
@@ -1,7 +1,7 @@
import { SettingsRolePermissions } from '@/settings/roles/role-permissions/components/SettingsRolePermissions';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { type Meta, type StoryObj } from '@storybook/react-vite';
import { useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
import { getRolesMock } from '~/testing/mock-data/roles';
@@ -9,8 +9,9 @@ import { getRolesMock } from '~/testing/mock-data/roles';
const SettingsRolePermissionsWrapper = (
args: React.ComponentProps<typeof SettingsRolePermissions>,
) => {
const setDraftRole = useSetRecoilState(
settingsDraftRoleFamilyState(args.roleId),
const setDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
args.roleId,
);
const role = getRolesMock().find((role) => role.id === args.roleId);
@@ -4,9 +4,9 @@ import { PermissionIcon } from '@/settings/roles/role-permissions/objects-permis
import { SETTINGS_ROLE_OBJECT_LEVEL_PERMISSION_TO_ROLE_OBJECT_PERMISSION_MAPPING } from '@/settings/roles/role-permissions/objects-permissions/constants/SettingsRoleObjectLevelPermissionToRoleObjectPermissionMapping';
import { type SettingsRoleObjectPermissionKey } from '@/settings/roles/role-permissions/objects-permissions/constants/SettingsRoleObjectPermissionIconConfig';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { AppTooltip, TooltipDelay } from 'twenty-ui/display';
@@ -27,8 +27,9 @@ export const SettingsRolePermissionsObjectLevelOverrideCell = ({
roleId,
objectLabel,
}: SettingsRolePermissionsObjectLevelOverrideCellProps) => {
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const roleLabel = settingsDraftRole.label;
@@ -5,11 +5,11 @@ import { useFilterObjectMetadataItemsWithPermissionOverride } from '@/settings/r
import { useObjectMetadataItemsThatCanHavePermission } from '@/settings/roles/role-permissions/object-level-permissions/hooks/useObjectMetadataItemsThatCanHavePermission';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { Table } from '@/ui/layout/table/components/Table';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { useMemo } from 'react';
import { useRecoilValue } from 'recoil';
import { SettingsPath } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { IconPlus } from 'twenty-ui/display';
@@ -49,8 +49,9 @@ export const SettingsRolePermissionsObjectLevelSection = ({
}: SettingsRolePermissionsObjectLevelSectionProps) => {
const navigateSettings = useNavigateSettings();
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const { objectMetadataItemsThatCanHavePermission } =
@@ -2,8 +2,8 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI
import { isHiddenSystemField } from '@/object-metadata/utils/isHiddenSystemField';
import { useObjectPermissionDerivedStates } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useObjectPermissionDerivedStates';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useLingui } from '@lingui/react/macro';
import { useRecoilValue } from 'recoil';
type SettingsRolePermissionsObjectLevelSeeFieldsValueForObjectProps = {
roleId: string;
@@ -16,8 +16,9 @@ export const SettingsRolePermissionsObjectLevelSeeFieldsValueForObject = ({
}: SettingsRolePermissionsObjectLevelSeeFieldsValueForObjectProps) => {
const { t } = useLingui();
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const objectMetadataItemId = objectMetadataItem.id;
@@ -2,8 +2,8 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI
import { filterUserFacingFieldMetadataItems } from '@/object-metadata/utils/filterUserFacingFieldMetadataItems';
import { useObjectPermissionDerivedStates } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useObjectPermissionDerivedStates';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useLingui } from '@lingui/react/macro';
import { useRecoilValue } from 'recoil';
type SettingsRolePermissionsObjectLevelUpdateFieldsValueForObjectProps = {
roleId: string;
@@ -16,8 +16,9 @@ export const SettingsRolePermissionsObjectLevelUpdateFieldsValueForObject = ({
}: SettingsRolePermissionsObjectLevelUpdateFieldsValueForObjectProps) => {
const { t } = useLingui();
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const objectMetadataItemId = objectMetadataItem.id;
@@ -18,7 +18,6 @@ import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFami
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { useState } from 'react';
import { useRecoilValue } from 'recoil';
import { isNonEmptyArray } from 'twenty-shared/utils';
import { H2Title, IconSearch } from 'twenty-ui/display';
import { Section } from 'twenty-ui/layout';
@@ -70,8 +69,9 @@ export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTable = ({
),
);
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const fieldPermissions =
@@ -7,9 +7,9 @@ import { useRestrictReadOnAllFieldsOfObject } from '@/settings/roles/role-permis
import { useRestrictUpdateOnAllFieldsOfObject } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRestrictUpdateOnAllFieldsOfObject';
import { OverridableCheckbox } from '@/settings/roles/role-permissions/object-level-permissions/object-form/components/OverridableCheckbox';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { useRecoilState } from 'recoil';
import { Label } from 'twenty-ui/display';
const StyledSectionHeader = styled.div`
@@ -40,8 +40,9 @@ export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTableAllHead
}) => {
const { t } = useLingui();
const [settingsDraftRole] = useRecoilState(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const { cannotAllowFieldReadRestrict, cannotAllowFieldUpdateRestrict } =
@@ -5,11 +5,15 @@ import {
MOCK_OBJECT_PERMISSION_3_NULL_ALL,
MOCK_ROLE_ID_GRANTS_ALL,
MOCK_ROLE_ID_REVOKES_ALL,
initializeRolesMockJotaiStore,
rolesMockHookWrapper,
} from '~/testing/mock-data/roles/roles-mock';
import { useGetObjectPermissionDerivedStates } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useGetObjectPermissionDerivedStates';
describe('useGetObjectPermissionDerivedStates', () => {
beforeEach(() => {
initializeRolesMockJotaiStore();
});
it('should return expected for object that revoke permissions', () => {
const { result } = renderHook(
() =>
@@ -1,5 +1,5 @@
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useRecoilValue } from 'recoil';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { isDefined } from 'twenty-shared/utils';
export const useGetObjectPermissionDerivedStates = ({
@@ -7,8 +7,9 @@ export const useGetObjectPermissionDerivedStates = ({
}: {
roleId: string;
}) => {
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const getObjectPermissionDerivedStates = (objectMetadataItemId: string) => {
@@ -1,23 +1,25 @@
import { getRoleWithRemovedFieldPermission } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/utils/getRoleWithRemovedFieldPermission';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useRecoilCallback } from 'recoil';
import { useStore } from 'jotai';
import { useCallback } from 'react';
export const useRemoveFieldPermissionInDraftRole = () => {
const removeFieldPermissionInDraftRole = useRecoilCallback(
({ set, snapshot }) =>
(roleId: string, fieldPermissionFieldMetadataId: string) => {
const currentSettingsDraftRole = snapshot
.getLoadable(settingsDraftRoleFamilyState(roleId))
.getValue();
const store = useStore();
const newRole = getRoleWithRemovedFieldPermission(
currentSettingsDraftRole,
fieldPermissionFieldMetadataId,
);
const removeFieldPermissionInDraftRole = useCallback(
(roleId: string, fieldPermissionFieldMetadataId: string) => {
const currentSettingsDraftRole = store.get(
settingsDraftRoleFamilyState.atomFamily(roleId),
);
set(settingsDraftRoleFamilyState(roleId), newRole);
},
[],
const newRole = getRoleWithRemovedFieldPermission(
currentSettingsDraftRole,
fieldPermissionFieldMetadataId,
);
store.set(settingsDraftRoleFamilyState.atomFamily(roleId), newRole);
},
[store],
);
return {
@@ -1,15 +1,16 @@
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { useUpsertFieldPermissionInDraftRole } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useUpsertFieldPermissionInDraftRole';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useRecoilValue } from 'recoil';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
export const useRemoveReadOverrideOnAllFieldsOfObject = ({
roleId,
}: {
roleId: string;
}) => {
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const { upsertFieldPermissionInDraftRole } =
@@ -1,15 +1,16 @@
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { useUpsertFieldPermissionInDraftRole } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useUpsertFieldPermissionInDraftRole';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useRecoilValue } from 'recoil';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
export const useRemoveUpdateOverrideOnAllFieldsOfObject = ({
roleId,
}: {
roleId: string;
}) => {
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const { upsertFieldPermissionInDraftRole } =
@@ -2,7 +2,7 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI
import { filterUserFacingFieldMetadataItems } from '@/object-metadata/utils/filterUserFacingFieldMetadataItems';
import { useUpsertFieldPermissionInDraftRole } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useUpsertFieldPermissionInDraftRole';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useRecoilValue } from 'recoil';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { isDefined } from 'twenty-shared/utils';
import { v4 } from 'uuid';
@@ -11,8 +11,9 @@ export const useRestrictReadOnAllFieldsOfObject = ({
}: {
roleId: string;
}) => {
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const { upsertFieldPermissionInDraftRole } =
@@ -2,7 +2,7 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI
import { filterUserFacingFieldMetadataItems } from '@/object-metadata/utils/filterUserFacingFieldMetadataItems';
import { useUpsertFieldPermissionInDraftRole } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useUpsertFieldPermissionInDraftRole';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useRecoilValue } from 'recoil';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { isDefined } from 'twenty-shared/utils';
import { v4 } from 'uuid';
@@ -11,8 +11,9 @@ export const useRestrictUpdateOnAllFieldsOfObject = ({
}: {
roleId: string;
}) => {
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const { upsertFieldPermissionInDraftRole } =
@@ -1,11 +1,12 @@
import { getRoleWithUpsertedFieldPermission } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/utils/getRoleWithUpsertedFieldPermission';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useSetRecoilState } from 'recoil';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { type FieldPermission } from '~/generated-metadata/graphql';
export const useUpsertFieldPermissionInDraftRole = (roleId: string) => {
const setSettingsDraftRole = useSetRecoilState(
settingsDraftRoleFamilyState(roleId),
const setSettingsDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
roleId,
);
const upsertFieldPermissionInDraftRole = (
@@ -2,7 +2,7 @@ import { useUpsertFieldPermissionInDraftRole } from '@/settings/roles/role-permi
import { useUpsertObjectPermissionInDraftRole } from '@/settings/roles/role-permissions/object-level-permissions/hooks/useUpsertObjectPermissionInDraftRole';
import { type SettingsRoleObjectPermissionKey } from '@/settings/roles/role-permissions/objects-permissions/constants/SettingsRoleObjectPermissionIconConfig';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useRecoilValue } from 'recoil';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { isDefined } from 'twenty-shared/utils';
import {
type FieldPermission,
@@ -17,8 +17,9 @@ const OBJECT_PERMISSION_KEYS: SettingsRoleObjectPermissionKey[] = [
];
export const useResetObjectPermission = (roleId: string) => {
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const { upsertObjectPermissionInDraftRole } =
@@ -1,13 +1,14 @@
import { useUpsertObjectPermissionInDraftRole } from '@/settings/roles/role-permissions/object-level-permissions/hooks/useUpsertObjectPermissionInDraftRole';
import { type SettingsRoleObjectPermissionKey } from '@/settings/roles/role-permissions/objects-permissions/constants/SettingsRoleObjectPermissionIconConfig';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useRecoilValue } from 'recoil';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { isDefined } from 'twenty-shared/utils';
import { type ObjectPermission } from '~/generated-metadata/graphql';
export const useUpsertObjectPermission = ({ roleId }: { roleId: string }) => {
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const { upsertObjectPermissionInDraftRole } =
@@ -1,11 +1,12 @@
import { getRoleWithUpsertedObjectPermission } from '@/settings/roles/role-permissions/object-level-permissions/hooks/getRoleWithUpsertedObjectPermission';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useSetRecoilState } from 'recoil';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { type ObjectPermission } from '~/generated-metadata/graphql';
export const useUpsertObjectPermissionInDraftRole = (roleId: string) => {
const setSettingsDraftRole = useSetRecoilState(
settingsDraftRoleFamilyState(roleId),
const setSettingsDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
roleId,
);
const upsertObjectPermissionInDraftRole = (
@@ -7,10 +7,10 @@ import { SettingsRolePermissionsObjectLevelObjectFormObjectLevel } from '@/setti
import { SettingsRolePermissionsObjectLevelRecordLevelSection } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import { t } from '@lingui/core/macro';
import { useSearchParams } from 'react-router-dom';
import { useRecoilValue } from 'recoil';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { SettingsPath, type ViewFilterOperand } from 'twenty-shared/types';
import { getSettingsPath, isDefined } from 'twenty-shared/utils';
@@ -36,8 +36,9 @@ export const SettingsRolePermissionsObjectLevelObjectForm = ({
const currentWorkspace = useRecoilValueV2(currentWorkspaceState);
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const { data: agentData } = useFindOneAgentQuery({
@@ -3,9 +3,9 @@ import { SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableHeader } fr
import { SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRow } from '@/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRow';
import { type SettingsRolePermissionsObjectLevelPermission } from '@/settings/roles/role-permissions/objects-permissions/types/SettingsRolePermissionsObjectPermission';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { useRecoilValue } from 'recoil';
import { H2Title } from 'twenty-ui/display';
import { Section } from 'twenty-ui/layout';
@@ -27,8 +27,9 @@ export const SettingsRolePermissionsObjectLevelObjectFormObjectLevel = ({
roleId,
objectMetadataItem,
}: SettingsRolePermissionsObjectLevelObjectFormObjectLevelProps) => {
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const settingsDraftRoleObjectPermissions =
@@ -7,10 +7,10 @@ import { type SettingsRoleObjectPermissionKey } from '@/settings/roles/role-perm
import { type SettingsRolePermissionsObjectLevelPermission } from '@/settings/roles/role-permissions/objects-permissions/types/SettingsRolePermissionsObjectPermission';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { type ObjectPermission, type Role } from '~/generated-metadata/graphql';
@@ -70,8 +70,9 @@ export const SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRow =
settingsDraftRoleObjectPermissions,
roleId,
}: SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRowProps) => {
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const label = permission.label;
@@ -9,7 +9,7 @@ import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/o
import { SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectFieldMenu } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectFieldMenu';
import { SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectSubFieldMenu } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectSubFieldMenu';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2';
const StyledContainer = styled.div`
flex: 2;
@@ -28,7 +28,7 @@ export const SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelect
useAdvancedFilterFieldSelectDropdown(recordFilterId);
const [objectFilterDropdownIsSelectingCompositeField] =
useRecoilComponentState(
useRecoilComponentStateV2(
objectFilterDropdownIsSelectingCompositeFieldComponentState,
);
@@ -24,8 +24,8 @@ import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/Gene
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2';
import { useContext } from 'react';
import { FieldMetadataType } from 'twenty-shared/types';
@@ -45,7 +45,7 @@ export const SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectF
advancedFilterFieldSelectDropdownId,
} = useAdvancedFilterFieldSelectDropdown(recordFilterId);
const [objectFilterDropdownSearchInput] = useRecoilComponentState(
const [objectFilterDropdownSearchInput] = useRecoilComponentStateV2(
objectFilterDropdownSearchInputComponentState,
);
@@ -77,16 +77,17 @@ export const SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectF
const { selectFieldUsedInAdvancedFilterDropdown } =
useSelectFieldUsedInAdvancedFilterDropdown();
const [, setObjectFilterDropdownSubMenuFieldType] = useRecoilComponentState(
objectFilterDropdownSubMenuFieldTypeComponentState,
);
const [, setObjectFilterDropdownSubMenuFieldType] =
useRecoilComponentStateV2(
objectFilterDropdownSubMenuFieldTypeComponentState,
);
const [, setObjectFilterDropdownIsSelectingCompositeField] =
useRecoilComponentState(
useRecoilComponentStateV2(
objectFilterDropdownIsSelectingCompositeFieldComponentState,
);
const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentState(
const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2(
fieldMetadataItemIdUsedInDropdownComponentState,
);
@@ -27,8 +27,8 @@ import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/Gene
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2';
import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
type SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectSubFieldMenuProps =
@@ -42,19 +42,19 @@ export const SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectS
}: SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectSubFieldMenuProps) => {
const { getIcon } = useIcons();
const fieldMetadataItemUsedInDropdown = useRecoilComponentValue(
const fieldMetadataItemUsedInDropdown = useRecoilComponentSelectorValueV2(
fieldMetadataItemUsedInDropdownComponentSelector,
);
const [, setObjectFilterDropdownIsSelectingCompositeField] =
useRecoilComponentState(
useRecoilComponentStateV2(
objectFilterDropdownIsSelectingCompositeFieldComponentState,
);
const [
objectFilterDropdownSubMenuFieldType,
setObjectFilterDropdownSubMenuFieldType,
] = useRecoilComponentState(
] = useRecoilComponentStateV2(
objectFilterDropdownSubMenuFieldTypeComponentState,
);
@@ -2,7 +2,6 @@
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { IconFilter, IconPlus } from 'twenty-ui/display';
import { Button } from 'twenty-ui/input';
@@ -23,8 +22,10 @@ import { useRecordLevelPermissionFilterActions } from '@/settings/roles/role-per
import { useRecordLevelPermissionFilterInitialization } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/hooks/useRecordLevelPermissionFilterInitialization';
import { useRecordLevelPermissionSyncToDraftRole } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/hooks/useRecordLevelPermissionSyncToDraftRole';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2';
const StyledContainer = styled.div`
align-items: start;
@@ -55,34 +56,35 @@ export const SettingsRolePermissionsObjectLevelRecordLevelPermissionFilterBuilde
roleId,
objectMetadataItem,
}: SettingsRolePermissionsObjectLevelRecordLevelPermissionFilterBuilderContentProps) => {
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems(
objectMetadataItem.id,
);
const setCurrentRecordFilters = useSetRecoilComponentState(
const setCurrentRecordFilters = useSetRecoilComponentStateV2(
currentRecordFiltersComponentState,
);
const setCurrentRecordFilterGroups = useSetRecoilComponentState(
const setCurrentRecordFilterGroups = useSetRecoilComponentStateV2(
currentRecordFilterGroupsComponentState,
);
const currentRecordFilters = useRecoilComponentValue(
const currentRecordFilters = useRecoilComponentValueV2(
currentRecordFiltersComponentState,
);
const currentRecordFilterGroups = useRecoilComponentValue(
const currentRecordFilterGroups = useRecoilComponentValueV2(
currentRecordFilterGroupsComponentState,
);
const { setRecordFilterUsedInAdvancedFilterDropdownRow } =
useSetRecordFilterUsedInAdvancedFilterDropdownRow();
const rootRecordFilterGroup = useRecoilComponentValue(
const rootRecordFilterGroup = useRecoilComponentSelectorValueV2(
rootLevelRecordFilterGroupComponentSelector,
);
@@ -29,7 +29,8 @@ import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
const StyledSearchInput = styled.input`
background: transparent;
@@ -76,11 +77,11 @@ export const SettingsRolePermissionsObjectLevelRecordLevelPermissionMeValueSelec
objectNameSingular: CoreObjectNameSingular.WorkspaceMember,
});
const selectedFieldMetadataItem = useRecoilComponentValue(
const selectedFieldMetadataItem = useRecoilComponentSelectorValueV2(
fieldMetadataItemUsedInDropdownComponentSelector,
);
const currentRecordFilters = useRecoilComponentValue(
const currentRecordFilters = useRecoilComponentValueV2(
currentRecordFiltersComponentState,
);
@@ -25,7 +25,7 @@ import { FormMultiSelectFieldInput } from '@/object-record/record-field/ui/form-
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
import { type CompositeFieldType } from '@/settings/data-model/types/CompositeFieldType';
import { createRecordLevelPermissionVariablePicker } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionVariablePicker';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
const StyledContainer = styled.div`
align-items: stretch;
@@ -102,7 +102,7 @@ export const SettingsRolePermissionsObjectLevelRecordLevelPermissionValueInput =
const { objectMetadataItem } = useContext(AdvancedFilterContext);
const currentRecordFilters = useRecoilComponentValue(
const currentRecordFilters = useRecoilComponentValueV2(
currentRecordFiltersComponentState,
);
@@ -23,7 +23,7 @@ import { type RecordFilter } from '@/object-record/record-filter/types/RecordFil
import { getDefaultSubFieldNameForCompositeFilterableFieldType } from '@/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType';
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
import { RECORD_LEVEL_PERMISSION_PREDICATE_FIELD_TYPES } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/constants/RecordLevelPermissionPredicateFieldTypes';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2';
import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2';
type UseRecordLevelPermissionFilterActionsProps = {
@@ -49,7 +49,7 @@ export const useRecordLevelPermissionFilterActions = ({
},
);
const rootRecordFilterGroup = useRecoilComponentValue(
const rootRecordFilterGroup = useRecoilComponentSelectorValueV2(
rootLevelRecordFilterGroupComponentSelector,
);
@@ -1,7 +1,6 @@
/* @license Enterprise */
import { useCallback, useEffect } from 'react';
import { useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
@@ -12,6 +11,7 @@ import {
convertRecordFilterToPredicate,
} from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/utils/recordLevelPermissionPredicateConversion';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
type UseRecordLevelPermissionSyncToDraftRoleProps = {
roleId: string;
@@ -28,8 +28,9 @@ export const useRecordLevelPermissionSyncToDraftRole = ({
currentRecordFilterGroups,
hasInitialized,
}: UseRecordLevelPermissionSyncToDraftRoleProps) => {
const setSettingsDraftRole = useSetRecoilState(
settingsDraftRoleFamilyState(roleId),
const setSettingsDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
roleId,
);
const syncToDraftRole = useCallback(() => {
@@ -2,9 +2,10 @@ import { SettingsRolePermissionsObjectsTableHeader } from '@/settings/roles/role
import { SettingsRolePermissionsObjectsTableRow } from '@/settings/roles/role-permissions/objects-permissions/components/SettingsRolePermissionsObjectsTableRow';
import { type SettingsRolePermissionsObjectPermission } from '@/settings/roles/role-permissions/objects-permissions/types/SettingsRolePermissionsObjectPermission';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { useRecoilState } from 'recoil';
import { H2Title } from 'twenty-ui/display';
import { Section } from 'twenty-ui/layout';
@@ -26,8 +27,13 @@ export const SettingsRolePermissionsObjectsSection = ({
roleId,
isEditable,
}: SettingsRolePermissionsObjectsSectionProps) => {
const [settingsDraftRole, setSettingsDraftRole] = useRecoilState(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const setSettingsDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
roleId,
);
const objectPermissions = settingsDraftRole.objectPermissions;
@@ -1,10 +1,11 @@
import { type SettingsRolePermissionsObjectPermission } from '@/settings/roles/role-permissions/objects-permissions/types/SettingsRolePermissionsObjectPermission';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { useRecoilState } from 'recoil';
import { Checkbox } from 'twenty-ui/input';
const StyledNameHeader = styled(TableHeader)`
@@ -29,8 +30,13 @@ export const SettingsRolePermissionsObjectsTableHeader = ({
objectPermissionsConfig,
isEditable,
}: SettingsRolePermissionsObjectsTableHeaderProps) => {
const [settingsDraftRole, setSettingsDraftRole] = useRecoilState(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const setSettingsDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
roleId,
);
const allPermissionsEnabled = objectPermissionsConfig.every(
@@ -3,9 +3,10 @@ import { SettingsRolePermissionsSettingsTableHeader } from '@/settings/roles/rol
import { SettingsRolePermissionsSettingsTableRow } from '@/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsTableRow';
import { useSettingsRolePermissionFlagConfig } from '@/settings/roles/role-permissions/permission-flags/hooks/useSettingsRolePermissionFlagConfig';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { useRecoilState } from 'recoil';
import { H2Title, IconSettings } from 'twenty-ui/display';
import { AnimatedExpandableContainer, Card, Section } from 'twenty-ui/layout';
@@ -31,8 +32,13 @@ export const SettingsRolePermissionsSettingsSection = ({
roleId,
isEditable,
}: SettingsRolePermissionsSettingsSectionProps) => {
const [settingsDraftRole, setSettingsDraftRole] = useRecoilState(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const setSettingsDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
roleId,
);
const settingsPermissionsConfig = useSettingsRolePermissionFlagConfig({
@@ -6,7 +6,8 @@ import { Checkbox } from 'twenty-ui/input';
import { type SettingsRolePermissionsSettingPermission } from '@/settings/roles/role-permissions/permission-flags/types/SettingsRolePermissionsSettingPermission';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useRecoilState } from 'recoil';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { v4 } from 'uuid';
type SettingsRolePermissionsSettingsTableHeaderProps = {
@@ -27,8 +28,13 @@ export const SettingsRolePermissionsSettingsTableHeader = ({
settingsPermissionsConfig,
isEditable,
}: SettingsRolePermissionsSettingsTableHeaderProps) => {
const [settingsDraftRole, setSettingsDraftRole] = useRecoilState(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const setSettingsDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
roleId,
);
const allSettingsPermissionsEnabled = settingsPermissionsConfig.every(
(permission) =>
@@ -1,10 +1,11 @@
import { type SettingsRolePermissionsSettingPermission } from '@/settings/roles/role-permissions/permission-flags/types/SettingsRolePermissionsSettingPermission';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useRecoilState } from 'recoil';
import { Checkbox } from 'twenty-ui/input';
import { v4 } from 'uuid';
@@ -53,8 +54,13 @@ export const SettingsRolePermissionsSettingsTableRow = ({
isEditable,
}: SettingsRolePermissionsSettingsTableRowProps) => {
const theme = useTheme();
const [settingsDraftRole, setSettingsDraftRole] = useRecoilState(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const setSettingsDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
roleId,
);
const isPermissionEnabled =
@@ -3,9 +3,10 @@ import { SettingsRolePermissionsSettingsTableHeader } from '@/settings/roles/rol
import { SettingsRolePermissionsSettingsTableRow } from '@/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsTableRow';
import { useActionRolePermissionFlagConfig } from '@/settings/roles/role-permissions/permission-flags/hooks/useActionRolePermissionFlagConfig';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { useRecoilState } from 'recoil';
import { H2Title, IconTool } from 'twenty-ui/display';
import { AnimatedExpandableContainer, Card, Section } from 'twenty-ui/layout';
@@ -32,8 +33,13 @@ export const SettingsRolePermissionsToolSection = ({
roleId,
isEditable,
}: SettingsRolePermissionsToolSectionProps) => {
const [settingsDraftRole, setSettingsDraftRole] = useRecoilState(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const setSettingsDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
roleId,
);
const toolPermissionsConfig = useActionRolePermissionFlagConfig({
@@ -1,12 +1,13 @@
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { useRecoilState } from 'recoil';
import { SettingsRoleApplicability } from '@/settings/roles/role-settings/components/SettingsRoleApplicability';
import { SettingsRoleSettingsDeleteRoleConfirmationModal } from '@/settings/roles/role-settings/components/SettingsRoleSettingsDeleteRoleConfirmationModal';
import { ROLE_SETTINGS_DELETE_ROLE_CONFIRMATION_MODAL_ID } from '@/settings/roles/role-settings/components/constants/RoleSettingsDeleteRoleConfirmationModalId';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { IconPicker } from '@/ui/input/components/IconPicker';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
import { TextArea } from '@/ui/input/components/TextArea';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
@@ -37,8 +38,13 @@ export const SettingsRoleSettings = ({
isEditable,
isCreateMode,
}: SettingsRoleSettingsProps) => {
const [settingsDraftRole, setSettingsDraftRole] = useRecoilState(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const setSettingsDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
roleId,
);
const { openModal } = useModal();
@@ -1,6 +1,6 @@
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { t } from '@lingui/core/macro';
import { useRecoilValue } from 'recoil';
type SettingsRoleSettingsDeleteRoleConfirmationModalSubtitleProps = {
roleId: string;
@@ -9,8 +9,9 @@ type SettingsRoleSettingsDeleteRoleConfirmationModalSubtitleProps = {
export const SettingsRoleSettingsDeleteRoleConfirmationModalSubtitle = ({
roleId,
}: SettingsRoleSettingsDeleteRoleConfirmationModalSubtitleProps) => {
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const roleName = settingsDraftRole.label;
@@ -1,7 +1,7 @@
import { SettingsRoleSettings } from '@/settings/roles/role-settings/components/SettingsRoleSettings';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { type Meta, type StoryObj } from '@storybook/react-vite';
import { useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
import { getRolesMock } from '~/testing/mock-data/roles';
@@ -9,8 +9,9 @@ import { getRolesMock } from '~/testing/mock-data/roles';
const SettingsRoleSettingsWrapper = (
args: React.ComponentProps<typeof SettingsRoleSettings>,
) => {
const setDraftRole = useSetRecoilState(
settingsDraftRoleFamilyState(args.roleId),
const setDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
args.roleId,
);
const role = getRolesMock().find((role) => role.id === args.roleId);
@@ -16,10 +16,11 @@ import { TabList } from '@/ui/layout/tab-list/components/TabList';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useLoadCurrentUser } from '@/users/hooks/useLoadCurrentUser';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { t } from '@lingui/core/macro';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { useState } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath, isDefined } from 'twenty-shared/utils';
import { IconLockOpen, IconSettings, IconUserPlus } from 'twenty-ui/display';
@@ -48,12 +49,18 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
settingsRolesIsLoadingStateV2,
);
const [settingsDraftRole, setSettingsDraftRole] = useRecoilState(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const setSettingsDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
roleId,
);
const settingsPersistedRole = useRecoilValue(
settingsPersistedRoleFamilyState(roleId),
const settingsPersistedRole = useFamilyRecoilValueV2(
settingsPersistedRoleFamilyState,
roleId,
);
const { loadCurrentUser } = useLoadCurrentUser();
@@ -2,10 +2,10 @@ import { SETTINGS_ROLE_DETAIL_TABS } from '@/settings/roles/role/constants/Setti
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2';
import { t } from '@lingui/core/macro';
import { useEffect, useState } from 'react';
import { useSetRecoilState } from 'recoil';
type SettingsRoleCreateEffectProps = {
roleId: string;
@@ -14,12 +14,14 @@ type SettingsRoleCreateEffectProps = {
export const SettingsRoleCreateEffect = ({
roleId,
}: SettingsRoleCreateEffectProps) => {
const setSettingsDraftRole = useSetRecoilState(
settingsDraftRoleFamilyState(roleId),
const setSettingsDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
roleId,
);
const setSettingsPersistedRole = useSetRecoilState(
settingsPersistedRoleFamilyState(roleId),
const setSettingsPersistedRole = useSetFamilyRecoilStateV2(
settingsPersistedRoleFamilyState,
roleId,
);
const setActiveTabId = useSetRecoilComponentStateV2(
@@ -3,10 +3,10 @@ import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDr
import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState';
import { type RoleWithPartialMembers } from '@/settings/roles/types/RoleWithPartialMembers';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { useEffect, useState } from 'react';
import { useRecoilCallback, useRecoilValue } from 'recoil';
import { useStore } from 'jotai';
import { useCallback, useEffect, useState } from 'react';
import { isDefined } from 'twenty-shared/utils';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
@@ -19,25 +19,25 @@ export const SettingsRoleEditEffect = ({
}: SettingsRoleEditEffectProps) => {
const [isInitialized, setIsInitialized] = useState(false);
const role = useRecoilValue(settingsPersistedRoleFamilyState(roleId));
const role = useFamilyRecoilValueV2(settingsPersistedRoleFamilyState, roleId);
const setActiveTabId = useSetRecoilComponentStateV2(
activeTabIdComponentState,
SETTINGS_ROLE_DETAIL_TABS.COMPONENT_INSTANCE_ID + '-' + roleId,
);
const updateDraftRoleIfNeeded = useRecoilCallback(
({ set, snapshot }) =>
(newRole: RoleWithPartialMembers) => {
const currentPersistedRole = getSnapshotValue(
snapshot,
settingsPersistedRoleFamilyState(newRole.id),
);
const store = useStore();
if (!isDeeplyEqual(newRole, currentPersistedRole)) {
set(settingsDraftRoleFamilyState(newRole.id), newRole);
}
},
[],
const updateDraftRoleIfNeeded = useCallback(
(newRole: RoleWithPartialMembers) => {
const currentPersistedRole = store.get(
settingsPersistedRoleFamilyState.atomFamily(newRole.id),
);
if (!isDeeplyEqual(newRole, currentPersistedRole)) {
store.set(settingsDraftRoleFamilyState.atomFamily(newRole.id), newRole);
}
},
[store],
);
useEffect(() => {
@@ -1,6 +1,6 @@
import { useRecoilState } from 'recoil';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
import { TitleInput } from '@/ui/input/components/TitleInput';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
@@ -23,8 +23,13 @@ type SettingsRoleLabelContainerProps = {
export const SettingsRoleLabelContainer = ({
roleId,
}: SettingsRoleLabelContainerProps) => {
const [settingsDraftRole, setSettingsDraftRole] = useRecoilState(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const setSettingsDraftRole = useSetFamilyRecoilStateV2(
settingsDraftRoleFamilyState,
roleId,
);
const handleChange = (newValue: string) => {
@@ -7,8 +7,8 @@ import { useRemoveFieldPermissionInDraftRole } from '@/settings/roles/role-permi
import { newFieldPermissionsFilter } from '@/settings/roles/role/hooks/utils/newFieldPermissionsFilter.util';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState';
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
import { getOperationName } from '@apollo/client/utilities';
import { useRecoilValue } from 'recoil';
import { isDefined, isNonEmptyArray } from 'twenty-shared/utils';
import {
type RowLevelPermissionPredicateGroupLogicalOperator,
@@ -57,12 +57,14 @@ export const useSaveDraftRoleToDB = ({
const { addAgentsToRole } = useUpdateAgentRole(roleId);
const { addApiKeysToRole } = useUpdateApiKeyRole(roleId);
const settingsPersistedRole = useRecoilValue(
settingsPersistedRoleFamilyState(roleId),
const settingsPersistedRole = useFamilyRecoilValueV2(
settingsPersistedRoleFamilyState,
roleId,
);
const settingsDraftRole = useRecoilValue(
settingsDraftRoleFamilyState(roleId),
const settingsDraftRole = useFamilyRecoilValueV2(
settingsDraftRoleFamilyState,
roleId,
);
const dirtyFields = getDirtyFields(settingsDraftRole, settingsPersistedRole);
@@ -1,14 +0,0 @@
import { selector } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { settingsPersistedRoleFamilyState } from './settingsPersistedRoleFamilyState';
import { settingsRoleIdsState } from './settingsRoleIdsState';
export const settingsAllRolesSelector = selector({
key: 'settingsAllRolesSelector',
get: ({ get }) => {
const roleIds = get(settingsRoleIdsState);
return roleIds
.map((roleId) => get(settingsPersistedRoleFamilyState(roleId)))
.filter(isDefined);
},
});
@@ -1,7 +1,7 @@
import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState';
import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2';
import { type RoleWithPartialMembers } from '@/settings/roles/types/RoleWithPartialMembers';
export const settingsDraftRoleFamilyState = createFamilyState<
export const settingsDraftRoleFamilyState = createFamilyStateV2<
RoleWithPartialMembers,
string
>({
@@ -1,7 +1,7 @@
import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState';
import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2';
import { type RoleWithPartialMembers } from '@/settings/roles/types/RoleWithPartialMembers';
export const settingsPersistedRoleFamilyState = createFamilyState<
export const settingsPersistedRoleFamilyState = createFamilyStateV2<
RoleWithPartialMembers | undefined,
string
>({
@@ -1,6 +1,6 @@
import { atom } from 'recoil';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const settingsRoleIdsState = atom<string[]>({
export const settingsRoleIdsState = createStateV2<string[]>({
key: 'settingsRoleIdsState',
default: [],
defaultValue: [],
});
@@ -1,6 +0,0 @@
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const settingsRoleIdsStateV2 = createStateV2<string[]>({
key: 'settingsRoleIdsStateV2',
defaultValue: [],
});
@@ -1,7 +1,7 @@
import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState';
import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2';
import { type Role } from '~/generated-metadata/graphql';
export const settingsValidateRoleFamilyState = createFamilyState<
export const settingsValidateRoleFamilyState = createFamilyStateV2<
Record<keyof Pick<Role, 'label'>, boolean>,
string
>({
@@ -13,7 +13,7 @@ import { type ApolloError } from '@apollo/client';
import isPropValid from '@emotion/is-prop-valid';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { useRecoilState } from 'recoil';
import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { getSettingsPath } from 'twenty-shared/utils';
import { IconKey } from 'twenty-ui/display';
@@ -33,7 +33,7 @@ export const SettingsSSOIdentitiesProvidersListCard = () => {
const { t } = useLingui();
const [SSOIdentitiesProviders, setSSOIdentitiesProviders] = useRecoilState(
const [SSOIdentitiesProviders, setSSOIdentitiesProviders] = useRecoilStateV2(
SSOIdentitiesProvidersState,
);
@@ -5,14 +5,14 @@ import { SettingsListCard } from '@/settings/components/SettingsListCard';
import { SettingsSSOIdentityProviderRowRightContainer } from '@/settings/security/components/SSO/SettingsSSOIdentityProviderRowRightContainer';
import { SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProvidersState';
import { guessSSOIdentityProviderIconByUrl } from '@/settings/security/utils/guessSSOIdentityProviderIconByUrl';
import { useRecoilValue } from 'recoil';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { SettingsPath } from 'twenty-shared/types';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
export const SettingsSSOIdentitiesProvidersListCardWrapper = () => {
const navigate = useNavigateSettings();
const SSOIdentitiesProviders = useRecoilValue(SSOIdentitiesProvidersState);
const SSOIdentitiesProviders = useRecoilValueV2(SSOIdentitiesProvidersState);
return (
<SettingsListCard
@@ -1,10 +1,9 @@
/* @license Enterprise */
import { SettingsSecuritySSORowDropdownMenu } from '@/settings/security/components/SSO/SettingsSecuritySSORowDropdownMenu';
import { type SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProvidersState';
import { type SSOIdentityProvider } from '@/settings/security/types/SSOIdentityProvider';
import { getColorBySSOIdentityProviderStatus } from '@/settings/security/utils/getColorBySSOIdentityProviderStatus';
import styled from '@emotion/styled';
import { type UnwrapRecoilValue } from 'recoil';
import { Status } from 'twenty-ui/display';
const StyledRowRightContainer = styled.div`
@@ -16,7 +15,7 @@ const StyledRowRightContainer = styled.div`
export const SettingsSSOIdentityProviderRowRightContainer = ({
SSOIdp,
}: {
SSOIdp: UnwrapRecoilValue<typeof SSOIdentitiesProvidersState>[0];
SSOIdp: Omit<SSOIdentityProvider, '__typename'>;
}) => {
return (
<StyledRowRightContainer>
@@ -1,13 +1,12 @@
import { useDeleteSSOIdentityProvider } from '@/settings/security/hooks/useDeleteSSOIdentityProvider';
import { useUpdateSSOIdentityProvider } from '@/settings/security/hooks/useUpdateSSOIdentityProvider';
import { type SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProvidersState';
import { type SSOIdentityProvider } from '@/settings/security/types/SSOIdentityProvider';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { useLingui } from '@lingui/react/macro';
import { type UnwrapRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { IconArchive, IconDotsVertical, IconTrash } from 'twenty-ui/display';
import { LightIconButton } from 'twenty-ui/input';
@@ -15,7 +14,7 @@ import { MenuItem } from 'twenty-ui/navigation';
import { SsoIdentityProviderStatus } from '~/generated-metadata/graphql';
type SettingsSecuritySSORowDropdownMenuProps = {
SSOIdp: UnwrapRecoilValue<typeof SSOIdentitiesProvidersState>[0];
SSOIdp: Omit<SSOIdentityProvider, '__typename'>;
};
export const SettingsSecuritySSORowDropdownMenu = ({
@@ -6,7 +6,6 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { ApolloError } from '@apollo/client';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { useRecoilValue } from 'recoil';
import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
import { ConnectedAccountProvider } from 'twenty-shared/types';
import { capitalize } from 'twenty-shared/utils';
@@ -35,7 +34,7 @@ export const SettingsSecurityAuthProvidersOptionsList = () => {
const { t } = useLingui();
const { enqueueErrorSnackBar } = useSnackBar();
const SSOIdentitiesProviders = useRecoilValue(SSOIdentitiesProvidersState);
const SSOIdentitiesProviders = useRecoilValueV2(SSOIdentitiesProvidersState);
const authProviders = useRecoilValueV2(authProvidersState);
const [currentWorkspace, setCurrentWorkspace] = useRecoilStateV2(
@@ -11,11 +11,12 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { ApolloError } from '@apollo/client';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { useRecoilState, useRecoilValue } from 'recoil';
import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { getSettingsPath } from 'twenty-shared/utils';
import { IconAt, IconMailCog, Status } from 'twenty-ui/display';
import { useGetApprovedAccessDomainsQuery } from '~/generated-metadata/graphql';
import { dateLocaleState } from '~/localization/states/dateLocaleState';
import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2';
import { beautifyPastDateRelativeToNow } from '~/utils/date-utils';
const StyledLink = styled(Link)`
@@ -26,9 +27,9 @@ export const SettingsApprovedAccessDomainsListCard = () => {
const { enqueueErrorSnackBar } = useSnackBar();
const navigate = useNavigate();
const { t } = useLingui();
const { localeCatalog } = useRecoilValue(dateLocaleState);
const { localeCatalog } = useRecoilValueV2(dateLocaleStateV2);
const [approvedAccessDomains, setApprovedAccessDomains] = useRecoilState(
const [approvedAccessDomains, setApprovedAccessDomains] = useRecoilStateV2(
approvedAccessDomainsState,
);
@@ -4,16 +4,19 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import { t } from '@lingui/core/macro';
import { type UnwrapRecoilValue, useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { IconDotsVertical, IconTrash } from 'twenty-ui/display';
import { LightIconButton } from 'twenty-ui/input';
import { MenuItem } from 'twenty-ui/navigation';
import { useDeleteApprovedAccessDomainMutation } from '~/generated-metadata/graphql';
import {
type ApprovedAccessDomain,
useDeleteApprovedAccessDomainMutation,
} from '~/generated-metadata/graphql';
type SettingsSecurityApprovedAccessDomainRowDropdownMenuProps = {
approvedAccessDomain: UnwrapRecoilValue<typeof approvedAccessDomainsState>[0];
approvedAccessDomain: Omit<ApprovedAccessDomain, '__typename'>;
};
export const SettingsSecurityApprovedAccessDomainRowDropdownMenu = ({
@@ -21,7 +24,7 @@ export const SettingsSecurityApprovedAccessDomainRowDropdownMenu = ({
}: SettingsSecurityApprovedAccessDomainRowDropdownMenuProps) => {
const dropdownId = `settings-approved-access-domain-row-${approvedAccessDomain.id}`;
const setApprovedAccessDomains = useSetRecoilState(
const setApprovedAccessDomains = useSetRecoilStateV2(
approvedAccessDomainsState,
);
@@ -3,7 +3,7 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { t } from '@lingui/core/macro';
import { useEffect } from 'react';
import { useSearchParams } from 'react-router-dom';
import { useSetRecoilState } from 'recoil';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import { isDefined } from 'twenty-shared/utils';
import { useValidateApprovedAccessDomainMutation } from '~/generated-metadata/graphql';
@@ -14,7 +14,7 @@ export const SettingsSecurityApprovedAccessDomainValidationEffect = () => {
const [searchParams] = useSearchParams();
const approvedAccessDomainId = searchParams.get('wtdId');
const validationToken = searchParams.get('validationToken');
const setApprovedAccessDomains = useSetRecoilState(
const setApprovedAccessDomains = useSetRecoilStateV2(
approvedAccessDomainsState,
);
@@ -1,7 +1,7 @@
/* @license Enterprise */
import { SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProvidersState';
import { useSetRecoilState } from 'recoil';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import {
type CreateOidcIdentityProviderMutationVariables,
type CreateSamlIdentityProviderMutationVariables,
@@ -15,7 +15,7 @@ export const useCreateSSOIdentityProvider = () => {
const [createSamlIdentityProviderMutation] =
useCreateSamlIdentityProviderMutation();
const setSSOIdentitiesProviders = useSetRecoilState(
const setSSOIdentitiesProviders = useSetRecoilStateV2(
SSOIdentitiesProvidersState,
);
@@ -1,7 +1,7 @@
/* @license Enterprise */
import { SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProvidersState';
import { useSetRecoilState } from 'recoil';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import {
type DeleteSsoIdentityProviderMutationVariables,
useDeleteSsoIdentityProviderMutation,
@@ -11,7 +11,7 @@ export const useDeleteSSOIdentityProvider = () => {
const [deleteSsoIdentityProviderMutation] =
useDeleteSsoIdentityProviderMutation();
const setSSOIdentitiesProviders = useSetRecoilState(
const setSSOIdentitiesProviders = useSetRecoilStateV2(
SSOIdentitiesProvidersState,
);
@@ -1,7 +1,7 @@
/* @license Enterprise */
import { SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProvidersState';
import { useSetRecoilState } from 'recoil';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import {
type EditSsoIdentityProviderMutationVariables,
useEditSsoIdentityProviderMutation,
@@ -11,7 +11,7 @@ export const useUpdateSSOIdentityProvider = () => {
const [editSsoIdentityProviderMutation] =
useEditSsoIdentityProviderMutation();
const setSSOIdentitiesProviders = useSetRecoilState(
const setSSOIdentitiesProviders = useSetRecoilStateV2(
SSOIdentitiesProvidersState,
);
@@ -1,7 +1,7 @@
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
import { type ApprovedAccessDomain } from '~/generated-metadata/graphql';
import { createState } from '@/ui/utilities/state/utils/createState';
export const approvedAccessDomainsState = createState<
export const approvedAccessDomainsState = createStateV2<
Omit<ApprovedAccessDomain, '__typename'>[]
>({
key: 'ApprovedAccessDomainsState',
@@ -1,9 +1,9 @@
/* @license Enterprise */
import { type SSOIdentityProvider } from '@/settings/security/types/SSOIdentityProvider';
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const SSOIdentitiesProvidersState = createState<
export const SSOIdentitiesProvidersState = createStateV2<
Omit<SSOIdentityProvider, '__typename'>[]
>({
key: 'SSOIdentitiesProvidersState',