Prefetch Skeleton Loading on Indexes and Shows (#5545)

### Description
Prefetch Skeleton Loading on Indexes and Shows

### Refs
#4458

### Demo

https://jam.dev/c/a1ad04e1-80b6-4b2a-b7df-373f52f4b169

https://jam.dev/c/c5038b97-2f18-4c29-8dee-18c09376e5ee

Fixes: #4458

---------

Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com>
Co-authored-by: v1b3m <vibenjamin6@gmail.com>
Co-authored-by: Matheus <matheus_benini@hotmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
gitstart-twenty
2024-05-27 15:56:08 +08:00
committed by GitHub
parent cfd83d6b8e
commit 9c046dcfdb
60 changed files with 490 additions and 161 deletions

View File

@ -1,9 +1,8 @@
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { TimelineCreateButtonGroup } from '@/activities/timeline/components/TimelineCreateButtonGroup'; import { TimelineCreateButtonGroup } from '@/activities/timeline/components/TimelineCreateButtonGroup';
import { TimelineSkeletonLoader } from '@/activities/timeline/components/TimelineSkeletonLoader';
import { timelineActivitiesForGroupState } from '@/activities/timeline/states/timelineActivitiesForGroupState'; import { timelineActivitiesForGroupState } from '@/activities/timeline/states/timelineActivitiesForGroupState';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import AnimatedPlaceholder from '@/ui/layout/animated-placeholder/components/AnimatedPlaceholder'; import AnimatedPlaceholder from '@/ui/layout/animated-placeholder/components/AnimatedPlaceholder';
@ -29,82 +28,19 @@ const StyledMainContainer = styled.div`
justify-content: center; justify-content: center;
`; `;
const StyledSkeletonContainer = styled.div`
align-items: center;
width: 100%;
padding: ${({ theme }) => theme.spacing(8)};
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(4)};
flex-wrap: wrap;
align-content: flex-start;
`;
const StyledSkeletonSubSection = styled.div`
display: flex;
gap: ${({ theme }) => theme.spacing(4)};
`;
const StyledSkeletonColumn = styled.div`
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(3)};
justify-content: center;
`;
const StyledSkeletonLoader = () => {
const theme = useTheme();
return (
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
borderRadius={80}
>
<Skeleton width={24} height={84} />
</SkeletonTheme>
);
};
const StyledTimelineSkeletonLoader = () => {
const theme = useTheme();
const skeletonItems = Array.from({ length: 3 }).map((_, index) => ({
id: `skeleton-item-${index}`,
}));
return (
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
borderRadius={4}
>
<StyledSkeletonContainer>
<Skeleton width={440} height={16} />
{skeletonItems.map(({ id }) => (
<StyledSkeletonSubSection key={id}>
<StyledSkeletonLoader />
<StyledSkeletonColumn>
<Skeleton width={400} height={24} />
<Skeleton width={400} height={24} />
</StyledSkeletonColumn>
</StyledSkeletonSubSection>
))}
</StyledSkeletonContainer>
</SkeletonTheme>
);
};
export const Timeline = ({ export const Timeline = ({
targetableObject, targetableObject,
loading, loading,
}: { }: {
targetableObject: ActivityTargetableObject; targetableObject: ActivityTargetableObject;
loading?: boolean; loading: boolean;
}) => { }) => {
const timelineActivitiesForGroup = useRecoilValue( const timelineActivitiesForGroup = useRecoilValue(
timelineActivitiesForGroupState, timelineActivitiesForGroupState,
); );
if (loading === true) { if (loading) {
return <StyledTimelineSkeletonLoader />; return <TimelineSkeletonLoader />;
} }
if (timelineActivitiesForGroup.length === 0) { if (timelineActivitiesForGroup.length === 0) {

View File

@ -0,0 +1,72 @@
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
const StyledSkeletonContainer = styled.div`
align-items: center;
width: 100%;
padding: ${({ theme }) => theme.spacing(8)};
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(4)};
flex-wrap: wrap;
align-content: flex-start;
`;
const StyledSkeletonSubSection = styled.div`
display: flex;
gap: ${({ theme }) => theme.spacing(4)};
`;
const StyledSkeletonColumn = styled.div`
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(3)};
justify-content: center;
`;
const StyledSkeletonLoader = ({
isSecondColumn,
}: {
isSecondColumn: boolean;
}) => {
const theme = useTheme();
return (
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
borderRadius={80}
>
<Skeleton width={24} height={isSecondColumn ? 120 : 84} />
</SkeletonTheme>
);
};
export const TimelineSkeletonLoader = () => {
const theme = useTheme();
const skeletonItems = Array.from({ length: 3 }).map((_, index) => ({
id: `skeleton-item-${index}`,
}));
return (
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
borderRadius={4}
>
<StyledSkeletonContainer>
<Skeleton width={440} height={16} />
{skeletonItems.map(({ id }, index) => (
<StyledSkeletonSubSection key={id}>
<StyledSkeletonLoader isSecondColumn={index === 1} />
<StyledSkeletonColumn>
<Skeleton width={400} height={24} />
<Skeleton width={400} height={24} />
{index === 1 && <Skeleton width={400} height={24} />}
</StyledSkeletonColumn>
</StyledSkeletonSubSection>
))}
</StyledSkeletonContainer>
</SkeletonTheme>
);
};

View File

@ -1,6 +1,8 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { Avatar } from 'twenty-ui'; import { Avatar } from 'twenty-ui';
import { FavoritesSkeletonLoader } from '@/favorites/components/FavoritesSkeletonLoader';
import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading';
import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem'; import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem';
import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList'; import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList';
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem'; import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
@ -32,6 +34,11 @@ const StyledNavigationDrawerItem = styled(NavigationDrawerItem)`
export const Favorites = () => { export const Favorites = () => {
const { favorites, handleReorderFavorite } = useFavorites(); const { favorites, handleReorderFavorite } = useFavorites();
const loading = useIsPrefetchLoading();
if (loading) {
return <FavoritesSkeletonLoader />;
}
if (!favorites || favorites.length === 0) return <></>; if (!favorites || favorites.length === 0) return <></>;

View File

@ -0,0 +1,36 @@
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
const StyledSkeletonContainer = styled.div`
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(2)};
height: 71px;
padding-left: ${({ theme }) => theme.spacing(1)};
`;
const StyledSkeletonColumn = styled.div`
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(1)};
`;
export const FavoritesSkeletonLoader = () => {
const theme = useTheme();
return (
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
borderRadius={4}
>
<StyledSkeletonContainer>
<Skeleton width={56} height={13} />
<StyledSkeletonColumn>
<Skeleton width={196} height={16} />
<Skeleton width={196} height={16} />
</StyledSkeletonColumn>
</StyledSkeletonContainer>
</SkeletonTheme>
);
};

View File

@ -1,7 +1,9 @@
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { useIcons } from 'twenty-ui'; import { useIcons } from 'twenty-ui';
import { ObjectMetadataNavItemsSkeletonLoader } from '@/object-metadata/components/ObjectMetadataNavItemsSkeletonLoader';
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading';
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData'; import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
import { PrefetchKey } from '@/prefetch/types/PrefetchKey'; import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem'; import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
@ -14,6 +16,11 @@ export const ObjectMetadataNavItems = () => {
const currentPath = useLocation().pathname; const currentPath = useLocation().pathname;
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews); const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
const loading = useIsPrefetchLoading();
if (loading) {
return <ObjectMetadataNavItemsSkeletonLoader />;
}
return ( return (
<> <>

View File

@ -0,0 +1,28 @@
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
const StyledSkeletonColumn = styled.div`
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(1)};
height: 76px;
padding-left: ${({ theme }) => theme.spacing(1)};
`;
export const ObjectMetadataNavItemsSkeletonLoader: React.FC = () => {
const theme = useTheme();
return (
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.light}
borderRadius={4}
>
<StyledSkeletonColumn>
<Skeleton width={196} height={16} />
<Skeleton width={196} height={16} />
<Skeleton width={196} height={16} />
</StyledSkeletonColumn>
</SkeletonTheme>
);
};

View File

@ -6,6 +6,7 @@ import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/Componen
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator'; import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator'; import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
@ -20,6 +21,7 @@ const meta: Meta<typeof ObjectMetadataNavItems> = {
ComponentWithRouterDecorator, ComponentWithRouterDecorator,
ComponentWithRecoilScopeDecorator, ComponentWithRecoilScopeDecorator,
SnackBarDecorator, SnackBarDecorator,
PrefetchLoadingDecorator,
], ],
parameters: { parameters: {
msw: graphqlMocks, msw: graphqlMocks,

View File

@ -0,0 +1,31 @@
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
const StyledSkeletonDiv = styled.div`
align-items: center;
display: flex;
gap: ${({ theme }) => theme.spacing(1)};
width: 100%;
height: 24px;
`;
export const PropertyBoxSkeletonLoader = () => {
const theme = useTheme();
const skeletonItems = Array.from({ length: 4 }).map((_, index) => ({
id: `skeleton-item-${index}`,
}));
return (
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
borderRadius={4}
>
{skeletonItems.map(({ id }) => (
<StyledSkeletonDiv key={id}>
<Skeleton width={92} height={16} />
<Skeleton width={154} height={16} />
</StyledSkeletonDiv>
))}
</SkeletonTheme>
);
};

View File

@ -12,6 +12,7 @@ import {
} from '@/object-record/record-field/contexts/FieldContext'; } from '@/object-record/record-field/contexts/FieldContext';
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell'; import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox'; import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox';
import { PropertyBoxSkeletonLoader } from '@/object-record/record-inline-cell/property-box/components/PropertyBoxSkeletonLoader';
import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope'; import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope';
import { RecordDetailDuplicatesSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailDuplicatesSection'; import { RecordDetailDuplicatesSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailDuplicatesSection';
import { RecordDetailRelationSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationSection'; import { RecordDetailRelationSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationSection';
@ -19,6 +20,7 @@ import { recordLoadingFamilyState } from '@/object-record/record-store/states/re
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { recordStoreIdentifierFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreIdentifierSelector'; import { recordStoreIdentifierFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreIdentifierSelector';
import { isFieldCellSupported } from '@/object-record/utils/isFieldCellSupported'; import { isFieldCellSupported } from '@/object-record/utils/isFieldCellSupported';
import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading';
import { ShowPageContainer } from '@/ui/layout/page/ShowPageContainer'; import { ShowPageContainer } from '@/ui/layout/page/ShowPageContainer';
import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer'; import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer';
import { ShowPageRightContainer } from '@/ui/layout/show-page/components/ShowPageRightContainer'; import { ShowPageRightContainer } from '@/ui/layout/show-page/components/ShowPageRightContainer';
@ -127,6 +129,7 @@ export const RecordShowContainer = ({
); );
const isReadOnly = objectMetadataItem.isRemote; const isReadOnly = objectMetadataItem.isRemote;
const isPrefetchLoading = useIsPrefetchLoading();
return ( return (
<RecoilScope CustomRecoilScopeContext={ShowPageRecoilScopeContext}> <RecoilScope CustomRecoilScopeContext={ShowPageRecoilScopeContext}>
@ -139,7 +142,7 @@ export const RecordShowContainer = ({
logoOrAvatar={recordIdentifier?.avatarUrl ?? ''} logoOrAvatar={recordIdentifier?.avatarUrl ?? ''}
avatarPlaceholder={recordIdentifier?.name ?? ''} avatarPlaceholder={recordIdentifier?.name ?? ''}
date={recordFromStore.createdAt ?? ''} date={recordFromStore.createdAt ?? ''}
loading={loading || recordLoading} loading={isPrefetchLoading || loading || recordLoading}
title={ title={
<FieldContext.Provider <FieldContext.Provider
value={{ value={{
@ -176,32 +179,36 @@ export const RecordShowContainer = ({
} }
/> />
<PropertyBox> <PropertyBox>
{inlineFieldMetadataItems.map((fieldMetadataItem, index) => ( {isPrefetchLoading ? (
<FieldContext.Provider <PropertyBoxSkeletonLoader />
key={objectRecordId + fieldMetadataItem.id} ) : (
value={{ inlineFieldMetadataItems.map((fieldMetadataItem, index) => (
entityId: objectRecordId, <FieldContext.Provider
maxWidth: 200, key={objectRecordId + fieldMetadataItem.id}
recoilScopeId: objectRecordId + fieldMetadataItem.id, value={{
isLabelIdentifier: false, entityId: objectRecordId,
fieldDefinition: maxWidth: 200,
formatFieldMetadataItemAsColumnDefinition({ recoilScopeId: objectRecordId + fieldMetadataItem.id,
field: fieldMetadataItem, isLabelIdentifier: false,
position: index, fieldDefinition:
objectMetadataItem, formatFieldMetadataItemAsColumnDefinition({
showLabel: true, field: fieldMetadataItem,
labelWidth: 90, position: index,
}), objectMetadataItem,
useUpdateRecord: useUpdateOneObjectRecordMutation, showLabel: true,
hotkeyScope: InlineCellHotkeyScope.InlineCell, labelWidth: 90,
}} }),
> useUpdateRecord: useUpdateOneObjectRecordMutation,
<RecordInlineCell hotkeyScope: InlineCellHotkeyScope.InlineCell,
loading={loading || recordLoading} }}
readonly={isReadOnly} >
/> <RecordInlineCell
</FieldContext.Provider> loading={loading || recordLoading}
))} readonly={isReadOnly}
/>
</FieldContext.Provider>
))
)}
</PropertyBox> </PropertyBox>
<RecordDetailDuplicatesSection <RecordDetailDuplicatesSection
objectRecordId={objectRecordId} objectRecordId={objectRecordId}
@ -224,7 +231,7 @@ export const RecordShowContainer = ({
}} }}
> >
<RecordDetailRelationSection <RecordDetailRelationSection
loading={loading || recordLoading} loading={isPrefetchLoading || loading || recordLoading}
/> />
</FieldContext.Provider> </FieldContext.Provider>
))} ))}
@ -241,7 +248,7 @@ export const RecordShowContainer = ({
tasks tasks
notes notes
emails emails
loading={loading || recordLoading} loading={isPrefetchLoading || loading || recordLoading}
/> />
) : ( ) : (
<></> <></>

View File

@ -1,6 +1,4 @@
import { useCallback, useContext } from 'react'; import { useCallback, useContext } from 'react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import qs from 'qs'; import qs from 'qs';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
@ -13,6 +11,7 @@ import { usePersistField } from '@/object-record/record-field/hooks/usePersistFi
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { RecordDetailRelationRecordsList } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsList'; import { RecordDetailRelationRecordsList } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsList';
import { RecordDetailRelationRecordsListEmptyState } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListEmptyState'; import { RecordDetailRelationRecordsListEmptyState } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListEmptyState';
import { RecordDetailRelationSectionSkeletonLoader } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationSectionSkeletonLoader';
import { RecordDetailSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailSection'; import { RecordDetailSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailSection';
import { RecordDetailSectionHeader } from '@/object-record/record-show/record-detail-section/components/RecordDetailSectionHeader'; import { RecordDetailSectionHeader } from '@/object-record/record-show/record-detail-section/components/RecordDetailSectionHeader';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
@ -37,25 +36,6 @@ const StyledAddDropdown = styled(Dropdown)`
margin-left: auto; margin-left: auto;
`; `;
const StyledSkeletonDiv = styled.div`
height: 40px;
`;
const StyledRecordDetailRelationSectionSkeletonLoader = () => {
const theme = useTheme();
return (
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
borderRadius={4}
>
<StyledSkeletonDiv>
<Skeleton width={129} height={16} />
</StyledSkeletonDiv>
</SkeletonTheme>
);
};
export const RecordDetailRelationSection = ({ export const RecordDetailRelationSection = ({
loading, loading,
}: RecordDetailRelationSectionProps) => { }: RecordDetailRelationSectionProps) => {
@ -142,7 +122,11 @@ export const RecordDetailRelationSection = ({
const showContent = () => { const showContent = () => {
if (loading) { if (loading) {
return <StyledRecordDetailRelationSectionSkeletonLoader />; return (
<RecordDetailRelationSectionSkeletonLoader
numSkeletons={fieldName === 'people' ? 2 : 1}
/>
);
} }
return relationRecords.length ? ( return relationRecords.length ? (

View File

@ -0,0 +1,31 @@
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
const StyledSkeletonDiv = styled.div`
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(4)};
height: 40px;
`;
export const RecordDetailRelationSectionSkeletonLoader = ({
numSkeletons = 1,
}: {
numSkeletons?: number;
}) => {
const theme = useTheme();
return (
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
borderRadius={4}
>
<StyledSkeletonDiv>
{Array.from({ length: numSkeletons }).map((_, index) => (
<Skeleton key={index} width={129} height={16} />
))}
</StyledSkeletonDiv>
</SkeletonTheme>
);
};

View File

@ -0,0 +1,14 @@
import { useRecoilValue } from 'recoil';
import { prefetchIsLoadedFamilyState } from '@/prefetch/states/prefetchIsLoadedFamilyState';
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
export const useIsPrefetchLoading = () => {
const areViewsPrefetched = useRecoilValue(
prefetchIsLoadedFamilyState(PrefetchKey.AllViews),
);
const areFavoritesPrefetched = useRecoilValue(
prefetchIsLoadedFamilyState(PrefetchKey.AllFavorites),
);
return !areViewsPrefetched || !areFavoritesPrefetched;
};

View File

@ -7,6 +7,8 @@ import { IconHelpCircle } from 'twenty-ui';
import { currentUserState } from '@/auth/states/currentUserState'; import { currentUserState } from '@/auth/states/currentUserState';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { supportChatState } from '@/client-config/states/supportChatState'; import { supportChatState } from '@/client-config/states/supportChatState';
import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading';
import { SupportChatSkeletonLoader } from '@/support/components/SupportChatSkeletonLoader';
import { Button } from '@/ui/input/button/components/Button'; import { Button } from '@/ui/input/button/components/Button';
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
import { User } from '~/generated/graphql'; import { User } from '~/generated/graphql';
@ -37,6 +39,7 @@ export const SupportChat = () => {
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
const supportChat = useRecoilValue(supportChatState); const supportChat = useRecoilValue(supportChatState);
const [isFrontChatLoaded, setIsFrontChatLoaded] = useState(false); const [isFrontChatLoaded, setIsFrontChatLoaded] = useState(false);
const loading = useIsPrefetchLoading();
const configureFront = useCallback( const configureFront = useCallback(
( (
@ -98,6 +101,10 @@ export const SupportChat = () => {
currentWorkspaceMember, currentWorkspaceMember,
]); ]);
if (loading) {
return <SupportChatSkeletonLoader />;
}
return isFrontChatLoaded ? ( return isFrontChatLoaded ? (
<StyledButtonContainer> <StyledButtonContainer>
<Button <Button

View File

@ -0,0 +1,15 @@
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { useTheme } from '@emotion/react';
export const SupportChatSkeletonLoader = () => {
const theme = useTheme();
return (
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
borderRadius={4}
>
<Skeleton width={84} height={24} />
</SkeletonTheme>
);
};

View File

@ -7,6 +7,7 @@ import { currentUserState } from '@/auth/states/currentUserState';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { supportChatState } from '@/client-config/states/supportChatState'; import { supportChatState } from '@/client-config/states/supportChatState';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { import {
mockDefaultWorkspace, mockDefaultWorkspace,
@ -35,6 +36,7 @@ const meta: Meta<typeof SupportChat> = {
return <Story />; return <Story />;
}, },
PrefetchLoadingDecorator,
], ],
parameters: { parameters: {
msw: graphqlMocks, msw: graphqlMocks,

View File

@ -12,6 +12,9 @@ const meta: Meta = {
maxWidth: 100, maxWidth: 100,
children: 'This is a long text that should be truncated', children: 'This is a long text that should be truncated',
}, },
parameters: {
chromatic: { disableSnapshot: true },
},
}; };
export default meta; export default meta;

View File

@ -53,7 +53,7 @@ type ShowPageRightContainerProps = {
tasks?: boolean; tasks?: boolean;
notes?: boolean; notes?: boolean;
emails?: boolean; emails?: boolean;
loading?: boolean; loading: boolean;
}; };
export const ShowPageRightContainer = ({ export const ShowPageRightContainer = ({

View File

@ -1,5 +1,8 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading';
import { NavigationDrawerSectionTitleSkeletonLoader } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitleSkeletonLoader';
type NavigationDrawerSectionTitleProps = { type NavigationDrawerSectionTitleProps = {
label: string; label: string;
}; };
@ -15,4 +18,11 @@ const StyledTitle = styled.div`
export const NavigationDrawerSectionTitle = ({ export const NavigationDrawerSectionTitle = ({
label, label,
}: NavigationDrawerSectionTitleProps) => <StyledTitle>{label}</StyledTitle>; }: NavigationDrawerSectionTitleProps) => {
const loading = useIsPrefetchLoading();
return loading ? (
<NavigationDrawerSectionTitleSkeletonLoader />
) : (
<StyledTitle>{label}</StyledTitle>
);
};

View File

@ -0,0 +1,23 @@
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
const StyledSkeletonTitle = styled.div`
margin-bottom: ${(props) => props.theme.spacing(2)};
padding-left: ${({ theme }) => theme.spacing(1)};
`;
export const NavigationDrawerSectionTitleSkeletonLoader = () => {
const theme = useTheme();
return (
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
borderRadius={4}
>
<StyledSkeletonTitle>
<Skeleton width={56} height={13} />
</StyledSkeletonTitle>
</SkeletonTheme>
);
};

View File

@ -4,12 +4,14 @@ import { useParams } from 'react-router-dom';
import { ObjectFilterDropdownButton } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownButton'; import { ObjectFilterDropdownButton } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownButton';
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope'; import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
import { ObjectSortDropdownButton } from '@/object-record/object-sort-dropdown/components/ObjectSortDropdownButton'; import { ObjectSortDropdownButton } from '@/object-record/object-sort-dropdown/components/ObjectSortDropdownButton';
import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading';
import { TopBar } from '@/ui/layout/top-bar/TopBar'; import { TopBar } from '@/ui/layout/top-bar/TopBar';
import { QueryParamsFiltersEffect } from '@/views/components/QueryParamsFiltersEffect'; import { QueryParamsFiltersEffect } from '@/views/components/QueryParamsFiltersEffect';
import { QueryParamsViewIdEffect } from '@/views/components/QueryParamsViewIdEffect'; import { QueryParamsViewIdEffect } from '@/views/components/QueryParamsViewIdEffect';
import { ViewBarEffect } from '@/views/components/ViewBarEffect'; import { ViewBarEffect } from '@/views/components/ViewBarEffect';
import { ViewBarFilterEffect } from '@/views/components/ViewBarFilterEffect'; import { ViewBarFilterEffect } from '@/views/components/ViewBarFilterEffect';
import { ViewBarPageTitle } from '@/views/components/ViewBarPageTitle'; import { ViewBarPageTitle } from '@/views/components/ViewBarPageTitle';
import { ViewBarSkeletonLoader } from '@/views/components/ViewBarSkeletonLoader';
import { ViewBarSortEffect } from '@/views/components/ViewBarSortEffect'; import { ViewBarSortEffect } from '@/views/components/ViewBarSortEffect';
import { ViewScope } from '@/views/scopes/ViewScope'; import { ViewScope } from '@/views/scopes/ViewScope';
import { GraphQLView } from '@/views/types/GraphQLView'; import { GraphQLView } from '@/views/types/GraphQLView';
@ -38,6 +40,8 @@ export const ViewBar = ({
const filterDropdownId = 'view-filter'; const filterDropdownId = 'view-filter';
const sortDropdownId = 'view-sort'; const sortDropdownId = 'view-sort';
const loading = useIsPrefetchLoading();
if (!objectNamePlural) { if (!objectNamePlural) {
return; return;
} }
@ -57,9 +61,7 @@ export const ViewBar = ({
<TopBar <TopBar
className={className} className={className}
leftComponent={ leftComponent={
<> loading ? <ViewBarSkeletonLoader /> : <ViewPickerDropdown />
<ViewPickerDropdown />
</>
} }
displayBottomBorder={false} displayBottomBorder={false}
rightComponent={ rightComponent={

View File

@ -0,0 +1,15 @@
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { useTheme } from '@emotion/react';
export const ViewBarSkeletonLoader = () => {
const theme = useTheme();
return (
<SkeletonTheme
baseColor={theme.background.tertiary}
highlightColor={theme.background.transparent.lighter}
borderRadius={4}
>
<Skeleton width={140} height={16} />
</SkeletonTheme>
);
};

View File

@ -9,6 +9,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedOnboardingUsersData } from '~/testing/mock-data/users'; import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';
@ -18,7 +19,7 @@ import { ChooseYourPlan } from '../ChooseYourPlan';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Auth/ChooseYourPlan', title: 'Pages/Auth/ChooseYourPlan',
component: ChooseYourPlan, component: ChooseYourPlan,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { routePath: AppPath.PlanRequired }, args: { routePath: AppPath.PlanRequired },
parameters: { parameters: {
msw: { msw: {

View File

@ -9,6 +9,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedOnboardingUsersData } from '~/testing/mock-data/users'; import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
@ -17,7 +18,7 @@ import { CreateProfile } from '../CreateProfile';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Auth/CreateProfile', title: 'Pages/Auth/CreateProfile',
component: CreateProfile, component: CreateProfile,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { routePath: AppPath.CreateProfile }, args: { routePath: AppPath.CreateProfile },
parameters: { parameters: {
msw: { msw: {

View File

@ -11,6 +11,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedOnboardingUsersData } from '~/testing/mock-data/users'; import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
@ -25,6 +26,7 @@ const meta: Meta<PageDecoratorArgs> = {
setCurrentWorkspace(mockedOnboardingUsersData[1].defaultWorkspace); setCurrentWorkspace(mockedOnboardingUsersData[1].defaultWorkspace);
return <Story />; return <Story />;
}, },
PrefetchLoadingDecorator,
PageDecorator, PageDecorator,
], ],
args: { routePath: AppPath.CreateWorkspace }, args: { routePath: AppPath.CreateWorkspace },

View File

@ -10,13 +10,14 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedOnboardingUsersData } from '~/testing/mock-data/users'; import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Auth/PasswordReset', title: 'Pages/Auth/PasswordReset',
component: PasswordReset, component: PasswordReset,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: '/reset-password/:passwordResetToken', routePath: '/reset-password/:passwordResetToken',
routeParams: { ':passwordResetToken': 'MOCKED_TOKEN' }, routeParams: { ':passwordResetToken': 'MOCKED_TOKEN' },

View File

@ -9,6 +9,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedOnboardingUsersData } from '~/testing/mock-data/users'; import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
@ -17,7 +18,7 @@ import { PaymentSuccess } from '../PaymentSuccess';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Auth/PaymentSuccess', title: 'Pages/Auth/PaymentSuccess',
component: PaymentSuccess, component: PaymentSuccess,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { routePath: AppPath.PlanRequiredSuccess }, args: { routePath: AppPath.PlanRequiredSuccess },
parameters: { parameters: {
msw: { msw: {

View File

@ -9,6 +9,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { SignInUp } from '../SignInUp'; import { SignInUp } from '../SignInUp';
@ -16,7 +17,7 @@ import { SignInUp } from '../SignInUp';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Auth/SignInUp', title: 'Pages/Auth/SignInUp',
component: SignInUp, component: SignInUp,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { routePath: AppPath.SignInUp }, args: { routePath: AppPath.SignInUp },
parameters: { parameters: {
msw: { msw: {

View File

@ -5,6 +5,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';
@ -13,7 +14,7 @@ import { ImpersonateEffect } from '../ImpersonateEffect';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Impersonate/Impersonate', title: 'Pages/Impersonate/Impersonate',
component: ImpersonateEffect, component: ImpersonateEffect,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: AppPath.Impersonate, routePath: AppPath.Impersonate,
routeParams: { ':userId': '1' }, routeParams: { ':userId': '1' },

View File

@ -1,9 +1,12 @@
import { expect } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { within } from '@storybook/test';
import { import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { RecordIndexPage } from '../RecordIndexPage'; import { RecordIndexPage } from '../RecordIndexPage';
@ -27,4 +30,26 @@ export default meta;
export type Story = StoryObj<typeof RecordIndexPage>; export type Story = StoryObj<typeof RecordIndexPage>;
export const Default: Story = {}; export const Default: Story = {
decorators: [PrefetchLoadingDecorator],
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await canvas.findByText('People');
await canvas.findAllByText('Companies');
await canvas.findByText('Opportunities');
await canvas.findByText('Listings');
await canvas.findByText('My Customs');
},
};
export const Loading: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
expect(canvas.queryByText('People')).toBeNull();
expect(canvas.queryByText('Opportunities')).toBeNull();
expect(canvas.queryByText('Listings')).toBeNull();
expect(canvas.queryByText('My Customs')).toBeNull();
},
};

View File

@ -1,3 +1,4 @@
import { expect } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { within } from '@storybook/test'; import { within } from '@storybook/test';
import { graphql, HttpResponse } from 'msw'; import { graphql, HttpResponse } from 'msw';
@ -6,6 +7,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedPeopleData } from '~/testing/mock-data/people'; import { mockedPeopleData } from '~/testing/mock-data/people';
import { mockedWorkspaceMemberData } from '~/testing/mock-data/users'; import { mockedWorkspaceMemberData } from '~/testing/mock-data/users';
@ -15,7 +17,6 @@ import { RecordShowPage } from '../RecordShowPage';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/ObjectRecord/RecordShowPage', title: 'Pages/ObjectRecord/RecordShowPage',
component: RecordShowPage, component: RecordShowPage,
decorators: [PageDecorator],
args: { args: {
routePath: '/object/:objectNameSingular/:objectRecordId', routePath: '/object/:objectNameSingular/:objectRecordId',
routeParams: { routeParams: {
@ -81,6 +82,9 @@ export default meta;
export type Story = StoryObj<typeof RecordShowPage>; export type Story = StoryObj<typeof RecordShowPage>;
export const Default: Story = { export const Default: Story = {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
decorators: [PrefetchLoadingDecorator, PageDecorator],
play: async ({ canvasElement }) => { play: async ({ canvasElement }) => {
const canvas = within(canvasElement); const canvas = within(canvasElement);
@ -88,3 +92,15 @@ export const Default: Story = {
await canvas.findByText('Add your first Activity'); await canvas.findByText('Add your first Activity');
}, },
}; };
export const Loading: Story = {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
decorators: [PageDecorator],
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
expect(canvas.queryByText('Alexandre Prot')).toBeNull();
expect(canvas.queryByText('Add your first Activity')).toBeNull();
},
};

View File

@ -4,6 +4,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { SettingsAppearance } from '../SettingsAppearance'; import { SettingsAppearance } from '../SettingsAppearance';
@ -11,7 +12,7 @@ import { SettingsAppearance } from '../SettingsAppearance';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/SettingsAppearance', title: 'Pages/Settings/SettingsAppearance',
component: SettingsAppearance, component: SettingsAppearance,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { routePath: '/settings/appearance' }, args: { routePath: '/settings/appearance' },
parameters: { parameters: {
msw: graphqlMocks, msw: graphqlMocks,

View File

@ -7,6 +7,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';
@ -15,7 +16,7 @@ import { SettingsBilling } from '../SettingsBilling';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/SettingsBilling', title: 'Pages/Settings/SettingsBilling',
component: SettingsBilling, component: SettingsBilling,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { routePath: getSettingsPagePath(SettingsPath.Billing) }, args: { routePath: getSettingsPagePath(SettingsPath.Billing) },
parameters: { parameters: {
msw: graphqlMocks, msw: graphqlMocks,

View File

@ -5,6 +5,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { SettingsProfile } from '../SettingsProfile'; import { SettingsProfile } from '../SettingsProfile';
@ -12,7 +13,7 @@ import { SettingsProfile } from '../SettingsProfile';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/SettingsProfile', title: 'Pages/Settings/SettingsProfile',
component: SettingsProfile, component: SettingsProfile,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: '/settings/profile', routePath: '/settings/profile',
additionalRoutes: ['/welcome'], additionalRoutes: ['/welcome'],

View File

@ -4,6 +4,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { SettingsWorkspace } from '../SettingsWorkspace'; import { SettingsWorkspace } from '../SettingsWorkspace';
@ -11,7 +12,7 @@ import { SettingsWorkspace } from '../SettingsWorkspace';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/SettingsWorkspace', title: 'Pages/Settings/SettingsWorkspace',
component: SettingsWorkspace, component: SettingsWorkspace,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { routePath: '/settings/workspace' }, args: { routePath: '/settings/workspace' },
parameters: { parameters: {
msw: graphqlMocks, msw: graphqlMocks,

View File

@ -5,6 +5,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';
@ -13,7 +14,7 @@ import { SettingsWorkspaceMembers } from '../SettingsWorkspaceMembers';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/SettingsWorkspaceMembers', title: 'Pages/Settings/SettingsWorkspaceMembers',
component: SettingsWorkspaceMembers, component: SettingsWorkspaceMembers,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { routePath: '/settings/workspace-members' }, args: { routePath: '/settings/workspace-members' },
parameters: { parameters: {
msw: graphqlMocks, msw: graphqlMocks,

View File

@ -5,6 +5,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { SettingsAccounts } from '../SettingsAccounts'; import { SettingsAccounts } from '../SettingsAccounts';
@ -12,7 +13,7 @@ import { SettingsAccounts } from '../SettingsAccounts';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Accounts/SettingsAccounts', title: 'Pages/Settings/Accounts/SettingsAccounts',
component: SettingsAccounts, component: SettingsAccounts,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: '/settings/accounts', routePath: '/settings/accounts',
}, },

View File

@ -7,6 +7,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';
@ -15,7 +16,7 @@ import { SettingsAccountsCalendars } from '../SettingsAccountsCalendars';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Accounts/SettingsAccountsCalendars', title: 'Pages/Settings/Accounts/SettingsAccountsCalendars',
component: SettingsAccountsCalendars, component: SettingsAccountsCalendars,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: getSettingsPagePath(SettingsPath.AccountsCalendars), routePath: getSettingsPagePath(SettingsPath.AccountsCalendars),
}, },

View File

@ -8,6 +8,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedConnectedAccounts } from '~/testing/mock-data/accounts'; import { mockedConnectedAccounts } from '~/testing/mock-data/accounts';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';
@ -17,7 +18,7 @@ import { SettingsAccountsCalendarsSettings } from '../SettingsAccountsCalendarsS
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Accounts/SettingsAccountsCalendarsSettings', title: 'Pages/Settings/Accounts/SettingsAccountsCalendarsSettings',
component: SettingsAccountsCalendarsSettings, component: SettingsAccountsCalendarsSettings,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: getSettingsPagePath(SettingsPath.AccountsCalendarsSettings), routePath: getSettingsPagePath(SettingsPath.AccountsCalendarsSettings),
routeParams: { ':accountUuid': mockedConnectedAccounts[0].id }, routeParams: { ':accountUuid': mockedConnectedAccounts[0].id },

View File

@ -4,6 +4,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { SettingsAccountsEmails } from '../SettingsAccountsEmails'; import { SettingsAccountsEmails } from '../SettingsAccountsEmails';
@ -11,7 +12,7 @@ import { SettingsAccountsEmails } from '../SettingsAccountsEmails';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Accounts/SettingsAccountsEmails', title: 'Pages/Settings/Accounts/SettingsAccountsEmails',
component: SettingsAccountsEmails, component: SettingsAccountsEmails,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: '/settings/accounts/emails', routePath: '/settings/accounts/emails',
}, },

View File

@ -7,12 +7,13 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Accounts/SettingsAccountsEmailsInboxSettings', title: 'Pages/Settings/Accounts/SettingsAccountsEmailsInboxSettings',
component: SettingsAccountsEmailsInboxSettings, component: SettingsAccountsEmailsInboxSettings,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: '/settings/accounts/emails/:accountUuid', routePath: '/settings/accounts/emails/:accountUuid',
routeParams: { ':accountUuid': '123' }, routeParams: { ':accountUuid': '123' },

View File

@ -5,12 +5,13 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Accounts/SettingsNewAccount', title: 'Pages/Settings/Accounts/SettingsNewAccount',
component: SettingsNewAccount, component: SettingsNewAccount,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: '/settings/accounts/new', routePath: '/settings/accounts/new',
}, },

View File

@ -5,6 +5,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { SettingsNewObject } from '../SettingsNewObject'; import { SettingsNewObject } from '../SettingsNewObject';
@ -12,7 +13,7 @@ import { SettingsNewObject } from '../SettingsNewObject';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/DataModel/SettingsNewObject', title: 'Pages/Settings/DataModel/SettingsNewObject',
component: SettingsNewObject, component: SettingsNewObject,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: '/settings/objects/new', routePath: '/settings/objects/new',
}, },

View File

@ -5,6 +5,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';
@ -13,7 +14,7 @@ import { SettingsObjectDetail } from '../SettingsObjectDetail';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/DataModel/SettingsObjectDetail', title: 'Pages/Settings/DataModel/SettingsObjectDetail',
component: SettingsObjectDetail, component: SettingsObjectDetail,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: '/settings/objects/:objectSlug', routePath: '/settings/objects/:objectSlug',
routeParams: { ':objectSlug': 'companies' }, routeParams: { ':objectSlug': 'companies' },

View File

@ -4,6 +4,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';
@ -12,7 +13,7 @@ import { SettingsObjectEdit } from '../SettingsObjectEdit';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/DataModel/SettingsObjectEdit', title: 'Pages/Settings/DataModel/SettingsObjectEdit',
component: SettingsObjectEdit, component: SettingsObjectEdit,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: '/settings/objects/:objectSlug/edit', routePath: '/settings/objects/:objectSlug/edit',
routeParams: { ':objectSlug': 'companies' }, routeParams: { ':objectSlug': 'companies' },

View File

@ -4,6 +4,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { SettingsObjectFieldEdit } from '../SettingsObjectFieldEdit'; import { SettingsObjectFieldEdit } from '../SettingsObjectFieldEdit';
@ -11,7 +12,7 @@ import { SettingsObjectFieldEdit } from '../SettingsObjectFieldEdit';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/DataModel/SettingsObjectFieldEdit', title: 'Pages/Settings/DataModel/SettingsObjectFieldEdit',
component: SettingsObjectFieldEdit, component: SettingsObjectFieldEdit,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: '/settings/objects/:objectSlug/:fieldSlug', routePath: '/settings/objects/:objectSlug/:fieldSlug',
routeParams: { ':objectSlug': 'companies', ':fieldSlug': 'name' }, routeParams: { ':objectSlug': 'companies', ':fieldSlug': 'name' },

View File

@ -5,6 +5,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { SettingsObjectNewFieldStep1 } from '../../SettingsObjectNewField/SettingsObjectNewFieldStep1'; import { SettingsObjectNewFieldStep1 } from '../../SettingsObjectNewField/SettingsObjectNewFieldStep1';
@ -13,7 +14,7 @@ const meta: Meta<PageDecoratorArgs> = {
title: title:
'Pages/Settings/DataModel/SettingsObjectNewField/SettingsObjectNewFieldStep1', 'Pages/Settings/DataModel/SettingsObjectNewField/SettingsObjectNewFieldStep1',
component: SettingsObjectNewFieldStep1, component: SettingsObjectNewFieldStep1,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: '/settings/objects/:objectSlug/new-field/step-1', routePath: '/settings/objects/:objectSlug/new-field/step-1',
routeParams: { ':objectSlug': 'companies' }, routeParams: { ':objectSlug': 'companies' },

View File

@ -5,6 +5,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { SettingsObjectNewFieldStep2 } from '../../SettingsObjectNewField/SettingsObjectNewFieldStep2'; import { SettingsObjectNewFieldStep2 } from '../../SettingsObjectNewField/SettingsObjectNewFieldStep2';
@ -13,7 +14,7 @@ const meta: Meta<PageDecoratorArgs> = {
title: title:
'Pages/Settings/DataModel/SettingsObjectNewField/SettingsObjectNewFieldStep2', 'Pages/Settings/DataModel/SettingsObjectNewField/SettingsObjectNewFieldStep2',
component: SettingsObjectNewFieldStep2, component: SettingsObjectNewFieldStep2,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: '/settings/objects/:objectSlug/new-field/step-2', routePath: '/settings/objects/:objectSlug/new-field/step-2',
routeParams: { ':objectSlug': 'companies' }, routeParams: { ':objectSlug': 'companies' },

View File

@ -5,6 +5,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';
@ -13,7 +14,7 @@ import { SettingsObjects } from '../SettingsObjects';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/DataModel/SettingsObjects', title: 'Pages/Settings/DataModel/SettingsObjects',
component: SettingsObjects, component: SettingsObjects,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { routePath: '/settings/objects' }, args: { routePath: '/settings/objects' },
parameters: { parameters: {
msw: graphqlMocks, msw: graphqlMocks,

View File

@ -6,13 +6,14 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Developers/SettingsDevelopers', title: 'Pages/Settings/Developers/SettingsDevelopers',
component: SettingsDevelopers, component: SettingsDevelopers,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { routePath: '/settings/developers' }, args: { routePath: '/settings/developers' },
parameters: { parameters: {
msw: graphqlMocks, msw: graphqlMocks,

View File

@ -7,12 +7,13 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Developers/ApiKeys/SettingsDevelopersApiKeyDetail', title: 'Pages/Settings/Developers/ApiKeys/SettingsDevelopersApiKeyDetail',
component: SettingsDevelopersApiKeyDetail, component: SettingsDevelopersApiKeyDetail,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: '/settings/developers/api-keys/:apiKeyId', routePath: '/settings/developers/api-keys/:apiKeyId',
routeParams: { routeParams: {

View File

@ -6,12 +6,13 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Developers/ApiKeys/SettingsDevelopersApiKeysNew', title: 'Pages/Settings/Developers/ApiKeys/SettingsDevelopersApiKeysNew',
component: SettingsDevelopersApiKeysNew, component: SettingsDevelopersApiKeysNew,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { routePath: '/settings/developers/api-keys/new' }, args: { routePath: '/settings/developers/api-keys/new' },
parameters: { parameters: {
msw: graphqlMocks, msw: graphqlMocks,

View File

@ -7,12 +7,13 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Developers/Webhooks/SettingsDevelopersWebhooksDetail', title: 'Pages/Settings/Developers/Webhooks/SettingsDevelopersWebhooksDetail',
component: SettingsDevelopersWebhooksDetail, component: SettingsDevelopersWebhooksDetail,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: '/settings/developers/webhooks/:webhookId', routePath: '/settings/developers/webhooks/:webhookId',
routeParams: { ':webhookId': '1234' }, routeParams: { ':webhookId': '1234' },

View File

@ -6,12 +6,13 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Developers/Webhooks/SettingsDevelopersWebhooksNew', title: 'Pages/Settings/Developers/Webhooks/SettingsDevelopersWebhooksNew',
component: SettingsDevelopersWebhooksNew, component: SettingsDevelopersWebhooksNew,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { routePath: '/settings/developers' }, args: { routePath: '/settings/developers' },
parameters: { parameters: {
msw: graphqlMocks, msw: graphqlMocks,

View File

@ -8,13 +8,14 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Integrations/SettingsIntegrationDatabase', title: 'Pages/Settings/Integrations/SettingsIntegrationDatabase',
component: SettingsIntegrationDatabase, component: SettingsIntegrationDatabase,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: getSettingsPagePath(SettingsPath.IntegrationDatabase), routePath: getSettingsPagePath(SettingsPath.IntegrationDatabase),
routeParams: { ':databaseKey': 'postgresql' }, routeParams: { ':databaseKey': 'postgresql' },

View File

@ -6,6 +6,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';
@ -13,7 +14,7 @@ const meta: Meta<PageDecoratorArgs> = {
title: title:
'Pages/Settings/Integrations/SettingsIntegrationEditDatabaseConnection', 'Pages/Settings/Integrations/SettingsIntegrationEditDatabaseConnection',
component: SettingsIntegrationEditDatabaseConnection, component: SettingsIntegrationEditDatabaseConnection,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: '/settings/integrations/:databaseKey/edit', routePath: '/settings/integrations/:databaseKey/edit',
routeParams: { routeParams: {

View File

@ -6,13 +6,14 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Integrations/SettingsIntegrationNewDatabaseConnection', title: 'Pages/Settings/Integrations/SettingsIntegrationNewDatabaseConnection',
component: SettingsIntegrationNewDatabaseConnection, component: SettingsIntegrationNewDatabaseConnection,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: '/settings/integrations/:databaseKey/new', routePath: '/settings/integrations/:databaseKey/new',
routeParams: { ':databaseKey': 'postgresql' }, routeParams: { ':databaseKey': 'postgresql' },

View File

@ -8,6 +8,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';
@ -15,7 +16,7 @@ const meta: Meta<PageDecoratorArgs> = {
title: title:
'Pages/Settings/Integrations/SettingsIntegrationShowDatabaseConnection', 'Pages/Settings/Integrations/SettingsIntegrationShowDatabaseConnection',
component: SettingsIntegrationShowDatabaseConnection, component: SettingsIntegrationShowDatabaseConnection,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { args: {
routePath: getSettingsPagePath(SettingsPath.IntegrationDatabaseConnection), routePath: getSettingsPagePath(SettingsPath.IntegrationDatabaseConnection),
routeParams: { routeParams: {

View File

@ -8,13 +8,14 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Integrations/SettingsIntegrations', title: 'Pages/Settings/Integrations/SettingsIntegrations',
component: SettingsIntegrations, component: SettingsIntegrations,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { routePath: getSettingsPagePath(SettingsPath.Integrations) }, args: { routePath: getSettingsPagePath(SettingsPath.Integrations) },
parameters: { parameters: {
msw: graphqlMocks, msw: graphqlMocks,

View File

@ -6,6 +6,7 @@ import {
PageDecorator, PageDecorator,
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedWorkspaceMemberData } from '~/testing/mock-data/users'; import { mockedWorkspaceMemberData } from '~/testing/mock-data/users';
import { sleep } from '~/testing/sleep'; import { sleep } from '~/testing/sleep';
@ -15,7 +16,7 @@ import { Tasks } from '../Tasks';
const meta: Meta<PageDecoratorArgs> = { const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Tasks/Default', title: 'Pages/Tasks/Default',
component: Tasks, component: Tasks,
decorators: [PageDecorator], decorators: [PrefetchLoadingDecorator, PageDecorator],
args: { routePath: AppPath.TasksPage }, args: { routePath: AppPath.TasksPage },
parameters: { parameters: {
msw: { msw: {

View File

@ -0,0 +1,19 @@
import { Decorator } from '@storybook/react';
import { useSetRecoilState } from 'recoil';
import { prefetchIsLoadedFamilyState } from '@/prefetch/states/prefetchIsLoadedFamilyState';
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
export const PrefetchLoadingDecorator: Decorator = (Story) => {
const setAreViewsPrefetched = useSetRecoilState(
prefetchIsLoadedFamilyState(PrefetchKey.AllViews),
);
const setAreFavoritesPrefetched = useSetRecoilState(
prefetchIsLoadedFamilyState(PrefetchKey.AllFavorites),
);
setAreViewsPrefetched(true);
setAreFavoritesPrefetched(true);
return <Story />;
};