diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuItemsContainer.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuItemsContainer.tsx
index b0f4ac40e..0eeeebfff 100644
--- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuItemsContainer.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuItemsContainer.tsx
@@ -45,11 +45,17 @@ export const DropdownMenuItemsContainer = ({
}) => {
return (
-
+ {hasMaxHeight ? (
+
+
+ {children}
+
+
+ ) : (
{children}
-
+ )}
);
};
diff --git a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerCreateOrEditContent.tsx b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerCreateOrEditContent.tsx
index 8d6ca8bff..127e64400 100644
--- a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerCreateOrEditContent.tsx
+++ b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerCreateOrEditContent.tsx
@@ -1,5 +1,5 @@
import styled from '@emotion/styled';
-import { useRecoilState, useRecoilValue } from 'recoil';
+import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import { Key } from 'ts-key-enum';
import { IconChevronLeft, IconLayoutKanban, IconTable, IconX } from 'twenty-ui';
@@ -57,6 +57,7 @@ export const ViewPickerCreateOrEditContent = () => {
viewPickerIsPersistingState,
viewPickerKanbanFieldMetadataIdState,
viewPickerTypeState,
+ viewPickerIsDirtyState,
} = useViewPickerStates();
const [viewPickerInputName, setViewPickerInputName] = useRecoilState(
@@ -66,6 +67,7 @@ export const ViewPickerCreateOrEditContent = () => {
viewPickerSelectedIconState,
);
const viewPickerIsPersisting = useRecoilValue(viewPickerIsPersistingState);
+ const setViewPickerIsDirty = useSetRecoilState(viewPickerIsDirtyState);
const [viewPickerKanbanFieldMetadataId, setViewPickerKanbanFieldMetadataId] =
useRecoilState(viewPickerKanbanFieldMetadataIdState);
@@ -80,16 +82,13 @@ export const ViewPickerCreateOrEditContent = () => {
useScopedHotkeys(
Key.Enter,
async () => {
+ if (viewPickerIsPersisting) {
+ return;
+ }
if (viewPickerMode === 'create') {
- if (viewPickerIsPersisting) {
- return;
- }
await handleCreate();
}
if (viewPickerMode === 'edit') {
- if (viewPickerIsPersisting) {
- return;
- }
await handleUpdate();
}
},
@@ -97,6 +96,7 @@ export const ViewPickerCreateOrEditContent = () => {
);
const onIconChange = ({ iconKey }: { iconKey: string }) => {
+ setViewPickerIsDirty(true);
setViewPickerSelectedIcon(iconKey);
};
@@ -128,7 +128,10 @@ export const ViewPickerCreateOrEditContent = () => {
/>
setViewPickerInputName(event.target.value)}
+ onChange={(event) => {
+ setViewPickerIsDirty(true);
+ setViewPickerInputName(event.target.value);
+ }}
autoFocus
/>
@@ -139,7 +142,10 @@ export const ViewPickerCreateOrEditContent = () => {
label="View type"
fullWidth
value={viewPickerType}
- onChange={(value) => setViewPickerType(value)}
+ onChange={(value) => {
+ setViewPickerIsDirty(true);
+ setViewPickerType(value);
+ }}
options={[
{ value: ViewType.Table, label: 'Table', Icon: IconTable },
{
diff --git a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerCreateOrEditContentEffect.tsx b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerCreateOrEditContentEffect.tsx
index d60ecd153..45c143222 100644
--- a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerCreateOrEditContentEffect.tsx
+++ b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerCreateOrEditContentEffect.tsx
@@ -14,6 +14,7 @@ export const ViewPickerCreateOrEditContentEffect = () => {
viewPickerIsPersistingState,
viewPickerKanbanFieldMetadataIdState,
viewPickerTypeState,
+ viewPickerIsDirtyState,
} = useViewPickerStates();
const setViewPickerSelectedIcon = useSetRecoilState(
@@ -30,6 +31,8 @@ export const ViewPickerCreateOrEditContentEffect = () => {
viewPickerReferenceViewIdState,
);
+ const viewPickerIsDirty = useRecoilValue(viewPickerIsDirtyState);
+
const viewPickerIsPersisting = useRecoilValue(viewPickerIsPersistingState);
const { viewsOnCurrentObject } = useGetCurrentView();
@@ -40,7 +43,11 @@ export const ViewPickerCreateOrEditContentEffect = () => {
const { availableFieldsForKanban } = useGetAvailableFieldsForKanban();
useEffect(() => {
- if (isDefined(referenceView) && !viewPickerIsPersisting) {
+ if (
+ isDefined(referenceView) &&
+ !viewPickerIsPersisting &&
+ !viewPickerIsDirty
+ ) {
setViewPickerSelectedIcon(referenceView.icon);
setViewPickerInputName(referenceView.name);
setViewPickerKanbanFieldMetadataId(referenceView.kanbanFieldMetadataId);
@@ -53,6 +60,7 @@ export const ViewPickerCreateOrEditContentEffect = () => {
setViewPickerSelectedIcon,
setViewPickerType,
viewPickerIsPersisting,
+ viewPickerIsDirty,
]);
useEffect(() => {
diff --git a/packages/twenty-front/src/modules/views/view-picker/hooks/useViewPickerPersistView.ts b/packages/twenty-front/src/modules/views/view-picker/hooks/useViewPickerPersistView.ts
index 42ef7c2db..ba9c00398 100644
--- a/packages/twenty-front/src/modules/views/view-picker/hooks/useViewPickerPersistView.ts
+++ b/packages/twenty-front/src/modules/views/view-picker/hooks/useViewPickerPersistView.ts
@@ -15,6 +15,7 @@ export const useViewPickerPersistView = () => {
viewPickerReferenceViewIdState,
viewPickerKanbanFieldMetadataIdState,
viewPickerTypeState,
+ viewPickerIsDirtyState,
} = useViewPickerStates();
const { createView, selectView, removeView, updateView } = useHandleViews();
@@ -35,6 +36,7 @@ export const useViewPickerPersistView = () => {
);
const id = v4();
set(viewPickerIsPersistingState, true);
+ set(viewPickerIsDirtyState, false);
await createView({
id,
name,
@@ -50,6 +52,7 @@ export const useViewPickerPersistView = () => {
createView,
selectView,
viewPickerInputNameState,
+ viewPickerIsDirtyState,
viewPickerIsPersistingState,
viewPickerKanbanFieldMetadataIdState,
viewPickerSelectedIconState,
@@ -62,6 +65,7 @@ export const useViewPickerPersistView = () => {
async () => {
set(viewPickerIsPersistingState, true);
closeAndResetViewPicker();
+ set(viewPickerIsDirtyState, false);
const viewPickerReferenceViewId = getSnapshotValue(
snapshot,
viewPickerReferenceViewIdState,
@@ -78,6 +82,7 @@ export const useViewPickerPersistView = () => {
closeAndResetViewPicker,
removeView,
selectView,
+ viewPickerIsDirtyState,
viewPickerIsPersistingState,
viewPickerReferenceViewIdState,
viewsOnCurrentObject,
@@ -88,6 +93,7 @@ export const useViewPickerPersistView = () => {
({ set, snapshot }) =>
async () => {
set(viewPickerIsPersistingState, true);
+ set(viewPickerIsDirtyState, false);
closeAndResetViewPicker();
const viewPickerReferenceViewId = getSnapshotValue(
@@ -112,12 +118,13 @@ export const useViewPickerPersistView = () => {
},
[
viewPickerIsPersistingState,
+ viewPickerIsDirtyState,
+ closeAndResetViewPicker,
viewPickerReferenceViewIdState,
viewPickerInputNameState,
viewPickerSelectedIconState,
updateView,
selectView,
- closeAndResetViewPicker,
],
);
diff --git a/packages/twenty-front/src/modules/views/view-picker/hooks/useViewPickerStates.ts b/packages/twenty-front/src/modules/views/view-picker/hooks/useViewPickerStates.ts
index a95274d41..58bfd987c 100644
--- a/packages/twenty-front/src/modules/views/view-picker/hooks/useViewPickerStates.ts
+++ b/packages/twenty-front/src/modules/views/view-picker/hooks/useViewPickerStates.ts
@@ -1,6 +1,7 @@
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
import { viewPickerInputNameComponentState } from '@/views/view-picker/states/viewPickerInputNameComponentState';
+import { viewPickerIsDirtyComponentState } from '@/views/view-picker/states/viewPickerIsDirtyComponentState';
import { viewPickerIsPersistingComponentState } from '@/views/view-picker/states/viewPickerIsPersistingComponentState';
import { viewPickerKanbanFieldMetadataIdComponentState } from '@/views/view-picker/states/viewPickerKanbanFieldMetadataIdComponentState';
import { viewPickerModeComponentState } from '@/views/view-picker/states/viewPickerModeComponentState';
@@ -46,5 +47,9 @@ export const useViewPickerStates = (viewComponentId?: string) => {
viewPickerTypeComponentState,
componentId,
),
+ viewPickerIsDirtyState: extractComponentState(
+ viewPickerIsDirtyComponentState,
+ componentId,
+ ),
};
};
diff --git a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerIsDirtyComponentState.ts b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerIsDirtyComponentState.ts
new file mode 100644
index 000000000..a732ae062
--- /dev/null
+++ b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerIsDirtyComponentState.ts
@@ -0,0 +1,6 @@
+import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
+
+export const viewPickerIsDirtyComponentState = createComponentState({
+ key: 'viewPickerIsDirtyComponentState',
+ defaultValue: false,
+});