feat(core): add self host team plan (#9569)
This commit is contained in:
@@ -105,7 +105,7 @@ export class LicenseService implements OnModuleInit {
|
|||||||
throw new WorkspaceLicenseAlreadyExists();
|
throw new WorkspaceLicenseAlreadyExists();
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await this.fetch<License>(
|
const data = await this.fetchAffinePro<License>(
|
||||||
`/api/team/licenses/${licenseKey}/activate`,
|
`/api/team/licenses/${licenseKey}/activate`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -155,7 +155,7 @@ export class LicenseService implements OnModuleInit {
|
|||||||
throw new LicenseNotFound();
|
throw new LicenseNotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.fetch(`/api/team/licenses/${license.key}/deactivate`, {
|
await this.fetchAffinePro(`/api/team/licenses/${license.key}/deactivate`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -170,10 +170,11 @@ export class LicenseService implements OnModuleInit {
|
|||||||
plan: SubscriptionPlan.SelfHostedTeam,
|
plan: SubscriptionPlan.SelfHostedTeam,
|
||||||
recurring: SubscriptionRecurring.Monthly,
|
recurring: SubscriptionRecurring.Monthly,
|
||||||
});
|
});
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateTeamRecurring(key: string, recurring: SubscriptionRecurring) {
|
async updateTeamRecurring(key: string, recurring: SubscriptionRecurring) {
|
||||||
await this.fetch(`/api/team/licenses/${key}/recurring`, {
|
await this.fetchAffinePro(`/api/team/licenses/${key}/recurring`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
recurring,
|
recurring,
|
||||||
@@ -192,7 +193,7 @@ export class LicenseService implements OnModuleInit {
|
|||||||
throw new LicenseNotFound();
|
throw new LicenseNotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.fetch<{ url: string }>(
|
return this.fetchAffinePro<{ url: string }>(
|
||||||
`/api/team/licenses/${license.key}/create-customer-portal`,
|
`/api/team/licenses/${license.key}/create-customer-portal`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -218,7 +219,7 @@ export class LicenseService implements OnModuleInit {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.fetch(`/api/team/licenses/${license.key}/seats`, {
|
await this.fetchAffinePro(`/api/team/licenses/${license.key}/seats`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
quantity: count,
|
quantity: count,
|
||||||
@@ -276,7 +277,7 @@ export class LicenseService implements OnModuleInit {
|
|||||||
|
|
||||||
private async revalidateLicense(license: InstalledLicense) {
|
private async revalidateLicense(license: InstalledLicense) {
|
||||||
try {
|
try {
|
||||||
const res = await this.fetch<License>(
|
const res = await this.fetchAffinePro<License>(
|
||||||
`/api/team/licenses/${license.key}/health`,
|
`/api/team/licenses/${license.key}/health`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
@@ -325,7 +326,7 @@ export class LicenseService implements OnModuleInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async fetch<T = any>(
|
private async fetchAffinePro<T = any>(
|
||||||
path: string,
|
path: string,
|
||||||
init?: RequestInit
|
init?: RequestInit
|
||||||
): Promise<T & { res: Response }> {
|
): Promise<T & { res: Response }> {
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ class CreateCheckoutSessionInput implements z.infer<typeof CheckoutParams> {
|
|||||||
idempotencyKey?: string;
|
idempotencyKey?: string;
|
||||||
|
|
||||||
@Field(() => GraphQLJSONObject, { nullable: true })
|
@Field(() => GraphQLJSONObject, { nullable: true })
|
||||||
args!: { workspaceId?: string; quantity?: number };
|
args!: { workspaceId?: string; quantity?: number } | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Resolver(() => SubscriptionType)
|
@Resolver(() => SubscriptionType)
|
||||||
@@ -278,7 +278,7 @@ export class SubscriptionResolver {
|
|||||||
if (input.plan === SubscriptionPlan.SelfHostedTeam) {
|
if (input.plan === SubscriptionPlan.SelfHostedTeam) {
|
||||||
session = await this.service.checkout(input, {
|
session = await this.service.checkout(input, {
|
||||||
plan: input.plan as any,
|
plan: input.plan as any,
|
||||||
quantity: input.args.quantity ?? 10,
|
quantity: input.args?.quantity ?? 10,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const InviteModal = ({
|
|||||||
}: InviteModalProps) => {
|
}: InviteModalProps) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const [inviteEmail, setInviteEmail] = useState('');
|
const [inviteEmail, setInviteEmail] = useState('');
|
||||||
const [permission] = useState(Permission.Write);
|
const [permission] = useState(Permission.Collaborator);
|
||||||
const [isValidEmail, setIsValidEmail] = useState(true);
|
const [isValidEmail, setIsValidEmail] = useState(true);
|
||||||
|
|
||||||
const handleConfirm = useCallback(() => {
|
const handleConfirm = useCallback(() => {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { ConfirmModal } from '@affine/component/ui/modal';
|
import { ConfirmModal } from '@affine/component/ui/modal';
|
||||||
import { openQuotaModalAtom } from '@affine/core/components/atoms';
|
import { openQuotaModalAtom } from '@affine/core/components/atoms';
|
||||||
import { UserQuotaService } from '@affine/core/modules/cloud';
|
|
||||||
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
||||||
import { WorkspacePermissionService } from '@affine/core/modules/permissions';
|
import { WorkspacePermissionService } from '@affine/core/modules/permissions';
|
||||||
import { WorkspaceQuotaService } from '@affine/core/modules/quota';
|
import { WorkspaceQuotaService } from '@affine/core/modules/quota';
|
||||||
@@ -30,18 +29,6 @@ export const CloudQuotaModal = () => {
|
|||||||
permissionService.permission.revalidate();
|
permissionService.permission.revalidate();
|
||||||
}, [permissionService]);
|
}, [permissionService]);
|
||||||
|
|
||||||
const quotaService = useService(UserQuotaService);
|
|
||||||
const userQuota = useLiveData(
|
|
||||||
quotaService.quota.quota$.map(q =>
|
|
||||||
q
|
|
||||||
? {
|
|
||||||
name: q.humanReadable.name,
|
|
||||||
blobLimit: q.humanReadable.blobLimit,
|
|
||||||
}
|
|
||||||
: null
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const workspaceDialogService = useService(WorkspaceDialogService);
|
const workspaceDialogService = useService(WorkspaceDialogService);
|
||||||
const handleUpgradeConfirm = useCallback(() => {
|
const handleUpgradeConfirm = useCallback(() => {
|
||||||
workspaceDialogService.open('setting', {
|
workspaceDialogService.open('setting', {
|
||||||
@@ -54,18 +41,19 @@ export const CloudQuotaModal = () => {
|
|||||||
}, [workspaceDialogService, setOpen]);
|
}, [workspaceDialogService, setOpen]);
|
||||||
|
|
||||||
const description = useMemo(() => {
|
const description = useMemo(() => {
|
||||||
if (userQuota && isOwner) {
|
if (!workspaceQuota) {
|
||||||
return <OwnerDescription quota={userQuota.blobLimit} />;
|
|
||||||
}
|
|
||||||
if (workspaceQuota) {
|
|
||||||
return t['com.affine.payment.blob-limit.description.member']({
|
|
||||||
quota: workspaceQuota.humanReadable.blobLimit,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// loading
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}, [userQuota, isOwner, workspaceQuota, t]);
|
if (isOwner) {
|
||||||
|
return (
|
||||||
|
<OwnerDescription quota={workspaceQuota.humanReadable.blobLimit} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return t['com.affine.payment.blob-limit.description.member']({
|
||||||
|
quota: workspaceQuota.humanReadable.blobLimit,
|
||||||
|
});
|
||||||
|
}, [isOwner, workspaceQuota, t]);
|
||||||
|
|
||||||
const onAbortLargeBlob = useAsyncCallback(
|
const onAbortLargeBlob = useAsyncCallback(
|
||||||
async (byteSize: number) => {
|
async (byteSize: number) => {
|
||||||
|
|||||||
@@ -49,15 +49,21 @@ export const generateSubscriptionCallbackLink = (
|
|||||||
recurring: SubscriptionRecurring,
|
recurring: SubscriptionRecurring,
|
||||||
workspaceId?: string
|
workspaceId?: string
|
||||||
) => {
|
) => {
|
||||||
if (account === null) {
|
|
||||||
throw new Error('Account is required');
|
|
||||||
}
|
|
||||||
const baseUrl =
|
const baseUrl =
|
||||||
plan === SubscriptionPlan.AI
|
plan === SubscriptionPlan.AI
|
||||||
? '/ai-upgrade-success'
|
? '/ai-upgrade-success'
|
||||||
: plan === SubscriptionPlan.Team
|
: plan === SubscriptionPlan.Team
|
||||||
? '/upgrade-success/team'
|
? '/upgrade-success/team'
|
||||||
: '/upgrade-success';
|
: plan === SubscriptionPlan.SelfHostedTeam
|
||||||
|
? '/upgrade-success/self-hosted-team'
|
||||||
|
: '/upgrade-success';
|
||||||
|
|
||||||
|
if (plan === SubscriptionPlan.SelfHostedTeam) {
|
||||||
|
return baseUrl;
|
||||||
|
}
|
||||||
|
if (account === null) {
|
||||||
|
throw new Error('Account is required');
|
||||||
|
}
|
||||||
|
|
||||||
let name = account?.info?.name ?? '';
|
let name = account?.info?.name ?? '';
|
||||||
if (name.includes(separator)) {
|
if (name.includes(separator)) {
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ const ActionButton = ({ detail, recurring }: PlanCardProps) => {
|
|||||||
// if contact => 'Contact Sales'
|
// if contact => 'Contact Sales'
|
||||||
// if not signed in:
|
// if not signed in:
|
||||||
// if free => 'Sign up free'
|
// if free => 'Sign up free'
|
||||||
|
// if team => 'Upgrade'
|
||||||
// else => 'Buy Pro'
|
// else => 'Buy Pro'
|
||||||
// else
|
// else
|
||||||
// if team => 'Start 14-day free trial'
|
// if team => 'Start 14-day free trial'
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { useWorkspaceInfo } from '@affine/core/components/hooks/use-workspace-info';
|
import { useWorkspaceInfo } from '@affine/core/components/hooks/use-workspace-info';
|
||||||
|
import { ServerService } from '@affine/core/modules/cloud';
|
||||||
import type { SettingTab } from '@affine/core/modules/dialogs/constant';
|
import type { SettingTab } from '@affine/core/modules/dialogs/constant';
|
||||||
import { WorkspaceService } from '@affine/core/modules/workspace';
|
import { WorkspaceService } from '@affine/core/modules/workspace';
|
||||||
|
import { ServerDeploymentType } from '@affine/graphql';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import {
|
import {
|
||||||
CollaborationIcon,
|
CollaborationIcon,
|
||||||
@@ -9,11 +11,12 @@ import {
|
|||||||
SaveIcon,
|
SaveIcon,
|
||||||
SettingsIcon,
|
SettingsIcon,
|
||||||
} from '@blocksuite/icons/rc';
|
} from '@blocksuite/icons/rc';
|
||||||
import { useService } from '@toeverything/infra';
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import type { SettingSidebarItem, SettingState } from '../types';
|
import type { SettingSidebarItem, SettingState } from '../types';
|
||||||
import { WorkspaceSettingBilling } from './billing';
|
import { WorkspaceSettingBilling } from './billing';
|
||||||
|
import { WorkspaceSettingLicense } from './license';
|
||||||
import { MembersPanel } from './members';
|
import { MembersPanel } from './members';
|
||||||
import { WorkspaceSettingDetail } from './preference';
|
import { WorkspaceSettingDetail } from './preference';
|
||||||
import { WorkspaceSettingProperties } from './properties';
|
import { WorkspaceSettingProperties } from './properties';
|
||||||
@@ -44,6 +47,8 @@ export const WorkspaceSetting = ({
|
|||||||
return <WorkspaceSettingBilling />;
|
return <WorkspaceSettingBilling />;
|
||||||
case 'workspace:storage':
|
case 'workspace:storage':
|
||||||
return <WorkspaceSettingStorage onCloseSetting={onCloseSetting} />;
|
return <WorkspaceSettingStorage onCloseSetting={onCloseSetting} />;
|
||||||
|
case 'workspace:license':
|
||||||
|
return <WorkspaceSettingLicense onCloseSetting={onCloseSetting} />;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -52,10 +57,19 @@ export const WorkspaceSetting = ({
|
|||||||
export const useWorkspaceSettingList = (): SettingSidebarItem[] => {
|
export const useWorkspaceSettingList = (): SettingSidebarItem[] => {
|
||||||
const workspaceService = useService(WorkspaceService);
|
const workspaceService = useService(WorkspaceService);
|
||||||
const information = useWorkspaceInfo(workspaceService.workspace);
|
const information = useWorkspaceInfo(workspaceService.workspace);
|
||||||
|
const serverService = useService(ServerService);
|
||||||
|
|
||||||
|
const isSelfhosted = useLiveData(
|
||||||
|
serverService.server.config$.selector(
|
||||||
|
c => c.type === ServerDeploymentType.Selfhosted
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
const showBilling = information?.isTeam && information?.isOwner;
|
const showBilling =
|
||||||
|
!isSelfhosted && information?.isTeam && information?.isOwner;
|
||||||
|
const showLicense = information?.isOwner && isSelfhosted;
|
||||||
const items = useMemo<SettingSidebarItem[]>(() => {
|
const items = useMemo<SettingSidebarItem[]>(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@@ -88,10 +102,14 @@ export const useWorkspaceSettingList = (): SettingSidebarItem[] => {
|
|||||||
icon: <PaymentIcon />,
|
icon: <PaymentIcon />,
|
||||||
testId: 'workspace-setting:billing',
|
testId: 'workspace-setting:billing',
|
||||||
},
|
},
|
||||||
|
showLicense && {
|
||||||
// todo(@pengx17): add selfhost's team license
|
key: 'workspace:license' as SettingTab,
|
||||||
|
title: t['com.affine.settings.workspace.license'](),
|
||||||
|
icon: <PaymentIcon />,
|
||||||
|
testId: 'workspace-setting:license',
|
||||||
|
},
|
||||||
].filter((item): item is SettingSidebarItem => !!item);
|
].filter((item): item is SettingSidebarItem => !!item);
|
||||||
}, [showBilling, t]);
|
}, [showBilling, showLicense, t]);
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
import { Button } from '@affine/component';
|
||||||
|
import {
|
||||||
|
SettingHeader,
|
||||||
|
SettingRow,
|
||||||
|
} from '@affine/component/setting-components';
|
||||||
|
import { getUpgradeQuestionnaireLink } from '@affine/core/components/hooks/affine/use-subscription-notify';
|
||||||
|
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
|
||||||
|
import { useMutation } from '@affine/core/components/hooks/use-mutation';
|
||||||
|
import {
|
||||||
|
AuthService,
|
||||||
|
WorkspaceSubscriptionService,
|
||||||
|
} from '@affine/core/modules/cloud';
|
||||||
|
import { WorkspacePermissionService } from '@affine/core/modules/permissions';
|
||||||
|
import { UrlService } from '@affine/core/modules/url';
|
||||||
|
import { WorkspaceService } from '@affine/core/modules/workspace';
|
||||||
|
import {
|
||||||
|
createSelfhostCustomerPortalMutation,
|
||||||
|
SubscriptionPlan,
|
||||||
|
SubscriptionRecurring,
|
||||||
|
} from '@affine/graphql';
|
||||||
|
import { useI18n } from '@affine/i18n';
|
||||||
|
import { FrameworkScope, useLiveData, useService } from '@toeverything/infra';
|
||||||
|
|
||||||
|
import { EnableCloudPanel } from '../preference/enable-cloud';
|
||||||
|
import { SelfHostTeamCard } from './self-host-team-card';
|
||||||
|
import { SelfHostTeamPlan } from './self-host-team-plan';
|
||||||
|
import * as styles from './styles.css';
|
||||||
|
|
||||||
|
export const WorkspaceSettingLicense = ({
|
||||||
|
onCloseSetting,
|
||||||
|
}: {
|
||||||
|
onCloseSetting: () => void;
|
||||||
|
}) => {
|
||||||
|
const workspace = useService(WorkspaceService).workspace;
|
||||||
|
|
||||||
|
const t = useI18n();
|
||||||
|
|
||||||
|
if (workspace === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FrameworkScope scope={workspace.scope}>
|
||||||
|
<SettingHeader
|
||||||
|
title={t['com.affine.settings.workspace.license']()}
|
||||||
|
subtitle={t['com.affine.settings.workspace.license.description']()}
|
||||||
|
/>
|
||||||
|
<SelfHostTeamPlan />
|
||||||
|
{workspace.flavour === 'local' ? (
|
||||||
|
<EnableCloudPanel onCloseSetting={onCloseSetting} />
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<SelfHostTeamCard />
|
||||||
|
<TypeFormLink />
|
||||||
|
<PaymentMethodUpdater />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</FrameworkScope>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const TypeFormLink = () => {
|
||||||
|
const t = useI18n();
|
||||||
|
const workspaceSubscriptionService = useService(WorkspaceSubscriptionService);
|
||||||
|
const authService = useService(AuthService);
|
||||||
|
|
||||||
|
const workspaceSubscription = useLiveData(
|
||||||
|
workspaceSubscriptionService.subscription.subscription$
|
||||||
|
);
|
||||||
|
const account = useLiveData(authService.session.account$);
|
||||||
|
|
||||||
|
if (!account) return null;
|
||||||
|
|
||||||
|
const link = getUpgradeQuestionnaireLink({
|
||||||
|
name: account.info?.name,
|
||||||
|
id: account.id,
|
||||||
|
email: account.email,
|
||||||
|
recurring: workspaceSubscription?.recurring ?? SubscriptionRecurring.Yearly,
|
||||||
|
plan: SubscriptionPlan.SelfHostedTeam,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingRow
|
||||||
|
className={styles.paymentMethod}
|
||||||
|
name={t['com.affine.payment.billing-type-form.title']()}
|
||||||
|
desc={t['com.affine.payment.billing-type-form.description']()}
|
||||||
|
>
|
||||||
|
<a target="_blank" href={link} rel="noreferrer">
|
||||||
|
<Button>{t['com.affine.payment.billing-type-form.go']()}</Button>
|
||||||
|
</a>
|
||||||
|
</SettingRow>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const PaymentMethodUpdater = () => {
|
||||||
|
const workspace = useService(WorkspaceService).workspace;
|
||||||
|
|
||||||
|
const permission = useService(WorkspacePermissionService).permission;
|
||||||
|
const isTeam = useLiveData(permission.isTeam$);
|
||||||
|
|
||||||
|
const { isMutating, trigger } = useMutation({
|
||||||
|
mutation: createSelfhostCustomerPortalMutation,
|
||||||
|
});
|
||||||
|
const urlService = useService(UrlService);
|
||||||
|
const t = useI18n();
|
||||||
|
|
||||||
|
const update = useAsyncCallback(async () => {
|
||||||
|
await trigger(
|
||||||
|
{
|
||||||
|
workspaceId: workspace.id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onSuccess: data => {
|
||||||
|
urlService.openPopupWindow(
|
||||||
|
data.createSelfhostWorkspaceCustomerPortal
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}, [trigger, urlService, workspace.id]);
|
||||||
|
|
||||||
|
if (!isTeam) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingRow
|
||||||
|
className={styles.paymentMethod}
|
||||||
|
name={t['com.affine.payment.billing-setting.payment-method']()}
|
||||||
|
desc={t[
|
||||||
|
'com.affine.payment.billing-setting.payment-method.description'
|
||||||
|
]()}
|
||||||
|
>
|
||||||
|
<Button onClick={update} loading={isMutating} disabled={isMutating}>
|
||||||
|
{t['com.affine.payment.billing-setting.payment-method.go']()}
|
||||||
|
</Button>
|
||||||
|
</SettingRow>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,280 @@
|
|||||||
|
import { Button, ConfirmModal, Input, notify } from '@affine/component';
|
||||||
|
import { SettingRow } from '@affine/component/setting-components';
|
||||||
|
import { useEnableCloud } from '@affine/core/components/hooks/affine/use-enable-cloud';
|
||||||
|
import {
|
||||||
|
SelfhostLicenseService,
|
||||||
|
WorkspaceSubscriptionService,
|
||||||
|
} from '@affine/core/modules/cloud';
|
||||||
|
import { WorkspacePermissionService } from '@affine/core/modules/permissions';
|
||||||
|
import { WorkspaceQuotaService } from '@affine/core/modules/quota';
|
||||||
|
import { WorkspaceService } from '@affine/core/modules/workspace';
|
||||||
|
import { UserFriendlyError } from '@affine/graphql';
|
||||||
|
import { Trans, useI18n } from '@affine/i18n';
|
||||||
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
|
import * as styles from './styles.css';
|
||||||
|
|
||||||
|
export const SelfHostTeamCard = () => {
|
||||||
|
const t = useI18n();
|
||||||
|
|
||||||
|
const workspace = useService(WorkspaceService).workspace;
|
||||||
|
const workspaceQuotaService = useService(WorkspaceQuotaService);
|
||||||
|
const workspaceSubscriptionService = useService(WorkspaceSubscriptionService);
|
||||||
|
|
||||||
|
const permission = useService(WorkspacePermissionService).permission;
|
||||||
|
const isTeam = useLiveData(permission.isTeam$);
|
||||||
|
const workspaceQuota = useLiveData(workspaceQuotaService.quota.quota$);
|
||||||
|
const confirmEnableCloud = useEnableCloud();
|
||||||
|
const isLocalWorkspace = workspace.flavour === 'local';
|
||||||
|
|
||||||
|
const [openModal, setOpenModal] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const selfhostLicenseService = useService(SelfhostLicenseService);
|
||||||
|
const license = useLiveData(selfhostLicenseService.license$);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
permission.revalidate();
|
||||||
|
workspaceQuotaService.quota.revalidate();
|
||||||
|
workspaceSubscriptionService.subscription.revalidate();
|
||||||
|
selfhostLicenseService.revalidate();
|
||||||
|
}, [
|
||||||
|
permission,
|
||||||
|
selfhostLicenseService,
|
||||||
|
workspaceQuotaService,
|
||||||
|
workspaceSubscriptionService,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const description = useMemo(() => {
|
||||||
|
if (isTeam) {
|
||||||
|
return t[
|
||||||
|
'com.affine.settings.workspace.license.self-host-team.team.description'
|
||||||
|
]({
|
||||||
|
expirationDate: new Date(license?.expiredAt || 0).toLocaleDateString(),
|
||||||
|
leftDays: Math.floor(
|
||||||
|
(new Date(license?.expiredAt || 0).getTime() - Date.now()) /
|
||||||
|
(1000 * 60 * 60 * 24)
|
||||||
|
).toLocaleString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return t[
|
||||||
|
'com.affine.settings.workspace.license.self-host-team.free.description'
|
||||||
|
]({
|
||||||
|
memberCount: workspaceQuota?.humanReadable.memberLimit || '10',
|
||||||
|
});
|
||||||
|
}, [isTeam, license, t, workspaceQuota]);
|
||||||
|
const handleClick = useCallback(() => {
|
||||||
|
if (isLocalWorkspace) {
|
||||||
|
confirmEnableCloud(workspace);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setOpenModal(true);
|
||||||
|
}, [confirmEnableCloud, isLocalWorkspace, workspace]);
|
||||||
|
|
||||||
|
const onActivate = useCallback(
|
||||||
|
(license: string) => {
|
||||||
|
setLoading(true);
|
||||||
|
selfhostLicenseService
|
||||||
|
.activateLicense(workspace.id, license)
|
||||||
|
.then(() => {
|
||||||
|
setLoading(false);
|
||||||
|
setOpenModal(false);
|
||||||
|
permission.revalidate();
|
||||||
|
selfhostLicenseService.revalidate();
|
||||||
|
notify.success({
|
||||||
|
title:
|
||||||
|
t['com.affine.settings.workspace.license.activate-success'](),
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
setLoading(false);
|
||||||
|
|
||||||
|
console.error(e);
|
||||||
|
const error = UserFriendlyError.fromAnyError(e);
|
||||||
|
|
||||||
|
notify.error({
|
||||||
|
title: error.name,
|
||||||
|
message: error.message,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[permission, selfhostLicenseService, t, workspace.id]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onDeactivate = useCallback(() => {
|
||||||
|
setLoading(true);
|
||||||
|
selfhostLicenseService
|
||||||
|
.deactivateLicense(workspace.id)
|
||||||
|
.then(() => {
|
||||||
|
setLoading(false);
|
||||||
|
setOpenModal(false);
|
||||||
|
permission.revalidate();
|
||||||
|
notify.success({
|
||||||
|
title:
|
||||||
|
t['com.affine.settings.workspace.license.deactivate-success'](),
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
setLoading(false);
|
||||||
|
|
||||||
|
console.error(e);
|
||||||
|
const error = UserFriendlyError.fromAnyError(e);
|
||||||
|
|
||||||
|
notify.error({
|
||||||
|
title: error.name,
|
||||||
|
message: error.message,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, [permission, selfhostLicenseService, t, workspace.id]);
|
||||||
|
|
||||||
|
const handleConfirm = useCallback(
|
||||||
|
(license: string) => {
|
||||||
|
if (isTeam) {
|
||||||
|
onDeactivate();
|
||||||
|
} else {
|
||||||
|
onActivate(license);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[isTeam, onActivate, onDeactivate]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={styles.planCard}>
|
||||||
|
<div className={styles.container}>
|
||||||
|
<div className={styles.currentPlan}>
|
||||||
|
<SettingRow
|
||||||
|
spreadCol={false}
|
||||||
|
name={t[
|
||||||
|
`com.affine.settings.workspace.license.self-host${isTeam ? '-team' : ''}`
|
||||||
|
]()}
|
||||||
|
desc={description}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={clsx(styles.planPrice, {
|
||||||
|
hidden: isLocalWorkspace,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<span className={styles.seat}>
|
||||||
|
{t[
|
||||||
|
'com.affine.settings.workspace.license.self-host-team.seats'
|
||||||
|
]()}
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
{workspaceQuota?.memberCount}
|
||||||
|
{isTeam ? '' : `/${workspaceQuota?.memberLimit}`}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={clsx(styles.buttonContainer, {
|
||||||
|
left: isTeam || isLocalWorkspace,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
className={styles.activeButton}
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
{t[
|
||||||
|
`com.affine.settings.workspace.license.self-host-team.${isTeam ? 'deactivate-license' : 'active-key'}`
|
||||||
|
]()}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ActionModal
|
||||||
|
open={openModal}
|
||||||
|
onOpenChange={setOpenModal}
|
||||||
|
isTeam={!!isTeam}
|
||||||
|
loading={loading}
|
||||||
|
onConfirm={handleConfirm}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ActionModal = ({
|
||||||
|
open,
|
||||||
|
onOpenChange,
|
||||||
|
isTeam,
|
||||||
|
onConfirm,
|
||||||
|
loading,
|
||||||
|
}: {
|
||||||
|
open: boolean;
|
||||||
|
onOpenChange: (open: boolean) => void;
|
||||||
|
isTeam: boolean;
|
||||||
|
loading: boolean;
|
||||||
|
onConfirm: (key: string) => void;
|
||||||
|
}) => {
|
||||||
|
const t = useI18n();
|
||||||
|
const [key, setKey] = useState('');
|
||||||
|
|
||||||
|
const handleConfirm = useCallback(() => {
|
||||||
|
onConfirm(key);
|
||||||
|
setKey('');
|
||||||
|
}, [key, onConfirm]);
|
||||||
|
|
||||||
|
const handleOpenChange = useCallback(
|
||||||
|
(open: boolean) => {
|
||||||
|
setKey('');
|
||||||
|
onOpenChange(open);
|
||||||
|
},
|
||||||
|
[onOpenChange]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfirmModal
|
||||||
|
width={480}
|
||||||
|
open={open}
|
||||||
|
onOpenChange={handleOpenChange}
|
||||||
|
title={t[
|
||||||
|
`com.affine.settings.workspace.license.${isTeam ? 'deactivate' : 'activate'}-modal.title`
|
||||||
|
]()}
|
||||||
|
description={t[
|
||||||
|
`com.affine.settings.workspace.license.${isTeam ? 'deactivate' : 'activate'}-modal.description`
|
||||||
|
]()}
|
||||||
|
cancelText={t['Cancel']()}
|
||||||
|
cancelButtonOptions={{
|
||||||
|
variant: 'secondary',
|
||||||
|
}}
|
||||||
|
contentOptions={{
|
||||||
|
['data-testid' as string]: 'invite-modal',
|
||||||
|
style: {
|
||||||
|
padding: '20px 24px',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
confirmText={t['Confirm']()}
|
||||||
|
confirmButtonOptions={{
|
||||||
|
loading: loading,
|
||||||
|
variant: isTeam ? 'error' : 'primary',
|
||||||
|
disabled: loading || (!isTeam && !key),
|
||||||
|
}}
|
||||||
|
onConfirm={handleConfirm}
|
||||||
|
childrenContentClassName={styles.activateModalContent}
|
||||||
|
>
|
||||||
|
{isTeam ? null : (
|
||||||
|
<>
|
||||||
|
<Input
|
||||||
|
value={key}
|
||||||
|
onChange={setKey}
|
||||||
|
placeholder="AAAA-AAAA-AAAA-AAAA-AAAA"
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
<Trans i18nKey="com.affine.settings.workspace.license.activate-modal.tips">
|
||||||
|
If you encounter any issues, please contact our
|
||||||
|
<a
|
||||||
|
href="mailto:support@toeverything.info"
|
||||||
|
style={{ color: 'var(--affine-link-color)' }}
|
||||||
|
>
|
||||||
|
customer support
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</Trans>
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</ConfirmModal>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import { cssVar } from '@toeverything/theme';
|
||||||
|
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||||
|
import { style } from '@vanilla-extract/css';
|
||||||
|
|
||||||
|
export const pricingPlan = style({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
padding: '12px',
|
||||||
|
border: `1px solid ${cssVarV2('layer/insideBorder/border')}`,
|
||||||
|
backgroundColor: cssVarV2('layer/white'),
|
||||||
|
borderRadius: '8px',
|
||||||
|
gap: '18px',
|
||||||
|
marginBottom: '24px',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const planCardHeader = style({
|
||||||
|
display: 'flex',
|
||||||
|
padding: '0px 6px',
|
||||||
|
gap: '4px',
|
||||||
|
flexDirection: 'column',
|
||||||
|
fontSize: cssVar('fontBase'),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const planCardTitle = style({
|
||||||
|
fontWeight: 600,
|
||||||
|
lineHeight: '24px',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const planCardSubtitle = style({
|
||||||
|
color: cssVarV2('text/secondary'),
|
||||||
|
fontWeight: 400,
|
||||||
|
lineHeight: '24px',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const benefitItems = style({
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: '1fr 1fr',
|
||||||
|
gap: '12px',
|
||||||
|
gridAutoRows: 'min-content',
|
||||||
|
'@media': {
|
||||||
|
'screen and (max-width: 768px)': {
|
||||||
|
gridTemplateColumns: '1fr',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const benefitItem = style({
|
||||||
|
display: 'flex',
|
||||||
|
gap: '8px',
|
||||||
|
fontSize: cssVar('fontXs'),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const doneIconStyle = style({
|
||||||
|
color: cssVarV2('button/primary'),
|
||||||
|
width: '20px',
|
||||||
|
height: '20px',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const leanMoreButtonContainer = style({
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
});
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import { Button } from '@affine/component';
|
||||||
|
import { WorkspacePermissionService } from '@affine/core/modules/permissions';
|
||||||
|
import { useI18n } from '@affine/i18n';
|
||||||
|
import { DoneIcon } from '@blocksuite/icons/rc';
|
||||||
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import * as styles from './self-host-team-plan.css';
|
||||||
|
|
||||||
|
const initialQuota = '100 GB';
|
||||||
|
const quotaPerSeat = '20 GB';
|
||||||
|
const maxFileSize = '500 MB';
|
||||||
|
|
||||||
|
export const SelfHostTeamPlan = () => {
|
||||||
|
const t = useI18n();
|
||||||
|
|
||||||
|
const permission = useService(WorkspacePermissionService).permission;
|
||||||
|
const isTeam = useLiveData(permission.isTeam$);
|
||||||
|
|
||||||
|
const handleClick = useCallback(() => {
|
||||||
|
window.open(BUILD_CONFIG.pricingUrl, '_blank');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (isTeam) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.pricingPlan}>
|
||||||
|
<div className={styles.planCardHeader}>
|
||||||
|
<div className={styles.planCardTitle}>
|
||||||
|
{t['com.affine.settings.workspace.license.benefit.team.title']()}
|
||||||
|
</div>
|
||||||
|
<div className={styles.planCardSubtitle}>
|
||||||
|
{t['com.affine.settings.workspace.license.benefit.team.subtitle']()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.benefitItems}>
|
||||||
|
<div className={styles.benefitItem}>
|
||||||
|
<DoneIcon className={styles.doneIconStyle} />
|
||||||
|
{t['com.affine.settings.workspace.license.benefit.team.g1']()}
|
||||||
|
</div>
|
||||||
|
<div className={styles.benefitItem}>
|
||||||
|
<DoneIcon className={styles.doneIconStyle} />
|
||||||
|
{t['com.affine.settings.workspace.license.benefit.team.g2']({
|
||||||
|
initialQuota,
|
||||||
|
quotaPerSeat,
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div className={styles.benefitItem}>
|
||||||
|
<DoneIcon className={styles.doneIconStyle} />
|
||||||
|
{t['com.affine.settings.workspace.license.benefit.team.g3']({
|
||||||
|
quota: maxFileSize,
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div className={styles.benefitItem}>
|
||||||
|
<DoneIcon className={styles.doneIconStyle} />
|
||||||
|
{t['com.affine.settings.workspace.license.benefit.team.g4']()}
|
||||||
|
</div>
|
||||||
|
<div className={styles.benefitItem}>
|
||||||
|
<DoneIcon className={styles.doneIconStyle} />
|
||||||
|
{t['com.affine.settings.workspace.license.benefit.team.g5']()}
|
||||||
|
</div>
|
||||||
|
<div className={styles.benefitItem}>
|
||||||
|
<DoneIcon className={styles.doneIconStyle} />
|
||||||
|
{t['com.affine.settings.workspace.license.benefit.team.g6']()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.leanMoreButtonContainer}>
|
||||||
|
<Button onClick={handleClick}>
|
||||||
|
{t['com.affine.settings.workspace.license.lean-more']()}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import { cssVar } from '@toeverything/theme';
|
||||||
|
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||||
|
import { style } from '@vanilla-extract/css';
|
||||||
|
|
||||||
|
export const paymentMethod = style({
|
||||||
|
marginTop: '24px',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const planCard = style({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
padding: '12px',
|
||||||
|
border: `1px solid ${cssVarV2('layer/insideBorder/border')}`,
|
||||||
|
backgroundColor: cssVarV2('layer/white'),
|
||||||
|
borderRadius: '8px',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const container = style({
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const currentPlan = style({
|
||||||
|
flex: '1 0 0',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const planPrice = style({
|
||||||
|
fontSize: cssVar('fontH6'),
|
||||||
|
fontWeight: 600,
|
||||||
|
display: 'flex',
|
||||||
|
gap: '4px',
|
||||||
|
margin: '0px 4px',
|
||||||
|
justifyContent: 'center',
|
||||||
|
height: '100%',
|
||||||
|
alignItems: 'center',
|
||||||
|
selectors: {
|
||||||
|
'&.hidden': {
|
||||||
|
visibility: 'hidden',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const buttonContainer = style({
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
marginTop: '12px',
|
||||||
|
selectors: {
|
||||||
|
'&.left': {
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
export const activeButton = style({
|
||||||
|
marginTop: '8px',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const seat = style({
|
||||||
|
fontSize: cssVar('fontXs'),
|
||||||
|
fontWeight: 400,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const activateModalContent = style({
|
||||||
|
padding: '0',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '12px',
|
||||||
|
marginTop: '12px',
|
||||||
|
marginBottom: '20px',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const tips = style({
|
||||||
|
color: cssVarV2('text/secondary'),
|
||||||
|
fontSize: cssVar('fontSm'),
|
||||||
|
});
|
||||||
@@ -260,7 +260,7 @@ const getMemberStatus = (member: Member): I18nString => {
|
|||||||
return 'Workspace Owner';
|
return 'Workspace Owner';
|
||||||
case Permission.Admin:
|
case Permission.Admin:
|
||||||
return 'Admin';
|
return 'Admin';
|
||||||
case Permission.Write:
|
case Permission.Collaborator:
|
||||||
return 'Collaborator';
|
return 'Collaborator';
|
||||||
default:
|
default:
|
||||||
return 'Member';
|
return 'Member';
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ export const MemberOptions = ({
|
|||||||
}, [member, membersService, t]);
|
}, [member, membersService, t]);
|
||||||
const handleChangeToCollaborator = useCallback(() => {
|
const handleChangeToCollaborator = useCallback(() => {
|
||||||
membersService
|
membersService
|
||||||
.adjustMemberPermission(member.id, Permission.Write)
|
.adjustMemberPermission(member.id, Permission.Collaborator)
|
||||||
.then(result => {
|
.then(result => {
|
||||||
if (result) {
|
if (result) {
|
||||||
notify.success({
|
notify.success({
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ const products = {
|
|||||||
believer: 'pro_lifetime',
|
believer: 'pro_lifetime',
|
||||||
team: 'team_yearly',
|
team: 'team_yearly',
|
||||||
'monthly-team': 'team_monthly',
|
'monthly-team': 'team_monthly',
|
||||||
|
'yearly-selfhost-team': 'selfhost-team_yearly',
|
||||||
|
'monthly-selfhost-team': 'selfhost-team_monthly',
|
||||||
'oneyear-ai': 'ai_yearly_onetime',
|
'oneyear-ai': 'ai_yearly_onetime',
|
||||||
'oneyear-pro': 'pro_yearly_onetime',
|
'oneyear-pro': 'pro_yearly_onetime',
|
||||||
'onemonth-pro': 'pro_monthly_onetime',
|
'onemonth-pro': 'pro_monthly_onetime',
|
||||||
@@ -45,6 +47,7 @@ const allowedPlan = {
|
|||||||
ai: SubscriptionPlan.AI,
|
ai: SubscriptionPlan.AI,
|
||||||
pro: SubscriptionPlan.Pro,
|
pro: SubscriptionPlan.Pro,
|
||||||
team: SubscriptionPlan.Team,
|
team: SubscriptionPlan.Team,
|
||||||
|
'selfhost-team': SubscriptionPlan.SelfHostedTeam,
|
||||||
};
|
};
|
||||||
const allowedRecurring = {
|
const allowedRecurring = {
|
||||||
monthly: SubscriptionRecurring.Monthly,
|
monthly: SubscriptionRecurring.Monthly,
|
||||||
|
|||||||
@@ -0,0 +1,124 @@
|
|||||||
|
import { Button, IconButton, Loading, notify } from '@affine/component';
|
||||||
|
import { AuthPageContainer } from '@affine/component/auth-components';
|
||||||
|
import { SelfhostGenerateLicenseService } from '@affine/core/modules/cloud';
|
||||||
|
import { OpenInAppService } from '@affine/core/modules/open-in-app';
|
||||||
|
import { copyTextToClipboard } from '@affine/core/utils/clipboard';
|
||||||
|
import { Trans, useI18n } from '@affine/i18n';
|
||||||
|
import { CopyIcon } from '@blocksuite/icons/rc';
|
||||||
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
|
import { useCallback, useEffect } from 'react';
|
||||||
|
import { useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { PageNotFound } from '../../404';
|
||||||
|
import * as styles from './styles.css';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* /upgrade-success/self-hosted-team page
|
||||||
|
*
|
||||||
|
* only on web
|
||||||
|
*/
|
||||||
|
export const Component = () => {
|
||||||
|
const [params] = useSearchParams();
|
||||||
|
const sessionId = params.get('session_id');
|
||||||
|
const selfhostGenerateLicenseService = useService(
|
||||||
|
SelfhostGenerateLicenseService
|
||||||
|
);
|
||||||
|
const isMutating = useLiveData(selfhostGenerateLicenseService.isLoading$);
|
||||||
|
const key = useLiveData(selfhostGenerateLicenseService.licenseKey$);
|
||||||
|
const error = useLiveData(selfhostGenerateLicenseService.error$);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isMutating || error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sessionId && !key) {
|
||||||
|
selfhostGenerateLicenseService.generateLicenseKey(sessionId);
|
||||||
|
}
|
||||||
|
}, [error, isMutating, key, selfhostGenerateLicenseService, sessionId]);
|
||||||
|
|
||||||
|
if (!sessionId) {
|
||||||
|
return <PageNotFound noPermission />;
|
||||||
|
}
|
||||||
|
if (isMutating || key) {
|
||||||
|
return <Success licenseKey={key} />;
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<AuthPageContainer
|
||||||
|
title={'failed to generate license key'}
|
||||||
|
subtitle={error?.message}
|
||||||
|
></AuthPageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Success = ({ licenseKey }: { licenseKey: string | null }) => {
|
||||||
|
const t = useI18n();
|
||||||
|
const openInAppService = useService(OpenInAppService);
|
||||||
|
|
||||||
|
const openAFFiNE = useCallback(() => {
|
||||||
|
openInAppService.showOpenInAppPage();
|
||||||
|
}, [openInAppService]);
|
||||||
|
|
||||||
|
const onCopy = useCallback(() => {
|
||||||
|
if (!licenseKey) {
|
||||||
|
notify.error({ title: 'Copy failed, please try again later' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
copyTextToClipboard(licenseKey)
|
||||||
|
.then(success => {
|
||||||
|
if (success) {
|
||||||
|
notify.success({
|
||||||
|
title: t['com.affine.payment.license-success.copy'](),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
notify.error({ title: 'Copy failed, please try again later' });
|
||||||
|
});
|
||||||
|
}, [licenseKey, t]);
|
||||||
|
|
||||||
|
const subtitle = (
|
||||||
|
<span className={styles.leftContentText}>
|
||||||
|
<span>{t['com.affine.payment.license-success.text-1']()}</span>
|
||||||
|
<span>
|
||||||
|
<Trans
|
||||||
|
i18nKey={'com.affine.payment.license-success.text-2'}
|
||||||
|
components={{
|
||||||
|
1: (
|
||||||
|
<a
|
||||||
|
href="mailto:support@toeverything.info"
|
||||||
|
className={styles.mail}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<AuthPageContainer
|
||||||
|
title={t['com.affine.payment.license-success.title']()}
|
||||||
|
subtitle={subtitle}
|
||||||
|
>
|
||||||
|
<div className={styles.content}>
|
||||||
|
<div className={styles.licenseKeyContainer}>
|
||||||
|
{licenseKey ? licenseKey : <Loading />}
|
||||||
|
<IconButton
|
||||||
|
icon={<CopyIcon />}
|
||||||
|
className={styles.icon}
|
||||||
|
size="20"
|
||||||
|
tooltip={t['Copy']()}
|
||||||
|
onClick={onCopy}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>{t['com.affine.payment.license-success.hint']()}</div>
|
||||||
|
<div>
|
||||||
|
<Button variant="primary" size="extraLarge" onClick={openAFFiNE}>
|
||||||
|
{t['com.affine.payment.license-success.open-affine']()}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AuthPageContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { cssVar } from '@toeverything/theme';
|
||||||
|
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||||
|
import { style } from '@vanilla-extract/css';
|
||||||
|
export const leftContentText = style({
|
||||||
|
fontSize: cssVar('fontBase'),
|
||||||
|
fontWeight: 400,
|
||||||
|
lineHeight: '1.6',
|
||||||
|
maxWidth: '548px',
|
||||||
|
});
|
||||||
|
export const mail = style({
|
||||||
|
color: cssVar('linkColor'),
|
||||||
|
textDecoration: 'none',
|
||||||
|
':visited': {
|
||||||
|
color: cssVar('linkColor'),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
export const content = style({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '28px',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const licenseKeyContainer = style({
|
||||||
|
width: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: cssVarV2('layer/background/secondary'),
|
||||||
|
borderRadius: '4px',
|
||||||
|
border: `1px solid ${cssVarV2('layer/insideBorder/blackBorder')}`,
|
||||||
|
padding: '8px 10px',
|
||||||
|
gap: '8px',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const icon = style({
|
||||||
|
color: cssVarV2('icon/primary'),
|
||||||
|
});
|
||||||
@@ -68,6 +68,10 @@ export const topLevelRoutes = [
|
|||||||
path: '/upgrade-success/team',
|
path: '/upgrade-success/team',
|
||||||
lazy: () => import('./pages/upgrade-success/team'),
|
lazy: () => import('./pages/upgrade-success/team'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/upgrade-success/self-hosted-team',
|
||||||
|
lazy: () => import('./pages/upgrade-success/self-host-team'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/ai-upgrade-success',
|
path: '/ai-upgrade-success',
|
||||||
lazy: () => import('./pages/ai-upgrade-success'),
|
lazy: () => import('./pages/ai-upgrade-success'),
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ export { EventSourceService } from './services/eventsource';
|
|||||||
export { FetchService } from './services/fetch';
|
export { FetchService } from './services/fetch';
|
||||||
export { GraphQLService } from './services/graphql';
|
export { GraphQLService } from './services/graphql';
|
||||||
export { InvoicesService } from './services/invoices';
|
export { InvoicesService } from './services/invoices';
|
||||||
|
export { SelfhostGenerateLicenseService } from './services/selfhost-generate-license';
|
||||||
|
export { SelfhostLicenseService } from './services/selfhost-license';
|
||||||
export { ServerService } from './services/server';
|
export { ServerService } from './services/server';
|
||||||
export { ServersService } from './services/servers';
|
export { ServersService } from './services/servers';
|
||||||
export { SubscriptionService } from './services/subscription';
|
export { SubscriptionService } from './services/subscription';
|
||||||
@@ -58,6 +60,8 @@ import { EventSourceService } from './services/eventsource';
|
|||||||
import { FetchService } from './services/fetch';
|
import { FetchService } from './services/fetch';
|
||||||
import { GraphQLService } from './services/graphql';
|
import { GraphQLService } from './services/graphql';
|
||||||
import { InvoicesService } from './services/invoices';
|
import { InvoicesService } from './services/invoices';
|
||||||
|
import { SelfhostGenerateLicenseService } from './services/selfhost-generate-license';
|
||||||
|
import { SelfhostLicenseService } from './services/selfhost-license';
|
||||||
import { ServerService } from './services/server';
|
import { ServerService } from './services/server';
|
||||||
import { ServersService } from './services/servers';
|
import { ServersService } from './services/servers';
|
||||||
import { SubscriptionService } from './services/subscription';
|
import { SubscriptionService } from './services/subscription';
|
||||||
@@ -70,6 +74,8 @@ import { WorkspaceSubscriptionService } from './services/workspace-subscription'
|
|||||||
import { AuthStore } from './stores/auth';
|
import { AuthStore } from './stores/auth';
|
||||||
import { CloudDocMetaStore } from './stores/cloud-doc-meta';
|
import { CloudDocMetaStore } from './stores/cloud-doc-meta';
|
||||||
import { InvoicesStore } from './stores/invoices';
|
import { InvoicesStore } from './stores/invoices';
|
||||||
|
import { SelfhostGenerateLicenseStore } from './stores/selfhost-generate-license';
|
||||||
|
import { SelfhostLicenseStore } from './stores/selfhost-license';
|
||||||
import { ServerConfigStore } from './stores/server-config';
|
import { ServerConfigStore } from './stores/server-config';
|
||||||
import { ServerListStore } from './stores/server-list';
|
import { ServerListStore } from './stores/server-list';
|
||||||
import { SubscriptionStore } from './stores/subscription';
|
import { SubscriptionStore } from './stores/subscription';
|
||||||
@@ -128,7 +134,9 @@ export function configureCloudModule(framework: Framework) {
|
|||||||
.store(UserFeatureStore, [GraphQLService])
|
.store(UserFeatureStore, [GraphQLService])
|
||||||
.service(InvoicesService)
|
.service(InvoicesService)
|
||||||
.store(InvoicesStore, [GraphQLService])
|
.store(InvoicesStore, [GraphQLService])
|
||||||
.entity(Invoices, [InvoicesStore]);
|
.entity(Invoices, [InvoicesStore])
|
||||||
|
.service(SelfhostGenerateLicenseService, [SelfhostGenerateLicenseStore])
|
||||||
|
.store(SelfhostGenerateLicenseStore, [GraphQLService]);
|
||||||
|
|
||||||
framework
|
framework
|
||||||
.scope(WorkspaceScope)
|
.scope(WorkspaceScope)
|
||||||
@@ -142,5 +150,7 @@ export function configureCloudModule(framework: Framework) {
|
|||||||
.service(WorkspaceSubscriptionService, [WorkspaceServerService])
|
.service(WorkspaceSubscriptionService, [WorkspaceServerService])
|
||||||
.entity(WorkspaceSubscription, [WorkspaceService, WorkspaceServerService])
|
.entity(WorkspaceSubscription, [WorkspaceService, WorkspaceServerService])
|
||||||
.service(WorkspaceInvoicesService)
|
.service(WorkspaceInvoicesService)
|
||||||
.entity(WorkspaceInvoices, [WorkspaceService, WorkspaceServerService]);
|
.entity(WorkspaceInvoices, [WorkspaceService, WorkspaceServerService])
|
||||||
|
.service(SelfhostLicenseService, [SelfhostLicenseStore, WorkspaceService])
|
||||||
|
.store(SelfhostLicenseStore, [WorkspaceServerService]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { UserFriendlyError } from '@affine/graphql';
|
||||||
|
import {
|
||||||
|
backoffRetry,
|
||||||
|
effect,
|
||||||
|
fromPromise,
|
||||||
|
LiveData,
|
||||||
|
onComplete,
|
||||||
|
onStart,
|
||||||
|
Service,
|
||||||
|
} from '@toeverything/infra';
|
||||||
|
import { catchError, EMPTY, exhaustMap, mergeMap } from 'rxjs';
|
||||||
|
|
||||||
|
import { isBackendError, isNetworkError } from '../error';
|
||||||
|
import type { SelfhostGenerateLicenseStore } from '../stores/selfhost-generate-license';
|
||||||
|
|
||||||
|
export class SelfhostGenerateLicenseService extends Service {
|
||||||
|
constructor(private readonly store: SelfhostGenerateLicenseStore) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
licenseKey$ = new LiveData<string | null>(null);
|
||||||
|
isLoading$ = new LiveData(false);
|
||||||
|
error$ = new LiveData<UserFriendlyError | null>(null);
|
||||||
|
|
||||||
|
generateLicenseKey = effect(
|
||||||
|
exhaustMap((sessionId: string) => {
|
||||||
|
return fromPromise(async () => {
|
||||||
|
return await this.store.generateKey(sessionId);
|
||||||
|
}).pipe(
|
||||||
|
backoffRetry({
|
||||||
|
when: isNetworkError,
|
||||||
|
count: Infinity,
|
||||||
|
}),
|
||||||
|
backoffRetry({
|
||||||
|
when: isBackendError,
|
||||||
|
}),
|
||||||
|
mergeMap(key => {
|
||||||
|
this.licenseKey$.next(key);
|
||||||
|
return EMPTY;
|
||||||
|
}),
|
||||||
|
catchError(err => {
|
||||||
|
this.error$.next(UserFriendlyError.fromAnyError(err));
|
||||||
|
console.error(err);
|
||||||
|
return EMPTY;
|
||||||
|
}),
|
||||||
|
onStart(() => {
|
||||||
|
this.isLoading$.next(true);
|
||||||
|
}),
|
||||||
|
onComplete(() => {
|
||||||
|
this.isLoading$.next(false);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import type { License } from '@affine/graphql';
|
||||||
|
import {
|
||||||
|
backoffRetry,
|
||||||
|
catchErrorInto,
|
||||||
|
effect,
|
||||||
|
exhaustMapWithTrailing,
|
||||||
|
fromPromise,
|
||||||
|
LiveData,
|
||||||
|
onComplete,
|
||||||
|
onStart,
|
||||||
|
Service,
|
||||||
|
} from '@toeverything/infra';
|
||||||
|
import { EMPTY, mergeMap } from 'rxjs';
|
||||||
|
|
||||||
|
import type { WorkspaceService } from '../../workspace';
|
||||||
|
import { isBackendError, isNetworkError } from '../error';
|
||||||
|
import type { SelfhostLicenseStore } from '../stores/selfhost-license';
|
||||||
|
|
||||||
|
export class SelfhostLicenseService extends Service {
|
||||||
|
constructor(
|
||||||
|
private readonly store: SelfhostLicenseStore,
|
||||||
|
private readonly workspaceService: WorkspaceService
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
license$ = new LiveData<License | null>(null);
|
||||||
|
isRevalidating$ = new LiveData(false);
|
||||||
|
error$ = new LiveData<any | null>(null);
|
||||||
|
|
||||||
|
revalidate = effect(
|
||||||
|
exhaustMapWithTrailing(() => {
|
||||||
|
return fromPromise(async signal => {
|
||||||
|
const currentWorkspaceId = this.workspaceService.workspace.id;
|
||||||
|
if (!currentWorkspaceId) {
|
||||||
|
return undefined; // no subscription if no user
|
||||||
|
}
|
||||||
|
return await this.store.getLicense(currentWorkspaceId, signal);
|
||||||
|
}).pipe(
|
||||||
|
backoffRetry({
|
||||||
|
when: isNetworkError,
|
||||||
|
count: Infinity,
|
||||||
|
}),
|
||||||
|
backoffRetry({
|
||||||
|
when: isBackendError,
|
||||||
|
}),
|
||||||
|
mergeMap(data => {
|
||||||
|
if (data) {
|
||||||
|
this.license$.next(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EMPTY;
|
||||||
|
}),
|
||||||
|
catchErrorInto(this.error$),
|
||||||
|
onStart(() => this.isRevalidating$.next(true)),
|
||||||
|
onComplete(() => this.isRevalidating$.next(false))
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
async activateLicense(workspaceId: string, licenseKey: string) {
|
||||||
|
return await this.store.activate(workspaceId, licenseKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deactivateLicense(workspaceId: string) {
|
||||||
|
return await this.store.deactivate(workspaceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.license$.next(null);
|
||||||
|
this.error$.next(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { generateLicenseKeyMutation } from '@affine/graphql';
|
||||||
|
import { Store } from '@toeverything/infra';
|
||||||
|
|
||||||
|
import type { GraphQLService } from '../services/graphql';
|
||||||
|
|
||||||
|
export class SelfhostGenerateLicenseStore extends Store {
|
||||||
|
constructor(private readonly gqlService: GraphQLService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async generateKey(sessionId: string, signal?: AbortSignal): Promise<string> {
|
||||||
|
const data = await this.gqlService.gql({
|
||||||
|
query: generateLicenseKeyMutation,
|
||||||
|
variables: {
|
||||||
|
sessionId: sessionId,
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
signal,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return data.generateLicenseKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import {
|
||||||
|
activateLicenseMutation,
|
||||||
|
deactivateLicenseMutation,
|
||||||
|
getLicenseQuery,
|
||||||
|
} from '@affine/graphql';
|
||||||
|
import { Store } from '@toeverything/infra';
|
||||||
|
|
||||||
|
import type { WorkspaceServerService } from '../services/workspace-server';
|
||||||
|
|
||||||
|
export class SelfhostLicenseStore extends Store {
|
||||||
|
constructor(private readonly workspaceServerService: WorkspaceServerService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLicense(workspaceId: string, signal?: AbortSignal) {
|
||||||
|
if (!this.workspaceServerService.server) {
|
||||||
|
throw new Error('No Server');
|
||||||
|
}
|
||||||
|
const data = await this.workspaceServerService.server.gql({
|
||||||
|
query: getLicenseQuery,
|
||||||
|
variables: {
|
||||||
|
workspaceId: workspaceId,
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
signal,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return data.workspace.license;
|
||||||
|
}
|
||||||
|
|
||||||
|
async activate(workspaceId: string, license: string, signal?: AbortSignal) {
|
||||||
|
if (!this.workspaceServerService.server) {
|
||||||
|
throw new Error('No Server');
|
||||||
|
}
|
||||||
|
const data = await this.workspaceServerService.server.gql({
|
||||||
|
query: activateLicenseMutation,
|
||||||
|
variables: {
|
||||||
|
workspaceId: workspaceId,
|
||||||
|
license: license,
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
signal,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return data.activateLicense;
|
||||||
|
}
|
||||||
|
|
||||||
|
async deactivate(workspaceId: string, signal?: AbortSignal) {
|
||||||
|
if (!this.workspaceServerService.server) {
|
||||||
|
throw new Error('No Server');
|
||||||
|
}
|
||||||
|
const data = await this.workspaceServerService.server.gql({
|
||||||
|
query: deactivateLicenseMutation,
|
||||||
|
variables: {
|
||||||
|
workspaceId: workspaceId,
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
signal,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return data.deactivateLicense;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,12 +4,13 @@ import {
|
|||||||
catchErrorInto,
|
catchErrorInto,
|
||||||
effect,
|
effect,
|
||||||
Entity,
|
Entity,
|
||||||
|
exhaustMapWithTrailing,
|
||||||
fromPromise,
|
fromPromise,
|
||||||
LiveData,
|
LiveData,
|
||||||
onComplete,
|
onComplete,
|
||||||
onStart,
|
onStart,
|
||||||
} from '@toeverything/infra';
|
} from '@toeverything/infra';
|
||||||
import { EMPTY, exhaustMap, mergeMap } from 'rxjs';
|
import { EMPTY, mergeMap } from 'rxjs';
|
||||||
|
|
||||||
import { isBackendError, isNetworkError } from '../../cloud';
|
import { isBackendError, isNetworkError } from '../../cloud';
|
||||||
import type { WorkspaceService } from '../../workspace';
|
import type { WorkspaceService } from '../../workspace';
|
||||||
@@ -32,7 +33,7 @@ export class WorkspacePermission extends Entity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
revalidate = effect(
|
revalidate = effect(
|
||||||
exhaustMap(() => {
|
exhaustMapWithTrailing(() => {
|
||||||
return fromPromise(async signal => {
|
return fromPromise(async signal => {
|
||||||
if (this.workspaceService.workspace.flavour !== 'local') {
|
if (this.workspaceService.workspace.flavour !== 'local') {
|
||||||
const info = await this.store.fetchWorkspaceInfo(
|
const info = await this.store.fetchWorkspaceInfo(
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
mutation activateLicense($workspaceId: String!, $license: String!) {
|
||||||
|
activateLicense(workspaceId: $workspaceId, license: $license) {
|
||||||
|
installedAt
|
||||||
|
validatedAt
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
mutation createSelfhostCustomerPortal ($workspaceId: String!) {
|
||||||
|
createSelfhostWorkspaceCustomerPortal(workspaceId: $workspaceId)
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
mutation deactivateLicense($workspaceId: String!) {
|
||||||
|
deactivateLicense(workspaceId: $workspaceId)
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
mutation generateLicenseKey($sessionId: String!) {
|
||||||
|
generateLicenseKey(sessionId: $sessionId)
|
||||||
|
}
|
||||||
11
packages/frontend/graphql/src/graphql/get-license.gql
Normal file
11
packages/frontend/graphql/src/graphql/get-license.gql
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
query getLicense($workspaceId: String!) {
|
||||||
|
workspace(id: $workspaceId) {
|
||||||
|
license {
|
||||||
|
expiredAt
|
||||||
|
installedAt
|
||||||
|
quantity
|
||||||
|
recurring
|
||||||
|
validatedAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,20 @@ fragment CredentialsRequirements on CredentialsRequirementType {
|
|||||||
...PasswordLimits
|
...PasswordLimits
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
export const activateLicenseMutation = {
|
||||||
|
id: 'activateLicenseMutation' as const,
|
||||||
|
operationName: 'activateLicense',
|
||||||
|
definitionName: 'activateLicense',
|
||||||
|
containsFile: false,
|
||||||
|
query: `
|
||||||
|
mutation activateLicense($workspaceId: String!, $license: String!) {
|
||||||
|
activateLicense(workspaceId: $workspaceId, license: $license) {
|
||||||
|
installedAt
|
||||||
|
validatedAt
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
};
|
||||||
|
|
||||||
export const adminServerConfigQuery = {
|
export const adminServerConfigQuery = {
|
||||||
id: 'adminServerConfigQuery' as const,
|
id: 'adminServerConfigQuery' as const,
|
||||||
operationName: 'adminServerConfig',
|
operationName: 'adminServerConfig',
|
||||||
@@ -217,6 +231,17 @@ mutation createCustomerPortal {
|
|||||||
}`,
|
}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const createSelfhostCustomerPortalMutation = {
|
||||||
|
id: 'createSelfhostCustomerPortalMutation' as const,
|
||||||
|
operationName: 'createSelfhostCustomerPortal',
|
||||||
|
definitionName: 'createSelfhostWorkspaceCustomerPortal',
|
||||||
|
containsFile: false,
|
||||||
|
query: `
|
||||||
|
mutation createSelfhostCustomerPortal($workspaceId: String!) {
|
||||||
|
createSelfhostWorkspaceCustomerPortal(workspaceId: $workspaceId)
|
||||||
|
}`,
|
||||||
|
};
|
||||||
|
|
||||||
export const createUserMutation = {
|
export const createUserMutation = {
|
||||||
id: 'createUserMutation' as const,
|
id: 'createUserMutation' as const,
|
||||||
operationName: 'createUser',
|
operationName: 'createUser',
|
||||||
@@ -245,6 +270,17 @@ mutation createWorkspace {
|
|||||||
}`,
|
}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const deactivateLicenseMutation = {
|
||||||
|
id: 'deactivateLicenseMutation' as const,
|
||||||
|
operationName: 'deactivateLicense',
|
||||||
|
definitionName: 'deactivateLicense',
|
||||||
|
containsFile: false,
|
||||||
|
query: `
|
||||||
|
mutation deactivateLicense($workspaceId: String!) {
|
||||||
|
deactivateLicense(workspaceId: $workspaceId)
|
||||||
|
}`,
|
||||||
|
};
|
||||||
|
|
||||||
export const deleteAccountMutation = {
|
export const deleteAccountMutation = {
|
||||||
id: 'deleteAccountMutation' as const,
|
id: 'deleteAccountMutation' as const,
|
||||||
operationName: 'deleteAccount',
|
operationName: 'deleteAccount',
|
||||||
@@ -293,6 +329,17 @@ mutation forkCopilotSession($options: ForkChatSessionInput!) {
|
|||||||
}`,
|
}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const generateLicenseKeyMutation = {
|
||||||
|
id: 'generateLicenseKeyMutation' as const,
|
||||||
|
operationName: 'generateLicenseKey',
|
||||||
|
definitionName: 'generateLicenseKey',
|
||||||
|
containsFile: false,
|
||||||
|
query: `
|
||||||
|
mutation generateLicenseKey($sessionId: String!) {
|
||||||
|
generateLicenseKey(sessionId: $sessionId)
|
||||||
|
}`,
|
||||||
|
};
|
||||||
|
|
||||||
export const getCopilotHistoriesQuery = {
|
export const getCopilotHistoriesQuery = {
|
||||||
id: 'getCopilotHistoriesQuery' as const,
|
id: 'getCopilotHistoriesQuery' as const,
|
||||||
operationName: 'getCopilotHistories',
|
operationName: 'getCopilotHistories',
|
||||||
@@ -440,6 +487,25 @@ query getIsOwner($workspaceId: String!) {
|
|||||||
}`,
|
}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getLicenseQuery = {
|
||||||
|
id: 'getLicenseQuery' as const,
|
||||||
|
operationName: 'getLicense',
|
||||||
|
definitionName: 'workspace',
|
||||||
|
containsFile: false,
|
||||||
|
query: `
|
||||||
|
query getLicense($workspaceId: String!) {
|
||||||
|
workspace(id: $workspaceId) {
|
||||||
|
license {
|
||||||
|
expiredAt
|
||||||
|
installedAt
|
||||||
|
quantity
|
||||||
|
recurring
|
||||||
|
validatedAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
};
|
||||||
|
|
||||||
export const getMemberCountByWorkspaceIdQuery = {
|
export const getMemberCountByWorkspaceIdQuery = {
|
||||||
id: 'getMemberCountByWorkspaceIdQuery' as const,
|
id: 'getMemberCountByWorkspaceIdQuery' as const,
|
||||||
operationName: 'getMemberCountByWorkspaceId',
|
operationName: 'getMemberCountByWorkspaceId',
|
||||||
|
|||||||
@@ -253,6 +253,23 @@ export interface DocNotFoundDataType {
|
|||||||
spaceId: Scalars['String']['output'];
|
spaceId: Scalars['String']['output'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** User permission in doc */
|
||||||
|
export enum DocRole {
|
||||||
|
Editor = 'Editor',
|
||||||
|
External = 'External',
|
||||||
|
Manager = 'Manager',
|
||||||
|
Owner = 'Owner',
|
||||||
|
Reader = 'Reader',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DocType {
|
||||||
|
__typename?: 'DocType';
|
||||||
|
id: Scalars['String']['output'];
|
||||||
|
permissions: RolePermissions;
|
||||||
|
public: Scalars['Boolean']['output'];
|
||||||
|
role: DocRole;
|
||||||
|
}
|
||||||
|
|
||||||
export interface EditorType {
|
export interface EditorType {
|
||||||
__typename?: 'EditorType';
|
__typename?: 'EditorType';
|
||||||
avatarUrl: Maybe<Scalars['String']['output']>;
|
avatarUrl: Maybe<Scalars['String']['output']>;
|
||||||
@@ -268,6 +285,9 @@ export type ErrorDataUnion =
|
|||||||
| DocAccessDeniedDataType
|
| DocAccessDeniedDataType
|
||||||
| DocHistoryNotFoundDataType
|
| DocHistoryNotFoundDataType
|
||||||
| DocNotFoundDataType
|
| DocNotFoundDataType
|
||||||
|
| ExpectToGrantDocUserRolesDataType
|
||||||
|
| ExpectToRevokeDocUserRolesDataType
|
||||||
|
| ExpectToUpdateDocUserRoleDataType
|
||||||
| InvalidEmailDataType
|
| InvalidEmailDataType
|
||||||
| InvalidHistoryTimestampDataType
|
| InvalidHistoryTimestampDataType
|
||||||
| InvalidLicenseUpdateParamsDataType
|
| InvalidLicenseUpdateParamsDataType
|
||||||
@@ -282,6 +302,7 @@ export type ErrorDataUnion =
|
|||||||
| SpaceAccessDeniedDataType
|
| SpaceAccessDeniedDataType
|
||||||
| SpaceNotFoundDataType
|
| SpaceNotFoundDataType
|
||||||
| SpaceOwnerNotFoundDataType
|
| SpaceOwnerNotFoundDataType
|
||||||
|
| SpaceShouldHaveOnlyOneOwnerDataType
|
||||||
| SubscriptionAlreadyExistsDataType
|
| SubscriptionAlreadyExistsDataType
|
||||||
| SubscriptionNotExistsDataType
|
| SubscriptionNotExistsDataType
|
||||||
| SubscriptionPlanNotFoundDataType
|
| SubscriptionPlanNotFoundDataType
|
||||||
@@ -289,11 +310,13 @@ export type ErrorDataUnion =
|
|||||||
| UnsupportedSubscriptionPlanDataType
|
| UnsupportedSubscriptionPlanDataType
|
||||||
| VersionRejectedDataType
|
| VersionRejectedDataType
|
||||||
| WorkspaceMembersExceedLimitToDowngradeDataType
|
| WorkspaceMembersExceedLimitToDowngradeDataType
|
||||||
|
| WorkspacePermissionNotFoundDataType
|
||||||
| WrongSignInCredentialsDataType;
|
| WrongSignInCredentialsDataType;
|
||||||
|
|
||||||
export enum ErrorNames {
|
export enum ErrorNames {
|
||||||
ACCESS_DENIED = 'ACCESS_DENIED',
|
ACCESS_DENIED = 'ACCESS_DENIED',
|
||||||
ACTION_FORBIDDEN = 'ACTION_FORBIDDEN',
|
ACTION_FORBIDDEN = 'ACTION_FORBIDDEN',
|
||||||
|
ACTION_FORBIDDEN_ON_NON_TEAM_WORKSPACE = 'ACTION_FORBIDDEN_ON_NON_TEAM_WORKSPACE',
|
||||||
ALREADY_IN_SPACE = 'ALREADY_IN_SPACE',
|
ALREADY_IN_SPACE = 'ALREADY_IN_SPACE',
|
||||||
AUTHENTICATION_REQUIRED = 'AUTHENTICATION_REQUIRED',
|
AUTHENTICATION_REQUIRED = 'AUTHENTICATION_REQUIRED',
|
||||||
BLOB_NOT_FOUND = 'BLOB_NOT_FOUND',
|
BLOB_NOT_FOUND = 'BLOB_NOT_FOUND',
|
||||||
@@ -320,8 +343,11 @@ export enum ErrorNames {
|
|||||||
EMAIL_ALREADY_USED = 'EMAIL_ALREADY_USED',
|
EMAIL_ALREADY_USED = 'EMAIL_ALREADY_USED',
|
||||||
EMAIL_TOKEN_NOT_FOUND = 'EMAIL_TOKEN_NOT_FOUND',
|
EMAIL_TOKEN_NOT_FOUND = 'EMAIL_TOKEN_NOT_FOUND',
|
||||||
EMAIL_VERIFICATION_REQUIRED = 'EMAIL_VERIFICATION_REQUIRED',
|
EMAIL_VERIFICATION_REQUIRED = 'EMAIL_VERIFICATION_REQUIRED',
|
||||||
|
EXPECT_TO_GRANT_DOC_USER_ROLES = 'EXPECT_TO_GRANT_DOC_USER_ROLES',
|
||||||
EXPECT_TO_PUBLISH_PAGE = 'EXPECT_TO_PUBLISH_PAGE',
|
EXPECT_TO_PUBLISH_PAGE = 'EXPECT_TO_PUBLISH_PAGE',
|
||||||
|
EXPECT_TO_REVOKE_DOC_USER_ROLES = 'EXPECT_TO_REVOKE_DOC_USER_ROLES',
|
||||||
EXPECT_TO_REVOKE_PUBLIC_PAGE = 'EXPECT_TO_REVOKE_PUBLIC_PAGE',
|
EXPECT_TO_REVOKE_PUBLIC_PAGE = 'EXPECT_TO_REVOKE_PUBLIC_PAGE',
|
||||||
|
EXPECT_TO_UPDATE_DOC_USER_ROLE = 'EXPECT_TO_UPDATE_DOC_USER_ROLE',
|
||||||
FAILED_TO_CHECKOUT = 'FAILED_TO_CHECKOUT',
|
FAILED_TO_CHECKOUT = 'FAILED_TO_CHECKOUT',
|
||||||
FAILED_TO_SAVE_UPDATES = 'FAILED_TO_SAVE_UPDATES',
|
FAILED_TO_SAVE_UPDATES = 'FAILED_TO_SAVE_UPDATES',
|
||||||
FAILED_TO_UPSERT_SNAPSHOT = 'FAILED_TO_UPSERT_SNAPSHOT',
|
FAILED_TO_UPSERT_SNAPSHOT = 'FAILED_TO_UPSERT_SNAPSHOT',
|
||||||
@@ -359,6 +385,7 @@ export enum ErrorNames {
|
|||||||
SPACE_ACCESS_DENIED = 'SPACE_ACCESS_DENIED',
|
SPACE_ACCESS_DENIED = 'SPACE_ACCESS_DENIED',
|
||||||
SPACE_NOT_FOUND = 'SPACE_NOT_FOUND',
|
SPACE_NOT_FOUND = 'SPACE_NOT_FOUND',
|
||||||
SPACE_OWNER_NOT_FOUND = 'SPACE_OWNER_NOT_FOUND',
|
SPACE_OWNER_NOT_FOUND = 'SPACE_OWNER_NOT_FOUND',
|
||||||
|
SPACE_SHOULD_HAVE_ONLY_ONE_OWNER = 'SPACE_SHOULD_HAVE_ONLY_ONE_OWNER',
|
||||||
SUBSCRIPTION_ALREADY_EXISTS = 'SUBSCRIPTION_ALREADY_EXISTS',
|
SUBSCRIPTION_ALREADY_EXISTS = 'SUBSCRIPTION_ALREADY_EXISTS',
|
||||||
SUBSCRIPTION_EXPIRED = 'SUBSCRIPTION_EXPIRED',
|
SUBSCRIPTION_EXPIRED = 'SUBSCRIPTION_EXPIRED',
|
||||||
SUBSCRIPTION_HAS_BEEN_CANCELED = 'SUBSCRIPTION_HAS_BEEN_CANCELED',
|
SUBSCRIPTION_HAS_BEEN_CANCELED = 'SUBSCRIPTION_HAS_BEEN_CANCELED',
|
||||||
@@ -376,10 +403,29 @@ export enum ErrorNames {
|
|||||||
WORKSPACE_ID_REQUIRED_TO_UPDATE_TEAM_SUBSCRIPTION = 'WORKSPACE_ID_REQUIRED_TO_UPDATE_TEAM_SUBSCRIPTION',
|
WORKSPACE_ID_REQUIRED_TO_UPDATE_TEAM_SUBSCRIPTION = 'WORKSPACE_ID_REQUIRED_TO_UPDATE_TEAM_SUBSCRIPTION',
|
||||||
WORKSPACE_LICENSE_ALREADY_EXISTS = 'WORKSPACE_LICENSE_ALREADY_EXISTS',
|
WORKSPACE_LICENSE_ALREADY_EXISTS = 'WORKSPACE_LICENSE_ALREADY_EXISTS',
|
||||||
WORKSPACE_MEMBERS_EXCEED_LIMIT_TO_DOWNGRADE = 'WORKSPACE_MEMBERS_EXCEED_LIMIT_TO_DOWNGRADE',
|
WORKSPACE_MEMBERS_EXCEED_LIMIT_TO_DOWNGRADE = 'WORKSPACE_MEMBERS_EXCEED_LIMIT_TO_DOWNGRADE',
|
||||||
|
WORKSPACE_PERMISSION_NOT_FOUND = 'WORKSPACE_PERMISSION_NOT_FOUND',
|
||||||
WRONG_SIGN_IN_CREDENTIALS = 'WRONG_SIGN_IN_CREDENTIALS',
|
WRONG_SIGN_IN_CREDENTIALS = 'WRONG_SIGN_IN_CREDENTIALS',
|
||||||
WRONG_SIGN_IN_METHOD = 'WRONG_SIGN_IN_METHOD',
|
WRONG_SIGN_IN_METHOD = 'WRONG_SIGN_IN_METHOD',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ExpectToGrantDocUserRolesDataType {
|
||||||
|
__typename?: 'ExpectToGrantDocUserRolesDataType';
|
||||||
|
docId: Scalars['String']['output'];
|
||||||
|
spaceId: Scalars['String']['output'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExpectToRevokeDocUserRolesDataType {
|
||||||
|
__typename?: 'ExpectToRevokeDocUserRolesDataType';
|
||||||
|
docId: Scalars['String']['output'];
|
||||||
|
spaceId: Scalars['String']['output'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExpectToUpdateDocUserRoleDataType {
|
||||||
|
__typename?: 'ExpectToUpdateDocUserRoleDataType';
|
||||||
|
docId: Scalars['String']['output'];
|
||||||
|
spaceId: Scalars['String']['output'];
|
||||||
|
}
|
||||||
|
|
||||||
export enum FeatureType {
|
export enum FeatureType {
|
||||||
AIEarlyAccess = 'AIEarlyAccess',
|
AIEarlyAccess = 'AIEarlyAccess',
|
||||||
Admin = 'Admin',
|
Admin = 'Admin',
|
||||||
@@ -400,6 +446,32 @@ export interface ForkChatSessionInput {
|
|||||||
workspaceId: Scalars['String']['input'];
|
workspaceId: Scalars['String']['input'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GrantDocUserRolesInput {
|
||||||
|
docId: Scalars['String']['input'];
|
||||||
|
role: DocRole;
|
||||||
|
userIds: Array<Scalars['String']['input']>;
|
||||||
|
workspaceId: Scalars['String']['input'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GrantedDocUserEdge {
|
||||||
|
__typename?: 'GrantedDocUserEdge';
|
||||||
|
cursor: Scalars['String']['output'];
|
||||||
|
user: GrantedDocUserType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GrantedDocUserType {
|
||||||
|
__typename?: 'GrantedDocUserType';
|
||||||
|
role: DocRole;
|
||||||
|
user: UserType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GrantedDocUsersConnection {
|
||||||
|
__typename?: 'GrantedDocUsersConnection';
|
||||||
|
edges: Array<GrantedDocUserEdge>;
|
||||||
|
pageInfo: PageInfo;
|
||||||
|
totalCount: Scalars['Int']['output'];
|
||||||
|
}
|
||||||
|
|
||||||
export interface InvalidEmailDataType {
|
export interface InvalidEmailDataType {
|
||||||
__typename?: 'InvalidEmailDataType';
|
__typename?: 'InvalidEmailDataType';
|
||||||
email: Scalars['String']['output'];
|
email: Scalars['String']['output'];
|
||||||
@@ -489,8 +561,13 @@ export interface InviteUserType {
|
|||||||
inviteId: Scalars['String']['output'];
|
inviteId: Scalars['String']['output'];
|
||||||
/** User name */
|
/** User name */
|
||||||
name: Maybe<Scalars['String']['output']>;
|
name: Maybe<Scalars['String']['output']>;
|
||||||
/** User permission in workspace */
|
/**
|
||||||
|
* User permission in workspace
|
||||||
|
* @deprecated Use role instead
|
||||||
|
*/
|
||||||
permission: Permission;
|
permission: Permission;
|
||||||
|
/** User role in workspace */
|
||||||
|
role: Permission;
|
||||||
/** Member invite status in workspace */
|
/** Member invite status in workspace */
|
||||||
status: WorkspaceMemberStatus;
|
status: WorkspaceMemberStatus;
|
||||||
}
|
}
|
||||||
@@ -606,6 +683,7 @@ export interface Mutation {
|
|||||||
/** Create a chat session */
|
/** Create a chat session */
|
||||||
forkCopilotSession: Scalars['String']['output'];
|
forkCopilotSession: Scalars['String']['output'];
|
||||||
generateLicenseKey: Scalars['String']['output'];
|
generateLicenseKey: Scalars['String']['output'];
|
||||||
|
grantDocUserRoles: Scalars['Boolean']['output'];
|
||||||
grantMember: Scalars['String']['output'];
|
grantMember: Scalars['String']['output'];
|
||||||
invite: Scalars['String']['output'];
|
invite: Scalars['String']['output'];
|
||||||
inviteBatch: Array<InviteResult>;
|
inviteBatch: Array<InviteResult>;
|
||||||
@@ -618,6 +696,7 @@ export interface Mutation {
|
|||||||
removeWorkspaceFeature: Scalars['Boolean']['output'];
|
removeWorkspaceFeature: Scalars['Boolean']['output'];
|
||||||
resumeSubscription: SubscriptionType;
|
resumeSubscription: SubscriptionType;
|
||||||
revoke: Scalars['Boolean']['output'];
|
revoke: Scalars['Boolean']['output'];
|
||||||
|
revokeDocUserRoles: Scalars['Boolean']['output'];
|
||||||
revokeInviteLink: Scalars['Boolean']['output'];
|
revokeInviteLink: Scalars['Boolean']['output'];
|
||||||
/** @deprecated use revokePublicPage */
|
/** @deprecated use revokePublicPage */
|
||||||
revokePage: Scalars['Boolean']['output'];
|
revokePage: Scalars['Boolean']['output'];
|
||||||
@@ -634,6 +713,7 @@ export interface Mutation {
|
|||||||
updateCopilotPrompt: CopilotPromptType;
|
updateCopilotPrompt: CopilotPromptType;
|
||||||
/** Update a chat session */
|
/** Update a chat session */
|
||||||
updateCopilotSession: Scalars['String']['output'];
|
updateCopilotSession: Scalars['String']['output'];
|
||||||
|
updateDocUserRole: Scalars['Boolean']['output'];
|
||||||
updateProfile: UserType;
|
updateProfile: UserType;
|
||||||
/** update server runtime configurable setting */
|
/** update server runtime configurable setting */
|
||||||
updateRuntimeConfig: ServerRuntimeConfigType;
|
updateRuntimeConfig: ServerRuntimeConfigType;
|
||||||
@@ -758,6 +838,10 @@ export interface MutationGenerateLicenseKeyArgs {
|
|||||||
sessionId: Scalars['String']['input'];
|
sessionId: Scalars['String']['input'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MutationGrantDocUserRolesArgs {
|
||||||
|
input: GrantDocUserRolesInput;
|
||||||
|
}
|
||||||
|
|
||||||
export interface MutationGrantMemberArgs {
|
export interface MutationGrantMemberArgs {
|
||||||
permission: Permission;
|
permission: Permission;
|
||||||
userId: Scalars['String']['input'];
|
userId: Scalars['String']['input'];
|
||||||
@@ -815,6 +899,11 @@ export interface MutationRevokeArgs {
|
|||||||
workspaceId: Scalars['String']['input'];
|
workspaceId: Scalars['String']['input'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MutationRevokeDocUserRolesArgs {
|
||||||
|
docId: Scalars['String']['input'];
|
||||||
|
userIds: Array<Scalars['String']['input']>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface MutationRevokeInviteLinkArgs {
|
export interface MutationRevokeInviteLinkArgs {
|
||||||
workspaceId: Scalars['String']['input'];
|
workspaceId: Scalars['String']['input'];
|
||||||
}
|
}
|
||||||
@@ -873,6 +962,12 @@ export interface MutationUpdateCopilotSessionArgs {
|
|||||||
options: UpdateChatSessionInput;
|
options: UpdateChatSessionInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MutationUpdateDocUserRoleArgs {
|
||||||
|
docId: Scalars['String']['input'];
|
||||||
|
role: DocRole;
|
||||||
|
userId: Scalars['String']['input'];
|
||||||
|
}
|
||||||
|
|
||||||
export interface MutationUpdateProfileArgs {
|
export interface MutationUpdateProfileArgs {
|
||||||
input: UpdateUserInput;
|
input: UpdateUserInput;
|
||||||
}
|
}
|
||||||
@@ -926,6 +1021,23 @@ export enum OAuthProviderType {
|
|||||||
OIDC = 'OIDC',
|
OIDC = 'OIDC',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PageGrantedUsersInput {
|
||||||
|
/** Cursor */
|
||||||
|
after?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
/** Cursor */
|
||||||
|
before?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
first: Scalars['Int']['input'];
|
||||||
|
offset: Scalars['Int']['input'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PageInfo {
|
||||||
|
__typename?: 'PageInfo';
|
||||||
|
endCursor: Maybe<Scalars['String']['output']>;
|
||||||
|
hasNextPage: Scalars['Boolean']['output'];
|
||||||
|
hasPreviousPage: Scalars['Boolean']['output'];
|
||||||
|
startCursor: Maybe<Scalars['String']['output']>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface PasswordLimitsType {
|
export interface PasswordLimitsType {
|
||||||
__typename?: 'PasswordLimitsType';
|
__typename?: 'PasswordLimitsType';
|
||||||
maxLength: Scalars['Int']['output'];
|
maxLength: Scalars['Int']['output'];
|
||||||
@@ -935,9 +1047,9 @@ export interface PasswordLimitsType {
|
|||||||
/** User permission in workspace */
|
/** User permission in workspace */
|
||||||
export enum Permission {
|
export enum Permission {
|
||||||
Admin = 'Admin',
|
Admin = 'Admin',
|
||||||
|
Collaborator = 'Collaborator',
|
||||||
|
External = 'External',
|
||||||
Owner = 'Owner',
|
Owner = 'Owner',
|
||||||
Read = 'Read',
|
|
||||||
Write = 'Write',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The mode which the public page default in */
|
/** The mode which the public page default in */
|
||||||
@@ -984,6 +1096,8 @@ export interface Query {
|
|||||||
usersCount: Scalars['Int']['output'];
|
usersCount: Scalars['Int']['output'];
|
||||||
/** Get workspace by id */
|
/** Get workspace by id */
|
||||||
workspace: WorkspaceType;
|
workspace: WorkspaceType;
|
||||||
|
/** Get workspace role permissions */
|
||||||
|
workspaceRolePermissions: WorkspaceRolePermissions;
|
||||||
/** Get all accessible workspaces for current user */
|
/** Get all accessible workspaces for current user */
|
||||||
workspaces: Array<WorkspaceType>;
|
workspaces: Array<WorkspaceType>;
|
||||||
}
|
}
|
||||||
@@ -1028,6 +1142,10 @@ export interface QueryWorkspaceArgs {
|
|||||||
id: Scalars['String']['input'];
|
id: Scalars['String']['input'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface QueryWorkspaceRolePermissionsArgs {
|
||||||
|
id: Scalars['String']['input'];
|
||||||
|
}
|
||||||
|
|
||||||
export interface QueryChatHistoriesInput {
|
export interface QueryChatHistoriesInput {
|
||||||
action?: InputMaybe<Scalars['Boolean']['input']>;
|
action?: InputMaybe<Scalars['Boolean']['input']>;
|
||||||
fork?: InputMaybe<Scalars['Boolean']['input']>;
|
fork?: InputMaybe<Scalars['Boolean']['input']>;
|
||||||
@@ -1048,6 +1166,36 @@ export interface RemoveAvatar {
|
|||||||
success: Scalars['Boolean']['output'];
|
success: Scalars['Boolean']['output'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RolePermissions {
|
||||||
|
__typename?: 'RolePermissions';
|
||||||
|
Doc_Copy: Scalars['Boolean']['output'];
|
||||||
|
Doc_Delete: Scalars['Boolean']['output'];
|
||||||
|
Doc_Duplicate: Scalars['Boolean']['output'];
|
||||||
|
Doc_Properties_Read: Scalars['Boolean']['output'];
|
||||||
|
Doc_Properties_Update: Scalars['Boolean']['output'];
|
||||||
|
Doc_Publish: Scalars['Boolean']['output'];
|
||||||
|
Doc_Read: Scalars['Boolean']['output'];
|
||||||
|
Doc_Restore: Scalars['Boolean']['output'];
|
||||||
|
Doc_TransferOwner: Scalars['Boolean']['output'];
|
||||||
|
Doc_Trash: Scalars['Boolean']['output'];
|
||||||
|
Doc_Update: Scalars['Boolean']['output'];
|
||||||
|
Doc_Users_Manage: Scalars['Boolean']['output'];
|
||||||
|
Doc_Users_Read: Scalars['Boolean']['output'];
|
||||||
|
Workspace_CreateDoc: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Delete: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Organize_Read: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Properties_Create: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Properties_Delete: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Properties_Read: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Properties_Update: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Settings_Read: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Settings_Update: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Sync: Scalars['Boolean']['output'];
|
||||||
|
Workspace_TransferOwner: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Users_Manage: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Users_Read: Scalars['Boolean']['output'];
|
||||||
|
}
|
||||||
|
|
||||||
export interface RuntimeConfigNotFoundDataType {
|
export interface RuntimeConfigNotFoundDataType {
|
||||||
__typename?: 'RuntimeConfigNotFoundDataType';
|
__typename?: 'RuntimeConfigNotFoundDataType';
|
||||||
key: Scalars['String']['output'];
|
key: Scalars['String']['output'];
|
||||||
@@ -1146,6 +1294,11 @@ export interface SpaceOwnerNotFoundDataType {
|
|||||||
spaceId: Scalars['String']['output'];
|
spaceId: Scalars['String']['output'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SpaceShouldHaveOnlyOneOwnerDataType {
|
||||||
|
__typename?: 'SpaceShouldHaveOnlyOneOwnerDataType';
|
||||||
|
spaceId: Scalars['String']['output'];
|
||||||
|
}
|
||||||
|
|
||||||
export interface SubscriptionAlreadyExistsDataType {
|
export interface SubscriptionAlreadyExistsDataType {
|
||||||
__typename?: 'SubscriptionAlreadyExistsDataType';
|
__typename?: 'SubscriptionAlreadyExistsDataType';
|
||||||
plan: Scalars['String']['output'];
|
plan: Scalars['String']['output'];
|
||||||
@@ -1377,6 +1530,28 @@ export interface WorkspacePageMeta {
|
|||||||
updatedBy: Maybe<EditorType>;
|
updatedBy: Maybe<EditorType>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WorkspacePermissionNotFoundDataType {
|
||||||
|
__typename?: 'WorkspacePermissionNotFoundDataType';
|
||||||
|
spaceId: Scalars['String']['output'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WorkspacePermissions {
|
||||||
|
__typename?: 'WorkspacePermissions';
|
||||||
|
Workspace_CreateDoc: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Delete: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Organize_Read: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Properties_Create: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Properties_Delete: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Properties_Read: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Properties_Update: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Settings_Read: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Settings_Update: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Sync: Scalars['Boolean']['output'];
|
||||||
|
Workspace_TransferOwner: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Users_Manage: Scalars['Boolean']['output'];
|
||||||
|
Workspace_Users_Read: Scalars['Boolean']['output'];
|
||||||
|
}
|
||||||
|
|
||||||
export interface WorkspaceQuotaHumanReadableType {
|
export interface WorkspaceQuotaHumanReadableType {
|
||||||
__typename?: 'WorkspaceQuotaHumanReadableType';
|
__typename?: 'WorkspaceQuotaHumanReadableType';
|
||||||
blobLimit: Scalars['String']['output'];
|
blobLimit: Scalars['String']['output'];
|
||||||
@@ -1402,6 +1577,12 @@ export interface WorkspaceQuotaType {
|
|||||||
usedStorageQuota: Scalars['SafeInt']['output'];
|
usedStorageQuota: Scalars['SafeInt']['output'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WorkspaceRolePermissions {
|
||||||
|
__typename?: 'WorkspaceRolePermissions';
|
||||||
|
permissions: WorkspacePermissions;
|
||||||
|
role: Permission;
|
||||||
|
}
|
||||||
|
|
||||||
export interface WorkspaceType {
|
export interface WorkspaceType {
|
||||||
__typename?: 'WorkspaceType';
|
__typename?: 'WorkspaceType';
|
||||||
/** List blobs of workspace */
|
/** List blobs of workspace */
|
||||||
@@ -1431,10 +1612,12 @@ export interface WorkspaceType {
|
|||||||
members: Array<InviteUserType>;
|
members: Array<InviteUserType>;
|
||||||
/** Owner of workspace */
|
/** Owner of workspace */
|
||||||
owner: UserType;
|
owner: UserType;
|
||||||
|
/** Page granted users list */
|
||||||
|
pageGrantedUsersList: GrantedDocUsersConnection;
|
||||||
/** Cloud page metadata of workspace */
|
/** Cloud page metadata of workspace */
|
||||||
pageMeta: WorkspacePageMeta;
|
pageMeta: WorkspacePageMeta;
|
||||||
/** Permission of current signed in user in workspace */
|
/** Check if current user has permission to access the page */
|
||||||
permission: Permission;
|
pagePermission: DocType;
|
||||||
/** is Public workspace */
|
/** is Public workspace */
|
||||||
public: Scalars['Boolean']['output'];
|
public: Scalars['Boolean']['output'];
|
||||||
/** Get public page of a workspace by page id. */
|
/** Get public page of a workspace by page id. */
|
||||||
@@ -1443,6 +1626,8 @@ export interface WorkspaceType {
|
|||||||
publicPages: Array<WorkspacePage>;
|
publicPages: Array<WorkspacePage>;
|
||||||
/** quota of workspace */
|
/** quota of workspace */
|
||||||
quota: WorkspaceQuotaType;
|
quota: WorkspaceQuotaType;
|
||||||
|
/** Role of current signed in user in workspace */
|
||||||
|
role: Permission;
|
||||||
/**
|
/**
|
||||||
* Shared pages of workspace
|
* Shared pages of workspace
|
||||||
* @deprecated use WorkspaceType.publicPages
|
* @deprecated use WorkspaceType.publicPages
|
||||||
@@ -1471,10 +1656,19 @@ export interface WorkspaceTypeMembersArgs {
|
|||||||
take?: InputMaybe<Scalars['Int']['input']>;
|
take?: InputMaybe<Scalars['Int']['input']>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WorkspaceTypePageGrantedUsersListArgs {
|
||||||
|
pageGrantedUsersInput: PageGrantedUsersInput;
|
||||||
|
pageId: Scalars['String']['input'];
|
||||||
|
}
|
||||||
|
|
||||||
export interface WorkspaceTypePageMetaArgs {
|
export interface WorkspaceTypePageMetaArgs {
|
||||||
pageId: Scalars['String']['input'];
|
pageId: Scalars['String']['input'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WorkspaceTypePagePermissionArgs {
|
||||||
|
pageId: Scalars['String']['input'];
|
||||||
|
}
|
||||||
|
|
||||||
export interface WorkspaceTypePublicPageArgs {
|
export interface WorkspaceTypePublicPageArgs {
|
||||||
pageId: Scalars['String']['input'];
|
pageId: Scalars['String']['input'];
|
||||||
}
|
}
|
||||||
@@ -1491,6 +1685,20 @@ export interface TokenType {
|
|||||||
token: Scalars['String']['output'];
|
token: Scalars['String']['output'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ActivateLicenseMutationVariables = Exact<{
|
||||||
|
workspaceId: Scalars['String']['input'];
|
||||||
|
license: Scalars['String']['input'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type ActivateLicenseMutation = {
|
||||||
|
__typename?: 'Mutation';
|
||||||
|
activateLicense: {
|
||||||
|
__typename?: 'License';
|
||||||
|
installedAt: string;
|
||||||
|
validatedAt: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export type AdminServerConfigQueryVariables = Exact<{ [key: string]: never }>;
|
export type AdminServerConfigQueryVariables = Exact<{ [key: string]: never }>;
|
||||||
|
|
||||||
export type AdminServerConfigQuery = {
|
export type AdminServerConfigQuery = {
|
||||||
@@ -1669,6 +1877,15 @@ export type CreateCustomerPortalMutation = {
|
|||||||
createCustomerPortal: string;
|
createCustomerPortal: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CreateSelfhostCustomerPortalMutationVariables = Exact<{
|
||||||
|
workspaceId: Scalars['String']['input'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type CreateSelfhostCustomerPortalMutation = {
|
||||||
|
__typename?: 'Mutation';
|
||||||
|
createSelfhostWorkspaceCustomerPortal: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type CreateUserMutationVariables = Exact<{
|
export type CreateUserMutationVariables = Exact<{
|
||||||
input: CreateUserInput;
|
input: CreateUserInput;
|
||||||
}>;
|
}>;
|
||||||
@@ -1690,6 +1907,15 @@ export type CreateWorkspaceMutation = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type DeactivateLicenseMutationVariables = Exact<{
|
||||||
|
workspaceId: Scalars['String']['input'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type DeactivateLicenseMutation = {
|
||||||
|
__typename?: 'Mutation';
|
||||||
|
deactivateLicense: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type DeleteAccountMutationVariables = Exact<{ [key: string]: never }>;
|
export type DeleteAccountMutationVariables = Exact<{ [key: string]: never }>;
|
||||||
|
|
||||||
export type DeleteAccountMutation = {
|
export type DeleteAccountMutation = {
|
||||||
@@ -1739,6 +1965,15 @@ export type PasswordLimitsFragment = {
|
|||||||
maxLength: number;
|
maxLength: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type GenerateLicenseKeyMutationVariables = Exact<{
|
||||||
|
sessionId: Scalars['String']['input'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type GenerateLicenseKeyMutation = {
|
||||||
|
__typename?: 'Mutation';
|
||||||
|
generateLicenseKey: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type GetCopilotHistoriesQueryVariables = Exact<{
|
export type GetCopilotHistoriesQueryVariables = Exact<{
|
||||||
workspaceId: Scalars['String']['input'];
|
workspaceId: Scalars['String']['input'];
|
||||||
docId?: InputMaybe<Scalars['String']['input']>;
|
docId?: InputMaybe<Scalars['String']['input']>;
|
||||||
@@ -1879,6 +2114,25 @@ export type GetIsOwnerQueryVariables = Exact<{
|
|||||||
|
|
||||||
export type GetIsOwnerQuery = { __typename?: 'Query'; isOwner: boolean };
|
export type GetIsOwnerQuery = { __typename?: 'Query'; isOwner: boolean };
|
||||||
|
|
||||||
|
export type GetLicenseQueryVariables = Exact<{
|
||||||
|
workspaceId: Scalars['String']['input'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type GetLicenseQuery = {
|
||||||
|
__typename?: 'Query';
|
||||||
|
workspace: {
|
||||||
|
__typename?: 'WorkspaceType';
|
||||||
|
license: {
|
||||||
|
__typename?: 'License';
|
||||||
|
expiredAt: string | null;
|
||||||
|
installedAt: string;
|
||||||
|
quantity: number;
|
||||||
|
recurring: SubscriptionRecurring;
|
||||||
|
validatedAt: string;
|
||||||
|
} | null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export type GetMemberCountByWorkspaceIdQueryVariables = Exact<{
|
export type GetMemberCountByWorkspaceIdQueryVariables = Exact<{
|
||||||
workspaceId: Scalars['String']['input'];
|
workspaceId: Scalars['String']['input'];
|
||||||
}>;
|
}>;
|
||||||
@@ -2843,6 +3097,11 @@ export type Queries =
|
|||||||
variables: GetIsOwnerQueryVariables;
|
variables: GetIsOwnerQueryVariables;
|
||||||
response: GetIsOwnerQuery;
|
response: GetIsOwnerQuery;
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
name: 'getLicenseQuery';
|
||||||
|
variables: GetLicenseQueryVariables;
|
||||||
|
response: GetLicenseQuery;
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
name: 'getMemberCountByWorkspaceIdQuery';
|
name: 'getMemberCountByWorkspaceIdQuery';
|
||||||
variables: GetMemberCountByWorkspaceIdQueryVariables;
|
variables: GetMemberCountByWorkspaceIdQueryVariables;
|
||||||
@@ -2990,6 +3249,11 @@ export type Queries =
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type Mutations =
|
export type Mutations =
|
||||||
|
| {
|
||||||
|
name: 'activateLicenseMutation';
|
||||||
|
variables: ActivateLicenseMutationVariables;
|
||||||
|
response: ActivateLicenseMutation;
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
name: 'deleteBlobMutation';
|
name: 'deleteBlobMutation';
|
||||||
variables: DeleteBlobMutationVariables;
|
variables: DeleteBlobMutationVariables;
|
||||||
@@ -3050,6 +3314,11 @@ export type Mutations =
|
|||||||
variables: CreateCustomerPortalMutationVariables;
|
variables: CreateCustomerPortalMutationVariables;
|
||||||
response: CreateCustomerPortalMutation;
|
response: CreateCustomerPortalMutation;
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
name: 'createSelfhostCustomerPortalMutation';
|
||||||
|
variables: CreateSelfhostCustomerPortalMutationVariables;
|
||||||
|
response: CreateSelfhostCustomerPortalMutation;
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
name: 'createUserMutation';
|
name: 'createUserMutation';
|
||||||
variables: CreateUserMutationVariables;
|
variables: CreateUserMutationVariables;
|
||||||
@@ -3060,6 +3329,11 @@ export type Mutations =
|
|||||||
variables: CreateWorkspaceMutationVariables;
|
variables: CreateWorkspaceMutationVariables;
|
||||||
response: CreateWorkspaceMutation;
|
response: CreateWorkspaceMutation;
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
name: 'deactivateLicenseMutation';
|
||||||
|
variables: DeactivateLicenseMutationVariables;
|
||||||
|
response: DeactivateLicenseMutation;
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
name: 'deleteAccountMutation';
|
name: 'deleteAccountMutation';
|
||||||
variables: DeleteAccountMutationVariables;
|
variables: DeleteAccountMutationVariables;
|
||||||
@@ -3080,6 +3354,11 @@ export type Mutations =
|
|||||||
variables: ForkCopilotSessionMutationVariables;
|
variables: ForkCopilotSessionMutationVariables;
|
||||||
response: ForkCopilotSessionMutation;
|
response: ForkCopilotSessionMutation;
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
name: 'generateLicenseKeyMutation';
|
||||||
|
variables: GenerateLicenseKeyMutationVariables;
|
||||||
|
response: GenerateLicenseKeyMutation;
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
name: 'leaveWorkspaceMutation';
|
name: 'leaveWorkspaceMutation';
|
||||||
variables: LeaveWorkspaceMutationVariables;
|
variables: LeaveWorkspaceMutationVariables;
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
{
|
{
|
||||||
"ar": 92,
|
"ar": 90,
|
||||||
"ca": 5,
|
"ca": 5,
|
||||||
"da": 5,
|
"da": 5,
|
||||||
"de": 92,
|
"de": 90,
|
||||||
"el-GR": 92,
|
"el-GR": 90,
|
||||||
"en": 100,
|
"en": 100,
|
||||||
"es-AR": 92,
|
"es-AR": 90,
|
||||||
"es-CL": 94,
|
"es-CL": 92,
|
||||||
"es": 92,
|
"es": 90,
|
||||||
"fa": 92,
|
"fa": 90,
|
||||||
"fr": 92,
|
"fr": 90,
|
||||||
"hi": 2,
|
"hi": 2,
|
||||||
"it-IT": 92,
|
"it-IT": 90,
|
||||||
"it": 1,
|
"it": 1,
|
||||||
"ja": 92,
|
"ja": 90,
|
||||||
"ko": 67,
|
"ko": 65,
|
||||||
"pl": 92,
|
"pl": 90,
|
||||||
"pt-BR": 92,
|
"pt-BR": 90,
|
||||||
"ru": 92,
|
"ru": 90,
|
||||||
"sv-SE": 92,
|
"sv-SE": 90,
|
||||||
"uk": 92,
|
"uk": 90,
|
||||||
"ur": 2,
|
"ur": 2,
|
||||||
"zh-Hans": 92,
|
"zh-Hans": 90,
|
||||||
"zh-Hant": 92
|
"zh-Hant": 90
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4185,6 +4185,26 @@ export function useAFFiNEI18N(): {
|
|||||||
* `Congratulations! Your workspace has been successfully upgraded to a Team Workspace. Now you can invite unlimited members to collaborate in this workspace.`
|
* `Congratulations! Your workspace has been successfully upgraded to a Team Workspace. Now you can invite unlimited members to collaborate in this workspace.`
|
||||||
*/
|
*/
|
||||||
["com.affine.payment.upgrade-success-page.team.text-1"](): string;
|
["com.affine.payment.upgrade-success-page.team.text-1"](): string;
|
||||||
|
/**
|
||||||
|
* `Thank you for your purchase!`
|
||||||
|
*/
|
||||||
|
["com.affine.payment.license-success.title"](): string;
|
||||||
|
/**
|
||||||
|
* `Thank you for purchasing the AFFiNE self-hosted license.`
|
||||||
|
*/
|
||||||
|
["com.affine.payment.license-success.text-1"](): string;
|
||||||
|
/**
|
||||||
|
* `You can use this key to upgrade in Settings > Workspace > Billing > Upgrade`
|
||||||
|
*/
|
||||||
|
["com.affine.payment.license-success.hint"](): string;
|
||||||
|
/**
|
||||||
|
* `Open AFFiNE`
|
||||||
|
*/
|
||||||
|
["com.affine.payment.license-success.open-affine"](): string;
|
||||||
|
/**
|
||||||
|
* `Copied key to clipboard`
|
||||||
|
*/
|
||||||
|
["com.affine.payment.license-success.copy"](): string;
|
||||||
/**
|
/**
|
||||||
* `Close`
|
* `Close`
|
||||||
*/
|
*/
|
||||||
@@ -5413,6 +5433,116 @@ export function useAFFiNEI18N(): {
|
|||||||
* `Cancel Plan`
|
* `Cancel Plan`
|
||||||
*/
|
*/
|
||||||
["com.affine.settings.workspace.billing.team-workspace.cancel-plan"](): string;
|
["com.affine.settings.workspace.billing.team-workspace.cancel-plan"](): string;
|
||||||
|
/**
|
||||||
|
* `License`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license"](): string;
|
||||||
|
/**
|
||||||
|
* `Manage license information and invoices for the self host team workspace.`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.description"](): string;
|
||||||
|
/**
|
||||||
|
* `Get teams plan for your self hosted workspace.`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.benefit.team.title"](): string;
|
||||||
|
/**
|
||||||
|
* `Need more seats? Best for scalable teams.`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.benefit.team.subtitle"](): string;
|
||||||
|
/**
|
||||||
|
* `Everything in Self Hosted FOSS`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.benefit.team.g1"](): string;
|
||||||
|
/**
|
||||||
|
* `{{initialQuota}} initial storage + {{quotaPerSeat}} per seat`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.benefit.team.g2"](options: Readonly<{
|
||||||
|
initialQuota: string;
|
||||||
|
quotaPerSeat: string;
|
||||||
|
}>): string;
|
||||||
|
/**
|
||||||
|
* `{{quota}} of maximum file size`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.benefit.team.g3"](options: {
|
||||||
|
readonly quota: string;
|
||||||
|
}): string;
|
||||||
|
/**
|
||||||
|
* `Unlimited team members (10+ seats)`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.benefit.team.g4"](): string;
|
||||||
|
/**
|
||||||
|
* `Multiple admin roles`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.benefit.team.g5"](): string;
|
||||||
|
/**
|
||||||
|
* `Priority customer support`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.benefit.team.g6"](): string;
|
||||||
|
/**
|
||||||
|
* `Lean more`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.lean-more"](): string;
|
||||||
|
/**
|
||||||
|
* `Selfhosted workspace`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.self-host"](): string;
|
||||||
|
/**
|
||||||
|
* `Self-host Team Workspace`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.self-host-team"](): string;
|
||||||
|
/**
|
||||||
|
* `This license will expire on {{expirationDate}}, with {{leftDays}} days remaining.`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.self-host-team.team.description"](options: Readonly<{
|
||||||
|
expirationDate: string;
|
||||||
|
leftDays: string;
|
||||||
|
}>): string;
|
||||||
|
/**
|
||||||
|
* `Basic version: {{memberCount}} seats. For more, purchase or use activation key.`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.self-host-team.free.description"](options: {
|
||||||
|
readonly memberCount: string;
|
||||||
|
}): string;
|
||||||
|
/**
|
||||||
|
* `Seats`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.self-host-team.seats"](): string;
|
||||||
|
/**
|
||||||
|
* `Active key`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.self-host-team.active-key"](): string;
|
||||||
|
/**
|
||||||
|
* `Deactivate`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.self-host-team.deactivate-license"](): string;
|
||||||
|
/**
|
||||||
|
* `Buy more seat`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.buy-more-seat"](): string;
|
||||||
|
/**
|
||||||
|
* `Activate License`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.activate-modal.title"](): string;
|
||||||
|
/**
|
||||||
|
* `Enter license key to activate this self host workspace.`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.activate-modal.description"](): string;
|
||||||
|
/**
|
||||||
|
* `License activated successfully.`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.activate-success"](): string;
|
||||||
|
/**
|
||||||
|
* `Deactivate License`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.deactivate-modal.title"](): string;
|
||||||
|
/**
|
||||||
|
* `Are you sure you want to deactivate this license?`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.deactivate-modal.description"](): string;
|
||||||
|
/**
|
||||||
|
* `License deactivated successfully.`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.deactivate-success"](): string;
|
||||||
/**
|
/**
|
||||||
* `Local`
|
* `Local`
|
||||||
*/
|
*/
|
||||||
@@ -6811,6 +6941,12 @@ export function useAFFiNEI18N(): {
|
|||||||
* `You must verify your email before accessing this resource.`
|
* `You must verify your email before accessing this resource.`
|
||||||
*/
|
*/
|
||||||
["error.EMAIL_VERIFICATION_REQUIRED"](): string;
|
["error.EMAIL_VERIFICATION_REQUIRED"](): string;
|
||||||
|
/**
|
||||||
|
* `Space {{spaceId}} permission not found.`
|
||||||
|
*/
|
||||||
|
["error.WORKSPACE_PERMISSION_NOT_FOUND"](options: {
|
||||||
|
readonly spaceId: string;
|
||||||
|
}): string;
|
||||||
/**
|
/**
|
||||||
* `Space {{spaceId}} not found.`
|
* `Space {{spaceId}} not found.`
|
||||||
*/
|
*/
|
||||||
@@ -6847,6 +6983,10 @@ export function useAFFiNEI18N(): {
|
|||||||
["error.SPACE_OWNER_NOT_FOUND"](options: {
|
["error.SPACE_OWNER_NOT_FOUND"](options: {
|
||||||
readonly spaceId: string;
|
readonly spaceId: string;
|
||||||
}): string;
|
}): string;
|
||||||
|
/**
|
||||||
|
* `Space should have only one owner.`
|
||||||
|
*/
|
||||||
|
["error.SPACE_SHOULD_HAVE_ONLY_ONE_OWNER"](): string;
|
||||||
/**
|
/**
|
||||||
* `Doc {{docId}} under Space {{spaceId}} not found.`
|
* `Doc {{docId}} under Space {{spaceId}} not found.`
|
||||||
*/
|
*/
|
||||||
@@ -6895,6 +7035,27 @@ export function useAFFiNEI18N(): {
|
|||||||
* `Expected to revoke a public page, not a Space.`
|
* `Expected to revoke a public page, not a Space.`
|
||||||
*/
|
*/
|
||||||
["error.EXPECT_TO_REVOKE_PUBLIC_PAGE"](): string;
|
["error.EXPECT_TO_REVOKE_PUBLIC_PAGE"](): string;
|
||||||
|
/**
|
||||||
|
* `Expect grant roles on doc {{docId}} under Space {{spaceId}}, not a Space.`
|
||||||
|
*/
|
||||||
|
["error.EXPECT_TO_GRANT_DOC_USER_ROLES"](options: Readonly<{
|
||||||
|
docId: string;
|
||||||
|
spaceId: string;
|
||||||
|
}>): string;
|
||||||
|
/**
|
||||||
|
* `Expect revoke roles on doc {{docId}} under Space {{spaceId}}, not a Space.`
|
||||||
|
*/
|
||||||
|
["error.EXPECT_TO_REVOKE_DOC_USER_ROLES"](options: Readonly<{
|
||||||
|
docId: string;
|
||||||
|
spaceId: string;
|
||||||
|
}>): string;
|
||||||
|
/**
|
||||||
|
* `Expect update roles on doc {{docId}} under Space {{spaceId}}, not a Space.`
|
||||||
|
*/
|
||||||
|
["error.EXPECT_TO_UPDATE_DOC_USER_ROLE"](options: Readonly<{
|
||||||
|
docId: string;
|
||||||
|
spaceId: string;
|
||||||
|
}>): string;
|
||||||
/**
|
/**
|
||||||
* `Page is not public.`
|
* `Page is not public.`
|
||||||
*/
|
*/
|
||||||
@@ -6907,6 +7068,10 @@ export function useAFFiNEI18N(): {
|
|||||||
* `Failed to store doc snapshot.`
|
* `Failed to store doc snapshot.`
|
||||||
*/
|
*/
|
||||||
["error.FAILED_TO_UPSERT_SNAPSHOT"](): string;
|
["error.FAILED_TO_UPSERT_SNAPSHOT"](): string;
|
||||||
|
/**
|
||||||
|
* `A Team workspace is required to perform this action.`
|
||||||
|
*/
|
||||||
|
["error.ACTION_FORBIDDEN_ON_NON_TEAM_WORKSPACE"](): string;
|
||||||
/**
|
/**
|
||||||
* `Unsupported subscription plan: {{plan}}.`
|
* `Unsupported subscription plan: {{plan}}.`
|
||||||
*/
|
*/
|
||||||
@@ -7376,6 +7541,12 @@ export const TypedTrans: {
|
|||||||
["com.affine.payment.upgrade-success-page.team.text-2"]: ComponentType<TypedTransProps<Readonly<{}>, {
|
["com.affine.payment.upgrade-success-page.team.text-2"]: ComponentType<TypedTransProps<Readonly<{}>, {
|
||||||
["1"]: JSX.Element;
|
["1"]: JSX.Element;
|
||||||
}>>;
|
}>>;
|
||||||
|
/**
|
||||||
|
* `If you have any questions, please contact our <1>customer support</1>.`
|
||||||
|
*/
|
||||||
|
["com.affine.payment.license-success.text-2"]: ComponentType<TypedTransProps<Readonly<{}>, {
|
||||||
|
["1"]: JSX.Element;
|
||||||
|
}>>;
|
||||||
/**
|
/**
|
||||||
* `This action deletes the old Favorites section. <b>Your documents are safe</b>, ensure you've moved your frequently accessed documents to the new personal Favorites section.`
|
* `This action deletes the old Favorites section. <b>Your documents are safe</b>, ensure you've moved your frequently accessed documents to the new personal Favorites section.`
|
||||||
*/
|
*/
|
||||||
@@ -7415,6 +7586,12 @@ export const TypedTrans: {
|
|||||||
["1"]: JSX.Element;
|
["1"]: JSX.Element;
|
||||||
["2"]: JSX.Element;
|
["2"]: JSX.Element;
|
||||||
}>>;
|
}>>;
|
||||||
|
/**
|
||||||
|
* `If you encounter any issues, please contact our <1>customer support</1>.`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.workspace.license.activate-modal.tips"]: ComponentType<TypedTransProps<Readonly<{}>, {
|
||||||
|
["1"]: JSX.Element;
|
||||||
|
}>>;
|
||||||
/**
|
/**
|
||||||
* `The "<1>{{ name }}</1>" property will be removed. This action cannot be undone.`
|
* `The "<1>{{ name }}</1>" property will be removed. This action cannot be undone.`
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1038,6 +1038,12 @@
|
|||||||
"com.affine.payment.upgrade-success-page.title": "Upgrade successful!",
|
"com.affine.payment.upgrade-success-page.title": "Upgrade successful!",
|
||||||
"com.affine.payment.upgrade-success-page.team.text-1": "Congratulations! Your workspace has been successfully upgraded to a Team Workspace. Now you can invite unlimited members to collaborate in this workspace.",
|
"com.affine.payment.upgrade-success-page.team.text-1": "Congratulations! Your workspace has been successfully upgraded to a Team Workspace. Now you can invite unlimited members to collaborate in this workspace.",
|
||||||
"com.affine.payment.upgrade-success-page.team.text-2": "If you have any questions, please contact our <1>customer support</1>.",
|
"com.affine.payment.upgrade-success-page.team.text-2": "If you have any questions, please contact our <1>customer support</1>.",
|
||||||
|
"com.affine.payment.license-success.title": "Thank you for your purchase!",
|
||||||
|
"com.affine.payment.license-success.text-1": "Thank you for purchasing the AFFiNE self-hosted license.",
|
||||||
|
"com.affine.payment.license-success.text-2": "If you have any questions, please contact our <1>customer support</1>.",
|
||||||
|
"com.affine.payment.license-success.hint": "You can use this key to upgrade in Settings > Workspace > Billing > Upgrade",
|
||||||
|
"com.affine.payment.license-success.open-affine": "Open AFFiNE",
|
||||||
|
"com.affine.payment.license-success.copy": "Copied key to clipboard",
|
||||||
"com.affine.peek-view-controls.close": "Close",
|
"com.affine.peek-view-controls.close": "Close",
|
||||||
"com.affine.peek-view-controls.open-doc": "Open this doc",
|
"com.affine.peek-view-controls.open-doc": "Open this doc",
|
||||||
"com.affine.peek-view-controls.open-doc-in-new-tab": "Open in new tab",
|
"com.affine.peek-view-controls.open-doc-in-new-tab": "Open in new tab",
|
||||||
@@ -1350,6 +1356,32 @@
|
|||||||
"com.affine.settings.workspace.billing.team-workspace.not-renewed": "Your subscription will end on {{date}}",
|
"com.affine.settings.workspace.billing.team-workspace.not-renewed": "Your subscription will end on {{date}}",
|
||||||
"com.affine.settings.workspace.billing.team-workspace.next-billing-date": "Next billing date: {{date}}",
|
"com.affine.settings.workspace.billing.team-workspace.next-billing-date": "Next billing date: {{date}}",
|
||||||
"com.affine.settings.workspace.billing.team-workspace.cancel-plan": "Cancel Plan",
|
"com.affine.settings.workspace.billing.team-workspace.cancel-plan": "Cancel Plan",
|
||||||
|
"com.affine.settings.workspace.license": "License",
|
||||||
|
"com.affine.settings.workspace.license.description": "Manage license information and invoices for the self host team workspace.",
|
||||||
|
"com.affine.settings.workspace.license.benefit.team.title": "Get teams plan for your self hosted workspace.",
|
||||||
|
"com.affine.settings.workspace.license.benefit.team.subtitle": "Need more seats? Best for scalable teams.",
|
||||||
|
"com.affine.settings.workspace.license.benefit.team.g1": "Everything in Self Hosted FOSS",
|
||||||
|
"com.affine.settings.workspace.license.benefit.team.g2": "{{initialQuota}} initial storage + {{quotaPerSeat}} per seat",
|
||||||
|
"com.affine.settings.workspace.license.benefit.team.g3": "{{quota}} of maximum file size",
|
||||||
|
"com.affine.settings.workspace.license.benefit.team.g4": "Unlimited team members (10+ seats)",
|
||||||
|
"com.affine.settings.workspace.license.benefit.team.g5": "Multiple admin roles",
|
||||||
|
"com.affine.settings.workspace.license.benefit.team.g6": "Priority customer support",
|
||||||
|
"com.affine.settings.workspace.license.lean-more": "Lean more",
|
||||||
|
"com.affine.settings.workspace.license.self-host": "Selfhosted workspace",
|
||||||
|
"com.affine.settings.workspace.license.self-host-team": "Self-host Team Workspace",
|
||||||
|
"com.affine.settings.workspace.license.self-host-team.team.description": "This license will expire on {{expirationDate}}, with {{leftDays}} days remaining.",
|
||||||
|
"com.affine.settings.workspace.license.self-host-team.free.description": "Basic version: {{memberCount}} seats. For more, purchase or use activation key.",
|
||||||
|
"com.affine.settings.workspace.license.self-host-team.seats": "Seats",
|
||||||
|
"com.affine.settings.workspace.license.self-host-team.active-key": "Active key",
|
||||||
|
"com.affine.settings.workspace.license.self-host-team.deactivate-license": "Deactivate",
|
||||||
|
"com.affine.settings.workspace.license.buy-more-seat": "Buy more seat",
|
||||||
|
"com.affine.settings.workspace.license.activate-modal.title": "Activate License",
|
||||||
|
"com.affine.settings.workspace.license.activate-modal.description": "Enter license key to activate this self host workspace.",
|
||||||
|
"com.affine.settings.workspace.license.activate-modal.tips": "If you encounter any issues, please contact our <1>customer support</1>.",
|
||||||
|
"com.affine.settings.workspace.license.activate-success": "License activated successfully.",
|
||||||
|
"com.affine.settings.workspace.license.deactivate-modal.title": "Deactivate License",
|
||||||
|
"com.affine.settings.workspace.license.deactivate-modal.description": "Are you sure you want to deactivate this license?",
|
||||||
|
"com.affine.settings.workspace.license.deactivate-success": "License deactivated successfully.",
|
||||||
"com.affine.settings.workspace.state.local": "Local",
|
"com.affine.settings.workspace.state.local": "Local",
|
||||||
"com.affine.settings.workspace.state.sync-affine-cloud": "Sync with AFFiNE Cloud",
|
"com.affine.settings.workspace.state.sync-affine-cloud": "Sync with AFFiNE Cloud",
|
||||||
"com.affine.settings.workspace.state.self-hosted": "Self-Hosted Server",
|
"com.affine.settings.workspace.state.self-hosted": "Self-Hosted Server",
|
||||||
@@ -1695,12 +1727,14 @@
|
|||||||
"error.ACTION_FORBIDDEN": "You are not allowed to perform this action.",
|
"error.ACTION_FORBIDDEN": "You are not allowed to perform this action.",
|
||||||
"error.ACCESS_DENIED": "You do not have permission to access this resource.",
|
"error.ACCESS_DENIED": "You do not have permission to access this resource.",
|
||||||
"error.EMAIL_VERIFICATION_REQUIRED": "You must verify your email before accessing this resource.",
|
"error.EMAIL_VERIFICATION_REQUIRED": "You must verify your email before accessing this resource.",
|
||||||
|
"error.WORKSPACE_PERMISSION_NOT_FOUND": "Space {{spaceId}} permission not found.",
|
||||||
"error.SPACE_NOT_FOUND": "Space {{spaceId}} not found.",
|
"error.SPACE_NOT_FOUND": "Space {{spaceId}} not found.",
|
||||||
"error.MEMBER_NOT_FOUND_IN_SPACE": "Member not found in Space {{spaceId}}.",
|
"error.MEMBER_NOT_FOUND_IN_SPACE": "Member not found in Space {{spaceId}}.",
|
||||||
"error.NOT_IN_SPACE": "You should join in Space {{spaceId}} before broadcasting messages.",
|
"error.NOT_IN_SPACE": "You should join in Space {{spaceId}} before broadcasting messages.",
|
||||||
"error.ALREADY_IN_SPACE": "You have already joined in Space {{spaceId}}.",
|
"error.ALREADY_IN_SPACE": "You have already joined in Space {{spaceId}}.",
|
||||||
"error.SPACE_ACCESS_DENIED": "You do not have permission to access Space {{spaceId}}.",
|
"error.SPACE_ACCESS_DENIED": "You do not have permission to access Space {{spaceId}}.",
|
||||||
"error.SPACE_OWNER_NOT_FOUND": "Owner of Space {{spaceId}} not found.",
|
"error.SPACE_OWNER_NOT_FOUND": "Owner of Space {{spaceId}} not found.",
|
||||||
|
"error.SPACE_SHOULD_HAVE_ONLY_ONE_OWNER": "Space should have only one owner.",
|
||||||
"error.DOC_NOT_FOUND": "Doc {{docId}} under Space {{spaceId}} not found.",
|
"error.DOC_NOT_FOUND": "Doc {{docId}} under Space {{spaceId}} not found.",
|
||||||
"error.DOC_ACCESS_DENIED": "You do not have permission to access doc {{docId}} under Space {{spaceId}}.",
|
"error.DOC_ACCESS_DENIED": "You do not have permission to access doc {{docId}} under Space {{spaceId}}.",
|
||||||
"error.VERSION_REJECTED": "Your client with version {{version}} is rejected by remote sync server. Please upgrade to {{serverVersion}}.",
|
"error.VERSION_REJECTED": "Your client with version {{version}} is rejected by remote sync server. Please upgrade to {{serverVersion}}.",
|
||||||
@@ -1709,9 +1743,13 @@
|
|||||||
"error.BLOB_NOT_FOUND": "Blob {{blobId}} not found in Space {{spaceId}}.",
|
"error.BLOB_NOT_FOUND": "Blob {{blobId}} not found in Space {{spaceId}}.",
|
||||||
"error.EXPECT_TO_PUBLISH_PAGE": "Expected to publish a page, not a Space.",
|
"error.EXPECT_TO_PUBLISH_PAGE": "Expected to publish a page, not a Space.",
|
||||||
"error.EXPECT_TO_REVOKE_PUBLIC_PAGE": "Expected to revoke a public page, not a Space.",
|
"error.EXPECT_TO_REVOKE_PUBLIC_PAGE": "Expected to revoke a public page, not a Space.",
|
||||||
|
"error.EXPECT_TO_GRANT_DOC_USER_ROLES": "Expect grant roles on doc {{docId}} under Space {{spaceId}}, not a Space.",
|
||||||
|
"error.EXPECT_TO_REVOKE_DOC_USER_ROLES": "Expect revoke roles on doc {{docId}} under Space {{spaceId}}, not a Space.",
|
||||||
|
"error.EXPECT_TO_UPDATE_DOC_USER_ROLE": "Expect update roles on doc {{docId}} under Space {{spaceId}}, not a Space.",
|
||||||
"error.PAGE_IS_NOT_PUBLIC": "Page is not public.",
|
"error.PAGE_IS_NOT_PUBLIC": "Page is not public.",
|
||||||
"error.FAILED_TO_SAVE_UPDATES": "Failed to store doc updates.",
|
"error.FAILED_TO_SAVE_UPDATES": "Failed to store doc updates.",
|
||||||
"error.FAILED_TO_UPSERT_SNAPSHOT": "Failed to store doc snapshot.",
|
"error.FAILED_TO_UPSERT_SNAPSHOT": "Failed to store doc snapshot.",
|
||||||
|
"error.ACTION_FORBIDDEN_ON_NON_TEAM_WORKSPACE": "A Team workspace is required to perform this action.",
|
||||||
"error.UNSUPPORTED_SUBSCRIPTION_PLAN": "Unsupported subscription plan: {{plan}}.",
|
"error.UNSUPPORTED_SUBSCRIPTION_PLAN": "Unsupported subscription plan: {{plan}}.",
|
||||||
"error.FAILED_TO_CHECKOUT": "Failed to create checkout session.",
|
"error.FAILED_TO_CHECKOUT": "Failed to create checkout session.",
|
||||||
"error.INVALID_CHECKOUT_PARAMETERS": "Invalid checkout parameters provided.",
|
"error.INVALID_CHECKOUT_PARAMETERS": "Invalid checkout parameters provided.",
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ test('page delete -> create new page -> refresh page -> new page should be appea
|
|||||||
.click();
|
.click();
|
||||||
await page.getByText('Delete permanently?').dblclick();
|
await page.getByText('Delete permanently?').dblclick();
|
||||||
await page.getByRole('button', { name: 'Delete' }).click();
|
await page.getByRole('button', { name: 'Delete' }).click();
|
||||||
expect(page.getByText("There's no page here yet")).not.toBeUndefined();
|
expect(page.getByText('Deleted docs will appear here')).not.toBeUndefined();
|
||||||
await page.getByTestId('all-pages').click();
|
await page.getByTestId('all-pages').click();
|
||||||
|
|
||||||
await clickNewPageButton(page);
|
await clickNewPageButton(page);
|
||||||
|
|||||||
1
tools/@types/build-config/__all.d.ts
vendored
1
tools/@types/build-config/__all.d.ts
vendored
@@ -23,6 +23,7 @@ declare interface BUILD_CONFIG_TYPE {
|
|||||||
|
|
||||||
githubUrl: string;
|
githubUrl: string;
|
||||||
changelogUrl: string;
|
changelogUrl: string;
|
||||||
|
pricingUrl: string;
|
||||||
downloadUrl: string;
|
downloadUrl: string;
|
||||||
// see: tools/workers
|
// see: tools/workers
|
||||||
imageProxyUrl: string;
|
imageProxyUrl: string;
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export function getBuildConfig(
|
|||||||
githubUrl: 'https://github.com/toeverything/AFFiNE',
|
githubUrl: 'https://github.com/toeverything/AFFiNE',
|
||||||
changelogUrl: 'https://affine.pro/what-is-new',
|
changelogUrl: 'https://affine.pro/what-is-new',
|
||||||
downloadUrl: 'https://affine.pro/download',
|
downloadUrl: 'https://affine.pro/download',
|
||||||
|
pricingUrl: 'https://affine.pro/pricing',
|
||||||
imageProxyUrl: '/api/worker/image-proxy',
|
imageProxyUrl: '/api/worker/image-proxy',
|
||||||
linkPreviewUrl: '/api/worker/link-preview',
|
linkPreviewUrl: '/api/worker/link-preview',
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user