diff --git a/packages/backend/server/src/__tests__/e2e/notification/resolver.spec.ts b/packages/backend/server/src/__tests__/e2e/notification/resolver.spec.ts index 1dd0748f3..8e2c2a53d 100644 --- a/packages/backend/server/src/__tests__/e2e/notification/resolver.spec.ts +++ b/packages/backend/server/src/__tests__/e2e/notification/resolver.spec.ts @@ -273,7 +273,7 @@ e2e('should mark notification as read', async t => { const count = await app.gql({ query: notificationCountQuery, }); - t.is(count.currentUser!.notificationCount, 0); + t.is(count.currentUser!.notifications.totalCount, 0); // read again should work for (const notification of notifications) { diff --git a/packages/backend/server/src/core/access-token/index.ts b/packages/backend/server/src/core/access-token/index.ts index 6df3b3fbe..0fd0bcc3c 100644 --- a/packages/backend/server/src/core/access-token/index.ts +++ b/packages/backend/server/src/core/access-token/index.ts @@ -1,8 +1,8 @@ import { Module } from '@nestjs/common'; -import { AccessTokenResolver } from './resolver'; +import { AccessTokenResolver, UserAccessTokenResolver } from './resolver'; @Module({ - providers: [AccessTokenResolver], + providers: [AccessTokenResolver, UserAccessTokenResolver], }) export class AccessTokenModule {} diff --git a/packages/backend/server/src/core/access-token/resolver.ts b/packages/backend/server/src/core/access-token/resolver.ts index b80a83d27..cfb734d1e 100644 --- a/packages/backend/server/src/core/access-token/resolver.ts +++ b/packages/backend/server/src/core/access-token/resolver.ts @@ -3,34 +3,17 @@ import { Field, InputType, Mutation, - ObjectType, + Parent, Query, + ResolveField, Resolver, } from '@nestjs/graphql'; +import { ActionForbidden } from '../../base'; import { Models } from '../../models'; import { CurrentUser } from '../auth/session'; - -@ObjectType() -class AccessToken { - @Field() - id!: string; - - @Field() - name!: string; - - @Field() - createdAt!: Date; - - @Field(() => Date, { nullable: true }) - expiresAt!: Date | null; -} - -@ObjectType() -class RevealedAccessToken extends AccessToken { - @Field() - token!: string; -} +import { UserType } from '../user'; +import { AccessToken, RevealedAccessToken } from './types'; @InputType() class GenerateAccessTokenInput { @@ -45,12 +28,16 @@ class GenerateAccessTokenInput { export class AccessTokenResolver { constructor(private readonly models: Models) {} - @Query(() => [AccessToken]) + @Query(() => [AccessToken], { + deprecationReason: 'use currentUser.accessTokens', + }) async accessTokens(@CurrentUser() user: CurrentUser): Promise { return await this.models.accessToken.list(user.id); } - @Query(() => [RevealedAccessToken]) + @Query(() => [RevealedAccessToken], { + deprecationReason: 'use currentUser.revealedAccessTokens', + }) async revealedAccessTokens( @CurrentUser() user: CurrentUser ): Promise { @@ -78,3 +65,30 @@ export class AccessTokenResolver { return true; } } + +@Resolver(() => UserType) +export class UserAccessTokenResolver { + constructor(private readonly models: Models) {} + + @ResolveField(() => [AccessToken]) + async accessTokens( + @CurrentUser() currentUser: CurrentUser, + @Parent() user: UserType + ): Promise { + if (!currentUser || currentUser.id !== user.id) { + throw new ActionForbidden(); + } + return await this.models.accessToken.list(user.id); + } + + @ResolveField(() => [RevealedAccessToken]) + async revealedAccessTokens( + @CurrentUser() currentUser: CurrentUser, + @Parent() user: UserType + ): Promise { + if (!currentUser || currentUser.id !== user.id) { + throw new ActionForbidden(); + } + return await this.models.accessToken.list(user.id, true); + } +} diff --git a/packages/backend/server/src/core/access-token/types.ts b/packages/backend/server/src/core/access-token/types.ts new file mode 100644 index 000000000..63979ed88 --- /dev/null +++ b/packages/backend/server/src/core/access-token/types.ts @@ -0,0 +1,22 @@ +import { Field, ObjectType } from '@nestjs/graphql'; + +@ObjectType() +export class AccessToken { + @Field() + id!: string; + + @Field() + name!: string; + + @Field() + createdAt!: Date; + + @Field(() => Date, { nullable: true }) + expiresAt!: Date | null; +} + +@ObjectType() +export class RevealedAccessToken extends AccessToken { + @Field() + token!: string; +} diff --git a/packages/backend/server/src/core/config/resolver.ts b/packages/backend/server/src/core/config/resolver.ts index 003973b72..9f37dc3fe 100644 --- a/packages/backend/server/src/core/config/resolver.ts +++ b/packages/backend/server/src/core/config/resolver.ts @@ -230,13 +230,31 @@ export class AppConfigResolver { return await this.service.updateConfig(me.id, updates); } - @Mutation(() => [AppConfigValidateResult], { + @Query(() => [AppConfigValidateResult], { description: 'validate app configuration', }) async validateAppConfig( @Args('updates', { type: () => [UpdateAppConfigInput] }) updates: UpdateAppConfigInput[] ): Promise { + return this.validateConfigInternal(updates); + } + + @Mutation(() => [AppConfigValidateResult], { + description: 'validate app configuration', + deprecationReason: 'use Query.validateAppConfig', + name: 'validateAppConfig', + }) + async validateAppConfigMutation( + @Args('updates', { type: () => [UpdateAppConfigInput] }) + updates: UpdateAppConfigInput[] + ): Promise { + return this.validateConfigInternal(updates); + } + + private validateConfigInternal( + updates: UpdateAppConfigInput[] + ): AppConfigValidateResult[] { const errors = this.service.validateConfig(updates); return updates.map(update => { diff --git a/packages/backend/server/src/core/workspaces/resolvers/blob.ts b/packages/backend/server/src/core/workspaces/resolvers/blob.ts index a50bcbe0a..d9966e978 100644 --- a/packages/backend/server/src/core/workspaces/resolvers/blob.ts +++ b/packages/backend/server/src/core/workspaces/resolvers/blob.ts @@ -156,6 +156,19 @@ export class WorkspaceBlobResolver { return this.storage.totalSize(workspace.id); } + @ResolveField(() => BlobUploadPart, { + description: 'Get blob upload part url', + }) + async blobUploadPartUrl( + @CurrentUser() user: CurrentUser, + @Parent() workspace: WorkspaceType, + @Args('key') key: string, + @Args('uploadId') uploadId: string, + @Args('partNumber', { type: () => Int }) partNumber: number + ): Promise { + return this.getUploadPart(user, workspace.id, key, uploadId, partNumber); + } + @Query(() => WorkspaceBlobSizes, { deprecationReason: 'use `user.quotaUsage` instead', }) @@ -399,13 +412,40 @@ export class WorkspaceBlobResolver { return key; } - @Mutation(() => BlobUploadPart) + @Mutation(() => BlobUploadPart, { + deprecationReason: 'use WorkspaceType.blobUploadPartUrl', + }) async getBlobUploadPartUrl( @CurrentUser() user: CurrentUser, @Args('workspaceId') workspaceId: string, @Args('key') key: string, @Args('uploadId') uploadId: string, @Args('partNumber', { type: () => Int }) partNumber: number + ): Promise { + return this.getUploadPart(user, workspaceId, key, uploadId, partNumber); + } + + @Mutation(() => Boolean) + async abortBlobUpload( + @CurrentUser() user: CurrentUser, + @Args('workspaceId') workspaceId: string, + @Args('key') key: string, + @Args('uploadId') uploadId: string + ) { + await this.ac + .user(user.id) + .workspace(workspaceId) + .assert('Workspace.Blobs.Write'); + + return this.storage.abortMultipartUpload(workspaceId, key, uploadId); + } + + private async getUploadPart( + user: CurrentUser, + workspaceId: string, + key: string, + uploadId: string, + partNumber: number ): Promise { await this.ac .user(user.id) @@ -429,21 +469,6 @@ export class WorkspaceBlobResolver { }; } - @Mutation(() => Boolean) - async abortBlobUpload( - @CurrentUser() user: CurrentUser, - @Args('workspaceId') workspaceId: string, - @Args('key') key: string, - @Args('uploadId') uploadId: string - ) { - await this.ac - .user(user.id) - .workspace(workspaceId) - .assert('Workspace.Blobs.Write'); - - return this.storage.abortMultipartUpload(workspaceId, key, uploadId); - } - @Mutation(() => Boolean) async deleteBlob( @CurrentUser() user: CurrentUser, diff --git a/packages/backend/server/src/plugins/calendar/index.ts b/packages/backend/server/src/plugins/calendar/index.ts index 31c7c7d7c..25e82ad5a 100644 --- a/packages/backend/server/src/plugins/calendar/index.ts +++ b/packages/backend/server/src/plugins/calendar/index.ts @@ -9,7 +9,14 @@ import { CalendarController } from './controller'; import { CalendarCronJobs } from './cron'; import { CalendarOAuthService } from './oauth'; import { CalendarProviderFactory, CalendarProviders } from './providers'; -import { CalendarResolver } from './resolver'; +import { + CalendarAccountResolver, + CalendarMutationResolver, + CalendarServerConfigResolver, + UserCalendarResolver, + WorkspaceCalendarEventsResolver, + WorkspaceCalendarResolver, +} from './resolver'; import { CalendarService } from './service'; @Module({ @@ -20,7 +27,12 @@ import { CalendarService } from './service'; CalendarService, CalendarOAuthService, CalendarCronJobs, - CalendarResolver, + CalendarServerConfigResolver, + UserCalendarResolver, + CalendarAccountResolver, + WorkspaceCalendarResolver, + WorkspaceCalendarEventsResolver, + CalendarMutationResolver, ], controllers: [CalendarController], }) diff --git a/packages/backend/server/src/plugins/calendar/resolver.ts b/packages/backend/server/src/plugins/calendar/resolver.ts index efebf3404..6cad77a0b 100644 --- a/packages/backend/server/src/plugins/calendar/resolver.ts +++ b/packages/backend/server/src/plugins/calendar/resolver.ts @@ -2,13 +2,17 @@ import { Args, GraphQLISODateTime, Mutation, - Query, + Parent, + ResolveField, Resolver, } from '@nestjs/graphql'; -import { AuthenticationRequired } from '../../base'; +import { ActionForbidden, AuthenticationRequired } from '../../base'; import { CurrentUser } from '../../core/auth'; +import { ServerConfigType } from '../../core/config/types'; import { AccessController } from '../../core/permission'; +import { UserType } from '../../core/user'; +import { WorkspaceType } from '../../core/workspaces'; import { Models } from '../../models'; import { CalendarOAuthService } from './oauth'; import { CalendarProviderFactory, CalendarProviderName } from './providers'; @@ -22,70 +26,100 @@ import { WorkspaceCalendarObjectType, } from './types'; -@Resolver(() => CalendarAccountObjectType) -export class CalendarResolver { - constructor( - private readonly calendar: CalendarService, - private readonly oauth: CalendarOAuthService, - private readonly models: Models, - private readonly access: AccessController, - private readonly providerFactory: CalendarProviderFactory - ) {} +@Resolver(() => ServerConfigType) +export class CalendarServerConfigResolver { + constructor(private readonly providerFactory: CalendarProviderFactory) {} - @Query(() => [CalendarAccountObjectType]) - async calendarAccounts(@CurrentUser() user: CurrentUser) { + @ResolveField(() => [CalendarProviderName]) + calendarProviders() { + return this.providerFactory.providers; + } +} + +@Resolver(() => UserType) +export class UserCalendarResolver { + constructor(private readonly calendar: CalendarService) {} + + @ResolveField(() => [CalendarAccountObjectType]) + async calendarAccounts( + @CurrentUser() currentUser: CurrentUser, + @Parent() user: UserType + ) { + if (!currentUser || currentUser.id !== user.id) { + throw new ActionForbidden(); + } return await this.calendar.listAccounts(user.id); } +} - @Query(() => [CalendarSubscriptionObjectType]) - async calendarAccountCalendars( +@Resolver(() => CalendarAccountObjectType) +export class CalendarAccountResolver { + constructor(private readonly calendar: CalendarService) {} + + @ResolveField(() => [CalendarSubscriptionObjectType]) + async calendars( @CurrentUser() user: CurrentUser, - @Args('accountId') accountId: string + @Parent() account: CalendarAccountObjectType ) { - return await this.calendar.listAccountCalendars(user.id, accountId); + return await this.calendar.listAccountCalendars(user.id, account.id); } +} - @Query(() => [WorkspaceCalendarObjectType]) - async workspaceCalendars( +@Resolver(() => WorkspaceType) +export class WorkspaceCalendarResolver { + constructor( + private readonly calendar: CalendarService, + private readonly access: AccessController + ) {} + + @ResolveField(() => [WorkspaceCalendarObjectType]) + async calendars( @CurrentUser() user: CurrentUser, - @Args('workspaceId') workspaceId: string + @Parent() workspace: WorkspaceType ) { await this.access .user(user.id) - .workspace(workspaceId) - .assert('Workspace.CreateDoc'); - return await this.calendar.getWorkspaceCalendars(workspaceId); + .workspace(workspace.id) + .assert('Workspace.Settings.Read'); + return await this.calendar.getWorkspaceCalendars(workspace.id); } +} - @Query(() => [CalendarEventObjectType]) - async calendarEvents( +@Resolver(() => WorkspaceCalendarObjectType) +export class WorkspaceCalendarEventsResolver { + constructor( + private readonly calendar: CalendarService, + private readonly access: AccessController + ) {} + + @ResolveField(() => [CalendarEventObjectType]) + async events( @CurrentUser() user: CurrentUser, - @Args('workspaceCalendarId') workspaceCalendarId: string, + @Parent() calendar: WorkspaceCalendarObjectType, @Args({ name: 'from', type: () => GraphQLISODateTime }) from: Date, @Args({ name: 'to', type: () => GraphQLISODateTime }) to: Date ) { - const workspaceCalendar = - await this.models.workspaceCalendar.get(workspaceCalendarId); - if (!workspaceCalendar) { - return []; - } - await this.access .user(user.id) - .workspace(workspaceCalendar.workspaceId) - .assert('Workspace.CreateDoc'); + .workspace(calendar.workspaceId) + .assert('Workspace.Settings.Read'); return await this.calendar.listWorkspaceEvents({ - workspaceCalendarId, + workspaceCalendarId: calendar.id, from, to, }); } +} - @Query(() => [CalendarProviderName]) - async calendarProviders() { - return this.providerFactory.providers; - } +@Resolver(() => CalendarAccountObjectType) +export class CalendarMutationResolver { + constructor( + private readonly calendar: CalendarService, + private readonly oauth: CalendarOAuthService, + private readonly models: Models, + private readonly access: AccessController + ) {} @Mutation(() => String) async linkCalendarAccount( diff --git a/packages/backend/server/src/plugins/copilot/resolver.ts b/packages/backend/server/src/plugins/copilot/resolver.ts index a106c562c..580fe7509 100644 --- a/packages/backend/server/src/plugins/copilot/resolver.ts +++ b/packages/backend/server/src/plugins/copilot/resolver.ts @@ -825,6 +825,7 @@ export class CopilotResolver { @Query(() => String, { description: 'Apply updates to a doc using LLM and return the merged markdown.', + deprecationReason: 'use Mutation.applyDocUpdates', }) async applyDocUpdates( @CurrentUser() user: CurrentUser, @@ -836,6 +837,35 @@ export class CopilotResolver { op: string, @Args({ name: 'updates', type: () => String }) updates: string + ): Promise { + return this.applyDocUpdatesInternal(user, workspaceId, docId, op, updates); + } + + @Mutation(() => String, { + description: + 'Apply updates to a doc using LLM and return the merged markdown.', + name: 'applyDocUpdates', + }) + async applyDocUpdatesMutation( + @CurrentUser() user: CurrentUser, + @Args({ name: 'workspaceId', type: () => String }) + workspaceId: string, + @Args({ name: 'docId', type: () => String }) + docId: string, + @Args({ name: 'op', type: () => String }) + op: string, + @Args({ name: 'updates', type: () => String }) + updates: string + ): Promise { + return this.applyDocUpdatesInternal(user, workspaceId, docId, op, updates); + } + + private async applyDocUpdatesInternal( + user: CurrentUser, + workspaceId: string, + docId: string, + op: string, + updates: string ): Promise { await this.assertPermission(user, { workspaceId, docId }); diff --git a/packages/backend/server/src/plugins/indexer/service.ts b/packages/backend/server/src/plugins/indexer/service.ts index abc2b8388..66d1d0eb9 100644 --- a/packages/backend/server/src/plugins/indexer/service.ts +++ b/packages/backend/server/src/plugins/indexer/service.ts @@ -230,64 +230,57 @@ export class IndexerService { docId, docSnapshot.blob ); - if (result) { - await this.write( - SearchTable.doc, - [ - { - workspaceId, - docId, - title: result.title, - summary: result.summary, - // NOTE(@fengmk): journal is not supported yet - // journal: result.journal, - createdByUserId: docSnapshot.createdBy ?? '', - updatedByUserId: docSnapshot.updatedBy ?? '', - createdAt: docSnapshot.createdAt, - updatedAt: docSnapshot.updatedAt, - }, - ], - options - ); - await this.deleteBlocksByDocId(workspaceId, docId, options); - await this.write( - SearchTable.block, - result.blocks.map(block => ({ + await this.write( + SearchTable.doc, + [ + { workspaceId, docId, - blockId: block.blockId, - content: block.content ?? '', - flavour: block.flavour, - blob: block.blob, - refDocId: block.refDocId, - ref: block.ref, - parentFlavour: block.parentFlavour, - parentBlockId: block.parentBlockId, - additional: block.additional - ? JSON.stringify(block.additional) - : undefined, - markdownPreview: undefined, + title: result.title, + summary: result.summary, + // NOTE(@fengmk): journal is not supported yet + // journal: result.journal, createdByUserId: docSnapshot.createdBy ?? '', updatedByUserId: docSnapshot.updatedBy ?? '', createdAt: docSnapshot.createdAt, updatedAt: docSnapshot.updatedAt, - })), - options - ); - - await this.queue.add('copilot.embedding.updateDoc', { + }, + ], + options + ); + await this.deleteBlocksByDocId(workspaceId, docId, options); + await this.write( + SearchTable.block, + result.blocks.map(block => ({ workspaceId, docId, - }); - this.logger.verbose( - `synced doc ${workspaceId}/${docId} with ${result.blocks.length} blocks` - ); - } else { - this.logger.warn( - `failed to parse ${workspaceId}/${docId}, no result returned`, - metadata - ); - } + blockId: block.blockId, + content: block.content ?? '', + flavour: block.flavour, + blob: block.blob, + refDocId: block.refDocId, + ref: block.ref, + parentFlavour: block.parentFlavour, + parentBlockId: block.parentBlockId, + additional: block.additional + ? JSON.stringify(block.additional) + : undefined, + markdownPreview: undefined, + createdByUserId: docSnapshot.createdBy ?? '', + updatedByUserId: docSnapshot.updatedBy ?? '', + createdAt: docSnapshot.createdAt, + updatedAt: docSnapshot.updatedAt, + })), + options + ); + + await this.queue.add('copilot.embedding.updateDoc', { + workspaceId, + docId, + }); + this.logger.verbose( + `synced doc ${workspaceId}/${docId} with ${result.blocks.length} blocks` + ); } catch (err) { this.logger.warn( `failed to parse ${workspaceId}/${docId}: ${err}`, diff --git a/packages/backend/server/src/schema.gql b/packages/backend/server/src/schema.gql index fa0f222d6..fbeb0d09c 100644 --- a/packages/backend/server/src/schema.gql +++ b/packages/backend/server/src/schema.gql @@ -193,6 +193,7 @@ type BlobUploadedPart { } type CalendarAccountObjectType { + calendars: [CalendarSubscriptionObjectType!]! calendarsCount: Int! createdAt: DateTime! displayName: String @@ -1384,6 +1385,9 @@ type Mutation { """Update workspace flags and features for admin""" adminUpdateWorkspace(input: AdminUpdateWorkspaceInput!): AdminWorkspace + + """Apply updates to a doc using LLM and return the merged markdown.""" + applyDocUpdates(docId: String!, op: String!, updates: String!, workspaceId: String!): String! approveMember(userId: String!, workspaceId: String!): Boolean! """Ban an user""" @@ -1449,7 +1453,7 @@ type Mutation { forkCopilotSession(options: ForkChatSessionInput!): String! generateLicenseKey(sessionId: String!): String! generateUserAccessToken(input: GenerateAccessTokenInput!): RevealedAccessToken! - getBlobUploadPartUrl(key: String!, partNumber: Int!, uploadId: String!, workspaceId: String!): BlobUploadPart! + getBlobUploadPartUrl(key: String!, partNumber: Int!, uploadId: String!, workspaceId: String!): BlobUploadPart! @deprecated(reason: "use WorkspaceType.blobUploadPartUrl") grantDocUserRoles(input: GrantDocUserRolesInput!): Boolean! grantMember(permission: Permission!, userId: String!, workspaceId: String!): Boolean! @@ -1572,7 +1576,7 @@ type Mutation { uploadCommentAttachment(attachment: Upload!, docId: String!, workspaceId: String!): String! """validate app configuration""" - validateAppConfig(updates: [UpdateAppConfigInput!]!): [AppConfigValidateResult!]! + validateAppConfig(updates: [UpdateAppConfigInput!]!): [AppConfigValidateResult!]! @deprecated(reason: "use Query.validateAppConfig") verifyEmail(token: String!): Boolean! } @@ -1750,7 +1754,7 @@ type PublicUserType { } type Query { - accessTokens: [AccessToken!]! + accessTokens: [AccessToken!]! @deprecated(reason: "use currentUser.accessTokens") """Get workspace detail for admin""" adminWorkspace(id: String!): AdminWorkspace @@ -1765,11 +1769,7 @@ type Query { appConfig: JSONObject! """Apply updates to a doc using LLM and return the merged markdown.""" - applyDocUpdates(docId: String!, op: String!, updates: String!, workspaceId: String!): String! - calendarAccountCalendars(accountId: String!): [CalendarSubscriptionObjectType!]! - calendarAccounts: [CalendarAccountObjectType!]! - calendarEvents(from: DateTime!, to: DateTime!, workspaceCalendarId: String!): [CalendarEventObjectType!]! - calendarProviders: [CalendarProviderType!]! + applyDocUpdates(docId: String!, op: String!, updates: String!, workspaceId: String!): String! @deprecated(reason: "use Mutation.applyDocUpdates") collectAllBlobSizes: WorkspaceBlobSizes! @deprecated(reason: "use `user.quotaUsage` instead") """Get current user""" @@ -1794,7 +1794,7 @@ type Query { """query workspace embedding status""" queryWorkspaceEmbeddingStatus(workspaceId: String!): ContextWorkspaceEmbeddingStatus! - revealedAccessTokens: [RevealedAccessToken!]! + revealedAccessTokens: [RevealedAccessToken!]! @deprecated(reason: "use currentUser.revealedAccessTokens") """server config""" serverConfig: ServerConfigType! @@ -1814,9 +1814,11 @@ type Query { """Get users count""" usersCount(filter: ListUserInput): Int! + """validate app configuration""" + validateAppConfig(updates: [UpdateAppConfigInput!]!): [AppConfigValidateResult!]! + """Get workspace by id""" workspace(id: String!): WorkspaceType! - workspaceCalendars(workspaceId: String!): [WorkspaceCalendarObjectType!]! """Get workspace role permissions""" workspaceRolePermissions(id: String!): WorkspaceRolePermissions! @deprecated(reason: "use WorkspaceType[permissions] instead") @@ -2048,6 +2050,7 @@ type ServerConfigType { """server base url""" baseUrl: String! + calendarProviders: [CalendarProviderType!]! """credentials requirement""" credentialsRequirement: CredentialsRequirementType! @@ -2345,8 +2348,11 @@ type UserSettingsType { } type UserType { + accessTokens: [AccessToken!]! + """User avatar url""" avatarUrl: String + calendarAccounts: [CalendarAccountObjectType!]! copilot(workspaceId: String): Copilot! """User email verified""" @@ -2382,6 +2388,7 @@ type UserType { notifications(pagination: PaginationInput!): PaginatedNotificationObjectType! quota: UserQuotaType! quotaUsage: UserQuotaUsageType! + revealedAccessTokens: [RevealedAccessToken!]! """Get user settings""" settings: UserSettingsType! @@ -2421,6 +2428,7 @@ type WorkspaceCalendarObjectType { createdByUserId: String! displayNameOverride: String enabled: Boolean! + events(from: DateTime!, to: DateTime!): [CalendarEventObjectType!]! id: String! items: [WorkspaceCalendarItemObjectType!]! workspaceId: String! @@ -2511,11 +2519,15 @@ type WorkspaceType { """Search a specific table with aggregate""" aggregate(input: AggregateInput!): AggregateResultObjectType! + """Get blob upload part url""" + blobUploadPartUrl(key: String!, partNumber: Int!, uploadId: String!): BlobUploadPart! + """List blobs of workspace""" blobs: [ListedBlob!]! """Blobs size of workspace""" blobsSize: Int! + calendars: [WorkspaceCalendarObjectType!]! """Get comment changes of a doc""" commentChanges(docId: String!, pagination: PaginationInput!): PaginatedCommentChangeObjectType! diff --git a/packages/common/graphql/src/graphql/access-token/list.gql b/packages/common/graphql/src/graphql/access-token/list.gql index 13dd31027..45b2af5ab 100644 --- a/packages/common/graphql/src/graphql/access-token/list.gql +++ b/packages/common/graphql/src/graphql/access-token/list.gql @@ -1,9 +1,11 @@ query listUserAccessTokens { - revealedAccessTokens { - id - name - createdAt - expiresAt - token + currentUser { + revealedAccessTokens { + id + name + createdAt + expiresAt + token + } } -} \ No newline at end of file +} diff --git a/packages/common/graphql/src/graphql/admin/validate-config.gql b/packages/common/graphql/src/graphql/admin/validate-config.gql index 603a9cf31..0ca494ffd 100644 --- a/packages/common/graphql/src/graphql/admin/validate-config.gql +++ b/packages/common/graphql/src/graphql/admin/validate-config.gql @@ -1,4 +1,4 @@ -mutation validateConfig($updates: [UpdateAppConfigInput!]!) { +query validateConfig($updates: [UpdateAppConfigInput!]!) { validateAppConfig(updates: $updates) { module key @@ -6,4 +6,4 @@ mutation validateConfig($updates: [UpdateAppConfigInput!]!) { valid error } -} \ No newline at end of file +} diff --git a/packages/common/graphql/src/graphql/blob-upload-part-url.gql b/packages/common/graphql/src/graphql/blob-upload-part-url.gql index b8b3f9131..837fb84fd 100644 --- a/packages/common/graphql/src/graphql/blob-upload-part-url.gql +++ b/packages/common/graphql/src/graphql/blob-upload-part-url.gql @@ -1,7 +1,9 @@ -mutation getBlobUploadPartUrl($workspaceId: String!, $key: String!, $uploadId: String!, $partNumber: Int!) { - getBlobUploadPartUrl(workspaceId: $workspaceId, key: $key, uploadId: $uploadId, partNumber: $partNumber) { - uploadUrl - headers - expiresAt +query getBlobUploadPartUrl($workspaceId: String!, $key: String!, $uploadId: String!, $partNumber: Int!) { + workspace(id: $workspaceId) { + blobUploadPartUrl(key: $key, uploadId: $uploadId, partNumber: $partNumber) { + uploadUrl + headers + expiresAt + } } } diff --git a/packages/common/graphql/src/graphql/calendar/calendar-account-calendars.gql b/packages/common/graphql/src/graphql/calendar/calendar-account-calendars.gql deleted file mode 100644 index f4c544180..000000000 --- a/packages/common/graphql/src/graphql/calendar/calendar-account-calendars.gql +++ /dev/null @@ -1,13 +0,0 @@ -query calendarAccountCalendars($accountId: String!) { - calendarAccountCalendars(accountId: $accountId) { - id - accountId - provider - externalCalendarId - displayName - timezone - color - enabled - lastSyncAt - } -} diff --git a/packages/common/graphql/src/graphql/calendar/calendar-accounts.gql b/packages/common/graphql/src/graphql/calendar/calendar-accounts.gql index 60f42fccf..330fcd098 100644 --- a/packages/common/graphql/src/graphql/calendar/calendar-accounts.gql +++ b/packages/common/graphql/src/graphql/calendar/calendar-accounts.gql @@ -1,15 +1,28 @@ query calendarAccounts { - calendarAccounts { - id - provider - providerAccountId - displayName - email - status - lastError - refreshIntervalMinutes - calendarsCount - createdAt - updatedAt + currentUser { + calendarAccounts { + id + provider + providerAccountId + displayName + email + status + lastError + refreshIntervalMinutes + calendarsCount + createdAt + updatedAt + calendars { + id + accountId + provider + externalCalendarId + displayName + timezone + color + enabled + lastSyncAt + } + } } } diff --git a/packages/common/graphql/src/graphql/calendar/calendar-events.gql b/packages/common/graphql/src/graphql/calendar/calendar-events.gql index 9d031d2f7..aafcf1670 100644 --- a/packages/common/graphql/src/graphql/calendar/calendar-events.gql +++ b/packages/common/graphql/src/graphql/calendar/calendar-events.gql @@ -1,16 +1,21 @@ -query calendarEvents($workspaceCalendarId: String!, $from: DateTime!, $to: DateTime!) { - calendarEvents(workspaceCalendarId: $workspaceCalendarId, from: $from, to: $to) { - id - subscriptionId - externalEventId - recurrenceId - status - title - description - location - startAtUtc - endAtUtc - originalTimezone - allDay +query calendarEvents($workspaceId: String!, $from: DateTime!, $to: DateTime!) { + workspace(id: $workspaceId) { + calendars { + id + events(from: $from, to: $to) { + id + subscriptionId + externalEventId + recurrenceId + status + title + description + location + startAtUtc + endAtUtc + originalTimezone + allDay + } + } } } diff --git a/packages/common/graphql/src/graphql/calendar/calendar-providers.gql b/packages/common/graphql/src/graphql/calendar/calendar-providers.gql index ab6ec2eb6..f66017c63 100644 --- a/packages/common/graphql/src/graphql/calendar/calendar-providers.gql +++ b/packages/common/graphql/src/graphql/calendar/calendar-providers.gql @@ -1,3 +1,5 @@ query calendarProviders { - calendarProviders + serverConfig { + calendarProviders + } } diff --git a/packages/common/graphql/src/graphql/calendar/workspace-calendars.gql b/packages/common/graphql/src/graphql/calendar/workspace-calendars.gql index f90a109fc..e42418f39 100644 --- a/packages/common/graphql/src/graphql/calendar/workspace-calendars.gql +++ b/packages/common/graphql/src/graphql/calendar/workspace-calendars.gql @@ -1,17 +1,19 @@ query workspaceCalendars($workspaceId: String!) { - workspaceCalendars(workspaceId: $workspaceId) { - id - workspaceId - createdByUserId - displayNameOverride - colorOverride - enabled - items { + workspace(id: $workspaceId) { + calendars { id - subscriptionId - sortOrder + workspaceId + createdByUserId + displayNameOverride colorOverride enabled + items { + id + subscriptionId + sortOrder + colorOverride + enabled + } } } } diff --git a/packages/common/graphql/src/graphql/copilot-apply-doc-updates.gql b/packages/common/graphql/src/graphql/copilot-apply-doc-updates.gql index 94b1e9508..1d67e3ed7 100644 --- a/packages/common/graphql/src/graphql/copilot-apply-doc-updates.gql +++ b/packages/common/graphql/src/graphql/copilot-apply-doc-updates.gql @@ -1,3 +1,3 @@ -query applyDocUpdates($workspaceId: String!, $docId: String!, $op: String!, $updates: String!) { +mutation applyDocUpdates($workspaceId: String!, $docId: String!, $op: String!, $updates: String!) { applyDocUpdates(workspaceId: $workspaceId, docId: $docId, op: $op, updates: $updates) -} \ No newline at end of file +} diff --git a/packages/common/graphql/src/graphql/fragments/current-user-profile.gql b/packages/common/graphql/src/graphql/fragments/current-user-profile.gql new file mode 100644 index 000000000..f2a4b148a --- /dev/null +++ b/packages/common/graphql/src/graphql/fragments/current-user-profile.gql @@ -0,0 +1,36 @@ +fragment CurrentUserProfile on UserType { + id + name + email + avatarUrl + emailVerified + features + settings { + receiveInvitationEmail + receiveMentionEmail + receiveCommentEmail + } + quota { + name + blobLimit + storageQuota + historyPeriod + memberLimit + humanReadable { + name + blobLimit + storageQuota + historyPeriod + memberLimit + } + } + quotaUsage { + storageQuota + } + copilot { + quota { + limit + used + } + } +} diff --git a/packages/common/graphql/src/graphql/get-current-user-profile.gql b/packages/common/graphql/src/graphql/get-current-user-profile.gql new file mode 100644 index 000000000..fd786998a --- /dev/null +++ b/packages/common/graphql/src/graphql/get-current-user-profile.gql @@ -0,0 +1,7 @@ +#import './fragments/current-user-profile.gql' + +query getCurrentUserProfile { + currentUser { + ...CurrentUserProfile + } +} diff --git a/packages/common/graphql/src/graphql/get-workspace-info.gql b/packages/common/graphql/src/graphql/get-workspace-info.gql index 29bfe9d26..abd19fd9d 100644 --- a/packages/common/graphql/src/graphql/get-workspace-info.gql +++ b/packages/common/graphql/src/graphql/get-workspace-info.gql @@ -1,5 +1,27 @@ query getWorkspaceInfo($workspaceId: String!) { workspace(id: $workspaceId) { + permissions { + Workspace_Administrators_Manage + Workspace_Blobs_List + Workspace_Blobs_Read + Workspace_Blobs_Write + Workspace_Copilot + Workspace_CreateDoc + Workspace_Delete + Workspace_Organize_Read + Workspace_Payment_Manage + Workspace_Properties_Create + Workspace_Properties_Delete + Workspace_Properties_Read + Workspace_Properties_Update + Workspace_Read + Workspace_Settings_Read + Workspace_Settings_Update + Workspace_Sync + Workspace_TransferOwner + Workspace_Users_Manage + Workspace_Users_Read + } role team } diff --git a/packages/common/graphql/src/graphql/index.ts b/packages/common/graphql/src/graphql/index.ts index 8b7c4b2e0..1ace1d24b 100644 --- a/packages/common/graphql/src/graphql/index.ts +++ b/packages/common/graphql/src/graphql/index.ts @@ -58,6 +58,42 @@ export const credentialsRequirementsFragment = `fragment CredentialsRequirements ...PasswordLimits } }`; +export const currentUserProfileFragment = `fragment CurrentUserProfile on UserType { + id + name + email + avatarUrl + emailVerified + features + settings { + receiveInvitationEmail + receiveMentionEmail + receiveCommentEmail + } + quota { + name + blobLimit + storageQuota + historyPeriod + memberLimit + humanReadable { + name + blobLimit + storageQuota + historyPeriod + memberLimit + } + } + quotaUsage { + storageQuota + } + copilot { + quota { + limit + used + } + } +}`; export const passwordLimitsFragment = `fragment PasswordLimits on PasswordLimitsType { minLength maxLength @@ -88,12 +124,14 @@ export const listUserAccessTokensQuery = { id: 'listUserAccessTokensQuery' as const, op: 'listUserAccessTokens', query: `query listUserAccessTokens { - revealedAccessTokens { - id - name - createdAt - expiresAt - token + currentUser { + revealedAccessTokens { + id + name + createdAt + expiresAt + token + } } }`, }; @@ -444,10 +482,10 @@ export const updateAppConfigMutation = { }`, }; -export const validateConfigMutation = { - id: 'validateConfigMutation' as const, +export const validateConfigQuery = { + id: 'validateConfigQuery' as const, op: 'validateConfig', - query: `mutation validateConfig($updates: [UpdateAppConfigInput!]!) { + query: `query validateConfig($updates: [UpdateAppConfigInput!]!) { validateAppConfig(updates: $updates) { module key @@ -540,37 +578,16 @@ export const createBlobUploadMutation = { }`, }; -export const getBlobUploadPartUrlMutation = { - id: 'getBlobUploadPartUrlMutation' as const, +export const getBlobUploadPartUrlQuery = { + id: 'getBlobUploadPartUrlQuery' as const, op: 'getBlobUploadPartUrl', - query: `mutation getBlobUploadPartUrl($workspaceId: String!, $key: String!, $uploadId: String!, $partNumber: Int!) { - getBlobUploadPartUrl( - workspaceId: $workspaceId - key: $key - uploadId: $uploadId - partNumber: $partNumber - ) { - uploadUrl - headers - expiresAt - } -}`, -}; - -export const calendarAccountCalendarsQuery = { - id: 'calendarAccountCalendarsQuery' as const, - op: 'calendarAccountCalendars', - query: `query calendarAccountCalendars($accountId: String!) { - calendarAccountCalendars(accountId: $accountId) { - id - accountId - provider - externalCalendarId - displayName - timezone - color - enabled - lastSyncAt + query: `query getBlobUploadPartUrl($workspaceId: String!, $key: String!, $uploadId: String!, $partNumber: Int!) { + workspace(id: $workspaceId) { + blobUploadPartUrl(key: $key, uploadId: $uploadId, partNumber: $partNumber) { + uploadUrl + headers + expiresAt + } } }`, }; @@ -579,18 +596,31 @@ export const calendarAccountsQuery = { id: 'calendarAccountsQuery' as const, op: 'calendarAccounts', query: `query calendarAccounts { - calendarAccounts { - id - provider - providerAccountId - displayName - email - status - lastError - refreshIntervalMinutes - calendarsCount - createdAt - updatedAt + currentUser { + calendarAccounts { + id + provider + providerAccountId + displayName + email + status + lastError + refreshIntervalMinutes + calendarsCount + createdAt + updatedAt + calendars { + id + accountId + provider + externalCalendarId + displayName + timezone + color + enabled + lastSyncAt + } + } } }`, }; @@ -598,20 +628,25 @@ export const calendarAccountsQuery = { export const calendarEventsQuery = { id: 'calendarEventsQuery' as const, op: 'calendarEvents', - query: `query calendarEvents($workspaceCalendarId: String!, $from: DateTime!, $to: DateTime!) { - calendarEvents(workspaceCalendarId: $workspaceCalendarId, from: $from, to: $to) { - id - subscriptionId - externalEventId - recurrenceId - status - title - description - location - startAtUtc - endAtUtc - originalTimezone - allDay + query: `query calendarEvents($workspaceId: String!, $from: DateTime!, $to: DateTime!) { + workspace(id: $workspaceId) { + calendars { + id + events(from: $from, to: $to) { + id + subscriptionId + externalEventId + recurrenceId + status + title + description + location + startAtUtc + endAtUtc + originalTimezone + allDay + } + } } }`, }; @@ -620,7 +655,9 @@ export const calendarProvidersQuery = { id: 'calendarProvidersQuery' as const, op: 'calendarProviders', query: `query calendarProviders { - calendarProviders + serverConfig { + calendarProviders + } }`, }; @@ -689,19 +726,21 @@ export const workspaceCalendarsQuery = { id: 'workspaceCalendarsQuery' as const, op: 'workspaceCalendars', query: `query workspaceCalendars($workspaceId: String!) { - workspaceCalendars(workspaceId: $workspaceId) { - id - workspaceId - createdByUserId - displayNameOverride - colorOverride - enabled - items { + workspace(id: $workspaceId) { + calendars { id - subscriptionId - sortOrder + workspaceId + createdByUserId + displayNameOverride colorOverride enabled + items { + id + subscriptionId + sortOrder + colorOverride + enabled + } } } }`, @@ -915,10 +954,10 @@ export const uploadCommentAttachmentMutation = { file: true, }; -export const applyDocUpdatesQuery = { - id: 'applyDocUpdatesQuery' as const, +export const applyDocUpdatesMutation = { + id: 'applyDocUpdatesMutation' as const, op: 'applyDocUpdates', - query: `query applyDocUpdates($workspaceId: String!, $docId: String!, $op: String!, $updates: String!) { + query: `mutation applyDocUpdates($workspaceId: String!, $docId: String!, $op: String!, $updates: String!) { applyDocUpdates( workspaceId: $workspaceId docId: $docId @@ -1748,6 +1787,17 @@ export const getCurrentUserFeaturesQuery = { }`, }; +export const getCurrentUserProfileQuery = { + id: 'getCurrentUserProfileQuery' as const, + op: 'getCurrentUserProfile', + query: `query getCurrentUserProfile { + currentUser { + ...CurrentUserProfile + } +} +${currentUserProfileFragment}`, +}; + export const getCurrentUserQuery = { id: 'getCurrentUserQuery' as const, op: 'getCurrentUser', @@ -1998,6 +2048,28 @@ export const getWorkspaceInfoQuery = { op: 'getWorkspaceInfo', query: `query getWorkspaceInfo($workspaceId: String!) { workspace(id: $workspaceId) { + permissions { + Workspace_Administrators_Manage + Workspace_Blobs_List + Workspace_Blobs_Read + Workspace_Blobs_Write + Workspace_Copilot + Workspace_CreateDoc + Workspace_Delete + Workspace_Organize_Read + Workspace_Payment_Manage + Workspace_Properties_Create + Workspace_Properties_Delete + Workspace_Properties_Read + Workspace_Properties_Update + Workspace_Read + Workspace_Settings_Read + Workspace_Settings_Update + Workspace_Sync + Workspace_TransferOwner + Workspace_Users_Manage + Workspace_Users_Read + } role team } @@ -2336,7 +2408,9 @@ export const notificationCountQuery = { op: 'notificationCount', query: `query notificationCount { currentUser { - notificationCount + notifications(pagination: {first: 1}) { + totalCount + } } }`, }; @@ -2523,6 +2597,7 @@ export const serverConfigQuery = { features type initialized + calendarProviders credentialsRequirement { ...CredentialsRequirements } diff --git a/packages/common/graphql/src/graphql/notification-count.gql b/packages/common/graphql/src/graphql/notification-count.gql index 42813d01d..b5c123fa0 100644 --- a/packages/common/graphql/src/graphql/notification-count.gql +++ b/packages/common/graphql/src/graphql/notification-count.gql @@ -1,5 +1,7 @@ query notificationCount { - currentUser { - notificationCount + currentUser { + notifications(pagination: { first: 1 }) { + totalCount } + } } diff --git a/packages/common/graphql/src/graphql/server-config.gql b/packages/common/graphql/src/graphql/server-config.gql index ac8408567..15e2176c9 100644 --- a/packages/common/graphql/src/graphql/server-config.gql +++ b/packages/common/graphql/src/graphql/server-config.gql @@ -9,6 +9,7 @@ query serverConfig { features type initialized + calendarProviders credentialsRequirement { ...CredentialsRequirements } diff --git a/packages/common/graphql/src/schema.ts b/packages/common/graphql/src/schema.ts index c0736fbad..3f68defd5 100644 --- a/packages/common/graphql/src/schema.ts +++ b/packages/common/graphql/src/schema.ts @@ -246,6 +246,7 @@ export interface BlobUploadedPart { export interface CalendarAccountObjectType { __typename?: 'CalendarAccountObjectType'; + calendars: Array; calendarsCount: Scalars['Int']['output']; createdAt: Scalars['DateTime']['output']; displayName: Maybe; @@ -1570,6 +1571,8 @@ export interface Mutation { addWorkspaceFeature: Scalars['Boolean']['output']; /** Update workspace flags and features for admin */ adminUpdateWorkspace: Maybe; + /** Apply updates to a doc using LLM and return the merged markdown. */ + applyDocUpdates: Scalars['String']['output']; approveMember: Scalars['Boolean']['output']; /** Ban an user */ banUser: UserType; @@ -1619,6 +1622,7 @@ export interface Mutation { forkCopilotSession: Scalars['String']['output']; generateLicenseKey: Scalars['String']['output']; generateUserAccessToken: RevealedAccessToken; + /** @deprecated use WorkspaceType.blobUploadPartUrl */ getBlobUploadPartUrl: BlobUploadPart; grantDocUserRoles: Scalars['Boolean']['output']; grantMember: Scalars['Boolean']['output']; @@ -1716,7 +1720,10 @@ export interface Mutation { uploadAvatar: UserType; /** Upload a comment attachment and return the access url */ uploadCommentAttachment: Scalars['String']['output']; - /** validate app configuration */ + /** + * validate app configuration + * @deprecated use Query.validateAppConfig + */ validateAppConfig: Array; verifyEmail: Scalars['Boolean']['output']; } @@ -1769,6 +1776,13 @@ export interface MutationAdminUpdateWorkspaceArgs { input: AdminUpdateWorkspaceInput; } +export interface MutationApplyDocUpdatesArgs { + docId: Scalars['String']['input']; + op: Scalars['String']['input']; + updates: Scalars['String']['input']; + workspaceId: Scalars['String']['input']; +} + export interface MutationApproveMemberArgs { userId: Scalars['String']['input']; workspaceId: Scalars['String']['input']; @@ -2387,6 +2401,7 @@ export interface PublicUserType { export interface Query { __typename?: 'Query'; + /** @deprecated use currentUser.accessTokens */ accessTokens: Array; /** Get workspace detail for admin */ adminWorkspace: Maybe; @@ -2396,12 +2411,11 @@ export interface Query { adminWorkspacesCount: Scalars['Int']['output']; /** get the whole app configuration */ appConfig: Scalars['JSONObject']['output']; - /** Apply updates to a doc using LLM and return the merged markdown. */ + /** + * Apply updates to a doc using LLM and return the merged markdown. + * @deprecated use Mutation.applyDocUpdates + */ applyDocUpdates: Scalars['String']['output']; - calendarAccountCalendars: Array; - calendarAccounts: Array; - calendarEvents: Array; - calendarProviders: Array; /** @deprecated use `user.quotaUsage` instead */ collectAllBlobSizes: WorkspaceBlobSizes; /** Get current user */ @@ -2426,6 +2440,7 @@ export interface Query { publicUserById: Maybe; /** query workspace embedding status */ queryWorkspaceEmbeddingStatus: ContextWorkspaceEmbeddingStatus; + /** @deprecated use currentUser.revealedAccessTokens */ revealedAccessTokens: Array; /** server config */ serverConfig: ServerConfigType; @@ -2439,9 +2454,10 @@ export interface Query { users: Array; /** Get users count */ usersCount: Scalars['Int']['output']; + /** validate app configuration */ + validateAppConfig: Array; /** Get workspace by id */ workspace: WorkspaceType; - workspaceCalendars: Array; /** * Get workspace role permissions * @deprecated use WorkspaceType[permissions] instead @@ -2470,16 +2486,6 @@ export interface QueryApplyDocUpdatesArgs { workspaceId: Scalars['String']['input']; } -export interface QueryCalendarAccountCalendarsArgs { - accountId: Scalars['String']['input']; -} - -export interface QueryCalendarEventsArgs { - from: Scalars['DateTime']['input']; - to: Scalars['DateTime']['input']; - workspaceCalendarId: Scalars['String']['input']; -} - export interface QueryErrorArgs { name: ErrorNames; } @@ -2524,12 +2530,12 @@ export interface QueryUsersCountArgs { filter?: InputMaybe; } -export interface QueryWorkspaceArgs { - id: Scalars['String']['input']; +export interface QueryValidateAppConfigArgs { + updates: Array; } -export interface QueryWorkspaceCalendarsArgs { - workspaceId: Scalars['String']['input']; +export interface QueryWorkspaceArgs { + id: Scalars['String']['input']; } export interface QueryWorkspaceRolePermissionsArgs { @@ -2754,6 +2760,7 @@ export interface ServerConfigType { availableWorkspaceFeatures: Array; /** server base url */ baseUrl: Scalars['String']['output']; + calendarProviders: Array; /** credentials requirement */ credentialsRequirement: CredentialsRequirementType; /** enabled server features */ @@ -3055,8 +3062,10 @@ export interface UserSettingsType { export interface UserType { __typename?: 'UserType'; + accessTokens: Array; /** User avatar url */ avatarUrl: Maybe; + calendarAccounts: Array; copilot: Copilot; /** * User email verified @@ -3085,6 +3094,7 @@ export interface UserType { notifications: PaginatedNotificationObjectType; quota: UserQuotaType; quotaUsage: UserQuotaUsageType; + revealedAccessTokens: Array; /** Get user settings */ settings: UserSettingsType; subscriptions: Array; @@ -3142,11 +3152,17 @@ export interface WorkspaceCalendarObjectType { createdByUserId: Scalars['String']['output']; displayNameOverride: Maybe; enabled: Scalars['Boolean']['output']; + events: Array; id: Scalars['String']['output']; items: Array; workspaceId: Scalars['String']['output']; } +export interface WorkspaceCalendarObjectTypeEventsArgs { + from: Scalars['DateTime']['input']; + to: Scalars['DateTime']['input']; +} + export interface WorkspaceDocMeta { __typename?: 'WorkspaceDocMeta'; createdAt: Scalars['DateTime']['output']; @@ -3239,10 +3255,13 @@ export interface WorkspaceType { __typename?: 'WorkspaceType'; /** Search a specific table with aggregate */ aggregate: AggregateResultObjectType; + /** Get blob upload part url */ + blobUploadPartUrl: BlobUploadPart; /** List blobs of workspace */ blobs: Array; /** Blobs size of workspace */ blobsSize: Scalars['Int']['output']; + calendars: Array; /** Get comment changes of a doc */ commentChanges: PaginatedCommentChangeObjectType; /** Get comments of a doc */ @@ -3314,6 +3333,12 @@ export interface WorkspaceTypeAggregateArgs { input: AggregateInput; } +export interface WorkspaceTypeBlobUploadPartUrlArgs { + key: Scalars['String']['input']; + partNumber: Scalars['Int']['input']; + uploadId: Scalars['String']['input']; +} + export interface WorkspaceTypeCommentChangesArgs { docId: Scalars['String']['input']; pagination: PaginationInput; @@ -3411,14 +3436,17 @@ export type ListUserAccessTokensQueryVariables = Exact<{ export type ListUserAccessTokensQuery = { __typename?: 'Query'; - revealedAccessTokens: Array<{ - __typename?: 'RevealedAccessToken'; - id: string; - name: string; - createdAt: string; - expiresAt: string | null; - token: string; - }>; + currentUser: { + __typename?: 'UserType'; + revealedAccessTokens: Array<{ + __typename?: 'RevealedAccessToken'; + id: string; + name: string; + createdAt: string; + expiresAt: string | null; + token: string; + }>; + } | null; }; export type RevokeUserAccessTokenMutationVariables = Exact<{ @@ -3793,12 +3821,12 @@ export type UpdateAppConfigMutation = { updateAppConfig: any; }; -export type ValidateConfigMutationVariables = Exact<{ +export type ValidateConfigQueryVariables = Exact<{ updates: Array | UpdateAppConfigInput; }>; -export type ValidateConfigMutation = { - __typename?: 'Mutation'; +export type ValidateConfigQuery = { + __typename?: 'Query'; validateAppConfig: Array<{ __typename?: 'AppConfigValidateResult'; module: string; @@ -3904,93 +3932,101 @@ export type CreateBlobUploadMutation = { }; }; -export type GetBlobUploadPartUrlMutationVariables = Exact<{ +export type GetBlobUploadPartUrlQueryVariables = Exact<{ workspaceId: Scalars['String']['input']; key: Scalars['String']['input']; uploadId: Scalars['String']['input']; partNumber: Scalars['Int']['input']; }>; -export type GetBlobUploadPartUrlMutation = { - __typename?: 'Mutation'; - getBlobUploadPartUrl: { - __typename?: 'BlobUploadPart'; - uploadUrl: string; - headers: any | null; - expiresAt: string | null; - }; -}; - -export type CalendarAccountCalendarsQueryVariables = Exact<{ - accountId: Scalars['String']['input']; -}>; - -export type CalendarAccountCalendarsQuery = { +export type GetBlobUploadPartUrlQuery = { __typename?: 'Query'; - calendarAccountCalendars: Array<{ - __typename?: 'CalendarSubscriptionObjectType'; - id: string; - accountId: string; - provider: CalendarProviderType; - externalCalendarId: string; - displayName: string | null; - timezone: string | null; - color: string | null; - enabled: boolean; - lastSyncAt: string | null; - }>; + workspace: { + __typename?: 'WorkspaceType'; + blobUploadPartUrl: { + __typename?: 'BlobUploadPart'; + uploadUrl: string; + headers: any | null; + expiresAt: string | null; + }; + }; }; export type CalendarAccountsQueryVariables = Exact<{ [key: string]: never }>; export type CalendarAccountsQuery = { __typename?: 'Query'; - calendarAccounts: Array<{ - __typename?: 'CalendarAccountObjectType'; - id: string; - provider: CalendarProviderType; - providerAccountId: string; - displayName: string | null; - email: string | null; - status: string; - lastError: string | null; - refreshIntervalMinutes: number; - calendarsCount: number; - createdAt: string; - updatedAt: string; - }>; + currentUser: { + __typename?: 'UserType'; + calendarAccounts: Array<{ + __typename?: 'CalendarAccountObjectType'; + id: string; + provider: CalendarProviderType; + providerAccountId: string; + displayName: string | null; + email: string | null; + status: string; + lastError: string | null; + refreshIntervalMinutes: number; + calendarsCount: number; + createdAt: string; + updatedAt: string; + calendars: Array<{ + __typename?: 'CalendarSubscriptionObjectType'; + id: string; + accountId: string; + provider: CalendarProviderType; + externalCalendarId: string; + displayName: string | null; + timezone: string | null; + color: string | null; + enabled: boolean; + lastSyncAt: string | null; + }>; + }>; + } | null; }; export type CalendarEventsQueryVariables = Exact<{ - workspaceCalendarId: Scalars['String']['input']; + workspaceId: Scalars['String']['input']; from: Scalars['DateTime']['input']; to: Scalars['DateTime']['input']; }>; export type CalendarEventsQuery = { __typename?: 'Query'; - calendarEvents: Array<{ - __typename?: 'CalendarEventObjectType'; - id: string; - subscriptionId: string; - externalEventId: string; - recurrenceId: string | null; - status: string | null; - title: string | null; - description: string | null; - location: string | null; - startAtUtc: string; - endAtUtc: string; - originalTimezone: string | null; - allDay: boolean; - }>; + workspace: { + __typename?: 'WorkspaceType'; + calendars: Array<{ + __typename?: 'WorkspaceCalendarObjectType'; + id: string; + events: Array<{ + __typename?: 'CalendarEventObjectType'; + id: string; + subscriptionId: string; + externalEventId: string; + recurrenceId: string | null; + status: string | null; + title: string | null; + description: string | null; + location: string | null; + startAtUtc: string; + endAtUtc: string; + originalTimezone: string | null; + allDay: boolean; + }>; + }>; + }; }; export type CalendarProvidersQueryVariables = Exact<{ [key: string]: never }>; export type CalendarProvidersQuery = { __typename?: 'Query'; - calendarProviders: Array; + serverConfig: { + __typename?: 'ServerConfigType'; + calendarProviders: Array; + }; }; export type LinkCalendarAccountMutationVariables = Exact<{ @@ -4065,23 +4101,26 @@ export type WorkspaceCalendarsQueryVariables = Exact<{ export type WorkspaceCalendarsQuery = { __typename?: 'Query'; - workspaceCalendars: Array<{ - __typename?: 'WorkspaceCalendarObjectType'; - id: string; - workspaceId: string; - createdByUserId: string; - displayNameOverride: string | null; - colorOverride: string | null; - enabled: boolean; - items: Array<{ - __typename?: 'WorkspaceCalendarItemObjectType'; + workspace: { + __typename?: 'WorkspaceType'; + calendars: Array<{ + __typename?: 'WorkspaceCalendarObjectType'; id: string; - subscriptionId: string; - sortOrder: number | null; + workspaceId: string; + createdByUserId: string; + displayNameOverride: string | null; colorOverride: string | null; enabled: boolean; + items: Array<{ + __typename?: 'WorkspaceCalendarItemObjectType'; + id: string; + subscriptionId: string; + sortOrder: number | null; + colorOverride: string | null; + enabled: boolean; + }>; }>; - }>; + }; }; export type CancelSubscriptionMutationVariables = Exact<{ @@ -4326,15 +4365,15 @@ export type UploadCommentAttachmentMutation = { uploadCommentAttachment: string; }; -export type ApplyDocUpdatesQueryVariables = Exact<{ +export type ApplyDocUpdatesMutationVariables = Exact<{ workspaceId: Scalars['String']['input']; docId: Scalars['String']['input']; op: Scalars['String']['input']; updates: Scalars['String']['input']; }>; -export type ApplyDocUpdatesQuery = { - __typename?: 'Query'; +export type ApplyDocUpdatesMutation = { + __typename?: 'Mutation'; applyDocUpdates: string; }; @@ -5722,6 +5761,43 @@ export type CredentialsRequirementsFragment = { }; }; +export type CurrentUserProfileFragment = { + __typename?: 'UserType'; + id: string; + name: string; + email: string; + avatarUrl: string | null; + emailVerified: boolean; + features: Array; + settings: { + __typename?: 'UserSettingsType'; + receiveInvitationEmail: boolean; + receiveMentionEmail: boolean; + receiveCommentEmail: boolean; + }; + quota: { + __typename?: 'UserQuotaType'; + name: string; + blobLimit: number; + storageQuota: number; + historyPeriod: number; + memberLimit: number; + humanReadable: { + __typename?: 'UserQuotaHumanReadableType'; + name: string; + blobLimit: string; + storageQuota: string; + historyPeriod: string; + memberLimit: string; + }; + }; + quotaUsage: { __typename?: 'UserQuotaUsageType'; storageQuota: number }; + copilot: { + __typename?: 'Copilot'; + quota: { __typename?: 'CopilotQuota'; limit: number | null; used: number }; + }; +}; + export type PasswordLimitsFragment = { __typename?: 'PasswordLimitsType'; minLength: number; @@ -5754,6 +5830,54 @@ export type GetCurrentUserFeaturesQuery = { } | null; }; +export type GetCurrentUserProfileQueryVariables = Exact<{ + [key: string]: never; +}>; + +export type GetCurrentUserProfileQuery = { + __typename?: 'Query'; + currentUser: { + __typename?: 'UserType'; + id: string; + name: string; + email: string; + avatarUrl: string | null; + emailVerified: boolean; + features: Array; + settings: { + __typename?: 'UserSettingsType'; + receiveInvitationEmail: boolean; + receiveMentionEmail: boolean; + receiveCommentEmail: boolean; + }; + quota: { + __typename?: 'UserQuotaType'; + name: string; + blobLimit: number; + storageQuota: number; + historyPeriod: number; + memberLimit: number; + humanReadable: { + __typename?: 'UserQuotaHumanReadableType'; + name: string; + blobLimit: string; + storageQuota: string; + historyPeriod: string; + memberLimit: string; + }; + }; + quotaUsage: { __typename?: 'UserQuotaUsageType'; storageQuota: number }; + copilot: { + __typename?: 'Copilot'; + quota: { + __typename?: 'CopilotQuota'; + limit: number | null; + used: number; + }; + }; + } | null; +}; + export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never }>; export type GetCurrentUserQuery = { @@ -6042,7 +6166,34 @@ export type GetWorkspaceInfoQueryVariables = Exact<{ export type GetWorkspaceInfoQuery = { __typename?: 'Query'; - workspace: { __typename?: 'WorkspaceType'; role: Permission; team: boolean }; + workspace: { + __typename?: 'WorkspaceType'; + role: Permission; + team: boolean; + permissions: { + __typename?: 'WorkspacePermissions'; + Workspace_Administrators_Manage: boolean; + Workspace_Blobs_List: boolean; + Workspace_Blobs_Read: boolean; + Workspace_Blobs_Write: boolean; + Workspace_Copilot: boolean; + Workspace_CreateDoc: boolean; + Workspace_Delete: boolean; + Workspace_Organize_Read: boolean; + Workspace_Payment_Manage: boolean; + Workspace_Properties_Create: boolean; + Workspace_Properties_Delete: boolean; + Workspace_Properties_Read: boolean; + Workspace_Properties_Update: boolean; + Workspace_Read: boolean; + Workspace_Settings_Read: boolean; + Workspace_Settings_Update: boolean; + Workspace_Sync: boolean; + Workspace_TransferOwner: boolean; + Workspace_Users_Manage: boolean; + Workspace_Users_Read: boolean; + }; + }; }; export type GetWorkspacePageByIdQueryVariables = Exact<{ @@ -6454,7 +6605,13 @@ export type NotificationCountQueryVariables = Exact<{ [key: string]: never }>; export type NotificationCountQuery = { __typename?: 'Query'; - currentUser: { __typename?: 'UserType'; notificationCount: number } | null; + currentUser: { + __typename?: 'UserType'; + notifications: { + __typename?: 'PaginatedNotificationObjectType'; + totalCount: number; + }; + } | null; }; export type PricesQueryVariables = Exact<{ [key: string]: never }>; @@ -6656,6 +6813,7 @@ export type ServerConfigQuery = { features: Array; type: ServerDeploymentType; initialized: boolean; + calendarProviders: Array; credentialsRequirement: { __typename?: 'CredentialsRequirementType'; password: { @@ -7101,15 +7259,20 @@ export type Queries = variables: ListUsersQueryVariables; response: ListUsersQuery; } + | { + name: 'validateConfigQuery'; + variables: ValidateConfigQueryVariables; + response: ValidateConfigQuery; + } | { name: 'listBlobsQuery'; variables: ListBlobsQueryVariables; response: ListBlobsQuery; } | { - name: 'calendarAccountCalendarsQuery'; - variables: CalendarAccountCalendarsQueryVariables; - response: CalendarAccountCalendarsQuery; + name: 'getBlobUploadPartUrlQuery'; + variables: GetBlobUploadPartUrlQueryVariables; + response: GetBlobUploadPartUrlQuery; } | { name: 'calendarAccountsQuery'; @@ -7141,11 +7304,6 @@ export type Queries = variables: ListCommentsQueryVariables; response: ListCommentsQuery; } - | { - name: 'applyDocUpdatesQuery'; - variables: ApplyDocUpdatesQueryVariables; - response: ApplyDocUpdatesQuery; - } | { name: 'listContextObjectQuery'; variables: ListContextObjectQueryVariables; @@ -7261,6 +7419,11 @@ export type Queries = variables: GetCurrentUserFeaturesQueryVariables; response: GetCurrentUserFeaturesQuery; } + | { + name: 'getCurrentUserProfileQuery'; + variables: GetCurrentUserProfileQueryVariables; + response: GetCurrentUserProfileQuery; + } | { name: 'getCurrentUserQuery'; variables: GetCurrentUserQueryVariables; @@ -7533,11 +7696,6 @@ export type Mutations = variables: UpdateAppConfigMutationVariables; response: UpdateAppConfigMutation; } - | { - name: 'validateConfigMutation'; - variables: ValidateConfigMutationVariables; - response: ValidateConfigMutation; - } | { name: 'deleteBlobMutation'; variables: DeleteBlobMutationVariables; @@ -7568,11 +7726,6 @@ export type Mutations = variables: CreateBlobUploadMutationVariables; response: CreateBlobUploadMutation; } - | { - name: 'getBlobUploadPartUrlMutation'; - variables: GetBlobUploadPartUrlMutationVariables; - response: GetBlobUploadPartUrlMutation; - } | { name: 'linkCalendarAccountMutation'; variables: LinkCalendarAccountMutationVariables; @@ -7648,6 +7801,11 @@ export type Mutations = variables: UploadCommentAttachmentMutationVariables; response: UploadCommentAttachmentMutation; } + | { + name: 'applyDocUpdatesMutation'; + variables: ApplyDocUpdatesMutationVariables; + response: ApplyDocUpdatesMutation; + } | { name: 'addContextBlobMutation'; variables: AddContextBlobMutationVariables; diff --git a/packages/common/nbstore/src/__tests__/cloud-blob.spec.ts b/packages/common/nbstore/src/__tests__/cloud-blob.spec.ts index 7be3d06f2..250a041ba 100644 --- a/packages/common/nbstore/src/__tests__/cloud-blob.spec.ts +++ b/packages/common/nbstore/src/__tests__/cloud-blob.spec.ts @@ -3,7 +3,7 @@ import { BlobUploadMethod, completeBlobUploadMutation, createBlobUploadMutation, - getBlobUploadPartUrlMutation, + getBlobUploadPartUrlQuery, setBlobMutation, workspaceBlobQuotaQuery, } from '@affine/graphql'; @@ -128,10 +128,12 @@ test('falls back to graphql and aborts when multipart upload fails', async () => }, }; } - if (query === getBlobUploadPartUrlMutation) { + if (query === getBlobUploadPartUrlQuery) { return { - getBlobUploadPartUrl: { - uploadUrl: 'https://upload.example.com/part', + workspace: { + blobUploadPartUrl: { + uploadUrl: 'https://upload.example.com/part', + }, }, }; } diff --git a/packages/common/nbstore/src/impls/cloud/blob.ts b/packages/common/nbstore/src/impls/cloud/blob.ts index bdf2a86a0..58d5170d9 100644 --- a/packages/common/nbstore/src/impls/cloud/blob.ts +++ b/packages/common/nbstore/src/impls/cloud/blob.ts @@ -5,7 +5,7 @@ import { completeBlobUploadMutation, createBlobUploadMutation, deleteBlobMutation, - getBlobUploadPartUrlMutation, + getBlobUploadPartUrlQuery, listBlobsQuery, releaseDeletedBlobsMutation, setBlobMutation, @@ -265,16 +265,16 @@ export class CloudBlobStorage extends BlobStorageBase { const chunk = data.subarray(start, end); const part = await this.connection.gql({ - query: getBlobUploadPartUrlMutation, + query: getBlobUploadPartUrlQuery, variables: { workspaceId: this.options.id, key, uploadId, partNumber }, context: { signal }, }); const res = await this.fetchWithTimeout( - part.getBlobUploadPartUrl.uploadUrl, + part.workspace.blobUploadPartUrl.uploadUrl, { method: 'PUT', - headers: part.getBlobUploadPartUrl.headers ?? undefined, + headers: part.workspace.blobUploadPartUrl.headers ?? undefined, body: chunk, signal, timeout: UPLOAD_REQUEST_TIMEOUT, diff --git a/packages/frontend/core/src/blocksuite/ai/provider/copilot-client.ts b/packages/frontend/core/src/blocksuite/ai/provider/copilot-client.ts index 63ac1bd49..506a7378d 100644 --- a/packages/frontend/core/src/blocksuite/ai/provider/copilot-client.ts +++ b/packages/frontend/core/src/blocksuite/ai/provider/copilot-client.ts @@ -6,7 +6,7 @@ import { addContextCategoryMutation, addContextDocMutation, addContextFileMutation, - applyDocUpdatesQuery, + applyDocUpdatesMutation, cleanupCopilotSessionMutation, createCopilotContextMutation, createCopilotMessageMutation, @@ -557,7 +557,7 @@ export class CopilotClient { updates: string ) { return this.gql({ - query: applyDocUpdatesQuery, + query: applyDocUpdatesMutation, variables: { workspaceId, docId, diff --git a/packages/frontend/core/src/desktop/dialogs/setting/account-setting/integrations-panel.tsx b/packages/frontend/core/src/desktop/dialogs/setting/account-setting/integrations-panel.tsx index 3125901da..f4525659e 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/account-setting/integrations-panel.tsx +++ b/packages/frontend/core/src/desktop/dialogs/setting/account-setting/integrations-panel.tsx @@ -24,7 +24,9 @@ import { import { CollapsibleWrapper } from '../layout'; import * as styles from './integrations-panel.css'; -type CalendarAccount = CalendarAccountsQuery['calendarAccounts'][number]; +type CalendarAccount = NonNullable< + CalendarAccountsQuery['currentUser'] +>['calendarAccounts'][number]; const providerMeta = { [CalendarProviderType.Google]: { @@ -66,8 +68,8 @@ export const IntegrationsPanel = () => { context: { signal }, }), ]); - setAccounts(accountsData.calendarAccounts); - setProviders(providersData.calendarProviders); + setAccounts(accountsData.currentUser?.calendarAccounts ?? []); + setProviders(providersData.serverConfig.calendarProviders ?? []); } catch (error) { if ( signal?.aborted || diff --git a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/calendar/subscription-setting.tsx b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/calendar/subscription-setting.tsx index 02ddcba9c..45528650d 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/calendar/subscription-setting.tsx +++ b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/calendar/subscription-setting.tsx @@ -1,12 +1,13 @@ import { Checkbox } from '@affine/component'; -import type { CalendarAccountCalendarsQuery } from '@affine/graphql'; +import type { CalendarAccountsQuery } from '@affine/graphql'; import { cssVarV2 } from '@toeverything/theme/v2'; import { useCallback } from 'react'; import * as styles from './subscription-setting.css'; -type CalendarSubscription = - CalendarAccountCalendarsQuery['calendarAccountCalendars'][number]; +type CalendarSubscription = NonNullable< + NonNullable['calendarAccounts'][number] +>['calendars'][number]; export const SubscriptionSetting = ({ subscription, diff --git a/packages/frontend/core/src/modules/cloud/stores/access-token.ts b/packages/frontend/core/src/modules/cloud/stores/access-token.ts index d1d5d95f3..e96142dff 100644 --- a/packages/frontend/core/src/modules/cloud/stores/access-token.ts +++ b/packages/frontend/core/src/modules/cloud/stores/access-token.ts @@ -8,8 +8,9 @@ import { Store } from '@toeverything/infra'; import type { GraphQLService } from '../services/graphql'; -export type AccessToken = - ListUserAccessTokensQuery['revealedAccessTokens'][number]; +export type AccessToken = NonNullable< + ListUserAccessTokensQuery['currentUser'] +>['revealedAccessTokens'][number]; export class AccessTokenStore extends Store { constructor(private readonly gqlService: GraphQLService) { @@ -22,7 +23,7 @@ export class AccessTokenStore extends Store { context: { signal }, }); - return data.revealedAccessTokens; + return data.currentUser?.revealedAccessTokens ?? []; } async generateUserAccessToken( diff --git a/packages/frontend/core/src/modules/cloud/stores/user-copilot-quota.ts b/packages/frontend/core/src/modules/cloud/stores/user-copilot-quota.ts index ebe5b5737..187925671 100644 --- a/packages/frontend/core/src/modules/cloud/stores/user-copilot-quota.ts +++ b/packages/frontend/core/src/modules/cloud/stores/user-copilot-quota.ts @@ -1,4 +1,4 @@ -import { copilotQuotaQuery } from '@affine/graphql'; +import { getCurrentUserProfileQuery } from '@affine/graphql'; import { Store } from '@toeverything/infra'; import type { GraphQLService } from '../services/graphql'; @@ -10,7 +10,7 @@ export class UserCopilotQuotaStore extends Store { async fetchUserCopilotQuota(abortSignal?: AbortSignal) { const data = await this.graphqlService.gql({ - query: copilotQuotaQuery, + query: getCurrentUserProfileQuery, context: { signal: abortSignal, }, diff --git a/packages/frontend/core/src/modules/cloud/stores/user-feature.ts b/packages/frontend/core/src/modules/cloud/stores/user-feature.ts index 6176c30ce..e720bb27f 100644 --- a/packages/frontend/core/src/modules/cloud/stores/user-feature.ts +++ b/packages/frontend/core/src/modules/cloud/stores/user-feature.ts @@ -1,4 +1,4 @@ -import { getUserFeaturesQuery } from '@affine/graphql'; +import { getCurrentUserProfileQuery } from '@affine/graphql'; import { Store } from '@toeverything/infra'; import type { GraphQLService } from '../services/graphql'; @@ -10,7 +10,7 @@ export class UserFeatureStore extends Store { async getUserFeatures(signal: AbortSignal) { const data = await this.gqlService.gql({ - query: getUserFeaturesQuery, + query: getCurrentUserProfileQuery, context: { signal, }, diff --git a/packages/frontend/core/src/modules/cloud/stores/user-quota.ts b/packages/frontend/core/src/modules/cloud/stores/user-quota.ts index 70698060a..e738a458d 100644 --- a/packages/frontend/core/src/modules/cloud/stores/user-quota.ts +++ b/packages/frontend/core/src/modules/cloud/stores/user-quota.ts @@ -1,4 +1,4 @@ -import { quotaQuery } from '@affine/graphql'; +import { getCurrentUserProfileQuery } from '@affine/graphql'; import { Store } from '@toeverything/infra'; import type { GraphQLService } from '../services/graphql'; @@ -10,7 +10,7 @@ export class UserQuotaStore extends Store { async fetchUserQuota(abortSignal?: AbortSignal) { const data = await this.graphqlService.gql({ - query: quotaQuery, + query: getCurrentUserProfileQuery, context: { signal: abortSignal, }, diff --git a/packages/frontend/core/src/modules/cloud/stores/user-settings.ts b/packages/frontend/core/src/modules/cloud/stores/user-settings.ts index a8d8e94e0..5e93a222b 100644 --- a/packages/frontend/core/src/modules/cloud/stores/user-settings.ts +++ b/packages/frontend/core/src/modules/cloud/stores/user-settings.ts @@ -1,6 +1,6 @@ import { - type GetUserSettingsQuery, - getUserSettingsQuery, + type GetCurrentUserProfileQuery, + getCurrentUserProfileQuery, type UpdateUserSettingsInput, updateUserSettingsMutation, } from '@affine/graphql'; @@ -9,7 +9,7 @@ import { Store } from '@toeverything/infra'; import type { GraphQLService } from '../services/graphql'; export type UserSettings = NonNullable< - GetUserSettingsQuery['currentUser'] + GetCurrentUserProfileQuery['currentUser'] >['settings']; export type { UpdateUserSettingsInput }; @@ -21,7 +21,7 @@ export class UserSettingsStore extends Store { async getUserSettings(): Promise { const result = await this.gqlService.gql({ - query: getUserSettingsQuery, + query: getCurrentUserProfileQuery, }); return result.currentUser?.settings; } diff --git a/packages/frontend/core/src/modules/integration/entities/calendar.ts b/packages/frontend/core/src/modules/integration/entities/calendar.ts index 6d370bcd1..25be0e2e7 100644 --- a/packages/frontend/core/src/modules/integration/entities/calendar.ts +++ b/packages/frontend/core/src/modules/integration/entities/calendar.ts @@ -1,5 +1,4 @@ import type { - CalendarAccountCalendarsQuery, CalendarAccountsQuery, CalendarEventsQuery, WorkspaceCalendarItemInput, @@ -16,20 +15,29 @@ export class CalendarIntegration extends Entity { super(); } - accounts$ = new LiveData( - [] - ); + accounts$ = new LiveData< + NonNullable< + CalendarAccountsQuery['currentUser'] + >['calendarAccounts'][number][] + >([]); accountCalendars$ = new LiveData< Map< string, - CalendarAccountCalendarsQuery['calendarAccountCalendars'][number][] + NonNullable< + NonNullable< + CalendarAccountsQuery['currentUser'] + >['calendarAccounts'][number] + >['calendars'] > >(new Map()); workspaceCalendars$ = new LiveData< - WorkspaceCalendarsQuery['workspaceCalendars'][number][] + WorkspaceCalendarsQuery['workspace']['calendars'][number][] >([]); readonly eventsByDateMap$ = new LiveData< - Map + Map< + string, + CalendarEventsQuery['workspace']['calendars'][number]['events'][number][] + > >(new Map()); readonly eventDates$ = LiveData.computed(get => { const eventsByDateMap = get(this.eventsByDateMap$); @@ -48,7 +56,11 @@ export class CalendarIntegration extends Entity { const subscriptionInfo = new Map< string, { - subscription: CalendarAccountCalendarsQuery['calendarAccountCalendars'][number]; + subscription: NonNullable< + NonNullable< + CalendarAccountsQuery['currentUser'] + >['calendarAccounts'][number] + >['calendars'][number]; colorOverride?: string | null; } >(); @@ -113,23 +125,16 @@ export class CalendarIntegration extends Entity { const calendarsByAccount = new Map< string, - CalendarAccountCalendarsQuery['calendarAccountCalendars'][number][] + NonNullable< + NonNullable< + CalendarAccountsQuery['currentUser'] + >['calendarAccounts'][number] + >['calendars'] >(); - await Promise.all( - accounts.map(async account => { - try { - const calendars = await this.store.fetchAccountCalendars( - account.id, - signal - ); - calendarsByAccount.set(account.id, calendars); - } catch (error) { - console.error('Failed to load calendar subscriptions', error); - calendarsByAccount.set(account.id, []); - } - }) - ); + accounts.forEach(account => { + calendarsByAccount.set(account.id, account.calendars ?? []); + }); this.accountCalendars$.setValue(calendarsByAccount); return calendarsByAccount; diff --git a/packages/frontend/core/src/modules/integration/store/calendar.ts b/packages/frontend/core/src/modules/integration/store/calendar.ts index 6fc5d6bcd..e56405e0f 100644 --- a/packages/frontend/core/src/modules/integration/store/calendar.ts +++ b/packages/frontend/core/src/modules/integration/store/calendar.ts @@ -1,6 +1,4 @@ import { - type CalendarAccountCalendarsQuery, - calendarAccountCalendarsQuery, type CalendarAccountsQuery, calendarAccountsQuery, type CalendarEventsQuery, @@ -34,38 +32,27 @@ export class CalendarStore extends Store { async fetchAccounts(signal?: AbortSignal) { const gql = this.gql; - if (!gql) return [] satisfies CalendarAccountsQuery['calendarAccounts']; + if (!gql) + return [] satisfies NonNullable< + CalendarAccountsQuery['currentUser'] + >['calendarAccounts']; const data = await gql({ query: calendarAccountsQuery, context: { signal }, }); - return data.calendarAccounts; - } - - async fetchAccountCalendars(accountId: string, signal?: AbortSignal) { - const gql = this.gql; - if (!gql) { - return [] satisfies CalendarAccountCalendarsQuery['calendarAccountCalendars']; - } - const data = await gql({ - query: calendarAccountCalendarsQuery, - variables: { accountId }, - context: { signal }, - }); - return data.calendarAccountCalendars; + return data.currentUser?.calendarAccounts ?? []; } async fetchWorkspaceCalendars(signal?: AbortSignal) { const gql = this.gql; - if (!gql) { - return [] satisfies WorkspaceCalendarsQuery['workspaceCalendars']; - } + if (!gql) + return [] satisfies WorkspaceCalendarsQuery['workspace']['calendars']; const data = await gql({ query: workspaceCalendarsQuery, variables: { workspaceId: this.workspaceId }, context: { signal }, }); - return data.workspaceCalendars; + return data.workspace.calendars; } async updateWorkspaceCalendars(items: WorkspaceCalendarItemInput[]) { @@ -92,16 +79,19 @@ export class CalendarStore extends Store { signal?: AbortSignal ) { const gql = this.gql; - if (!gql) return [] satisfies CalendarEventsQuery['calendarEvents']; + if (!gql) + return [] satisfies CalendarEventsQuery['workspace']['calendars'][number]['events']; const data = await gql({ query: calendarEventsQuery, variables: { - workspaceCalendarId, + workspaceId: this.workspaceId, from, to, }, context: { signal }, }); - return data.calendarEvents; + const calendars = data.workspace.calendars; + const calendar = calendars.find(item => item.id === workspaceCalendarId); + return calendar?.events ?? []; } } diff --git a/packages/frontend/core/src/modules/notification/stores/notification.ts b/packages/frontend/core/src/modules/notification/stores/notification.ts index 945e74bfc..7cd561ce1 100644 --- a/packages/frontend/core/src/modules/notification/stores/notification.ts +++ b/packages/frontend/core/src/modules/notification/stores/notification.ts @@ -60,7 +60,7 @@ export class NotificationStore extends Store { }, }); - return result.currentUser?.notificationCount; + return result.currentUser?.notifications.totalCount; } async listNotification(pagination: PaginationInput, signal?: AbortSignal) { diff --git a/packages/frontend/core/src/modules/permissions/stores/guard.ts b/packages/frontend/core/src/modules/permissions/stores/guard.ts index 6b0f1fcbd..1a8a93f88 100644 --- a/packages/frontend/core/src/modules/permissions/stores/guard.ts +++ b/packages/frontend/core/src/modules/permissions/stores/guard.ts @@ -1,8 +1,8 @@ import { type GetDocRolePermissionsQuery, getDocRolePermissionsQuery, - type GetWorkspaceRolePermissionsQuery, - getWorkspaceRolePermissionsQuery, + type GetWorkspaceInfoQuery, + getWorkspaceInfoQuery, } from '@affine/graphql'; import { Store } from '@toeverything/infra'; @@ -10,7 +10,7 @@ import type { WorkspaceServerService } from '../../cloud'; import type { WorkspaceService } from '../../workspace'; export type WorkspacePermissionActions = keyof Omit< - GetWorkspaceRolePermissionsQuery['workspaceRolePermissions']['permissions'], + GetWorkspaceInfoQuery['workspace']['permissions'], '__typename' >; @@ -34,12 +34,12 @@ export class GuardStore extends Store { throw new Error('No server'); } const data = await this.workspaceServerService.server.gql({ - query: getWorkspaceRolePermissionsQuery, + query: getWorkspaceInfoQuery, variables: { - id: this.workspaceService.workspace.id, + workspaceId: this.workspaceService.workspace.id, }, }); - return data.workspaceRolePermissions.permissions; + return data.workspace.permissions; } async getDocPermissions(