Fix post merge revamp navigation bar (#6297)
Closes #6285 @charlesBochet Also added some more utils for our component state v2.
This commit is contained in:
@ -209,15 +209,16 @@ export const useFetchMoreRecordsWithPagination = <
|
||||
|
||||
const totalCount = data?.[objectMetadataItem.namePlural]?.totalCount;
|
||||
|
||||
const recordConnection = data?.[objectMetadataItem.namePlural];
|
||||
|
||||
const records = useMemo(
|
||||
() =>
|
||||
data?.[objectMetadataItem.namePlural]
|
||||
isDefined(recordConnection)
|
||||
? getRecordsFromRecordConnection<T>({
|
||||
recordConnection: data?.[objectMetadataItem.namePlural],
|
||||
recordConnection,
|
||||
})
|
||||
: ([] as T[]),
|
||||
|
||||
[data, objectMetadataItem.namePlural],
|
||||
: [],
|
||||
[recordConnection],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@ -13,7 +13,7 @@ import {
|
||||
RecordUpdateHookParams,
|
||||
} from '@/object-record/record-field/contexts/FieldContext';
|
||||
import { getFieldButtonIcon } from '@/object-record/record-field/utils/getFieldButtonIcon';
|
||||
import { RecordIndexRecordChip } from '@/object-record/record-index/components/RecordIndexRecordChip';
|
||||
import { RecordIdentifierChip } from '@/object-record/record-index/components/RecordIndexRecordChip';
|
||||
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
|
||||
import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope';
|
||||
import { RecordValueSetterEffect } from '@/object-record/record-store/components/RecordValueSetterEffect';
|
||||
@ -222,7 +222,7 @@ export const RecordBoardCard = () => {
|
||||
}}
|
||||
>
|
||||
<StyledBoardCardHeader showCompactView={isCompactModeActive}>
|
||||
<RecordIndexRecordChip
|
||||
<RecordIdentifierChip
|
||||
objectNameSingular={objectMetadataItem.nameSingular}
|
||||
record={record}
|
||||
variant={AvatarChipVariant.Transparent}
|
||||
|
||||
@ -4,7 +4,8 @@ import { BooleanFieldDisplay } from '@/object-record/record-field/meta-types/dis
|
||||
import { LinksFieldDisplay } from '@/object-record/record-field/meta-types/display/components/LinksFieldDisplay';
|
||||
import { RatingFieldDisplay } from '@/object-record/record-field/meta-types/display/components/RatingFieldDisplay';
|
||||
import { RelationFromManyFieldDisplay } from '@/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay';
|
||||
import { isFieldChipDisplay } from '@/object-record/record-field/meta-types/display/utils/isFieldChipDisplay';
|
||||
|
||||
import { isFieldIdentifierDisplay } from '@/object-record/record-field/meta-types/display/utils/isFieldIdentifierDisplay';
|
||||
import { isFieldBoolean } from '@/object-record/record-field/types/guards/isFieldBoolean';
|
||||
import { isFieldDisplayedAsPhone } from '@/object-record/record-field/types/guards/isFieldDisplayedAsPhone';
|
||||
import { isFieldLinks } from '@/object-record/record-field/types/guards/isFieldLinks';
|
||||
@ -46,7 +47,10 @@ import { isFieldUuid } from '../types/guards/isFieldUuid';
|
||||
export const FieldDisplay = () => {
|
||||
const { fieldDefinition, isLabelIdentifier } = useContext(FieldContext);
|
||||
|
||||
const isChipDisplay = isFieldChipDisplay(fieldDefinition, isLabelIdentifier);
|
||||
const isChipDisplay = isFieldIdentifierDisplay(
|
||||
fieldDefinition,
|
||||
isLabelIdentifier,
|
||||
);
|
||||
|
||||
return isChipDisplay ? (
|
||||
<ChipFieldDisplay />
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { RecordChip } from '@/object-record/components/RecordChip';
|
||||
import { useChipFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useChipFieldDisplay';
|
||||
import { RecordIndexRecordChip } from '@/object-record/record-index/components/RecordIndexRecordChip';
|
||||
import { RecordIdentifierChip } from '@/object-record/record-index/components/RecordIndexRecordChip';
|
||||
|
||||
export const ChipFieldDisplay = () => {
|
||||
const { recordValue, objectNameSingular, isLabelIdentifier } =
|
||||
@ -11,7 +11,7 @@ export const ChipFieldDisplay = () => {
|
||||
}
|
||||
|
||||
return isLabelIdentifier ? (
|
||||
<RecordIndexRecordChip
|
||||
<RecordIdentifierChip
|
||||
objectNameSingular={objectNameSingular}
|
||||
record={recordValue}
|
||||
/>
|
||||
|
||||
@ -3,7 +3,7 @@ import { isFieldFullName } from '@/object-record/record-field/types/guards/isFie
|
||||
import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber';
|
||||
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
|
||||
|
||||
export const isFieldChipDisplay = (
|
||||
export const isFieldIdentifierDisplay = (
|
||||
field: Pick<FieldMetadataItem, 'type'>,
|
||||
isLabelIdentifier: boolean,
|
||||
) =>
|
||||
@ -1,17 +1,10 @@
|
||||
import styled from '@emotion/styled';
|
||||
import {
|
||||
useRecoilCallback,
|
||||
useRecoilState,
|
||||
useRecoilValue,
|
||||
useSetRecoilState,
|
||||
} from 'recoil';
|
||||
import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||
import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId';
|
||||
import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter';
|
||||
import { RecordIndexBoardContainer } from '@/object-record/record-index/components/RecordIndexBoardContainer';
|
||||
import { RecordIndexBoardDataLoader } from '@/object-record/record-index/components/RecordIndexBoardDataLoader';
|
||||
import { RecordIndexBoardDataLoaderEffect } from '@/object-record/record-index/components/RecordIndexBoardDataLoaderEffect';
|
||||
@ -26,22 +19,17 @@ import { recordIndexIsCompactModeActiveState } from '@/object-record/record-inde
|
||||
import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState';
|
||||
import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState';
|
||||
import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState';
|
||||
import { useFindRecordCursorFromFindManyCacheRootQuery } from '@/object-record/record-show/hooks/useFindRecordCursorFromFindManyCacheRootQuery';
|
||||
import { findView } from '@/object-record/record-show/hooks/useRecordShowPagePagination';
|
||||
|
||||
import { useHandleIndexIdentifierClick } from '@/object-record/record-index/hooks/useHandleIndexIdentifierClick';
|
||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider';
|
||||
import { ViewBar } from '@/views/components/ViewBar';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { View } from '@/views/types/View';
|
||||
import { ViewField } from '@/views/types/ViewField';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions';
|
||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
@ -124,54 +112,11 @@ export const RecordIndexContainer = ({
|
||||
[columnDefinitions, setTableColumns],
|
||||
);
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
|
||||
const currentViewId = useRecoilValue(
|
||||
currentViewIdComponentState({
|
||||
scopeId: recordIndexId,
|
||||
}),
|
||||
);
|
||||
|
||||
const view = findView({
|
||||
objectMetadataItemId: objectMetadataItem?.id ?? '',
|
||||
viewId: currentViewId ?? null,
|
||||
views,
|
||||
});
|
||||
|
||||
const filter = turnObjectDropdownFilterIntoQueryFilter(
|
||||
mapViewFiltersToFilters(view?.viewFilters ?? [], filterDefinitions),
|
||||
objectMetadataItem?.fields ?? [],
|
||||
);
|
||||
|
||||
const orderBy = turnSortsIntoOrderBy(
|
||||
const { handleIndexIdentifierClick } = useHandleIndexIdentifierClick({
|
||||
objectMetadataItem,
|
||||
mapViewSortsToSorts(view?.viewSorts ?? [], sortDefinitions),
|
||||
);
|
||||
|
||||
const { findCursorInCache } = useFindRecordCursorFromFindManyCacheRootQuery({
|
||||
fieldVariables: {
|
||||
filter,
|
||||
orderBy,
|
||||
},
|
||||
objectNamePlural: objectNamePlural,
|
||||
recordIndexId,
|
||||
});
|
||||
|
||||
const handleIndexIdentifierClick = (recordId: string) => {
|
||||
const cursor = findCursorInCache(recordId);
|
||||
|
||||
// TODO: use URL builder
|
||||
navigate(
|
||||
`/object/${objectNameSingular}/${recordId}?view=${currentViewId}`,
|
||||
{
|
||||
state: {
|
||||
cursor,
|
||||
},
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
const handleIndexRecordsLoaded = useRecoilCallback(
|
||||
({ set }) =>
|
||||
() => {
|
||||
|
||||
@ -5,17 +5,17 @@ import { RecordIndexEventContext } from '@/object-record/record-index/contexts/R
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { useContext } from 'react';
|
||||
|
||||
export type RecordIndexRecordChipProps = {
|
||||
export type RecordIdentifierChipProps = {
|
||||
objectNameSingular: string;
|
||||
record: ObjectRecord;
|
||||
variant?: AvatarChipVariant;
|
||||
};
|
||||
|
||||
export const RecordIndexRecordChip = ({
|
||||
export const RecordIdentifierChip = ({
|
||||
objectNameSingular,
|
||||
record,
|
||||
variant,
|
||||
}: RecordIndexRecordChipProps) => {
|
||||
}: RecordIdentifierChipProps) => {
|
||||
const { onIndexIdentifierClick } = useContext(RecordIndexEventContext);
|
||||
|
||||
const { recordChipData } = useRecordChipData({
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { buildShowPageURL } from '@/object-record/record-show/utils/buildShowPageURL';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
export const useHandleIndexIdentifierClick = ({
|
||||
objectMetadataItem,
|
||||
recordIndexId,
|
||||
}: {
|
||||
recordIndexId: string;
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const currentViewId = useRecoilValue(
|
||||
currentViewIdComponentState({
|
||||
scopeId: recordIndexId,
|
||||
}),
|
||||
);
|
||||
|
||||
const handleIndexIdentifierClick = (recordId: string) => {
|
||||
const showPageURL = buildShowPageURL(
|
||||
objectMetadataItem.nameSingular,
|
||||
recordId,
|
||||
currentViewId,
|
||||
);
|
||||
|
||||
navigate(showPageURL);
|
||||
};
|
||||
|
||||
return { handleIndexIdentifierClick };
|
||||
};
|
||||
@ -1,11 +1,10 @@
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { RecordGqlOperationSignatureFactory } from '@/object-record/graphql/types/RecordGqlOperationSignatureFactory';
|
||||
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
|
||||
|
||||
export const findOneRecordForShowPageOperationSignatureFactory: RecordGqlOperationSignatureFactory =
|
||||
export const buildFindOneRecordForShowPageOperationSignature: RecordGqlOperationSignatureFactory =
|
||||
({ objectMetadataItem }: { objectMetadataItem: ObjectMetadataItem }) => ({
|
||||
objectNameSingular: CoreObjectNameSingular.Activity,
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
variables: {},
|
||||
fields: generateDepthOneRecordGqlFields({ objectMetadataItem }),
|
||||
});
|
||||
|
||||
@ -7,7 +7,7 @@ import { useFavorites } from '@/favorites/hooks/useFavorites';
|
||||
import { useLabelIdentifierFieldMetadataItem } from '@/object-metadata/hooks/useLabelIdentifierFieldMetadataItem';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||
import { findOneRecordForShowPageOperationSignatureFactory } from '@/object-record/record-show/graphql/operations/factories/findOneRecordForShowPageOperationSignatureFactory';
|
||||
import { buildFindOneRecordForShowPageOperationSignature } from '@/object-record/record-show/graphql/operations/factories/findOneRecordForShowPageOperationSignatureFactory';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
@ -39,7 +39,8 @@ export const useRecordShowPage = (
|
||||
const { getIcon } = useIcons();
|
||||
const headerIcon = getIcon(objectMetadataItem?.icon);
|
||||
const FIND_ONE_RECORD_FOR_SHOW_PAGE_OPERATION_SIGNATURE =
|
||||
findOneRecordForShowPageOperationSignatureFactory({ objectMetadataItem });
|
||||
buildFindOneRecordForShowPageOperationSignature({ objectMetadataItem });
|
||||
|
||||
const { record, loading } = useFindOneRecord({
|
||||
objectRecordId,
|
||||
objectNameSingular,
|
||||
|
||||
@ -1,52 +1,19 @@
|
||||
/* eslint-disable @nx/workspace-no-navigate-prefer-link */
|
||||
import { useMemo, useState } from 'react';
|
||||
import {
|
||||
useLocation,
|
||||
useNavigate,
|
||||
useParams,
|
||||
useSearchParams,
|
||||
} from 'react-router-dom';
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { formatFieldMetadataItemsAsFilterDefinitions } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { formatFieldMetadataItemsAsSortDefinitions } from '@/object-metadata/utils/formatFieldMetadataItemsAsSortDefinitions';
|
||||
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||
import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId';
|
||||
import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter';
|
||||
import { useRecordIdsFromFindManyCacheRootQuery } from '@/object-record/record-show/hooks/useRecordIdsFromFindManyCacheRootQuery';
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { View } from '@/views/types/View';
|
||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
|
||||
import { buildShowPageURL } from '@/object-record/record-show/utils/buildShowPageURL';
|
||||
import { buildIndexTablePageURL } from '@/object-record/record-table/utils/buildIndexTableURL';
|
||||
import { useQueryVariablesFromActiveFieldsOfViewOrDefaultView } from '@/views/hooks/useQueryVariablesFromActiveFieldsOfViewOrDefaultView';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { getRelayCursorFromRecordId } from '~/utils/getRelayCursorFromRecordId';
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
|
||||
export const findView = ({
|
||||
viewId,
|
||||
objectMetadataItemId,
|
||||
views,
|
||||
}: {
|
||||
viewId: string | null;
|
||||
objectMetadataItemId: string;
|
||||
views: View[];
|
||||
}) => {
|
||||
if (!viewId) {
|
||||
return views.find(
|
||||
(view: any) =>
|
||||
view.key === 'INDEX' && view?.objectMetadataId === objectMetadataItemId,
|
||||
) as View;
|
||||
} else {
|
||||
return views.find(
|
||||
(view: any) =>
|
||||
view?.id === viewId && view?.objectMetadataId === objectMetadataItemId,
|
||||
) as View;
|
||||
}
|
||||
};
|
||||
|
||||
export const useRecordShowPagePagination = (
|
||||
propsObjectNameSingular: string,
|
||||
propsObjectRecordId: string,
|
||||
@ -61,8 +28,6 @@ export const useRecordShowPagePagination = (
|
||||
|
||||
const setLastShowPageRecordId = useSetRecoilState(lastShowPageRecordIdState);
|
||||
|
||||
const [isLoadedRecords] = useState(false);
|
||||
|
||||
const objectNameSingular = propsObjectNameSingular || paramObjectNameSingular;
|
||||
const objectRecordId = propsObjectRecordId || paramObjectRecordId;
|
||||
|
||||
@ -71,77 +36,26 @@ export const useRecordShowPagePagination = (
|
||||
}
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular });
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
|
||||
const view = useMemo(() => {
|
||||
return findView({
|
||||
objectMetadataItemId: objectMetadataItem?.id ?? '',
|
||||
viewId: viewIdQueryParam,
|
||||
views,
|
||||
});
|
||||
}, [viewIdQueryParam, objectMetadataItem, views]);
|
||||
|
||||
const activeFieldMetadataItems = useMemo(
|
||||
() =>
|
||||
objectMetadataItem
|
||||
? objectMetadataItem.fields.filter(
|
||||
({ isActive, isSystem }) => isActive && !isSystem,
|
||||
)
|
||||
: [],
|
||||
[objectMetadataItem],
|
||||
);
|
||||
|
||||
const filterDefinitions = formatFieldMetadataItemsAsFilterDefinitions({
|
||||
fields: activeFieldMetadataItems,
|
||||
});
|
||||
|
||||
const sortDefinitions = formatFieldMetadataItemsAsSortDefinitions({
|
||||
fields: activeFieldMetadataItems,
|
||||
});
|
||||
|
||||
const filter = turnObjectDropdownFilterIntoQueryFilter(
|
||||
mapViewFiltersToFilters(view?.viewFilters ?? [], filterDefinitions),
|
||||
objectMetadataItem?.fields ?? [],
|
||||
);
|
||||
|
||||
const orderBy = turnSortsIntoOrderBy(
|
||||
objectMetadataItem,
|
||||
mapViewSortsToSorts(view?.viewSorts ?? [], sortDefinitions),
|
||||
);
|
||||
|
||||
const recordGqlFields = generateDepthOneRecordGqlFields({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
const { state } = useLocation();
|
||||
|
||||
const cursorFromIndexPage = state?.cursor;
|
||||
|
||||
const { loading: loadingCurrentRecord, pageInfo: currentRecordsPageInfo } =
|
||||
useFindManyRecords({
|
||||
filter: {
|
||||
id: { eq: objectRecordId },
|
||||
},
|
||||
orderBy,
|
||||
skip: isLoadedRecords,
|
||||
limit: 1,
|
||||
objectNameSingular,
|
||||
recordGqlFields,
|
||||
const { filter, orderBy } =
|
||||
useQueryVariablesFromActiveFieldsOfViewOrDefaultView({
|
||||
objectMetadataItem,
|
||||
viewId: viewIdQueryParam,
|
||||
});
|
||||
|
||||
const currentRecordCursor = currentRecordsPageInfo?.endCursor;
|
||||
|
||||
const cursor = cursorFromIndexPage ?? currentRecordCursor;
|
||||
const cursor = getRelayCursorFromRecordId(objectRecordId);
|
||||
|
||||
const {
|
||||
loading: loadingRecordBefore,
|
||||
records: recordsBefore,
|
||||
pageInfo: pageInfoBefore,
|
||||
totalCount: totalCountBefore,
|
||||
} = useFindManyRecords({
|
||||
filter,
|
||||
orderBy,
|
||||
skip: isLoadedRecords,
|
||||
cursorFilter: isNonEmptyString(cursor)
|
||||
? {
|
||||
cursorDirection: 'before',
|
||||
@ -156,12 +70,10 @@ export const useRecordShowPagePagination = (
|
||||
const {
|
||||
loading: loadingRecordAfter,
|
||||
records: recordsAfter,
|
||||
pageInfo: pageInfoAfter,
|
||||
totalCount: totalCountAfter,
|
||||
} = useFindManyRecords({
|
||||
filter,
|
||||
orderBy,
|
||||
skip: isLoadedRecords,
|
||||
cursorFilter: cursor
|
||||
? {
|
||||
cursorDirection: 'after',
|
||||
@ -175,8 +87,7 @@ export const useRecordShowPagePagination = (
|
||||
|
||||
const totalCount = Math.max(totalCountBefore ?? 0, totalCountAfter ?? 0);
|
||||
|
||||
const loading =
|
||||
loadingRecordAfter || loadingRecordBefore || loadingCurrentRecord;
|
||||
const loading = loadingRecordAfter || loadingRecordBefore;
|
||||
|
||||
const isThereARecordBefore = recordsBefore.length > 0;
|
||||
const isThereARecordAfter = recordsAfter.length > 0;
|
||||
@ -184,43 +95,27 @@ export const useRecordShowPagePagination = (
|
||||
const recordBefore = recordsBefore[0];
|
||||
const recordAfter = recordsAfter[0];
|
||||
|
||||
const recordBeforeCursor = pageInfoBefore?.endCursor;
|
||||
const recordAfterCursor = pageInfoAfter?.endCursor;
|
||||
|
||||
const navigateToPreviousRecord = () => {
|
||||
navigate(
|
||||
`/object/${objectNameSingular}/${recordBefore.id}${
|
||||
viewIdQueryParam ? `?view=${viewIdQueryParam}` : ''
|
||||
}`,
|
||||
{
|
||||
state: {
|
||||
cursor: recordBeforeCursor,
|
||||
},
|
||||
},
|
||||
buildShowPageURL(objectNameSingular, recordBefore.id, viewIdQueryParam),
|
||||
);
|
||||
};
|
||||
|
||||
const navigateToNextRecord = () => {
|
||||
navigate(
|
||||
`/object/${objectNameSingular}/${recordAfter.id}${
|
||||
viewIdQueryParam ? `?view=${viewIdQueryParam}` : ''
|
||||
}`,
|
||||
{
|
||||
state: {
|
||||
cursor: recordAfterCursor,
|
||||
},
|
||||
},
|
||||
buildShowPageURL(objectNameSingular, recordAfter.id, viewIdQueryParam),
|
||||
);
|
||||
};
|
||||
|
||||
const navigateToIndexView = () => {
|
||||
const indexPath = `/objects/${objectMetadataItem.namePlural}${
|
||||
viewIdQueryParam ? `?view=${viewIdQueryParam}` : ''
|
||||
}`;
|
||||
const indexTableURL = buildIndexTablePageURL(
|
||||
objectMetadataItem.namePlural,
|
||||
viewIdQueryParam,
|
||||
);
|
||||
|
||||
setLastShowPageRecordId(objectRecordId);
|
||||
|
||||
navigate(indexPath);
|
||||
navigate(indexTableURL);
|
||||
};
|
||||
|
||||
const { recordIdsInCache } = useRecordIdsFromFindManyCacheRootQuery({
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
export const buildShowPageURL = (
|
||||
objectNameSingular: string,
|
||||
recordId: string,
|
||||
viewId?: string | null | undefined,
|
||||
) => {
|
||||
return `/object/${objectNameSingular}/${recordId}${
|
||||
viewId ? `?view=${viewId}` : ''
|
||||
}`;
|
||||
};
|
||||
@ -0,0 +1 @@
|
||||
export const ROW_HEIGHT = 32;
|
||||
@ -24,17 +24,18 @@ export const useSetRecordTableData = ({
|
||||
|
||||
return useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
<T extends ObjectRecord>(newEntityArray: T[], totalCount?: number) => {
|
||||
for (const entity of newEntityArray) {
|
||||
<T extends ObjectRecord>(newRecords: T[], totalCount?: number) => {
|
||||
for (const record of newRecords) {
|
||||
// TODO: refactor with scoped state later
|
||||
const currentEntity = snapshot
|
||||
.getLoadable(recordStoreFamilyState(entity.id))
|
||||
const currentRecord = snapshot
|
||||
.getLoadable(recordStoreFamilyState(record.id))
|
||||
.getValue();
|
||||
|
||||
if (JSON.stringify(currentEntity) !== JSON.stringify(entity)) {
|
||||
set(recordStoreFamilyState(entity.id), entity);
|
||||
if (JSON.stringify(currentRecord) !== JSON.stringify(record)) {
|
||||
set(recordStoreFamilyState(record.id), record);
|
||||
}
|
||||
}
|
||||
|
||||
const currentRowIds = getSnapshotValue(snapshot, tableRowIdsState);
|
||||
|
||||
const hasUserSelectedAllRows = getSnapshotValue(
|
||||
@ -42,7 +43,7 @@ export const useSetRecordTableData = ({
|
||||
hasUserSelectedAllRowsState,
|
||||
);
|
||||
|
||||
const entityIds = newEntityArray.map((entity) => entity.id);
|
||||
const entityIds = newRecords.map((entity) => entity.id);
|
||||
|
||||
if (!isDeeplyEqual(currentRowIds, entityIds)) {
|
||||
set(tableRowIdsState, entityIds);
|
||||
|
||||
@ -4,6 +4,7 @@ import { useDebouncedCallback } from 'use-debounce';
|
||||
|
||||
import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId';
|
||||
import { useLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLoadRecordIndexTable';
|
||||
import { ROW_HEIGHT } from '@/object-record/record-table/constants/RowHeight';
|
||||
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
||||
import { isRecordTableScrolledLeftComponentState } from '@/object-record/record-table/states/isRecordTableScrolledLeftComponentState';
|
||||
@ -13,11 +14,8 @@ import { scrollLeftState } from '@/ui/utilities/scroll/states/scrollLeftState';
|
||||
import { scrollTopState } from '@/ui/utilities/scroll/states/scrollTopState';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useScrollRestoration } from '~/hooks/useScrollRestoration';
|
||||
import { useScrollToPosition } from '~/hooks/useScrollToPosition';
|
||||
|
||||
export const ROW_HEIGHT = 32;
|
||||
|
||||
export const RecordTableBodyEffect = () => {
|
||||
const { objectNameSingular } = useContext(RecordTableContext);
|
||||
|
||||
@ -30,6 +28,7 @@ export const RecordTableBodyEffect = () => {
|
||||
setRecordTableData,
|
||||
loading,
|
||||
queryStateIdentifier,
|
||||
cursorsByRecordId,
|
||||
} = useLoadRecordIndexTable(objectNameSingular);
|
||||
|
||||
const isFetchingMoreObjects = useRecoilValue(
|
||||
@ -45,6 +44,7 @@ export const RecordTableBodyEffect = () => {
|
||||
isRecordTableScrolledTopComponentState,
|
||||
);
|
||||
|
||||
// TODO: move this outside because it might cause way too many re-renders for other hooks
|
||||
useEffect(() => {
|
||||
setIsRecordTableScrolledTop(scrollTop === 0);
|
||||
if (scrollTop > 0) {
|
||||
@ -83,9 +83,6 @@ export const RecordTableBodyEffect = () => {
|
||||
}
|
||||
}, [scrollLeft, setIsRecordTableScrolledLeft]);
|
||||
|
||||
const rowHeight = ROW_HEIGHT;
|
||||
const viewportHeight = records.length * rowHeight;
|
||||
|
||||
const [lastShowPageRecordId, setLastShowPageRecordId] = useRecoilState(
|
||||
lastShowPageRecordIdState,
|
||||
);
|
||||
@ -121,13 +118,11 @@ export const RecordTableBodyEffect = () => {
|
||||
setLastShowPageRecordId,
|
||||
]);
|
||||
|
||||
useScrollRestoration(viewportHeight);
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading) {
|
||||
setRecordTableData(records, totalCount);
|
||||
}
|
||||
}, [records, totalCount, setRecordTableData, loading]);
|
||||
}, [records, totalCount, setRecordTableData, loading, cursorsByRecordId]);
|
||||
|
||||
const fetchMoreDebouncedIfRequested = useDebouncedCallback(async () => {
|
||||
// We are debouncing here to give the user some room to scroll if they want to within this throttle window
|
||||
|
||||
@ -4,6 +4,7 @@ import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/Co
|
||||
|
||||
import { ColumnDefinition } from '../../types/ColumnDefinition';
|
||||
|
||||
// TODO: separate scope contexts from event contexts
|
||||
type RecordTableScopeInternalContextProps = ComponentStateKey & {
|
||||
onColumnsChange: (columns: ColumnDefinition<FieldMetadata>[]) => void;
|
||||
};
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
export const buildIndexTablePageURL = (
|
||||
objectNamePlural: string,
|
||||
viewId?: string | null | undefined,
|
||||
) => {
|
||||
return `/objects/${objectNamePlural}${viewId ? `?view=${viewId}` : ''}`;
|
||||
};
|
||||
@ -8,7 +8,7 @@ import { getAvatarUrl } from '@/object-metadata/utils/getAvatarUrl';
|
||||
import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem';
|
||||
import { getLabelIdentifierFieldValue } from '@/object-metadata/utils/getLabelIdentifierFieldValue';
|
||||
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
|
||||
import { isFieldChipDisplay } from '@/object-record/record-field/meta-types/display/utils/isFieldChipDisplay';
|
||||
import { isFieldIdentifierDisplay } from '@/object-record/record-field/meta-types/display/utils/isFieldIdentifierDisplay';
|
||||
import { RecordChipData } from '@/object-record/record-field/types/RecordChipData';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
@ -34,7 +34,7 @@ export const getRecordChipGenerators = (
|
||||
(fieldMetadataItem) =>
|
||||
labelIdentifierFieldMetadataItem?.id === fieldMetadataItem.id ||
|
||||
fieldMetadataItem.type === FieldMetadataType.Relation ||
|
||||
isFieldChipDisplay(
|
||||
isFieldIdentifierDisplay(
|
||||
fieldMetadataItem,
|
||||
isLabelIdentifierField({
|
||||
fieldMetadataItem: fieldMetadataItem,
|
||||
|
||||
Reference in New Issue
Block a user