fix(page-layout): render relation field widgets in table display mode (#22220)

Adding a to-many relation field as a **Table** on a record page rendered
an empty widget (header only) in several cases. This fixes three
independent defects behind that.

- **Morph inverse relations crashed the table.** The host-scoping view
filter (`IS current record`) is built on the relation's inverse field.
When that inverse is a `MORPH_RELATION` (attachments, notes, tasks…),
`getFilterTypeFromFieldType` fell through to `TEXT` and the GraphQL
builder threw `Unknown operand IS for TEXT filter`, unmounting the table
via the ErrorBoundary. `MORPH_RELATION` now classifies as `RELATION`,
and the relation filter resolves the correct morph join column (e.g.
`targetPersonId`) from the current record's object type.
- **Stale `viewId` on field change.** Changing the bound field on a
Table widget kept the previous relation's draft view (wrong
object/fields/filter). Field selection now regenerates the draft view
for the new relation, or clears the stale `viewId` when the new field
can't back a table.
- **Label identifier could be hidden or reordered.** Relation-table
widget views now pin the label-identifier field first and visible on
view creation and save.

Deferred: morph relation filters with arbitrary selected record ids (not
just "current record") — needs target-object identity in the filter
value schema.

**Test:** open a Person → edit layout → add a Field widget → bind a
to-many relation → switch Layout to Table. Previously empty for
`attachments` (morph) and for any field changed on an existing Table
widget; now scoped to the host record.


<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22220?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
This commit is contained in:
nitin
2026-06-30 19:03:04 +05:30
committed by GitHub
parent 46ef8a8813
commit 5a5c829129
15 changed files with 459 additions and 27 deletions
@@ -1,8 +1,10 @@
import { createContext } from 'react';
import { type RecordFilterValueDependencies } from 'twenty-shared/types';
export type RecordFilterValueDependenciesContextValue = {
currentRecordId?: string;
};
export type RecordFilterValueDependenciesContextValue = Pick<
RecordFilterValueDependencies,
'currentRecord'
>;
export const RecordFilterValueDependenciesContext =
createContext<RecordFilterValueDependenciesContextValue>({});
@@ -14,15 +14,15 @@ export const useFilterValueDependencies = (): {
const { userTimezone } = useUserTimezone();
const { currentRecordId } = useContext(RecordFilterValueDependenciesContext);
const { currentRecord } = useContext(RecordFilterValueDependenciesContext);
const filterValueDependencies = useMemo(
() => ({
currentWorkspaceMemberId,
currentRecordId,
currentRecord,
timeZone: userTimezone,
}),
[currentWorkspaceMemberId, currentRecordId, userTimezone],
[currentWorkspaceMemberId, currentRecord, userTimezone],
);
return { filterValueDependencies };
@@ -24,7 +24,7 @@ export const useBuildRecordInputFromFilters = ({
const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState);
const { currentRecordId } = useContext(RecordFilterValueDependenciesContext);
const { currentRecord } = useContext(RecordFilterValueDependenciesContext);
const { userTimezone } = useUserTimezone();
@@ -33,7 +33,7 @@ export const useBuildRecordInputFromFilters = ({
currentRecordFilters,
objectMetadataItem,
currentWorkspaceMember: currentWorkspaceMember ?? undefined,
currentRecordId,
currentRecordId: currentRecord?.id,
timeZone: userTimezone,
});
};