diff --git a/packages/twenty-front/src/modules/settings/components/SettingsDatabaseEventsForm.tsx b/packages/twenty-front/src/modules/settings/components/SettingsDatabaseEventsForm.tsx index 93b1c52094..b9b7494398 100644 --- a/packages/twenty-front/src/modules/settings/components/SettingsDatabaseEventsForm.tsx +++ b/packages/twenty-front/src/modules/settings/components/SettingsDatabaseEventsForm.tsx @@ -19,8 +19,12 @@ const StyledFilterRow = styled.div<{ isMobile: boolean }>` gap: ${themeCssVariables.spacing[2]}; grid-template-columns: ${({ isMobile }) => isMobile - ? `${OBJECT_MOBILE_WIDTH}px ${ACTION_MOBILE_WIDTH}px auto` - : `${OBJECT_DROPDOWN_WIDTH}px ${ACTION_DROPDOWN_WIDTH}px auto`}; + ? `minmax(${OBJECT_MOBILE_WIDTH}px, 1fr) ${ACTION_MOBILE_WIDTH}px ${ + themeCssVariables.spacing[8] + }` + : `minmax(${OBJECT_DROPDOWN_WIDTH}px, 1fr) ${ACTION_DROPDOWN_WIDTH}px ${ + themeCssVariables.spacing[8] + }`}; margin-bottom: ${themeCssVariables.spacing[2]}; `; @@ -91,6 +95,7 @@ export const SettingsDatabaseEventsForm = ({ Icon={IconTrash} variant="tertiary" size="medium" + ariaLabel={t`Remove filter`} onClick={() => removeOperation?.(index)} /> ) : ( diff --git a/packages/twenty-front/src/modules/settings/developers/components/WebhookEntitySelect.tsx b/packages/twenty-front/src/modules/settings/developers/components/WebhookEntitySelect.tsx index d70560ef69..ac96945a14 100644 --- a/packages/twenty-front/src/modules/settings/developers/components/WebhookEntitySelect.tsx +++ b/packages/twenty-front/src/modules/settings/developers/components/WebhookEntitySelect.tsx @@ -1,5 +1,6 @@ import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { useObjectMetadataSelectHelpers } from '@/object-metadata/hooks/useObjectMetadataSelectHelpers'; +import { SelectControl } from '@/ui/input/components/SelectControl'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; @@ -12,66 +13,22 @@ import { SelectableList } from '@/ui/layout/selectable-list/components/Selectabl import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; -import { useContext, useState } from 'react'; +import { useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { IconBox, - IconChevronDown, - IconCode, - IconEye, - IconNorthStar, - IconSettings, + IconDatabase, + IconFileInfo, + IconListDetails, IconTable, + IconWebhook, } from 'twenty-ui/icon'; import { type SelectOption } from 'twenty-ui/input'; import { MenuItemSelect } from 'twenty-ui/navigation'; -import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants'; const WEBHOOK_ENTITY_DROPDOWN_ID = 'webhook-entity-select'; -const StyledControlContainer = styled.div<{ disabled?: boolean }>` - align-items: center; - background-color: ${themeCssVariables.background.transparent.lighter}; - border: 1px solid ${themeCssVariables.border.color.medium}; - border-radius: ${themeCssVariables.border.radius.sm}; - box-sizing: border-box; - cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')}; - display: flex; - gap: ${themeCssVariables.spacing[1]}; - height: ${themeCssVariables.spacing[8]}; - justify-content: space-between; - padding: 0 ${themeCssVariables.spacing[2]}; - width: 100%; - - &:hover { - background-color: ${({ disabled }) => - disabled - ? themeCssVariables.background.transparent.lighter - : themeCssVariables.background.transparent.light}; - } -`; - -const StyledControlLabel = styled.span` - color: ${themeCssVariables.font.color.primary}; - font-size: ${themeCssVariables.font.size.md}; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -`; - -const StyledControlIconChevronDownContainer = styled.span<{ - disabled?: boolean; -}>` - align-items: center; - color: ${({ disabled }) => - disabled - ? themeCssVariables.font.color.extraLight - : themeCssVariables.font.color.tertiary}; - display: flex; -`; - type WebhookEntitySelectProps = { value: string | null; onChange: (value: string | null) => void; @@ -85,7 +42,6 @@ export const WebhookEntitySelect = ({ disabled = false, dropdownId = WEBHOOK_ENTITY_DROPDOWN_ID, }: WebhookEntitySelectProps) => { - const { theme } = useContext(ThemeContext); const { getSelectIconPropsFromObjectMetadataItem } = useObjectMetadataSelectHelpers(); const [searchInput, setSearchInput] = useState(''); @@ -97,23 +53,29 @@ export const WebhookEntitySelect = ({ dropdownId, ); - const metadataOptions = [ - { label: t`All Metadata`, value: 'metadata.*', icon: IconNorthStar }, - { label: t`Object`, value: 'metadata.objectMetadata', icon: IconTable }, - { label: t`Field`, value: 'metadata.fieldMetadata', icon: IconBox }, - { label: t`View`, value: 'metadata.view', icon: IconEye }, - { label: t`View Field`, value: 'metadata.viewField', icon: IconEye }, - { label: t`Index`, value: 'metadata.index', icon: IconSettings }, - { label: t`Webhook`, value: 'metadata.webhook', icon: IconCode }, + const metadataOptions: SelectOption[] = [ + { label: t`All Metadata`, value: 'metadata.*', Icon: IconFileInfo }, + { label: t`Object`, value: 'metadata.objectMetadata', Icon: IconBox }, + { label: t`Field`, value: 'metadata.fieldMetadata', Icon: IconListDetails }, + { label: t`View`, value: 'metadata.view', Icon: IconTable }, + { + label: t`View Field`, + value: 'metadata.viewField', + Icon: IconListDetails, + }, + { label: t`Index`, value: 'metadata.index', Icon: IconDatabase }, + { label: t`Webhook`, value: 'metadata.webhook', Icon: IconWebhook }, ]; const objectOptions: SelectOption[] = [ - { label: t`All Objects`, value: '*', Icon: IconNorthStar }, - ...objectMetadataItems.map((item) => ({ - label: item.labelPlural, - value: item.nameSingular, - ...getSelectIconPropsFromObjectMetadataItem(item), - })), + { label: t`All Objects`, value: '*', Icon: IconBox }, + ...[...objectMetadataItems] + .sort((a, b) => a.labelPlural.localeCompare(b.labelPlural)) + .map((item) => ({ + label: item.labelPlural, + value: item.nameSingular, + ...getSelectIconPropsFromObjectMetadataItem(item), + })), ]; const filteredObjectOptions = objectOptions.filter((option) => @@ -124,26 +86,11 @@ export const WebhookEntitySelect = ({ option.label.toLowerCase().includes(searchInput.toLowerCase()), ); - const getSelectedLabel = () => { - if (!isDefined(value)) { - return t`Select entity`; - } - if (value === '*') { - return t`All Objects`; - } - - const metadataOption = metadataOptions.find((opt) => opt.value === value); - if (isDefined(metadataOption)) { - return metadataOption.label; - } - - const objectOption = objectOptions.find((opt) => opt.value === value); - if (isDefined(objectOption)) { - return objectOption.label; - } - - return value; - }; + const selectedOption = !isDefined(value) + ? { label: t`Select entity`, value: '' } + : ([...objectOptions, ...metadataOptions].find( + (option) => option.value === value, + ) ?? { label: value, value, Icon: IconBox }); const handleSelect = (selectedValue: string) => { if (disabled) return; @@ -168,12 +115,11 @@ export const WebhookEntitySelect = ({ disableClickForClickableComponent={disabled} onClose={() => setSearchInput('')} clickableComponent={ - - {getSelectedLabel()} - - - - + } dropdownComponents={ @@ -222,7 +168,7 @@ export const WebhookEntitySelect = ({ onEnter={() => handleSelect(option.value)} > ` - --padding: ${themeCssVariables.spacing[1]}; + --dropdown-menu-items-padding: ${themeCssVariables.spacing[1]}; + --dropdown-menu-items-row-gap: 2px; align-items: flex-start; box-sizing: border-box; @@ -17,7 +18,7 @@ const StyledExternalContainer = styled.div<{ max-height: ${({ maxHeight }) => (maxHeight ? `${maxHeight}px` : 'none')}; - padding: var(--padding); + padding: var(--dropdown-menu-items-padding); width: 100%; `; @@ -41,10 +42,34 @@ const StyledInternalContainer = styled.div` display: flex; flex-direction: column; - gap: 2px; + gap: var(--dropdown-menu-items-row-gap); height: 100%; width: 100%; + + > [data-dropdown-menu-section-label], + > [data-dropdown-menu-separator] { + margin-left: calc(0px - var(--dropdown-menu-items-padding)); + margin-right: calc(0px - var(--dropdown-menu-items-padding)); + width: calc( + 100% + var(--dropdown-menu-items-padding) + + var(--dropdown-menu-items-padding) + ); + } + + > [data-dropdown-menu-section-label]:first-child { + margin-top: calc(0px - var(--dropdown-menu-items-padding)); + } + + > [data-dropdown-menu-section-label] + * { + margin-top: calc( + var(--dropdown-menu-items-padding) - var(--dropdown-menu-items-row-gap) + ); + } + + > [data-dropdown-menu-separator] + [data-dropdown-menu-section-label] { + margin-top: calc(0px - var(--dropdown-menu-items-row-gap)); + } `; export const DropdownMenuItemsContainer = ({ diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSectionLabel.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSectionLabel.tsx index 7e718f21fc..63d1e74c77 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSectionLabel.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSectionLabel.tsx @@ -4,14 +4,16 @@ import { styled } from '@linaria/react'; const StyledDropdownMenuSectionLabel = styled.div` align-items: center; background-color: ${themeCssVariables.background.transparent.lighter}; + box-sizing: border-box; color: ${themeCssVariables.font.color.tertiary}; display: flex; font-size: ${themeCssVariables.font.size.xxs}; justify-content: flex-start; min-height: 20px; - padding-left: ${themeCssVariables.spacing[1]}; + padding-left: ${themeCssVariables.spacing[2]}; + padding-right: ${themeCssVariables.spacing[2]}; user-select: none; - width: auto; + width: 100%; `; export type DropdownMenuSectionLabelProps = { @@ -22,6 +24,8 @@ export const DropdownMenuSectionLabel = ({ label, }: DropdownMenuSectionLabelProps) => { return ( - {label} + + {label} + ); }; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSeparator.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSeparator.tsx index 472cfd8a3b..4593de943d 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSeparator.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSeparator.tsx @@ -1,4 +1,5 @@ import { styled } from '@linaria/react'; +import { forwardRef } from 'react'; import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledDropdownMenuSeparator = styled.div` @@ -7,4 +8,8 @@ const StyledDropdownMenuSeparator = styled.div` width: 100%; `; -export const DropdownMenuSeparator = StyledDropdownMenuSeparator; +export const DropdownMenuSeparator = forwardRef((_, ref) => { + return ; +}); + +DropdownMenuSeparator.displayName = 'DropdownMenuSeparator';