feat(core): add enable url preview to workspace settings (#8089)

This commit is contained in:
JimmFly
2024-09-10 04:04:05 +00:00
parent fe1eefdbb2
commit 9d343bdaa6
12 changed files with 276 additions and 0 deletions

View File

@@ -17,6 +17,7 @@ import { ExportPanel } from './export';
import { LabelsPanel } from './labels';
import { MembersPanel } from './members';
import { ProfilePanel } from './profile';
import { SharingPanel } from './sharing';
import type { WorkspaceSettingDetailProps } from './types';
export const WorkspaceSettingDetail = ({
@@ -67,6 +68,7 @@ export const WorkspaceSettingDetail = ({
<EnableCloudPanel />
<MembersPanel />
</SettingWrapper>
<SharingPanel />
{environment.isElectron && (
<SettingWrapper title={t['Storage and Export']()}>
<ExportPanel

View File

@@ -0,0 +1,49 @@
import { Switch } from '@affine/component';
import {
SettingRow,
SettingWrapper,
} from '@affine/component/setting-components';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { WorkspaceShareSettingService } from '@affine/core/modules/share-setting';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { useI18n } from '@affine/i18n';
import { useLiveData, useService, WorkspaceService } from '@toeverything/infra';
export const SharingPanel = () => {
const workspace = useService(WorkspaceService).workspace;
if (workspace.flavour === WorkspaceFlavour.LOCAL) {
return null;
}
return <Sharing />;
};
export const Sharing = () => {
const t = useI18n();
const shareSetting = useService(WorkspaceShareSettingService).sharePreview;
const enableUrlPreview = useLiveData(shareSetting.enableUrlPreview$);
const loading = useLiveData(shareSetting.isLoading$);
const handleCheck = useAsyncCallback(
async (checked: boolean) => {
await shareSetting.setEnableUrlPreview(checked);
},
[shareSetting]
);
return (
<SettingWrapper title={t['com.affine.settings.workspace.sharing.title']()}>
<SettingRow
name={t['com.affine.settings.workspace.sharing.url-preview.title']()}
desc={t[
'com.affine.settings.workspace.sharing.url-preview.description'
]()}
>
<Switch
checked={enableUrlPreview || false}
onChange={handleCheck}
disabled={loading}
/>
</SettingRow>
</SettingWrapper>
);
};

View File

@@ -19,6 +19,7 @@ import { configurePermissionsModule } from './permissions';
import { configureWorkspacePropertiesModule } from './properties';
import { configureQuickSearchModule } from './quicksearch';
import { configureShareDocsModule } from './share-doc';
import { configureShareSettingModule } from './share-setting';
import { configureSystemFontFamilyModule } from './system-font-family';
import { configureTagModule } from './tag';
import { configureTelemetryModule } from './telemetry';
@@ -34,6 +35,7 @@ export function configureCommonModules(framework: Framework) {
configureQuotaModule(framework);
configurePermissionsModule(framework);
configureShareDocsModule(framework);
configureShareSettingModule(framework);
configureTelemetryModule(framework);
configureFindInPageModule(framework);
configurePeekViewModule(framework);

View File

@@ -0,0 +1,80 @@
import { DebugLogger } from '@affine/debug';
import type { GetEnableUrlPreviewQuery } from '@affine/graphql';
import type { WorkspaceService } from '@toeverything/infra';
import {
backoffRetry,
catchErrorInto,
effect,
Entity,
fromPromise,
LiveData,
mapInto,
onComplete,
onStart,
} from '@toeverything/infra';
import { exhaustMap } from 'rxjs';
import { isBackendError, isNetworkError } from '../../cloud';
import type { WorkspaceShareSettingStore } from '../stores/share-setting';
type EnableUrlPreview =
GetEnableUrlPreviewQuery['workspace']['enableUrlPreview'];
const logger = new DebugLogger('affine:workspace-permission');
export class WorkspaceShareSetting extends Entity {
enableUrlPreview$ = new LiveData<EnableUrlPreview | null>(null);
isLoading$ = new LiveData(false);
error$ = new LiveData<any>(null);
constructor(
private readonly workspaceService: WorkspaceService,
private readonly store: WorkspaceShareSettingStore
) {
super();
this.revalidate();
}
revalidate = effect(
exhaustMap(() => {
return fromPromise(signal =>
this.store.fetchWorkspaceEnableUrlPreview(
this.workspaceService.workspace.id,
signal
)
).pipe(
backoffRetry({
when: isNetworkError,
count: Infinity,
}),
backoffRetry({
when: isBackendError,
count: 3,
}),
mapInto(this.enableUrlPreview$),
catchErrorInto(this.error$, error => {
logger.error('Failed to fetch enableUrlPreview', error);
}),
onStart(() => this.isLoading$.setValue(true)),
onComplete(() => this.isLoading$.setValue(false))
);
})
);
async waitForRevalidation(signal?: AbortSignal) {
this.revalidate();
await this.isLoading$.waitFor(isLoading => !isLoading, signal);
}
async setEnableUrlPreview(enableUrlPreview: EnableUrlPreview) {
await this.store.updateWorkspaceEnableUrlPreview(
this.workspaceService.workspace.id,
enableUrlPreview
);
await this.waitForRevalidation();
}
override dispose(): void {
this.revalidate.unsubscribe();
}
}

View File

@@ -0,0 +1,23 @@
export { WorkspaceShareSettingService } from './services/share-setting';
import { GraphQLService } from '@affine/core/modules/cloud';
import {
type Framework,
WorkspaceScope,
WorkspaceService,
} from '@toeverything/infra';
import { WorkspaceShareSetting } from './entities/share-setting';
import { WorkspaceShareSettingService } from './services/share-setting';
import { WorkspaceShareSettingStore } from './stores/share-setting';
export function configureShareSettingModule(framework: Framework) {
framework
.scope(WorkspaceScope)
.service(WorkspaceShareSettingService)
.store(WorkspaceShareSettingStore, [GraphQLService])
.entity(WorkspaceShareSetting, [
WorkspaceService,
WorkspaceShareSettingStore,
]);
}

View File

@@ -0,0 +1,7 @@
import { Service } from '@toeverything/infra';
import { WorkspaceShareSetting } from '../entities/share-setting';
export class WorkspaceShareSettingService extends Service {
sharePreview = this.framework.createEntity(WorkspaceShareSetting);
}

View File

@@ -0,0 +1,45 @@
import type { GraphQLService } from '@affine/core/modules/cloud';
import {
getEnableUrlPreviewQuery,
setEnableUrlPreviewMutation,
} from '@affine/graphql';
import { Store } from '@toeverything/infra';
export class WorkspaceShareSettingStore extends Store {
constructor(private readonly graphqlService: GraphQLService) {
super();
}
async fetchWorkspaceEnableUrlPreview(
workspaceId: string,
signal?: AbortSignal
) {
const data = await this.graphqlService.gql({
query: getEnableUrlPreviewQuery,
variables: {
id: workspaceId,
},
context: {
signal,
},
});
return data.workspace.enableUrlPreview;
}
async updateWorkspaceEnableUrlPreview(
workspaceId: string,
enableUrlPreview: boolean,
signal?: AbortSignal
) {
await this.graphqlService.gql({
query: setEnableUrlPreviewMutation,
variables: {
id: workspaceId,
enableUrlPreview,
},
context: {
signal,
},
});
}
}