8978 add navigation inside the command menu for showpage (#9103)
Closes #8978 - Added new options in the actions config files: `shortLabel`, `availableOn` - Added two actions: Navigate to previous records and Navigate to next records - Modified `useRecordShowPagePagination` to loop on records when we are on first record and we hit previous or when we are on last record and we hit next - Introduced a new component state `contextStoreCurrentViewTypeComponentState`
This commit is contained in:
@ -23,7 +23,9 @@ import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTabl
|
||||
import { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider';
|
||||
|
||||
import { RecordIndexActionMenu } from '@/action-menu/components/RecordIndexActionMenu';
|
||||
import { ContextStoreCurrentViewTypeEffect } from '@/context-store/components/ContextStoreCurrentViewTypeEffect';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||
import { useSetRecordGroup } from '@/object-record/record-group/hooks/useSetRecordGroup';
|
||||
import { RecordIndexFiltersToContextStoreEffect } from '@/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect';
|
||||
import { recordIndexKanbanAggregateOperationState } from '@/object-record/record-index/states/recordIndexKanbanAggregateOperationState';
|
||||
@ -164,89 +166,98 @@ export const RecordIndexContainer = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<InformationBannerWrapper />
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<SpreadsheetImportProvider>
|
||||
<ViewBar
|
||||
viewBarId={recordIndexId}
|
||||
optionsDropdownButton={
|
||||
<ObjectOptionsDropdown
|
||||
recordIndexId={recordIndexId}
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
viewType={recordIndexViewType ?? ViewType.Table}
|
||||
/>
|
||||
}
|
||||
onCurrentViewChange={(view) => {
|
||||
if (!view) {
|
||||
return;
|
||||
<>
|
||||
<ContextStoreCurrentViewTypeEffect
|
||||
viewType={
|
||||
recordIndexViewType === ViewType.Table
|
||||
? ContextStoreViewType.Table
|
||||
: ContextStoreViewType.Kanban
|
||||
}
|
||||
/>
|
||||
<StyledContainer>
|
||||
<InformationBannerWrapper />
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<SpreadsheetImportProvider>
|
||||
<ViewBar
|
||||
viewBarId={recordIndexId}
|
||||
optionsDropdownButton={
|
||||
<ObjectOptionsDropdown
|
||||
recordIndexId={recordIndexId}
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
viewType={recordIndexViewType ?? ViewType.Table}
|
||||
/>
|
||||
}
|
||||
onCurrentViewChange={(view) => {
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
|
||||
onViewFieldsChange(view.viewFields);
|
||||
onViewGroupsChange(view.viewGroups);
|
||||
setTableViewFilterGroups(view.viewFilterGroups ?? []);
|
||||
setTableFilters(
|
||||
mapViewFiltersToFilters(view.viewFilters, filterDefinitions),
|
||||
);
|
||||
setRecordIndexFilters(
|
||||
mapViewFiltersToFilters(view.viewFilters, filterDefinitions),
|
||||
);
|
||||
setRecordIndexViewFilterGroups(view.viewFilterGroups ?? []);
|
||||
setContextStoreTargetedRecordsRule((prev) => ({
|
||||
...prev,
|
||||
filters: mapViewFiltersToFilters(
|
||||
view.viewFilters,
|
||||
filterDefinitions,
|
||||
),
|
||||
}));
|
||||
setTableSorts(
|
||||
mapViewSortsToSorts(view.viewSorts, sortDefinitions),
|
||||
);
|
||||
setRecordIndexSorts(
|
||||
mapViewSortsToSorts(view.viewSorts, sortDefinitions),
|
||||
);
|
||||
setRecordIndexViewType(view.type);
|
||||
setRecordIndexViewKanbanFieldMetadataIdState(
|
||||
view.kanbanFieldMetadataId,
|
||||
);
|
||||
setRecordIndexViewKanbanAggregateOperationState({
|
||||
operation: view.kanbanAggregateOperation,
|
||||
fieldMetadataId: view.kanbanAggregateOperationFieldMetadataId,
|
||||
});
|
||||
setRecordIndexIsCompactModeActive(view.isCompact);
|
||||
}}
|
||||
/>
|
||||
<RecordIndexViewBarEffect
|
||||
objectNamePlural={objectNamePlural}
|
||||
viewBarId={recordIndexId}
|
||||
/>
|
||||
</SpreadsheetImportProvider>
|
||||
<RecordIndexFiltersToContextStoreEffect />
|
||||
{recordIndexViewType === ViewType.Table && (
|
||||
<>
|
||||
<RecordIndexTableContainer
|
||||
recordTableId={recordIndexId}
|
||||
onViewFieldsChange(view.viewFields);
|
||||
onViewGroupsChange(view.viewGroups);
|
||||
setTableViewFilterGroups(view.viewFilterGroups ?? []);
|
||||
setTableFilters(
|
||||
mapViewFiltersToFilters(view.viewFilters, filterDefinitions),
|
||||
);
|
||||
setRecordIndexFilters(
|
||||
mapViewFiltersToFilters(view.viewFilters, filterDefinitions),
|
||||
);
|
||||
setRecordIndexViewFilterGroups(view.viewFilterGroups ?? []);
|
||||
setContextStoreTargetedRecordsRule((prev) => ({
|
||||
...prev,
|
||||
filters: mapViewFiltersToFilters(
|
||||
view.viewFilters,
|
||||
filterDefinitions,
|
||||
),
|
||||
}));
|
||||
setTableSorts(
|
||||
mapViewSortsToSorts(view.viewSorts, sortDefinitions),
|
||||
);
|
||||
setRecordIndexSorts(
|
||||
mapViewSortsToSorts(view.viewSorts, sortDefinitions),
|
||||
);
|
||||
setRecordIndexViewType(view.type);
|
||||
setRecordIndexViewKanbanFieldMetadataIdState(
|
||||
view.kanbanFieldMetadataId,
|
||||
);
|
||||
setRecordIndexViewKanbanAggregateOperationState({
|
||||
operation: view.kanbanAggregateOperation,
|
||||
fieldMetadataId: view.kanbanAggregateOperationFieldMetadataId,
|
||||
});
|
||||
setRecordIndexIsCompactModeActive(view.isCompact);
|
||||
}}
|
||||
/>
|
||||
<RecordIndexViewBarEffect
|
||||
objectNamePlural={objectNamePlural}
|
||||
viewBarId={recordIndexId}
|
||||
/>
|
||||
<RecordIndexTableContainerEffect />
|
||||
</>
|
||||
)}
|
||||
{recordIndexViewType === ViewType.Kanban && (
|
||||
<StyledContainerWithPadding>
|
||||
<RecordIndexBoardContainer
|
||||
recordBoardId={recordIndexId}
|
||||
viewBarId={recordIndexId}
|
||||
objectNameSingular={objectNameSingular}
|
||||
/>
|
||||
<RecordIndexBoardDataLoader
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordBoardId={recordIndexId}
|
||||
/>
|
||||
<RecordIndexBoardDataLoaderEffect recordBoardId={recordIndexId} />
|
||||
</StyledContainerWithPadding>
|
||||
)}
|
||||
{!isPageHeaderV2Enabled && <RecordIndexActionMenu />}
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
</StyledContainer>
|
||||
</SpreadsheetImportProvider>
|
||||
<RecordIndexFiltersToContextStoreEffect />
|
||||
{recordIndexViewType === ViewType.Table && (
|
||||
<>
|
||||
<RecordIndexTableContainer
|
||||
recordTableId={recordIndexId}
|
||||
viewBarId={recordIndexId}
|
||||
/>
|
||||
<RecordIndexTableContainerEffect />
|
||||
</>
|
||||
)}
|
||||
{recordIndexViewType === ViewType.Kanban && (
|
||||
<StyledContainerWithPadding>
|
||||
<RecordIndexBoardContainer
|
||||
recordBoardId={recordIndexId}
|
||||
viewBarId={recordIndexId}
|
||||
objectNameSingular={objectNameSingular}
|
||||
/>
|
||||
<RecordIndexBoardDataLoader
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordBoardId={recordIndexId}
|
||||
/>
|
||||
<RecordIndexBoardDataLoaderEffect recordBoardId={recordIndexId} />
|
||||
</StyledContainerWithPadding>
|
||||
)}
|
||||
{!isPageHeaderV2Enabled && <RecordIndexActionMenu />}
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
</StyledContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
/* eslint-disable @nx/workspace-no-navigate-prefer-link */
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useState } from 'react';
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
@ -11,6 +10,7 @@ import { useRecordIdsFromFindManyCacheRootQuery } from '@/object-record/record-s
|
||||
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 { isDefined } from 'twenty-ui';
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
|
||||
export const useRecordShowPagePagination = (
|
||||
@ -100,22 +100,43 @@ export const useRecordShowPagePagination = (
|
||||
|
||||
const loading = loadingRecordAfter || loadingRecordBefore || loadingCursor;
|
||||
|
||||
const isThereARecordBefore = recordsBefore.length > 0;
|
||||
const isThereARecordAfter = recordsAfter.length > 0;
|
||||
|
||||
const recordBefore = recordsBefore[0];
|
||||
const recordAfter = recordsAfter[0];
|
||||
|
||||
const { recordIdsInCache } = useRecordIdsFromFindManyCacheRootQuery({
|
||||
objectNamePlural: objectMetadataItem.namePlural,
|
||||
fieldVariables: {
|
||||
filter,
|
||||
orderBy,
|
||||
},
|
||||
});
|
||||
|
||||
const navigateToPreviousRecord = () => {
|
||||
navigate(
|
||||
buildShowPageURL(objectNameSingular, recordBefore.id, viewIdQueryParam),
|
||||
);
|
||||
if (isDefined(recordBefore)) {
|
||||
navigate(
|
||||
buildShowPageURL(objectNameSingular, recordBefore.id, viewIdQueryParam),
|
||||
);
|
||||
}
|
||||
if (!loadingRecordBefore && !isDefined(recordBefore)) {
|
||||
const firstRecordId = recordIdsInCache[recordIdsInCache.length - 1];
|
||||
navigate(
|
||||
buildShowPageURL(objectNameSingular, firstRecordId, viewIdQueryParam),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const navigateToNextRecord = () => {
|
||||
navigate(
|
||||
buildShowPageURL(objectNameSingular, recordAfter.id, viewIdQueryParam),
|
||||
);
|
||||
if (isDefined(recordAfter)) {
|
||||
navigate(
|
||||
buildShowPageURL(objectNameSingular, recordAfter.id, viewIdQueryParam),
|
||||
);
|
||||
}
|
||||
if (!loadingRecordAfter && !isDefined(recordAfter)) {
|
||||
const lastRecordId = recordIdsInCache[0];
|
||||
navigate(
|
||||
buildShowPageURL(objectNameSingular, lastRecordId, viewIdQueryParam),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const navigateToIndexView = () => {
|
||||
@ -129,31 +150,21 @@ export const useRecordShowPagePagination = (
|
||||
navigate(indexTableURL);
|
||||
};
|
||||
|
||||
const { recordIdsInCache } = useRecordIdsFromFindManyCacheRootQuery({
|
||||
objectNamePlural: objectMetadataItem.namePlural,
|
||||
fieldVariables: {
|
||||
filter,
|
||||
orderBy,
|
||||
},
|
||||
});
|
||||
|
||||
const rankInView = recordIdsInCache.findIndex((id) => id === objectRecordId);
|
||||
|
||||
const rankFoundInFiew = rankInView > -1;
|
||||
const rankFoundInView = rankInView > -1;
|
||||
|
||||
const objectLabel = capitalize(objectMetadataItem.labelPlural);
|
||||
|
||||
const totalCount = Math.max(1, totalCountBefore, totalCountAfter);
|
||||
|
||||
const viewNameWithCount = rankFoundInFiew
|
||||
const viewNameWithCount = rankFoundInView
|
||||
? `${rankInView + 1} of ${totalCount} in ${objectLabel}`
|
||||
: `${objectLabel} (${totalCount})`;
|
||||
|
||||
return {
|
||||
viewName: viewNameWithCount,
|
||||
hasPreviousRecord: isThereARecordBefore,
|
||||
isLoadingPagination: loading,
|
||||
hasNextRecord: isThereARecordAfter,
|
||||
navigateToPreviousRecord,
|
||||
navigateToNextRecord,
|
||||
navigateToIndexView,
|
||||
|
||||
Reference in New Issue
Block a user