diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx index 608e4cbc7..19d2e151f 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx @@ -127,7 +127,7 @@ export const CalendarEventDetails = ({ size={ChipSize.Large} variant={ChipVariant.Highlighted} clickable={false} - leftComponent={() => } + leftComponent={} label="Event" /> diff --git a/packages/twenty-front/src/modules/activities/emails/components/MessageThreadSubscribersChip.tsx b/packages/twenty-front/src/modules/activities/emails/components/MessageThreadSubscribersChip.tsx index 47c575a80..e78e29159 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/MessageThreadSubscribersChip.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/MessageThreadSubscribersChip.tsx @@ -1,8 +1,8 @@ import { MessageThreadSubscriber } from '@/activities/emails/types/MessageThreadSubscriber'; import { isNonEmptyString } from '@sniptt/guards'; import { useContext } from 'react'; -import { Avatar, AvatarGroup, IconChevronDown } from 'twenty-ui/display'; import { Chip, ChipVariant } from 'twenty-ui/components'; +import { Avatar, AvatarGroup, IconChevronDown } from 'twenty-ui/display'; import { ThemeContext } from 'twenty-ui/theme'; const MAX_NUMBER_OF_AVATARS = 3; @@ -46,20 +46,16 @@ export const MessageThreadSubscribersChip = ({ { - if (isOnlyOneSubscriber) { - return ( - - ); - } - - return ( + leftComponent={ + isOnlyOneSubscriber ? ( + + ) : ( ( ))} /> - ); - }} + ) + } rightComponent={() => } clickable /> diff --git a/packages/twenty-front/src/modules/apollo/hooks/useApolloFactory.ts b/packages/twenty-front/src/modules/apollo/hooks/useApolloFactory.ts index ab47e4e81..8303dab65 100644 --- a/packages/twenty-front/src/modules/apollo/hooks/useApolloFactory.ts +++ b/packages/twenty-front/src/modules/apollo/hooks/useApolloFactory.ts @@ -16,8 +16,8 @@ import { useUpdateEffect } from '~/hooks/useUpdateEffect'; import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState'; import { AppPath } from '@/types/AppPath'; -import { ApolloFactory, Options } from '../services/apollo.factory'; import { isDefined } from 'twenty-shared/utils'; +import { ApolloFactory, Options } from '../services/apollo.factory'; export const useApolloFactory = (options: Partial> = {}) => { // eslint-disable-next-line @nx/workspace-no-state-useref @@ -26,7 +26,7 @@ export const useApolloFactory = (options: Partial> = {}) => { const navigate = useNavigate(); const { isMatchingLocation } = useIsMatchingLocation(); - const [tokenPair, setTokenPair] = useRecoilState(tokenPairState); + const setTokenPair = useSetRecoilState(tokenPairState); const [currentWorkspace, setCurrentWorkspace] = useRecoilState( currentWorkspaceState, ); @@ -62,8 +62,6 @@ export const useApolloFactory = (options: Partial> = {}) => { }, }, connectToDevTools: isDebugMode, - // We don't want to re-create the client on token change or it will cause infinite loop - initialTokenPair: tokenPair, currentWorkspaceMember: currentWorkspaceMember, onTokenPairChange: (tokenPair) => { setTokenPair(tokenPair); @@ -104,12 +102,6 @@ export const useApolloFactory = (options: Partial> = {}) => { setPreviousUrl, ]); - useUpdateEffect(() => { - if (isDefined(apolloRef.current)) { - apolloRef.current.updateTokenPair(tokenPair); - } - }, [tokenPair]); - useUpdateEffect(() => { if (isDefined(apolloRef.current)) { apolloRef.current.updateWorkspaceMember(currentWorkspaceMember); diff --git a/packages/twenty-front/src/modules/apollo/services/__tests__/apollo.factory.test.ts b/packages/twenty-front/src/modules/apollo/services/__tests__/apollo.factory.test.ts index c5daf63c7..60d49ac58 100644 --- a/packages/twenty-front/src/modules/apollo/services/__tests__/apollo.factory.test.ts +++ b/packages/twenty-front/src/modules/apollo/services/__tests__/apollo.factory.test.ts @@ -33,10 +33,6 @@ const mockWorkspaceMember = { const createMockOptions = (): Options => ({ uri: 'http://localhost:3000', - initialTokenPair: { - accessToken: { token: 'mockAccessToken', expiresAt: '' }, - refreshToken: { token: 'mockRefreshToken', expiresAt: '' }, - }, currentWorkspaceMember: mockWorkspaceMember, cache: new InMemoryCache(), isDebugMode: true, diff --git a/packages/twenty-front/src/modules/apollo/services/apollo.factory.ts b/packages/twenty-front/src/modules/apollo/services/apollo.factory.ts index cc425813f..97192aa9c 100644 --- a/packages/twenty-front/src/modules/apollo/services/apollo.factory.ts +++ b/packages/twenty-front/src/modules/apollo/services/apollo.factory.ts @@ -18,9 +18,11 @@ import { logDebug } from '~/utils/logDebug'; import { i18n } from '@lingui/core'; import { GraphQLFormattedError } from 'graphql'; +import { isDefined } from 'twenty-shared/utils'; +import { cookieStorage } from '~/utils/cookie-storage'; +import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; import { ApolloManager } from '../types/apolloManager.interface'; import { loggerLink } from '../utils/loggerLink'; -import { isDefined } from 'twenty-shared/utils'; const logger = loggerLink(() => 'Twenty'); @@ -29,7 +31,6 @@ export interface Options extends ApolloClientOptions { onNetworkError?: (err: Error | ServerParseError | ServerError) => void; onTokenPairChange?: (tokenPair: AuthTokenPair) => void; onUnauthenticatedError?: () => void; - initialTokenPair: AuthTokenPair | null; currentWorkspaceMember: CurrentWorkspaceMember | null; extraLinks?: ApolloLink[]; isDebugMode?: boolean; @@ -37,7 +38,6 @@ export interface Options extends ApolloClientOptions { export class ApolloFactory implements ApolloManager { private client: ApolloClient; - private tokenPair: AuthTokenPair | null = null; private currentWorkspaceMember: CurrentWorkspaceMember | null = null; constructor(opts: Options) { @@ -47,28 +47,45 @@ export class ApolloFactory implements ApolloManager { onNetworkError, onTokenPairChange, onUnauthenticatedError, - initialTokenPair, currentWorkspaceMember, extraLinks, isDebugMode, ...options } = opts; - this.tokenPair = initialTokenPair; this.currentWorkspaceMember = currentWorkspaceMember; + const getTokenPair = () => { + const stringTokenPair = cookieStorage.getItem('tokenPair'); + const tokenPair = isDefined(stringTokenPair) + ? (JSON.parse(stringTokenPair) as AuthTokenPair) + : undefined; + return tokenPair; + }; + const buildApolloLink = (): ApolloLink => { const httpLink = createUploadLink({ uri, }); const authLink = setContext(async (_, { headers }) => { + const tokenPair = getTokenPair(); + + if (isUndefinedOrNull(tokenPair)) { + return { + headers: { + ...headers, + ...options.headers, + }, + }; + } + return { headers: { ...headers, ...options.headers, - authorization: this.tokenPair?.accessToken.token - ? `Bearer ${this.tokenPair?.accessToken.token}` + authorization: tokenPair.accessToken.token + ? `Bearer ${tokenPair.accessToken.token}` : '', ...(this.currentWorkspaceMember?.locale ? { 'x-locale': this.currentWorkspaceMember.locale } @@ -93,7 +110,7 @@ export class ApolloFactory implements ApolloManager { for (const graphQLError of graphQLErrors) { if (graphQLError.message === 'Unauthorized') { return fromPromise( - renewToken(uri, this.tokenPair) + renewToken(uri, getTokenPair()) .then((tokens) => { if (isDefined(tokens)) { onTokenPairChange?.(tokens); @@ -108,10 +125,14 @@ export class ApolloFactory implements ApolloManager { switch (graphQLError?.extensions?.code) { case 'UNAUTHENTICATED': { return fromPromise( - renewToken(uri, this.tokenPair) + renewToken(uri, getTokenPair()) .then((tokens) => { if (isDefined(tokens)) { onTokenPairChange?.(tokens); + cookieStorage.setItem( + 'tokenPair', + JSON.stringify(tokens), + ); } }) .catch(() => { @@ -162,10 +183,6 @@ export class ApolloFactory implements ApolloManager { }); } - updateTokenPair(tokenPair: AuthTokenPair | null) { - this.tokenPair = tokenPair; - } - updateWorkspaceMember(workspaceMember: CurrentWorkspaceMember | null) { this.currentWorkspaceMember = workspaceMember; } diff --git a/packages/twenty-front/src/modules/apollo/types/apolloManager.interface.ts b/packages/twenty-front/src/modules/apollo/types/apolloManager.interface.ts index 1f033c8c3..8f34289d1 100644 --- a/packages/twenty-front/src/modules/apollo/types/apolloManager.interface.ts +++ b/packages/twenty-front/src/modules/apollo/types/apolloManager.interface.ts @@ -1,10 +1,8 @@ import { ApolloClient } from '@apollo/client'; import { CurrentWorkspaceMember } from '@/auth/states/currentWorkspaceMemberState'; -import { AuthTokenPair } from '~/generated/graphql'; export interface ApolloManager { getClient(): ApolloClient; - updateTokenPair(tokenPair: AuthTokenPair | null): void; updateWorkspaceMember(workspaceMember: CurrentWorkspaceMember | null): void; } diff --git a/packages/twenty-front/src/modules/auth/hooks/useAuth.ts b/packages/twenty-front/src/modules/auth/hooks/useAuth.ts index 5a4a3891a..8d970c2fd 100644 --- a/packages/twenty-front/src/modules/auth/hooks/useAuth.ts +++ b/packages/twenty-front/src/modules/auth/hooks/useAuth.ts @@ -63,6 +63,7 @@ import { useSearchParams } from 'react-router-dom'; import { APP_LOCALES } from 'twenty-shared/translations'; import { isDefined } from 'twenty-shared/utils'; import { iconsState } from 'twenty-ui/display'; +import { cookieStorage } from '~/utils/cookie-storage'; import { getWorkspaceUrl } from '~/utils/getWorkspaceUrl'; import { dynamicActivate } from '~/utils/i18n/dynamicActivate'; @@ -348,6 +349,12 @@ export const useAuth = () => { setTokenPair( getAuthTokensResult.data?.getAuthTokensFromLoginToken.tokens, ); + cookieStorage.setItem( + 'tokenPair', + JSON.stringify( + getAuthTokensResult.data?.getAuthTokensFromLoginToken.tokens, + ), + ); await refreshObjectMetadataItems(); await loadCurrentUser(); diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/EmailsFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/EmailsFieldDisplay.tsx index b2a6fc724..e0d22664c 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/EmailsFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/EmailsFieldDisplay.tsx @@ -1,8 +1,8 @@ -import { useEmailsField } from '@/object-record/record-field/meta-types/hooks/useEmailsField'; +import { useEmailsFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useEmailsFieldDisplay'; import { EmailsDisplay } from '@/ui/field/display/components/EmailsDisplay'; export const EmailsFieldDisplay = () => { - const { fieldValue } = useEmailsField(); + const { fieldValue } = useEmailsFieldDisplay(); return ; }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellDisplayContainer.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellDisplayContainer.tsx index a648e9350..4f0f2c342 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellDisplayContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellDisplayContainer.tsx @@ -2,9 +2,7 @@ import { Theme, withTheme } from '@emotion/react'; import { styled } from '@linaria/react'; import { Ref } from 'react'; -const StyledOuterContainer = styled.div<{ - hasSoftFocus?: boolean; -}>` +const StyledOuterContainer = styled.div` align-items: center; display: flex; height: 100%; @@ -50,7 +48,6 @@ export const RecordTableCellDisplayContainer = ({ } onClick={onClick} ref={scrollRef} - hasSoftFocus={softFocus} onContextMenu={onContextMenu} > {placeholderForEmptyCell ? ( diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellWrapper.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellWrapper.tsx index 59c8600bd..81f2ea988 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellWrapper.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellWrapper.tsx @@ -1,5 +1,3 @@ -import { useMemo } from 'react'; - import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext'; @@ -9,6 +7,7 @@ import { isTableCellInEditModeComponentFamilyState } from '@/object-record/recor import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2'; +import { useMemo } from 'react'; export const RecordTableCellWrapper = ({ children, diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableTd.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableTd.tsx index b85d0276a..20e590e07 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableTd.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableTd.tsx @@ -18,25 +18,19 @@ const StyledTd = styled.td<{ width?: number; }>` border-bottom: 1px solid - ${({ borderColor, hasBottomBorder }) => - hasBottomBorder ? borderColor : 'transparent'}; + ${({ borderColor, hasBottomBorder, isDragging }) => + hasBottomBorder && !isDragging ? borderColor : 'transparent'}; color: ${({ fontColor }) => fontColor}; - border-right: ${({ borderColor, hasRightBorder }) => - hasRightBorder ? `1px solid ${borderColor}` : 'none'}; + border-right: ${({ borderColor, hasRightBorder, isDragging }) => + hasRightBorder && !isDragging ? `1px solid ${borderColor}` : 'none'}; padding: 0; transition: 0.3s ease; text-align: left; - background: ${({ backgroundColor }) => backgroundColor}; - ${({ isDragging }) => - isDragging - ? ` - background-color: transparent; - border-color: transparent; - ` - : ''} + background: ${({ backgroundColor, isDragging }) => + isDragging ? 'transparent' : backgroundColor}; ${({ freezeFirstColumns }) => freezeFirstColumns diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHeadDropdownMenu.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHeadDropdownMenu.tsx index 09f6ea9c8..083467c79 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHeadDropdownMenu.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHeadDropdownMenu.tsx @@ -6,10 +6,9 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { onToggleColumnFilterComponentState } from '@/object-record/record-table/states/onToggleColumnFilterComponentState'; import { onToggleColumnSortComponentState } from '@/object-record/record-table/states/onToggleColumnSortComponentState'; import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector'; +import { useToggleScrollWrapper } from '@/ui/utilities/scroll/hooks/useToggleScrollWrapper'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useLingui } from '@lingui/react/macro'; -import { useTableColumns } from '../../hooks/useTableColumns'; -import { ColumnDefinition } from '../../types/ColumnDefinition'; import { IconArrowLeft, IconArrowRight, @@ -18,6 +17,8 @@ import { IconSortDescending, } from 'twenty-ui/display'; import { MenuItem } from 'twenty-ui/navigation'; +import { useTableColumns } from '../../hooks/useTableColumns'; +import { ColumnDefinition } from '../../types/ColumnDefinition'; export type RecordTableColumnHeadDropdownMenuProps = { column: ColumnDefinition; @@ -28,6 +29,9 @@ export const RecordTableColumnHeadDropdownMenu = ({ }: RecordTableColumnHeadDropdownMenuProps) => { const { t } = useLingui(); + const { toggleScrollXWrapper, toggleScrollYWrapper } = + useToggleScrollWrapper(); + const visibleTableColumns = useRecoilComponentValueV2( visibleTableColumnsComponentSelector, ); @@ -46,16 +50,21 @@ export const RecordTableColumnHeadDropdownMenu = ({ const { closeDropdown } = useDropdown(column.fieldMetadataId + '-header'); - const handleColumnMoveLeft = () => { + const closeDropdownAndToggleScroll = () => { closeDropdown(); + toggleScrollXWrapper(true); + toggleScrollYWrapper(false); + }; + const handleColumnMoveLeft = () => { + closeDropdownAndToggleScroll(); if (!canMoveLeft) return; handleMoveTableColumn('left', column); }; const handleColumnMoveRight = () => { - closeDropdown(); + closeDropdownAndToggleScroll(); if (!canMoveRight) return; @@ -63,7 +72,7 @@ export const RecordTableColumnHeadDropdownMenu = ({ }; const handleColumnVisibility = () => { - closeDropdown(); + closeDropdownAndToggleScroll(); handleColumnVisibilityChange(column); }; @@ -75,13 +84,13 @@ export const RecordTableColumnHeadDropdownMenu = ({ ); const handleSortClick = () => { - closeDropdown(); + closeDropdownAndToggleScroll(); onToggleColumnSort?.(column.fieldMetadataId); }; const handleFilterClick = () => { - closeDropdown(); + closeDropdownAndToggleScroll(); onToggleColumnFilter?.(column.fieldMetadataId); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTrEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTrEffect.tsx index 3fbe22e7b..c1d02cc0a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTrEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTrEffect.tsx @@ -1,4 +1,3 @@ -import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { isRowVisibleComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowVisibleComponentFamilyState'; import { useScrollWrapperElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperElement'; import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2'; @@ -9,7 +8,6 @@ type RecordTableTrEffectProps = { }; export const RecordTableTrEffect = ({ recordId }: RecordTableTrEffectProps) => { - const { onIndexRecordsLoaded } = useRecordIndexContextOrThrow(); const { scrollWrapperHTMLElement } = useScrollWrapperElement(); const setIsRowVisible = useSetRecoilComponentFamilyStateV2( @@ -29,7 +27,6 @@ export const RecordTableTrEffect = ({ recordId }: RecordTableTrEffectProps) => { const isIntersecting = entry.isIntersecting; if (isIntersecting) { - onIndexRecordsLoaded?.(); setIsRowVisible(true); } @@ -50,12 +47,7 @@ export const RecordTableTrEffect = ({ recordId }: RecordTableTrEffectProps) => { return () => { observer.disconnect(); }; - }, [ - onIndexRecordsLoaded, - recordId, - scrollWrapperHTMLElement, - setIsRowVisible, - ]); + }, [recordId, scrollWrapperHTMLElement, setIsRowVisible]); return <>; }; diff --git a/packages/twenty-front/src/modules/ui/field/display/components/EmailsDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/EmailsDisplay.tsx index d98c14b19..9e39e0ecd 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/EmailsDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/EmailsDisplay.tsx @@ -2,7 +2,7 @@ import { useMemo } from 'react'; import { FieldEmailsValue } from '@/object-record/record-field/types/FieldMetadata'; import { ExpandableList } from '@/ui/layout/expandable-list/components/ExpandableList'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; import { RoundedLink } from 'twenty-ui/navigation'; import { THEME_COMMON } from 'twenty-ui/theme'; diff --git a/packages/twenty-front/src/modules/ui/field/display/components/MultiSelectDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/MultiSelectDisplay.tsx index 6e2169246..d56fab1e1 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/MultiSelectDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/MultiSelectDisplay.tsx @@ -1,7 +1,7 @@ import { FieldMultiSelectValue } from '@/object-record/record-field/types/FieldMetadata'; -import styled from '@emotion/styled'; -import { SelectOption } from 'twenty-ui/input'; +import { styled } from '@linaria/react'; import { Tag } from 'twenty-ui/components'; +import { SelectOption } from 'twenty-ui/input'; import { THEME_COMMON } from 'twenty-ui/theme'; const spacing1 = THEME_COMMON.spacing(1); diff --git a/packages/twenty-front/src/modules/ui/field/display/components/PhonesDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/PhonesDisplay.tsx index 5f62b0345..bf801bd67 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/PhonesDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/PhonesDisplay.tsx @@ -1,15 +1,15 @@ -import styled from '@emotion/styled'; import React, { useMemo } from 'react'; import { FieldPhonesValue } from '@/object-record/record-field/types/FieldMetadata'; import { ExpandableList } from '@/ui/layout/expandable-list/components/ExpandableList'; import { DEFAULT_PHONE_CALLING_CODE } from '@/object-record/record-field/meta-types/input/components/PhonesFieldInput'; +import { styled } from '@linaria/react'; import { parsePhoneNumber } from 'libphonenumber-js'; -import { logError } from '~/utils/logError'; import { isDefined } from 'twenty-shared/utils'; import { RoundedLink } from 'twenty-ui/navigation'; import { THEME_COMMON } from 'twenty-ui/theme'; +import { logError } from '~/utils/logError'; type PhonesDisplayProps = { value?: FieldPhonesValue; diff --git a/packages/twenty-front/src/modules/ui/field/display/components/TextDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/TextDisplay.tsx index a795e5e39..0a0ffa8f9 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/TextDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/TextDisplay.tsx @@ -1,4 +1,3 @@ -import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell'; import { OverflowingTextWithTooltip } from 'twenty-ui/display'; type TextDisplayProps = { @@ -7,13 +6,11 @@ type TextDisplayProps = { }; export const TextDisplay = ({ text, displayedMaxRows }: TextDisplayProps) => { - const { isInlineCellInEditMode } = useInlineCell(); return ( ); }; diff --git a/packages/twenty-front/src/modules/ui/field/display/components/URLDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/URLDisplay.tsx index 35f61f94c..21e33989e 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/URLDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/URLDisplay.tsx @@ -1,19 +1,8 @@ -import styled from '@emotion/styled'; import { MouseEvent } from 'react'; +import { LinkType, RoundedLink, SocialLink } from 'twenty-ui/navigation'; import { checkUrlType } from '~/utils/checkUrlType'; import { EllipsisDisplay } from './EllipsisDisplay'; -import { LinkType, RoundedLink, SocialLink } from 'twenty-ui/navigation'; - -const StyledRawLink = styled(RoundedLink)` - overflow: hidden; - - a { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } -`; type URLDisplayProps = { value: string | null; @@ -48,7 +37,7 @@ export const URLDisplay = ({ value }: URLDisplayProps) => { } return ( - theme.spacing(2)}; z-index: 1; `; @@ -195,51 +195,56 @@ export const ViewBarDetails = ({ return ( - - {isDefined(softDeleteFilter) && ( - - )} - {isDefined(softDeleteFilter) && ( - - - - )} - {currentRecordSorts.map((recordSort) => ( - - ))} - {isNonEmptyArray(recordFilters) && - isNonEmptyArray(currentRecordSorts) && ( + + + {isDefined(softDeleteFilter) && ( + + )} + {isDefined(softDeleteFilter) && ( )} - {shouldShowAdvancedFilterDropdownButton && ( - - )} - {recordFilters.map((recordFilter) => ( - - - - - - - ))} - + {currentRecordSorts.map((recordSort) => ( + + ))} + {isNonEmptyArray(recordFilters) && + isNonEmptyArray(currentRecordSorts) && ( + + + + )} + {shouldShowAdvancedFilterDropdownButton && ( + + )} + {recordFilters.map((recordFilter) => ( + + + + + + + ))} + + {hasFilterButton && ( { '**/RecordTableHeaderDragDropColumn.tsx', '**/ActorDisplay.tsx', '**/AvatarChip.tsx', + '**/URLDisplay.tsx', + '**/EmailsDisplay.tsx', + '**/PhonesDisplay.tsx', + '**/MultiSelectDisplay.tsx', + ], babelOptions: { presets: ['@babel/preset-typescript', '@babel/preset-react'], diff --git a/packages/twenty-ui/src/components/avatar-chip/AvatarChip.tsx b/packages/twenty-ui/src/components/avatar-chip/AvatarChip.tsx index b957ba427..8b2e96047 100644 --- a/packages/twenty-ui/src/components/avatar-chip/AvatarChip.tsx +++ b/packages/twenty-ui/src/components/avatar-chip/AvatarChip.tsx @@ -19,7 +19,7 @@ export const AvatarChip = ({ label={name} variant={ChipVariant.Transparent} size={size} - leftComponent={() => ( + leftComponent={ - )} + } clickable={false} className={className} maxWidth={maxWidth} diff --git a/packages/twenty-ui/src/components/avatar-chip/AvatarChipLeftComponent.tsx b/packages/twenty-ui/src/components/avatar-chip/AvatarChipLeftComponent.tsx index 1543c9950..efe08146e 100644 --- a/packages/twenty-ui/src/components/avatar-chip/AvatarChipLeftComponent.tsx +++ b/packages/twenty-ui/src/components/avatar-chip/AvatarChipLeftComponent.tsx @@ -1,5 +1,5 @@ import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Avatar } from '@ui/display/avatar/components/Avatar'; import { AvatarType } from '@ui/display/avatar/types/AvatarType'; import { IconComponent } from '@ui/display/icon/types/IconComponent'; diff --git a/packages/twenty-ui/src/components/avatar-chip/LinkAvatarChip.tsx b/packages/twenty-ui/src/components/avatar-chip/LinkAvatarChip.tsx index ca1001803..f291dd8ac 100644 --- a/packages/twenty-ui/src/components/avatar-chip/LinkAvatarChip.tsx +++ b/packages/twenty-ui/src/components/avatar-chip/LinkAvatarChip.tsx @@ -39,7 +39,7 @@ export const LinkAvatarChip = ({ : ChipVariant.Regular } size={size} - leftComponent={() => ( + leftComponent={ - )} + } className={className} maxWidth={maxWidth} /> diff --git a/packages/twenty-ui/src/components/chip/Chip.tsx b/packages/twenty-ui/src/components/chip/Chip.tsx index 4f471479e..4b65715eb 100644 --- a/packages/twenty-ui/src/components/chip/Chip.tsx +++ b/packages/twenty-ui/src/components/chip/Chip.tsx @@ -30,7 +30,7 @@ export type ChipProps = { maxWidth?: number; variant?: ChipVariant; accent?: ChipAccent; - leftComponent?: (() => ReactNode) | null; + leftComponent?: ReactNode | null; rightComponent?: (() => ReactNode) | null; className?: string; }; @@ -146,7 +146,7 @@ export const Chip = ({ className={className} maxWidth={maxWidth} > - {leftComponent?.()} + {leftComponent} {!isLabelHidden && ( )} diff --git a/packages/twenty-ui/src/components/chip/LinkChip.tsx b/packages/twenty-ui/src/components/chip/LinkChip.tsx index 5076ec3b3..a7a4bc937 100644 --- a/packages/twenty-ui/src/components/chip/LinkChip.tsx +++ b/packages/twenty-ui/src/components/chip/LinkChip.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Chip, ChipAccent, @@ -17,8 +17,6 @@ export type LinkChipProps = Omit< onClick?: (event: MouseEvent) => void; }; -// Ideally we would use the UndecoratedLink component from @ui/navigation -// but it led to a bug probably linked to circular dependencies, which was hard to solve const StyledLink = styled(Link)` text-decoration: none; `; diff --git a/packages/twenty-ui/src/display/avatar/components/Avatar.tsx b/packages/twenty-ui/src/display/avatar/components/Avatar.tsx index f33d76bff..92cb2963b 100644 --- a/packages/twenty-ui/src/display/avatar/components/Avatar.tsx +++ b/packages/twenty-ui/src/display/avatar/components/Avatar.tsx @@ -1,7 +1,6 @@ import { styled } from '@linaria/react'; import { isNonEmptyString, isNull, isUndefined } from '@sniptt/guards'; import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { invalidAvatarUrlsState } from '@ui/display/avatar/components/states/isInvalidAvatarUrlState'; import { AVATAR_PROPERTIES_BY_SIZE } from '@ui/display/avatar/constants/AvatarPropertiesBySize'; @@ -11,6 +10,7 @@ import { IconComponent } from '@ui/display/icon/types/IconComponent'; import { ThemeContext } from '@ui/theme'; import { Nullable, stringToHslColor } from '@ui/utilities'; import { REACT_APP_SERVER_BASE_URL } from '@ui/utilities/config'; +import { useRecoilState } from 'recoil'; import { getImageAbsoluteURI } from 'twenty-shared/utils'; const StyledAvatar = styled.div<{ diff --git a/packages/twenty-ui/src/navigation/link/components/RoundedLink.tsx b/packages/twenty-ui/src/navigation/link/components/RoundedLink.tsx index ef3b05953..808e316e9 100644 --- a/packages/twenty-ui/src/navigation/link/components/RoundedLink.tsx +++ b/packages/twenty-ui/src/navigation/link/components/RoundedLink.tsx @@ -7,6 +7,7 @@ type RoundedLinkProps = { href: string; label?: string; onClick?: (event: React.MouseEvent) => void; + className?: string; }; const fontSizeMd = FONT_COMMON.size.md; @@ -59,7 +60,12 @@ const StyledLink = styled.a<{ } `; -export const RoundedLink = ({ label, href, onClick }: RoundedLinkProps) => { +export const RoundedLink = ({ + label, + href, + onClick, + className, +}: RoundedLinkProps) => { const { theme } = useContext(ThemeContext); const background = theme.background.transparent.lighter; @@ -89,6 +95,7 @@ export const RoundedLink = ({ label, href, onClick }: RoundedLinkProps) => { backgroundHover={backgroundHover} backgroundActive={backgroundActive} border={border} + className={className} > {label} diff --git a/packages/twenty-ui/vite.config.ts b/packages/twenty-ui/vite.config.ts index f1239a9f4..d14c84510 100644 --- a/packages/twenty-ui/vite.config.ts +++ b/packages/twenty-ui/vite.config.ts @@ -84,6 +84,9 @@ export default defineConfig(({ command }) => { '**/Tag.tsx', '**/Avatar.tsx', '**/Chip.tsx', + '**/LinkChip.tsx', + '**/Avatar.tsx', + '**/AvatarChipLeftComponent.tsx', '**/ContactLink.tsx', '**/RoundedLink.tsx', ],