feat(server): support query overcapacity member count of workspace (#12050)

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Workspace quota information now includes a new metric: the count of members exceeding seat capacity ("overcapacityMemberCount"), available in both numeric and human-readable formats.
  - The workspace quota display and related queries have been updated to show this new overcapacity member count alongside existing quota metrics.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
forehalo
2025-04-30 09:47:50 +00:00
parent 04531508cb
commit f1605e246b
7 changed files with 34 additions and 1 deletions
@@ -142,12 +142,16 @@ export class QuotaService {
const usedStorageQuota = quota.ownerQuota const usedStorageQuota = quota.ownerQuota
? await this.getUserStorageUsage(quota.ownerQuota) ? await this.getUserStorageUsage(quota.ownerQuota)
: await this.getWorkspaceStorageUsage(workspaceId); : await this.getWorkspaceStorageUsage(workspaceId);
const memberCount = await this.models.workspaceUser.count(workspaceId); const memberCount =
await this.models.workspaceUser.chargedCount(workspaceId);
const overcapacityMemberCount =
await this.models.workspaceUser.insufficientSeatMemberCount(workspaceId);
return { return {
...quota, ...quota,
usedStorageQuota, usedStorageQuota,
memberCount, memberCount,
overcapacityMemberCount,
usedSize: usedStorageQuota, usedSize: usedStorageQuota,
}; };
} }
@@ -203,6 +207,7 @@ export class QuotaService {
historyPeriod: formatDate(quota.historyPeriod), historyPeriod: formatDate(quota.historyPeriod),
memberLimit: quota.memberLimit.toString(), memberLimit: quota.memberLimit.toString(),
memberCount: quota.memberCount.toString(), memberCount: quota.memberCount.toString(),
overcapacityMemberCount: quota.overcapacityMemberCount.toString(),
}; };
} }
@@ -85,6 +85,9 @@ export class WorkspaceQuotaHumanReadableType {
@Field() @Field()
memberCount!: string; memberCount!: string;
@Field()
overcapacityMemberCount!: string;
} }
@ObjectType() @ObjectType()
@@ -110,6 +113,9 @@ export class WorkspaceQuotaType implements Partial<WorkspaceQuota> {
@Field() @Field()
memberCount!: number; memberCount!: number;
@Field()
overcapacityMemberCount!: number;
@Field() @Field()
humanReadable!: WorkspaceQuotaHumanReadableType; humanReadable!: WorkspaceQuotaHumanReadableType;
@@ -289,6 +289,15 @@ export class WorkspaceUserModel extends BaseModel {
}); });
} }
async insufficientSeatMemberCount(workspaceId: string) {
return this.db.workspaceUserRole.count({
where: {
workspaceId,
status: WorkspaceMemberStatus.NeedMoreSeat,
},
});
}
async getUserActiveRoles( async getUserActiveRoles(
userId: string, userId: string,
filter: { role?: WorkspaceRole } = {} filter: { role?: WorkspaceRole } = {}
+2
View File
@@ -1746,6 +1746,7 @@ type WorkspaceQuotaHumanReadableType {
memberCount: String! memberCount: String!
memberLimit: String! memberLimit: String!
name: String! name: String!
overcapacityMemberCount: String!
storageQuota: String! storageQuota: String!
storageQuotaUsed: String! storageQuotaUsed: String!
} }
@@ -1757,6 +1758,7 @@ type WorkspaceQuotaType {
memberCount: Int! memberCount: Int!
memberLimit: Int! memberLimit: Int!
name: String! name: String!
overcapacityMemberCount: Int!
storageQuota: SafeInt! storageQuota: SafeInt!
usedSize: SafeInt! @deprecated(reason: "use `usedStorageQuota` instead") usedSize: SafeInt! @deprecated(reason: "use `usedStorageQuota` instead")
usedStorageQuota: SafeInt! usedStorageQuota: SafeInt!
@@ -1821,12 +1821,15 @@ export const workspaceQuotaQuery = {
historyPeriod historyPeriod
memberLimit memberLimit
memberCount memberCount
overcapacityMemberCount
humanReadable { humanReadable {
name name
blobLimit blobLimit
storageQuota storageQuota
historyPeriod historyPeriod
memberLimit memberLimit
memberCount
overcapacityMemberCount
} }
} }
} }
@@ -8,12 +8,15 @@ query workspaceQuota($id: String!) {
historyPeriod historyPeriod
memberLimit memberLimit
memberCount memberCount
overcapacityMemberCount
humanReadable { humanReadable {
name name
blobLimit blobLimit
storageQuota storageQuota
historyPeriod historyPeriod
memberLimit memberLimit
memberCount
overcapacityMemberCount
} }
} }
} }
+5
View File
@@ -2310,6 +2310,7 @@ export interface WorkspaceQuotaHumanReadableType {
memberCount: Scalars['String']['output']; memberCount: Scalars['String']['output'];
memberLimit: Scalars['String']['output']; memberLimit: Scalars['String']['output'];
name: Scalars['String']['output']; name: Scalars['String']['output'];
overcapacityMemberCount: Scalars['String']['output'];
storageQuota: Scalars['String']['output']; storageQuota: Scalars['String']['output'];
storageQuotaUsed: Scalars['String']['output']; storageQuotaUsed: Scalars['String']['output'];
} }
@@ -2322,6 +2323,7 @@ export interface WorkspaceQuotaType {
memberCount: Scalars['Int']['output']; memberCount: Scalars['Int']['output'];
memberLimit: Scalars['Int']['output']; memberLimit: Scalars['Int']['output'];
name: Scalars['String']['output']; name: Scalars['String']['output'];
overcapacityMemberCount: Scalars['Int']['output'];
storageQuota: Scalars['SafeInt']['output']; storageQuota: Scalars['SafeInt']['output'];
/** @deprecated use `usedStorageQuota` instead */ /** @deprecated use `usedStorageQuota` instead */
usedSize: Scalars['SafeInt']['output']; usedSize: Scalars['SafeInt']['output'];
@@ -4498,6 +4500,7 @@ export type WorkspaceQuotaQuery = {
historyPeriod: number; historyPeriod: number;
memberLimit: number; memberLimit: number;
memberCount: number; memberCount: number;
overcapacityMemberCount: number;
humanReadable: { humanReadable: {
__typename?: 'WorkspaceQuotaHumanReadableType'; __typename?: 'WorkspaceQuotaHumanReadableType';
name: string; name: string;
@@ -4505,6 +4508,8 @@ export type WorkspaceQuotaQuery = {
storageQuota: string; storageQuota: string;
historyPeriod: string; historyPeriod: string;
memberLimit: string; memberLimit: string;
memberCount: string;
overcapacityMemberCount: string;
}; };
}; };
}; };