nicolium: groups migrations

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
nicole mikołajczyk
2026-02-22 20:08:16 +01:00
parent be44696640
commit fbbcbdce3f
34 changed files with 446 additions and 499 deletions

View File

@ -11,6 +11,14 @@ const relationships = memoize((client: PlApiClient) =>
}),
);
const groupRelationships = memoize((client: PlApiClient) =>
create({
fetcher: (ids: string[]) => client.experimental.groups.getGroupRelationships(ids),
resolver: keyResolver('id'),
scheduler: bufferScheduler(200),
}),
);
// TODO: proper multi-client support
const translations = memoize((lang: string, client: PlApiClient) =>
create({
@ -22,6 +30,7 @@ const translations = memoize((lang: string, client: PlApiClient) =>
const batcher = {
relationships,
groupRelationships,
translations,
};

View File

@ -1,27 +0,0 @@
import * as v from 'valibot';
import { Entities } from '@/entity-store/entities';
import { useCreateEntity } from '@/entity-store/hooks/use-create-entity';
import { useClient } from '@/hooks/use-client';
import type { Group, GroupMember, GroupRole } from 'pl-api';
const useDemoteGroupMember = (group: Pick<Group, 'id'>, groupMember: Pick<GroupMember, 'id'>) => {
const client = useClient();
const { createEntity } = useCreateEntity(
[Entities.GROUP_MEMBERSHIPS, groupMember.id],
({ account_ids, role }: { account_ids: string[]; role: GroupRole }) =>
client.experimental.groups.demoteGroupUsers(group.id, account_ids, role),
{
schema: v.pipe(
v.any(),
v.transform((arr) => arr[0]),
),
},
);
return createEntity;
};
export { useDemoteGroupMember };

View File

@ -1,54 +0,0 @@
import { GroupRoles } from 'pl-api';
import { Entities } from '@/entity-store/entities';
import { useDismissEntity } from '@/entity-store/hooks/use-dismiss-entity';
import { useEntities } from '@/entity-store/hooks/use-entities';
import { useClient } from '@/hooks/use-client';
import { useGroupRelationship } from './use-group-relationship';
import type { ExpandedEntitiesPath } from '@/entity-store/hooks/types';
import type { Account } from 'pl-api';
const useGroupMembershipRequests = (groupId: string) => {
const client = useClient();
const path: ExpandedEntitiesPath = [Entities.ACCOUNTS, 'membership_requests', groupId];
const { groupRelationship: relationship } = useGroupRelationship(groupId);
const { entities, invalidate, fetchEntities, ...rest } = useEntities<Account>(
path,
() => client.experimental.groups.getGroupMembershipRequests(groupId),
{
enabled: relationship?.role === GroupRoles.OWNER || relationship?.role === GroupRoles.ADMIN,
},
);
const { dismissEntity: authorize } = useDismissEntity(path, async (accountId: string) => {
const response = await client.experimental.groups.acceptGroupMembershipRequest(
groupId,
accountId,
);
invalidate();
return response;
});
const { dismissEntity: reject } = useDismissEntity(path, async (accountId: string) => {
const response = await client.experimental.groups.rejectGroupMembershipRequest(
groupId,
accountId,
);
invalidate();
return response;
});
return {
accounts: entities,
refetch: fetchEntities,
authorize,
reject,
...rest,
};
};
export { useGroupMembershipRequests };

View File

@ -1,30 +0,0 @@
import * as v from 'valibot';
import { Entities } from '@/entity-store/entities';
import { useEntity } from '@/entity-store/hooks/use-entity';
import { useClient } from '@/hooks/use-client';
import type { GroupRelationship } from 'pl-api';
const useGroupRelationship = (groupId: string | undefined) => {
const client = useClient();
const { entity: groupRelationship, ...result } = useEntity<GroupRelationship>(
[Entities.GROUP_RELATIONSHIPS, groupId!],
() => client.experimental.groups.getGroupRelationships([groupId!]),
{
enabled: !!groupId,
schema: v.pipe(
v.any(),
v.transform((arr) => arr[0]),
),
},
);
return {
groupRelationship,
...result,
};
};
export { useGroupRelationship };

View File

@ -1,25 +0,0 @@
import { Entities } from '@/entity-store/entities';
import { useBatchedEntities } from '@/entity-store/hooks/use-batched-entities';
import { useClient } from '@/hooks/use-client';
import { useLoggedIn } from '@/hooks/use-logged-in';
import type { GroupRelationship } from 'pl-api';
const useGroupRelationships = (listKey: string[], groupIds: string[]) => {
const client = useClient();
const { isLoggedIn } = useLoggedIn();
const fetchGroupRelationships = (groupIds: string[]) =>
client.experimental.groups.getGroupRelationships(groupIds);
const { entityMap: relationships, ...result } = useBatchedEntities<GroupRelationship>(
[Entities.GROUP_RELATIONSHIPS, ...listKey],
groupIds,
fetchGroupRelationships,
{ enabled: isLoggedIn },
);
return { relationships, ...result };
};
export { useGroupRelationships };

View File

@ -1,45 +0,0 @@
import { useLocation, useNavigate } from '@tanstack/react-router';
import { useEffect } from 'react';
import { Entities } from '@/entity-store/entities';
import { useEntity } from '@/entity-store/hooks/use-entity';
import { useClient } from '@/hooks/use-client';
import { useGroupRelationship } from './use-group-relationship';
import type { Group } from 'pl-api';
const useGroup = (groupId: string, refetch = true) => {
const client = useClient();
const location = useLocation();
const navigate = useNavigate();
const {
entity: group,
isUnauthorized,
...result
} = useEntity<Group, Group>(
[Entities.GROUPS, groupId],
() => client.experimental.groups.getGroup(groupId),
{
refetch,
enabled: !!groupId,
},
);
const { groupRelationship: relationship } = useGroupRelationship(groupId);
useEffect(() => {
if (isUnauthorized) {
localStorage.setItem('plfe:redirect_uri', location.href);
navigate({ to: '/login', replace: true });
}
}, [isUnauthorized]);
return {
...result,
isUnauthorized,
group: group ? { ...group, relationship: relationship ?? null } : undefined,
};
};
export { useGroup };

View File

@ -1,35 +0,0 @@
import { Entities } from '@/entity-store/entities';
import { useEntities } from '@/entity-store/hooks/use-entities';
import { useClient } from '@/hooks/use-client';
import { useFeatures } from '@/hooks/use-features';
import { useGroupRelationships } from './use-group-relationships';
import type { Group } from 'pl-api';
const useGroups = () => {
const client = useClient();
const features = useFeatures();
const { entities, ...result } = useEntities<Group, Group>(
[Entities.GROUPS, 'search', ''],
() => client.experimental.groups.getGroups(),
{ enabled: features.groups },
);
const { relationships } = useGroupRelationships(
['search', ''],
entities.map((entity) => entity.id),
);
const groups = entities.map((group) => ({
...group,
relationship: relationships[group.id] || null,
}));
return {
...result,
groups,
};
};
export { useGroups };

View File

@ -1,25 +0,0 @@
import { Entities } from '@/entity-store/entities';
import { useCreateEntity } from '@/entity-store/hooks/use-create-entity';
import { useClient } from '@/hooks/use-client';
import { useGroups } from './use-groups';
import type { Group } from 'pl-api';
const useJoinGroup = (group: Pick<Group, 'id'>) => {
const client = useClient();
const { invalidate } = useGroups();
const { createEntity, isSubmitting } = useCreateEntity(
[Entities.GROUP_RELATIONSHIPS, group.id],
() => client.experimental.groups.joinGroup(group.id),
);
return {
mutate: createEntity,
isSubmitting,
invalidate,
};
};
export { useJoinGroup };

View File

@ -1,25 +0,0 @@
import { Entities } from '@/entity-store/entities';
import { useCreateEntity } from '@/entity-store/hooks/use-create-entity';
import { useClient } from '@/hooks/use-client';
import { useGroups } from './use-groups';
import type { Group } from 'pl-api';
const useLeaveGroup = (group: Pick<Group, 'id'>) => {
const client = useClient();
const { invalidate } = useGroups();
const { createEntity, isSubmitting } = useCreateEntity(
[Entities.GROUP_RELATIONSHIPS, group.id],
() => client.experimental.groups.leaveGroup(group.id),
);
return {
mutate: createEntity,
isSubmitting,
invalidate,
};
};
export { useLeaveGroup };

View File

@ -1,27 +0,0 @@
import * as v from 'valibot';
import { Entities } from '@/entity-store/entities';
import { useCreateEntity } from '@/entity-store/hooks/use-create-entity';
import { useClient } from '@/hooks/use-client';
import type { Group, GroupMember, GroupRole } from 'pl-api';
const usePromoteGroupMember = (group: Pick<Group, 'id'>, groupMember: Pick<GroupMember, 'id'>) => {
const client = useClient();
const { createEntity } = useCreateEntity(
[Entities.GROUP_MEMBERSHIPS, groupMember.id],
({ account_ids, role }: { account_ids: string[]; role: GroupRole }) =>
client.experimental.groups.promoteGroupUsers(group.id, account_ids, role),
{
schema: v.pipe(
v.any(),
v.transform((arr) => arr[0]),
),
},
);
return createEntity;
};
export { usePromoteGroupMember };