Fix View picker dropdown placement (#14457)

Fixes https://github.com/twentyhq/twenty/issues/14445

## What

In the current `MenuItemWithOptionDropdown` component (which is a
MenuItem with the 3 dots dropdown), we used to have a position: static
on the 3 dots hovered.
This enabled the dropdown to not move when we scroll the MenuItems.

However, this is not playing well with the dropdown autoplacement.
I'm removing it as I think the right solution would actually to prevent
the scroll when the dropdown is open but this is non straight forward
and not really a big issue. I'm fine with the dropdown being "fixed" to
the scrollable content, it also makes sense

Before:


https://github.com/user-attachments/assets/8efec8fa-430a-408e-b549-fd7433b7a38d

After:


https://github.com/user-attachments/assets/b8ee4375-0944-4008-9ab6-f7f9f1d67e9c



## Testing

I was considering adding a story here but this is hard to test: hover +
scroll behavior are not well supported, I don't think it worth the
investment especially as I think the vision is to block the scroll

This componenent is used in ViewPicker and MultiItemsInput (ex.
PhonesFieldInput). I have check that both were still working well
This commit is contained in:
Charles Bochet
2025-09-12 22:47:51 +02:00
committed by Charles Bochet
parent f0f12a0643
commit 9828f27bbd
5 changed files with 40 additions and 10 deletions
@@ -3508,9 +3508,7 @@ export type UpdateViewInput = {
isCompact?: InputMaybe<Scalars['Boolean']>;
kanbanAggregateOperation?: InputMaybe<AggregateOperations>;
kanbanAggregateOperationFieldMetadataId?: InputMaybe<Scalars['UUID']>;
key?: InputMaybe<ViewKey>;
name?: InputMaybe<Scalars['String']>;
objectMetadataId?: InputMaybe<Scalars['UUID']>;
openRecordIn?: InputMaybe<ViewOpenRecordIn>;
position?: InputMaybe<Scalars['Float']>;
type?: InputMaybe<ViewType>;
@@ -3346,9 +3346,7 @@ export type UpdateViewInput = {
isCompact?: InputMaybe<Scalars['Boolean']>;
kanbanAggregateOperation?: InputMaybe<AggregateOperations>;
kanbanAggregateOperationFieldMetadataId?: InputMaybe<Scalars['UUID']>;
key?: InputMaybe<ViewKey>;
name?: InputMaybe<Scalars['String']>;
objectMetadataId?: InputMaybe<Scalars['UUID']>;
openRecordIn?: InputMaybe<ViewOpenRecordIn>;
position?: InputMaybe<Scalars['Float']>;
type?: InputMaybe<ViewType>;
@@ -1,6 +1,43 @@
import { InputType, PartialType } from '@nestjs/graphql';
import { Field, InputType } from '@nestjs/graphql';
import { CreateViewInput } from './create-view.input';
import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant';
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { ViewOpenRecordIn } from 'src/engine/core-modules/view/enums/view-open-record-in';
import { ViewType } from 'src/engine/core-modules/view/enums/view-type.enum';
// TODO: this should be refactored like for view-field.input.ts
// This is a temporary fix as we were extending the CreateViewInput class which was adding default values for the non filled fields
@InputType()
export class UpdateViewInput extends PartialType(CreateViewInput) {}
export class UpdateViewInput {
@Field(() => UUIDScalarType, { nullable: true })
id: string;
@Field({ nullable: true })
name?: string;
@Field(() => ViewType, { nullable: true })
type?: ViewType;
@Field({ nullable: true })
icon?: string;
@Field({ nullable: true })
position?: number;
@Field({ nullable: true })
isCompact?: boolean;
@Field(() => ViewOpenRecordIn, {
nullable: true,
})
openRecordIn?: ViewOpenRecordIn;
@Field(() => AggregateOperations, { nullable: true })
kanbanAggregateOperation?: AggregateOperations;
@Field(() => UUIDScalarType, { nullable: true })
kanbanAggregateOperationFieldMetadataId?: string;
@Field({ nullable: true })
anyFieldFilterValue?: string;
}
@@ -237,7 +237,6 @@ describe('View Resolver', () => {
name: 'Updated View',
type: ViewType.KANBAN,
isCompact: true,
objectMetadataId: testObjectMetadataId,
});
const operation = updateViewOperationFactory({
@@ -138,14 +138,12 @@ export const StyledHoverableMenuItemBase = styled(StyledMenuItemBase)<{
css`
& .hoverable-buttons {
opacity: 0;
position: fixed;
right: ${theme.spacing(2)};
}
&:hover {
& .hoverable-buttons {
opacity: 1;
position: static;
}
}
`};