feat: backend module awareness & optional request (#5909)

This commit is contained in:
DarkSky
2024-02-28 08:29:37 +00:00
parent 35454c3bfc
commit 3432f355b0
7 changed files with 34 additions and 31 deletions

View File

@@ -46,6 +46,7 @@ export class ServerConfigType {
@Field(() => [ServerFeature], { description: 'enabled server features' }) @Field(() => [ServerFeature], { description: 'enabled server features' })
features!: ServerFeature[]; features!: ServerFeature[];
} }
export class ServerConfigResolver { export class ServerConfigResolver {
@Query(() => ServerConfigType, { @Query(() => ServerConfigType, {
description: 'server config', description: 'server config',

View File

@@ -17,11 +17,10 @@ import { StripeWebhook } from './webhook';
UserSubscriptionResolver, UserSubscriptionResolver,
], ],
controllers: [StripeWebhook], controllers: [StripeWebhook],
// TODO(@forehalo): enable this requirements when conditional query is implemented in frontend requires: [
// requires: [ 'plugins.payment.stripe.keys.APIKey',
// 'plugins.payment.stripe.keys.APIKey', 'plugins.payment.stripe.keys.webhookKey',
// 'plugins.payment.stripe.keys.webhookKey', ],
// ],
contributesTo: ServerFeature.Payment, contributesTo: ServerFeature.Payment,
if: config => config.flavor.graphql, if: config => config.flavor.graphql,
}) })

View File

