Files
twenty/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetActionFieldEdit.tsx
T
Etienne d0c1841f0f File - Migrate avatarUrl > avatarFile on person (data migration + logic) + Attachment data migration (#17752)
- Migration command
    - Check IS_FILES_FIELD_MIGRATED:false
    - Check or create avatarFile field
    - Fetch all people with avatarUrl
           - Move (Copy/move) file in storage
           - Create core.file record
           - Update person record
           
    - bonus : attachment migration  : fullPath > file (same logic)
   
- BE logic
    - Add avatarFile field on person

- FE logic 
   - Adapt logic to upload on/display avatarFile data

The whole imageIdentifier logic will be done later
2026-02-11 15:07:05 +00:00

137 lines
5.5 KiB
TypeScript

import { useFieldMetadataItemById } from '@/object-metadata/hooks/useFieldMetadataItemById';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { useIsRecordReadOnly } from '@/object-record/read-only/hooks/useIsRecordReadOnly';
import { isRecordFieldReadOnly } from '@/object-record/read-only/utils/isRecordFieldReadOnly';
import { RecordFieldsScopeContextProvider } from '@/object-record/record-field-list/contexts/RecordFieldsScopeContext';
import {
FieldContext,
type GenericFieldContextType,
} from '@/object-record/record-field/ui/contexts/FieldContext';
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext';
import { isFieldInputOnly } from '@/object-record/record-field/ui/types/guards/isFieldInputOnly';
import { isFieldMorphRelation } from '@/object-record/record-field/ui/types/guards/isFieldMorphRelation';
import { isFieldRelation } from '@/object-record/record-field/ui/types/guards/isFieldRelation';
import { useRecordShowContainerActions } from '@/object-record/record-show/hooks/useRecordShowContainerActions';
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
import { useResolveFieldMetadataIdFromNameOrId } from '@/page-layout/hooks/useResolveFieldMetadataIdFromNameOrId';
import { FieldWidgetEditAction } from '@/page-layout/widgets/field/components/FieldWidgetEditAction';
import { FieldWidgetRelationEditAction } from '@/page-layout/widgets/field/components/FieldWidgetRelationEditAction';
import { generateFieldWidgetInstanceId } from '@/page-layout/widgets/field/utils/generateFieldWidgetInstanceId';
import { isFieldWidget } from '@/page-layout/widgets/field/utils/isFieldWidget';
import { useCurrentWidget } from '@/page-layout/widgets/hooks/useCurrentWidget';
import { getObjectPermissionsFromMapByObjectMetadataId } from '@/settings/roles/role-permissions/objects-permissions/utils/getObjectPermissionsFromMapByObjectMetadataId';
import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord';
import { assertIsDefinedOrThrow } from 'twenty-shared/utils';
export const WidgetActionFieldEdit = () => {
const widget = useCurrentWidget();
const targetRecord = useTargetRecord();
const { isInRightDrawer } = useLayoutRenderingContext();
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular: targetRecord.targetObjectNameSingular,
});
const fieldMetadataId = isFieldWidget(widget)
? widget.configuration.fieldMetadataId
: undefined;
const resolvedFieldMetadataId = useResolveFieldMetadataIdFromNameOrId(
fieldMetadataId ?? '',
);
const { fieldMetadataItem } = useFieldMetadataItemById(
resolvedFieldMetadataId ?? '',
);
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
const { useUpdateOneObjectRecordMutation } = useRecordShowContainerActions({
objectNameSingular: objectMetadataItem.nameSingular,
});
const isRecordReadOnly = useIsRecordReadOnly({
recordId: targetRecord.id,
objectMetadataId: objectMetadataItem.id,
});
assertIsDefinedOrThrow(fieldMetadataItem);
const fieldDefinition = formatFieldMetadataItemAsColumnDefinition({
field: fieldMetadataItem,
position: 0,
objectMetadataItem,
showLabel: true,
labelWidth: 90,
});
const isRelationField =
isFieldRelation(fieldDefinition) || isFieldMorphRelation(fieldDefinition);
const instanceId = generateFieldWidgetInstanceId({
widgetId: widget.id,
recordId: targetRecord.id,
fieldName: fieldMetadataItem.name,
isInRightDrawer,
});
if (isRelationField) {
return (
<RecordFieldsScopeContextProvider value={{ scopeInstanceId: instanceId }}>
<FieldWidgetRelationEditAction
fieldDefinition={fieldDefinition}
recordId={targetRecord.id}
/>
</RecordFieldsScopeContextProvider>
);
}
if (isFieldInputOnly(fieldDefinition)) {
return null;
}
const recordFieldInputInstanceId = getRecordFieldInputInstanceId({
recordId: targetRecord.id,
fieldName: fieldMetadataItem.name,
prefix: instanceId,
});
const fieldContextValue = {
recordId: targetRecord.id,
maxWidth: 200,
isLabelIdentifier: false,
fieldDefinition,
useUpdateRecord: useUpdateOneObjectRecordMutation,
isDisplayModeFixHeight: false,
isRecordFieldReadOnly: isRecordFieldReadOnly({
isRecordReadOnly,
objectPermissions: getObjectPermissionsFromMapByObjectMetadataId({
objectPermissionsByObjectMetadataId,
objectMetadataId: objectMetadataItem.id,
}),
fieldMetadataItem: {
id: fieldMetadataItem.id,
isUIReadOnly: fieldMetadataItem.isUIReadOnly ?? false,
},
}),
anchorId: recordFieldInputInstanceId,
} satisfies GenericFieldContextType;
return (
<RecordFieldsScopeContextProvider value={{ scopeInstanceId: instanceId }}>
<RecordFieldComponentInstanceContext.Provider
value={{
instanceId: recordFieldInputInstanceId,
}}
>
<FieldContext.Provider value={fieldContextValue}>
<FieldWidgetEditAction />
</FieldContext.Provider>
</RecordFieldComponentInstanceContext.Provider>
</RecordFieldsScopeContextProvider>
);
};