feat: backend module awareness & optional request (#5909)
This commit is contained in:
@@ -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',
|
||||||
|
|||||||
@@ -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,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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'](),
|
||||||
|
|||||||
@@ -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']()}>
|
||||||
|
|||||||
@@ -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 = () => {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user