diff --git a/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx b/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx
index 09fdaf62b..2b0f2d052 100644
--- a/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx
+++ b/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx
@@ -13,6 +13,7 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
import { useFieldContext } from '@/object-record/hooks/useFieldContext';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { FieldFocusContextProvider } from '@/object-record/record-field/contexts/FieldFocusContextProvider';
+import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useIsFieldValueReadOnly';
import { RecordFieldInputScope } from '@/object-record/record-field/scopes/RecordFieldInputScope';
import { RecordInlineCellContainer } from '@/object-record/record-inline-cell/components/RecordInlineCellContainer';
import { RecordInlineCellContext } from '@/object-record/record-inline-cell/components/RecordInlineCellContext';
@@ -23,7 +24,6 @@ type ActivityTargetsInlineCellProps = {
activity: Task | Note;
showLabel?: boolean;
maxWidth?: number;
- readonly?: boolean;
activityObjectNameSingular:
| CoreObjectNameSingular.Note
| CoreObjectNameSingular.Task;
@@ -33,7 +33,6 @@ export const ActivityTargetsInlineCell = ({
activity,
showLabel = true,
maxWidth,
- readonly,
activityObjectNameSingular,
}: ActivityTargetsInlineCellProps) => {
const { activityTargetObjectRecords } =
@@ -43,6 +42,8 @@ export const ActivityTargetsInlineCell = ({
const { fieldDefinition } = useContext(FieldContext);
+ const isFieldReadOnly = useIsFieldValueReadOnly();
+
useScopedHotkeys(
Key.Escape,
() => {
@@ -76,7 +77,7 @@ export const ActivityTargetsInlineCell = ({
},
IconLabel: showLabel ? IconArrowUpRight : undefined,
showLabel: showLabel,
- readonly: readonly,
+ readonly: isFieldReadOnly,
labelWidth: fieldDefinition?.labelWidth,
editModeContent: (
)}
diff --git a/packages/twenty-front/src/modules/activities/tasks/components/TaskRow.tsx b/packages/twenty-front/src/modules/activities/tasks/components/TaskRow.tsx
index ee4822006..588af20d9 100644
--- a/packages/twenty-front/src/modules/activities/tasks/components/TaskRow.tsx
+++ b/packages/twenty-front/src/modules/activities/tasks/components/TaskRow.tsx
@@ -134,7 +134,6 @@ export const TaskRow = ({ task }: { task: Task }) => {
activity={task}
showLabel={false}
maxWidth={200}
- readonly
/>
)}
diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/__tests__/useIsFieldValueReadOnly.test.tsx b/packages/twenty-front/src/modules/object-record/record-field/hooks/__tests__/useIsFieldValueReadOnly.test.tsx
index a436b9753..274a251a0 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/hooks/__tests__/useIsFieldValueReadOnly.test.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/__tests__/useIsFieldValueReadOnly.test.tsx
@@ -2,6 +2,7 @@ import { renderHook } from '@testing-library/react';
import { ReactNode } from 'react';
import { RecoilRoot } from 'recoil';
+import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
import {
actorFieldDefinition,
phonesFieldDefinition,
@@ -17,34 +18,39 @@ import { JestRecordStoreSetter } from '~/testing/jest/JestRecordStoreSetter';
import { useIsFieldValueReadOnly } from '../useIsFieldValueReadOnly';
const recordId = 'recordId';
+const mockInstanceId = 'mock-instance-id';
const getWrapper =
(fieldDefinition: FieldDefinition, isRecordDeleted: boolean) =>
({ children }: { children: ReactNode }) => {
return (
-
-
-
+
+
- {children}
-
-
-
+
+ {children}
+
+
+
+
);
};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/useIsFieldValueReadOnly.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/useIsFieldValueReadOnly.ts
index c6e6c2bae..d6146718c 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/hooks/useIsFieldValueReadOnly.ts
+++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/useIsFieldValueReadOnly.ts
@@ -1,9 +1,11 @@
import { useContext } from 'react';
+import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useRecoilValue } from 'recoil';
import { FieldContext } from '../contexts/FieldContext';
import { isFieldValueReadOnly } from '../utils/isFieldValueReadOnly';
@@ -17,6 +19,10 @@ export const useIsFieldValueReadOnly = () => {
recordStoreFamilyState(recordId),
);
+ const contextStoreCurrentViewType = useRecoilComponentValueV2(
+ contextStoreCurrentViewTypeComponentState,
+ );
+
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular: metadata.objectMetadataNameSingular ?? '',
});
@@ -30,5 +36,6 @@ export const useIsFieldValueReadOnly = () => {
isObjectRemote: objectMetadataItem.isRemote,
isRecordDeleted: recordFromStore?.deletedAt,
hasObjectReadOnlyPermission,
+ contextStoreCurrentViewType,
});
};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/utils/__tests__/isFieldValueReadOnly.test.ts b/packages/twenty-front/src/modules/object-record/record-field/utils/__tests__/isFieldValueReadOnly.test.ts
index 9744b3b8f..db435778f 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/utils/__tests__/isFieldValueReadOnly.test.ts
+++ b/packages/twenty-front/src/modules/object-record/record-field/utils/__tests__/isFieldValueReadOnly.test.ts
@@ -1,3 +1,4 @@
+import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
import { isFieldValueReadOnly } from '@/object-record/record-field/utils/isFieldValueReadOnly';
import { FieldMetadataType } from '~/generated/graphql';
@@ -5,19 +6,37 @@ describe('isFieldValueReadOnly', () => {
it('should return true if fieldName is noteTargets or taskTargets', () => {
const result = isFieldValueReadOnly({
fieldName: 'noteTargets',
+ contextStoreCurrentViewType: ContextStoreViewType.Table,
});
expect(result).toBe(true);
const result2 = isFieldValueReadOnly({
fieldName: 'taskTargets',
+ contextStoreCurrentViewType: ContextStoreViewType.Table,
});
expect(result2).toBe(true);
});
+ it('should return true if fieldName is noteTargets or taskTargets but is not in table or kanban view', () => {
+ const result = isFieldValueReadOnly({
+ fieldName: 'noteTargets',
+ contextStoreCurrentViewType: ContextStoreViewType.ShowPage,
+ });
+ expect(result).toBe(false);
+
+ const result2 = isFieldValueReadOnly({
+ fieldName: 'taskTargets',
+ contextStoreCurrentViewType: ContextStoreViewType.ShowPage,
+ });
+
+ expect(result2).toBe(false);
+ });
+
it('should return false if fieldName is not noteTargets or taskTargets', () => {
const result = isFieldValueReadOnly({
fieldName: 'test',
+ contextStoreCurrentViewType: ContextStoreViewType.Table,
});
expect(result).toBe(false);
@@ -26,6 +45,7 @@ describe('isFieldValueReadOnly', () => {
it('should return true if isObjectRemote is true', () => {
const result = isFieldValueReadOnly({
isObjectRemote: true,
+ contextStoreCurrentViewType: ContextStoreViewType.Table,
});
expect(result).toBe(true);
@@ -34,6 +54,7 @@ describe('isFieldValueReadOnly', () => {
it('should return false if isObjectRemote is false', () => {
const result = isFieldValueReadOnly({
isObjectRemote: false,
+ contextStoreCurrentViewType: ContextStoreViewType.Table,
});
expect(result).toBe(false);
@@ -42,6 +63,7 @@ describe('isFieldValueReadOnly', () => {
it('should return true if isRecordDeleted is true', () => {
const result = isFieldValueReadOnly({
isRecordDeleted: true,
+ contextStoreCurrentViewType: ContextStoreViewType.Table,
});
expect(result).toBe(true);
@@ -50,6 +72,7 @@ describe('isFieldValueReadOnly', () => {
it('should return false if isRecordDeleted is false', () => {
const result = isFieldValueReadOnly({
isRecordDeleted: false,
+ contextStoreCurrentViewType: ContextStoreViewType.Table,
});
expect(result).toBe(false);
@@ -59,6 +82,7 @@ describe('isFieldValueReadOnly', () => {
const result = isFieldValueReadOnly({
objectNameSingular: 'workflow',
fieldName: 'test',
+ contextStoreCurrentViewType: ContextStoreViewType.Table,
});
expect(result).toBe(true);
@@ -68,6 +92,7 @@ describe('isFieldValueReadOnly', () => {
const result = isFieldValueReadOnly({
objectNameSingular: 'Workflow',
fieldName: 'name',
+ contextStoreCurrentViewType: ContextStoreViewType.Table,
});
expect(result).toBe(false);
@@ -76,6 +101,7 @@ describe('isFieldValueReadOnly', () => {
it('should return true if isWorkflowSubObjectMetadata is true', () => {
const result = isFieldValueReadOnly({
objectNameSingular: 'workflowVersion',
+ contextStoreCurrentViewType: ContextStoreViewType.Table,
});
expect(result).toBe(true);
@@ -84,6 +110,7 @@ describe('isFieldValueReadOnly', () => {
it('should return true if fieldType is FieldMetadataType.ACTOR', () => {
const result = isFieldValueReadOnly({
fieldType: FieldMetadataType.ACTOR,
+ contextStoreCurrentViewType: ContextStoreViewType.Table,
});
expect(result).toBe(true);
@@ -92,6 +119,7 @@ describe('isFieldValueReadOnly', () => {
it('should return true if fieldType is FieldMetadataType.RICH_TEXT', () => {
const result = isFieldValueReadOnly({
fieldType: FieldMetadataType.RICH_TEXT,
+ contextStoreCurrentViewType: ContextStoreViewType.Table,
});
expect(result).toBe(true);
@@ -100,13 +128,16 @@ describe('isFieldValueReadOnly', () => {
it('should return false if fieldType is not FieldMetadataType.ACTOR or FieldMetadataType.RICH_TEXT', () => {
const result = isFieldValueReadOnly({
fieldType: FieldMetadataType.TEXT,
+ contextStoreCurrentViewType: ContextStoreViewType.Table,
});
expect(result).toBe(false);
});
it('should return false if none of the conditions are met', () => {
- const result = isFieldValueReadOnly({});
+ const result = isFieldValueReadOnly({
+ contextStoreCurrentViewType: ContextStoreViewType.Table,
+ });
expect(result).toBe(false);
});
diff --git a/packages/twenty-front/src/modules/object-record/record-field/utils/isFieldValueReadOnly.ts b/packages/twenty-front/src/modules/object-record/record-field/utils/isFieldValueReadOnly.ts
index 41ce33a7f..acaa33b72 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/utils/isFieldValueReadOnly.ts
+++ b/packages/twenty-front/src/modules/object-record/record-field/utils/isFieldValueReadOnly.ts
@@ -1,3 +1,4 @@
+import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata';
import { isFieldActor } from '@/object-record/record-field/types/guards/isFieldActor';
@@ -13,6 +14,7 @@ type isFieldValueReadOnlyParams = {
isObjectRemote?: boolean;
isRecordDeleted?: boolean;
hasObjectReadOnlyPermission?: boolean;
+ contextStoreCurrentViewType: ContextStoreViewType | null;
};
export const isFieldValueReadOnly = ({
@@ -22,8 +24,16 @@ export const isFieldValueReadOnly = ({
isObjectRemote = false,
isRecordDeleted = false,
hasObjectReadOnlyPermission = false,
+ contextStoreCurrentViewType,
}: isFieldValueReadOnlyParams) => {
- if (fieldName === 'noteTargets' || fieldName === 'taskTargets') {
+ const isTableViewOrKanbanView =
+ contextStoreCurrentViewType === ContextStoreViewType.Table ||
+ contextStoreCurrentViewType === ContextStoreViewType.Kanban;
+
+ const isTargetField =
+ fieldName === 'noteTargets' || fieldName === 'taskTargets';
+
+ if (isTableViewOrKanbanView && isTargetField) {
return true;
}
diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/SummaryCard.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/SummaryCard.tsx
index ffbcd364d..bf580fc61 100644
--- a/packages/twenty-front/src/modules/object-record/record-show/components/SummaryCard.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-show/components/SummaryCard.tsx
@@ -1,3 +1,4 @@
+import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
import { useGetStandardObjectIcon } from '@/object-metadata/hooks/useGetStandardObjectIcon';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
@@ -53,6 +54,7 @@ export const SummaryCard = ({
const isReadOnly = isFieldValueReadOnly({
objectNameSingular,
isRecordDeleted: recordFromStore?.isDeleted,
+ contextStoreCurrentViewType: ContextStoreViewType.ShowPage,
});
const isCommandMenuV2Enabled = useIsFeatureEnabled(
diff --git a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/__stories__/RecordDetailRelationSection.stories.tsx b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/__stories__/RecordDetailRelationSection.stories.tsx
index 7d212b39c..dc788344b 100644
--- a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/__stories__/RecordDetailRelationSection.stories.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/__stories__/RecordDetailRelationSection.stories.tsx
@@ -10,6 +10,7 @@ import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { getCompaniesMock } from '~/testing/mock-data/companies';
+import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { allMockPersonRecords } from '~/testing/mock-data/people';
@@ -31,21 +32,25 @@ const meta: Meta = {
component: RecordDetailRelationSection,
decorators: [
(Story) => (
- name === 'people',
- )!,
- objectMetadataItem: mockedCompanyObjectMetadataItem,
- }),
- hotkeyScope: 'hotkey-scope',
- }}
+
-
-
+ name === 'people',
+ )!,
+ objectMetadataItem: mockedCompanyObjectMetadataItem,
+ }),
+ hotkeyScope: 'hotkey-scope',
+ }}
+ >
+
+
+
),
ComponentDecorator,
ObjectMetadataItemsDecorator,