feat: add editor record (#7938)

fix CLOUD-58, CLOUD-61, CLOUD-62, PD-1607, PD-1608
This commit is contained in:
darkskygit
2024-09-02 09:37:39 +00:00
parent d9cedf89e1
commit d93d39e29d
33 changed files with 622 additions and 55 deletions
@@ -0,0 +1,66 @@
import type { GetWorkspacePageMetaByIdQuery } from '@affine/graphql';
import type { DocService, GlobalCache } from '@toeverything/infra';
import {
backoffRetry,
catchErrorInto,
effect,
Entity,
exhaustMapWithTrailing,
fromPromise,
LiveData,
onComplete,
onStart,
} from '@toeverything/infra';
import { EMPTY, mergeMap } from 'rxjs';
import { isBackendError, isNetworkError } from '../error';
import type { CloudDocMetaStore } from '../stores/cloud-doc-meta';
export type CloudDocMetaType =
GetWorkspacePageMetaByIdQuery['workspace']['pageMeta'];
const CACHE_KEY_PREFIX = 'cloud-doc-meta:';
export class CloudDocMeta extends Entity {
constructor(
private readonly store: CloudDocMetaStore,
private readonly docService: DocService,
private readonly cache: GlobalCache
) {
super();
}
readonly docId = this.docService.doc.id;
readonly workspaceId = this.docService.doc.workspace.id;
readonly cacheKey = `${CACHE_KEY_PREFIX}${this.workspaceId}:${this.docId}`;
meta$ = LiveData.from<CloudDocMetaType | undefined>(
this.cache.watch<CloudDocMetaType>(this.cacheKey),
undefined
);
isRevalidating$ = new LiveData(false);
error$ = new LiveData<any | null>(null);
revalidate = effect(
exhaustMapWithTrailing(() => {
return fromPromise(
this.store.fetchCloudDocMeta(this.workspaceId, this.docId)
).pipe(
backoffRetry({
when: isNetworkError,
count: Infinity,
}),
backoffRetry({
when: isBackendError,
}),
mergeMap(meta => {
this.cache.set<CloudDocMetaType>(this.cacheKey, meta);
return EMPTY;
}),
catchErrorInto(this.error$),
onStart(() => this.isRevalidating$.next(true)),
onComplete(() => this.isRevalidating$.next(false))
);
})
);
}
@@ -16,11 +16,15 @@ export { UserQuotaService } from './services/user-quota';
export { WebSocketService } from './services/websocket';
import {
DocScope,
DocService,
type Framework,
GlobalCacheService,
GlobalStateService,
GlobalCache,
GlobalState,
WorkspaceScope,
} from '@toeverything/infra';
import { CloudDocMeta } from './entities/cloud-doc-meta';
import { ServerConfig } from './entities/server-config';
import { AuthSession } from './entities/session';
import { Subscription } from './entities/subscription';
@@ -29,6 +33,7 @@ import { UserCopilotQuota } from './entities/user-copilot-quota';
import { UserFeature } from './entities/user-feature';
import { UserQuota } from './entities/user-quota';
import { AuthService } from './services/auth';
import { CloudDocMetaService } from './services/cloud-doc-meta';
import { FetchService } from './services/fetch';
import { GraphQLService } from './services/graphql';
import { ServerConfigService } from './services/server-config';
@@ -38,6 +43,7 @@ import { UserFeatureService } from './services/user-feature';
import { UserQuotaService } from './services/user-quota';
import { WebSocketService } from './services/websocket';
import { AuthStore } from './stores/auth';
import { CloudDocMetaStore } from './stores/cloud-doc-meta';
import { ServerConfigStore } from './stores/server-config';
import { SubscriptionStore } from './stores/subscription';
import { UserCopilotQuotaStore } from './stores/user-copilot-quota';
@@ -53,10 +59,10 @@ export function configureCloudModule(framework: Framework) {
.entity(ServerConfig, [ServerConfigStore])
.store(ServerConfigStore, [GraphQLService])
.service(AuthService, [FetchService, AuthStore])
.store(AuthStore, [FetchService, GraphQLService, GlobalStateService])
.store(AuthStore, [FetchService, GraphQLService, GlobalState])
.entity(AuthSession, [AuthStore])
.service(SubscriptionService, [SubscriptionStore])
.store(SubscriptionStore, [GraphQLService, GlobalCacheService])
.store(SubscriptionStore, [GraphQLService, GlobalCache])
.entity(Subscription, [AuthService, ServerConfigService, SubscriptionStore])
.entity(SubscriptionPrices, [ServerConfigService, SubscriptionStore])
.service(UserQuotaService)
@@ -71,5 +77,10 @@ export function configureCloudModule(framework: Framework) {
])
.service(UserFeatureService)
.entity(UserFeature, [AuthService, UserFeatureStore])
.store(UserFeatureStore, [GraphQLService]);
.store(UserFeatureStore, [GraphQLService])
.scope(WorkspaceScope)
.scope(DocScope)
.service(CloudDocMetaService)
.entity(CloudDocMeta, [CloudDocMetaStore, DocService, GlobalCache])
.store(CloudDocMetaStore, [GraphQLService]);
}
@@ -0,0 +1,7 @@
import { Service } from '@toeverything/infra';
import { CloudDocMeta } from '../entities/cloud-doc-meta';
export class CloudDocMetaService extends Service {
cloudDocMeta = this.framework.createEntity(CloudDocMeta);
}
@@ -4,7 +4,7 @@ import {
updateUserProfileMutation,
uploadAvatarMutation,
} from '@affine/graphql';
import type { GlobalStateService } from '@toeverything/infra';
import type { GlobalState } from '@toeverything/infra';
import { Store } from '@toeverything/infra';
import type { AuthSessionInfo } from '../entities/session';
@@ -24,19 +24,17 @@ export class AuthStore extends Store {
constructor(
private readonly fetchService: FetchService,
private readonly gqlService: GraphQLService,
private readonly globalStateService: GlobalStateService
private readonly globalState: GlobalState
) {
super();
}
watchCachedAuthSession() {
return this.globalStateService.globalState.watch<AuthSessionInfo>(
'affine-cloud-auth'
);
return this.globalState.watch<AuthSessionInfo>('affine-cloud-auth');
}
setCachedAuthSession(session: AuthSessionInfo | null) {
this.globalStateService.globalState.set('affine-cloud-auth', session);
this.globalState.set('affine-cloud-auth', session);
}
async fetchSession() {
@@ -0,0 +1,26 @@
import { getWorkspacePageMetaByIdQuery } from '@affine/graphql';
import { Store } from '@toeverything/infra';
import { type CloudDocMetaType } from '../entities/cloud-doc-meta';
import type { GraphQLService } from '../services/graphql';
export class CloudDocMetaStore extends Store {
constructor(private readonly gqlService: GraphQLService) {
super();
}
async fetchCloudDocMeta(
workspaceId: string,
docId: string,
abortSignal?: AbortSignal
): Promise<CloudDocMetaType> {
const serverConfigData = await this.gqlService.gql({
query: getWorkspacePageMetaByIdQuery,
variables: { id: workspaceId, pageId: docId },
context: {
signal: abortSignal,
},
});
return serverConfigData.workspace.pageMeta;
}
}
@@ -12,7 +12,7 @@ import {
subscriptionQuery,
updateSubscriptionMutation,
} from '@affine/graphql';
import type { GlobalCacheService } from '@toeverything/infra';
import type { GlobalCache } from '@toeverything/infra';
import { Store } from '@toeverything/infra';
import type { SubscriptionType } from '../entities/subscription';
@@ -37,7 +37,7 @@ const getDefaultSubscriptionSuccessCallbackLink = (
export class SubscriptionStore extends Store {
constructor(
private readonly gqlService: GraphQLService,
private readonly globalCacheService: GlobalCacheService
private readonly globalCache: GlobalCache
) {
super();
}
@@ -97,16 +97,13 @@ export class SubscriptionStore extends Store {
}
getCachedSubscriptions(userId: string) {
return this.globalCacheService.globalCache.get<SubscriptionType[]>(
return this.globalCache.get<SubscriptionType[]>(
SUBSCRIPTION_CACHE_KEY + userId
);
}
setCachedSubscriptions(userId: string, subscriptions: SubscriptionType[]) {
return this.globalCacheService.globalCache.set(
SUBSCRIPTION_CACHE_KEY + userId,
subscriptions
);
return this.globalCache.set(SUBSCRIPTION_CACHE_KEY + userId, subscriptions);
}
setSubscriptionRecurring(
@@ -21,6 +21,8 @@ export enum PagePropertyType {
Progress = 'progress',
Checkbox = 'checkbox',
Tags = 'tags',
CreatedBy = 'createdBy',
UpdatedBy = 'updatedBy',
}
export const PagePropertyMetaBaseSchema = z.object({
@@ -30,6 +32,7 @@ export const PagePropertyMetaBaseSchema = z.object({
type: z.nativeEnum(PagePropertyType),
icon: z.string(),
required: z.boolean().optional(),
readonly: z.boolean().optional(),
});
export const PageSystemPropertyMetaBaseSchema =
@@ -6,12 +6,13 @@ import {
catchErrorInto,
effect,
Entity,
exhaustMapWithTrailing,
fromPromise,
LiveData,
onComplete,
onStart,
} from '@toeverything/infra';
import { EMPTY, mergeMap, switchMap } from 'rxjs';
import { EMPTY, mergeMap } from 'rxjs';
import { isBackendError, isNetworkError } from '../../cloud';
import type { ShareDocsStore } from '../stores/share-docs';
@@ -35,7 +36,7 @@ export class ShareDocsList extends Entity {
}
revalidate = effect(
switchMap(() =>
exhaustMapWithTrailing(() =>
fromPromise(signal => {
return this.store.getWorkspacesShareDocs(
this.workspaceService.workspace.id,