fix: distinguish soft-deleted relations from RLS-restricted ones
When a relation FK exists but the target record is null, the frontend now checks whether row-level permission predicates are configured on the target object. If RLS is active, shows "Not shared" (record may be access-restricted). If no RLS exists, shows empty (record is soft-deleted). Fixes #20076 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+21
-1
@@ -3,9 +3,11 @@ import { useContext } from 'react';
|
||||
import { useActivityTargetObjectRecords } from '@/activities/hooks/useActivityTargetObjectRecords';
|
||||
import { type NoteTarget } from '@/activities/types/NoteTarget';
|
||||
import { type TaskTarget } from '@/activities/types/TaskTarget';
|
||||
import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObjectPermissionsForObject';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
import { RecordChip } from '@/object-record/components/RecordChip';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { isActivityTargetField } from '@/object-record/record-field-list/utils/categorizeRelationFields';
|
||||
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { useFieldFocus } from '@/object-record/record-field/ui/hooks/useFieldFocus';
|
||||
@@ -13,6 +15,7 @@ import { useRelationFromManyFieldDisplay } from '@/object-record/record-field/ui
|
||||
import { ForbiddenFieldDisplay } from '@/object-record/record-field/ui/meta-types/display/components/ForbiddenFieldDisplay';
|
||||
import { extractTargetRecordsFromJunction } from '@/object-record/record-field/ui/utils/junction/extractTargetRecordsFromJunction';
|
||||
import { getJunctionConfig } from '@/object-record/record-field/ui/utils/junction/getJunctionConfig';
|
||||
import { getTargetObjectMetadataIdsFromField } from '@/object-record/record-field/ui/utils/junction/getTargetObjectMetadataIdsFromField';
|
||||
import { hasJunctionConfig } from '@/object-record/record-field/ui/utils/junction/hasJunctionConfig';
|
||||
|
||||
import { ExpandableList } from '@/ui/layout/expandable-list/components/ExpandableList';
|
||||
@@ -37,6 +40,7 @@ export const RelationFromManyFieldDisplay = () => {
|
||||
const { isFocused } = useFieldFocus();
|
||||
const { disableChipClick, triggerEvent } = useContext(FieldContext);
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
|
||||
|
||||
const { fieldName, objectMetadataNameSingular } = fieldDefinition.metadata;
|
||||
|
||||
@@ -147,7 +151,23 @@ export const RelationFromManyFieldDisplay = () => {
|
||||
.filter(isDefined);
|
||||
|
||||
if (fieldValue.some(isDefined) && targetRecordsWithMetadata.length === 0) {
|
||||
return <ForbiddenFieldDisplay />;
|
||||
const targetObjectMetadataIds = junctionConfig.targetFields.flatMap(
|
||||
getTargetObjectMetadataIdsFromField,
|
||||
);
|
||||
|
||||
const hasRowLevelRestrictions = targetObjectMetadataIds.some(
|
||||
(targetId) =>
|
||||
getObjectPermissionsForObject(
|
||||
objectPermissionsByObjectMetadataId,
|
||||
targetId,
|
||||
).rowLevelPermissionPredicates.length > 0,
|
||||
);
|
||||
|
||||
if (hasRowLevelRestrictions) {
|
||||
return <ForbiddenFieldDisplay />;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
+13
-1
@@ -1,5 +1,6 @@
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
import { RecordChip } from '@/object-record/components/RecordChip';
|
||||
import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject';
|
||||
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { ForbiddenFieldDisplay } from '@/object-record/record-field/ui/meta-types/display/components/ForbiddenFieldDisplay';
|
||||
import { useRelationToOneFieldDisplay } from '@/object-record/record-field/ui/meta-types/hooks/useRelationToOneFieldDisplay';
|
||||
@@ -16,8 +17,19 @@ export const RelationToOneFieldDisplay = () => {
|
||||
|
||||
const { disableChipClick, triggerEvent } = useContext(FieldContext);
|
||||
|
||||
const targetObjectPermissions = useObjectPermissionsForObject(
|
||||
fieldDefinition.metadata.relationObjectMetadataId,
|
||||
);
|
||||
|
||||
if (!isDefined(fieldValue) && isDefined(foreignKeyFieldValue)) {
|
||||
return <ForbiddenFieldDisplay />;
|
||||
const hasRowLevelRestrictions =
|
||||
targetObjectPermissions.rowLevelPermissionPredicates.length > 0;
|
||||
|
||||
if (hasRowLevelRestrictions) {
|
||||
return <ForbiddenFieldDisplay />;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
|
||||
Reference in New Issue
Block a user