feat: reduce backend (#14251)

#### PR Dependency Tree


* **PR #14251** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

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

* **New Features**
* Current user profile now exposes access tokens, revealed tokens, and
detailed calendar accounts/subscriptions.
* Workspace now exposes permissions, calendars, calendar events, and a
workspace-scoped blob upload part URL.
  * New document-update mutation for applying doc updates.

* **API Changes**
  * validateAppConfig is now a query (mutation deprecated).
* Several legacy top-level calendar/blob endpoints deprecated in favor
of user/workspace fields.

* **Refactor**
* Calendar, blob-upload and access-token surfaces reorganized to use
user/workspace-centric fields.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-01-14 00:01:07 +08:00
committed by GitHub
parent 7c440686ad
commit 7c24b2521a
41 changed files with 978 additions and 503 deletions

View File

@@ -273,7 +273,7 @@ e2e('should mark notification as read', async t => {
const count = await app.gql({ const count = await app.gql({
query: notificationCountQuery, query: notificationCountQuery,
}); });
t.is(count.currentUser!.notificationCount, 0); t.is(count.currentUser!.notifications.totalCount, 0);
// read again should work // read again should work
for (const notification of notifications) { for (const notification of notifications) {

View File

@@ -1,8 +1,8 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { AccessTokenResolver } from './resolver'; import { AccessTokenResolver, UserAccessTokenResolver } from './resolver';
@Module({ @Module({
providers: [AccessTokenResolver], providers: [AccessTokenResolver, UserAccessTokenResolver],
}) })
export class AccessTokenModule {} export class AccessTokenModule {}

View File

@@ -3,34 +3,17 @@ import {
Field, Field,
InputType, InputType,
Mutation, Mutation,
ObjectType, Parent,
Query, Query,
ResolveField,
Resolver, Resolver,
} from '@nestjs/graphql'; } from '@nestjs/graphql';
import { ActionForbidden } from '../../base';
import { Models } from '../../models'; import { Models } from '../../models';
import { CurrentUser } from '../auth/session'; import { CurrentUser } from '../auth/session';
import { UserType } from '../user';
@ObjectType() import { AccessToken, RevealedAccessToken } from './types';
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;
}
@InputType() @InputType()
class GenerateAccessTokenInput { class GenerateAccessTokenInput {
@@ -45,12 +28,16 @@ class GenerateAccessTokenInput {
export class AccessTokenResolver { export class AccessTokenResolver {
constructor(private readonly models: Models) {} constructor(private readonly models: Models) {}
@Query(() => [AccessToken]) @Query(() => [AccessToken], {
deprecationReason: 'use currentUser.accessTokens',
})
async accessTokens(@CurrentUser() user: CurrentUser): Promise<AccessToken[]> { async accessTokens(@CurrentUser() user: CurrentUser): Promise<AccessToken[]> {
return await this.models.accessToken.list(user.id); return await this.models.accessToken.list(user.id);
} }
@Query(() => [RevealedAccessToken]) @Query(() => [RevealedAccessToken], {
deprecationReason: 'use currentUser.revealedAccessTokens',
})
async revealedAccessTokens( async revealedAccessTokens(
@CurrentUser() user: CurrentUser @CurrentUser() user: CurrentUser
): Promise<RevealedAccessToken[]> { ): Promise<RevealedAccessToken[]> {
@@ -78,3 +65,30 @@ export class AccessTokenResolver {
return true; return true;
} }
} }
@Resolver(() => UserType)
export class UserAccessTokenResolver {
constructor(private readonly models: Models) {}
@ResolveField(() => [AccessToken])
async accessTokens(
@CurrentUser() currentUser: CurrentUser,
@Parent() user: UserType
): Promise<AccessToken[]> {
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<RevealedAccessToken[]> {
if (!currentUser || currentUser.id !== user.id) {
throw new ActionForbidden();
}
return await this.models.accessToken.list(user.id, true);
}
}

View File

@@ -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;
}

View File

@@ -230,13 +230,31 @@ export class AppConfigResolver {
return await this.service.updateConfig(me.id, updates); return await this.service.updateConfig(me.id, updates);
} }
@Mutation(() => [AppConfigValidateResult], { @Query(() => [AppConfigValidateResult], {
description: 'validate app configuration', description: 'validate app configuration',
}) })
async validateAppConfig( async validateAppConfig(
@Args('updates', { type: () => [UpdateAppConfigInput] }) @Args('updates', { type: () => [UpdateAppConfigInput] })
updates: UpdateAppConfigInput[] updates: UpdateAppConfigInput[]
): Promise<AppConfigValidateResult[]> { ): Promise<AppConfigValidateResult[]> {
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<AppConfigValidateResult[]> {
return this.validateConfigInternal(updates);
}
private validateConfigInternal(
updates: UpdateAppConfigInput[]
): AppConfigValidateResult[] {
const errors = this.service.validateConfig(updates); const errors = this.service.validateConfig(updates);
return updates.map(update => { return updates.map(update => {

View File

@@ -156,6 +156,19 @@ export class WorkspaceBlobResolver {
return this.storage.totalSize(workspace.id); 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<BlobUploadPart> {
return this.getUploadPart(user, workspace.id, key, uploadId, partNumber);
}
@Query(() => WorkspaceBlobSizes, { @Query(() => WorkspaceBlobSizes, {
deprecationReason: 'use `user.quotaUsage` instead', deprecationReason: 'use `user.quotaUsage` instead',
}) })
@@ -399,13 +412,40 @@ export class WorkspaceBlobResolver {
return key; return key;
} }
@Mutation(() => BlobUploadPart) @Mutation(() => BlobUploadPart, {
deprecationReason: 'use WorkspaceType.blobUploadPartUrl',
})
async getBlobUploadPartUrl( async getBlobUploadPartUrl(
@CurrentUser() user: CurrentUser, @CurrentUser() user: CurrentUser,
@Args('workspaceId') workspaceId: string, @Args('workspaceId') workspaceId: string,
@Args('key') key: string, @Args('key') key: string,
@Args('uploadId') uploadId: string, @Args('uploadId') uploadId: string,
@Args('partNumber', { type: () => Int }) partNumber: number @Args('partNumber', { type: () => Int }) partNumber: number
): Promise<BlobUploadPart> {
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<BlobUploadPart> { ): Promise<BlobUploadPart> {
await this.ac await this.ac
.user(user.id) .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) @Mutation(() => Boolean)
async deleteBlob( async deleteBlob(
@CurrentUser() user: CurrentUser, @CurrentUser() user: CurrentUser,

View File

@@ -9,7 +9,14 @@ import { CalendarController } from './controller';
import { CalendarCronJobs } from './cron'; import { CalendarCronJobs } from './cron';
import { CalendarOAuthService } from './oauth'; import { CalendarOAuthService } from './oauth';
import { CalendarProviderFactory, CalendarProviders } from './providers'; import { CalendarProviderFactory, CalendarProviders } from './providers';
import { CalendarResolver } from './resolver'; import {
CalendarAccountResolver,
CalendarMutationResolver,
CalendarServerConfigResolver,
UserCalendarResolver,
WorkspaceCalendarEventsResolver,
WorkspaceCalendarResolver,
} from './resolver';
import { CalendarService } from './service'; import { CalendarService } from './service';
@Module({ @Module({
@@ -20,7 +27,12 @@ import { CalendarService } from './service';
CalendarService, CalendarService,
CalendarOAuthService, CalendarOAuthService,
CalendarCronJobs, CalendarCronJobs,
CalendarResolver, CalendarServerConfigResolver,
UserCalendarResolver,
CalendarAccountResolver,
WorkspaceCalendarResolver,
WorkspaceCalendarEventsResolver,
CalendarMutationResolver,
], ],
controllers: [CalendarController], controllers: [CalendarController],
}) })

View File

@@ -2,13 +2,17 @@ import {
Args, Args,
GraphQLISODateTime, GraphQLISODateTime,
Mutation, Mutation,
Query, Parent,
ResolveField,
Resolver, Resolver,
} from '@nestjs/graphql'; } from '@nestjs/graphql';
import { AuthenticationRequired } from '../../base'; import { ActionForbidden, AuthenticationRequired } from '../../base';
import { CurrentUser } from '../../core/auth'; import { CurrentUser } from '../../core/auth';
import { ServerConfigType } from '../../core/config/types';
import { AccessController } from '../../core/permission'; import { AccessController } from '../../core/permission';
import { UserType } from '../../core/user';
import { WorkspaceType } from '../../core/workspaces';
import { Models } from '../../models'; import { Models } from '../../models';
import { CalendarOAuthService } from './oauth'; import { CalendarOAuthService } from './oauth';
import { CalendarProviderFactory, CalendarProviderName } from './providers'; import { CalendarProviderFactory, CalendarProviderName } from './providers';
@@ -22,71 +26,101 @@ import {
WorkspaceCalendarObjectType, WorkspaceCalendarObjectType,
} from './types'; } from './types';
@Resolver(() => CalendarAccountObjectType) @Resolver(() => ServerConfigType)
export class CalendarResolver { export class CalendarServerConfigResolver {
constructor( constructor(private readonly providerFactory: CalendarProviderFactory) {}
private readonly calendar: CalendarService,
private readonly oauth: CalendarOAuthService,
private readonly models: Models,
private readonly access: AccessController,
private readonly providerFactory: CalendarProviderFactory
) {}
@Query(() => [CalendarAccountObjectType]) @ResolveField(() => [CalendarProviderName])
async calendarAccounts(@CurrentUser() user: CurrentUser) { 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); return await this.calendar.listAccounts(user.id);
} }
@Query(() => [CalendarSubscriptionObjectType])
async calendarAccountCalendars(
@CurrentUser() user: CurrentUser,
@Args('accountId') accountId: string
) {
return await this.calendar.listAccountCalendars(user.id, accountId);
} }
@Query(() => [WorkspaceCalendarObjectType]) @Resolver(() => CalendarAccountObjectType)
async workspaceCalendars( export class CalendarAccountResolver {
constructor(private readonly calendar: CalendarService) {}
@ResolveField(() => [CalendarSubscriptionObjectType])
async calendars(
@CurrentUser() user: CurrentUser, @CurrentUser() user: CurrentUser,
@Args('workspaceId') workspaceId: string @Parent() account: CalendarAccountObjectType
) {
return await this.calendar.listAccountCalendars(user.id, account.id);
}
}
@Resolver(() => WorkspaceType)
export class WorkspaceCalendarResolver {
constructor(
private readonly calendar: CalendarService,
private readonly access: AccessController
) {}
@ResolveField(() => [WorkspaceCalendarObjectType])
async calendars(
@CurrentUser() user: CurrentUser,
@Parent() workspace: WorkspaceType
) { ) {
await this.access await this.access
.user(user.id) .user(user.id)
.workspace(workspaceId) .workspace(workspace.id)
.assert('Workspace.CreateDoc'); .assert('Workspace.Settings.Read');
return await this.calendar.getWorkspaceCalendars(workspaceId); return await this.calendar.getWorkspaceCalendars(workspace.id);
}
} }
@Query(() => [CalendarEventObjectType]) @Resolver(() => WorkspaceCalendarObjectType)
async calendarEvents( export class WorkspaceCalendarEventsResolver {
constructor(
private readonly calendar: CalendarService,
private readonly access: AccessController
) {}
@ResolveField(() => [CalendarEventObjectType])
async events(
@CurrentUser() user: CurrentUser, @CurrentUser() user: CurrentUser,
@Args('workspaceCalendarId') workspaceCalendarId: string, @Parent() calendar: WorkspaceCalendarObjectType,
@Args({ name: 'from', type: () => GraphQLISODateTime }) from: Date, @Args({ name: 'from', type: () => GraphQLISODateTime }) from: Date,
@Args({ name: 'to', type: () => GraphQLISODateTime }) to: Date @Args({ name: 'to', type: () => GraphQLISODateTime }) to: Date
) { ) {
const workspaceCalendar =
await this.models.workspaceCalendar.get(workspaceCalendarId);
if (!workspaceCalendar) {
return [];
}
await this.access await this.access
.user(user.id) .user(user.id)
.workspace(workspaceCalendar.workspaceId) .workspace(calendar.workspaceId)
.assert('Workspace.CreateDoc'); .assert('Workspace.Settings.Read');
return await this.calendar.listWorkspaceEvents({ return await this.calendar.listWorkspaceEvents({
workspaceCalendarId, workspaceCalendarId: calendar.id,
from, from,
to, 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) @Mutation(() => String)
async linkCalendarAccount( async linkCalendarAccount(
@CurrentUser() user: CurrentUser | null, @CurrentUser() user: CurrentUser | null,

View File

@@ -825,6 +825,7 @@ export class CopilotResolver {
@Query(() => String, { @Query(() => String, {
description: description:
'Apply updates to a doc using LLM and return the merged markdown.', 'Apply updates to a doc using LLM and return the merged markdown.',
deprecationReason: 'use Mutation.applyDocUpdates',
}) })
async applyDocUpdates( async applyDocUpdates(
@CurrentUser() user: CurrentUser, @CurrentUser() user: CurrentUser,
@@ -836,6 +837,35 @@ export class CopilotResolver {
op: string, op: string,
@Args({ name: 'updates', type: () => String }) @Args({ name: 'updates', type: () => String })
updates: string updates: string
): Promise<string> {
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<string> {
return this.applyDocUpdatesInternal(user, workspaceId, docId, op, updates);
}
private async applyDocUpdatesInternal(
user: CurrentUser,
workspaceId: string,
docId: string,
op: string,
updates: string
): Promise<string> { ): Promise<string> {
await this.assertPermission(user, { workspaceId, docId }); await this.assertPermission(user, { workspaceId, docId });

View File

@@ -230,7 +230,6 @@ export class IndexerService {
docId, docId,
docSnapshot.blob docSnapshot.blob
); );
if (result) {
await this.write( await this.write(
SearchTable.doc, SearchTable.doc,
[ [
@@ -282,12 +281,6 @@ export class IndexerService {
this.logger.verbose( this.logger.verbose(
`synced doc ${workspaceId}/${docId} with ${result.blocks.length} blocks` `synced doc ${workspaceId}/${docId} with ${result.blocks.length} blocks`
); );
} else {
this.logger.warn(
`failed to parse ${workspaceId}/${docId}, no result returned`,
metadata
);
}
} catch (err) { } catch (err) {
this.logger.warn( this.logger.warn(
`failed to parse ${workspaceId}/${docId}: ${err}`, `failed to parse ${workspaceId}/${docId}: ${err}`,

View File

@@ -193,6 +193,7 @@ type BlobUploadedPart {
} }
type CalendarAccountObjectType { type CalendarAccountObjectType {
calendars: [CalendarSubscriptionObjectType!]!
calendarsCount: Int! calendarsCount: Int!
createdAt: DateTime! createdAt: DateTime!
displayName: String displayName: String
@@ -1384,6 +1385,9 @@ type Mutation {
"""Update workspace flags and features for admin""" """Update workspace flags and features for admin"""
adminUpdateWorkspace(input: AdminUpdateWorkspaceInput!): AdminWorkspace 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! approveMember(userId: String!, workspaceId: String!): Boolean!
"""Ban an user""" """Ban an user"""
@@ -1449,7 +1453,7 @@ type Mutation {
forkCopilotSession(options: ForkChatSessionInput!): String! forkCopilotSession(options: ForkChatSessionInput!): String!
generateLicenseKey(sessionId: String!): String! generateLicenseKey(sessionId: String!): String!
generateUserAccessToken(input: GenerateAccessTokenInput!): RevealedAccessToken! 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! grantDocUserRoles(input: GrantDocUserRolesInput!): Boolean!
grantMember(permission: Permission!, userId: String!, workspaceId: String!): Boolean! grantMember(permission: Permission!, userId: String!, workspaceId: String!): Boolean!
@@ -1572,7 +1576,7 @@ type Mutation {
uploadCommentAttachment(attachment: Upload!, docId: String!, workspaceId: String!): String! uploadCommentAttachment(attachment: Upload!, docId: String!, workspaceId: String!): String!
"""validate app configuration""" """validate app configuration"""
validateAppConfig(updates: [UpdateAppConfigInput!]!): [AppConfigValidateResult!]! validateAppConfig(updates: [UpdateAppConfigInput!]!): [AppConfigValidateResult!]! @deprecated(reason: "use Query.validateAppConfig")
verifyEmail(token: String!): Boolean! verifyEmail(token: String!): Boolean!
} }
@@ -1750,7 +1754,7 @@ type PublicUserType {
} }
type Query { type Query {
accessTokens: [AccessToken!]! accessTokens: [AccessToken!]! @deprecated(reason: "use currentUser.accessTokens")
"""Get workspace detail for admin""" """Get workspace detail for admin"""
adminWorkspace(id: String!): AdminWorkspace adminWorkspace(id: String!): AdminWorkspace
@@ -1765,11 +1769,7 @@ type Query {
appConfig: JSONObject! appConfig: JSONObject!
"""Apply updates to a doc using LLM and return the merged markdown.""" """Apply updates to a doc using LLM and return the merged markdown."""
applyDocUpdates(docId: String!, op: String!, updates: String!, workspaceId: String!): String! applyDocUpdates(docId: String!, op: String!, updates: String!, workspaceId: String!): String! @deprecated(reason: "use Mutation.applyDocUpdates")
calendarAccountCalendars(accountId: String!): [CalendarSubscriptionObjectType!]!
calendarAccounts: [CalendarAccountObjectType!]!
calendarEvents(from: DateTime!, to: DateTime!, workspaceCalendarId: String!): [CalendarEventObjectType!]!
calendarProviders: [CalendarProviderType!]!
collectAllBlobSizes: WorkspaceBlobSizes! @deprecated(reason: "use `user.quotaUsage` instead") collectAllBlobSizes: WorkspaceBlobSizes! @deprecated(reason: "use `user.quotaUsage` instead")
"""Get current user""" """Get current user"""
@@ -1794,7 +1794,7 @@ type Query {
"""query workspace embedding status""" """query workspace embedding status"""
queryWorkspaceEmbeddingStatus(workspaceId: String!): ContextWorkspaceEmbeddingStatus! queryWorkspaceEmbeddingStatus(workspaceId: String!): ContextWorkspaceEmbeddingStatus!
revealedAccessTokens: [RevealedAccessToken!]! revealedAccessTokens: [RevealedAccessToken!]! @deprecated(reason: "use currentUser.revealedAccessTokens")
"""server config""" """server config"""
serverConfig: ServerConfigType! serverConfig: ServerConfigType!
@@ -1814,9 +1814,11 @@ type Query {
"""Get users count""" """Get users count"""
usersCount(filter: ListUserInput): Int! usersCount(filter: ListUserInput): Int!
"""validate app configuration"""
validateAppConfig(updates: [UpdateAppConfigInput!]!): [AppConfigValidateResult!]!
"""Get workspace by id""" """Get workspace by id"""
workspace(id: String!): WorkspaceType! workspace(id: String!): WorkspaceType!
workspaceCalendars(workspaceId: String!): [WorkspaceCalendarObjectType!]!
"""Get workspace role permissions""" """Get workspace role permissions"""
workspaceRolePermissions(id: String!): WorkspaceRolePermissions! @deprecated(reason: "use WorkspaceType[permissions] instead") workspaceRolePermissions(id: String!): WorkspaceRolePermissions! @deprecated(reason: "use WorkspaceType[permissions] instead")
@@ -2048,6 +2050,7 @@ type ServerConfigType {
"""server base url""" """server base url"""
baseUrl: String! baseUrl: String!
calendarProviders: [CalendarProviderType!]!
"""credentials requirement""" """credentials requirement"""
credentialsRequirement: CredentialsRequirementType! credentialsRequirement: CredentialsRequirementType!
@@ -2345,8 +2348,11 @@ type UserSettingsType {
} }
type UserType { type UserType {
accessTokens: [AccessToken!]!
"""User avatar url""" """User avatar url"""
avatarUrl: String avatarUrl: String
calendarAccounts: [CalendarAccountObjectType!]!
copilot(workspaceId: String): Copilot! copilot(workspaceId: String): Copilot!
"""User email verified""" """User email verified"""
@@ -2382,6 +2388,7 @@ type UserType {
notifications(pagination: PaginationInput!): PaginatedNotificationObjectType! notifications(pagination: PaginationInput!): PaginatedNotificationObjectType!
quota: UserQuotaType! quota: UserQuotaType!
quotaUsage: UserQuotaUsageType! quotaUsage: UserQuotaUsageType!
revealedAccessTokens: [RevealedAccessToken!]!
"""Get user settings""" """Get user settings"""
settings: UserSettingsType! settings: UserSettingsType!
@@ -2421,6 +2428,7 @@ type WorkspaceCalendarObjectType {
createdByUserId: String! createdByUserId: String!
displayNameOverride: String displayNameOverride: String
enabled: Boolean! enabled: Boolean!
events(from: DateTime!, to: DateTime!): [CalendarEventObjectType!]!
id: String! id: String!
items: [WorkspaceCalendarItemObjectType!]! items: [WorkspaceCalendarItemObjectType!]!
workspaceId: String! workspaceId: String!
@@ -2511,11 +2519,15 @@ type WorkspaceType {
"""Search a specific table with aggregate""" """Search a specific table with aggregate"""
aggregate(input: AggregateInput!): AggregateResultObjectType! aggregate(input: AggregateInput!): AggregateResultObjectType!
"""Get blob upload part url"""
blobUploadPartUrl(key: String!, partNumber: Int!, uploadId: String!): BlobUploadPart!
"""List blobs of workspace""" """List blobs of workspace"""
blobs: [ListedBlob!]! blobs: [ListedBlob!]!
"""Blobs size of workspace""" """Blobs size of workspace"""
blobsSize: Int! blobsSize: Int!
calendars: [WorkspaceCalendarObjectType!]!
"""Get comment changes of a doc""" """Get comment changes of a doc"""
commentChanges(docId: String!, pagination: PaginationInput!): PaginatedCommentChangeObjectType! commentChanges(docId: String!, pagination: PaginationInput!): PaginatedCommentChangeObjectType!

View File

@@ -1,4 +1,5 @@
query listUserAccessTokens { query listUserAccessTokens {
currentUser {
revealedAccessTokens { revealedAccessTokens {
id id
name name
@@ -7,3 +8,4 @@ query listUserAccessTokens {
token token
} }
} }
}

View File

@@ -1,4 +1,4 @@
mutation validateConfig($updates: [UpdateAppConfigInput!]!) { query validateConfig($updates: [UpdateAppConfigInput!]!) {
validateAppConfig(updates: $updates) { validateAppConfig(updates: $updates) {
module module
key key

View File

@@ -1,7 +1,9 @@
mutation getBlobUploadPartUrl($workspaceId: String!, $key: String!, $uploadId: String!, $partNumber: Int!) { query getBlobUploadPartUrl($workspaceId: String!, $key: String!, $uploadId: String!, $partNumber: Int!) {
getBlobUploadPartUrl(workspaceId: $workspaceId, key: $key, uploadId: $uploadId, partNumber: $partNumber) { workspace(id: $workspaceId) {
blobUploadPartUrl(key: $key, uploadId: $uploadId, partNumber: $partNumber) {
uploadUrl uploadUrl
headers headers
expiresAt expiresAt
} }
} }
}

View File

@@ -1,13 +0,0 @@
query calendarAccountCalendars($accountId: String!) {
calendarAccountCalendars(accountId: $accountId) {
id
accountId
provider
externalCalendarId
displayName
timezone
color
enabled
lastSyncAt
}
}

View File

@@ -1,4 +1,5 @@
query calendarAccounts { query calendarAccounts {
currentUser {
calendarAccounts { calendarAccounts {
id id
provider provider
@@ -11,5 +12,17 @@ query calendarAccounts {
calendarsCount calendarsCount
createdAt createdAt
updatedAt updatedAt
calendars {
id
accountId
provider
externalCalendarId
displayName
timezone
color
enabled
lastSyncAt
}
}
} }
} }

View File

@@ -1,5 +1,8 @@
query calendarEvents($workspaceCalendarId: String!, $from: DateTime!, $to: DateTime!) { query calendarEvents($workspaceId: String!, $from: DateTime!, $to: DateTime!) {
calendarEvents(workspaceCalendarId: $workspaceCalendarId, from: $from, to: $to) { workspace(id: $workspaceId) {
calendars {
id
events(from: $from, to: $to) {
id id
subscriptionId subscriptionId
externalEventId externalEventId
@@ -14,3 +17,5 @@ query calendarEvents($workspaceCalendarId: String!, $from: DateTime!, $to: DateT
allDay allDay
} }
} }
}
}

View File

@@ -1,3 +1,5 @@
query calendarProviders { query calendarProviders {
serverConfig {
calendarProviders calendarProviders
} }
}

View File

@@ -1,5 +1,6 @@
query workspaceCalendars($workspaceId: String!) { query workspaceCalendars($workspaceId: String!) {
workspaceCalendars(workspaceId: $workspaceId) { workspace(id: $workspaceId) {
calendars {
id id
workspaceId workspaceId
createdByUserId createdByUserId
@@ -15,3 +16,4 @@ query workspaceCalendars($workspaceId: String!) {
} }
} }
} }
}

View File

@@ -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) applyDocUpdates(workspaceId: $workspaceId, docId: $docId, op: $op, updates: $updates)
} }

View File

@@ -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
}
}
}

View File

@@ -0,0 +1,7 @@
#import './fragments/current-user-profile.gql'
query getCurrentUserProfile {
currentUser {
...CurrentUserProfile
}
}

View File

@@ -1,5 +1,27 @@
query getWorkspaceInfo($workspaceId: String!) { query getWorkspaceInfo($workspaceId: String!) {
workspace(id: $workspaceId) { 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 role
team team
} }

View File

@@ -58,6 +58,42 @@ export const credentialsRequirementsFragment = `fragment CredentialsRequirements
...PasswordLimits ...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 { export const passwordLimitsFragment = `fragment PasswordLimits on PasswordLimitsType {
minLength minLength
maxLength maxLength
@@ -88,6 +124,7 @@ export const listUserAccessTokensQuery = {
id: 'listUserAccessTokensQuery' as const, id: 'listUserAccessTokensQuery' as const,
op: 'listUserAccessTokens', op: 'listUserAccessTokens',
query: `query listUserAccessTokens { query: `query listUserAccessTokens {
currentUser {
revealedAccessTokens { revealedAccessTokens {
id id
name name
@@ -95,6 +132,7 @@ export const listUserAccessTokensQuery = {
expiresAt expiresAt
token token
} }
}
}`, }`,
}; };
@@ -444,10 +482,10 @@ export const updateAppConfigMutation = {
}`, }`,
}; };
export const validateConfigMutation = { export const validateConfigQuery = {
id: 'validateConfigMutation' as const, id: 'validateConfigQuery' as const,
op: 'validateConfig', op: 'validateConfig',
query: `mutation validateConfig($updates: [UpdateAppConfigInput!]!) { query: `query validateConfig($updates: [UpdateAppConfigInput!]!) {
validateAppConfig(updates: $updates) { validateAppConfig(updates: $updates) {
module module
key key
@@ -540,37 +578,16 @@ export const createBlobUploadMutation = {
}`, }`,
}; };
export const getBlobUploadPartUrlMutation = { export const getBlobUploadPartUrlQuery = {
id: 'getBlobUploadPartUrlMutation' as const, id: 'getBlobUploadPartUrlQuery' as const,
op: 'getBlobUploadPartUrl', op: 'getBlobUploadPartUrl',
query: `mutation getBlobUploadPartUrl($workspaceId: String!, $key: String!, $uploadId: String!, $partNumber: Int!) { query: `query getBlobUploadPartUrl($workspaceId: String!, $key: String!, $uploadId: String!, $partNumber: Int!) {
getBlobUploadPartUrl( workspace(id: $workspaceId) {
workspaceId: $workspaceId blobUploadPartUrl(key: $key, uploadId: $uploadId, partNumber: $partNumber) {
key: $key
uploadId: $uploadId
partNumber: $partNumber
) {
uploadUrl uploadUrl
headers headers
expiresAt 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
} }
}`, }`,
}; };
@@ -579,6 +596,7 @@ export const calendarAccountsQuery = {
id: 'calendarAccountsQuery' as const, id: 'calendarAccountsQuery' as const,
op: 'calendarAccounts', op: 'calendarAccounts',
query: `query calendarAccounts { query: `query calendarAccounts {
currentUser {
calendarAccounts { calendarAccounts {
id id
provider provider
@@ -591,6 +609,18 @@ export const calendarAccountsQuery = {
calendarsCount calendarsCount
createdAt createdAt
updatedAt updatedAt
calendars {
id
accountId
provider
externalCalendarId
displayName
timezone
color
enabled
lastSyncAt
}
}
} }
}`, }`,
}; };
@@ -598,8 +628,11 @@ export const calendarAccountsQuery = {
export const calendarEventsQuery = { export const calendarEventsQuery = {
id: 'calendarEventsQuery' as const, id: 'calendarEventsQuery' as const,
op: 'calendarEvents', op: 'calendarEvents',
query: `query calendarEvents($workspaceCalendarId: String!, $from: DateTime!, $to: DateTime!) { query: `query calendarEvents($workspaceId: String!, $from: DateTime!, $to: DateTime!) {
calendarEvents(workspaceCalendarId: $workspaceCalendarId, from: $from, to: $to) { workspace(id: $workspaceId) {
calendars {
id
events(from: $from, to: $to) {
id id
subscriptionId subscriptionId
externalEventId externalEventId
@@ -613,6 +646,8 @@ export const calendarEventsQuery = {
originalTimezone originalTimezone
allDay allDay
} }
}
}
}`, }`,
}; };
@@ -620,7 +655,9 @@ export const calendarProvidersQuery = {
id: 'calendarProvidersQuery' as const, id: 'calendarProvidersQuery' as const,
op: 'calendarProviders', op: 'calendarProviders',
query: `query calendarProviders { query: `query calendarProviders {
serverConfig {
calendarProviders calendarProviders
}
}`, }`,
}; };
@@ -689,7 +726,8 @@ export const workspaceCalendarsQuery = {
id: 'workspaceCalendarsQuery' as const, id: 'workspaceCalendarsQuery' as const,
op: 'workspaceCalendars', op: 'workspaceCalendars',
query: `query workspaceCalendars($workspaceId: String!) { query: `query workspaceCalendars($workspaceId: String!) {
workspaceCalendars(workspaceId: $workspaceId) { workspace(id: $workspaceId) {
calendars {
id id
workspaceId workspaceId
createdByUserId createdByUserId
@@ -704,6 +742,7 @@ export const workspaceCalendarsQuery = {
enabled enabled
} }
} }
}
}`, }`,
}; };
@@ -915,10 +954,10 @@ export const uploadCommentAttachmentMutation = {
file: true, file: true,
}; };
export const applyDocUpdatesQuery = { export const applyDocUpdatesMutation = {
id: 'applyDocUpdatesQuery' as const, id: 'applyDocUpdatesMutation' as const,
op: 'applyDocUpdates', 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( applyDocUpdates(
workspaceId: $workspaceId workspaceId: $workspaceId
docId: $docId 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 = { export const getCurrentUserQuery = {
id: 'getCurrentUserQuery' as const, id: 'getCurrentUserQuery' as const,
op: 'getCurrentUser', op: 'getCurrentUser',
@@ -1998,6 +2048,28 @@ export const getWorkspaceInfoQuery = {
op: 'getWorkspaceInfo', op: 'getWorkspaceInfo',
query: `query getWorkspaceInfo($workspaceId: String!) { query: `query getWorkspaceInfo($workspaceId: String!) {
workspace(id: $workspaceId) { 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 role
team team
} }
@@ -2336,7 +2408,9 @@ export const notificationCountQuery = {
op: 'notificationCount', op: 'notificationCount',
query: `query notificationCount { query: `query notificationCount {
currentUser { currentUser {
notificationCount notifications(pagination: {first: 1}) {
totalCount
}
} }
}`, }`,
}; };
@@ -2523,6 +2597,7 @@ export const serverConfigQuery = {
features features
type type
initialized initialized
calendarProviders
credentialsRequirement { credentialsRequirement {
...CredentialsRequirements ...CredentialsRequirements
} }

View File

@@ -1,5 +1,7 @@
query notificationCount { query notificationCount {
currentUser { currentUser {
notificationCount notifications(pagination: { first: 1 }) {
totalCount
}
} }
} }

View File

@@ -9,6 +9,7 @@ query serverConfig {
features features
type type
initialized initialized
calendarProviders
credentialsRequirement { credentialsRequirement {
...CredentialsRequirements ...CredentialsRequirements
} }

View File

@@ -246,6 +246,7 @@ export interface BlobUploadedPart {
export interface CalendarAccountObjectType { export interface CalendarAccountObjectType {
__typename?: 'CalendarAccountObjectType'; __typename?: 'CalendarAccountObjectType';
calendars: Array<CalendarSubscriptionObjectType>;
calendarsCount: Scalars['Int']['output']; calendarsCount: Scalars['Int']['output'];
createdAt: Scalars['DateTime']['output']; createdAt: Scalars['DateTime']['output'];
displayName: Maybe<Scalars['String']['output']>; displayName: Maybe<Scalars['String']['output']>;
@@ -1570,6 +1571,8 @@ export interface Mutation {
addWorkspaceFeature: Scalars['Boolean']['output']; addWorkspaceFeature: Scalars['Boolean']['output'];
/** Update workspace flags and features for admin */ /** Update workspace flags and features for admin */
adminUpdateWorkspace: Maybe<AdminWorkspace>; adminUpdateWorkspace: Maybe<AdminWorkspace>;
/** Apply updates to a doc using LLM and return the merged markdown. */
applyDocUpdates: Scalars['String']['output'];
approveMember: Scalars['Boolean']['output']; approveMember: Scalars['Boolean']['output'];
/** Ban an user */ /** Ban an user */
banUser: UserType; banUser: UserType;
@@ -1619,6 +1622,7 @@ export interface Mutation {
forkCopilotSession: Scalars['String']['output']; forkCopilotSession: Scalars['String']['output'];
generateLicenseKey: Scalars['String']['output']; generateLicenseKey: Scalars['String']['output'];
generateUserAccessToken: RevealedAccessToken; generateUserAccessToken: RevealedAccessToken;
/** @deprecated use WorkspaceType.blobUploadPartUrl */
getBlobUploadPartUrl: BlobUploadPart; getBlobUploadPartUrl: BlobUploadPart;
grantDocUserRoles: Scalars['Boolean']['output']; grantDocUserRoles: Scalars['Boolean']['output'];
grantMember: Scalars['Boolean']['output']; grantMember: Scalars['Boolean']['output'];
@@ -1716,7 +1720,10 @@ export interface Mutation {
uploadAvatar: UserType; uploadAvatar: UserType;
/** Upload a comment attachment and return the access url */ /** Upload a comment attachment and return the access url */
uploadCommentAttachment: Scalars['String']['output']; uploadCommentAttachment: Scalars['String']['output'];
/** validate app configuration */ /**
* validate app configuration
* @deprecated use Query.validateAppConfig
*/
validateAppConfig: Array<AppConfigValidateResult>; validateAppConfig: Array<AppConfigValidateResult>;
verifyEmail: Scalars['Boolean']['output']; verifyEmail: Scalars['Boolean']['output'];
} }
@@ -1769,6 +1776,13 @@ export interface MutationAdminUpdateWorkspaceArgs {
input: AdminUpdateWorkspaceInput; input: AdminUpdateWorkspaceInput;
} }
export interface MutationApplyDocUpdatesArgs {
docId: Scalars['String']['input'];
op: Scalars['String']['input'];
updates: Scalars['String']['input'];
workspaceId: Scalars['String']['input'];
}
export interface MutationApproveMemberArgs { export interface MutationApproveMemberArgs {
userId: Scalars['String']['input']; userId: Scalars['String']['input'];
workspaceId: Scalars['String']['input']; workspaceId: Scalars['String']['input'];
@@ -2387,6 +2401,7 @@ export interface PublicUserType {
export interface Query { export interface Query {
__typename?: 'Query'; __typename?: 'Query';
/** @deprecated use currentUser.accessTokens */
accessTokens: Array<AccessToken>; accessTokens: Array<AccessToken>;
/** Get workspace detail for admin */ /** Get workspace detail for admin */
adminWorkspace: Maybe<AdminWorkspace>; adminWorkspace: Maybe<AdminWorkspace>;
@@ -2396,12 +2411,11 @@ export interface Query {
adminWorkspacesCount: Scalars['Int']['output']; adminWorkspacesCount: Scalars['Int']['output'];
/** get the whole app configuration */ /** get the whole app configuration */
appConfig: Scalars['JSONObject']['output']; 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']; applyDocUpdates: Scalars['String']['output'];
calendarAccountCalendars: Array<CalendarSubscriptionObjectType>;
calendarAccounts: Array<CalendarAccountObjectType>;
calendarEvents: Array<CalendarEventObjectType>;
calendarProviders: Array<CalendarProviderType>;
/** @deprecated use `user.quotaUsage` instead */ /** @deprecated use `user.quotaUsage` instead */
collectAllBlobSizes: WorkspaceBlobSizes; collectAllBlobSizes: WorkspaceBlobSizes;
/** Get current user */ /** Get current user */
@@ -2426,6 +2440,7 @@ export interface Query {
publicUserById: Maybe<PublicUserType>; publicUserById: Maybe<PublicUserType>;
/** query workspace embedding status */ /** query workspace embedding status */
queryWorkspaceEmbeddingStatus: ContextWorkspaceEmbeddingStatus; queryWorkspaceEmbeddingStatus: ContextWorkspaceEmbeddingStatus;
/** @deprecated use currentUser.revealedAccessTokens */
revealedAccessTokens: Array<RevealedAccessToken>; revealedAccessTokens: Array<RevealedAccessToken>;
/** server config */ /** server config */
serverConfig: ServerConfigType; serverConfig: ServerConfigType;
@@ -2439,9 +2454,10 @@ export interface Query {
users: Array<UserType>; users: Array<UserType>;
/** Get users count */ /** Get users count */
usersCount: Scalars['Int']['output']; usersCount: Scalars['Int']['output'];
/** validate app configuration */
validateAppConfig: Array<AppConfigValidateResult>;
/** Get workspace by id */ /** Get workspace by id */
workspace: WorkspaceType; workspace: WorkspaceType;
workspaceCalendars: Array<WorkspaceCalendarObjectType>;
/** /**
* Get workspace role permissions * Get workspace role permissions
* @deprecated use WorkspaceType[permissions] instead * @deprecated use WorkspaceType[permissions] instead
@@ -2470,16 +2486,6 @@ export interface QueryApplyDocUpdatesArgs {
workspaceId: Scalars['String']['input']; 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 { export interface QueryErrorArgs {
name: ErrorNames; name: ErrorNames;
} }
@@ -2524,12 +2530,12 @@ export interface QueryUsersCountArgs {
filter?: InputMaybe<ListUserInput>; filter?: InputMaybe<ListUserInput>;
} }
export interface QueryWorkspaceArgs { export interface QueryValidateAppConfigArgs {
id: Scalars['String']['input']; updates: Array<UpdateAppConfigInput>;
} }
export interface QueryWorkspaceCalendarsArgs { export interface QueryWorkspaceArgs {
workspaceId: Scalars['String']['input']; id: Scalars['String']['input'];
} }
export interface QueryWorkspaceRolePermissionsArgs { export interface QueryWorkspaceRolePermissionsArgs {
@@ -2754,6 +2760,7 @@ export interface ServerConfigType {
availableWorkspaceFeatures: Array<FeatureType>; availableWorkspaceFeatures: Array<FeatureType>;
/** server base url */ /** server base url */
baseUrl: Scalars['String']['output']; baseUrl: Scalars['String']['output'];
calendarProviders: Array<CalendarProviderType>;
/** credentials requirement */ /** credentials requirement */
credentialsRequirement: CredentialsRequirementType; credentialsRequirement: CredentialsRequirementType;
/** enabled server features */ /** enabled server features */
@@ -3055,8 +3062,10 @@ export interface UserSettingsType {
export interface UserType { export interface UserType {
__typename?: 'UserType'; __typename?: 'UserType';
accessTokens: Array<AccessToken>;
/** User avatar url */ /** User avatar url */
avatarUrl: Maybe<Scalars['String']['output']>; avatarUrl: Maybe<Scalars['String']['output']>;
calendarAccounts: Array<CalendarAccountObjectType>;
copilot: Copilot; copilot: Copilot;
/** /**
* User email verified * User email verified
@@ -3085,6 +3094,7 @@ export interface UserType {
notifications: PaginatedNotificationObjectType; notifications: PaginatedNotificationObjectType;
quota: UserQuotaType; quota: UserQuotaType;
quotaUsage: UserQuotaUsageType; quotaUsage: UserQuotaUsageType;
revealedAccessTokens: Array<RevealedAccessToken>;
/** Get user settings */ /** Get user settings */
settings: UserSettingsType; settings: UserSettingsType;
subscriptions: Array<SubscriptionType>; subscriptions: Array<SubscriptionType>;
@@ -3142,11 +3152,17 @@ export interface WorkspaceCalendarObjectType {
createdByUserId: Scalars['String']['output']; createdByUserId: Scalars['String']['output'];
displayNameOverride: Maybe<Scalars['String']['output']>; displayNameOverride: Maybe<Scalars['String']['output']>;
enabled: Scalars['Boolean']['output']; enabled: Scalars['Boolean']['output'];
events: Array<CalendarEventObjectType>;
id: Scalars['String']['output']; id: Scalars['String']['output'];
items: Array<WorkspaceCalendarItemObjectType>; items: Array<WorkspaceCalendarItemObjectType>;
workspaceId: Scalars['String']['output']; workspaceId: Scalars['String']['output'];
} }
export interface WorkspaceCalendarObjectTypeEventsArgs {
from: Scalars['DateTime']['input'];
to: Scalars['DateTime']['input'];
}
export interface WorkspaceDocMeta { export interface WorkspaceDocMeta {
__typename?: 'WorkspaceDocMeta'; __typename?: 'WorkspaceDocMeta';
createdAt: Scalars['DateTime']['output']; createdAt: Scalars['DateTime']['output'];
@@ -3239,10 +3255,13 @@ export interface WorkspaceType {
__typename?: 'WorkspaceType'; __typename?: 'WorkspaceType';
/** Search a specific table with aggregate */ /** Search a specific table with aggregate */
aggregate: AggregateResultObjectType; aggregate: AggregateResultObjectType;
/** Get blob upload part url */
blobUploadPartUrl: BlobUploadPart;
/** List blobs of workspace */ /** List blobs of workspace */
blobs: Array<ListedBlob>; blobs: Array<ListedBlob>;
/** Blobs size of workspace */ /** Blobs size of workspace */
blobsSize: Scalars['Int']['output']; blobsSize: Scalars['Int']['output'];
calendars: Array<WorkspaceCalendarObjectType>;
/** Get comment changes of a doc */ /** Get comment changes of a doc */
commentChanges: PaginatedCommentChangeObjectType; commentChanges: PaginatedCommentChangeObjectType;
/** Get comments of a doc */ /** Get comments of a doc */
@@ -3314,6 +3333,12 @@ export interface WorkspaceTypeAggregateArgs {
input: AggregateInput; input: AggregateInput;
} }
export interface WorkspaceTypeBlobUploadPartUrlArgs {
key: Scalars['String']['input'];
partNumber: Scalars['Int']['input'];
uploadId: Scalars['String']['input'];
}
export interface WorkspaceTypeCommentChangesArgs { export interface WorkspaceTypeCommentChangesArgs {
docId: Scalars['String']['input']; docId: Scalars['String']['input'];
pagination: PaginationInput; pagination: PaginationInput;
@@ -3411,6 +3436,8 @@ export type ListUserAccessTokensQueryVariables = Exact<{
export type ListUserAccessTokensQuery = { export type ListUserAccessTokensQuery = {
__typename?: 'Query'; __typename?: 'Query';
currentUser: {
__typename?: 'UserType';
revealedAccessTokens: Array<{ revealedAccessTokens: Array<{
__typename?: 'RevealedAccessToken'; __typename?: 'RevealedAccessToken';
id: string; id: string;
@@ -3419,6 +3446,7 @@ export type ListUserAccessTokensQuery = {
expiresAt: string | null; expiresAt: string | null;
token: string; token: string;
}>; }>;
} | null;
}; };
export type RevokeUserAccessTokenMutationVariables = Exact<{ export type RevokeUserAccessTokenMutationVariables = Exact<{
@@ -3793,12 +3821,12 @@ export type UpdateAppConfigMutation = {
updateAppConfig: any; updateAppConfig: any;
}; };
export type ValidateConfigMutationVariables = Exact<{ export type ValidateConfigQueryVariables = Exact<{
updates: Array<UpdateAppConfigInput> | UpdateAppConfigInput; updates: Array<UpdateAppConfigInput> | UpdateAppConfigInput;
}>; }>;
export type ValidateConfigMutation = { export type ValidateConfigQuery = {
__typename?: 'Mutation'; __typename?: 'Query';
validateAppConfig: Array<{ validateAppConfig: Array<{
__typename?: 'AppConfigValidateResult'; __typename?: 'AppConfigValidateResult';
module: string; module: string;
@@ -3904,47 +3932,32 @@ export type CreateBlobUploadMutation = {
}; };
}; };
export type GetBlobUploadPartUrlMutationVariables = Exact<{ export type GetBlobUploadPartUrlQueryVariables = Exact<{
workspaceId: Scalars['String']['input']; workspaceId: Scalars['String']['input'];
key: Scalars['String']['input']; key: Scalars['String']['input'];
uploadId: Scalars['String']['input']; uploadId: Scalars['String']['input'];
partNumber: Scalars['Int']['input']; partNumber: Scalars['Int']['input'];
}>; }>;
export type GetBlobUploadPartUrlMutation = { export type GetBlobUploadPartUrlQuery = {
__typename?: 'Mutation'; __typename?: 'Query';
getBlobUploadPartUrl: { workspace: {
__typename?: 'WorkspaceType';
blobUploadPartUrl: {
__typename?: 'BlobUploadPart'; __typename?: 'BlobUploadPart';
uploadUrl: string; uploadUrl: string;
headers: any | null; headers: any | null;
expiresAt: string | null; expiresAt: string | null;
}; };
}; };
export type CalendarAccountCalendarsQueryVariables = Exact<{
accountId: Scalars['String']['input'];
}>;
export type CalendarAccountCalendarsQuery = {
__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;
}>;
}; };
export type CalendarAccountsQueryVariables = Exact<{ [key: string]: never }>; export type CalendarAccountsQueryVariables = Exact<{ [key: string]: never }>;
export type CalendarAccountsQuery = { export type CalendarAccountsQuery = {
__typename?: 'Query'; __typename?: 'Query';
currentUser: {
__typename?: 'UserType';
calendarAccounts: Array<{ calendarAccounts: Array<{
__typename?: 'CalendarAccountObjectType'; __typename?: 'CalendarAccountObjectType';
id: string; id: string;
@@ -3958,18 +3971,36 @@ export type CalendarAccountsQuery = {
calendarsCount: number; calendarsCount: number;
createdAt: string; createdAt: string;
updatedAt: 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<{ export type CalendarEventsQueryVariables = Exact<{
workspaceCalendarId: Scalars['String']['input']; workspaceId: Scalars['String']['input'];
from: Scalars['DateTime']['input']; from: Scalars['DateTime']['input'];
to: Scalars['DateTime']['input']; to: Scalars['DateTime']['input'];
}>; }>;
export type CalendarEventsQuery = { export type CalendarEventsQuery = {
__typename?: 'Query'; __typename?: 'Query';
calendarEvents: Array<{ workspace: {
__typename?: 'WorkspaceType';
calendars: Array<{
__typename?: 'WorkspaceCalendarObjectType';
id: string;
events: Array<{
__typename?: 'CalendarEventObjectType'; __typename?: 'CalendarEventObjectType';
id: string; id: string;
subscriptionId: string; subscriptionId: string;
@@ -3984,14 +4015,19 @@ export type CalendarEventsQuery = {
originalTimezone: string | null; originalTimezone: string | null;
allDay: boolean; allDay: boolean;
}>; }>;
}>;
};
}; };
export type CalendarProvidersQueryVariables = Exact<{ [key: string]: never }>; export type CalendarProvidersQueryVariables = Exact<{ [key: string]: never }>;
export type CalendarProvidersQuery = { export type CalendarProvidersQuery = {
__typename?: 'Query'; __typename?: 'Query';
serverConfig: {
__typename?: 'ServerConfigType';
calendarProviders: Array<CalendarProviderType>; calendarProviders: Array<CalendarProviderType>;
}; };
};
export type LinkCalendarAccountMutationVariables = Exact<{ export type LinkCalendarAccountMutationVariables = Exact<{
input: LinkCalendarAccountInput; input: LinkCalendarAccountInput;
@@ -4065,7 +4101,9 @@ export type WorkspaceCalendarsQueryVariables = Exact<{
export type WorkspaceCalendarsQuery = { export type WorkspaceCalendarsQuery = {
__typename?: 'Query'; __typename?: 'Query';
workspaceCalendars: Array<{ workspace: {
__typename?: 'WorkspaceType';
calendars: Array<{
__typename?: 'WorkspaceCalendarObjectType'; __typename?: 'WorkspaceCalendarObjectType';
id: string; id: string;
workspaceId: string; workspaceId: string;
@@ -4083,6 +4121,7 @@ export type WorkspaceCalendarsQuery = {
}>; }>;
}>; }>;
}; };
};
export type CancelSubscriptionMutationVariables = Exact<{ export type CancelSubscriptionMutationVariables = Exact<{
plan?: InputMaybe<SubscriptionPlan>; plan?: InputMaybe<SubscriptionPlan>;
@@ -4326,15 +4365,15 @@ export type UploadCommentAttachmentMutation = {
uploadCommentAttachment: string; uploadCommentAttachment: string;
}; };
export type ApplyDocUpdatesQueryVariables = Exact<{ export type ApplyDocUpdatesMutationVariables = Exact<{
workspaceId: Scalars['String']['input']; workspaceId: Scalars['String']['input'];
docId: Scalars['String']['input']; docId: Scalars['String']['input'];
op: Scalars['String']['input']; op: Scalars['String']['input'];
updates: Scalars['String']['input']; updates: Scalars['String']['input'];
}>; }>;
export type ApplyDocUpdatesQuery = { export type ApplyDocUpdatesMutation = {
__typename?: 'Query'; __typename?: 'Mutation';
applyDocUpdates: string; 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<FeatureType>;
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 = { export type PasswordLimitsFragment = {
__typename?: 'PasswordLimitsType'; __typename?: 'PasswordLimitsType';
minLength: number; minLength: number;
@@ -5754,6 +5830,54 @@ export type GetCurrentUserFeaturesQuery = {
} | null; } | 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<FeatureType>;
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 GetCurrentUserQueryVariables = Exact<{ [key: string]: never }>;
export type GetCurrentUserQuery = { export type GetCurrentUserQuery = {
@@ -6042,7 +6166,34 @@ export type GetWorkspaceInfoQueryVariables = Exact<{
export type GetWorkspaceInfoQuery = { export type GetWorkspaceInfoQuery = {
__typename?: 'Query'; __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<{ export type GetWorkspacePageByIdQueryVariables = Exact<{
@@ -6454,7 +6605,13 @@ export type NotificationCountQueryVariables = Exact<{ [key: string]: never }>;
export type NotificationCountQuery = { export type NotificationCountQuery = {
__typename?: 'Query'; __typename?: 'Query';
currentUser: { __typename?: 'UserType'; notificationCount: number } | null; currentUser: {
__typename?: 'UserType';
notifications: {
__typename?: 'PaginatedNotificationObjectType';
totalCount: number;
};
} | null;
}; };
export type PricesQueryVariables = Exact<{ [key: string]: never }>; export type PricesQueryVariables = Exact<{ [key: string]: never }>;
@@ -6656,6 +6813,7 @@ export type ServerConfigQuery = {
features: Array<ServerFeature>; features: Array<ServerFeature>;
type: ServerDeploymentType; type: ServerDeploymentType;
initialized: boolean; initialized: boolean;
calendarProviders: Array<CalendarProviderType>;
credentialsRequirement: { credentialsRequirement: {
__typename?: 'CredentialsRequirementType'; __typename?: 'CredentialsRequirementType';
password: { password: {
@@ -7101,15 +7259,20 @@ export type Queries =
variables: ListUsersQueryVariables; variables: ListUsersQueryVariables;
response: ListUsersQuery; response: ListUsersQuery;
} }
| {
name: 'validateConfigQuery';
variables: ValidateConfigQueryVariables;
response: ValidateConfigQuery;
}
| { | {
name: 'listBlobsQuery'; name: 'listBlobsQuery';
variables: ListBlobsQueryVariables; variables: ListBlobsQueryVariables;
response: ListBlobsQuery; response: ListBlobsQuery;
} }
| { | {
name: 'calendarAccountCalendarsQuery'; name: 'getBlobUploadPartUrlQuery';
variables: CalendarAccountCalendarsQueryVariables; variables: GetBlobUploadPartUrlQueryVariables;
response: CalendarAccountCalendarsQuery; response: GetBlobUploadPartUrlQuery;
} }
| { | {
name: 'calendarAccountsQuery'; name: 'calendarAccountsQuery';
@@ -7141,11 +7304,6 @@ export type Queries =
variables: ListCommentsQueryVariables; variables: ListCommentsQueryVariables;
response: ListCommentsQuery; response: ListCommentsQuery;
} }
| {
name: 'applyDocUpdatesQuery';
variables: ApplyDocUpdatesQueryVariables;
response: ApplyDocUpdatesQuery;
}
| { | {
name: 'listContextObjectQuery'; name: 'listContextObjectQuery';
variables: ListContextObjectQueryVariables; variables: ListContextObjectQueryVariables;
@@ -7261,6 +7419,11 @@ export type Queries =
variables: GetCurrentUserFeaturesQueryVariables; variables: GetCurrentUserFeaturesQueryVariables;
response: GetCurrentUserFeaturesQuery; response: GetCurrentUserFeaturesQuery;
} }
| {
name: 'getCurrentUserProfileQuery';
variables: GetCurrentUserProfileQueryVariables;
response: GetCurrentUserProfileQuery;
}
| { | {
name: 'getCurrentUserQuery'; name: 'getCurrentUserQuery';
variables: GetCurrentUserQueryVariables; variables: GetCurrentUserQueryVariables;
@@ -7533,11 +7696,6 @@ export type Mutations =
variables: UpdateAppConfigMutationVariables; variables: UpdateAppConfigMutationVariables;
response: UpdateAppConfigMutation; response: UpdateAppConfigMutation;
} }
| {
name: 'validateConfigMutation';
variables: ValidateConfigMutationVariables;
response: ValidateConfigMutation;
}
| { | {
name: 'deleteBlobMutation'; name: 'deleteBlobMutation';
variables: DeleteBlobMutationVariables; variables: DeleteBlobMutationVariables;
@@ -7568,11 +7726,6 @@ export type Mutations =
variables: CreateBlobUploadMutationVariables; variables: CreateBlobUploadMutationVariables;
response: CreateBlobUploadMutation; response: CreateBlobUploadMutation;
} }
| {
name: 'getBlobUploadPartUrlMutation';
variables: GetBlobUploadPartUrlMutationVariables;
response: GetBlobUploadPartUrlMutation;
}
| { | {
name: 'linkCalendarAccountMutation'; name: 'linkCalendarAccountMutation';
variables: LinkCalendarAccountMutationVariables; variables: LinkCalendarAccountMutationVariables;
@@ -7648,6 +7801,11 @@ export type Mutations =
variables: UploadCommentAttachmentMutationVariables; variables: UploadCommentAttachmentMutationVariables;
response: UploadCommentAttachmentMutation; response: UploadCommentAttachmentMutation;
} }
| {
name: 'applyDocUpdatesMutation';
variables: ApplyDocUpdatesMutationVariables;
response: ApplyDocUpdatesMutation;
}
| { | {
name: 'addContextBlobMutation'; name: 'addContextBlobMutation';
variables: AddContextBlobMutationVariables; variables: AddContextBlobMutationVariables;

View File

@@ -3,7 +3,7 @@ import {
BlobUploadMethod, BlobUploadMethod,
completeBlobUploadMutation, completeBlobUploadMutation,
createBlobUploadMutation, createBlobUploadMutation,
getBlobUploadPartUrlMutation, getBlobUploadPartUrlQuery,
setBlobMutation, setBlobMutation,
workspaceBlobQuotaQuery, workspaceBlobQuotaQuery,
} from '@affine/graphql'; } from '@affine/graphql';
@@ -128,11 +128,13 @@ test('falls back to graphql and aborts when multipart upload fails', async () =>
}, },
}; };
} }
if (query === getBlobUploadPartUrlMutation) { if (query === getBlobUploadPartUrlQuery) {
return { return {
getBlobUploadPartUrl: { workspace: {
blobUploadPartUrl: {
uploadUrl: 'https://upload.example.com/part', uploadUrl: 'https://upload.example.com/part',
}, },
},
}; };
} }
if (query === abortBlobUploadMutation) { if (query === abortBlobUploadMutation) {

View File

@@ -5,7 +5,7 @@ import {
completeBlobUploadMutation, completeBlobUploadMutation,
createBlobUploadMutation, createBlobUploadMutation,
deleteBlobMutation, deleteBlobMutation,
getBlobUploadPartUrlMutation, getBlobUploadPartUrlQuery,
listBlobsQuery, listBlobsQuery,
releaseDeletedBlobsMutation, releaseDeletedBlobsMutation,
setBlobMutation, setBlobMutation,
@@ -265,16 +265,16 @@ export class CloudBlobStorage extends BlobStorageBase {
const chunk = data.subarray(start, end); const chunk = data.subarray(start, end);
const part = await this.connection.gql({ const part = await this.connection.gql({
query: getBlobUploadPartUrlMutation, query: getBlobUploadPartUrlQuery,
variables: { workspaceId: this.options.id, key, uploadId, partNumber }, variables: { workspaceId: this.options.id, key, uploadId, partNumber },
context: { signal }, context: { signal },
}); });
const res = await this.fetchWithTimeout( const res = await this.fetchWithTimeout(
part.getBlobUploadPartUrl.uploadUrl, part.workspace.blobUploadPartUrl.uploadUrl,
{ {
method: 'PUT', method: 'PUT',
headers: part.getBlobUploadPartUrl.headers ?? undefined, headers: part.workspace.blobUploadPartUrl.headers ?? undefined,
body: chunk, body: chunk,
signal, signal,
timeout: UPLOAD_REQUEST_TIMEOUT, timeout: UPLOAD_REQUEST_TIMEOUT,

View File

@@ -6,7 +6,7 @@ import {
addContextCategoryMutation, addContextCategoryMutation,
addContextDocMutation, addContextDocMutation,
addContextFileMutation, addContextFileMutation,
applyDocUpdatesQuery, applyDocUpdatesMutation,
cleanupCopilotSessionMutation, cleanupCopilotSessionMutation,
createCopilotContextMutation, createCopilotContextMutation,
createCopilotMessageMutation, createCopilotMessageMutation,
@@ -557,7 +557,7 @@ export class CopilotClient {
updates: string updates: string
) { ) {
return this.gql({ return this.gql({
query: applyDocUpdatesQuery, query: applyDocUpdatesMutation,
variables: { variables: {
workspaceId, workspaceId,
docId, docId,

View File

@@ -24,7 +24,9 @@ import {
import { CollapsibleWrapper } from '../layout'; import { CollapsibleWrapper } from '../layout';
import * as styles from './integrations-panel.css'; import * as styles from './integrations-panel.css';
type CalendarAccount = CalendarAccountsQuery['calendarAccounts'][number]; type CalendarAccount = NonNullable<
CalendarAccountsQuery['currentUser']
>['calendarAccounts'][number];
const providerMeta = { const providerMeta = {
[CalendarProviderType.Google]: { [CalendarProviderType.Google]: {
@@ -66,8 +68,8 @@ export const IntegrationsPanel = () => {
context: { signal }, context: { signal },
}), }),
]); ]);
setAccounts(accountsData.calendarAccounts); setAccounts(accountsData.currentUser?.calendarAccounts ?? []);
setProviders(providersData.calendarProviders); setProviders(providersData.serverConfig.calendarProviders ?? []);
} catch (error) { } catch (error) {
if ( if (
signal?.aborted || signal?.aborted ||

View File

@@ -1,12 +1,13 @@
import { Checkbox } from '@affine/component'; import { Checkbox } from '@affine/component';
import type { CalendarAccountCalendarsQuery } from '@affine/graphql'; import type { CalendarAccountsQuery } from '@affine/graphql';
import { cssVarV2 } from '@toeverything/theme/v2'; import { cssVarV2 } from '@toeverything/theme/v2';
import { useCallback } from 'react'; import { useCallback } from 'react';
import * as styles from './subscription-setting.css'; import * as styles from './subscription-setting.css';
type CalendarSubscription = type CalendarSubscription = NonNullable<
CalendarAccountCalendarsQuery['calendarAccountCalendars'][number]; NonNullable<CalendarAccountsQuery['currentUser']>['calendarAccounts'][number]
>['calendars'][number];
export const SubscriptionSetting = ({ export const SubscriptionSetting = ({
subscription, subscription,

View File

@@ -8,8 +8,9 @@ import { Store } from '@toeverything/infra';
import type { GraphQLService } from '../services/graphql'; import type { GraphQLService } from '../services/graphql';
export type AccessToken = export type AccessToken = NonNullable<
ListUserAccessTokensQuery['revealedAccessTokens'][number]; ListUserAccessTokensQuery['currentUser']
>['revealedAccessTokens'][number];
export class AccessTokenStore extends Store { export class AccessTokenStore extends Store {
constructor(private readonly gqlService: GraphQLService) { constructor(private readonly gqlService: GraphQLService) {
@@ -22,7 +23,7 @@ export class AccessTokenStore extends Store {
context: { signal }, context: { signal },
}); });
return data.revealedAccessTokens; return data.currentUser?.revealedAccessTokens ?? [];
} }
async generateUserAccessToken( async generateUserAccessToken(

View File

@@ -1,4 +1,4 @@
import { copilotQuotaQuery } from '@affine/graphql'; import { getCurrentUserProfileQuery } from '@affine/graphql';
import { Store } from '@toeverything/infra'; import { Store } from '@toeverything/infra';
import type { GraphQLService } from '../services/graphql'; import type { GraphQLService } from '../services/graphql';
@@ -10,7 +10,7 @@ export class UserCopilotQuotaStore extends Store {
async fetchUserCopilotQuota(abortSignal?: AbortSignal) { async fetchUserCopilotQuota(abortSignal?: AbortSignal) {
const data = await this.graphqlService.gql({ const data = await this.graphqlService.gql({
query: copilotQuotaQuery, query: getCurrentUserProfileQuery,
context: { context: {
signal: abortSignal, signal: abortSignal,
}, },

View File

@@ -1,4 +1,4 @@
import { getUserFeaturesQuery } from '@affine/graphql'; import { getCurrentUserProfileQuery } from '@affine/graphql';
import { Store } from '@toeverything/infra'; import { Store } from '@toeverything/infra';
import type { GraphQLService } from '../services/graphql'; import type { GraphQLService } from '../services/graphql';
@@ -10,7 +10,7 @@ export class UserFeatureStore extends Store {
async getUserFeatures(signal: AbortSignal) { async getUserFeatures(signal: AbortSignal) {
const data = await this.gqlService.gql({ const data = await this.gqlService.gql({
query: getUserFeaturesQuery, query: getCurrentUserProfileQuery,
context: { context: {
signal, signal,
}, },

View File

@@ -1,4 +1,4 @@
import { quotaQuery } from '@affine/graphql'; import { getCurrentUserProfileQuery } from '@affine/graphql';
import { Store } from '@toeverything/infra'; import { Store } from '@toeverything/infra';
import type { GraphQLService } from '../services/graphql'; import type { GraphQLService } from '../services/graphql';
@@ -10,7 +10,7 @@ export class UserQuotaStore extends Store {
async fetchUserQuota(abortSignal?: AbortSignal) { async fetchUserQuota(abortSignal?: AbortSignal) {
const data = await this.graphqlService.gql({ const data = await this.graphqlService.gql({
query: quotaQuery, query: getCurrentUserProfileQuery,
context: { context: {
signal: abortSignal, signal: abortSignal,
}, },

View File

@@ -1,6 +1,6 @@
import { import {
type GetUserSettingsQuery, type GetCurrentUserProfileQuery,
getUserSettingsQuery, getCurrentUserProfileQuery,
type UpdateUserSettingsInput, type UpdateUserSettingsInput,
updateUserSettingsMutation, updateUserSettingsMutation,
} from '@affine/graphql'; } from '@affine/graphql';
@@ -9,7 +9,7 @@ import { Store } from '@toeverything/infra';
import type { GraphQLService } from '../services/graphql'; import type { GraphQLService } from '../services/graphql';
export type UserSettings = NonNullable< export type UserSettings = NonNullable<
GetUserSettingsQuery['currentUser'] GetCurrentUserProfileQuery['currentUser']
>['settings']; >['settings'];
export type { UpdateUserSettingsInput }; export type { UpdateUserSettingsInput };
@@ -21,7 +21,7 @@ export class UserSettingsStore extends Store {
async getUserSettings(): Promise<UserSettings | undefined> { async getUserSettings(): Promise<UserSettings | undefined> {
const result = await this.gqlService.gql({ const result = await this.gqlService.gql({
query: getUserSettingsQuery, query: getCurrentUserProfileQuery,
}); });
return result.currentUser?.settings; return result.currentUser?.settings;
} }

View File

@@ -1,5 +1,4 @@
import type { import type {
CalendarAccountCalendarsQuery,
CalendarAccountsQuery, CalendarAccountsQuery,
CalendarEventsQuery, CalendarEventsQuery,
WorkspaceCalendarItemInput, WorkspaceCalendarItemInput,
@@ -16,20 +15,29 @@ export class CalendarIntegration extends Entity {
super(); super();
} }
accounts$ = new LiveData<CalendarAccountsQuery['calendarAccounts'][number][]>( accounts$ = new LiveData<
[] NonNullable<
); CalendarAccountsQuery['currentUser']
>['calendarAccounts'][number][]
>([]);
accountCalendars$ = new LiveData< accountCalendars$ = new LiveData<
Map< Map<
string, string,
CalendarAccountCalendarsQuery['calendarAccountCalendars'][number][] NonNullable<
NonNullable<
CalendarAccountsQuery['currentUser']
>['calendarAccounts'][number]
>['calendars']
> >
>(new Map()); >(new Map());
workspaceCalendars$ = new LiveData< workspaceCalendars$ = new LiveData<
WorkspaceCalendarsQuery['workspaceCalendars'][number][] WorkspaceCalendarsQuery['workspace']['calendars'][number][]
>([]); >([]);
readonly eventsByDateMap$ = new LiveData< readonly eventsByDateMap$ = new LiveData<
Map<string, CalendarEventsQuery['calendarEvents'][number][]> Map<
string,
CalendarEventsQuery['workspace']['calendars'][number]['events'][number][]
>
>(new Map()); >(new Map());
readonly eventDates$ = LiveData.computed(get => { readonly eventDates$ = LiveData.computed(get => {
const eventsByDateMap = get(this.eventsByDateMap$); const eventsByDateMap = get(this.eventsByDateMap$);
@@ -48,7 +56,11 @@ export class CalendarIntegration extends Entity {
const subscriptionInfo = new Map< const subscriptionInfo = new Map<
string, string,
{ {
subscription: CalendarAccountCalendarsQuery['calendarAccountCalendars'][number]; subscription: NonNullable<
NonNullable<
CalendarAccountsQuery['currentUser']
>['calendarAccounts'][number]
>['calendars'][number];
colorOverride?: string | null; colorOverride?: string | null;
} }
>(); >();
@@ -113,23 +125,16 @@ export class CalendarIntegration extends Entity {
const calendarsByAccount = new Map< const calendarsByAccount = new Map<
string, string,
CalendarAccountCalendarsQuery['calendarAccountCalendars'][number][] NonNullable<
NonNullable<
CalendarAccountsQuery['currentUser']
>['calendarAccounts'][number]
>['calendars']
>(); >();
await Promise.all( accounts.forEach(account => {
accounts.map(async account => { calendarsByAccount.set(account.id, account.calendars ?? []);
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, []);
}
})
);
this.accountCalendars$.setValue(calendarsByAccount); this.accountCalendars$.setValue(calendarsByAccount);
return calendarsByAccount; return calendarsByAccount;

View File

@@ -1,6 +1,4 @@
import { import {
type CalendarAccountCalendarsQuery,
calendarAccountCalendarsQuery,
type CalendarAccountsQuery, type CalendarAccountsQuery,
calendarAccountsQuery, calendarAccountsQuery,
type CalendarEventsQuery, type CalendarEventsQuery,
@@ -34,38 +32,27 @@ export class CalendarStore extends Store {
async fetchAccounts(signal?: AbortSignal) { async fetchAccounts(signal?: AbortSignal) {
const gql = this.gql; const gql = this.gql;
if (!gql) return [] satisfies CalendarAccountsQuery['calendarAccounts']; if (!gql)
return [] satisfies NonNullable<
CalendarAccountsQuery['currentUser']
>['calendarAccounts'];
const data = await gql({ const data = await gql({
query: calendarAccountsQuery, query: calendarAccountsQuery,
context: { signal }, context: { signal },
}); });
return data.calendarAccounts; return data.currentUser?.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;
} }
async fetchWorkspaceCalendars(signal?: AbortSignal) { async fetchWorkspaceCalendars(signal?: AbortSignal) {
const gql = this.gql; const gql = this.gql;
if (!gql) { if (!gql)
return [] satisfies WorkspaceCalendarsQuery['workspaceCalendars']; return [] satisfies WorkspaceCalendarsQuery['workspace']['calendars'];
}
const data = await gql({ const data = await gql({
query: workspaceCalendarsQuery, query: workspaceCalendarsQuery,
variables: { workspaceId: this.workspaceId }, variables: { workspaceId: this.workspaceId },
context: { signal }, context: { signal },
}); });
return data.workspaceCalendars; return data.workspace.calendars;
} }
async updateWorkspaceCalendars(items: WorkspaceCalendarItemInput[]) { async updateWorkspaceCalendars(items: WorkspaceCalendarItemInput[]) {
@@ -92,16 +79,19 @@ export class CalendarStore extends Store {
signal?: AbortSignal signal?: AbortSignal
) { ) {
const gql = this.gql; const gql = this.gql;
if (!gql) return [] satisfies CalendarEventsQuery['calendarEvents']; if (!gql)
return [] satisfies CalendarEventsQuery['workspace']['calendars'][number]['events'];
const data = await gql({ const data = await gql({
query: calendarEventsQuery, query: calendarEventsQuery,
variables: { variables: {
workspaceCalendarId, workspaceId: this.workspaceId,
from, from,
to, to,
}, },
context: { signal }, context: { signal },
}); });
return data.calendarEvents; const calendars = data.workspace.calendars;
const calendar = calendars.find(item => item.id === workspaceCalendarId);
return calendar?.events ?? [];
} }
} }

View File

@@ -60,7 +60,7 @@ export class NotificationStore extends Store {
}, },
}); });
return result.currentUser?.notificationCount; return result.currentUser?.notifications.totalCount;
} }
async listNotification(pagination: PaginationInput, signal?: AbortSignal) { async listNotification(pagination: PaginationInput, signal?: AbortSignal) {

View File

@@ -1,8 +1,8 @@
import { import {
type GetDocRolePermissionsQuery, type GetDocRolePermissionsQuery,
getDocRolePermissionsQuery, getDocRolePermissionsQuery,
type GetWorkspaceRolePermissionsQuery, type GetWorkspaceInfoQuery,
getWorkspaceRolePermissionsQuery, getWorkspaceInfoQuery,
} from '@affine/graphql'; } from '@affine/graphql';
import { Store } from '@toeverything/infra'; import { Store } from '@toeverything/infra';
@@ -10,7 +10,7 @@ import type { WorkspaceServerService } from '../../cloud';
import type { WorkspaceService } from '../../workspace'; import type { WorkspaceService } from '../../workspace';
export type WorkspacePermissionActions = keyof Omit< export type WorkspacePermissionActions = keyof Omit<
GetWorkspaceRolePermissionsQuery['workspaceRolePermissions']['permissions'], GetWorkspaceInfoQuery['workspace']['permissions'],
'__typename' '__typename'
>; >;
@@ -34,12 +34,12 @@ export class GuardStore extends Store {
throw new Error('No server'); throw new Error('No server');
} }
const data = await this.workspaceServerService.server.gql({ const data = await this.workspaceServerService.server.gql({
query: getWorkspaceRolePermissionsQuery, query: getWorkspaceInfoQuery,
variables: { variables: {
id: this.workspaceService.workspace.id, workspaceId: this.workspaceService.workspace.id,
}, },
}); });
return data.workspaceRolePermissions.permissions; return data.workspace.permissions;
} }
async getDocPermissions( async getDocPermissions(