kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
Merge branch 'entity-pos' into 'develop'
EntityStore: allow customizing import position See merge request soapbox-pub/soapbox!2430environments/review-develop-3zknud/deployments/3137
commit
75045a5eff
|
@ -110,7 +110,7 @@ test('import entities with override', () => {
|
|||
|
||||
const now = new Date();
|
||||
|
||||
const action = entitiesFetchSuccess(entities, 'TestEntity', 'thingies', {
|
||||
const action = entitiesFetchSuccess(entities, 'TestEntity', 'thingies', 'end', {
|
||||
next: undefined,
|
||||
prev: undefined,
|
||||
totalCount: 2,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { Entity, EntityListState } from './types';
|
||||
import type { Entity, EntityListState, ImportPosition } from './types';
|
||||
|
||||
const ENTITIES_IMPORT = 'ENTITIES_IMPORT' as const;
|
||||
const ENTITIES_DELETE = 'ENTITIES_DELETE' as const;
|
||||
|
@ -10,12 +10,13 @@ const ENTITIES_FETCH_FAIL = 'ENTITIES_FETCH_FAIL' as const;
|
|||
const ENTITIES_INVALIDATE_LIST = 'ENTITIES_INVALIDATE_LIST' as const;
|
||||
|
||||
/** Action to import entities into the cache. */
|
||||
function importEntities(entities: Entity[], entityType: string, listKey?: string) {
|
||||
function importEntities(entities: Entity[], entityType: string, listKey?: string, pos?: ImportPosition) {
|
||||
return {
|
||||
type: ENTITIES_IMPORT,
|
||||
entityType,
|
||||
entities,
|
||||
listKey,
|
||||
pos,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -62,6 +63,7 @@ function entitiesFetchSuccess(
|
|||
entities: Entity[],
|
||||
entityType: string,
|
||||
listKey?: string,
|
||||
pos?: ImportPosition,
|
||||
newState?: EntityListState,
|
||||
overwrite = false,
|
||||
) {
|
||||
|
@ -70,6 +72,7 @@ function entitiesFetchSuccess(
|
|||
entityType,
|
||||
entities,
|
||||
listKey,
|
||||
pos,
|
||||
newState,
|
||||
overwrite,
|
||||
};
|
||||
|
|
|
@ -30,7 +30,7 @@ function useCreateEntity<TEntity extends Entity = Entity, Data = unknown>(
|
|||
const entity = schema.parse(result.data);
|
||||
|
||||
// TODO: optimistic updating
|
||||
dispatch(importEntities([entity], entityType, listKey));
|
||||
dispatch(importEntities([entity], entityType, listKey, 'start'));
|
||||
|
||||
if (callbacks.onSuccess) {
|
||||
callbacks.onSuccess(entity);
|
||||
|
|
|
@ -54,7 +54,7 @@ function useEntities<TEntity extends Entity>(
|
|||
const next = useListState(path, 'next');
|
||||
const prev = useListState(path, 'prev');
|
||||
|
||||
const fetchPage = async(req: EntityFn<void>, overwrite = false): Promise<void> => {
|
||||
const fetchPage = async(req: EntityFn<void>, pos: 'start' | 'end', overwrite = false): Promise<void> => {
|
||||
// Get `isFetching` state from the store again to prevent race conditions.
|
||||
const isFetching = selectListState(getState(), path, 'fetching');
|
||||
if (isFetching) return;
|
||||
|
@ -67,7 +67,7 @@ function useEntities<TEntity extends Entity>(
|
|||
const parsedCount = realNumberSchema.safeParse(response.headers['x-total-count']);
|
||||
const totalCount = parsedCount.success ? parsedCount.data : undefined;
|
||||
|
||||
dispatch(entitiesFetchSuccess(entities, entityType, listKey, {
|
||||
dispatch(entitiesFetchSuccess(entities, entityType, listKey, pos, {
|
||||
next: getNextLink(response),
|
||||
prev: getPrevLink(response),
|
||||
totalCount: Number(totalCount) >= entities.length ? totalCount : undefined,
|
||||
|
@ -83,18 +83,18 @@ function useEntities<TEntity extends Entity>(
|
|||
};
|
||||
|
||||
const fetchEntities = async(): Promise<void> => {
|
||||
await fetchPage(entityFn, true);
|
||||
await fetchPage(entityFn, 'end', true);
|
||||
};
|
||||
|
||||
const fetchNextPage = async(): Promise<void> => {
|
||||
if (next) {
|
||||
await fetchPage(() => api.get(next));
|
||||
await fetchPage(() => api.get(next), 'end');
|
||||
}
|
||||
};
|
||||
|
||||
const fetchPreviousPage = async(): Promise<void> => {
|
||||
if (prev) {
|
||||
await fetchPage(() => api.get(prev));
|
||||
await fetchPage(() => api.get(prev), 'start');
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
import { createCache, createList, updateStore, updateList } from './utils';
|
||||
|
||||
import type { DeleteEntitiesOpts } from './actions';
|
||||
import type { Entity, EntityCache, EntityListState } from './types';
|
||||
import type { Entity, EntityCache, EntityListState, ImportPosition } from './types';
|
||||
|
||||
enableMapSet();
|
||||
|
||||
|
@ -29,6 +29,7 @@ const importEntities = (
|
|||
entityType: string,
|
||||
entities: Entity[],
|
||||
listKey?: string,
|
||||
pos?: ImportPosition,
|
||||
newState?: EntityListState,
|
||||
overwrite = false,
|
||||
): State => {
|
||||
|
@ -43,7 +44,7 @@ const importEntities = (
|
|||
list.ids = new Set();
|
||||
}
|
||||
|
||||
list = updateList(list, entities);
|
||||
list = updateList(list, entities, pos);
|
||||
|
||||
if (newState) {
|
||||
list.state = newState;
|
||||
|
@ -159,7 +160,7 @@ const invalidateEntityList = (state: State, entityType: string, listKey: string)
|
|||
function reducer(state: Readonly<State> = {}, action: EntityAction): State {
|
||||
switch (action.type) {
|
||||
case ENTITIES_IMPORT:
|
||||
return importEntities(state, action.entityType, action.entities, action.listKey);
|
||||
return importEntities(state, action.entityType, action.entities, action.listKey, action.pos);
|
||||
case ENTITIES_DELETE:
|
||||
return deleteEntities(state, action.entityType, action.ids, action.opts);
|
||||
case ENTITIES_DISMISS:
|
||||
|
@ -167,7 +168,7 @@ function reducer(state: Readonly<State> = {}, action: EntityAction): State {
|
|||
case ENTITIES_INCREMENT:
|
||||
return incrementEntities(state, action.entityType, action.listKey, action.diff);
|
||||
case ENTITIES_FETCH_SUCCESS:
|
||||
return importEntities(state, action.entityType, action.entities, action.listKey, action.newState, action.overwrite);
|
||||
return importEntities(state, action.entityType, action.entities, action.listKey, action.pos, action.newState, action.overwrite);
|
||||
case ENTITIES_FETCH_REQUEST:
|
||||
return setFetching(state, action.entityType, action.listKey, true);
|
||||
case ENTITIES_FETCH_FAIL:
|
||||
|
|
|
@ -47,10 +47,14 @@ interface EntityCache<TEntity extends Entity = Entity> {
|
|||
}
|
||||
}
|
||||
|
||||
/** Whether to import items at the start or end of the list. */
|
||||
type ImportPosition = 'start' | 'end'
|
||||
|
||||
export {
|
||||
Entity,
|
||||
EntityStore,
|
||||
EntityList,
|
||||
EntityListState,
|
||||
EntityCache,
|
||||
ImportPosition,
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
import type { Entity, EntityStore, EntityList, EntityCache, EntityListState } from './types';
|
||||
import type { Entity, EntityStore, EntityList, EntityCache, EntityListState, ImportPosition } from './types';
|
||||
|
||||
/** Insert the entities into the store. */
|
||||
const updateStore = (store: EntityStore, entities: Entity[]): EntityStore => {
|
||||
|
@ -9,9 +9,10 @@ const updateStore = (store: EntityStore, entities: Entity[]): EntityStore => {
|
|||
};
|
||||
|
||||
/** Update the list with new entity IDs. */
|
||||
const updateList = (list: EntityList, entities: Entity[]): EntityList => {
|
||||
const updateList = (list: EntityList, entities: Entity[], pos: ImportPosition = 'end'): EntityList => {
|
||||
const newIds = entities.map(entity => entity.id);
|
||||
const ids = new Set([...newIds, ...Array.from(list.ids)]);
|
||||
const oldIds = Array.from(list.ids);
|
||||
const ids = new Set(pos === 'start' ? [...newIds, ...oldIds] : [...oldIds, ...newIds]);
|
||||
|
||||
if (typeof list.state.totalCount === 'number') {
|
||||
const sizeDiff = ids.size - list.ids.size;
|
||||
|
|
Ładowanie…
Reference in New Issue