@@ -34,7 +34,7 @@ import {
openSignOutModalAtom, openSignOutModalAtom,
} from '../../../../atoms'; } from '../../../../atoms';
import { useCurrentUser } from '../../../../hooks/affine/use-current-user'; import { useCurrentUser } from '../../../../hooks/affine/use-current-user';
import { useSelfHosted } from '../../../../hooks/affine/use-server-config'; import { useServerFeatures } from '../../../../hooks/affine/use-server-config';
import { useMutation } from '../../../../hooks/use-mutation'; import { useMutation } from '../../../../hooks/use-mutation';
import { useQuery } from '../../../../hooks/use-query'; import { useQuery } from '../../../../hooks/use-query';
import { useUserSubscription } from '../../../../hooks/use-subscription'; import { useUserSubscription } from '../../../../hooks/use-subscription';
@@ -169,7 +169,7 @@ export const AvatarAndName = () => {
const StoragePanel = () => { const StoragePanel = () => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const isSelfHosted = useSelfHosted(); const { payment: hasPaymentFeature } = useServerFeatures();
const { data } = useQuery({ const { data } = useQuery({
query: allBlobSizesQuery, query: allBlobSizesQuery,
@@ -205,7 +205,7 @@ const StoragePanel = () => {
plan={plan} plan={plan}
value={data.collectAllBlobSizes.size} value={data.collectAllBlobSizes.size}
onUpgrade={onUpgrade} onUpgrade={onUpgrade}
upgradable={!isSelfHosted} upgradable={hasPaymentFeature}
/> />
</SettingRow> </SettingRow>
); );

View File

@@ -7,7 +7,7 @@ import {
import type { ReactElement, SVGProps } from 'react'; import type { ReactElement, SVGProps } from 'react';
import { useCurrentLoginStatus } from '../../../../hooks/affine/use-current-login-status'; import { useCurrentLoginStatus } from '../../../../hooks/affine/use-current-login-status';
import { useSelfHosted } from '../../../../hooks/affine/use-server-config'; import { useServerFeatures } from '../../../../hooks/affine/use-server-config';
import type { GeneralSettingKey } from '../types'; import type { GeneralSettingKey } from '../types';
import { AboutAffine } from './about'; import { AboutAffine } from './about';
import { AppearanceSettings } from './appearance'; import { AppearanceSettings } from './appearance';
@@ -28,7 +28,7 @@ export type GeneralSettingList = GeneralSettingListItem[];
export const useGeneralSettingList = (): GeneralSettingList => { export const useGeneralSettingList = (): GeneralSettingList => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const status = useCurrentLoginStatus(); const status = useCurrentLoginStatus();
const isSelfHosted = useSelfHosted(); const { payment: hasPaymentFeature } = useServerFeatures();
const settings: GeneralSettingListItem[] = [ const settings: GeneralSettingListItem[] = [
{ {
@@ -51,7 +51,7 @@ export const useGeneralSettingList = (): GeneralSettingList => {
}, },
]; ];
if (!isSelfHosted) { if (hasPaymentFeature) {
settings.splice(3, 0, { settings.splice(3, 0, {
key: 'plans', key: 'plans',
title: t['com.affine.payment.title'](), title: t['com.affine.payment.title'](),

View File

@@ -3,7 +3,7 @@ import {
SettingRow, SettingRow,
SettingWrapper, SettingWrapper,
} from '@affine/component/setting-components'; } from '@affine/component/setting-components';
import { useSelfHosted } from '@affine/core/hooks/affine/use-server-config'; import { useServerFeatures } from '@affine/core/hooks/affine/use-server-config';
import { useWorkspace } from '@affine/core/hooks/use-workspace'; import { useWorkspace } from '@affine/core/hooks/use-workspace';
import { useWorkspaceInfo } from '@affine/core/hooks/use-workspace-info'; import { useWorkspaceInfo } from '@affine/core/hooks/use-workspace-info';
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant'; import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
@@ -20,7 +20,7 @@ import type { WorkspaceSettingDetailProps } from './types';
export const WorkspaceSettingDetail = (props: WorkspaceSettingDetailProps) => { export const WorkspaceSettingDetail = (props: WorkspaceSettingDetailProps) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const isSelfHosted = useSelfHosted(); const { payment: hasPaymentFeature } = useServerFeatures();
const workspaceMetadata = props.workspaceMetadata; const workspaceMetadata = props.workspaceMetadata;
// useWorkspace hook is a vary heavy operation here, but we need syncing name and avatar changes here, // useWorkspace hook is a vary heavy operation here, but we need syncing name and avatar changes here,
@@ -49,7 +49,7 @@ export const WorkspaceSettingDetail = (props: WorkspaceSettingDetailProps) => {
</SettingWrapper> </SettingWrapper>
<SettingWrapper title={t['com.affine.brand.affineCloud']()}> <SettingWrapper title={t['com.affine.brand.affineCloud']()}>
<EnableCloudPanel workspace={workspace} {...props} /> <EnableCloudPanel workspace={workspace} {...props} />
<MembersPanel upgradable={!isSelfHosted} {...props} /> <MembersPanel upgradable={hasPaymentFeature} {...props} />
</SettingWrapper> </SettingWrapper>
{environment.isDesktop && ( {environment.isDesktop && (
<SettingWrapper title={t['Storage and Export']()}> <SettingWrapper title={t['Storage and Export']()}>

View File

@@ -1,4 +1,5 @@
import { serverConfigQuery, ServerDeploymentType } from '@affine/graphql'; import type { ServerFeature } from '@affine/graphql';
import { serverConfigQuery } from '@affine/graphql';
import type { BareFetcher, Middleware } from 'swr'; import type { BareFetcher, Middleware } from 'swr';
import { useQueryImmutable } from '../use-query'; import { useQueryImmutable } from '../use-query';
@@ -25,20 +26,22 @@ const useServerConfig = () => {
return config.serverConfig; return config.serverConfig;
}; };
export const useServerType = () => { type LowercaseServerFeature = Lowercase<ServerFeature>;
type ServerFeatureRecord = {
[key in LowercaseServerFeature]: boolean;
};
export const useServerFeatures = (): ServerFeatureRecord => {
const config = useServerConfig(); const config = useServerConfig();
if (!config) { if (!config) {
return 'local'; return {} as ServerFeatureRecord;
} }
return config.type; return Array.from(new Set(config.features)).reduce((acc, cur) => {
}; acc[cur.toLowerCase() as LowercaseServerFeature] = true;
return acc;
export const useSelfHosted = () => { }, {} as ServerFeatureRecord);
const serverType = useServerType();
return ['local', ServerDeploymentType.Selfhosted].includes(serverType);
}; };
export const useServerBaseUrl = () => { export const useServerBaseUrl = () => {

View File

@@ -1,7 +1,7 @@
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { type SubscriptionQuery, subscriptionQuery } from '@affine/graphql'; import { type SubscriptionQuery, subscriptionQuery } from '@affine/graphql';
import { useSelfHosted } from './affine/use-server-config'; import { useServerFeatures } from './affine/use-server-config';
import { useQuery } from './use-query'; import { useQuery } from './use-query';
export type Subscription = NonNullable< export type Subscription = NonNullable<
@@ -14,10 +14,10 @@ const selector = (data: SubscriptionQuery) =>
data.currentUser?.subscription ?? null; data.currentUser?.subscription ?? null;
export const useUserSubscription = () => { export const useUserSubscription = () => {
const isSelfHosted = useSelfHosted(); const { payment: hasPaymentFeature } = useServerFeatures();
const { data, mutate } = useQuery({ const { data, mutate } = useQuery(
query: subscriptionQuery, hasPaymentFeature ? { query: subscriptionQuery } : undefined
}); );
const set: SubscriptionMutator = useAsyncCallback( const set: SubscriptionMutator = useAsyncCallback(
async (update?: Partial<Subscription>) => { async (update?: Partial<Subscription>) => {
@@ -39,8 +39,8 @@ export const useUserSubscription = () => {
[mutate] [mutate]
); );
if (isSelfHosted) { if (!hasPaymentFeature) {
return [selector(data), () => {}] as const; return [null, () => {}] as const;
} }
return [selector(data), set] as const; return [selector(data), set] as const;