mirror of
https://github.com/twentyhq/twenty
synced 2026-04-21 13:37:22 +00:00
Fix deactivated tabs not visible in new tab action (#19811)
## Context On custom objects, clicking "+ New Tab" on a record page layout never exposed deactivated tabs for reactivation, even though isActive: false tabs were correctly returned by the API. Standard objects worked fine. ## Fix isReactivatableTab gated reactivation on tab.applicationId === objectMetadata.applicationId. For custom objects these two ids are intentionally different. This check was unnecessary after all, we simply want to check if a tab is inactive (only non-custom entities can be de-activated) 👍 <img width="694" height="551" alt="Screenshot 2026-04-17 at 18 14 28" src="https://github.com/user-attachments/assets/42485cb2-8be5-4a55-a311-479ed3226908" />
This commit is contained in:
parent
6095798434
commit
a18840f3cd
5 changed files with 10 additions and 73 deletions
|
|
@ -1,7 +1,6 @@
|
|||
import { STANDARD_PAGE_LAYOUT_TAB_TITLE_TRANSLATIONS } from '@/page-layout/constants/StandardPageLayoutTabTitleTranslations';
|
||||
import { useCurrentPageLayoutOrThrow } from '@/page-layout/hooks/useCurrentPageLayoutOrThrow';
|
||||
import { useIsCurrentObjectCustom } from '@/page-layout/hooks/useIsCurrentObjectCustom';
|
||||
import { useRecordPageLayoutObjectApplicationId } from '@/page-layout/hooks/useRecordPageLayoutObjectApplicationId';
|
||||
import { useUpdatePageLayoutTab } from '@/page-layout/hooks/useUpdatePageLayoutTab';
|
||||
import { pageLayoutTabSettingsOpenTabIdComponentState } from '@/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState';
|
||||
import { isReactivatableTab } from '@/page-layout/utils/isReactivatableTab';
|
||||
|
|
@ -39,7 +38,6 @@ export const PageLayoutTabListNewTabDropdownContent = ({
|
|||
const shouldTranslateTabTitles = !isCustom;
|
||||
|
||||
const { currentPageLayout } = useCurrentPageLayoutOrThrow();
|
||||
const { objectApplicationId } = useRecordPageLayoutObjectApplicationId();
|
||||
const { updatePageLayoutTab } = useUpdatePageLayoutTab();
|
||||
|
||||
const setActiveTabId = useSetAtomComponentState(activeTabIdComponentState);
|
||||
|
|
@ -49,13 +47,8 @@ export const PageLayoutTabListNewTabDropdownContent = ({
|
|||
const { navigatePageLayoutSidePanel } = useNavigatePageLayoutSidePanel();
|
||||
|
||||
const inactiveTabs = useMemo(
|
||||
() =>
|
||||
sortTabsByPosition(
|
||||
currentPageLayout.tabs.filter((tab) =>
|
||||
isReactivatableTab({ tab, objectApplicationId }),
|
||||
),
|
||||
),
|
||||
[currentPageLayout.tabs, objectApplicationId],
|
||||
() => sortTabsByPosition(currentPageLayout.tabs.filter(isReactivatableTab)),
|
||||
[currentPageLayout.tabs],
|
||||
);
|
||||
|
||||
const handleCreateEmptyTab = useCallback(() => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { useCreatePageLayoutTab } from '@/page-layout/hooks/useCreatePageLayoutTab';
|
||||
import { useCurrentPageLayoutOrThrow } from '@/page-layout/hooks/useCurrentPageLayoutOrThrow';
|
||||
import { useIsPageLayoutInEditMode } from '@/page-layout/hooks/useIsPageLayoutInEditMode';
|
||||
import { useRecordPageLayoutObjectApplicationId } from '@/page-layout/hooks/useRecordPageLayoutObjectApplicationId';
|
||||
import { pageLayoutTabSettingsOpenTabIdComponentState } from '@/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState';
|
||||
import { type PageLayoutAddTabStrategy } from '@/page-layout/types/PageLayoutAddTabStrategy';
|
||||
import { isReactivatableTab } from '@/page-layout/utils/isReactivatableTab';
|
||||
|
|
@ -25,7 +24,6 @@ export const usePageLayoutAddTabStrategy = ({
|
|||
}): PageLayoutAddTabStrategy | undefined => {
|
||||
const { currentPageLayout } = useCurrentPageLayoutOrThrow();
|
||||
const isPageLayoutInEditMode = useIsPageLayoutInEditMode();
|
||||
const { objectApplicationId } = useRecordPageLayoutObjectApplicationId();
|
||||
|
||||
const isRecordPageGlobalEditionEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED,
|
||||
|
|
@ -77,9 +75,7 @@ export const usePageLayoutAddTabStrategy = ({
|
|||
return undefined;
|
||||
}
|
||||
|
||||
const hasInactiveTabs = currentPageLayout.tabs.some((tab) =>
|
||||
isReactivatableTab({ tab, objectApplicationId }),
|
||||
);
|
||||
const hasInactiveTabs = currentPageLayout.tabs.some(isReactivatableTab);
|
||||
|
||||
const mode =
|
||||
currentPageLayout.type === PageLayoutType.RECORD_PAGE && hasInactiveTabs
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
import { objectMetadataItemsSelector } from '@/object-metadata/states/objectMetadataItemsSelector';
|
||||
import { useCurrentPageLayoutOrThrow } from '@/page-layout/hooks/useCurrentPageLayoutOrThrow';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useRecordPageLayoutObjectApplicationId = (): {
|
||||
objectApplicationId: string | undefined;
|
||||
} => {
|
||||
const { currentPageLayout } = useCurrentPageLayoutOrThrow();
|
||||
const objectMetadataItems = useAtomStateValue(objectMetadataItemsSelector);
|
||||
|
||||
const objectMetadataId = currentPageLayout.objectMetadataId;
|
||||
|
||||
if (!isDefined(objectMetadataId)) {
|
||||
return { objectApplicationId: undefined };
|
||||
}
|
||||
|
||||
const objectMetadataItem = objectMetadataItems.find(
|
||||
(item) => item.id === objectMetadataId,
|
||||
);
|
||||
|
||||
return {
|
||||
objectApplicationId: objectMetadataItem?.applicationId,
|
||||
};
|
||||
};
|
||||
|
|
@ -17,35 +17,15 @@ const makeTab = (overrides: Partial<PageLayoutTab> = {}): PageLayoutTab =>
|
|||
}) as unknown as PageLayoutTab;
|
||||
|
||||
describe('isReactivatableTab', () => {
|
||||
it('should return true when tab is inactive and applicationId matches', () => {
|
||||
const tab = makeTab({ isActive: false, applicationId: 'app-1' });
|
||||
it('should return true when tab is inactive', () => {
|
||||
const tab = makeTab({ isActive: false });
|
||||
|
||||
expect(isReactivatableTab({ tab, objectApplicationId: 'app-1' })).toBe(
|
||||
true,
|
||||
);
|
||||
expect(isReactivatableTab(tab)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when tab is active', () => {
|
||||
const tab = makeTab({ isActive: true, applicationId: 'app-1' });
|
||||
const tab = makeTab({ isActive: true });
|
||||
|
||||
expect(isReactivatableTab({ tab, objectApplicationId: 'app-1' })).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
it('should return false when applicationId does not match', () => {
|
||||
const tab = makeTab({ isActive: false, applicationId: 'app-1' });
|
||||
|
||||
expect(isReactivatableTab({ tab, objectApplicationId: 'app-2' })).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
it('should return false when objectApplicationId is undefined', () => {
|
||||
const tab = makeTab({ isActive: false, applicationId: 'app-1' });
|
||||
|
||||
expect(isReactivatableTab({ tab, objectApplicationId: undefined })).toBe(
|
||||
false,
|
||||
);
|
||||
expect(isReactivatableTab(tab)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,11 +1,4 @@
|
|||
import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab';
|
||||
|
||||
export const isReactivatableTab = ({
|
||||
tab,
|
||||
objectApplicationId,
|
||||
}: {
|
||||
tab: PageLayoutTab;
|
||||
objectApplicationId: string | undefined;
|
||||
}): boolean => {
|
||||
return !tab.isActive && tab.applicationId === objectApplicationId;
|
||||
};
|
||||
export const isReactivatableTab = (tab: PageLayoutTab): boolean =>
|
||||
!tab.isActive;
|
||||
|
|
|
|||
Loading…
Reference in a new issue