Various fixes (#11448)
# Scrollbar fix Fixes https://github.com/twentyhq/twenty/issues/11403 <img width="1512" alt="image" src="https://github.com/user-attachments/assets/b13fe0f2-8c61-4ea8-9ea1-e61e571a90da" /> --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
@ -433,6 +433,17 @@ const HookMockWrapper = getJestMetadataAndApolloMocksWrapper({
|
||||
apolloMocks: mocks,
|
||||
});
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
...jest.requireActual('react-router-dom'),
|
||||
useLocation: jest.fn().mockReturnValue({
|
||||
pathname: '/',
|
||||
search: '',
|
||||
hash: '',
|
||||
state: null,
|
||||
key: 'default',
|
||||
}),
|
||||
}));
|
||||
|
||||
const Wrapper = ({ children }: { children: ReactNode }) => {
|
||||
return (
|
||||
<HookMockWrapper>
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
import { RecordIndexActionMenu } from '@/action-menu/components/RecordIndexActionMenu';
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
@ -7,7 +9,7 @@ import { PageHeader } from '@/ui/layout/page/components/PageHeader';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import styled from '@emotion/styled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||
import { useIcons } from 'twenty-ui/display';
|
||||
|
||||
const StyledTitleWithSelectedRecords = styled.div`
|
||||
@ -59,10 +61,19 @@ export const RecordIndexPageHeader = () => {
|
||||
label
|
||||
);
|
||||
|
||||
const contextStoreCurrentViewId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||
);
|
||||
|
||||
return (
|
||||
<PageHeader title={pageHeaderTitle} Icon={Icon}>
|
||||
<RecordIndexActionMenu indexId={recordIndexId} />
|
||||
<PageHeaderToggleCommandMenuButton />
|
||||
{isDefined(contextStoreCurrentViewId) && (
|
||||
<>
|
||||
<RecordIndexActionMenu indexId={recordIndexId} />
|
||||
<PageHeaderToggleCommandMenuButton />
|
||||
</>
|
||||
)}
|
||||
</PageHeader>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,15 +1,14 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords';
|
||||
import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams';
|
||||
import { useRecordTableRecordGqlFields } from '@/object-record/record-index/hooks/useRecordTableRecordGqlFields';
|
||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||
import { SIGN_IN_BACKGROUND_MOCK_COMPANIES } from '@/sign-in-background-mock/constants/SignInBackgroundMockCompanies';
|
||||
import { isWorkspaceActiveOrSuspended } from 'twenty-shared/workspace';
|
||||
import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal';
|
||||
|
||||
export const useLazyLoadRecordIndexTable = (objectNameSingular: string) => {
|
||||
const showAuthModal = useShowAuthModal();
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
@ -17,8 +16,6 @@ export const useLazyLoadRecordIndexTable = (objectNameSingular: string) => {
|
||||
const { setRecordTableData, setIsRecordTableInitialLoading } =
|
||||
useRecordTable();
|
||||
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
|
||||
const params = useFindManyRecordIndexTableParams(objectNameSingular);
|
||||
|
||||
const recordGqlFields = useRecordTableRecordGqlFields({ objectMetadataItem });
|
||||
@ -44,9 +41,7 @@ export const useLazyLoadRecordIndexTable = (objectNameSingular: string) => {
|
||||
|
||||
return {
|
||||
findManyRecords,
|
||||
records: isWorkspaceActiveOrSuspended(currentWorkspace)
|
||||
? records
|
||||
: SIGN_IN_BACKGROUND_MOCK_COMPANIES,
|
||||
records: !showAuthModal ? records : SIGN_IN_BACKGROUND_MOCK_COMPANIES,
|
||||
totalCount: totalCount,
|
||||
loading,
|
||||
fetchMoreRecords,
|
||||
|
||||
@ -2,25 +2,28 @@ import { useEffect, useState } from 'react';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId';
|
||||
import { useLazyLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLazyLoadRecordIndexTable';
|
||||
import { ROW_HEIGHT } from '@/object-record/record-table/constants/RowHeight';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||
import { hasRecordTableFetchedAllRecordsComponentStateV2 } from '@/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2';
|
||||
import { tableEncounteredUnrecoverableErrorComponentState } from '@/object-record/record-table/states/tableEncounteredUnrecoverableErrorComponentState';
|
||||
import { tableLastRowVisibleComponentState } from '@/object-record/record-table/states/tableLastRowVisibleComponentState';
|
||||
import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState';
|
||||
import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal';
|
||||
import { useScrollToPosition } from '@/ui/utilities/scroll/hooks/useScrollToPosition';
|
||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { isNonEmptyString, isNull } from '@sniptt/guards';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
export const RecordTableNoRecordGroupBodyEffect = () => {
|
||||
const { objectNameSingular } = useRecordTableContextOrThrow();
|
||||
|
||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||
const { setIsRecordTableInitialLoading } = useRecordTable();
|
||||
|
||||
const showAuthModal = useShowAuthModal();
|
||||
|
||||
const [hasInitializedScroll, setHasInitializedScroll] = useState(false);
|
||||
|
||||
@ -139,7 +142,8 @@ export const RecordTableNoRecordGroupBodyEffect = () => {
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isNull(currentWorkspaceMember)) {
|
||||
if (showAuthModal) {
|
||||
setIsRecordTableInitialLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -147,7 +151,12 @@ export const RecordTableNoRecordGroupBodyEffect = () => {
|
||||
findManyRecords();
|
||||
setHasInitialized(true);
|
||||
}
|
||||
}, [currentWorkspaceMember, findManyRecords, hasInitialized]);
|
||||
}, [
|
||||
findManyRecords,
|
||||
hasInitialized,
|
||||
setIsRecordTableInitialLoading,
|
||||
showAuthModal,
|
||||
]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
@ -1,21 +1,22 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId';
|
||||
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId';
|
||||
import { useLazyLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLazyLoadRecordIndexTable';
|
||||
import { recordIndexHasFetchedAllRecordsByGroupComponentState } from '@/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState';
|
||||
import { ROW_HEIGHT } from '@/object-record/record-table/constants/RowHeight';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
|
||||
import { useScrollToPosition } from '@/ui/utilities/scroll/hooks/useScrollToPosition';
|
||||
import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2';
|
||||
import { isNonEmptyString, isNull } from '@sniptt/guards';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { OnboardingStatus } from '~/generated-metadata/graphql';
|
||||
|
||||
export const RecordTableRecordGroupBodyEffect = () => {
|
||||
const { objectNameSingular } = useRecordTableContextOrThrow();
|
||||
|
||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||
const onboardingStatus = useOnboardingStatus();
|
||||
|
||||
const recordGroupId = useCurrentRecordGroupId();
|
||||
|
||||
@ -79,12 +80,12 @@ export const RecordTableRecordGroupBodyEffect = () => {
|
||||
}, [hasNextPage, setHasRecordFetchedAllRecordsComponents]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isNull(currentWorkspaceMember)) {
|
||||
if (onboardingStatus !== OnboardingStatus.COMPLETED) {
|
||||
return;
|
||||
}
|
||||
|
||||
findManyRecords();
|
||||
}, [currentWorkspaceMember, findManyRecords]);
|
||||
}, [onboardingStatus, findManyRecords]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
@ -2,7 +2,6 @@ import { ReactElement, useContext } from 'react';
|
||||
|
||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||
import { RecordTableCellBaseContainer } from '@/object-record/record-table/record-table-cell/components/RecordTableCellBaseContainer';
|
||||
import { RecordTableCellSoftFocusMode } from '@/object-record/record-table/record-table-cell/components/RecordTableCellSoftFocusMode';
|
||||
|
||||
import { RecordTableCellSoftFocusModeHotkeysSetterEffect } from '@/object-record/record-table/record-table-cell/components/RecordTableCellSoftFocusModeHotkeysSetterEffect';
|
||||
import { RecordTableCellDisplayMode } from './RecordTableCellDisplayMode';
|
||||
@ -27,19 +26,14 @@ export const RecordTableCellContainer = ({
|
||||
<RecordTableCellBaseContainer>
|
||||
{isInEditMode ? (
|
||||
<RecordTableCellEditMode>{editModeContent}</RecordTableCellEditMode>
|
||||
) : hasSoftFocus ? (
|
||||
<>
|
||||
<RecordTableCellSoftFocusModeHotkeysSetterEffect />
|
||||
<RecordTableCellSoftFocusMode
|
||||
editModeContent={editModeContent}
|
||||
nonEditModeContent={nonEditModeContent}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<RecordTableCellDisplayMode>
|
||||
{nonEditModeContent}
|
||||
</RecordTableCellDisplayMode>
|
||||
)}
|
||||
{hasSoftFocus ? (
|
||||
<RecordTableCellSoftFocusModeHotkeysSetterEffect />
|
||||
) : null}
|
||||
</RecordTableCellBaseContainer>
|
||||
);
|
||||
};
|
||||
|
||||
@ -41,11 +41,11 @@ export const RecordTableCellFieldContextWrapper = ({
|
||||
return (
|
||||
<RecordFieldComponentInstanceContext.Provider value={{ instanceId }}>
|
||||
{isLabelIdentifier ? (
|
||||
<RecordTableCellFieldContextLabelIdentifier>
|
||||
<RecordTableCellFieldContextLabelIdentifier key={instanceId}>
|
||||
{children}
|
||||
</RecordTableCellFieldContextLabelIdentifier>
|
||||
) : (
|
||||
<RecordTableCellFieldContextGeneric>
|
||||
<RecordTableCellFieldContextGeneric key={instanceId}>
|
||||
{children}
|
||||
</RecordTableCellFieldContextGeneric>
|
||||
)}
|
||||
|
||||
@ -1,117 +0,0 @@
|
||||
import { ReactElement, useContext, useEffect, useRef } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useGetButtonIcon } from '@/object-record/record-field/hooks/useGetButtonIcon';
|
||||
import { useIsFieldEmpty } from '@/object-record/record-field/hooks/useIsFieldEmpty';
|
||||
import { useIsFieldInputOnly } from '@/object-record/record-field/hooks/useIsFieldInputOnly';
|
||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||
import { RecordTableCellButton } from '@/object-record/record-table/record-table-cell/components/RecordTableCellButton';
|
||||
import { useOpenRecordTableCellFromCell } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellFromCell';
|
||||
import { isSoftFocusUsingMouseState } from '@/object-record/record-table/states/isSoftFocusUsingMouseState';
|
||||
|
||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||
import { useRecordTableBodyContextOrThrow } from '@/object-record/record-table/contexts/RecordTableBodyContext';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IconArrowUpRight } from 'twenty-ui/display';
|
||||
import { useIsMobile } from 'twenty-ui/utilities';
|
||||
import { RecordTableCellDisplayContainer } from './RecordTableCellDisplayContainer';
|
||||
|
||||
type RecordTableCellSoftFocusModeProps = {
|
||||
editModeContent: ReactElement;
|
||||
nonEditModeContent: ReactElement;
|
||||
};
|
||||
|
||||
export const RecordTableCellSoftFocusMode = ({
|
||||
editModeContent,
|
||||
nonEditModeContent,
|
||||
}: RecordTableCellSoftFocusModeProps) => {
|
||||
const { columnIndex, columnDefinition } = useContext(RecordTableCellContext);
|
||||
const { recordId, isReadOnly } = useContext(FieldContext);
|
||||
|
||||
const { onActionMenuDropdownOpened } = useRecordTableBodyContextOrThrow();
|
||||
|
||||
const { openTableCell } = useOpenRecordTableCellFromCell();
|
||||
|
||||
const editModeContentOnly = useIsFieldInputOnly();
|
||||
|
||||
const isFieldInputOnly = useIsFieldInputOnly();
|
||||
|
||||
const isEmpty = useIsFieldEmpty();
|
||||
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const isSoftFocusUsingMouse = useRecoilValue(isSoftFocusUsingMouseState);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isSoftFocusUsingMouse) {
|
||||
scrollRef.current?.scrollIntoView({ block: 'nearest' });
|
||||
}
|
||||
}, [isSoftFocusUsingMouse]);
|
||||
|
||||
const handleClick = () => {
|
||||
if (!isFieldInputOnly && !isReadOnly) {
|
||||
openTableCell();
|
||||
}
|
||||
};
|
||||
|
||||
const handleButtonClick = () => {
|
||||
if (!isFieldInputOnly && isFirstColumn) {
|
||||
openTableCell(undefined, false, true);
|
||||
} else {
|
||||
openTableCell();
|
||||
}
|
||||
/*
|
||||
Disabling sidepanel access for now, TODO: launch
|
||||
if (!isFieldInputOnly) {
|
||||
openTableCell(undefined, true);
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
const handleActionMenuDropdown = (event: React.MouseEvent) => {
|
||||
onActionMenuDropdownOpened(event, recordId);
|
||||
};
|
||||
|
||||
const isFirstColumn = columnIndex === 0;
|
||||
const customButtonIcon = useGetButtonIcon();
|
||||
const buttonIcon = isFirstColumn
|
||||
? IconArrowUpRight // IconLayoutSidebarRightExpand - Disabling sidepanel access for now
|
||||
: customButtonIcon;
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
const showButton =
|
||||
isDefined(buttonIcon) &&
|
||||
!editModeContentOnly &&
|
||||
!isReadOnly &&
|
||||
!(isMobile && isFirstColumn);
|
||||
|
||||
const dontShowContent = isEmpty && isReadOnly;
|
||||
|
||||
const showPlaceholder =
|
||||
!editModeContentOnly && !isReadOnly && isFirstColumn && isEmpty;
|
||||
|
||||
return (
|
||||
<>
|
||||
<RecordTableCellDisplayContainer
|
||||
onClick={handleClick}
|
||||
scrollRef={scrollRef}
|
||||
softFocus
|
||||
onContextMenu={handleActionMenuDropdown}
|
||||
placeholderForEmptyCell={
|
||||
showPlaceholder ? columnDefinition.label : undefined
|
||||
}
|
||||
>
|
||||
{dontShowContent ? (
|
||||
<></>
|
||||
) : editModeContentOnly ? (
|
||||
editModeContent
|
||||
) : (
|
||||
nonEditModeContent
|
||||
)}
|
||||
</RecordTableCellDisplayContainer>
|
||||
{showButton && (
|
||||
<RecordTableCellButton onClick={handleButtonClick} Icon={buttonIcon} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user