Files
twenty/packages/twenty-server/src/engine/twenty-orm/utils/validate-enum-value-compatibility.util.ts
T
c795b8c52a RLS FE implementation (#17062)
## Summary
This PR introduces row-level security (RLS) permissions for roles in the
frontend, allowing fine-grained access control at the record level.
Users can now define permission rules that determine which specific
records a role can access based on dynamic conditions and filters.
## What's Changed
Implemented UI for configuring record-level permissions on object
permissions screens
Added support for defining permission predicates using filter conditions
(similar to advanced filters)
Introduced variable picker for dynamic permission rules (e.g., "me"
context for user-specific access)
Built predicate conversion layer to sync UI state with backend
permission structure
Extended GraphQL schema with mutations for upserting row-level
permission predicates
Fixed handling of orphaned RLS groups to prevent data inconsistencies
Added enterprise key validation for RLS features
The implementation enables scenarios like "users can only see their own
records" or "users can access records associated with their team."

<img width="687" height="702" alt="Screenshot 2026-01-09 at 23 07 02"
src="https://github.com/user-attachments/assets/33fe736e-6cbf-40bd-b2eb-c8a90c8d21bc"
/>

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-12 17:39:17 +00:00

48 lines
1.4 KiB
TypeScript

import { FieldMetadataType } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
type ValidateEnumValueCompatibilityArgs = {
workspaceMemberFieldMetadata: FlatFieldMetadata;
targetFieldMetadata: FlatFieldMetadata;
predicateValue: unknown;
};
export const validateEnumValueCompatibility = ({
workspaceMemberFieldMetadata,
targetFieldMetadata,
predicateValue,
}: ValidateEnumValueCompatibilityArgs): boolean => {
const isWorkspaceMemberFieldEnum =
workspaceMemberFieldMetadata.type === FieldMetadataType.SELECT ||
workspaceMemberFieldMetadata.type === FieldMetadataType.MULTI_SELECT;
const isTargetFieldEnum =
targetFieldMetadata.type === FieldMetadataType.SELECT ||
targetFieldMetadata.type === FieldMetadataType.MULTI_SELECT;
if (!isWorkspaceMemberFieldEnum || !isTargetFieldEnum) {
return true;
}
const targetFieldOptions = targetFieldMetadata.options || [];
const validTargetValues = new Set(
targetFieldOptions.map((option) => option.value),
);
if (validTargetValues.size === 0) {
return true;
}
const valuesToCheck = Array.isArray(predicateValue)
? predicateValue
: [predicateValue];
const allValuesAreValid = valuesToCheck.every(
(value) => isDefined(value) && validTargetValues.has(String(value)),
);
return allValuesAreValid;
};