mirror of
https://github.com/lingble/twenty.git
synced 2025-10-28 19:32:28 +00:00
Add Skeleton loading for side panel (#7394)
This PR was created by [GitStart](https://gitstart.com/) to address the requirements from this ticket: [TWNTY-7112](https://clients.gitstart.com/twenty/5449/tickets/TWNTY-7112). --- ### Description - To test you can use `await new Promise(r => setTimeout(r, 5000));` line 74 of \`openCreateActivityDrawer.ts\` - We added a recoil state to define the loading status - Design points to note: 1 - We did not change the chip component styles because would be unrelated to the issue can you confirm if you still need this change?  2- In Figma, the loading state shows the Chip rendering an initial name before showing the loaded name, currently, we are rendering the correct name while loading, the change that makes this possible is below  if we set it as null, the initial name would appear, but also the previous data in the state would affect the UI, passing the `activityObjectNameSingular` data allows us to clear the previous data, and make the Chip instantly updated, let us know if this behavior is fine, or if you still want an initial name to be rendered while is loading. 3 - Currently, the loading state of the tabs does not affect the selected tab (auto-defined by the component) should we change this logic for all Tabs used in the app, or make this behavior optional by using props?  ### Demo <https://www.loom.com/share/590df738a8ec41e6b64232bde237c01f?sid=7f8f4e40-ec82-4282-a43d-452a1cf27f4a> ### Refs #7112 --------- Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com> Co-authored-by: gitstart-twenty <140154534+gitstart-twenty@users.noreply.github.com> Co-authored-by: Marie Stoppa <marie.stoppa@essec.edu>
This commit is contained in:
committed by
GitHub
parent
97eff774bd
commit
8afa504b65
@@ -3,6 +3,7 @@ import { motion } from 'framer-motion';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
import { ANIMATION, BACKGROUND_LIGHT, GRAY_SCALE } from 'twenty-ui';
|
||||
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { DESKTOP_NAV_DRAWER_WIDTHS } from '@/ui/navigation/navigation-drawer/constants/DesktopNavDrawerWidths';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { MainNavigationDrawerItemsSkeletonLoader } from '~/loading/components/MainNavigationDrawerItemsSkeletonLoader';
|
||||
@@ -67,7 +68,10 @@ export const LeftPanelSkeletonLoader = () => {
|
||||
highlightColor={BACKGROUND_LIGHT.transparent.lighter}
|
||||
borderRadius={4}
|
||||
>
|
||||
<Skeleton width={96} height={16} />
|
||||
<Skeleton
|
||||
width={96}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
|
||||
/>
|
||||
</SkeletonTheme>
|
||||
</StyledSkeletonTitleContainer>
|
||||
<StyledSkeletonContainer>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import styled from '@emotion/styled';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
import { BACKGROUND_LIGHT, GRAY_SCALE } from 'twenty-ui';
|
||||
@@ -26,9 +27,18 @@ export const MainNavigationDrawerItemsSkeletonLoader = ({
|
||||
highlightColor={BACKGROUND_LIGHT.transparent.lighter}
|
||||
borderRadius={4}
|
||||
>
|
||||
{title && <Skeleton width={48} height={13} />}
|
||||
{title && (
|
||||
<Skeleton
|
||||
width={48}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.xs}
|
||||
/>
|
||||
)}
|
||||
{Array.from({ length }).map((_, index) => (
|
||||
<Skeleton key={index} width={196} height={16} />
|
||||
<Skeleton
|
||||
key={index}
|
||||
width={196}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
|
||||
/>
|
||||
))}
|
||||
</SkeletonTheme>
|
||||
</StyledSkeletonContainer>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import styled from '@emotion/styled';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
import {
|
||||
@@ -60,7 +61,10 @@ const StyledSkeletonHeaderLoader = () => {
|
||||
highlightColor={BACKGROUND_LIGHT.transparent.lighter}
|
||||
borderRadius={4}
|
||||
>
|
||||
<Skeleton height={16} width={104} />
|
||||
<Skeleton
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
|
||||
width={104}
|
||||
/>
|
||||
</SkeletonTheme>
|
||||
</StyledHeaderContainer>
|
||||
);
|
||||
@@ -73,7 +77,7 @@ const StyledSkeletonAddLoader = () => {
|
||||
highlightColor={BACKGROUND_LIGHT.transparent.lighter}
|
||||
borderRadius={4}
|
||||
>
|
||||
<Skeleton width={132} height={16} />
|
||||
<Skeleton width={132} height={SKELETON_LOADER_HEIGHT_SIZES.standard.s} />
|
||||
</SkeletonTheme>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
|
||||
const StyledSkeletonContainer = styled.div`
|
||||
align-items: center;
|
||||
@@ -25,6 +25,21 @@ const StyledSkeletonSubSectionContent = styled.div`
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
export const SKELETON_LOADER_HEIGHT_SIZES = {
|
||||
standard: {
|
||||
xs: 13,
|
||||
s: 16,
|
||||
m: 24,
|
||||
l: 32,
|
||||
xl: 40,
|
||||
},
|
||||
columns: {
|
||||
s: 84,
|
||||
m: 120,
|
||||
xxl: 542,
|
||||
},
|
||||
};
|
||||
|
||||
const SkeletonColumnLoader = ({ height }: { height: number }) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
@@ -55,15 +70,35 @@ export const SkeletonLoader = ({
|
||||
borderRadius={4}
|
||||
>
|
||||
<StyledSkeletonContainer>
|
||||
<Skeleton width={440} height={16} />
|
||||
<Skeleton
|
||||
width={440}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
|
||||
/>
|
||||
{withSubSections &&
|
||||
skeletonItems.map(({ id }, index) => (
|
||||
<StyledSkeletonSubSection key={id}>
|
||||
<SkeletonColumnLoader height={index === 1 ? 120 : 84} />
|
||||
<SkeletonColumnLoader
|
||||
height={
|
||||
index === 1
|
||||
? SKELETON_LOADER_HEIGHT_SIZES.columns.m
|
||||
: SKELETON_LOADER_HEIGHT_SIZES.columns.s
|
||||
}
|
||||
/>
|
||||
<StyledSkeletonSubSectionContent>
|
||||
<Skeleton width={400} height={24} />
|
||||
<Skeleton width={400} height={24} />
|
||||
{index === 1 && <Skeleton width={400} height={24} />}
|
||||
<Skeleton
|
||||
width={400}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.m}
|
||||
/>
|
||||
<Skeleton
|
||||
width={400}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.m}
|
||||
/>
|
||||
{index === 1 && (
|
||||
<Skeleton
|
||||
width={400}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.m}
|
||||
/>
|
||||
)}
|
||||
</StyledSkeletonSubSectionContent>
|
||||
</StyledSkeletonSubSection>
|
||||
))}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { Task } from '@/activities/types/Task';
|
||||
import { TaskTarget } from '@/activities/types/TaskTarget';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||
import { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading';
|
||||
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
|
||||
import { ActivityTargetableObject } from '../types/ActivityTargetableEntity';
|
||||
|
||||
@@ -52,7 +53,9 @@ export const useOpenCreateActivityDrawer = ({
|
||||
const setViewableRecordNameSingular = useSetRecoilState(
|
||||
viewableRecordNameSingularState,
|
||||
);
|
||||
|
||||
const setIsNewViewableRecordLoading = useSetRecoilState(
|
||||
isNewViewableRecordLoadingState,
|
||||
);
|
||||
const setIsUpsertingActivityInDB = useSetRecoilState(
|
||||
isUpsertingActivityInDBState,
|
||||
);
|
||||
@@ -64,6 +67,11 @@ export const useOpenCreateActivityDrawer = ({
|
||||
targetableObjects: ActivityTargetableObject[];
|
||||
customAssignee?: WorkspaceMember;
|
||||
}) => {
|
||||
openRightDrawer(RightDrawerPages.ViewRecord);
|
||||
setIsNewViewableRecordLoading(true);
|
||||
setViewableRecordId(null);
|
||||
setViewableRecordNameSingular(activityObjectNameSingular);
|
||||
|
||||
const activity = await createOneActivity({
|
||||
assigneeId: customAssignee?.id,
|
||||
});
|
||||
@@ -101,10 +109,9 @@ export const useOpenCreateActivityDrawer = ({
|
||||
|
||||
setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false });
|
||||
setViewableRecordId(activity.id);
|
||||
setViewableRecordNameSingular(activityObjectNameSingular);
|
||||
|
||||
openRightDrawer(RightDrawerPages.ViewRecord);
|
||||
setIsUpsertingActivityInDB(false);
|
||||
setIsNewViewableRecordLoading(false);
|
||||
};
|
||||
|
||||
return openCreateActivityDrawer;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
|
||||
const StyledSkeletonContainer = styled.div`
|
||||
display: flex;
|
||||
@@ -25,10 +26,19 @@ export const FavoritesSkeletonLoader = () => {
|
||||
borderRadius={4}
|
||||
>
|
||||
<StyledSkeletonContainer>
|
||||
<Skeleton width={56} height={13} />
|
||||
<Skeleton
|
||||
width={56}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.xs}
|
||||
/>
|
||||
<StyledSkeletonColumn>
|
||||
<Skeleton width={196} height={16} />
|
||||
<Skeleton width={196} height={16} />
|
||||
<Skeleton
|
||||
width={196}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
|
||||
/>
|
||||
<Skeleton
|
||||
width={196}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
|
||||
/>
|
||||
</StyledSkeletonColumn>
|
||||
</StyledSkeletonContainer>
|
||||
</SkeletonTheme>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
@@ -20,9 +21,18 @@ export const NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader: React.
|
||||
borderRadius={4}
|
||||
>
|
||||
<StyledSkeletonColumn>
|
||||
<Skeleton width={196} height={16} />
|
||||
<Skeleton width={196} height={16} />
|
||||
<Skeleton width={196} height={16} />
|
||||
<Skeleton
|
||||
width={196}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
|
||||
/>
|
||||
<Skeleton
|
||||
width={196}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
|
||||
/>
|
||||
<Skeleton
|
||||
width={196}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
|
||||
/>
|
||||
</StyledSkeletonColumn>
|
||||
</SkeletonTheme>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import {
|
||||
StyledBoardCardBody,
|
||||
StyledBoardCardHeader,
|
||||
@@ -43,7 +44,10 @@ export const RecordBoardColumnCardContainerSkeletonLoader = ({
|
||||
>
|
||||
<StyledBoardCardHeader showCompactView={isCompactModeActive}>
|
||||
<StyledSkeletonTitle>
|
||||
<Skeleton width={titleSkeletonWidth} height={16} />
|
||||
<Skeleton
|
||||
width={titleSkeletonWidth}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
|
||||
/>
|
||||
</StyledSkeletonTitle>
|
||||
</StyledBoardCardHeader>
|
||||
<StyledSeparator />
|
||||
@@ -51,8 +55,14 @@ export const RecordBoardColumnCardContainerSkeletonLoader = ({
|
||||
skeletonItems.map(({ id }) => (
|
||||
<StyledBoardCardBody key={id}>
|
||||
<StyledSkeletonIconAndText>
|
||||
<Skeleton width={16} height={16} />
|
||||
<Skeleton width={151} height={16} />
|
||||
<Skeleton
|
||||
width={16}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
|
||||
/>
|
||||
<Skeleton
|
||||
width={151}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
|
||||
/>
|
||||
</StyledSkeletonIconAndText>
|
||||
</StyledBoardCardBody>
|
||||
))}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { StyledSkeletonDiv } from './RecordInlineCellContainer';
|
||||
|
||||
export const RecordInlineCellSkeletonLoader = () => {
|
||||
@@ -13,7 +14,10 @@ export const RecordInlineCellSkeletonLoader = () => {
|
||||
borderRadius={4}
|
||||
>
|
||||
<StyledSkeletonDiv>
|
||||
<Skeleton width={154} height={16} />
|
||||
<Skeleton
|
||||
width={154}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
|
||||
/>
|
||||
</StyledSkeletonDiv>
|
||||
</SkeletonTheme>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
|
||||
const StyledSkeletonDiv = styled.div`
|
||||
align-items: center;
|
||||
@@ -22,8 +23,14 @@ export const PropertyBoxSkeletonLoader = () => {
|
||||
>
|
||||
{skeletonItems.map(({ id }) => (
|
||||
<StyledSkeletonDiv key={id}>
|
||||
<Skeleton width={92} height={16} />
|
||||
<Skeleton width={154} height={16} />
|
||||
<Skeleton
|
||||
width={92}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
|
||||
/>
|
||||
<Skeleton
|
||||
width={154}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
|
||||
/>
|
||||
</StyledSkeletonDiv>
|
||||
))}
|
||||
</SkeletonTheme>
|
||||
|
||||
@@ -19,15 +19,6 @@ export const RightDrawerRecord = () => {
|
||||
viewableRecordNameSingularState,
|
||||
);
|
||||
const viewableRecordId = useRecoilValue(viewableRecordIdState);
|
||||
|
||||
if (!viewableRecordNameSingular) {
|
||||
throw new Error(`Object name is not defined`);
|
||||
}
|
||||
|
||||
if (!viewableRecordId) {
|
||||
throw new Error(`Record id is not defined`);
|
||||
}
|
||||
|
||||
const { objectNameSingular, objectRecordId } = useRecordShowPage(
|
||||
viewableRecordNameSingular ?? '',
|
||||
viewableRecordId ?? '',
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { createState } from 'twenty-ui';
|
||||
|
||||
export const isNewViewableRecordLoadingState = createState<boolean>({
|
||||
key: 'activities/is-new-viewable-record-loading',
|
||||
defaultValue: false,
|
||||
});
|
||||
@@ -21,6 +21,7 @@ import { RecordInlineCell } from '@/object-record/record-inline-cell/components/
|
||||
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 { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading';
|
||||
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 { recordLoadingFamilyState } from '@/object-record/record-store/states/recordLoadingFamilyState';
|
||||
@@ -33,6 +34,7 @@ import { ShowPageContainer } from '@/ui/layout/page/ShowPageContainer';
|
||||
import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer';
|
||||
import { ShowPageRightContainer } from '@/ui/layout/show-page/components/ShowPageRightContainer';
|
||||
import { ShowPageSummaryCard } from '@/ui/layout/show-page/components/ShowPageSummaryCard';
|
||||
import { ShowPageSummaryCardSkeletonLoader } from '@/ui/layout/show-page/components/ShowPageSummaryCardSkeletonLoader';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import {
|
||||
FieldMetadataType,
|
||||
@@ -80,7 +82,9 @@ export const RecordShowContainer = ({
|
||||
recordId: objectRecordId,
|
||||
}),
|
||||
);
|
||||
|
||||
const isNewViewableRecordLoading = useRecoilValue(
|
||||
isNewViewableRecordLoadingState,
|
||||
);
|
||||
const [uploadImage] = useUploadImageMutation();
|
||||
const { updateOneRecord } = useUpdateOneRecord({ objectNameSingular });
|
||||
|
||||
@@ -162,53 +166,56 @@ export const RecordShowContainer = ({
|
||||
const isReadOnly = objectMetadataItem.isRemote;
|
||||
const isMobile = useIsMobile() || isInRightDrawer;
|
||||
const isPrefetchLoading = useIsPrefetchLoading();
|
||||
const isNewRightDrawerItemLoading =
|
||||
isInRightDrawer && isNewViewableRecordLoading;
|
||||
|
||||
const summaryCard = isDefined(recordFromStore) ? (
|
||||
<ShowPageSummaryCard
|
||||
isMobile={isMobile}
|
||||
id={objectRecordId}
|
||||
logoOrAvatar={recordIdentifier?.avatarUrl ?? ''}
|
||||
icon={Icon}
|
||||
iconColor={IconColor}
|
||||
avatarPlaceholder={recordIdentifier?.name ?? ''}
|
||||
date={recordFromStore.createdAt ?? ''}
|
||||
loading={isPrefetchLoading || loading || recordLoading}
|
||||
title={
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
recordId: objectRecordId,
|
||||
recoilScopeId:
|
||||
objectRecordId + labelIdentifierFieldMetadataItem?.id,
|
||||
isLabelIdentifier: false,
|
||||
fieldDefinition: {
|
||||
type:
|
||||
labelIdentifierFieldMetadataItem?.type ||
|
||||
FieldMetadataType.Text,
|
||||
iconName: '',
|
||||
fieldMetadataId: labelIdentifierFieldMetadataItem?.id ?? '',
|
||||
label: labelIdentifierFieldMetadataItem?.label || '',
|
||||
metadata: {
|
||||
fieldName: labelIdentifierFieldMetadataItem?.name || '',
|
||||
objectMetadataNameSingular: objectNameSingular,
|
||||
const summaryCard =
|
||||
!isNewRightDrawerItemLoading && isDefined(recordFromStore) ? (
|
||||
<ShowPageSummaryCard
|
||||
isMobile={isMobile}
|
||||
id={objectRecordId}
|
||||
logoOrAvatar={recordIdentifier?.avatarUrl ?? ''}
|
||||
icon={Icon}
|
||||
iconColor={IconColor}
|
||||
avatarPlaceholder={recordIdentifier?.name ?? ''}
|
||||
date={recordFromStore.createdAt ?? ''}
|
||||
loading={isPrefetchLoading || loading || recordLoading}
|
||||
title={
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
recordId: objectRecordId,
|
||||
recoilScopeId:
|
||||
objectRecordId + labelIdentifierFieldMetadataItem?.id,
|
||||
isLabelIdentifier: false,
|
||||
fieldDefinition: {
|
||||
type:
|
||||
labelIdentifierFieldMetadataItem?.type ||
|
||||
FieldMetadataType.Text,
|
||||
iconName: '',
|
||||
fieldMetadataId: labelIdentifierFieldMetadataItem?.id ?? '',
|
||||
label: labelIdentifierFieldMetadataItem?.label || '',
|
||||
metadata: {
|
||||
fieldName: labelIdentifierFieldMetadataItem?.name || '',
|
||||
objectMetadataNameSingular: objectNameSingular,
|
||||
},
|
||||
defaultValue: labelIdentifierFieldMetadataItem?.defaultValue,
|
||||
},
|
||||
defaultValue: labelIdentifierFieldMetadataItem?.defaultValue,
|
||||
},
|
||||
useUpdateRecord: useUpdateOneObjectRecordMutation,
|
||||
hotkeyScope: InlineCellHotkeyScope.InlineCell,
|
||||
isCentered: true,
|
||||
}}
|
||||
>
|
||||
<RecordInlineCell readonly={isReadOnly} isCentered={true} />
|
||||
</FieldContext.Provider>
|
||||
}
|
||||
avatarType={recordIdentifier?.avatarType ?? 'rounded'}
|
||||
onUploadPicture={
|
||||
objectNameSingular === 'person' ? onUploadPicture : undefined
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
useUpdateRecord: useUpdateOneObjectRecordMutation,
|
||||
hotkeyScope: InlineCellHotkeyScope.InlineCell,
|
||||
isCentered: true,
|
||||
}}
|
||||
>
|
||||
<RecordInlineCell readonly={isReadOnly} isCentered={true} />
|
||||
</FieldContext.Provider>
|
||||
}
|
||||
avatarType={recordIdentifier?.avatarType ?? 'rounded'}
|
||||
onUploadPicture={
|
||||
objectNameSingular === 'person' ? onUploadPicture : undefined
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<ShowPageSummaryCardSkeletonLoader />
|
||||
);
|
||||
|
||||
const fieldsBox = (
|
||||
<>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
|
||||
const StyledSkeletonContainer = styled.div`
|
||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||
@@ -15,7 +16,10 @@ const StyledRecordTableCellLoader = ({ width }: { width?: number }) => {
|
||||
highlightColor={theme.background.transparent.lighter}
|
||||
borderRadius={4}
|
||||
>
|
||||
<Skeleton width={width} height={16} />
|
||||
<Skeleton
|
||||
width={width}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
|
||||
/>
|
||||
</SkeletonTheme>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
|
||||
export const SupportButtonSkeletonLoader = () => {
|
||||
const theme = useTheme();
|
||||
@@ -9,7 +10,7 @@ export const SupportButtonSkeletonLoader = () => {
|
||||
highlightColor={theme.background.transparent.lighter}
|
||||
borderRadius={4}
|
||||
>
|
||||
<Skeleton width={84} height={24} />
|
||||
<Skeleton width={84} height={SKELETON_LOADER_HEIGHT_SIZES.standard.m} />
|
||||
</SkeletonTheme>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
|
||||
const StyledDropdownMenuSkeletonContainer = styled.div`
|
||||
--horizontal-padding: ${({ theme }) => theme.spacing(1)};
|
||||
@@ -21,7 +22,7 @@ export const DropdownMenuSkeletonItem = () => {
|
||||
baseColor={theme.background.quaternary}
|
||||
highlightColor={theme.background.secondary}
|
||||
>
|
||||
<Skeleton height={16} />
|
||||
<Skeleton height={SKELETON_LOADER_HEIGHT_SIZES.standard.s} />
|
||||
</SkeletonTheme>
|
||||
</StyledDropdownMenuSkeletonContainer>
|
||||
);
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Chip, ChipAccent, ChipSize, useIcons } from 'twenty-ui';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
|
||||
import { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading';
|
||||
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
||||
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
|
||||
import { RightDrawerTopBarCloseButton } from '@/ui/layout/right-drawer/components/RightDrawerTopBarCloseButton';
|
||||
@@ -66,6 +67,10 @@ export const RightDrawerTopBar = () => {
|
||||
viewableRecordNameSingularState,
|
||||
);
|
||||
|
||||
const isNewViewableRecordLoading = useRecoilValue(
|
||||
isNewViewableRecordLoadingState,
|
||||
);
|
||||
|
||||
const viewableRecordId = useRecoilValue(viewableRecordIdState);
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
@@ -95,6 +100,7 @@ export const RightDrawerTopBar = () => {
|
||||
>
|
||||
{!isRightDrawerMinimized && (
|
||||
<Chip
|
||||
disabled={isNewViewableRecordLoading}
|
||||
label={label}
|
||||
leftComponent={<Icon size={theme.icon.size.md} />}
|
||||
size={ChipSize.Large}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { RichTextEditor } from '@/activities/components/RichTextEditor';
|
||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading';
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
const StyledShowPageActivityContainer = styled.div`
|
||||
margin-top: ${({ theme }) => theme.spacing(6)};
|
||||
@@ -16,7 +18,11 @@ export const ShowPageActivityContainer = ({
|
||||
'targetObjectNameSingular' | 'id'
|
||||
>;
|
||||
}) => {
|
||||
return (
|
||||
const isNewViewableRecordLoading = useRecoilValue(
|
||||
isNewViewableRecordLoadingState,
|
||||
);
|
||||
|
||||
return !isNewViewableRecordLoading ? (
|
||||
<ScrollWrapper contextProviderName="showPageActivityContainer">
|
||||
<StyledShowPageActivityContainer>
|
||||
<RichTextEditor
|
||||
@@ -30,5 +36,7 @@ export const ShowPageActivityContainer = ({
|
||||
/>
|
||||
</StyledShowPageActivityContainer>
|
||||
</ScrollWrapper>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ import { TimelineActivities } from '@/activities/timelineActivities/components/T
|
||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
||||
import { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { Button } from '@/ui/input/button/components/Button';
|
||||
@@ -135,6 +136,10 @@ export const ShowPageRightContainer = ({
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const isNewViewableRecordLoading = useRecoilValue(
|
||||
isNewViewableRecordLoadingState,
|
||||
);
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
id: 'richText',
|
||||
@@ -272,7 +277,7 @@ export const ShowPageRightContainer = ({
|
||||
<StyledShowPageRightContainer isMobile={isMobile}>
|
||||
<StyledTabListContainer>
|
||||
<TabList
|
||||
loading={loading}
|
||||
loading={loading || isNewViewableRecordLoading}
|
||||
tabListId={`${TAB_LIST_COMPONENT_ID}-${isInRightDrawer}`}
|
||||
tabs={tabs}
|
||||
/>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { ChangeEvent, ReactNode, useRef } from 'react';
|
||||
@@ -88,9 +89,9 @@ const StyledShowPageSummaryCardSkeletonLoader = () => {
|
||||
highlightColor={theme.background.transparent.lighter}
|
||||
borderRadius={4}
|
||||
>
|
||||
<Skeleton width={40} height={40} />
|
||||
<Skeleton width={40} height={SKELETON_LOADER_HEIGHT_SIZES.standard.xl} />
|
||||
<StyledSubSkeleton>
|
||||
<Skeleton width={96} height={16} />
|
||||
<Skeleton width={96} height={SKELETON_LOADER_HEIGHT_SIZES.standard.s} />
|
||||
</StyledSubSkeleton>
|
||||
</SkeletonTheme>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(4)};
|
||||
height: ${({ theme }) => theme.spacing(19)};
|
||||
margin: ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
const StyledRectangularSkeleton = styled(Skeleton)`
|
||||
height: ${({ theme }) => theme.spacing(4)};
|
||||
width: ${({ theme }) => theme.spacing(24)};
|
||||
margin: ${({ theme }) => theme.spacing(1)};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
`;
|
||||
|
||||
export const ShowPageSummaryCardSkeletonLoader = () => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<SkeletonTheme
|
||||
baseColor={theme.background.tertiary}
|
||||
highlightColor={theme.background.transparent.lighter}
|
||||
>
|
||||
<StyledContainer>
|
||||
<Skeleton
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.xl}
|
||||
width={40}
|
||||
/>
|
||||
<StyledRectangularSkeleton />
|
||||
</StyledContainer>
|
||||
</SkeletonTheme>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
|
||||
const StyledSkeletonTitle = styled.div`
|
||||
margin-bottom: ${(props) => props.theme.spacing(2)};
|
||||
@@ -16,7 +17,10 @@ export const NavigationDrawerSectionTitleSkeletonLoader = () => {
|
||||
borderRadius={4}
|
||||
>
|
||||
<StyledSkeletonTitle>
|
||||
<Skeleton width={56} height={13} />
|
||||
<Skeleton
|
||||
width={56}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.xs}
|
||||
/>
|
||||
</StyledSkeletonTitle>
|
||||
</SkeletonTheme>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
|
||||
export const ViewBarSkeletonLoader = () => {
|
||||
const theme = useTheme();
|
||||
@@ -9,7 +10,7 @@ export const ViewBarSkeletonLoader = () => {
|
||||
highlightColor={theme.background.transparent.lighter}
|
||||
borderRadius={4}
|
||||
>
|
||||
<Skeleton width={140} height={16} />
|
||||
<Skeleton width={140} height={SKELETON_LOADER_HEIGHT_SIZES.standard.s} />
|
||||
</SkeletonTheme>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { Logo } from '@/auth/components/Logo';
|
||||
import { Title } from '@/auth/components/Title';
|
||||
import { useAuth } from '@/auth/hooks/useAuth';
|
||||
@@ -174,7 +175,7 @@ export const PasswordReset = () => {
|
||||
highlightColor={theme.background.secondary}
|
||||
>
|
||||
<Skeleton
|
||||
height={32}
|
||||
height={SKELETON_LOADER_HEIGHT_SIZES.standard.m}
|
||||
count={2}
|
||||
style={{
|
||||
marginBottom: theme.spacing(2),
|
||||
|
||||
Reference in New Issue
Block a user