mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
fix: modify experimental features to app-level (#6823)
This commit is contained in:
1
packages/common/env/src/global.ts
vendored
1
packages/common/env/src/global.ts
vendored
@@ -23,6 +23,7 @@ export const runtimeFlagsSchema = z.object({
|
|||||||
enableEnhanceShareMode: z.boolean(),
|
enableEnhanceShareMode: z.boolean(),
|
||||||
enablePayment: z.boolean(),
|
enablePayment: z.boolean(),
|
||||||
enablePageHistory: z.boolean(),
|
enablePageHistory: z.boolean(),
|
||||||
|
enableExperimentalFeature: z.boolean(),
|
||||||
allowLocalWorkspace: z.boolean(),
|
allowLocalWorkspace: z.boolean(),
|
||||||
// this is for the electron app
|
// this is for the electron app
|
||||||
serverUrlPrefix: z.string(),
|
serverUrlPrefix: z.string(),
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const ExperimentalFeaturesPrompt = ({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.promptRoot}>
|
<div className={styles.promptRoot} data-testid="experimental-prompt">
|
||||||
<div className={styles.promptTitle}>
|
<div className={styles.promptTitle}>
|
||||||
{t[
|
{t[
|
||||||
'com.affine.settings.workspace.experimental-features.prompt-header'
|
'com.affine.settings.workspace.experimental-features.prompt-header'
|
||||||
@@ -49,14 +49,23 @@ const ExperimentalFeaturesPrompt = ({
|
|||||||
<div className={styles.spacer} />
|
<div className={styles.spacer} />
|
||||||
|
|
||||||
<label className={styles.promptDisclaimer}>
|
<label className={styles.promptDisclaimer}>
|
||||||
<Checkbox checked={checked} onChange={onChange} />
|
<Checkbox
|
||||||
|
checked={checked}
|
||||||
|
onChange={onChange}
|
||||||
|
data-testid="experimental-prompt-disclaimer"
|
||||||
|
/>
|
||||||
{t[
|
{t[
|
||||||
'com.affine.settings.workspace.experimental-features.prompt-disclaimer'
|
'com.affine.settings.workspace.experimental-features.prompt-disclaimer'
|
||||||
]()}
|
]()}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div className={styles.promptDisclaimerConfirm}>
|
<div className={styles.promptDisclaimerConfirm}>
|
||||||
<Button disabled={!checked} onClick={onConfirm} type="primary">
|
<Button
|
||||||
|
disabled={!checked}
|
||||||
|
onClick={onConfirm}
|
||||||
|
type="primary"
|
||||||
|
data-testid="experimental-confirm-button"
|
||||||
|
>
|
||||||
{t[
|
{t[
|
||||||
'com.affine.settings.workspace.experimental-features.get-started'
|
'com.affine.settings.workspace.experimental-features.get-started'
|
||||||
]()}
|
]()}
|
||||||
@@ -158,7 +167,10 @@ const ExperimentalFeaturesMain = () => {
|
|||||||
'com.affine.settings.workspace.experimental-features.header.plugins'
|
'com.affine.settings.workspace.experimental-features.header.plugins'
|
||||||
]()}
|
]()}
|
||||||
/>
|
/>
|
||||||
<div className={styles.settingsContainer}>
|
<div
|
||||||
|
className={styles.settingsContainer}
|
||||||
|
data-testid="experimental-settings"
|
||||||
|
>
|
||||||
<SplitViewSettingRow />
|
<SplitViewSettingRow />
|
||||||
<BlocksuiteFeatureFlagSettings />
|
<BlocksuiteFeatureFlagSettings />
|
||||||
</div>
|
</div>
|
||||||
@@ -1,17 +1,21 @@
|
|||||||
|
import { UserFeatureService } from '@affine/core/modules/cloud/services/user-feature';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import {
|
import {
|
||||||
AppearanceIcon,
|
AppearanceIcon,
|
||||||
|
ExperimentIcon,
|
||||||
InformationIcon,
|
InformationIcon,
|
||||||
KeyboardIcon,
|
KeyboardIcon,
|
||||||
} from '@blocksuite/icons';
|
} from '@blocksuite/icons';
|
||||||
import { useLiveData, useService } from '@toeverything/infra';
|
import { useLiveData, useServices } from '@toeverything/infra';
|
||||||
import type { ReactElement, SVGProps } from 'react';
|
import type { ReactElement, SVGProps } from 'react';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { AuthService, ServerConfigService } from '../../../../modules/cloud';
|
import { AuthService, ServerConfigService } from '../../../../modules/cloud';
|
||||||
import type { GeneralSettingKey } from '../types';
|
import type { GeneralSettingKey } from '../types';
|
||||||
import { AboutAffine } from './about';
|
import { AboutAffine } from './about';
|
||||||
import { AppearanceSettings } from './appearance';
|
import { AppearanceSettings } from './appearance';
|
||||||
import { BillingSettings } from './billing';
|
import { BillingSettings } from './billing';
|
||||||
|
import { ExperimentalFeatures } from './experimental-features';
|
||||||
import { PaymentIcon, UpgradeIcon } from './icons';
|
import { PaymentIcon, UpgradeIcon } from './icons';
|
||||||
import { AFFiNEPricingPlans } from './plans';
|
import { AFFiNEPricingPlans } from './plans';
|
||||||
import { Shortcuts } from './shortcuts';
|
import { Shortcuts } from './shortcuts';
|
||||||
@@ -27,11 +31,22 @@ export type GeneralSettingList = GeneralSettingListItem[];
|
|||||||
|
|
||||||
export const useGeneralSettingList = (): GeneralSettingList => {
|
export const useGeneralSettingList = (): GeneralSettingList => {
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
const status = useLiveData(useService(AuthService).session.status$);
|
const { authService, serverConfigService, userFeatureService } = useServices({
|
||||||
const serverConfig = useService(ServerConfigService).serverConfig;
|
AuthService,
|
||||||
|
ServerConfigService,
|
||||||
|
UserFeatureService,
|
||||||
|
});
|
||||||
|
const status = useLiveData(authService.session.status$);
|
||||||
const hasPaymentFeature = useLiveData(
|
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[] = [
|
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;
|
return settings;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -90,6 +114,8 @@ export const GeneralSetting = ({ generalKey }: GeneralSettingProps) => {
|
|||||||
return <AFFiNEPricingPlans />;
|
return <AFFiNEPricingPlans />;
|
||||||
case 'billing':
|
case 'billing':
|
||||||
return <BillingSettings />;
|
return <BillingSettings />;
|
||||||
|
case 'experimental-features':
|
||||||
|
return <ExperimentalFeatures />;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,10 +234,6 @@ const subTabConfigs = [
|
|||||||
key: 'preference',
|
key: 'preference',
|
||||||
title: 'com.affine.settings.workspace.preferences',
|
title: 'com.affine.settings.workspace.preferences',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: 'experimental-features',
|
|
||||||
title: 'com.affine.settings.workspace.experimental-features',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: 'properties',
|
key: 'properties',
|
||||||
title: 'com.affine.settings.workspace.properties',
|
title: 'com.affine.settings.workspace.properties',
|
||||||
@@ -267,9 +263,6 @@ const WorkspaceListItem = ({
|
|||||||
const currentWorkspace = workspaceService.workspace;
|
const currentWorkspace = workspaceService.workspace;
|
||||||
const isCurrent = currentWorkspace.id === meta.id;
|
const isCurrent = currentWorkspace.id === meta.id;
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
const isEarlyAccess = useLiveData(
|
|
||||||
userFeatureService.userFeature.isEarlyAccess$
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
userFeatureService.userFeature.revalidate();
|
userFeatureService.userFeature.revalidate();
|
||||||
@@ -280,30 +273,23 @@ const WorkspaceListItem = ({
|
|||||||
}, [onClick]);
|
}, [onClick]);
|
||||||
|
|
||||||
const subTabs = useMemo(() => {
|
const subTabs = useMemo(() => {
|
||||||
return subTabConfigs
|
return subTabConfigs.map(({ key, title }) => {
|
||||||
.filter(({ key }) => {
|
return (
|
||||||
if (key === 'experimental-features') {
|
<div
|
||||||
return information?.isOwner && isEarlyAccess;
|
data-testid={`workspace-list-item-${key}`}
|
||||||
}
|
onClick={() => {
|
||||||
return true;
|
onClick(key);
|
||||||
})
|
}}
|
||||||
.map(({ key, title }) => {
|
className={clsx(style.sidebarSelectSubItem, {
|
||||||
return (
|
active: activeSubTab === key,
|
||||||
<div
|
})}
|
||||||
data-testid={`workspace-list-item-${key}`}
|
key={key}
|
||||||
onClick={() => {
|
>
|
||||||
onClick(key);
|
{t[title]()}
|
||||||
}}
|
</div>
|
||||||
className={clsx(style.sidebarSelectSubItem, {
|
);
|
||||||
active: activeSubTab === key,
|
});
|
||||||
})}
|
}, [activeSubTab, onClick, t]);
|
||||||
key={key}
|
|
||||||
>
|
|
||||||
{t[title]()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}, [activeSubTab, information?.isOwner, isEarlyAccess, onClick, t]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -4,13 +4,10 @@ export const GeneralSettingKeys = [
|
|||||||
'about',
|
'about',
|
||||||
'plans',
|
'plans',
|
||||||
'billing',
|
'billing',
|
||||||
|
'experimental-features',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export const WorkspaceSubTabs = [
|
export const WorkspaceSubTabs = ['preference', 'properties'] as const;
|
||||||
'preference',
|
|
||||||
'experimental-features',
|
|
||||||
'properties',
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
export type GeneralSettingKey = (typeof GeneralSettingKeys)[number];
|
export type GeneralSettingKey = (typeof GeneralSettingKeys)[number];
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { WorkspaceMetadata } from '@toeverything/infra';
|
import type { WorkspaceMetadata } from '@toeverything/infra';
|
||||||
|
|
||||||
import { ExperimentalFeatures } from './experimental-features';
|
import type { WorkspaceSubTab } from '../types';
|
||||||
import { WorkspaceSettingDetail } from './new-workspace-setting-detail';
|
import { WorkspaceSettingDetail } from './new-workspace-setting-detail';
|
||||||
import { WorkspaceSettingProperties } from './properties';
|
import { WorkspaceSettingProperties } from './properties';
|
||||||
|
|
||||||
@@ -9,13 +9,11 @@ export const WorkspaceSetting = ({
|
|||||||
subTab,
|
subTab,
|
||||||
}: {
|
}: {
|
||||||
workspaceMetadata: WorkspaceMetadata;
|
workspaceMetadata: WorkspaceMetadata;
|
||||||
subTab: 'preference' | 'experimental-features' | 'properties';
|
subTab: WorkspaceSubTab;
|
||||||
}) => {
|
}) => {
|
||||||
switch (subTab) {
|
switch (subTab) {
|
||||||
case 'preference':
|
case 'preference':
|
||||||
return <WorkspaceSettingDetail workspaceMetadata={workspaceMetadata} />;
|
return <WorkspaceSettingDetail workspaceMetadata={workspaceMetadata} />;
|
||||||
case 'experimental-features':
|
|
||||||
return <ExperimentalFeatures />;
|
|
||||||
case 'properties':
|
case 'properties':
|
||||||
return (
|
return (
|
||||||
<WorkspaceSettingProperties workspaceMetadata={workspaceMetadata} />
|
<WorkspaceSettingProperties workspaceMetadata={workspaceMetadata} />
|
||||||
|
|||||||
@@ -1129,7 +1129,7 @@
|
|||||||
"com.affine.settings.translucent-style-description": "Use transparency effect on the sidebar.",
|
"com.affine.settings.translucent-style-description": "Use transparency effect on the sidebar.",
|
||||||
"com.affine.settings.workspace": "Workspace",
|
"com.affine.settings.workspace": "Workspace",
|
||||||
"com.affine.settings.workspace.description": "You can view current workspace's information here.",
|
"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.get-started": "Get Started",
|
||||||
"com.affine.settings.workspace.experimental-features.header.plugins": "Experimental Features",
|
"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.",
|
"com.affine.settings.workspace.experimental-features.prompt-disclaimer": "I am aware of the risks, and I am willing to continue to use it.",
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ import { test } from '@affine-test/kit/playwright';
|
|||||||
import { openHomePage } from '@affine-test/kit/utils/load-page';
|
import { openHomePage } from '@affine-test/kit/utils/load-page';
|
||||||
import { waitForEditorLoad } from '@affine-test/kit/utils/page-logic';
|
import { waitForEditorLoad } from '@affine-test/kit/utils/page-logic';
|
||||||
import {
|
import {
|
||||||
|
confirmExperimentalPrompt,
|
||||||
openAboutPanel,
|
openAboutPanel,
|
||||||
openAppearancePanel,
|
openAppearancePanel,
|
||||||
|
openExperimentalFeaturesPanel,
|
||||||
openSettingModal,
|
openSettingModal,
|
||||||
openShortcutsPanel,
|
openShortcutsPanel,
|
||||||
} from '@affine-test/kit/utils/setting';
|
} from '@affine-test/kit/utils/setting';
|
||||||
@@ -87,6 +89,18 @@ test('Open about panel', async ({ page }) => {
|
|||||||
await expect(title).toBeVisible();
|
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 ({
|
test('Different workspace should have different name in the setting panel', async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
|
|||||||
@@ -24,6 +24,15 @@ export async function openAboutPanel(page: Page) {
|
|||||||
await page.getByTestId('about-panel-trigger').click();
|
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(
|
export async function openWorkspaceSettingPanel(
|
||||||
page: Page,
|
page: Page,
|
||||||
workspaceName: string
|
workspaceName: string
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export function getRuntimeConfig(buildFlags: BuildFlags): RuntimeConfig {
|
|||||||
enableEnhanceShareMode: false,
|
enableEnhanceShareMode: false,
|
||||||
enablePayment: true,
|
enablePayment: true,
|
||||||
enablePageHistory: true,
|
enablePageHistory: true,
|
||||||
|
enableExperimentalFeature: false,
|
||||||
allowLocalWorkspace: buildFlags.distribution === 'desktop' ? true : false,
|
allowLocalWorkspace: buildFlags.distribution === 'desktop' ? true : false,
|
||||||
serverUrlPrefix: 'https://app.affine.pro',
|
serverUrlPrefix: 'https://app.affine.pro',
|
||||||
appVersion: packageJson.version,
|
appVersion: packageJson.version,
|
||||||
@@ -61,6 +62,7 @@ export function getRuntimeConfig(buildFlags: BuildFlags): RuntimeConfig {
|
|||||||
enableEnhanceShareMode: false,
|
enableEnhanceShareMode: false,
|
||||||
enablePayment: true,
|
enablePayment: true,
|
||||||
enablePageHistory: true,
|
enablePageHistory: true,
|
||||||
|
enableExperimentalFeature: true,
|
||||||
allowLocalWorkspace: buildFlags.distribution === 'desktop' ? true : false,
|
allowLocalWorkspace: buildFlags.distribution === 'desktop' ? true : false,
|
||||||
serverUrlPrefix: 'https://affine.fail',
|
serverUrlPrefix: 'https://affine.fail',
|
||||||
appVersion: packageJson.version,
|
appVersion: packageJson.version,
|
||||||
|
|||||||
Reference in New Issue
Block a user