From 9828f27bbdc70a43f79e67d0cd0959547654a4e3 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Fri, 12 Sep 2025 19:45:23 +0200 Subject: [PATCH] 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 --- .../src/generated-metadata/graphql.ts | 2 - .../twenty-front/src/generated/graphql.ts | 2 - .../view/dtos/inputs/update-view.input.ts | 43 +++++++++++++++++-- .../view/view-resolver.integration-spec.ts | 1 - .../components/StyledMenuItemBase.tsx | 2 - 5 files changed, 40 insertions(+), 10 deletions(-) diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 03f46f5adb0..84184406269 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -3508,9 +3508,7 @@ export type UpdateViewInput = { isCompact?: InputMaybe; kanbanAggregateOperation?: InputMaybe; kanbanAggregateOperationFieldMetadataId?: InputMaybe; - key?: InputMaybe; name?: InputMaybe; - objectMetadataId?: InputMaybe; openRecordIn?: InputMaybe; position?: InputMaybe; type?: InputMaybe; diff --git a/packages/twenty-front/src/generated/graphql.ts b/packages/twenty-front/src/generated/graphql.ts index 85417c98005..88ea5514f6d 100644 --- a/packages/twenty-front/src/generated/graphql.ts +++ b/packages/twenty-front/src/generated/graphql.ts @@ -3346,9 +3346,7 @@ export type UpdateViewInput = { isCompact?: InputMaybe; kanbanAggregateOperation?: InputMaybe; kanbanAggregateOperationFieldMetadataId?: InputMaybe; - key?: InputMaybe; name?: InputMaybe; - objectMetadataId?: InputMaybe; openRecordIn?: InputMaybe; position?: InputMaybe; type?: InputMaybe; diff --git a/packages/twenty-server/src/engine/core-modules/view/dtos/inputs/update-view.input.ts b/packages/twenty-server/src/engine/core-modules/view/dtos/inputs/update-view.input.ts index 3eaf34ebd84..965936b365b 100644 --- a/packages/twenty-server/src/engine/core-modules/view/dtos/inputs/update-view.input.ts +++ b/packages/twenty-server/src/engine/core-modules/view/dtos/inputs/update-view.input.ts @@ -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; +} diff --git a/packages/twenty-server/test/integration/graphql/suites/view/view-resolver.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/view/view-resolver.integration-spec.ts index c291b8a57ca..8168c47a04b 100644 --- a/packages/twenty-server/test/integration/graphql/suites/view/view-resolver.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/view/view-resolver.integration-spec.ts @@ -237,7 +237,6 @@ describe('View Resolver', () => { name: 'Updated View', type: ViewType.KANBAN, isCompact: true, - objectMetadataId: testObjectMetadataId, }); const operation = updateViewOperationFactory({ diff --git a/packages/twenty-ui/src/navigation/menu-item/internals/components/StyledMenuItemBase.tsx b/packages/twenty-ui/src/navigation/menu-item/internals/components/StyledMenuItemBase.tsx index 8c7547f6bd5..6ae784315a8 100644 --- a/packages/twenty-ui/src/navigation/menu-item/internals/components/StyledMenuItemBase.tsx +++ b/packages/twenty-ui/src/navigation/menu-item/internals/components/StyledMenuItemBase.tsx @@ -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; } } `};