diff --git a/packages/twenty-front/src/modules/object-record/record-field/components/FieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/components/FieldDisplay.tsx
index fd24519a27fd..9096626cf3d6 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/components/FieldDisplay.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/components/FieldDisplay.tsx
@@ -1,5 +1,8 @@
import { useContext } from 'react';
+import { JsonFieldDisplay } from '@/object-record/record-field/meta-types/display/components/JsonFieldDisplay';
+import { isFieldRawJson } from '@/object-record/record-field/types/guards/isFieldRawJson';
+
import { FieldContext } from '../contexts/FieldContext';
import { AddressFieldDisplay } from '../meta-types/display/components/AddressFieldDisplay';
import { ChipFieldDisplay } from '../meta-types/display/components/ChipFieldDisplay';
@@ -59,5 +62,7 @@ export const FieldDisplay = () => {
) : isFieldAddress(fieldDefinition) ? (
+ ) : isFieldRawJson(fieldDefinition) ? (
+
) : null;
};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx
index 63ddafac26eb..ad2279e824d2 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx
@@ -2,9 +2,11 @@ import { useContext } from 'react';
import { AddressFieldInput } from '@/object-record/record-field/meta-types/input/components/AddressFieldInput';
import { FullNameFieldInput } from '@/object-record/record-field/meta-types/input/components/FullNameFieldInput';
+import { RawJsonFieldInput } from '@/object-record/record-field/meta-types/input/components/RawJsonFieldInput';
import { SelectFieldInput } from '@/object-record/record-field/meta-types/input/components/SelectFieldInput';
import { RecordFieldInputScope } from '@/object-record/record-field/scopes/RecordFieldInputScope';
import { isFieldFullName } from '@/object-record/record-field/types/guards/isFieldFullName';
+import { isFieldRawJson } from '@/object-record/record-field/types/guards/isFieldRawJson';
import { isFieldSelect } from '@/object-record/record-field/types/guards/isFieldSelect';
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
@@ -137,6 +139,14 @@ export const FieldInput = ({
onTab={onTab}
onShiftTab={onShiftTab}
/>
+ ) : isFieldRawJson(fieldDefinition) ? (
+
) : (
<>>
)}
diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/usePersistField.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/usePersistField.ts
index 6757c1bc047e..de825b7dfc3b 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/hooks/usePersistField.ts
+++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/usePersistField.ts
@@ -5,6 +5,8 @@ import { isFieldAddress } from '@/object-record/record-field/types/guards/isFiel
import { isFieldAddressValue } from '@/object-record/record-field/types/guards/isFieldAddressValue';
import { isFieldFullName } from '@/object-record/record-field/types/guards/isFieldFullName';
import { isFieldFullNameValue } from '@/object-record/record-field/types/guards/isFieldFullNameValue';
+import { isFieldRawJson } from '@/object-record/record-field/types/guards/isFieldRawJson';
+import { isFieldRawJsonValue } from '@/object-record/record-field/types/guards/isFieldRawJsonValue';
import { isFieldSelect } from '@/object-record/record-field/types/guards/isFieldSelect';
import { isFieldSelectValue } from '@/object-record/record-field/types/guards/isFieldSelectValue';
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
@@ -88,6 +90,10 @@ export const usePersistField = () => {
isFieldAddress(fieldDefinition) &&
isFieldAddressValue(valueToPersist);
+ const fieldIsRawJson =
+ isFieldRawJson(fieldDefinition) &&
+ isFieldRawJsonValue(valueToPersist);
+
if (
fieldIsRelation ||
fieldIsText ||
@@ -101,7 +107,8 @@ export const usePersistField = () => {
fieldIsCurrency ||
fieldIsFullName ||
fieldIsSelect ||
- fieldIsAddress
+ fieldIsAddress ||
+ fieldIsRawJson
) {
const fieldName = fieldDefinition.metadata.fieldName;
set(
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/JsonFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/JsonFieldDisplay.tsx
new file mode 100644
index 000000000000..5a0f553cde44
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/JsonFieldDisplay.tsx
@@ -0,0 +1,13 @@
+import { useJsonField } from '@/object-record/record-field/meta-types/hooks/useJsonField';
+import { JsonDisplay } from '@/ui/field/display/components/JsonDisplay';
+
+export const JsonFieldDisplay = () => {
+ const { fieldValue, maxWidth } = useJsonField();
+
+ return (
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useJsonField.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useJsonField.ts
new file mode 100644
index 000000000000..0219eb17398b
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useJsonField.ts
@@ -0,0 +1,48 @@
+import { useContext } from 'react';
+import { useRecoilState, useRecoilValue } from 'recoil';
+
+import { useRecordFieldInput } from '@/object-record/record-field/hooks/useRecordFieldInput';
+import { FieldJsonValue } from '@/object-record/record-field/types/FieldMetadata';
+import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
+import { FieldMetadataType } from '~/generated-metadata/graphql';
+
+import { FieldContext } from '../../contexts/FieldContext';
+import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata';
+import { isFieldRawJson } from '../../types/guards/isFieldRawJson';
+import { isFieldTextValue } from '../../types/guards/isFieldTextValue';
+
+export const useJsonField = () => {
+ const { entityId, fieldDefinition, hotkeyScope, maxWidth } =
+ useContext(FieldContext);
+
+ assertFieldMetadata(
+ FieldMetadataType.RawJson,
+ isFieldRawJson,
+ fieldDefinition,
+ );
+
+ const fieldName = fieldDefinition.metadata.fieldName;
+
+ const [fieldValue, setFieldValue] = useRecoilState(
+ recordStoreFamilySelector({
+ recordId: entityId,
+ fieldName: fieldName,
+ }),
+ );
+ const fieldTextValue = isFieldTextValue(fieldValue) ? fieldValue : '';
+
+ const { setDraftValue, getDraftValueSelector } =
+ useRecordFieldInput(`${entityId}-${fieldName}`);
+
+ const draftValue = useRecoilValue(getDraftValueSelector());
+
+ return {
+ draftValue,
+ setDraftValue,
+ maxWidth,
+ fieldDefinition,
+ fieldValue: fieldTextValue,
+ setFieldValue,
+ hotkeyScope,
+ };
+};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RawJsonFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RawJsonFieldInput.tsx
new file mode 100644
index 000000000000..34a06e814144
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RawJsonFieldInput.tsx
@@ -0,0 +1,83 @@
+import { isValidJSON } from '@/object-record/record-field/utils/isFieldValueJson';
+import { FieldTextAreaOverlay } from '@/ui/field/input/components/FieldTextAreaOverlay';
+import { TextAreaInput } from '@/ui/field/input/components/TextAreaInput';
+
+import { usePersistField } from '../../../hooks/usePersistField';
+import { useJsonField } from '../../hooks/useJsonField';
+
+import { FieldInputEvent } from './DateFieldInput';
+
+export type RawJsonFieldInputProps = {
+ onClickOutside?: FieldInputEvent;
+ onEnter?: FieldInputEvent;
+ onEscape?: FieldInputEvent;
+ onTab?: FieldInputEvent;
+ onShiftTab?: FieldInputEvent;
+};
+
+export const RawJsonFieldInput = ({
+ onEnter,
+ onEscape,
+ onClickOutside,
+ onTab,
+ onShiftTab,
+}: RawJsonFieldInputProps) => {
+ const { fieldDefinition, draftValue, hotkeyScope, setDraftValue } =
+ useJsonField();
+
+ const persistField = usePersistField();
+
+ const handlePersistField = (newText: string) => {
+ if (!newText || isValidJSON(newText)) persistField(newText || null);
+ };
+
+ const handleEnter = (newText: string) => {
+ onEnter?.(() => handlePersistField(newText));
+ };
+
+ const handleEscape = (newText: string) => {
+ onEscape?.(() => handlePersistField(newText));
+ };
+
+ const handleClickOutside = (
+ _event: MouseEvent | TouchEvent,
+ newText: string,
+ ) => {
+ onClickOutside?.(() => handlePersistField(newText));
+ };
+
+ const handleTab = (newText: string) => {
+ onTab?.(() => handlePersistField(newText));
+ };
+
+ const handleShiftTab = (newText: string) => {
+ onShiftTab?.(() => handlePersistField(newText));
+ };
+
+ const handleChange = (newText: string) => {
+ setDraftValue(newText);
+ };
+
+ const value =
+ draftValue && isValidJSON(draftValue)
+ ? JSON.stringify(JSON.parse(draftValue), null, 2)
+ : draftValue ?? '';
+
+ return (
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/FieldMetadata.ts b/packages/twenty-front/src/modules/object-record/record-field/types/FieldMetadata.ts
index f682bd422944..d65d17bf6c7f 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/types/FieldMetadata.ts
+++ b/packages/twenty-front/src/modules/object-record/record-field/types/FieldMetadata.ts
@@ -78,6 +78,7 @@ export type FieldAddressMetadata = {
export type FieldRawJsonMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
+ placeHolder: string;
};
export type FieldDefinitionRelationType =
@@ -146,3 +147,4 @@ export type FieldRatingValue = (typeof RATING_VALUES)[number];
export type FieldSelectValue = string | null;
export type FieldRelationValue = EntityForSelect | null;
+export type FieldJsonValue = string;
diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRawJsonValue.ts b/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRawJsonValue.ts
new file mode 100644
index 000000000000..8c7657d8dc4b
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRawJsonValue.ts
@@ -0,0 +1,8 @@
+import { isNull, isString } from '@sniptt/guards';
+
+import { FieldJsonValue } from '../FieldMetadata';
+
+// TODO: add zod
+export const isFieldRawJsonValue = (
+ fieldValue: unknown,
+): fieldValue is FieldJsonValue => isString(fieldValue) || isNull(fieldValue);
diff --git a/packages/twenty-front/src/modules/object-record/record-field/utils/isFieldValueEmpty.ts b/packages/twenty-front/src/modules/object-record/record-field/utils/isFieldValueEmpty.ts
index 62ee380f7939..c20b06742d04 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/utils/isFieldValueEmpty.ts
+++ b/packages/twenty-front/src/modules/object-record/record-field/utils/isFieldValueEmpty.ts
@@ -13,6 +13,7 @@ import { isFieldLink } from '@/object-record/record-field/types/guards/isFieldLi
import { isFieldLinkValue } from '@/object-record/record-field/types/guards/isFieldLinkValue';
import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber';
import { isFieldRating } from '@/object-record/record-field/types/guards/isFieldRating';
+import { isFieldRawJson } from '@/object-record/record-field/types/guards/isFieldRawJson';
import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation';
import { isFieldSelect } from '@/object-record/record-field/types/guards/isFieldSelect';
import { isFieldSelectValue } from '@/object-record/record-field/types/guards/isFieldSelectValue';
@@ -39,7 +40,8 @@ export const isFieldValueEmpty = ({
isFieldRating(fieldDefinition) ||
isFieldEmail(fieldDefinition) ||
isFieldBoolean(fieldDefinition) ||
- isFieldRelation(fieldDefinition)
+ isFieldRelation(fieldDefinition) ||
+ isFieldRawJson(fieldDefinition)
//|| isFieldPhone(fieldDefinition)
) {
return isValueEmpty(fieldValue);
diff --git a/packages/twenty-front/src/modules/object-record/record-field/utils/isFieldValueJson.ts b/packages/twenty-front/src/modules/object-record/record-field/utils/isFieldValueJson.ts
new file mode 100644
index 000000000000..6e577e7794d5
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-field/utils/isFieldValueJson.ts
@@ -0,0 +1,12 @@
+import { isString } from '@sniptt/guards';
+
+export const isValidJSON = (str: string) => {
+ try {
+ if (isString(JSON.parse(str))) {
+ throw new Error(`Strings are not supported as JSON: ${str}`);
+ }
+ return true;
+ } catch (error) {
+ return false;
+ }
+};
diff --git a/packages/twenty-front/src/modules/object-record/utils/generateEmptyFieldValue.ts b/packages/twenty-front/src/modules/object-record/utils/generateEmptyFieldValue.ts
index 2d8b314931f2..dd5d98f65255 100644
--- a/packages/twenty-front/src/modules/object-record/utils/generateEmptyFieldValue.ts
+++ b/packages/twenty-front/src/modules/object-record/utils/generateEmptyFieldValue.ts
@@ -75,6 +75,9 @@ export const generateEmptyFieldValue = (
case FieldMetadataType.MultiSelect: {
throw new Error('Not implemented yet');
}
+ case FieldMetadataType.RawJson: {
+ return null;
+ }
default: {
throw new Error('Unhandled FieldMetadataType');
}
diff --git a/packages/twenty-front/src/modules/settings/data-model/constants/SettingsFieldTypeConfigs.ts b/packages/twenty-front/src/modules/settings/data-model/constants/SettingsFieldTypeConfigs.ts
index d661a355c290..c4e2d798d418 100644
--- a/packages/twenty-front/src/modules/settings/data-model/constants/SettingsFieldTypeConfigs.ts
+++ b/packages/twenty-front/src/modules/settings/data-model/constants/SettingsFieldTypeConfigs.ts
@@ -2,6 +2,7 @@ import {
IconCalendarEvent,
IconCheck,
IconCoins,
+ IconJson,
IconKey,
IconLink,
IconMail,
@@ -117,4 +118,9 @@ export const SETTINGS_FIELD_TYPE_CONFIGS: Record<
addressLng: -118.2437,
},
},
+ [FieldMetadataType.RawJson]: {
+ label: 'JSON',
+ Icon: IconJson,
+ defaultValue: `{ "key": "value" }`,
+ },
};
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldSettingsFormCard.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldSettingsFormCard.tsx
index 0cf85a8157fc..8a344827f409 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldSettingsFormCard.tsx
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldSettingsFormCard.tsx
@@ -69,6 +69,7 @@ const previewableTypes = [
FieldMetadataType.Relation,
FieldMetadataType.Text,
FieldMetadataType.Address,
+ FieldMetadataType.RawJson,
];
export const SettingsDataModelFieldSettingsFormCard = ({
diff --git a/packages/twenty-front/src/modules/settings/data-model/types/SettingsSupportedFieldType.ts b/packages/twenty-front/src/modules/settings/data-model/types/SettingsSupportedFieldType.ts
index 5a337be84666..0149601685e3 100644
--- a/packages/twenty-front/src/modules/settings/data-model/types/SettingsSupportedFieldType.ts
+++ b/packages/twenty-front/src/modules/settings/data-model/types/SettingsSupportedFieldType.ts
@@ -2,5 +2,5 @@ import { FieldMetadataType } from '~/generated-metadata/graphql';
export type SettingsSupportedFieldType = Exclude<
FieldMetadataType,
- FieldMetadataType.Position | FieldMetadataType.RawJson
+ FieldMetadataType.Position
>;
diff --git a/packages/twenty-front/src/modules/ui/display/tooltip/AppTooltip.tsx b/packages/twenty-front/src/modules/ui/display/tooltip/AppTooltip.tsx
index 99fa35032fe4..ad8abe37afb8 100644
--- a/packages/twenty-front/src/modules/ui/display/tooltip/AppTooltip.tsx
+++ b/packages/twenty-front/src/modules/ui/display/tooltip/AppTooltip.tsx
@@ -35,6 +35,7 @@ export type AppTooltipProps = {
className?: string;
anchorSelect?: string;
content?: string;
+ children?: React.ReactNode;
delayHide?: number;
offset?: number;
noArrow?: boolean;
@@ -53,6 +54,7 @@ export const AppTooltip = ({
offset,
place,
positionStrategy,
+ children,
}: AppTooltipProps) => (
);
diff --git a/packages/twenty-front/src/modules/ui/display/tooltip/OverflowingTextWithTooltip.tsx b/packages/twenty-front/src/modules/ui/display/tooltip/OverflowingTextWithTooltip.tsx
index 41b266efaf04..f8ee4ebcd484 100644
--- a/packages/twenty-front/src/modules/ui/display/tooltip/OverflowingTextWithTooltip.tsx
+++ b/packages/twenty-front/src/modules/ui/display/tooltip/OverflowingTextWithTooltip.tsx
@@ -22,9 +22,11 @@ const StyledOverflowingText = styled.div<{ cursorPointer: boolean }>`
export const OverflowingTextWithTooltip = ({
text,
className,
+ mutliline,
}: {
text: string | null | undefined;
className?: string;
+ mutliline?: boolean;
}) => {
const textElementId = `title-id-${uuidV4()}`;
@@ -65,13 +67,15 @@ export const OverflowingTextWithTooltip = ({
+ >
+ {mutliline ?
{text}
: ''}
+
,
document.body,
)}
diff --git a/packages/twenty-front/src/modules/ui/field/display/components/JsonDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/JsonDisplay.tsx
new file mode 100644
index 000000000000..63614d358c04
--- /dev/null
+++ b/packages/twenty-front/src/modules/ui/field/display/components/JsonDisplay.tsx
@@ -0,0 +1,10 @@
+import { EllipsisDisplay } from './EllipsisDisplay';
+
+type JsonDisplayProps = {
+ text: string;
+ maxWidth?: number;
+};
+
+export const JsonDisplay = ({ text, maxWidth }: JsonDisplayProps) => (
+ {text}
+);
diff --git a/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx
index 43f9254bb6ef..29b754391362 100644
--- a/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx
+++ b/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx
@@ -19,6 +19,7 @@ export type TextAreaInputProps = {
onClickOutside: (event: MouseEvent | TouchEvent, inputValue: string) => void;
hotkeyScope: string;
onChange?: (newText: string) => void;
+ maxRows?: number;
};
const StyledTextArea = styled(TextareaAutosize)`
@@ -45,6 +46,7 @@ export const TextAreaInput = ({
onShiftTab,
onClickOutside,
onChange,
+ maxRows,
}: TextAreaInputProps) => {
const [internalText, setInternalText] = useState(value);
@@ -84,6 +86,7 @@ export const TextAreaInput = ({
onChange={handleChange}
autoFocus={autoFocus}
value={internalText}
+ maxRows={maxRows}
/>
);
};
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars/index.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars/index.ts
index 32b0466f2060..b6c4f05a8474 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars/index.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars/index.ts
@@ -1,3 +1,4 @@
+import { JsonScalarType } from './json.scalar';
import { PositionScalarType } from './position.scalar';
import { CursorScalarType } from './cursor.scalar';
import { BigFloatScalarType } from './big-float.scalar';
@@ -24,4 +25,5 @@ export const scalars = [
UUIDScalarType,
CursorScalarType,
PositionScalarType,
+ JsonScalarType,
];
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars/json.scalar.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars/json.scalar.ts
new file mode 100644
index 000000000000..1f03304e715c
--- /dev/null
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars/json.scalar.ts
@@ -0,0 +1,14 @@
+import { isString } from 'class-validator';
+import { GraphQLScalarType } from 'graphql';
+import GraphQLJSON from 'graphql-type-json';
+
+export const JsonScalarType = new GraphQLScalarType({
+ ...GraphQLJSON,
+ parseValue: (value) => {
+ if (isString(value) && isString(JSON.parse(value))) {
+ throw new Error(`Strings are not supported as JSON: ${value}`);
+ }
+
+ return GraphQLJSON.parseValue(value);
+ },
+});
diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/services/type-mapper.service.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/services/type-mapper.service.ts
index 2739f25949cf..3d5ca2f1b0d4 100644
--- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/services/type-mapper.service.ts
+++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/services/type-mapper.service.ts
@@ -14,7 +14,6 @@ import {
GraphQLString,
GraphQLType,
} from 'graphql';
-import GraphQLJSON from 'graphql-type-json';
import {
DateScalarMode,
@@ -39,6 +38,7 @@ import {
UUIDScalarType,
} from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { PositionScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars/position.scalar';
+import { JsonScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars/json.scalar';
export interface TypeOptions {
nullable?: boolean;
@@ -71,7 +71,7 @@ export class TypeMapperService {
[FieldMetadataType.PROBABILITY, GraphQLFloat],
[FieldMetadataType.RELATION, UUIDScalarType],
[FieldMetadataType.POSITION, PositionScalarType],
- [FieldMetadataType.RAW_JSON, GraphQLJSON],
+ [FieldMetadataType.RAW_JSON, JsonScalarType],
]);
return typeScalarMapping.get(fieldMetadataType);
diff --git a/packages/twenty-server/src/engine/core-modules/open-api/utils/components.utils.ts b/packages/twenty-server/src/engine/core-modules/open-api/utils/components.utils.ts
index 75307797a23c..07401cb78491 100644
--- a/packages/twenty-server/src/engine/core-modules/open-api/utils/components.utils.ts
+++ b/packages/twenty-server/src/engine/core-modules/open-api/utils/components.utils.ts
@@ -72,7 +72,7 @@ const getSchemaComponentsProperties = (
};
break;
case FieldMetadataType.RAW_JSON:
- type: 'object';
+ itemProperty.type = 'object';
break;
default:
itemProperty.type = 'string';
diff --git a/packages/twenty-ui/src/display/icon/components/TablerIcons.ts b/packages/twenty-ui/src/display/icon/components/TablerIcons.ts
index 25ec8383fa5d..f16f99dd205c 100644
--- a/packages/twenty-ui/src/display/icon/components/TablerIcons.ts
+++ b/packages/twenty-ui/src/display/icon/components/TablerIcons.ts
@@ -82,6 +82,7 @@ export {
IconHierarchy2,
IconInbox,
IconInfoCircle,
+ IconJson,
IconKey,
IconLanguage,
IconLayersLinked,