mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
fix(server): wrong member count query (#4506)
This commit is contained in:
@@ -21,7 +21,14 @@ import { Tooltip } from '@toeverything/components/tooltip';
|
||||
import clsx from 'clsx';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import type { ReactElement } from 'react';
|
||||
import { Suspense, useCallback, useMemo, useState } from 'react';
|
||||
import {
|
||||
Suspense,
|
||||
useCallback,
|
||||
useLayoutEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { ErrorBoundary } from 'react-error-boundary';
|
||||
|
||||
import type { CheckedUser } from '../../../hooks/affine/use-current-user';
|
||||
@@ -96,6 +103,20 @@ export const CloudWorkspaceMembersPanel = ({
|
||||
[invite, pushNotification, t]
|
||||
);
|
||||
|
||||
const listContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
const [memberListHeight, setMemberListHeight] = useState<number | null>(null);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (
|
||||
memberCount > COUNT_PER_PAGE &&
|
||||
listContainerRef.current &&
|
||||
memberListHeight === null
|
||||
) {
|
||||
const rect = listContainerRef.current.getBoundingClientRect();
|
||||
setMemberListHeight(rect.height);
|
||||
}
|
||||
}, [listContainerRef, memberCount, memberListHeight]);
|
||||
|
||||
const onRevoke = useCallback<OnRevoke>(
|
||||
async memberId => {
|
||||
const res = await revokeMemberPermission(memberId);
|
||||
@@ -129,7 +150,11 @@ export const CloudWorkspaceMembersPanel = ({
|
||||
) : null}
|
||||
</SettingRow>
|
||||
|
||||
<div className={style.membersPanel}>
|
||||
<div
|
||||
className={style.membersPanel}
|
||||
ref={listContainerRef}
|
||||
style={memberListHeight ? { height: memberListHeight } : {}}
|
||||
>
|
||||
<Suspense fallback={<MemberListFallback memberCount={memberCount} />}>
|
||||
<MemberList
|
||||
workspaceId={workspaceId}
|
||||
@@ -139,11 +164,13 @@ export const CloudWorkspaceMembersPanel = ({
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
{memberCount > COUNT_PER_PAGE && (
|
||||
<Pagination
|
||||
totalCount={memberCount}
|
||||
countPerPage={COUNT_PER_PAGE}
|
||||
onPageChange={onPageChange}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
@@ -186,7 +213,7 @@ const MemberList = ({
|
||||
const currentUser = useCurrentUser();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={style.memberList}>
|
||||
{members.map(member => (
|
||||
<MemberItem
|
||||
key={member.id}
|
||||
@@ -196,7 +223,7 @@ const MemberList = ({
|
||||
onRevoke={onRevoke}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -225,8 +252,11 @@ const MemberItem = ({
|
||||
}, [currentUser.id, isOwner, member.id, t]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div key={member.id} className={style.listItem} data-testid="member-item">
|
||||
<div
|
||||
key={member.id}
|
||||
className={style.memberListItem}
|
||||
data-testid="member-item"
|
||||
>
|
||||
<Avatar
|
||||
size={36}
|
||||
url={member.avatarUrl}
|
||||
@@ -272,7 +302,6 @@ const MemberItem = ({
|
||||
</IconButton>
|
||||
</Menu>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -93,14 +93,17 @@ export const membersFallback = style({
|
||||
color: 'var(--affine-primary-color)',
|
||||
});
|
||||
export const membersPanel = style({
|
||||
marginTop: '24px',
|
||||
padding: '4px',
|
||||
borderRadius: '12px',
|
||||
background: 'var(--affine-background-primary-color)',
|
||||
border: '1px solid var(--affine-border-color)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
});
|
||||
|
||||
export const listItem = style({
|
||||
export const memberList = style({});
|
||||
export const memberListItem = style({
|
||||
padding: '0 4px 0 16px',
|
||||
height: '58px',
|
||||
display: 'flex',
|
||||
@@ -155,7 +158,7 @@ export const memberEmail = style({
|
||||
});
|
||||
export const iconButton = style({});
|
||||
|
||||
globalStyle(`${listItem}:hover ${iconButton}`, {
|
||||
globalStyle(`${memberListItem}:hover ${iconButton}`, {
|
||||
opacity: 1,
|
||||
pointerEvents: 'all',
|
||||
});
|
||||
|
||||
@@ -174,6 +174,9 @@ export class WorkspaceResolver {
|
||||
return this.prisma.userWorkspacePermission.count({
|
||||
where: {
|
||||
workspaceId: workspace.id,
|
||||
userId: {
|
||||
not: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -214,6 +217,9 @@ export class WorkspaceResolver {
|
||||
const data = await this.prisma.userWorkspacePermission.findMany({
|
||||
where: {
|
||||
workspaceId: workspace.id,
|
||||
userId: {
|
||||
not: null,
|
||||
},
|
||||
},
|
||||
skip,
|
||||
take: take || 8,
|
||||
|
||||
@@ -173,6 +173,15 @@ type Query {
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
signUp(name: String!, email: String!, password: String!): UserType!
|
||||
signIn(email: String!, password: String!): UserType!
|
||||
changePassword(token: String!, newPassword: String!): UserType!
|
||||
changeEmail(token: String!): UserType!
|
||||
sendChangePasswordEmail(email: String!, callbackUrl: String!): Boolean!
|
||||
sendSetPasswordEmail(email: String!, callbackUrl: String!): Boolean!
|
||||
sendChangeEmail(email: String!, callbackUrl: String!): Boolean!
|
||||
sendVerifyChangeEmail(token: String!, email: String!, callbackUrl: String!): Boolean!
|
||||
|
||||
"""Create a new workspace"""
|
||||
createWorkspace(init: Upload!): WorkspaceType!
|
||||
|
||||
@@ -196,14 +205,6 @@ type Mutation {
|
||||
removeAvatar: RemoveAvatar!
|
||||
deleteAccount: DeleteAccount!
|
||||
addToNewFeaturesWaitingList(type: NewFeaturesKind!, email: String!): AddToNewFeaturesWaitingList!
|
||||
signUp(name: String!, email: String!, password: String!): UserType!
|
||||
signIn(email: String!, password: String!): UserType!
|
||||
changePassword(token: String!, newPassword: String!): UserType!
|
||||
changeEmail(token: String!): UserType!
|
||||
sendChangePasswordEmail(email: String!, callbackUrl: String!): Boolean!
|
||||
sendSetPasswordEmail(email: String!, callbackUrl: String!): Boolean!
|
||||
sendChangeEmail(email: String!, callbackUrl: String!): Boolean!
|
||||
sendVerifyChangeEmail(token: String!, email: String!, callbackUrl: String!): Boolean!
|
||||
}
|
||||
|
||||
"""The `Upload` scalar type represents a file upload."""
|
||||
|
||||
Reference in New Issue
Block a user