nicolium: group migrations
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -10,6 +10,7 @@ import type {
|
||||
Poll as BasePoll,
|
||||
Relationship as BaseRelationship,
|
||||
Status as BaseStatus,
|
||||
GroupRelationship,
|
||||
} from 'pl-api';
|
||||
|
||||
const STATUS_IMPORT = 'STATUS_IMPORT' as const;
|
||||
@ -112,7 +113,10 @@ const importEntities =
|
||||
for (const group of Object.values(groups)) {
|
||||
queryClient.setQueryData<BaseGroup>(['groups', group.id], group);
|
||||
if (group.relationship) {
|
||||
queryClient.setQueryData<BaseGroup>(['groupRelationships', group.id], group.relationship);
|
||||
queryClient.setQueryData<GroupRelationship>(
|
||||
['groupRelationships', group.id],
|
||||
group.relationship,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!isEmpty(polls)) {
|
||||
|
||||
@ -14,6 +14,7 @@ import StatusTypeIcon from '@/features/status/components/status-type-icon';
|
||||
import { Hotkeys } from '@/features/ui/components/hotkeys';
|
||||
import { useAppDispatch } from '@/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from '@/hooks/use-app-selector';
|
||||
import { useGroupQuery } from '@/queries/groups/use-group';
|
||||
import { useFollowedTags } from '@/queries/hashtags/use-followed-tags';
|
||||
import {
|
||||
useFavouriteStatus,
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useMatch } from '@tanstack/react-router';
|
||||
import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
@ -6,7 +7,6 @@ import { groupComposeModal } from '@/actions/compose';
|
||||
import ThumbNavigationLink from '@/components/thumb-navigation-link';
|
||||
import Icon from '@/components/ui/icon';
|
||||
import { useStatContext } from '@/contexts/stat-context';
|
||||
import { Entities } from '@/entity-store/entities';
|
||||
import { layouts } from '@/features/ui/router';
|
||||
import { useAppDispatch } from '@/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from '@/hooks/use-app-selector';
|
||||
@ -16,6 +16,8 @@ import { useModalsActions } from '@/stores/modals';
|
||||
import { useIsSidebarOpen, useUiStoreActions } from '@/stores/ui';
|
||||
import { isStandalone } from '@/utils/state';
|
||||
|
||||
import type { Group } from 'pl-api';
|
||||
|
||||
const messages = defineMessages({
|
||||
home: { id: 'column.home', defaultMessage: 'Home' },
|
||||
search: { id: 'column.search', defaultMessage: 'Search' },
|
||||
@ -31,6 +33,7 @@ const ThumbNavigation: React.FC = React.memo((): JSX.Element => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { account } = useOwnAccount();
|
||||
const features = useFeatures();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const match = useMatch({ from: layouts.group.id, shouldThrow: false });
|
||||
|
||||
@ -45,7 +48,7 @@ const ThumbNavigation: React.FC = React.memo((): JSX.Element => {
|
||||
const handleOpenComposeModal = () => {
|
||||
if (match?.params.groupId) {
|
||||
dispatch((_, getState) => {
|
||||
const group = getState().entities[Entities.GROUPS]?.store[match.params.groupId];
|
||||
const group = queryClient.getQueryData<Group>(['groups', match.params.groupId]);
|
||||
if (group) dispatch(groupComposeModal(group));
|
||||
});
|
||||
} else {
|
||||
|
||||
@ -1,37 +1,14 @@
|
||||
import type { Entities } from './entities';
|
||||
import type { EntitiesTransaction, Entity, ImportPosition } from './types';
|
||||
import type { EntitiesTransaction, Entity } from './types';
|
||||
|
||||
const ENTITIES_IMPORT = 'ENTITIES_IMPORT' as const;
|
||||
const ENTITIES_DELETE = 'ENTITIES_DELETE' as const;
|
||||
const ENTITIES_TRANSACTION = 'ENTITIES_TRANSACTION' as const;
|
||||
|
||||
/** Action to import entities into the cache. */
|
||||
const importEntities = (
|
||||
entities: Entity[],
|
||||
entityType: Entities,
|
||||
listKey?: string,
|
||||
pos?: ImportPosition,
|
||||
) => ({
|
||||
const importEntities = (entities: Entity[], entityType: Entities) => ({
|
||||
type: ENTITIES_IMPORT,
|
||||
entityType,
|
||||
entities,
|
||||
listKey,
|
||||
pos,
|
||||
});
|
||||
|
||||
interface DeleteEntitiesOpts {
|
||||
preserveLists?: boolean;
|
||||
}
|
||||
|
||||
const deleteEntities = (
|
||||
ids: Iterable<string>,
|
||||
entityType: string,
|
||||
opts: DeleteEntitiesOpts = {},
|
||||
) => ({
|
||||
type: ENTITIES_DELETE,
|
||||
ids,
|
||||
entityType,
|
||||
opts,
|
||||
});
|
||||
|
||||
const entitiesTransaction = (transaction: EntitiesTransaction) => ({
|
||||
@ -40,18 +17,12 @@ const entitiesTransaction = (transaction: EntitiesTransaction) => ({
|
||||
});
|
||||
|
||||
/** Any action pertaining to entities. */
|
||||
type EntityAction =
|
||||
| ReturnType<typeof importEntities>
|
||||
| ReturnType<typeof deleteEntities>
|
||||
| ReturnType<typeof entitiesTransaction>;
|
||||
type EntityAction = ReturnType<typeof importEntities> | ReturnType<typeof entitiesTransaction>;
|
||||
|
||||
export {
|
||||
type DeleteEntitiesOpts,
|
||||
type EntityAction,
|
||||
ENTITIES_IMPORT,
|
||||
ENTITIES_DELETE,
|
||||
ENTITIES_TRANSACTION,
|
||||
importEntities,
|
||||
deleteEntities,
|
||||
entitiesTransaction,
|
||||
};
|
||||
|
||||
@ -1,12 +1,6 @@
|
||||
import { create, type Immutable, type Draft } from 'mutative';
|
||||
|
||||
import {
|
||||
ENTITIES_IMPORT,
|
||||
ENTITIES_DELETE,
|
||||
ENTITIES_TRANSACTION,
|
||||
type EntityAction,
|
||||
type DeleteEntitiesOpts,
|
||||
} from './actions';
|
||||
import { ENTITIES_IMPORT, ENTITIES_TRANSACTION, type EntityAction } from './actions';
|
||||
import { Entities } from './entities';
|
||||
import { createCache, createList, updateStore, updateList } from './utils';
|
||||
|
||||
@ -55,33 +49,6 @@ const importEntities = (
|
||||
draft[entityType] = cache;
|
||||
};
|
||||
|
||||
const deleteEntities = (
|
||||
draft: Draft<State>,
|
||||
entityType: string,
|
||||
ids: Iterable<string>,
|
||||
opts: DeleteEntitiesOpts,
|
||||
) => {
|
||||
const cache = draft[entityType] ?? createCache();
|
||||
|
||||
for (const id of ids) {
|
||||
delete cache.store[id];
|
||||
|
||||
if (!opts?.preserveLists) {
|
||||
for (const list of Object.values(cache.lists)) {
|
||||
if (list) {
|
||||
list.ids.delete(id);
|
||||
|
||||
if (typeof list.state.totalCount === 'number') {
|
||||
list.state.totalCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
draft[entityType] = cache;
|
||||
};
|
||||
|
||||
const doTransaction = (draft: Draft<State>, transaction: EntitiesTransaction) => {
|
||||
for (const [entityType, changes] of Object.entries(transaction)) {
|
||||
const cache = draft[entityType] ?? createCache();
|
||||
@ -101,14 +68,10 @@ const reducer = (state: Readonly<State> = {}, action: EntityAction): State => {
|
||||
return create(
|
||||
state,
|
||||
(draft) => {
|
||||
importEntities(draft, action.entityType, action.entities, action.listKey, action.pos);
|
||||
importEntities(draft, action.entityType, action.entities);
|
||||
},
|
||||
{ enableAutoFreeze: true },
|
||||
);
|
||||
case ENTITIES_DELETE:
|
||||
return create(state, (draft) => {
|
||||
deleteEntities(draft, action.entityType, action.ids, action.opts);
|
||||
});
|
||||
case ENTITIES_TRANSACTION:
|
||||
return create(state, (draft) => {
|
||||
doTransaction(draft, action.transaction);
|
||||
|
||||
@ -25,18 +25,12 @@ interface EntityListState {
|
||||
next: (() => Promise<PaginatedResponse<any>>) | null;
|
||||
/** Previous URL for pagination, if any. */
|
||||
prev: (() => Promise<PaginatedResponse<any>>) | null;
|
||||
/** Total number of items according to the API. */
|
||||
totalCount: number | undefined;
|
||||
/** Error returned from the API, if any. */
|
||||
error: unknown;
|
||||
/** Whether data has already been fetched */
|
||||
fetched: boolean;
|
||||
/** Whether data for this list is currently being fetched. */
|
||||
fetching: boolean;
|
||||
/** Date of the last API fetch for this list. */
|
||||
lastFetchedAt: Date | undefined;
|
||||
/** Whether the entities should be refetched on the next component mount. */
|
||||
invalid: boolean;
|
||||
}
|
||||
|
||||
/** Cache data pertaining to a paritcular entity type.. */
|
||||
|
||||
@ -27,11 +27,6 @@ const updateList = (
|
||||
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;
|
||||
list.state.totalCount += sizeDiff;
|
||||
}
|
||||
|
||||
return {
|
||||
...list,
|
||||
ids,
|
||||
@ -54,12 +49,9 @@ const createList = (): EntityList => ({
|
||||
const createListState = (): EntityListState => ({
|
||||
next: null,
|
||||
prev: null,
|
||||
totalCount: 0,
|
||||
error: null,
|
||||
fetched: false,
|
||||
fetching: false,
|
||||
lastFetchedAt: undefined,
|
||||
invalid: false,
|
||||
});
|
||||
|
||||
export { updateStore, updateList, createCache, createList };
|
||||
|
||||
@ -5,6 +5,7 @@ import Link from '@/components/link';
|
||||
import Text from '@/components/ui/text';
|
||||
import Emojify from '@/features/emoji/emojify';
|
||||
import { useAppSelector } from '@/hooks/use-app-selector';
|
||||
import { useGroupQuery } from '@/queries/groups/use-group';
|
||||
import { makeGetStatus } from '@/selectors';
|
||||
|
||||
interface IReplyGroupIndicator {
|
||||
@ -19,7 +20,8 @@ const ReplyGroupIndicator = (props: IReplyGroupIndicator) => {
|
||||
const status = useAppSelector((state) =>
|
||||
getStatus(state, { id: state.compose[composeId]?.inReplyToId! }),
|
||||
);
|
||||
const group = status?.group;
|
||||
|
||||
const { data: group } = useGroupQuery(status?.group_id ?? undefined);
|
||||
|
||||
if (!group) {
|
||||
return null;
|
||||
|
||||
@ -69,15 +69,12 @@ const DetailedStatus: React.FC<IDetailedStatus> = ({
|
||||
group: (
|
||||
<Link
|
||||
to='/groups/$groupId'
|
||||
params={{ groupId: status.group.id }}
|
||||
params={{ groupId: status.group_id }}
|
||||
className='hover:underline'
|
||||
>
|
||||
<bdi className='truncate'>
|
||||
<strong className='text-gray-800 dark:text-gray-200'>
|
||||
<Emojify
|
||||
text={status.account.display_name}
|
||||
emojis={status.account.emojis}
|
||||
/>
|
||||
<Emojify text={group.display_name} emojis={group.emojis} />
|
||||
</strong>
|
||||
</bdi>
|
||||
</Link>
|
||||
|
||||
@ -12,7 +12,7 @@ import type { minifyAdminReport } from '@/queries/utils/minify-list';
|
||||
import type { MinifiedStatus } from '@/reducers/statuses';
|
||||
import type { MRFSimple } from '@/schemas/pleroma';
|
||||
import type { RootState } from '@/store';
|
||||
import type { Account, Filter, FilterResult, Group, NotificationGroup } from 'pl-api';
|
||||
import type { Account, Filter, FilterResult, NotificationGroup } from 'pl-api';
|
||||
|
||||
const selectAccount = (state: RootState, accountId: string) =>
|
||||
state.entities[Entities.ACCOUNTS]?.store[accountId] as Account | undefined;
|
||||
@ -120,11 +120,6 @@ const makeGetStatus = () =>
|
||||
state.statuses[state.statuses[id]?.reblog_id ?? ''] || null,
|
||||
(state: RootState, { id }: APIStatus) =>
|
||||
state.statuses[state.statuses[id]?.quote_id ?? ''] || null,
|
||||
(state: RootState, { id }: APIStatus) => {
|
||||
const group = state.statuses[id]?.group_id;
|
||||
if (group) return state.entities[Entities.GROUPS]?.store[group] as Group;
|
||||
return undefined;
|
||||
},
|
||||
(_state: RootState, { username }: APIStatus) => username,
|
||||
(state: RootState) => state.filters,
|
||||
(_state: RootState, { contextType }: FilterContext) => contextType,
|
||||
@ -132,17 +127,7 @@ const makeGetStatus = () =>
|
||||
(state: RootState) => state.auth.client.features,
|
||||
],
|
||||
|
||||
(
|
||||
statusBase,
|
||||
statusReblog,
|
||||
statusQuote,
|
||||
statusGroup,
|
||||
username,
|
||||
filters,
|
||||
contextType,
|
||||
me,
|
||||
features,
|
||||
) => {
|
||||
(statusBase, statusReblog, statusQuote, username, filters, contextType, me, features) => {
|
||||
if (!statusBase) return null;
|
||||
const { account } = statusBase;
|
||||
const accountUsername = account.acct;
|
||||
@ -165,7 +150,6 @@ const makeGetStatus = () =>
|
||||
...statusBase,
|
||||
reblog: statusReblog || null,
|
||||
quote: statusQuote || null,
|
||||
group: statusGroup ?? null,
|
||||
filtered,
|
||||
};
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user