From c36d112ab4ae3aa9bbf9563600fc10b7198db146 Mon Sep 17 00:00:00 2001 From: Weiko Date: Tue, 27 Jan 2026 12:51:08 +0100 Subject: [PATCH] Add upgrade to org plan card to RLS (#17455) ## Context Screenshot 2026-01-26 at 18 19 39 --- .../SettingsOptionCardContentButton.tsx | 46 ++++++++++++++ ...gsRolePermissionsObjectLevelObjectForm.tsx | 5 +- ...rmissionsObjectLevelRecordLevelSection.tsx | 62 ++++++++++++++++++- .../twenty-ui/src/components/Pill/Pill.tsx | 16 +++-- 4 files changed, 119 insertions(+), 10 deletions(-) create mode 100644 packages/twenty-front/src/modules/settings/components/SettingsOptions/SettingsOptionCardContentButton.tsx diff --git a/packages/twenty-front/src/modules/settings/components/SettingsOptions/SettingsOptionCardContentButton.tsx b/packages/twenty-front/src/modules/settings/components/SettingsOptions/SettingsOptionCardContentButton.tsx new file mode 100644 index 0000000000..7641508179 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/components/SettingsOptions/SettingsOptionCardContentButton.tsx @@ -0,0 +1,46 @@ +import { + StyledSettingsOptionCardContent, + StyledSettingsOptionCardDescription, + StyledSettingsOptionCardIcon, + StyledSettingsOptionCardTitle, +} from '@/settings/components/SettingsOptions/SettingsOptionCardContentBase'; +import { SettingsOptionIconCustomizer } from '@/settings/components/SettingsOptions/SettingsOptionIconCustomizer'; +import styled from '@emotion/styled'; +import { type IconComponent } from 'twenty-ui/display'; + +type SettingsOptionCardContentButtonProps = { + Icon?: IconComponent; + title: React.ReactNode; + description?: string | React.ReactNode; + disabled?: boolean; + Button?: React.ReactNode; +}; + +const StyledButtonContainer = styled.div` + margin-left: auto; +`; + +export const SettingsOptionCardContentButton = ({ + Icon, + title, + description, + disabled = false, + Button, +}: SettingsOptionCardContentButtonProps) => { + return ( + + {Icon && ( + + + + )} +
+ {title} + + {description} + +
+ {Button && {Button}} +
+ ); +}; diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectForm.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectForm.tsx index fd561eb343..360dbd01a6 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectForm.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectForm.tsx @@ -60,9 +60,7 @@ export const SettingsRolePermissionsObjectLevelObjectForm = ({ ) ?? false; const isRowLevelPermissionPredicatesEnabled = - featureFlagsMap[ - FeatureFlagKey.IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED - ] && isRLSBillingEntitlementEnabled; + featureFlagsMap[FeatureFlagKey.IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED]; const objectMetadataItem = objectMetadata.objectMetadataItem; @@ -170,6 +168,7 @@ export const SettingsRolePermissionsObjectLevelObjectForm = ({ )} diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection.tsx index 4a5589b322..88e9e70224 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection.tsx @@ -2,26 +2,84 @@ import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; -import { H2Title } from 'twenty-ui/display'; -import { Section } from 'twenty-ui/layout'; +import { Pill } from 'twenty-ui/components'; +import { H2Title, IconArrowUp, IconLock } from 'twenty-ui/display'; +import { Card, Section } from 'twenty-ui/layout'; +import { billingState } from '@/client-config/states/billingState'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { SettingsOptionCardContentButton } from '@/settings/components/SettingsOptions/SettingsOptionCardContentButton'; import { SettingsRolePermissionsObjectLevelRecordLevelPermissionFilterBuilder } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFilterBuilder'; +import { useRecoilValue } from 'recoil'; +import { SettingsPath } from 'twenty-shared/types'; +import { Button } from 'twenty-ui/input'; +import { useNavigateSettings } from '~/hooks/useNavigateSettings'; const StyledContent = styled.div` padding-bottom: ${({ theme }) => theme.spacing(2)}; padding-top: ${({ theme }) => theme.spacing(4)}; `; +const StyledCard = styled(Card)` + margin-top: ${({ theme }) => theme.spacing(4)}; + overflow: hidden; +`; + +const StyledPill = styled(Pill)` + border-radius: 40px; + border: 1px solid ${({ theme }) => theme.border.color.light}; + background: ${({ theme }) => theme.background.secondary}; + color: ${({ theme }) => theme.font.color.tertiary}; + font-weight: ${({ theme }) => theme.font.weight.medium}; + padding: ${({ theme }) => theme.spacing(1)} ${({ theme }) => theme.spacing(2)}; +`; + type SettingsRolePermissionsObjectLevelRecordLevelSectionProps = { objectMetadataItem: ObjectMetadataItem; roleId: string; + hasOrganizationPlan: boolean; }; export const SettingsRolePermissionsObjectLevelRecordLevelSection = ({ objectMetadataItem, roleId, + hasOrganizationPlan, }: SettingsRolePermissionsObjectLevelRecordLevelSectionProps) => { + const navigateSettings = useNavigateSettings(); + const billing = useRecoilValue(billingState); + const isBillingEnabled = billing?.isBillingEnabled ?? false; + + if (!hasOrganizationPlan) { + return ( +
+ } + /> + + navigateSettings(SettingsPath.Billing)} + /> + ) + } + /> + +
+ ); + } + return (
theme.background.transparent.light}; border-radius: ${({ theme }) => theme.border.radius.pill}; color: ${({ theme }) => theme.font.color.light}; - display: inline-block; + display: inline-flex; font-size: ${({ theme }) => theme.font.size.xs}; font-style: normal; font-weight: ${({ theme }) => theme.font.weight.medium}; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${({ theme }) => theme.spacing(1)}; height: ${({ theme }) => theme.spacing(4)}; justify-content: flex-end; line-height: ${({ theme }) => theme.text.lineHeight.lg}; padding: ${({ theme }) => `0 ${theme.spacing(2)}`}; `; -export const Pill = ({ className, label }: PillProps) => { - return {label}; +export const Pill = ({ className, label, Icon }: PillProps) => { + return ( + + {Icon && } + {label} + + ); };