Repository: twentyhq/twenty
File: packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutWithRelationWidgets.ts (TypeScript)

Code before:
            ...tab,
            widgets: [...tab.widgets, ...relationWidgets],
          };
        }

        const noteWidgetIndex = tab.widgets.findIndex(
          (widget) => widget.type === WidgetType.NOTES,
        );

        const widgetsBeforeRelation = tab.widgets.slice(
          0,
          firstFieldsWidgetIndex + 1,
        );
        const widgetsAfterRelation =
          noteWidgetIndex === -1
            ? tab.widgets.slice(firstFieldsWidgetIndex + 1)
            : [
                ...tab.widgets.slice(
                  firstFieldsWidgetIndex + 1,
                  noteWidgetIndex,
                ),
                ...tab.widgets.slice(noteWidgetIndex + 1),
              ];

        const noteWidget =
          noteWidgetIndex !== -1 ? [tab.widgets[noteWidgetIndex]] : [];

        return {
          ...tab,
          widgets: [
            ...widgetsBeforeRelation,
            ...relationWidgets,
            ...noteWidget,
            ...widgetsAfterRelation,
          ],
        };
      }
      return tab;
    }),
  };
};

export const usePageLayoutWithRelationWidgets = (
  basePageLayout: PageLayout | undefined,
): PageLayout | undefined => {
  const { targetRecordIdentifier, layoutType } = useLayoutRenderingContext();

  const { boxedRelationFieldMetadataItems } = useFieldListFieldMetadataItems({
    objectNameSingular: targetRecordIdentifier?.targetObjectNameSingular ?? '',
  });


Review comment (bug):
The logic for extracting widgets after the FIELDS widget has an issue when a NOTES widget exists between FIELDS and the end of the list. When `noteWidgetIndex !== -1`, the code extracts widgets between FIELDS and NOTES (lines 93-96), then widgets after NOTES (line 97). However, if the NOTES widget is immediately after the FIELDS widget (e.g., at index `firstFieldsWidgetIndex + 1`), the slice on lines 93-96 will have `firstFieldsWidgetIndex + 1` as start and `noteWidgetIndex` as end with the same value, resulting in an empty array. This is actually correct behavior, but the logic could be clearer.

More critically, the current implementation doesn't handle the case where NOTES appears BEFORE the FIELDS widget. In that scenario, `noteWidgetIndex` could be less than `firstFieldsWidgetIndex`, which would cause the slicing logic to behave incorrectly. The slice from `firstFieldsWidgetIndex + 1` to `noteWidgetIndex` would produce an empty array (which is fine), but then the NOTES widget would still be repositioned after relations even though it was originally before FIELDS, changing the intended layout unexpectedly.

Code after:
            ...tab,
            widgets: [...tab.widgets, ...relationWidgets],
          };
        }

        // TODO: This note widget repositioning logic is temporary and will be deleted soon.
        // We need this to ensure the note editor is displayed before record relations,
        // matching the behavior of the old show page.
        const noteWidgetIndex = tab.widgets.findIndex(
          (widget) => widget.type === WidgetType.NOTES,
        );

        const widgetsBeforeRelation = tab.widgets.slice(
          0,
          firstFieldsWidgetIndex + 1,
        );
        const widgetsAfterRelation =
          noteWidgetIndex === -1
            ? tab.widgets.slice(firstFieldsWidgetIndex + 1)
            : [
                ...tab.widgets.slice(
                  firstFieldsWidgetIndex + 1,
                  noteWidgetIndex,
                ),
                ...tab.widgets.slice(noteWidgetIndex + 1),
              ];

        const noteWidget =
          noteWidgetIndex !== -1 ? [tab.widgets[noteWidgetIndex]] : [];

        return {
          ...tab,
          widgets: [
            ...widgetsBeforeRelation,
            ...relationWidgets,
            ...noteWidget,
            ...widgetsAfterRelation,
          ],
        };
      }
      return tab;
    }),
  };
};

export const usePageLayoutWithRelationWidgets = (
  basePageLayout: PageLayout | undefined,
): PageLayout | undefined => {
  const { targetRecordIdentifier, layoutType } = useLayoutRenderingContext();

  const { boxedRelationFieldMetadataItems } = useFieldListFieldMetadataItems({