+
diff --git a/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/experimental-features/light-art-svg.ts b/packages/frontend/core/src/components/affine/setting-modal/general-setting/experimental-features/light-art-svg.ts
similarity index 100%
rename from packages/frontend/core/src/components/affine/setting-modal/workspace-setting/experimental-features/light-art-svg.ts
rename to packages/frontend/core/src/components/affine/setting-modal/general-setting/experimental-features/light-art-svg.ts
diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/index.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/index.tsx
index 7a57b3991..b85df46bc 100644
--- a/packages/frontend/core/src/components/affine/setting-modal/general-setting/index.tsx
+++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/index.tsx
@@ -1,17 +1,21 @@
+import { UserFeatureService } from '@affine/core/modules/cloud/services/user-feature';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import {
AppearanceIcon,
+ ExperimentIcon,
InformationIcon,
KeyboardIcon,
} from '@blocksuite/icons';
-import { useLiveData, useService } from '@toeverything/infra';
+import { useLiveData, useServices } from '@toeverything/infra';
import type { ReactElement, SVGProps } from 'react';
+import { useEffect } from 'react';
import { AuthService, ServerConfigService } from '../../../../modules/cloud';
import type { GeneralSettingKey } from '../types';
import { AboutAffine } from './about';
import { AppearanceSettings } from './appearance';
import { BillingSettings } from './billing';
+import { ExperimentalFeatures } from './experimental-features';
import { PaymentIcon, UpgradeIcon } from './icons';
import { AFFiNEPricingPlans } from './plans';
import { Shortcuts } from './shortcuts';
@@ -27,11 +31,22 @@ export type GeneralSettingList = GeneralSettingListItem[];
export const useGeneralSettingList = (): GeneralSettingList => {
const t = useAFFiNEI18N();
- const status = useLiveData(useService(AuthService).session.status$);
- const serverConfig = useService(ServerConfigService).serverConfig;
+ const { authService, serverConfigService, userFeatureService } = useServices({
+ AuthService,
+ ServerConfigService,
+ UserFeatureService,
+ });
+ const status = useLiveData(authService.session.status$);
const hasPaymentFeature = useLiveData(
- serverConfig.features$.map(f => f?.payment)
+ serverConfigService.serverConfig.features$.map(f => f?.payment)
);
+ const isEarlyAccess = useLiveData(
+ userFeatureService.userFeature.isEarlyAccess$
+ );
+
+ useEffect(() => {
+ userFeatureService.userFeature.revalidate();
+ }, [userFeatureService]);
const settings: GeneralSettingListItem[] = [
{
@@ -71,6 +86,15 @@ export const useGeneralSettingList = (): GeneralSettingList => {
}
}
+ if (isEarlyAccess || runtimeConfig.enableExperimentalFeature) {
+ settings.push({
+ key: 'experimental-features',
+ title: t['com.affine.settings.workspace.experimental-features'](),
+ icon: ExperimentIcon,
+ testId: 'experimental-features-trigger',
+ });
+ }
+
return settings;
};
@@ -90,6 +114,8 @@ export const GeneralSetting = ({ generalKey }: GeneralSettingProps) => {
return
;
case 'billing':
return
;
+ case 'experimental-features':
+ return
;
default:
return null;
}
diff --git a/packages/frontend/core/src/components/affine/setting-modal/setting-sidebar/index.tsx b/packages/frontend/core/src/components/affine/setting-modal/setting-sidebar/index.tsx
index 78ef0b83a..3821d538b 100644
--- a/packages/frontend/core/src/components/affine/setting-modal/setting-sidebar/index.tsx
+++ b/packages/frontend/core/src/components/affine/setting-modal/setting-sidebar/index.tsx
@@ -234,10 +234,6 @@ const subTabConfigs = [
key: 'preference',
title: 'com.affine.settings.workspace.preferences',
},
- {
- key: 'experimental-features',
- title: 'com.affine.settings.workspace.experimental-features',
- },
{
key: 'properties',
title: 'com.affine.settings.workspace.properties',
@@ -267,9 +263,6 @@ const WorkspaceListItem = ({
const currentWorkspace = workspaceService.workspace;
const isCurrent = currentWorkspace.id === meta.id;
const t = useAFFiNEI18N();
- const isEarlyAccess = useLiveData(
- userFeatureService.userFeature.isEarlyAccess$
- );
useEffect(() => {
userFeatureService.userFeature.revalidate();
@@ -280,30 +273,23 @@ const WorkspaceListItem = ({
}, [onClick]);
const subTabs = useMemo(() => {
- return subTabConfigs
- .filter(({ key }) => {
- if (key === 'experimental-features') {
- return information?.isOwner && isEarlyAccess;
- }
- return true;
- })
- .map(({ key, title }) => {
- return (
-
{
- onClick(key);
- }}
- className={clsx(style.sidebarSelectSubItem, {
- active: activeSubTab === key,
- })}
- key={key}
- >
- {t[title]()}
-
- );
- });
- }, [activeSubTab, information?.isOwner, isEarlyAccess, onClick, t]);
+ return subTabConfigs.map(({ key, title }) => {
+ return (
+
{
+ onClick(key);
+ }}
+ className={clsx(style.sidebarSelectSubItem, {
+ active: activeSubTab === key,
+ })}
+ key={key}
+ >
+ {t[title]()}
+
+ );
+ });
+ }, [activeSubTab, onClick, t]);
return (
<>
diff --git a/packages/frontend/core/src/components/affine/setting-modal/types.ts b/packages/frontend/core/src/components/affine/setting-modal/types.ts
index 8f60d151a..4226fe09e 100644
--- a/packages/frontend/core/src/components/affine/setting-modal/types.ts
+++ b/packages/frontend/core/src/components/affine/setting-modal/types.ts
@@ -4,13 +4,10 @@ export const GeneralSettingKeys = [
'about',
'plans',
'billing',
+ 'experimental-features',
] as const;
-export const WorkspaceSubTabs = [
- 'preference',
- 'experimental-features',
- 'properties',
-] as const;
+export const WorkspaceSubTabs = ['preference', 'properties'] as const;
export type GeneralSettingKey = (typeof GeneralSettingKeys)[number];
diff --git a/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/index.tsx b/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/index.tsx
index a39854222..34ae66ce7 100644
--- a/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/index.tsx
+++ b/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/index.tsx
@@ -1,6 +1,6 @@
import type { WorkspaceMetadata } from '@toeverything/infra';
-import { ExperimentalFeatures } from './experimental-features';
+import type { WorkspaceSubTab } from '../types';
import { WorkspaceSettingDetail } from './new-workspace-setting-detail';
import { WorkspaceSettingProperties } from './properties';
@@ -9,13 +9,11 @@ export const WorkspaceSetting = ({
subTab,
}: {
workspaceMetadata: WorkspaceMetadata;
- subTab: 'preference' | 'experimental-features' | 'properties';
+ subTab: WorkspaceSubTab;
}) => {
switch (subTab) {
case 'preference':
return
;
- case 'experimental-features':
- return
;
case 'properties':
return (
diff --git a/packages/frontend/i18n/src/resources/en.json b/packages/frontend/i18n/src/resources/en.json
index 0b3c8d27c..6b1bf9879 100644
--- a/packages/frontend/i18n/src/resources/en.json
+++ b/packages/frontend/i18n/src/resources/en.json
@@ -1129,7 +1129,7 @@
"com.affine.settings.translucent-style-description": "Use transparency effect on the sidebar.",
"com.affine.settings.workspace": "Workspace",
"com.affine.settings.workspace.description": "You can view current workspace's information here.",
- "com.affine.settings.workspace.experimental-features": "Plugins",
+ "com.affine.settings.workspace.experimental-features": "Experimental Features",
"com.affine.settings.workspace.experimental-features.get-started": "Get Started",
"com.affine.settings.workspace.experimental-features.header.plugins": "Experimental Features",
"com.affine.settings.workspace.experimental-features.prompt-disclaimer": "I am aware of the risks, and I am willing to continue to use it.",
diff --git a/tests/affine-local/e2e/settings.spec.ts b/tests/affine-local/e2e/settings.spec.ts
index 6a0f2d038..0143481f0 100644
--- a/tests/affine-local/e2e/settings.spec.ts
+++ b/tests/affine-local/e2e/settings.spec.ts
@@ -2,8 +2,10 @@ import { test } from '@affine-test/kit/playwright';
import { openHomePage } from '@affine-test/kit/utils/load-page';
import { waitForEditorLoad } from '@affine-test/kit/utils/page-logic';
import {
+ confirmExperimentalPrompt,
openAboutPanel,
openAppearancePanel,
+ openExperimentalFeaturesPanel,
openSettingModal,
openShortcutsPanel,
} from '@affine-test/kit/utils/setting';
@@ -87,6 +89,18 @@ test('Open about panel', async ({ page }) => {
await expect(title).toBeVisible();
});
+test('Open experimental features panel', async ({ page }) => {
+ await openHomePage(page);
+ await waitForEditorLoad(page);
+ await openSettingModal(page);
+ await openExperimentalFeaturesPanel(page);
+ const prompt = page.getByTestId('experimental-prompt');
+ await expect(prompt).toBeVisible();
+ await confirmExperimentalPrompt(page);
+ const settings = page.getByTestId('experimental-settings');
+ await expect(settings).toBeVisible();
+});
+
test('Different workspace should have different name in the setting panel', async ({
page,
}) => {
diff --git a/tests/kit/utils/setting.ts b/tests/kit/utils/setting.ts
index 07d709613..37a4eb091 100644
--- a/tests/kit/utils/setting.ts
+++ b/tests/kit/utils/setting.ts
@@ -24,6 +24,15 @@ export async function openAboutPanel(page: Page) {
await page.getByTestId('about-panel-trigger').click();
}
+export async function openExperimentalFeaturesPanel(page: Page) {
+ await page.getByTestId('experimental-features-trigger').click();
+}
+
+export async function confirmExperimentalPrompt(page: Page) {
+ await page.getByTestId('experimental-prompt-disclaimer').click();
+ await page.getByTestId('experimental-confirm-button').click();
+}
+
export async function openWorkspaceSettingPanel(
page: Page,
workspaceName: string
diff --git a/tools/cli/src/webpack/runtime-config.ts b/tools/cli/src/webpack/runtime-config.ts
index 69c36141e..588a7e673 100644
--- a/tools/cli/src/webpack/runtime-config.ts
+++ b/tools/cli/src/webpack/runtime-config.ts
@@ -22,6 +22,7 @@ export function getRuntimeConfig(buildFlags: BuildFlags): RuntimeConfig {
enableEnhanceShareMode: false,
enablePayment: true,
enablePageHistory: true,
+ enableExperimentalFeature: false,
allowLocalWorkspace: buildFlags.distribution === 'desktop' ? true : false,
serverUrlPrefix: 'https://app.affine.pro',
appVersion: packageJson.version,
@@ -61,6 +62,7 @@ export function getRuntimeConfig(buildFlags: BuildFlags): RuntimeConfig {
enableEnhanceShareMode: false,
enablePayment: true,
enablePageHistory: true,
+ enableExperimentalFeature: true,
allowLocalWorkspace: buildFlags.distribution === 'desktop' ? true : false,
serverUrlPrefix: 'https://affine.fail',
appVersion: packageJson.version,